= Usher

Tree-based router library. Useful for (specifically) for Rails and Rack, but probably generally useful for anyone interested in doing routing. Based on Ilya Grigorik suggestion, turns out looking up in a hash and following a tree is faster than Krauter's massive regex approach.

== Features

* Understands single and path-globbing variables
* Understands arbitrary regex variables
* Arbitrary HTTP header requirements
* No optimization phase, so routes are always alterable after the fact
* Understands Proc and Regex transformations, validations
* Really, really fast
* Relatively light and happy code-base, should be easy and fun to alter (it hovers around 1,000 LOC, 800 for the core)
* Interface and implementation are separate, encouraging cross-pollination
* Works in 1.9!

== Route format

From the rdoc:

Creates a route from +path+ and +options+

=== +path+
A path consists a mix of dynamic and static parts delimited by <tt>/</tt>

==== Dynamic
Dynamic parts are prefixed with either :, *.  :variable matches only one part of the path, whereas *variable can match one or
more parts.

<b>Example:</b>
<tt>/path/:variable/path</tt> would match

* <tt>/path/test/path</tt>
* <tt>/path/something_else/path</tt>
* <tt>/path/one_more/path</tt>

In the above examples, 'test', 'something_else' and 'one_more' respectively would be bound to the key <tt>:variable</tt>.
However, <tt>/path/test/one_more/path</tt> would not be matched.

<b>Example:</b>
<tt>/path/*variable/path</tt> would match

* <tt>/path/one/two/three/path</tt>
* <tt>/path/four/five/path</tt>

In the above examples, ['one', 'two', 'three'] and ['four', 'five'] respectively would be bound to the key :variable.

As well, variables can have a regex matcher.

<b>Example:</b>
<tt>/product/{:id,\d+}</tt> would match

* <tt>/product/123</tt>
* <tt>/product/4521</tt>

But not
* <tt>/product/AE-35</tt>

As well, the same logic applies for * variables as well, where only parts matchable by the supplied regex will
actually be bound to the variable

Variables can also have a greedy regex matcher. These matchers ignore all delimiters, and continue matching for as long as much as their
regex allows.

<b>Example:</b>
<tt>/product/{!id,hello/world|hello}</tt> would match

* <tt>/product/hello/world</tt>
* <tt>/product/hello</tt>


==== Static

Static parts of literal character sequences. For instance, <tt>/path/something.html</tt> would match only the same path.
As well, static parts can have a regex pattern in them as well, such as <tt>/path/something.{html|xml}</tt> which would match only
<tt>/path/something.html</tt> and <tt>/path/something.xml</tt>

==== Optional sections

Sections of a route can be marked as optional by surrounding it with brackets. For instance, in the above static example, <tt>/path/something(.html)</tt> would match both <tt>/path/something</tt> and <tt>/path/something.html</tt>.

==== One and only one sections

Sections of a route can be marked as "one and only one" by surrounding it with brackets and separating parts of the route with pipes.
For instance, the path, <tt>/path/something(.xml|.html)</tt> would only match <tt>/path/something.xml</tt> and
<tt>/path/something.html</tt>. Generally its more efficent to use one and only sections over using regex.

=== +options+
* +requirements+ - After transformation, tests the condition using ===. If it returns false, it raises an <tt>Usher::ValidationException</tt>
* +conditions+ - Accepts any of the +request_methods+ specificied in the construction of Usher. This can be either a <tt>string</tt> or a regular expression.
* Any other key is interpreted as a requirement for the variable of its name.

== Rails

  script/plugin install git://github.com/joshbuddy/usher.git

== Rack

=== config.ru

  require 'usher'
  app = proc do |env|
    body = "Hi there #{env['usher.params'][:name]}"
    [
      200,          # Status code
      {             # Response headers
        'Content-Type' => 'text/plain',
        'Content-Length' => body.size.to_s,
      },
      [body]        # Response body
    ]
  end

  routes = Usher::Interface.for(:rack) do
    add('/hello/:name').to(app)
  end

  run routes

------------

  >> curl http://127.0.0.1:3000/hello/samueltanders
  << Hi there samueltanders

== DONE

* add support for () optional parts
* Add support for arbitrary HTTP header checks
* Emit exceptions inline with relevant interfaces
* More RDoc! (optionally cowbell)

== TODO

* Make it integrate with merb
* Make it integrate with rails3
* Create decent DSL for use with rack

(Let me show you to your request)