7

I'm trying to write my first web app in compojure. I'm using ccw, and I File-New-Project, Clojure Project and use the "compojure" leiningen template. End up with project.clj looking like

(defproject asdf "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :dependencies [[org.clojure/clojure "1.4.0"]
                 [compojure "1.1.5"]]
  :plugins [[lein-ring "0.8.2"]]
  :ring {:handler asdf.handler/app}
  :profiles
  {:dev {:dependencies [[ring-mock "0.1.3"]]}})

src/asdf/handler.clj looks like

(ns asdf.handler
  (:use compojure.core)
  (:require [compojure.handler :as handler]
            [compojure.route :as route]))

(defroutes app-routes
  (GET "/" [] "Hello World")
  (route/not-found "Not Found"))

(def app
  (handler/site app-routes))

I found I can run this using lein ring server from the command line, but I'm not sure how to run this from eclipse. I'm of course hoping to be able not only to run it, but also to debug it and set breakpoints and such. Is there a way to do this in eclipse? Or, if not, how about IntelliJ/La-Clojure? (I'm a bit afraid of emacs, for now, but maybe if it's super-simple I'd give it a try).

Or, is this just not the typical development process for a compojure app? (If not, what is? Just run lein ring server and pray?)

If it makes a difference this is on Win7.

lobsterism
  • 3,469
  • 2
  • 22
  • 36

2 Answers2

5

Here's a recipe that's work great for me while developing Ring applications:

  • Ensure you have leiningen support properly configured for your projet (do it once if in doubt):
    • in the package explorer, select the project, and invoke the contextual command Leiningen > Reset configuration
    • then also invoke the Leiningen > Update dependencies command
    • you should see a Leiningen Dependencies virtual node in your project, referencing the direct and transitive dependencies of your project
  • Select the asdf.handler file, right click and then Debug as > Clojure Application
  • Open the asdf.handler namespace in an editor
  • With the cursor currently still in the editor, type Ctrl+Alt+N to jump to the REPL and switch the REPL's current namespace to asdf.handler at the same time
  • Start the app by typing (app) + Enter (or Ctrl+Enter if your cursor is not at the end of the line)

You can now navigate between the editors and the REPL.

  • To send editor content to the REPL, select it, and hit Ctrl+Enter
  • If you hit Ctrl+Enter without a selection, the whole 'top level expression' (e.g. a defn) will be sent to the REPL
  • To resend the whole file to the REPL, type Ctrl+Alt+S
  • the whole list of keyboard shortcuts specific to CCW is here: http://code.google.com/p/counterclockwise/wiki/EditorKeyBindingsFeatures

Note that a future version of Counterclockwise will integrate a little bit more with Leiningen 2, but as it currently stands, the very nature of developing ring applications make it not so painful to bootstrap things as described above, IMHO

Laurent Petit
  • 1,201
  • 7
  • 12
  • When typing `(app)` I get `ArityException Wrong number of args (0) passed to: cookies$wrap-cookies$fn clojure.lang.AFn.throwArity (AFn.java:437)`. – lobsterism Mar 16 '13 at 18:14
  • Oh yes, sorry : `app` is just the main handler, it's not the server. You need to create a function for starting your server, something like `(defn start [] (run-jetty #'app {:join? false}))` , and don't forget to add a require to your namespace : `(:require [ring.adapter.jetty :only [run-jetty]])`. And thus it is `(start)` that you must call, not `(app)` – Laurent Petit Mar 16 '13 at 22:44
  • Almost, I was getting `Could not locate ring/adapter/jetty__init.class or ring/adapter/jetty.clj on classpath` error that way, but then I found this link on compojure's wiki and following section II solved it: https://github.com/ring-clojure/ring/wiki/Interactive-Development – lobsterism Mar 17 '13 at 00:32
  • Actually in retrospect, I think if I just added [ring] to the project dependencies (compojure is only dependent on [ring/ring-core]) it would have worked. – lobsterism Mar 17 '13 at 00:37
  • oh yes, ok. Sorry, I haven't done compojure dev, but straight ring dev, so I was not aware compojure didn't already add ring.adapter.jetty to the dependencies. So now everything's okay for you with ccw & webapp dev ? – Laurent Petit Mar 17 '13 at 08:49
  • By the way what's your opinion on emacs for clojure? Do you see any advantages over using ccw? – lobsterism Mar 17 '13 at 14:29
3

You can run Compojure/Ring apps on IntelliJ IDEA and La Clojure with the following steps:

  1. Generate pom.xml from leiningen's project.clj using lein pom command.
  2. Import maven project with IntelliJ IDEA as usual. You might want to make sure that you have Clojure jar in classpath.
  3. Once the project is loaded, you can start Clojure REPL using Tools -> Start Clojure Console.
  4. To load a Clojure file to REPL, select Tools -> Clojure REPL -> Load file to REPL.

After that, to start a Ring app you can just load a Clojure file that invokes ring.adapter.jetty/run-jetty.

The code to run a simple route on http://localhost:4004/ would look like this:

(require 'compojure.core)
(require 'ring.adapter.jetty)

(ring.adapter.jetty/run-jetty
  (compojure.core/routes (compojure.core/ANY "/" [] "Hello world!"))
  {:port 4004 :join? false})

:join? option is important, if it would be set to true (the default), the REPL would not accept more commands. Your routes will usually be more complex and compojure.core/defroutes or other means should be used.

You can put such file in test path, so it wouldn't be loaded when running the project outside of IDEA. If Clojure facet is not added to your module, you can add it in File -> Project Structure -> Modules.

A complete sample (with jetty reloading) is available here: https://github.com/tlipski/ganelon-demo - development is done with IDEA and real site runs on Heroku: http://ganelon.herokuapp.com.

Debugging Clojure apps run with the technique above is possible as well - you just have to:

  1. Create Remote debugging Run profile in IntelliJ IDEA
  2. Add apropriate JVM options from a profile above (e.g. agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005) to REPL settings in File -> Project Structure -> Modules -> [your module] -> Clojure facet -> JVM Arguments field.
  3. Start REPL with Tools -> Start Clojure Console.
  4. Start Remote debugging profile.

After that, you can add breakpoints, inspect variables, etc.

Tomek Lipski
  • 166
  • 4
  • 1
    `(require 'asdf.handler) (use 'ring.server.standalone) (serve asdf.handler/app)` is a simpler test file for compojure. Just have to include `[ring-server "0.2.8"]` in dev dependencies. – lobsterism Apr 11 '13 at 15:31
  • Sure, just wanted to make the example Compojure based, not Ring-only. Anyway I hope the answer helps, I've also posted detailed tutorial on the technique to http://blog.tomeklipski.com/ – Tomek Lipski Apr 19 '13 at 08:04
  • your blog link is dead, though I assume you know this by now. – lobsterism Nov 29 '13 at 19:55
  • blog.tomeklipski.com runs on Blogger, which has quite good, but not 99.9999% availability I think - so occasional downtime might be possible. I've just checked and it works properly to me, even when using direct link to the post: http://blog.tomeklipski.com/2013/04/running-and-debugging-clojure-code-with.html Anyway, this post becomes kind of obsololete with growing popularity of Cursive plugin for IntelliJ - please see http://cursiveclojure.com/eap.html and http://cursiveclojure.com/userguide/ – Tomek Lipski Dec 06 '13 at 13:56