# * George Moschovitis # (c) 2004-2005 Navel, all rights reserved. # $Id$ module N require 'nitro/controller' # The Dispatcher manages a set of controllers. class Dispatcher # The root directory. attr_accessor :root # The controllers map. attr_accessor :controllers # APIs map. attr_accessor :apis # Create a new Dispatcher. # # Input: # # [+controllers+] # Either a hash of controller mappings or a single # controller that gets mapped to :root. # # [+apis+] # A hash of apis supported by the Dispatcher. def initialize(controllers = nil, apis = nil) @root = 'root' if controllers and controllers.is_a?(Class) and controllers.ancestors.include?(Controller) @controllers = { :root => controllers } else @controllers = controllers || { :root => SimpleController } end @apis = apis end # Process the given hash and mount the # defined controllers. # # Input: # # [+controllers+] # A hash representing the mapping of # mount points to controllers. # # === Examples # # dispatcher.mount { # :root => MainController # mounts / # 'users' => UsersController # mounts /users # } def mount(controllers) (@controllers ||= {}).update(controllers) end # Add a new api to the dispatcher # # [+api+] # API symbol # [+data+] # Data for this API [content_type, ..] def add_api(api, data) (@apis ||= {})[api] = data end # Processes the path and dispatches to the corresponding # controller/action pair. # The base returned contains a trailing '/'. # # [+path+] # The path to dispatch. # # [:context] # The dispatching context. def dispatch(path, context) api = :xhtml if @apis @apis.each { |k, v| api = k if path.slice!(/#{k}\//) } end parts = path.split('/') case parts.size when 0 # / -> root.index base = @root klass = controller_class_for(:root, context) action = 'index' when 2 if klass = controller_class_for(parts[1], context) # controller/ -> controller.index base = "#{@root}/#{parts[1]}" action = 'index' else # action/ -> root.action base = @root klass = controller_class_for(:root, context) action = parts[1] end when 3 # controller/action/ -> controller.action base = "#{@root}/#{parts[1]}" klass = controller_class_for(parts[1], context) action = parts[2] end content_type = @apis ? @apis[:api] : 'text/html' return klass, "__#{api}__#{action}", base, content_type end alias_method :split_path, :dispatch # Get the controller for the given key. # Also handles reloading of controllers. def controller_class_for(key, context) klass = @controllers[key] if context[:__RELOADED__].nil? and (:full == Rendering.reload) and klass def_file = klass::DEF_FILE Controller.remove_subclasses load(def_file) klass = @controllers[key] = Object.const_get(klass.name.intern) context[:__RELOADED__] = true end return klass end end end