I need to read a clojure function from an edn file which outputs hiccup to generate html content.
But I'm stuck at the part where the function needs to be evaluated.
I receive the error message:
java.lang.RuntimeException: Unable to resolve symbol: fn in this context, compiling:(null:1:1)
((eval (read-string "(fn [] (list [:div\"Hello\"]))")))
and
((load-string "(fn [] (list [:div\"Hello\"]))"))
are working inside a clojure REPL and output the expected result
([:div "Hello"])
project.clj
(defproject infocenter "0.1.0-SNAPSHOT"
:dependencies [[org.clojure/clojure "1.8.0"]
[org.clojure/clojurescript "1.9.225"]
[hiccup "1.0.5"]]
:plugins [[lein-figwheel "0.5.4-7"]]
:clean-targets ^{:protect false} [:target-path "out" "resources/public/cljs"]
:cljsbuild {
:builds [{:id "dev"
:source-paths ["src"]
:figwheel true
:compiler {:main "templ.core"
:asset-path "cljs/out"
:output-to "resources/public/cljs/main.js"
:output-dir "resources/public/cljs/out"}}]}
:figwheel {
:css-dirs ["resources/public/template"]})
core.cljs
(ns templ.core
(:require-macros [templ.edn :refer [read-edn]]))
(let [div (. js/document getElementById "content")]
(set! (. div -innerHTML) (read-edn "fn.edn")))
edn.clj
(ns templ.edn
(:use [hiccup core form]))
(defmacro read-edn
"Read template from file in resources/"
[edn-name]
;(slurp edn-name)
;((eval (read-string "(fn [] (list [:div\"Hello\"]))")))
((load-string "(fn [] (list [:div\"Hello\"]))"))
)
Try this:
(ns xyz.core
(:gen-class))
(defn -main
"I don't do a whole lot ... yet."
[& args]
(println "main - enter")
(println (eval '(+ 2 3)))
(println ((eval (read-string "(fn [] (list [:div\"Hello\"]))"))))
(println "main - exit")
)
with results:
> lein run
main - enter
5
([:div Hello])
main - exit
This is just plain Clojure, and I see you are using CLJS as well. There may be some problem in your setup with the CLJS part of it. What are you trying to do with read-edn and fn.edn? I would avoid macros completely whenever possible.
Related
I'm writing a web app which uses Overtone. When I try running the app using lein run or when I try to start the repl while in the project's directory I get the same error: java.lang.ExceptionInInitializerError at clojure.main.<clinit>(main.java:20) Caused by: java.lang.Exception: Server needs to be connected before you can perform this action.
It seems to me that both of those actions make all the files in my project compile. Is there any way to compile the namespaces which use Overtone after I run the server? Or maybe this isn't the issue, and the problem is coming from something else?
Here is my project.clj file:
(defproject comusic "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:dependencies [[buddy "1.3.0"]
[compojure "1.5.2"]
[conman "0.6.3"]
[cprop "0.1.10"]
[funcool/struct "1.0.0"]
[luminus-immutant "0.2.3"]
[luminus-migrations "0.3.0"]
[luminus-nrepl "0.1.4"]
[markdown-clj "0.9.98"]
[metosin/muuntaja "0.1.0"]
[metosin/ring-http-response "0.8.2"]
[mount "0.1.11"]
[org.clojure/clojure "1.8.0"]
[org.clojure/tools.cli "0.3.5"]
[org.clojure/tools.logging "0.3.1"]
[org.postgresql/postgresql "42.0.0"]
[org.webjars.bower/tether "1.4.0"]
[org.webjars/bootstrap "4.0.0-alpha.5"]
[org.webjars/font-awesome "4.7.0"]
[org.webjars/jquery "3.1.1"]
[org.webjars/webjars-locator-jboss-vfs "0.1.0"]
[ring-webjars "0.1.1"]
[ring/ring-core "1.6.0-RC1"]
[ring/ring-defaults "0.2.3"]
[selmer "1.10.7"]
[overtone "0.10.1"]]
:min-lein-version "2.0.0"
:jvm-opts ["-server" "-Dconf=.lein-env"]
:source-paths ["src/clj"]
:test-paths ["test/clj"]
:resource-paths ["resources"]
:target-path "target/%s/"
:main ^:skip-aot comusic.core
:migratus {:store :database :db ~(get (System/getenv) "DATABASE_URL")}
:plugins [[lein-cprop "1.0.1"]
[migratus-lein "0.4.4"]
[lein-immutant "2.1.0"]]
:profiles
{:uberjar {:omit-source true
:aot :all
:uberjar-name "comusic.jar"
:source-paths ["env/prod/clj"]
:resource-paths ["env/prod/resources"]}
:dev [:project/dev :profiles/dev]
:test [:project/dev :project/test :profiles/test]
:project/dev {:dependencies [[prone "1.1.4"]
[ring/ring-mock "0.3.0"]
[ring/ring-devel "1.5.1"]
[pjstadig/humane-test-output "0.8.1"]]
:plugins [[com.jakemccrary/lein-test-refresh "0.18.1"]]
:source-paths ["env/dev/clj"]
:resource-paths ["env/dev/resources"]
:repl-options {:init-ns user}
:injections [(require 'pjstadig.humane-test-output)
(pjstadig.humane-test-output/activate!)]}
:project/test {:resource-paths ["env/test/resources"]}
:profiles/dev {}
:profiles/test {}})
EDIT: After booting a SC server and trying to connect to it in my main function I still get the same error. File which contains main function:
(ns comusic.core
(:require [comusic.handler :as handler]
[luminus.repl-server :as repl]
[luminus.http-server :as http]
[luminus-migrations.core :as migrations]
[comusic.config :refer [env]]
[clojure.tools.cli :refer [parse-opts]]
[clojure.tools.logging :as log]
[mount.core :as mount]
[overtone.core :as overtone])
(:gen-class))
(def cli-options
[["-p" "--port PORT" "Port number"
:parse-fn #(Integer/parseInt %)]])
(mount/defstate ^{:on-reload :noop}
http-server
:start
(http/start
(-> env
(assoc :handler (handler/app))
(update :port #(or (-> env :options :port) %))))
:stop
(http/stop http-server))
(mount/defstate ^{:on-reload :noop}
repl-server
:start
(when-let [nrepl-port (env :nrepl-port)]
(repl/start {:port nrepl-port}))
:stop
(when repl-server
(repl/stop repl-server)))
(defn stop-app []
(doseq [component (:stopped (mount/stop))]
(log/info component "stopped"))
(shutdown-agents))
(defn start-app [args]
(doseq [component (-> args
(parse-opts cli-options)
mount/start-with-args
:started)]
(log/info component "started"))
(.addShutdownHook (Runtime/getRuntime) (Thread. stop-app)))
(defn -main [& args]
(cond
(some #{"migrate" "rollback"} args)
(do
(mount/start #'comusic.config/env)
(migrations/migrate args (select-keys env [:database-url]))
(System/exit 0))
:else
(do
(overtone/connect-external-server 57110)
(start-app args))))
I'm new to clojure and I'm trying to wrap my head around live reload in in clojure I want to be able to monitor/ watch all/ any project file and update the browser automatically
So far I have the following
(defproject app2 "0.1.0-SNAPSHOT"
:description "FIXME: write this!"
:url "http://exampl.com/FIXME"
:dependencies [[org.clojure/clojure "1.8.0"]
[org.clojure/clojurescript "1.9.89"]
[ring "1.5.0"]
[stasis "2.2.0"]
[hiccup "1.0.5"]
[clj-tagsoup "0.3.0"]
[optimus "0.18.5"]
[ring/ring-jetty-adapter "1.5.0"]
[cljs-ajax "0.5.8"]
[enfocus "2.1.1"]]
:plugins [[lein-cljsbuild "1.1.3"]
[lein-ring "0.9.7"]]
:cljsbuild {:builds [
{:id "dev"
:incremental true
:source-paths ["src/cljs"]
:compiler {
:main "scripts.client"
:output-to "resources/public/js/main.js"
:output-dir "resources/public/js/out"
:asset-path "js/out"
}}]}
:aliases {
"start-dev" ["pdo" ["cljsbuild" "auto"] ["ring" "server-headless"]]
}
:source-paths ["src"]
:resource-paths ["resources"]
:main app2.server
:repl-options {
:prompt (fn [ns] (str "your command for <" ns ">, master? " ))
:welcome (println "Welcome to the magical world of the repl!")
:init-ns app2.hawk
:init (app2.hawk/init)
:caught clj-stacktrace.repl/pst+
:skip-default-init false
:host "0.0.0.0"
:port 9000
:timeout 40000
}
:ring {
:init app2.hawk/init
:handler app2.server/app
:auto-reload? true :auto-refresh? true :reload-paths ["resources/public"]
:refresh-paths ["resrouces/public"]
}
:profiles {
:dev {
:repl-options {
:nrepl-middleware [cemerick.piggieback/wrap-cljs-repl]
}
:source-paths ["src"]
:ring {
:nrepl {
:start? true
:port 9000
:host "0.0.0.0"
}
}
:dependencies [
[ring-refresh "0.1.1"]
[http-kit "2.0.0"]
[org.clojure/tools.nrepl "0.2.11"]
[com.cemerick/piggieback "0.2.1"]
[hawk "0.2.10"]
]
:plugins [
[lein-pdo "0.1.1"]
]
}
}
)
for my handler I have
(ns app2.server
(:use [ring.middleware.resource :only [wrap-resource]]
[ring.middleware.file-info :only [wrap-file-info]]
[ring.middleware.file :only [wrap-file]]
[ring.middleware.reload :refer [wrap-reload]]
[ring.middleware.content-type :refer [wrap-content-type]]
[ring.middleware.refresh :refer [wrap-refresh]]
[ring.util.response :refer [file-response]]
)
(defn wrap-utf-8
"This function works around the fact that Ring simply chooses the default JVM
encoding for the response encoding. This is not desirable, we always want to
send UTF-8."
[handler]
(fn [request]
(when-let [response (handler request)]
(if (.contains (get-in response [:headers "Content-Type"]) ";")
response
(if (string? (:body response))
(update-in response [:headers "Content-Type"] #(str % "; charset=utf-8"))
response)))))
(defn handler [request]
(file-response (:uri request) {:root "resources/public"}))
(def app (-> handler
wrap-content-type
wrap-reload
wrap-refresh []
wrap-utf-8))
And then I am running hawk from repl
(ns app2.hawk
(:require [hawk.core :as hawk])
(:require [app2.server :refer [export-pages]]))
(defn init
[]
(export-pages)
(hawk/watch! [{:paths ["src/app2/templates" "resources/templates"]
:filter hawk/modified?
:handler (fn [ctx e]
(export-pages) ;; i'm compiling html pages dynamically to the server root but how do I then notify browser than html has changed? can i force server to reload from here?
ctx)}]))
If you don't mind using Boot instead of Leiningen, the system project will give you all the reload goodness you can expect from a Lisp, with plenty of examples.
Be sure to check the Holy Grail demo, which leverages system, to get started with minimal fuss.
It sounds like you have put together a great setup so far.
and for managing this workflow Figwheel is the logical next step. If you are doing any Clojurescript + clojure-web stuff you almost certainly should start with figwheel, you will have a much more pleasant experience.
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.
I've built a very simple web app in Clojure (in fact I followed a tutorial). The project.clj file looks like this:
(defproject webdev "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"]
[ring "1.2.2"]
[hiccup "1.0.5"]
[compojure "1.1.6"]
[org.clojure/java.jdbc "0.3.3"]
[postgresql/postgresql "9.1-901.jdbc4"]]
:plugins [[lein-ring "0.8.10"]]
:ring {:handler (webdev.core/-main)
:port 8000}
:uberjar-name "webdev.jar"
:main webdev.core
:aot [webdev.core]
:profiles {:dev
{:main webdev.core/-dev-main}})
The relevant parts of my main webdev/core.clj look like this:
(defroutes routes
(GET "/about" [] about)
(ANY "/request" [] handle-dump)
(GET "/items" [] handle-index-items)
(POST "/items" [] handle-create-item)
(DELETE "/items/:item-id" [] handle-delete-item)
(PUT "/items/:item-id" [] handle-update-item)
(not-found "Page not found."))
(defn wrap-db [hndlr]
(fn [req]
(hndlr (assoc req :webdev/db db))))
(defn wrap-server-header [hndlr]
(fn [req]
(hndlr (assoc req :webdev/db db))))
(defn wrap-server-response [hndlr]
(fn [req]
(let [response (hndlr req)]
(assoc-in response [:headers "Server:"] "my-server"))))
(def sim-methods {"PUT" :put
"DELETE" :delete})
(defn wrap-simulated-methods [hndlr]
(fn [req]
(if-let [method (and (= :post (:request-method req))
(sim-methods (get-in req [:params "_method"])))]
(hndlr (assoc req :request-method method))
(hndlr req))))
(def app
(wrap-file-info
(wrap-resource
(wrap-server-response
(wrap-db
(wrap-params
(wrap-simulated-methods routes)))) "static")))
(defn -main [& [port]]
(items/create-table db)
(jetty/run-jetty #'app
{:port (if port (Integer/parseInt port)
(Integer/parseInt (System/getenv "PORT")))}))
(defn -dev-main [port]
(items/create-table db)
(jetty/run-jetty (wrap-reload #'app) {:port (Integer. port)}))
....
If I run Lein ring server or Lein ring uberjar on my project I get the following error:
java.lang.ClassCastException: clojure.lang.PersistentList
cannot be cast to clojure.lang.Named
If I run Lein run 8000. It works correctly and I can browse to localhost:8000
My Leiningen version is:
Leiningen 2.3.4 on Java 1.6.0_26 Java HotSpot(TM) 64-Bit Server VM
Anyone know what's wrong?
Regards,
Simon
That's looking wrong.
:ring {:handler (webdev.core/-main)
:port 8000}
(webdev.core/-main) means running your main function and delegating the result of the main Function as the handler to the ring-plugin.
Try using something more like this when using lein ring ...
:ring {:handler webdev.core/app
:port 8000}
I am getting
Warning: specified :main without including it in :aot.
If you only need AOT for your uberjar, consider adding :aot :all into your
:uberjar profile instead.
Here is my 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)
and here is core.clj
(ns korma-test.core
(require [korma.db :as kdb])
(require [clojure.string :as str])
(:use [clojure.tools.cli])
(:import java.util.Date)
(:gen-class)
)
; Parses for options passed in on the command line.
(defn parse-opts
"Using the newer cli library, parses command line args."
[args]
(cli args
(optional ["-host" "Informix host" :default "localhost"] )
(optional ["-port" "Informix host's service port" :default "1498"] )
(required ["-username" "user name"] )
(required ["-password" "password"] )
(optional ["-database" "Informix host's database" :default "stores7/ministores.dbs" ] )))
(defn -main
[& args]
(if (= 0 (count args))
(println "Usage: korma-test --host <host-name> --port <port-num> --database <db-name>")
(let [opts (parse-opts args)
start-time (str (Date.))]
(def db-config {:classname "com.informix.jdbc.IfxDriver"
:subprotocol "postgresql"
:subname (format "//%s:(:port opts)/%s"
(:host opts)
(:database opts))
:user (:user opts)
:password (:password opts)})
(kdb/defdb db db-config)
(println opts))))
I'm confused as to where to put :aot to satisfy the warning.
I could have sworn it worked without warning before but in any case you now need to add an :aot directive in your project.clj
See here
The following works
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"]
[org.clojure/tools.cli "0.3.1"]]
:main korma-test.core
:aot [korma-test.core])
core.clj
(ns korma-test.core
(:require [korma.db :as kdb])
(:require [clojure.string :as str])
(:require [clojure.tools.cli :as c])
(:import java.util.Date)
(:gen-class))
; Parses for options passed in on the command line.
(defn parse-opts
"Using the newer cli library, parses command line args."
[args]
(c/cli args
[ ["-host" "Informix host" :default "localhost"]
["-port" "Informix host's service port" :default "1498"]
["-username" "user name"]
["-password" "password"]
["-database" "Informix host's database" :default "stores7/ministores.dbs" ]]))
(defn -main
[& args]
(if (= 0 (count args))
(println "Usage: korma-test --host <host-name> --port <port-num> --database <db-name>")
(let [opts (parse-opts args)
start-time (str (Date.))
db-config {:classname "com.informix.jdbc.IfxDriver"
:subprotocol "postgresql"
:subname (format "//%s:(:port opts)/%s"
(:host opts)
(:database opts))
:user (:user opts)
:password (:password opts)}]
(kdb/defdb db db-config)
(println opts))))