2 # Created by Matt Todd on 2008-01-02.
3 # Copyright (c) 2007. All rights reserved.
11 %w(rubygems merb/core_ext merb/router).each {|dep|require dep}
13 abort "Merb must be installed for Routing to function. Please install Merb."
22 # = MRouter, the Rack Merb Router
27 # include MRouterHelper
29 # r.match('/path/to/match').to(:action => 'do_stuff')
30 # {:action => 'not_found'} # the default route
32 # def do_stuff(params)
36 # [200, {'Content-Type'=>'text/plain'}, env['merb.route'].inspect]
42 # Supplying a default route if none of the others match is good practice,
43 # but is unnecessary as the predefined route is always, automatically,
44 # going to contain a redirection to the +not_found+ method. (So your app
45 # should implement a +not_found+ method.)
47 # In order to set a different default route, simply end the call to +route+
48 # with a hash containing the action to run along with any other params.
50 # If your particular app requires another field to default to, such as a
51 # controller of some sort, defining a default route will be necessary as
52 # MRouter only knows it should default to +not_found+.
56 # The mechanics of the router are solely from the efforts of the Merb
57 # community. This functionality is completely ripped right out of Merb
58 # and makes it functional. All credit to them, and be sure to check out
59 # their great framework: if you need a beefier framework, maybe Merb is
62 # http://merbivore.com/
63 class MRouter < Merb::Router
70 env['merb.router'] = self
71 env['merb.route'] = self.class.route(env)
75 # Retrieves the last value from the +route+ call and, if it's a Hash, sets
76 # it to +@@default_route+ to designate the failover route. If +route+ is
77 # not a Hash, though, the internal default should be used instead (as the
78 # last returned value is probably a Route object returned by the
79 # <tt>r.match().to()</tt> call).
81 # Used exclusively internally.
82 def self.default_to route
83 @@default_route = route.is_a?(Hash) ? route : {:action => 'not_found'}
86 # Called internally by the +call+ method to match the current request
87 # against the currently defined routes. Returns the params list defined in
88 # the +to+ routing definition, opting for the default route if no match is
91 # pull out the path requested (WEBrick keeps the host and port and protocol in REQUEST_URI)
92 uri = URI.parse(env['REQUEST_URI']).path
95 path = (uri ? uri.split('?').first : '').sub(/\/+/, '/')
96 path = path[0..-2] if (path[-1] == ?/) && path.size > 1
97 req = Struct.new(:path, :method).new(path, env['REQUEST_METHOD'].downcase.to_sym)
100 route = self.match(req, {})
102 # make sure a route is returned even if no match is found
104 #return default route
107 # params (including action and module if set) for the matching route
115 # The Helper that provides the +route+ class method and +route+ instance method
116 # to setup routes and to actually route the request.
119 # Matches the request information in +env+ to the appropriate route.
121 Rack::MRouter.route(@env)
125 # Yields the router which allows routes to be set up.
128 Rack::MRouter.prepare do |router|
129 Rack::MRouter.default_to yield(router)
132 abort "Halcyon::Server::Base.route expects a block to define routes."
137 # Hook to include the class methods into the receiver.
138 def self.included(receiver)
139 receiver.extend(ClassMethods)