Permalink
Browse files

Ported over the concept of public instance methods on controller chil…

…d classes as callable action methods
  • Loading branch information...
1 parent d58b57a commit 4ee3e5b094463383891789f484e927b19fccc744 Yehuda Katz + Carl Lerche committed Apr 30, 2009
@@ -4,13 +4,44 @@ class Base
attr_internal :response_body
attr_internal :response_obj
attr_internal :action_name
-
- def self.process(action)
- new.process(action)
+
+ 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)
+ end
+
+ 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_sym }.to_set -
+ # Except for public instance methods of Base and its ancestors
+ internal_methods.map { |m| m.to_sym } +
+ # Be sure to include shadowed public instance methods of this class
+ public_instance_methods(false).map { |m| m.to_sym } -
+ # And always exclude explicitly hidden actions
+ hidden_actions
+ end
end
- def self.inherited(klass)
- end
+ abstract!
def initialize
self.response_obj = {}
@@ -29,6 +60,10 @@ def process(action_name)
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
@@ -45,8 +80,7 @@ def process_action
# 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
@@ -1,5 +1,6 @@
module ActionController
class Http < AbstractController::Base
+ abstract!
# :api: public
attr_internal :request, :response, :params
@@ -19,18 +20,15 @@ def self.controller_path
# :api: public
def controller_path() self.class.controller_path end
-
- # :api: private
- def self.action_methods
- @action_names ||= Set.new(self.public_instance_methods - self::CORE_METHODS)
+
+ # :api: private
+ def self.internal_methods
+ ActionController::Http.public_instance_methods(true)
end
# :api: private
def self.action_names() action_methods end
- # :api: private
- def action_methods() self.class.action_names end
-
# :api: private
def action_names() action_methods end
@@ -44,7 +42,7 @@ def self.call(env)
def call(env)
@_request = ActionDispatch::Request.new(env)
@_response = ActionDispatch::Response.new
- process(@_request.parameters[:action])
+ process(@_request.parameters[:action].to_sym)
@_response.body = response_body
@_response.prepare!
self
@@ -4,6 +4,7 @@
module Fun
class GamesController < ActionController::Base
+ # :ported:
def hello_world
end
end
@@ -116,6 +117,7 @@ def render_hello_world_from_variable
render :text => "hello #{@person}"
end
+ # :ported:
def render_action_hello_world
render :action => "hello_world"
end
@@ -839,17 +841,20 @@ def test_render_from_variable
assert_equal "hello david", @response.body
end
+ # :ported:
def test_render_action
get :render_action_hello_world
assert_template "test/hello_world"
end
+ # :ported:
def test_render_action_hello_world_as_string
get :render_action_hello_world_as_string
assert_equal "Hello world!", @response.body
assert_template "test/hello_world"
end
+ # :ported:
def test_render_action_with_symbol
get :render_action_hello_world_with_symbol
assert_template "test/hello_world"
@@ -949,6 +954,7 @@ def test_render_json_with_render_to_string
assert_equal 'application/json', @response.content_type
end
+ # :ported:
def test_render_custom_code
get :render_custom_code
assert_response 404
@@ -1082,6 +1088,7 @@ def test_render_to_string_inline
assert_template "test/hello_world"
end
+ # :ported:
def test_nested_rendering
@controller = Fun::GamesController.new
get :hello_world
@@ -35,4 +35,14 @@ class TestBasic < SimpleRouteCase
end
end
end
+
+ class TestRenderObjectMethod < SimpleRouteCase
+ describe "Methods on Object are not actions"
+
+ test "raises an exception" do
+ assert_raises(AbstractController::ActionNotFound) do
+ get "/render/blank_render/clone"
+ end
+ end
+ end
end
@@ -34,6 +34,8 @@ def x.test?() true end
module ActionController
class Base2 < Http
+ abstract!
+
use AbstractController::Callbacks
use AbstractController::Helpers
use AbstractController::Logger
@@ -80,15 +82,13 @@ def process_action
end
def respond_to_action?(action_name)
- super || view_paths.find_by_parts(action_name, {:formats => formats, :locales => [I18n.locale]}, controller_path)
+ super || view_paths.find_by_parts?(action_name.to_s, {:formats => formats, :locales => [I18n.locale]}, controller_path)
end
-
- # append_view_path File.join(File.dirname(__FILE__), '..', 'fixtures')
-
- CORE_METHODS = self.public_instance_methods
end
class CompatibleBase2 < Base2
+ abstract!
+
use ActionController::Rails2Compatibility
end
end

0 comments on commit 4ee3e5b

Please sign in to comment.