lib/nitro/dispatcher.rb in nitro-0.19.0 vs lib/nitro/dispatcher.rb in nitro-0.20.0

- old
+ new

@@ -1,16 +1,22 @@ -module Nitro +require 'facet/object/special_class' require 'nitro/controller' require 'nitro/routing' -require 'nitro/simple' +require 'nitro/mixin/helper' +module Nitro + # The Dispatcher manages a set of controllers. class Dispatcher include Router + + unless const_defined?('ROOT') + ROOT = '/' + end # The public root directory. The files in this # directory are published by the web server. attr_accessor :public_root @@ -38,47 +44,80 @@ def initialize(controllers = nil) @public_root = 'public' @template_root = @public_root if controllers and controllers.is_a?(Class) and controllers.ancestors.include?(Controller) - controllers = { :root => controllers } + controllers = { '/' => controllers } else - controllers ||= { :root => SimpleController } + controllers ||= { '/' => SimpleController } end mount(controllers) end + # A published object is exposed through a REST interface. + # Only the public non standard methods of the object are + # accessible. Published objects implement the Controller + # part of MVC. + # # Process the given hash and mount the - # defined controllers. + # defined classes (controllers). # # Input: # # [+controllers+] # A hash representing the mapping of # mount points to controllers. # # === Examples # - # dispatcher.mount( - # :root => MainController, # mounts / - # 'users' => UsersController # mounts /users + # disp.mount( + # '/' => MainController, # mounts / + # '/users' => UsersController # mounts /users # ) + # disp.publish '/' => MainController def add_controller(controllers) + for c in controllers.values + unless (c.ancestors.include?(Controller) or c.ancestors.include?(Publishable)) + c.send :include, Publishable + end + + auto_mixin(c) + end + (@controllers ||= {}).update(controllers) - update_routes + + update_routes() end alias_method :mount, :add_controller + alias_method :publish, :add_controller + # Call this method to automatically include helpers in the + # Controllers. For each Controller 'XxxController' the + # default helper 'Helper' and the auto mixin + # 'XxxControllerMixin' (if it exists) are included. + + def auto_mixin(c) + c.helper(Helper) + + begin + if helper = Module.by_name("#{c}Mixin") + c.helper(helper) + end + rescue NameError + # The auto helper is not defined. + end + end + # Update the routes. Typically called after a new # Controller is mounted. def update_routes @routes = [] @controllers.each do |base, c| - base = (base == :root ? '' : "/#{base}") + base = '' if base == '/' c.action_metadata.each do |action, meta| if route = meta[:route] @routes << [route, "#{base}/#{action}", *meta.params.keys] end end @@ -92,10 +131,15 @@ # [+path+] # The path to dispatch. # # [:context] # The dispatching context. + # + #-- + # FIXME: this is a critical method that should be optimized + # watch out for excessive String creation. + #++ def dispatch(path, context = nil) path = route(path, context) parts = path.split('/') @@ -103,35 +147,35 @@ case parts.size when 0 # / -> root.index base = '/' - klass = controller_class_for(:root, context) + klass = controller_class_for(base) action = 'index' when 1 - if klass = controller_class_for(parts[0], context) + base = "/#{parts[0]}" + if klass = controller_class_for(base) # controller/ -> controller.index - base = "/#{parts[0]}" action = 'index' else # action/ -> root.action base = '/' - klass = controller_class_for(:root, context) + klass = controller_class_for(base) action = parts[0] end else - if klass = controller_class_for(parts[0], context) + base = "/#{parts[0]}" + if klass = controller_class_for(base) # controller/action -> controller.action - base = "/#{parts[0]}" parts.shift action = parts.join('__') else # action/ -> root.action base = '/' - klass = controller_class_for(:root, context) + klass = controller_class_for(base) action = parts.join('__') end end return klass, "#{action}_action", base @@ -139,10 +183,10 @@ alias_method :split_path, :dispatch # Get the controller for the given key. # Also handles reloading of controllers. - def controller_class_for(key, context) + def controller_class_for(key) klass = @controllers[key] if klass and (:full == Rendering.reload) klass.instance_methods.grep(/(action$)|(template$)/).each do |m| klass.send(:remove_method, m) rescue nil