I am new to Clojure coding and went through a number of articles to set up Emacs for development.
The setup itself works as designed, but I have been running server from Cider session and killing Emacs entirely when making any code change. Or, I need to find the server process from shell session, and kill it from there. This is far from ideal.
clojure-getting-started/web.clj
(defn -main [& [port]]
(let [port (Integer. (or port (env :port) 5000))]
(jetty/run-jetty (site #'app) {:port port :join? false})))
Cider session
clojure-getting-started.web> (defonce server (-main))
After starting the server, I will get the below error with (server) function:
1. Unhandled java.lang.ClassCastException
org.eclipse.jetty.server.Server cannot be cast to clojure.lang.IFn
The error message makes sense, but how can I refresh my code base using just Emacs?
I suppose (and hope) there is a better way than starting shell session on Emacs and kill the process there...
Assuming what you are wanting is to run a jetty server and have it load or reload your code when you change it from within emacs. While the advice already given is good, it may be more complex than you need when getting started. My advice is to take advantage of some of the templates out there for lein which will setup a default environment and workflow for you to begin with. You can then refine this default as you learn more until you get the workflow which suits you. My recommendation would be to start witht the default compojure template i.e.
lein new compojure my-project
This creates a bare bones project with the basic ring and compojure libraries and lein plugins as well as a simple dev profile.
Edit the src/my_project/handler.clj file and add the ring.middleware.reload middleware e.g.
(ns my-project.handler
(:require [compojure.core :refer :all]
[compojure.route :as route]
[ring.middleware.reload :refer [wrap-reload]]
[ring.middleware.defaults :refer [wrap-defaults site-defaults]]))
(defroutes app-routes
(GET "/" [] "Hello World")
(route/not-found "Not Found"))
(def app
(-> app-routes
wrap-reload
(wrap-defaults site-defaults)))
The wrap-reload middleware will cause your code to be reloaded when it is modified. You won't need to restart the jetty server for your code changes to take effect - just reload the page.
In a terminal run either
lein ring server
or
lein ring server-headless
This will start a jetty server listening on port 3000. Then from within emacs, you can just open a cider repl to use while writing your code. You won't need to restart the server process unless you make changes to your project.clj file. Same with the cider process.
Then, once your comfortable with this, look at the lein-ring documentation. There you will find information on how to setup a repl.clj file within the project. Once you do that, you will be able to do something like
lein repl
and then from within that repl, do something like
(start-server)
which will start the server. You can then switch to emacs and instead of running cider-jack-in, you can do a cider-connect, which will connect tot he already running repl rather than starting a second repl session. Later, if you decide to start also looking at clojurescript, you can look at some of the default templates for clojure+clojurescript apps. I quite like figwheel and use reagent a fair bit, so I also find the reagent template quite good.
There are quite a few lein templates out there and I find it really useful to just run them and have a look at what they do. I then tend to cherry pick the features/options I like.
Here's most of the answer I just gave to a similar question:
Try the (refresh) function in the clojure.tools.namespace.repl namespace:
The refresh function will scan all the directories on the classpath for Clojure source files, read their ns declarations, build a graph of their dependencies, and load them in dependency order.
https://github.com/clojure/tools.namespace#reloading-code-usage
We generally add that plus a few other useful things to the user namespace, so it's loaded into the REPL on startup:
(ns user
(:require [clojure.tools.namespace.repl :refer [refresh]]
[clojure.repl :refer [doc source]]
[clojure.pprint :refer [pprint pp]]
[midje.repl :as midje]
[clojure.stacktrace :as st]))
To keep that code separate from your main and test sources, put that in a file at <project root>/dev/user.clj, then add the following to your lein project.clj file:
:profiles {:dev {:source-paths ["dev"]}}
Concerning the ClassCastException - server needs to be a function of 1 param:
(defonce server (fn [request] (-main)))
Related
I'm learning Clojure (1.10) and am writing a small web app using the Luminus framework (3.93), using the Monger client (3.1.0) to connect to a MongoDB instance. Luminus generates some scaffolding code that is to create the database connection pool (using the function monger.core/connect-via-uri) on startup in <myproject>.db.core:
(ns myproject.db.core
(:require [monger.core :as mg] ... ))
(defstate db*
:start (-> env :database-url mg/connect-via-uri)
:stop (-> db* :conn mg/disconnect))
...
My problem: if the MongoDB instance is not available at this point, nothing is shown to warn of the problem. Web pages are served, until one requires a call to a Monger function. At this point the app "churns" and then timeouts (set at 30s) with an exception/stacktrace error screen (which, besides being a horrible user experience, may also expose code/data that is supposed to remain secret).
How can I best guard against starting up the application when the prerequisite database is not available?
One (admittedly clumsy) initial attempt is to insert a Monger call into the above startup code. This causes a timeout exception during startup (with an exception message), instead of starting up the web app. What is a better way?
Also, do you know of a way to let a problem like this halt the startup process instead of retrying and churning out failure messages?
(defstate db*
:start (-> env :database-url mg/connect-via-uri
; clumsy way to catch timeouts due to no database when starting up:
(#(mg/get-db-names (:conn %)) %))
:stop (-> db* :conn mg/disconnect))
I'm not an expert on Monger, but this guide on their website shows ways of changing the timeout.
So, maybe change the timeout to 3 seconds or something, then see of you can connect. Otherwise, throw and exception or something.
you can try to ping the db to check its availability:
(mg/command db {:ping 1})
Moreover, you can create a scheduler (for example here this) to check the db's status periodically
I new with clojure and I am trying to host a server with a specific url using it.
Doing some research online I got something as below.
(ns rest-demo.core
(:require [org.httpkit.server :as server]
[compojure.core :refer :all]
[compojure.route :as route]
[ring.middleware.defaults :refer :all]
[clojure.string :as str]
[clojure.data.json :as json])
(:gen-class))
(defn hello-name
[req]
{:status 200
:headers {"Content-Type" "text/html"}
:body (str "Hello " (:name (:params req)))})
(defroutes app-routes
(GET "/hello" [] hello-name)
(route/not-found "Error, page not found!"))
(defn -main
"This is our main entry point"
[& args]
(let [port (Integer/parseInt (or (System/getenv "PORT") "3000"))]
; Run the server with Ring.defaults middleware
(server/run-server (wrap-defaults #'app-routes site-defaults) {:port port})))
Running with lein run and accessing the 127.0.0.1:3000/hello I can access the API.
How would I host this with a url of my choice?
Thanks in advance!
A URL* consists of several parts, two of the most important ones are
the hostname of the computer on which it's being hosted
the path to the specific page.
It looks like you have taken care of #2.
For solving #1 you can take two approaches:
find a good place on the internet to host your program. Something like Heroku
find a way to give you laptop a name on the internet. Something like https://portmap.io/
when you get these problems solved then we get back to the programming part of this question. httpskit will by default answer requests with any hostname. so you don't need to do anything and can accept the defaults.
'*' there are distinctions between URL vs. URI at play here and i'm glossing over them
Hosting this on a specific URL of your choice basically means, you would like your web application to be accessible on that particular URL. For that, you would first have to purchase the domain (for example .com) from an ICANN-accredited domain name registrar(like Namecheap, domain.com, Godaddy) for a fee and then configure it to redirect it to the server where you are sunning the service from. In this case, it would your machine's public IP address(or as #Arthur_Ulfeldt mentioned use something like portmap or ngrok).
This is certainly not recommended as your machine might not have a good uptime or reliable connectivity. Which is why you would host it on a cloud solution. Either something like Heroku(a PaaS which would be the best choice for you as it is really easy to deploy for Clojure) or some compute instances from any of the providers(AWS ec2 or GCP compute engine or Azure VM's) just clone your application there, run your server there and redirect all your requests there.
I'm using ClojureScript, Boot and Boot-Cljs to build a Firefox Add-On. Firefox's Add-On SDK assumes a certain directory structure; in my case, I'll need a project-root/data directory, which will house my contentScriptFile.
How should I go about building a ClojureScript file, which lives in project-root/src/foo/core.cljs and either outputting it or moving it to project-root/data? I've tried using boot sift --move to no avail (I admittedly don't fully understand how this task is supposed to work, which arguments are required, etc.), using a main.cljs.edn manifest and tweaking its location, :asset-path, :output-path, etc. to no avail.
;; src/main.cljs.edn
{:require [foo.core]
:init-fns [foo.core/init!]
:compiler-options {:output-path "data"}}
;; build.boot
(set-env!
:source-paths #{"src" "data"}
:dependencies '[[org.clojure/clojure "1.7.0"]
[org.clojure/clojurescript "1.7.170"]
[adzerk/boot-cljs "1.7.170-3"]])
(require '[adzerk.boot-cljs :refer [cljs]])
(deftask build []
(comp (cljs :optimizations :whitespace)))
I'm intrigued by Boot and want to figure this out, but I have to admit, I've wasted a lot of time on this (and it looks like I'm not alone). Seeing as I already have a simple, working Clojure script which calls the ClojureScript compiler directly - and uses :output-to to do exactly what I need - I may revert back to that approach in order to wrap this experiment up.
The weird thing about Boot that looks to be tripping you up a bit is that tasks - such as the cljs task - don't necessarily interact directly with the filesystem. They interact with the FileSet, a type of immutable value they are passed and expected to return.
At the beginning of the build, Boot gathers files on disk into the build's first FileSet. Then, it threads the FileSet through the task stack. Finally, Boot writes the FileSet returned by the last task to the target directory.
Boot's sift task can be used to move files around within the FileSet, returning a new FileSet, but not to move files outside of the target directory.
Long story short, I think you can do what you want by specifying a target directory to Boot like so:
(set-env! :target-path "data" ...)
This task might help:
(deftask public []
(comp (production)
(build)
(sift :invert true :include #{#"js/app.out" #"js/app.cljs.edn"})
(target :dir #{"data"})))
In Eclipse+Counterclockwise, when I want to connect to REPL, the dialog tells me I can use nREPL over HTTP:
How to set this up? Is this somehow connected to drawbridge? I haven't been able to make these work together, although lein repl :connect http://my.url/repl worked for me.
For clarity, why this is useful compared to classic REPL: classic REPL works for localhost only. You can bridge it through SSH port tunnelling, but this - REPL over HTTP - is a viable alternative for remote, "live" servers.
Just for completeness, the server side:
drawbridge - the HTTP transport - https://github.com/cemerick/drawbridge
how to use it - https://devcenter.heroku.com/articles/debugging-clojure
example app - https://github.com/technomancy/chortles
I've just installed CCW and tried against https://github.com/technomancy/chortles: I did "lein run" after exporting the environment variables suggested there and it connects to http://flynn:reindeerflotilla#localhost:5000/repl like a charm. I tried to evaluate simple expressions and I had no problems at all while the server was up&running. I'm using Leiningen 2.4.3 to run it.
Chortle's sources https://github.com/technomancy/chortles/blob/master/src/chortles/web.clj seem to be quite simple, the main handler is wrapped in drawbridge middleware including session and parameters support too. Does that work for you? Is it feasible to use the same approach for your own application?
I recently upgrated to Emacs 23.2.1. I am using VM version 8.1.93a to read my email.
I used to change html mail to text via the following line in my vm configuration file:
(add-to-list 'vm-mime-type-converter-alist
'("text/html" "text/plain" "lynx -force_html -dump -stdin"))
but under emacs 23 I get the following error message:
Inline text/html by emacs-w3m display failed:
(error "Emacs-w3m of this version does not support
Emacs 23; try the development version")
Searching a bit in Emacs documentation, I thought I had found a solution, by the way of
(load-library "mm-decode")
(setq mm-text-html-renderer "lynx")
But it seems that vm-8 totally ignores both vm-mime-type-converter-alist (which is still documented) and mm-text-html-renderer (which is documented, was set to w3m till I set it to lynx). Did I miss something or is vm messed up and I should choose another emacs mail reader?
I found the answer via some more googling, in the release description of vm-8.1
(http://savannah.c3sl.ufpr.br/viewmail/NEWS)
text/html handling controlled by a new variable
`vm-mime-text/html-handler' which is set to 'auto-select by
default. It causes VM to locate the best library among
emacs-w3m, external w3m, w3 and lynx to display html
internally. (This replaces the earlier variable
`vm-mime-use-w3-for-text/html'.)
Note that this variable was not set to "auto-select" but to "emacs--w3m" by default.
Adding the following to my vm configuration did the trick for me:
(setq vm-mime-text/html-handler "lynx")
And the yanking of html emails work (contrarily to what happened to me with w3m-emacs)
Try (setq vm-mime-renderer-for-text/html 'lynx). It had worked for someone using vm 8.0 sometime back, as seen here.