lein run exits without running all of my -main function - clojure

Here's my project.clj:
(defproject fixurls "0.1.0-SNAPSHOT"
:description "Fixurls"
:url "https://github.com/swizzard/fixurls"
:license {:name "WTFPL"
:url "http://www.wtfpl.net/"}
:dependencies [[org.clojure/clojure "1.5.1"]
[clj-http "0.9.2"]
[org.clojure/data.json "0.2.4"]
[me.raynes/fs "1.4.4"]
]
:plugins [[lein-gorilla "0.2.0"]]
:jvm-opts ["-Xmx4g" "-Xms2g" "-Xss1g" "-server"]
:main ^:skip-aot fixurls.core
)
Here's ~/clojure-stuff/fixurls/src/core.clj:
(ns fixurls.core
(:require
[clj-http.client :as client]
[clojure.string :as string]
[clojure.java.io :as io]
[me.raynes.fs :as fs]
[clojure.data.json :as json]
)
(:import [java.net URL])
(:gen-class)
)
...
(defn process-file [in-file] (spit (get-fixed-name in-file)
(update-file in-file)))
(defn process-files [] (map process-file valid-files))
(defn -main [] (do (println "Hello, world!") (process-files)))
When I run lein run, all that happens, after a pause, is the printing of Hello, world! to stdout, and then lein exits. I've independently verified that the (process-files) part of -main isn't getting called. I can run (-main) from the repl and it works properly. What am I doing wrong?

The map function is lazy, and is not guaranteed process any input unless the corresponding output is accessed. If you are using map for side effects alone, wrap it in dorun. If you also need the result, use doall to force processing of the entire input.

Related

clojure-api: Single main clj for multiple API handlers

The below is my app project.clj
(defproject clojure-my-app-api "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:ring {:handler clojure-my-app-api.core/app}
:dependencies [[org.clojure/clojure "1.8.0"]
[metosin/compojure-api "1.1.10"]
[ring/ring-core "1.4.0"]
[ring/ring-jetty-adapter "1.4.0"]]
:main clojure-my-app-api.core)
and my app core.clj is
(ns clojure-my-app-api.core
(:require [ring.adapter.jetty :as jetty])
(:require [compojure.api.sweet :refer :all])
(:require [ring.util.http-response :refer :all]))
(defapi app
(GET "/hello" []
:query-params [name :- String]
(ok {:message (str "Dear " name ", Hello I am here ")})))
(jetty/run-jetty app {:port 3000})
My doubt is, Is it mandatory to put (jetty/run-jetty app {:port 3000}) in every clj class if we have multiple classes for handling multiple API requests.
Can you please help me out is there any single main class mechanism for multiple clj class to handle different API path.
I have modified my code.
project.clj
(defproject clojure-dauble-business-api "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:ring {:handler {clojure-dauble-business-api.core/app
clojure-dauble-business-api.test/test1}}
:repl-options {:init-ns clojure-dauble-business-api.user}
:dependencies [[org.clojure/clojure "1.8.0"]
[metosin/compojure-api "1.1.10"]
[ring/ring-core "1.4.0"]
[ring/ring-jetty-adapter "1.4.0"]]
:main clojure-dauble-business-api.user)
user.clj
(ns clojure-dauble-business-api.user
(:require [ring.adapter.jetty :as jetty])
(:require [compojure.api.sweet :refer :all])
(:require [ring.util.http-response :refer :all])
(:require [clojure-dauble-business-api.core :as core])
(:require [clojure-dauble-business-api.test :as test]))
(jetty/run-jetty (list core/app test/test) {:port 3000})
core.clj
(ns clojure-dauble-business-api.core
(:require [ring.adapter.jetty :as jetty])
(:require [compojure.api.sweet :refer :all])
(:require [ring.util.http-response :refer :all]))
(defapi app
(GET "/hello" []
:query-params [name :- String]
(ok {:message (str "Dear " name ", Hello I am here ")})))
test.clj
(ns clojure-dauble-business-api.test
(:require [ring.adapter.jetty :as jetty])
(:require [compojure.api.sweet :refer :all])
(:require [ring.util.http-response :refer :all]))
(defapi test
(GET "/ping" []
:query-params [name :- String]
(ok {:message (str "Dear " name ", Hello I am here ")})))
Error while running http://localhost:3000/hello?name=acbd endpoint in Postman
2017-07-08 10:46:34.413:WARN:oejs.HttpChannel:qtp191004666-15: /hello?name=abcd
java.lang.ClassCastException: clojure.lang.PersistentList cannot be cast to clojure.lang.IFn
at ring.adapter.jetty$proxy_handler$fn__1401.invoke(jetty.clj:24)
at ring.adapter.jetty.proxy$org.eclipse.jetty.server.handler.AbstractHandler$ff19274a.handle(Unknown Source)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)
at org.eclipse.jetty.server.Server.handle(Server.java:497)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:310)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:257)
at org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:540)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635)
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555)
at java.lang.Thread.run(Thread.java:745)
You shouldn't have (jetty/run-jetty (list core/app test/test) {:port 3000}) in any of your namespaces. (Having it in user.clj is fine for REPL work).
Typically, you have a single handler route that you pass to ring for handing your application.
For example, I generally have a routes namespace that I combine by routes from other namespaces.
So, from your example.
(ns clojure-dauble-business-api.routes
:require [compojure.core :refer :all]
(clojure-dauble-business-api [core :as core]
[test :as t]))
(def app
(routes core/app t/test))
This is what you could pass into Jetty, or refer to in your :ring entry in your project.clj.
:ring {:handler clojure-dauble-business-api.routes}
You're getting the error, because run-jetty must be passed a function, but you're passing it a list instead (because you're trying to consolidate your routes with (list core/app test/test)
I would also add the plugin lein-ring to your project and remove the :main entry. You will also have to correct your :ring entry in your project as above.
I am a newbie too, but hope this helps:
This is how I have implemented. There is one file named user.clj which has
(jetty/run-jetty app {:port 3000})
and other common function that you may specify in main and then in project.clj
:repl-options {:init-ns user}
you can also use injections to load namespaces but I have never used them.

Clojure Ring wrap-reload is not working

This is my core.clj file
(ns lein-app.core
(:require [compojure.core :refer :all]
[compojure.route :as route]
[ring.middleware.reload :refer [wrap-reload]]))
(use 'ring.adapter.jetty)
(defroutes app
(GET "/" [] "<h1>Hello world</h1>")
(route/not-found "<h1>Not found</h1>"))
(def reloadable-app
(wrap-reload app))
(defn -main
[]
(run-jetty reloadable-app {:port 3000}))
And this is my project.clj
(defproject lein-app "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [
[org.clojure/clojure "1.8.0"]
[compojure "1.5.2"]
[ring "1.5.0"]]
:main lein-app.core)
When I run lein run it starts the server correctly but if I change the GET response to be anything else for example I need to kill the server and restart it.
as indicated in the ring issue#104 the doc is not quite clear.
For wrap-reload (as well for similar functionality in other libs/projects) one has to pass the var itself not the value.
Like so
(wrap-reload #'app)

What is wrong with (use 'korma.db) directive?

When I try to create an uberjar using lein with the following very simple Clojure test file, I get an error
Compiling korma-test.core
Exception in thread "main" java.lang.Exception:
lib names inside prefix lists must not contain periods, compiling:(core.clj:1:1)
and cannot figure out why. I got the (use 'korma.db) from sqlkorma.com's docs section, and tried a require statement as well (not listed in my examples here).
project.clj
(defproject korma-test "0.1.0-SNAPSHOT"
:description "korma db test"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.5.1"]
[korma "0.3.0-RC5"]]
:main korma-test.core)
core.clj (simplified)
(ns korma-test.core
(:gen-class)
(use 'korma.db)
(require '[clojure.string :as str])
(:import java.util.Date)
)
(defn -main
[& args]
(let [opts (parse-opts args)
start-time (str (Date.))]))
The ns macro uses keywords in place of functions and does take quoted arguments.
(ns korma-test.core
...
(:use korma.db)
(:require [clojure.string :as str])
...)
There is a nice write-up here: http://blog.8thlight.com/colin-jones/2010/12/05/clojure-libs-and-namespaces-require-use-import-and-ns.html

Clojure REPL environment lost after running refresh-all

I'm hacking on a Clojure app I created with lein new app inclojure. There are a few things I'd like to pre-load every time I fire up the REPL, so I created a dev/user.clj file, and source it in my project.clj:
(defproject inclojure "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.5.1"]]
:main ^:skip-aot inclojure.core
:target-path "target/%s"
:profiles {:uberjar {:aot :all}
:dev {:source-paths ["dev"]}})
The file mostly just requires a bunch of crap so I can use shorthand:
(ns inclojure.core
(:require [clojure.java.io :as io]
[clojure.tools.namespace.repl :refer (refresh-all)])
(:use [clojure.reflect :only [reflect]]
[clojure.pprint :only [pprint print-table pp]]))
(defn r
"inspect all of the properties in a java object, optionally by specifying a
pattern"
([o] (r o "."))
([o prefix]
(->> (reflect o :ancestors true)
:members
(filter #(re-find (re-pattern (str "(?i)" prefix)) (str (:name %))))
(pprint))))
This all works, but when I run (refresh-all), it loses everything from dev/user.clj. Is there a way for me to be able to (refresh-all) from the and either keep or re-load everything from dev/user.clj?
It seems like I may want to create a REPL-specific namespace like inclojure.repl in dev/user.clj, and then make that the REPL's init-ns.

Hiccup not working : FileNotFoundException: Could not locate ../as__init.class or ../as.clj on classpath

I'm just beginning with clojure and I'm trying to build a small web app. I wanted to try out hiccup but it doesn't seem to be working. My code is below.
Project.clj
(defproject WebTest "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:dependencies [[org.clojure/clojure "1.4.0"]
[compojure "1.1.5"]
[hiccup "1.0.3"]
[org.clojure/java.jdbc "0.2.3"]
[net.sourceforge.jtds/jtds "1.2.4"]
]
:plugins [[lein-ring "0.8.2"]
[lein-idea "1.0.1"]]
:ring {:handler WebTest.handler/app}
:profiles
{:dev {:dependencies [[ring-mock "0.1.3"]]}})
handler.clj
(ns WebTest.handler
(:use compojure.core)
(:require [compojure.handler :as handler]
[compojure.route :as route]
[WebTest.Content :as pages]
[hiccup.core :as templ]))
(defroutes app-routes
(GET "/" [] (templ/html [h1 "Hello world"]))
(GET "/Greeting/:name" [name] (str "<h1>Hello " name "</h1>"))
(GET "/Date/:year/:month/:day" [year month day] (str "<h1>It is " month "/" day "/" year "</h1>"))
(route/not-found "Not Found"))
(def app
(handler/site app-routes))
And the error that I get is
Exception in thread "main" java.io.FileNotFoundException: Could not locate hiccu
p/core/as__init.class or hiccup/core/as.clj on classpath:
at clojure.lang.RT.load(RT.java:432)
at clojure.lang.RT.load(RT.java:400)
at clojure.core$load$fn__4890.invoke(core.clj:5415)
at clojure.core$load.doInvoke(core.clj:5414)
A very long stack trace follows that. Any insight into what I'm doing wrong?
Attempting to require WebTest.Content as you do fails for me, Though the rest works fine if I remove that one:
(ns WebTest.handler
(:use compojure.core)
(:require [compojure.handler :as handler]
[compojure.route :as route]
;[WebTest.Content :as pages]
[hiccup.core :as templ]))
The error you mention would be the case if there where mismatched []s in the :require section of handler.clj's ns form though they are not caused by it as you show it.