gf3/secretary — pull request #50 by noprompt (2014-09-15 21:44:10+00:00)
Title: v2.0.0 (DO NOT MERGE)

Version 2.0.0 is primarily focused on addressing issues #16 and #41 as well as cleaning up some of the API. As with any major release, this means breaking changes.

### Solution to #16

Solving #16 required the removal of the global `*routes*` atom. Removing it had a dramatic impact on the code consequently

* creating a new record type `Route` (`[pattern action]`) which specifies default implementations for all of the routing protocols. It also implements `IFn` which defaults to `render-route`.
* adding a new `make-route` function as a convenience for creating routes. This is now what `defroute` uses reducing the complexity of the macro.
* removing functions such as `locate-route` and `locate-route-value`. Since routes are no longer stored in a container managed by Secretary, these can be implemented by the library consumer.

### Solution to #41

Solving #41 required solving #16 in order to create customer dispatchers. There is a new data type `Dispatcher` (`[routes handler]`) which is simply a container for housing routes and a handler function `([routes dispatch-val]`). The `Dispatcher` type implements a unary `IFn` which takes a dispatch value and delegates to the handler. This means

* removing `dispatch!`. We simply do not need this function any longer.
* creating a new function `uri-dispatcher [routes handler]` which returns an instance of `Dispatcher` that does most of the work the original `dispatch!` function did with the exception `handler` is a ring style handler. Why is it called `uri-dispatcher`? Because that is what it's designed to do: dispatch actions based on URIs. There is nothing in the routing protocols that say patterns _must_ apply to URIs. A `input-dispatcher` might be used to dispatch against the values of `` element.
* removing `*config*`. This was a "fix it for now" artifact. The problem of prepending/removing prefixes and ensuring leading slashes shouldn't be a concern for Secretary. These are problems which are better addressed by the library consumer. For example, to ensure a URI has a leading `/` one can create a function which creates a new instance of `Dispatcher` wrapping the `Dispatcher` return from `uri-dispatcher`. Prepending prefixes to `Route`s can be handled by overriding `IFn` with an implementation that does so.

```clj
(defroute r1 "/foo/:x" {{:keys [x]} :params :as req}
[x req])

(defroute r2 "/foo/:y/bar" {{:keys [y]} :params :as req}
[y req])

(defroute r3 #"/bar/(\d+)" {[id] :params :as req}
[(js/parseInt id) req])

(defroute r4 #"/bar/([a-z]+)" {[alpha] :params :as req}
[alpha req])

(let [d (uri-dispatcher
[r1 r2 r3 r4]
(fn [handler]
(fn [req]
(let [route-name (get {r1 :foo/x
r2 :foo/y
r3 :bar/digit
r4 :bar/alpha}
(:route req)
:not-found)]
(handler (assoc req :route-name route-name))))))]
{:r1 (d "/foo/hello")
:r2 (d "/foo/goodbye/bar")
:r3 (d "/bar/100")
:r4 (d "/bar/fizzle")})
```

### Clean up

In the spirit of Ring, query-parameter encoding/decoding and serialization has been moved from `secretary.core` to `secretary.codec`.

### Won't fix?

I do not believe, although I'm open to conversation, we need to implement #18, `defroutes`, or other concepts from Compojure. My rational, again, being that these are library consumer decisions and are trivial to implement when needed.

### Summary

This version focuses on trimming down the parts of the API we simply do not need and creating the right abstractions and functions such that solving client-side routing issues is easy and flexible. These changes will definitely break existing applications which use Secretary and upgrading will require extra on behalf of the consumer (although hopefully not much). Overall, I hope many of these changes will be welcome.