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