(To be honest, I think clojure has its purposes, but a one-off calculator page isn't one of them. Use the right tool for the right job and all that.)
"time to make trivial webapp" is NOT a good reason to choose anything.
But a real webapp would have lots of templates and lots of files.
Where Clojure really shines in web development is when you mix it with cgrand's Enlive templating engine (http://github.com/cgrand/enlive), which is an amazing project with lots of active development. This approach is so cool that even a lot of the Rails and Python startup folks are starting to copy it.
Having written a lengthy Enlive tutorial, http://github.com/swannodette/enlive-tutorial, I of course swear by it and scoff at inline html generation :D So I prefer coupling Ring+Enlive+Moustache (and tasty Aleph) myself but that would be an awful lot to cover in a single blog post now wouldn't it ;)
All in good time.
You may have glossed over some of the details.
As far as the framework is concerned, the example shows how to build a production deployment of the application. The author is not showing a toy teaser application. There are a lot of details there, but these are things that you would want to know if you actually want to run a production server.
(defpackage :add-nums
(:use :cl :hunchentoot :cl-who))
(in-package :add-nums)
(defmacro with-html (&body body)
`(with-html-output-to-string (*standard-output* nil :prologue t :indent t)
,@body))
(define-easy-handler (add-nums :uri "/add-nums")
((a :parameter-type 'integer)
(b :parameter-type 'integer))
(with-html
(:html
(:head (:title "Add two numbers"))
(:body
(if (and a b)
(htm (:p (str (+ a b)))))
(:form :method :get
(:input :type :text :name "a")
(:input :type :text :name "b")
(:input :type :submit))))))
(defparameter *site* (make-instance 'acceptor :port 8080))
(start *site*) (ns add-nums
(:use compojure.core [hiccup core page-helpers] ring.adapter.jetty))
(defroutes handler
(GET "/add-nums" [a b]
(let [a (Integer/parseInt a)
b (Integer/parseInt b)]
(html
[:html
[:head [:title "Add two numbers"]]
[:body
(if (and a b) [:p (+ a b)])
(form-to [:get "/add-nums"]
(text-field :a)
(text-field :b)
(submit-button))]])))
(run-jetty handler {:port 8080})
Mark's tutorial code is a little more complete than your example, and doesn't aim for brevity. It also doesn't use any of the form functions from Hiccup (admittedly, they're not as well documented as they could be).Thank you! It's good to know that verbosity was for the sake pedagogy and completeness, and not necessity.
* you've omitted code to control the output content-type and the associated response headers (xhtml vs html)
* you've removed text, formatting from the form page
* you've discarded the results page altogether
* you aren't properly distinguishing between GET and POST
Do the same to the clojure code and it'll be about the same length as well.
you've omitted code to control the output content-type and the associated response headers (xhtml vs html)
Add this single line to your WITH-HTML macro.
(setf (html-mode) :xml) ; for XML or :sgml for HTML.
http://weitz.de/cl-who/#html-modeyou've removed text, formatting from the form page
Add one line for a CSS file inclusion and style it to your heart's content. In real web apps I use html-template to template the code, and do not sloppily generate html like I did with the example; but I had to do what the clojure code did, in the same manner.
you've discarded the results page altogether
I am printing the results on the same page. Yeah, that's a better usability.
you aren't properly distinguishing between GET and POST
Says who? the DEFINE-EASY-HANDLER takes arguments, which correspond to the submitted form elements, via GET or POST. In fact, that macro also does some type conversion for you as well; since you declared your parameters to be integers they will be converted to integers when you get them, and not remain strings. This stuff is built into the web server.
http://weitz.de/hunchentoot/#define-easy-handler
If you're gonna implement a full REST then you have no business generating your display html from within your container.
What else do you think I omitted?
I have been screaming for ages telling Clojurists to rip CL APIs and implement them in clojure. They're more tasteful and cultured than that entrerprisey crap that java is smearing all over this nice Lisp dialect.
The majority of open source clojure code that I have seen looks like Java FFI stubs; you need to tuck those loose ends in and tidy them up with macros. But this probably wont happen until Clojure is ported to another runtime/platform; portability is a surefire way to distill the essence of a language from its implementation detail.
In the July/August 2010 column, Getting Started with Google App Engine and Clojure, guest columnist Aaron Bedra shows how to use Clojure, a relatively new but robust Lisp implementation on the Java Virtual Machine, create and deploy an application using the Compojure web framework on the Google App Engine platform.
Couple more helpful links for some basics not covered in the article (all work in progress):
Compojure docs: http://www.compojure.org
Stub for "Clojure Web Development" book: https://docs.google.com/Doc?docid=0AQqGP1CDN0uIZGhmZjJmcGZfM...