lib/usher/interface/rack.rb in usher-0.6.6 vs lib/usher/interface/rack.rb in usher-0.6.7

- old
+ new

@@ -5,11 +5,16 @@ module Interface class Rack ENV_KEY_RESPONSE = 'usher.response' ENV_KEY_PARAMS = 'usher.params' - + ENV_KEY_DEFAULT_ROUTER = 'usher.router' + + + # Middleware for using Usher's rack interface to recognize the request, then, pass on to the next application. + # Values are stored in <tt>env</tt> normally. + # class Middleware def initialize(app, router) @app = app @router = router @@ -19,11 +24,14 @@ @router.call(env) @app.call(env) end end - + + # Replacement for <tt>Rack::Builder</tt> which using Usher to map requests instead of a simple Hash. + # As well, add convenience methods for the request methods. + # class Builder < ::Rack::Builder def initialize(&block) @usher = Usher::Interface::Rack.new super end @@ -51,37 +59,55 @@ def delete(path, options = nil, &block) self.map(path, options.merge!(:conditions => {:request_method => "DELETE"}), &block) end end - attr_reader :router + attr_reader :router, :router_key + # Constructor for Rack interface for Usher. + # <tt>app</tt> - the default application to route to if no matching route is found. The default is a 404 response. + # <tt>options</tt> - options to configure the router + # * <tt>use_destinations</tt> - option to disable using the destinations passed into routes. (Default <tt>true</tt>) + # * <tt>router_key</tt> - Key in which to put router into env. (Default <tt>usher.router</tt>) + # * <tt>request_methods</tt> - Request methods on <tt>Rack::Request</tt> to use in determining recognition. (Default <tt>[:request_method, :host, :port, :scheme]</tt>) + # * <tt>generator</tt> - Route generator to use. (Default <tt>Usher::Util::Generators::URL.new</tt>) + # * <tt>allow_identical_variable_names</tt> - Option to prevent routes with identical variable names to be added. eg, /:variable/:variable would raise an exception if this option is not enabled. (Default <tt>false</tt>) def initialize(app = nil, options = nil, &blk) - @_app = app || lambda { |env| ::Rack::Response.new("No route found", 404).finish } - @router = Usher.new(:request_methods => [:request_method, :host, :port, :scheme], :generator => Usher::Util::Generators::URL.new, :allow_identical_variable_names => false) + @_app = app || proc{|env| ::Rack::Response.new("No route found", 404).finish } @use_destinations = options && options.key?(:use_destinations) ? options[:use_destinations] : true + @router_key = options && options[:router_key] || ENV_KEY_DEFAULT_ROUTER + request_methods = options && options[:request_methods] || [:request_method, :host, :port, :scheme] + generator = options && options[:generator] || Usher::Util::Generators::URL.new + allow_identical_variable_names = options && options.key(:allow_identical_variable_names) ? options[:allow_identical_variable_names] : false + @router = Usher.new(:request_methods => request_methods, :generator => generator, :allow_identical_variable_names => allow_identical_variable_names) instance_eval(&blk) if blk end - + + # Returns whether the route set has use_destinations? enabled. def use_destinations? @use_destinations end + # Creates a deep copy of the current route set. def dup new_one = super original = self new_one.instance_eval do @router = router.dup end new_one end - + + # Adds a route to the route set with a +path+ and optional +options+. + # See <tt>Usher#add_route</tt> for more details about the format of the route and options accepted here. def add(path, options = nil) @router.add_route(path, options) end alias_method :path, :add + # Sets the default application when route matching is unsuccessful. Accepts either an application +app+ or a block to call. + # # default { |env| ... } # default DefaultApp def default(app = nil, &block) @_app = app ? app : block end @@ -91,24 +117,34 @@ # is the same as: # post("/url") # it returns route, and because you may want to work with the route, # for example give it a name, we returns the route with GET request + + # Convenience method for adding a route that only matches request method +GET+. + def only_get(path, options = {}) + add(path, options.merge!(:conditions => {:request_method => ["GET"]})) + end + + # Convenience method for adding a route that only matches request methods +GET+ and +HEAD+. def get(path, options = {}) - self.add(path, options.merge!(:conditions => {:request_method => ["HEAD", "GET"]})) + add(path, options.merge!(:conditions => {:request_method => ["HEAD", "GET"]})) end + # Convenience method for adding a route that only matches request method +POST+. def post(path, options = {}) - self.add(path, options.merge!(:conditions => {:request_method => "POST"})) + add(path, options.merge!(:conditions => {:request_method => "POST"})) end + # Convenience method for adding a route that only matches request method +PUT+. def put(path, options = {}) - self.add(path, options.merge!(:conditions => {:request_method => "PUT"})) + add(path, options.merge!(:conditions => {:request_method => "PUT"})) end + # Convenience method for adding a route that only matches request method +DELETE+. def delete(path, options = {}) - self.add(path, options.merge!(:conditions => {:request_method => "DELETE"})) + add(path, options.merge!(:conditions => {:request_method => "DELETE"})) end def parent_route=(route) @router.parent_route = route end @@ -120,10 +156,11 @@ def reset! @router.reset! end def call(env) + env[router_key] = self request = ::Rack::Request.new(env) response = @router.recognize(request, request.path_info) after_match(request, response) if response determine_respondant(response).call(env) end @@ -159,9 +196,11 @@ # # @api private def determine_respondant(response) if use_destinations? && response && response.destination && response.destination.respond_to?(:call) response.destination + elsif use_destinations? && response && response.destination && response.destination.respond_to?(:args) && response.destination.args.first.respond_to?(:call) + response.args.first else _app end end