Better Workflow with App Engine?

43 views
Skip to first unread message

Thorsten Wilms

unread,
Feb 15, 2011, 2:48:31 AM2/15/11
to clo...@googlegroups.com
Hi!

I managed to get to a "Hello world" level using appengine-magic, plus an
Emacs Swank/Slime setup.

While I'm pretty sure I won't look back to Python regarding the language
itself, I already miss the speed and simplicity of just saving,
switching to a browser, reloading and seeing results.

How would I best go about writing a script that starts swank, emacs
(with project files), automatically connects slime and evaluates a few
lines in the slime REPL (switch namespace, compile, run Jetty ...)?
None of this should happen, if I just start Emacs to work on anything else.

Would it be sensible/feasible to somehow hook compiling of the core to
saving any .clj file in Emacs? Or would monitoring the filesystem and
recompile on changes, daemon-style be better, and if so, how to
accomplish that?


--
Thorsten Wilms

thorwil's design for free software:
http://thorwil.wordpress.com/

Rasmus Svensson

unread,
Feb 16, 2011, 11:10:29 AM2/16/11
to clo...@googlegroups.com
2011/2/15 Thorsten Wilms <t_...@freenet.de>:

> Hi!
>
> I managed to get to a "Hello world" level using appengine-magic, plus an
> Emacs Swank/Slime setup.

I haven't used appengine-magic myself, but I do interactive web
programming from Emacs (mainly using Ring + Moustache + Enlive), so I
thought I'd share how my typical workflow looks like.

> While I'm pretty sure I won't look back to Python regarding the language
> itself, I already miss the speed and simplicity of just saving, switching to
> a browser, reloading and seeing results.

Updating some code and seeing the results shouldn't be more
complicated than hitting a keystroke and refreshing the page in
Clojure too. :-)


Assuming a project.clj file like this:

(defproject my-web "1.0.0-SNAPSHOT"
:description "FIXME: write"
:dependencies [[org.clojure/clojure "1.2.0"]
[ring "0.3.6"]]
:dev-dependencies [[swank-clojure "1.2.1"]])


And some source files:


(ns my-web.controller)

(defn my-app [request]
{:status 202
:headers {"Content-Type" "text/plain; charset=UTF-8"}
:body "Hello, world!"})


(ns my-web.main
(:use [my-web.controller :only [my-app]]
[ring.adapter.jetty :only [run-jetty]]))

(defn -main []
(run-jetty #'my-app {:port 8080, :join? false}))


My first step is to start Emacs and open the main.clj file. I then
start a swank server and connect to it with M-x durendal-jack-in.
(durendal takes care of finding the project directory, running the
lein commands, and connecting slime.) When the repl is ready, I
evaluate the whole main.clj file by pressing C-c C-k in its buffer.
(This will also load controller.clj, since main.clj uses it.) To start
the web server, I first enter the main namespace by pressing C-c M-p
<RET> in the main.clj buffer and then evaluate (-main) in the slime
repl. When the web server has started, I'm ready to start coding.

(The long startup time is a great disadvantage of Clojure. However, I
don't see it as a very big problem practically. I usually start the
Clojure instance once when I begin developing, and after that there is
really no reason to restart it. The advantage that IMHO outweighs the
startup time problem is that the interactive development features of
Clojure allows you to change the code while it's running, correct
mistakes, and remove old unused code without having to restart the
process.)

With the web server up an running, I open up http://localhost:8080/ in
my browser. Now, lets assume that I want to change the "Hello, world!"
text to "Hello, Clojure-land!". I open the controller.clj file, edit
the corresponding line and press C-M-x somewhere within the defn form
to evaluate it. The change is then visible directly when refreshing
the page in the browser.

If I have written a new function in the controller namespace and want
to try it in the repl, I first enter the namespace by pressing C-c M-p
<RET> in the controller.clj file. The slime repl is now in that
namespace, and I can, for instance, evaluate (my-app {:uri "/test",
:request-method :get}).

> Would it be sensible/feasible to somehow hook compiling of the core to
> saving any .clj file in Emacs? Or would monitoring the filesystem and
> recompile on changes, daemon-style be better, and if so, how to accomplish
> that?

There is a ring middleware called "wrap-reload" that automatically
reloads a namespace when its file has changed. I don't use it myself,
since I feel that reevaluating code is simple enough in Emacs.

> How would I best go about writing a script that starts swank, emacs (with
> project files), automatically connects slime

Durendal (https://github.com/technomancy/durendal) takes care of
running lein swank for the correct project and connect slime to it.

> and evaluates a few lines in
> the slime REPL (switch namespace, compile, run Jetty ...)?

The first ones can be solved by C-c C-k (eval file) and C-c M-p (enter
namespace). For, the rest, you can invoke a function containing all
the startup code, or you could keep the code in a (comment ...) block
and evaluate the lines by pressing C-x C-e at the end of the lines.

Notes:
* durendal required me to have leiningen on some directory in the
system path, e.g. /usr/local.
* Some prefer putting the code that I put in the -main function
directly at the top level of the namespace. This works equally well
for interactive development, but the approach presented here is also
suitable for compiling into jar files (code at the top level - e.g.
starting the server - level will then be executed at compile time
rather than at runtime) and use with lein run.

// raek

Rasmus Svensson

unread,
Feb 16, 2011, 11:12:28 AM2/16/11
to clo...@googlegroups.com
P.S.

I forgot to mention that a lot of really useful slime commands are
documented at the swank-clojure project site:
https://github.com/technomancy/swank-clojure

// raek

James Reeves

unread,
Feb 16, 2011, 12:05:18 PM2/16/11
to clo...@googlegroups.com
On 16 February 2011 16:10, Rasmus Svensson <ra...@lysator.liu.se> wrote:
> (defn -main []
>  (run-jetty #'my-app {:port 8080, :join? false}))

Have you tried using ring-serve
(https://github.com/weavejester/ring-serve)? It has a few advantages
over running the run-jetty adapter directly. In particular:

* It ensures `swank.core/break` works when used inside a handler
* It uses wrap-stacktrace to give you pretty development stack traces
* It automatically finds a free port and opens a web browser
* It's safe to run multiple times (uses an atom to keep track of
whether it's already running)

- James

Thorsten Wilms

unread,
Feb 16, 2011, 3:21:21 PM2/16/11
to clo...@googlegroups.com
On 02/16/2011 05:10 PM, Rasmus Svensson wrote:

> With the web server up an running, I open up http://localhost:8080/ in
> my browser. Now, lets assume that I want to change the "Hello, world!"
> text to "Hello, Clojure-land!". I open the controller.clj file, edit
> the corresponding line and press C-M-x somewhere within the defn form
> to evaluate it. The change is then visible directly when refreshing
> the page in the browser.
>
> If I have written a new function in the controller namespace and want
> to try it in the repl, I first enter the namespace by pressing C-c M-p
> <RET> in the controller.clj file. The slime repl is now in that
> namespace, and I can, for instance, evaluate (my-app {:uri "/test",
> :request-method :get}).

I must have read about C-M-x, but it didn't "click". Many thanks for
your excellent answer, it's already making me a much happier camper :)

Reply all
Reply to author
Forward
0 new messages