public
Description: small fast tree-based general purpose router with interfaces for rails, rack, email or choose your own adventure
Homepage: http://joshbuddy-usher.rubyforge.org/
Clone URL: git://github.com/joshbuddy/usher.git
usher /
name age message
file .gitignore Sun Oct 18 06:28:46 -0700 2009 Ignore NetBeans files [Daniel Vartanov]
file History.txt Sun Feb 22 06:46:41 -0800 2009 gemify [joshbuddy]
file Manifest.txt Sun Mar 01 20:36:43 -0800 2009 fixed gemspec [joshbuddy]
file README.rdoc Mon Aug 31 06:11:36 -0700 2009 whitespace issues iwth git [Daniel Neighman]
file Rakefile Thu Dec 03 01:27:04 -0800 2009 removed rubyforge tasks [joshbuddy]
file VERSION.yml Fri Nov 20 12:48:22 -0800 2009 Version bump to 0.5.11 [joshbuddy]
directory benchmarks/ Wed Dec 02 23:01:36 -0800 2009 easier to read [joshbuddy]
directory lib/ Thu Dec 03 17:05:23 -0800 2009 flattened conditions from array [joshbuddy]
directory rails/ Thu Nov 26 13:22:58 -0800 2009 removed _interface. simpler interface module [joshbuddy]
directory spec/ Thu Dec 03 17:05:23 -0800 2009 flattened conditions from array [joshbuddy]
directory tasks/ Wed Jun 03 09:48:10 -0700 2009 cleaned up rails 2.2 2.3 interfaces [joshbuddy]
file usher.gemspec Thu Nov 26 21:27:10 -0800 2009 added dirge dependency. regenerate spec [joshbuddy]
README.rdoc

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 /

Dynamic

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

Example: /path/:variable/path would match

  • /path/test/path
  • /path/something_else/path
  • /path/one_more/path

In the above examples, ‘test’, ‘something_else’ and ‘one_more’ respectively would be bound to the key :variable. However, /path/test/one_more/path would not be matched.

Example: /path/*variable/path would match

  • /path/one/two/three/path
  • /path/four/five/path

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.

Example: /product/{:id,\d+} would match

  • /product/123
  • /product/4521

But not

  • /product/AE-35

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.

Example: /product/{!id,hello/world|hello} would match

  • /product/hello/world
  • /product/hello

Static

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

Optional sections

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

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, /path/something(.xml|.html) would only match /path/something.xml and /path/something.html. 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 Usher::ValidationException
  • conditions - Accepts any of the request_methods specificied in the construction of Usher. This can be either a string 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)