diff options
author | Emilio Tagua <miloops@gmail.com> | 2009-05-12 16:13:00 -0300 |
---|---|---|
committer | Emilio Tagua <miloops@gmail.com> | 2009-05-12 16:13:00 -0300 |
commit | 0048897a417774f7e5a0c8c9e82fc8684f94ebc1 (patch) | |
tree | 8df248dab434bdaac61ea60249d4630958260eed /actionpack/lib/action_controller/abstract | |
parent | 6c7d8cb8ac9e6b6775e9a54ef0be62dbaab592f5 (diff) | |
parent | 22c5667c2ef46d6723c1805d3adc52dc8e92429b (diff) | |
download | rails-0048897a417774f7e5a0c8c9e82fc8684f94ebc1.tar.gz rails-0048897a417774f7e5a0c8c9e82fc8684f94ebc1.tar.bz2 rails-0048897a417774f7e5a0c8c9e82fc8684f94ebc1.zip |
Merge commit 'rails/master'
Diffstat (limited to 'actionpack/lib/action_controller/abstract')
7 files changed, 116 insertions, 56 deletions
diff --git a/actionpack/lib/action_controller/abstract/base.rb b/actionpack/lib/action_controller/abstract/base.rb index 39e9ad0440..ab9aed0b26 100644 --- a/actionpack/lib/action_controller/abstract/base.rb +++ b/actionpack/lib/action_controller/abstract/base.rb @@ -1,38 +1,85 @@ module AbstractController class Base + attr_internal :response_body attr_internal :response_obj attr_internal :action_name - def self.process(action) - new.process(action) - end + class << self + attr_reader :abstract + + def abstract! + @abstract = true + end + + alias_method :abstract?, :abstract + + def internal_methods + controller = self + controller = controller.superclass until controller.abstract? + controller.public_instance_methods(true) + end + + def process(action) + new.process(action.to_s) + end - def self.inherited(klass) + def hidden_actions + [] + end + + def action_methods + @action_methods ||= + # All public instance methods of this class, including ancestors + public_instance_methods(true).map { |m| m.to_s }.to_set - + # Except for public instance methods of Base and its ancestors + internal_methods.map { |m| m.to_s } + + # Be sure to include shadowed public instance methods of this class + public_instance_methods(false).map { |m| m.to_s } - + # And always exclude explicitly hidden actions + hidden_actions + end end - + + abstract! + def initialize self.response_obj = {} end - + def process(action_name) unless respond_to_action?(action_name) raise ActionNotFound, "The action '#{action_name}' could not be found" end - + @_action_name = action_name process_action - self.response_obj[:body] = self.response_body self end - + private + + def action_methods + self.class.action_methods + end + + # It is possible for respond_to?(action_name) to be false and + # respond_to?(:action_missing) to be false if respond_to_action? + # is overridden in a subclass. For instance, ActionController::Base + # overrides it to include the case where a template matching the + # action_name is found. def process_action - respond_to?(action_name) ? send(action_name) : send(:action_missing, action_name) + if respond_to?(action_name) then send(action_name) + elsif respond_to?(:action_missing, true) then action_missing(action_name) + end end - + + # Override this to change the conditions that will raise an + # ActionNotFound error. If you accept a difference case, + # you must handle it by also overriding process_action and + # handling the case. def respond_to_action?(action_name) - respond_to?(action_name) || respond_to?(:action_missing, true) + action_methods.include?(action_name) || respond_to?(:action_missing, true) end end -end +end
\ No newline at end of file diff --git a/actionpack/lib/action_controller/abstract/callbacks.rb b/actionpack/lib/action_controller/abstract/callbacks.rb index cb8aade0be..6e15b3e81b 100644 --- a/actionpack/lib/action_controller/abstract/callbacks.rb +++ b/actionpack/lib/action_controller/abstract/callbacks.rb @@ -13,19 +13,19 @@ module AbstractController super end end - + module ClassMethods def _normalize_callback_options(options) if only = options[:only] - only = Array(only).map {|o| "action_name == :#{o}"}.join(" || ") + only = Array(only).map {|o| "action_name == '#{o}'"}.join(" || ") options[:per_key] = {:if => only} end if except = options[:except] - except = Array(except).map {|e| "action_name == :#{e}"}.join(" || ") + except = Array(except).map {|e| "action_name == '#{e}'"}.join(" || ") options[:per_key] = {:unless => except} end end - + [:before, :after, :around].each do |filter| class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 def #{filter}_filter(*names, &blk) @@ -40,4 +40,4 @@ module AbstractController end end end -end +end
\ No newline at end of file diff --git a/actionpack/lib/action_controller/abstract/exceptions.rb b/actionpack/lib/action_controller/abstract/exceptions.rb index a7d07868bb..ec4680629b 100644 --- a/actionpack/lib/action_controller/abstract/exceptions.rb +++ b/actionpack/lib/action_controller/abstract/exceptions.rb @@ -1,3 +1,3 @@ module AbstractController class ActionNotFound < StandardError ; end -end +end
\ No newline at end of file diff --git a/actionpack/lib/action_controller/abstract/helpers.rb b/actionpack/lib/action_controller/abstract/helpers.rb index 38e3ce8127..968d3080c1 100644 --- a/actionpack/lib/action_controller/abstract/helpers.rb +++ b/actionpack/lib/action_controller/abstract/helpers.rb @@ -9,13 +9,6 @@ module AbstractController self.master_helper_module = Module.new end - # def self.included(klass) - # klass.class_eval do - # extlib_inheritable_accessor :master_helper_module - # self.master_helper_module = Module.new - # end - # end - def _action_view @_action_view ||= begin av = super @@ -23,19 +16,19 @@ module AbstractController av end end - + module ClassMethods def inherited(klass) klass.master_helper_module = Module.new klass.master_helper_module.__send__ :include, master_helper_module - + super end - + def add_template_helper(mod) master_helper_module.module_eval { include mod } end - + def helper_method(*meths) meths.flatten.each do |meth| master_helper_module.class_eval <<-ruby_eval, __FILE__, __LINE__ + 1 @@ -45,7 +38,7 @@ module AbstractController ruby_eval end end - + def helper(*args, &blk) args.flatten.each do |arg| case arg @@ -56,5 +49,6 @@ module AbstractController master_helper_module.module_eval(&blk) if block_given? end end + end -end +end
\ No newline at end of file diff --git a/actionpack/lib/action_controller/abstract/layouts.rb b/actionpack/lib/action_controller/abstract/layouts.rb index 69fe4efc19..e48b8b2b4b 100644 --- a/actionpack/lib/action_controller/abstract/layouts.rb +++ b/actionpack/lib/action_controller/abstract/layouts.rb @@ -9,18 +9,18 @@ module AbstractController unless [String, Symbol, FalseClass, NilClass].include?(layout.class) raise ArgumentError, "Layouts must be specified as a String, Symbol, false, or nil" end - + @_layout = layout || false # Converts nil to false _write_layout_method end - + def _implied_layout_name name.underscore end - + # Takes the specified layout and creates a _layout method to be called # by _default_layout - # + # # If the specified layout is a: # String:: return the string # Symbol:: call the method specified by the symbol @@ -49,22 +49,26 @@ module AbstractController end end end - + def _render_template(template, options) - _action_view._render_template_with_layout(template, options[:_layout]) + _action_view._render_template_with_layout(template, options[:_layout], options) end - + private + def _layout() end # This will be overwritten - + + # :api: plugin + # ==== + # Override this to mutate the inbound layout name def _layout_for_name(name) unless [String, FalseClass, NilClass].include?(name.class) raise ArgumentError, "String, false, or nil expected; you passed #{name.inspect}" end - + name && view_paths.find_by_parts(name, {:formats => formats}, "layouts") end - + def _default_layout(require_layout = false) if require_layout && !_layout raise ArgumentError, @@ -74,9 +78,9 @@ module AbstractController begin layout = _layout_for_name(_layout) rescue NameError => e - raise NoMethodError, + raise NoMethodError, "You specified #{@_layout.inspect} as the layout, but no such method was found" end end end -end +end
\ No newline at end of file diff --git a/actionpack/lib/action_controller/abstract/logger.rb b/actionpack/lib/action_controller/abstract/logger.rb index c3bccd7778..5fb78f1755 100644 --- a/actionpack/lib/action_controller/abstract/logger.rb +++ b/actionpack/lib/action_controller/abstract/logger.rb @@ -6,4 +6,4 @@ module AbstractController cattr_accessor :logger end end -end +end
\ No newline at end of file diff --git a/actionpack/lib/action_controller/abstract/renderer.rb b/actionpack/lib/action_controller/abstract/renderer.rb index b5c31a27ee..b58688c9da 100644 --- a/actionpack/lib/action_controller/abstract/renderer.rb +++ b/actionpack/lib/action_controller/abstract/renderer.rb @@ -1,6 +1,15 @@ require "action_controller/abstract/logger" module AbstractController + class AbstractControllerError < StandardError; end + class DoubleRenderError < AbstractControllerError + DEFAULT_MESSAGE = "Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like \"redirect_to(...) and return\"." + + def initialize(message = nil) + super(message || DEFAULT_MESSAGE) + end + end + module Renderer extend ActiveSupport::DependencyModule @@ -15,31 +24,36 @@ module AbstractController end def _action_view - @_action_view ||= ActionView::Base.new(self.class.view_paths, {}, self) + @_action_view ||= ActionView::Base.new(self.class.view_paths, {}, self) end - + def render(options = {}) + if response_body + raise AbstractController::DoubleRenderError, "OMG" + end + self.response_body = render_to_body(options) end - + # Raw rendering of a template to a Rack-compatible body. # ==== # @option _prefix<String> The template's path prefix # @option _layout<String> The relative path to the layout template to use - # + # # :api: plugin def render_to_body(options = {}) name = options[:_template_name] || action_name - - template = options[:_template] || view_paths.find_by_parts(name.to_s, {:formats => formats}, options[:_prefix]) - _render_template(template, options) + + options[:_template] ||= view_paths.find_by_parts(name.to_s, {:formats => formats}, options[:_prefix]) + + _render_template(options[:_template], options) end # Raw rendering of a template to a string. # ==== # @option _prefix<String> The template's path prefix # @option _layout<String> The relative path to the layout template to use - # + # # :api: plugin def render_to_string(options = {}) AbstractController::Renderer.body_to_s(render_to_body(options)) @@ -48,7 +62,7 @@ module AbstractController def _render_template(template, options) _action_view._render_template_with_layout(template) end - + def view_paths() _view_paths end # Return a string representation of a Rack-compatible response body. @@ -64,14 +78,15 @@ module AbstractController end module ClassMethods + def append_view_path(path) self.view_paths << path end - + def view_paths self._view_paths end - + def view_paths=(paths) self._view_paths = paths.is_a?(ActionView::PathSet) ? paths : ActionView::Base.process_view_paths(paths) |