Clojure REPL environment lost after running refresh-all - clojure

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.

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)

GUI Using Seesaw

I am trying to make a small window using Seesaw for Clojure. I have created a project "sample" using Leiningen.
lein new app sample
I have made added the dependency in the project file.
(defproject sample "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.6.0"] [seesaw "1.4.4"]]
:main ^:skip-aot sample.core
:target-path "target/%s"
:profiles {:uberjar {:aot :all}})
My source file is as follows:
(ns sample.core
(:gen-class)
(:require [seesaw.core :as seesaw]
[seesaw.dev :as dev]))
(def window (seesaw/frame
:title "First Example"
:content "hello world"))
(dev/show-options window)
But when I run it I keep getting an error: clojure.lang.Compiler$CompilerException: java.lang.RuntimeException: No such namespace: dev, compiling:(C:\Users\A\sample\src\sample\core.clj:10:1)
I followed your instructions and it worked fine for me, so long as I left the -main definition in place.

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

hiccup form-helper with compojure

Exception: Exception in thread "main" java.io.FileNotFoundException: Could not locate hiccup/form_helpers__init.class or hiccup/form_helpers.clj on classpath:
I'm trying to get a toy compojure app up and running. The original app was from CloudBees and their ClickStart app for Clojure/Compojure. I'm trying to add a simple form (that won't persist anything yet) using hiccup form_helpers but I'm getting a ClassNotFound exception. Here's what I've done:
project.clj:
(defproject mywebapp "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:dependencies [[org.clojure/clojure "1.4.0"]
[compojure "1.1.1"]
[hiccup "1.0.1"]]
:plugins [[lein-ring "0.7.3"]]
:ring {:handler mywebapp.routes/app}
:profiles
{:dev {:dependencies [[ring-mock "0.1.3"]]}})
views.clj:
(ns mywebapp.views
(:use [hiccup core page]
[hiccup form-helpers :only [form-to label text-area submit-button]]))
...
(defn shout-form []
[:div {:id "shout-form" }
(form-to [:post "/form"]
(label "shout" "What do you want to SHOUT?")
[:br]
(text-area "shout")
[:br]
(submit-button "SHOUT!"))])
...
Ah, looks like I just had an old example of forms in hiccup. form_helpers was from a previous version.
if I change my views.clj file from this:
(:use [hiccup form-helpers])
to look like this:
(:use [hiccup form])
(and presumably this would work though i haven't tested it):
(:use [hiccup form :only [form-to label text-area submit-button]])
I don't get the error anymore.
To clarify: the package used to be called "form_helpers" and is now simply called "form".