Thanks a lot! We should have our own James Reeves appreciation day :)
On Mar 21, 3:23 pm, James Reeves <
weavejes...@googlemail.com> wrote:
> Hi folks,
>
> I've just finished making some large changes to the Compojure
> repository. Read on for a breakdown of the new additions:
>
> == Version 0.1 released ==
>
> I've taken the current code that people have been using, and forked it
> into the "stable" branch. People have been using this with fairly few
> problems reported, so I've released this as version 0.1. This version
> uses the tried-and-tested "defservlet" syntax most people are familiar
> with.
>
> == Ring branch merged ==
>
> The "ring" branch has now been merged into the master branch. This
> represents a big change to how Compojure is put together, with a few
> changes to the syntax. Note that this hasn't been used as extensively
> as version 0.1, so you might run into bugs that have been missed out
> during testing. I'll try and fix any reported issue as quickly as
> possible.
>
> = defroutes syntax =
>
> Instead of using defservlet to define a servlet, you now should use
> defroutes:
>
> (defroutes my-app
> (GET "/"
> (html [:h1 "Hello World"])))
>
> This defines a Ring handler. This is a function that takes in a
> request map, and returns a response map:
>
> => (my-app {:request-method :get, :uri "/"})
> {:status 200, :headers {}, :body "<h1>Hello World</h1>"}
>
> With this syntax, Compojure achieves a great deal of flexibility. You
> can simply define middleware functions to handle caching, and easily
> write interfaces to plug Compojure into any web server you wish. It's
> also a heck of a lot easier to test.
>
> Read more about how the request and response map are defined in the
> Ring SPEC:
>
>
http://github.com/mmcgrana/ring/blob/4a035a2c20c654cf8020379aad8625e2...
>
> Once you've applied all your middleware to your routes, you can turn
> it into a servlet with the 'servlet' inline:
>
> (run-server {:port 8080}
> "/*" (servlet my-app))
>
> Or use the defservice macro to create a "-service" function, suitable
> for genclass:
>
> (defservice my-app)
>
> No longer is there a need for messy hacks to abstract your routes from
> their implementation. But it gets even better; because defservice and
> servlet are macros and inlines respectively, if you redefine your
> routes, any changes you make will automatically and instantly be
> picked up.
>
> = Embedding routes =
>
> You can also embed routes inside routes. This is useful if you have a
> whole bunch of routes and you want to split them up into logical
> sections:
>
> (defroutes all-routes
> (GET "/admin/*"
> admin-routes)
> (GET "/*"
> public-routes))
>
> = Returning headers =
>
> Compojure now treats any map being returned by a route as a response
> map. This means that adding headers is a little more verbose:
>
> (GET "/"
> [{:headers {"Content-Type" "text/plain"}}
> "Hello World"])
>
> Or alternatively:
>
> (GET "/"
> {:headers {"Content-Type" "text/plain"}
> :body "Hello World"})
>
> = Route local bindings =
>
> There are now only five local bindings defined for each route:
>
> * request - the request map
> * params - a map of all the parameters in the request
> * cookies - the cookies in the request
> * session - the request session
> * flash - the session flash
>
> This seems bare, but that's because a lot of information is now stored
> in the request map. Along with all the keys mentioned in Mark's Ring
> SPEC file, such as :uri and :request-method, Compojure adds the
> following additional keys:
>
> * :route-params - parameters matched by the route
> * :query-params - parameters encoded in the query string
> * :form-params - parameters encoded in the request body
> * :cookies - the cookies in the request
> * :session - the request session
> * :flash - the session flash
>
> Basically, all the information you could ever want is now stored in
> the request map. The local bindings just provide convenient shortcuts.
>
> = Sessions =
>
> Sessions are now completely detached from Java. They're functional and
> easily extensible, so you can store your sessions in files, in a
> database, or wherever you wish, just by overriding a few multimethods.
> Compojure defaults to using in-memory sessions, and this is currently
> the only type of session included with Compojure.
>
> To read from sessions, you can use the session binding:
>
> (GET "/"
> (html [:h1 "User: " (session :user)]))
>
> To write a session you can return the session in the response map:
>
> (POST "/"
> [{:session (assoc session :user (params :user))}
> (redirect-to "/")])
>
> That's a little long-winded though, so you can use the session-assoc
> and session-dissoc functions to make it easier:
>
> (POST "/"
> [(session-assoc :user (params :user))
> (redirect-to "/")])
>
> The session-assoc and session-dissoc demonstrate functionality related
> to embedded routes. Because routes are just functions, you can return
> your own handler functions from routes:
>
> (POST "/"
> (fn [request]
> {:session (assoc (request :session) :user (params :user))}))
>
> This is why session-assoc can functionally modify the session without
> needing to be passed the session explicitly.
>
> = Flash =
>
> The flash is a place to store temporary messages between requests.
> Anything added to (session :flash) will persist until the next
> request, then be wiped. For example:
>
> (POST "/register"
> [(flash-assoc :message "Set username")
> (session-assoc :user (params :user))
> (redirect-to "/")])
> (GET "/"
> (html
> (if (flash :message)
> [:div.message (flash :message)])
> ...))
>
> = Upcoming features =
>
> That's about it for the current changes. I'll briefly mention what I'm
> looking to have in Compojure in the near future:
>
> * Session storage types of :cookie and :file
> * File uploads
> * SSL support in Jetty server
> * Possibly a Grizzly server
> * Absolute URL support in routes so you can set subdomains:
>
> (GET "http://:
category.example.com/"
> (index (params :category)))
>
> - James