mirror of
https://github.com/github/rails.git
synced 2026-04-26 03:00:59 -04:00
Try to build a new AC::Base on top of AbstractController
This commit is contained in:
5
actionpack/lib/action_controller/new_base.rb
Normal file
5
actionpack/lib/action_controller/new_base.rb
Normal file
@@ -0,0 +1,5 @@
|
||||
module ActionController
|
||||
autoload :AbstractBase, "action_controller/new_base/base"
|
||||
autoload :HideActions, "action_controller/new_base/hide_actions"
|
||||
autoload :UrlFor, "action_controller/new_base/url_for"
|
||||
end
|
||||
26
actionpack/lib/action_controller/new_base/base.rb
Normal file
26
actionpack/lib/action_controller/new_base/base.rb
Normal file
@@ -0,0 +1,26 @@
|
||||
module ActionController
|
||||
class AbstractBase < AbstractController::Base
|
||||
attr_internal :request, :response, :params
|
||||
|
||||
def self.controller_name
|
||||
@controller_name ||= controller_path.split("/").last
|
||||
end
|
||||
|
||||
def controller_name() self.class.controller_name end
|
||||
|
||||
def self.controller_path
|
||||
@controller_path ||= self.name.sub(/Controller$/, '').underscore
|
||||
end
|
||||
|
||||
def controller_path() self.class.controller_path end
|
||||
|
||||
def self.action_methods
|
||||
@action_names ||= Set.new(self.public_instance_methods - self::CORE_METHODS)
|
||||
end
|
||||
|
||||
def self.action_names() action_methods end
|
||||
|
||||
def action_methods() self.class.action_names end
|
||||
def action_names() action_methods end
|
||||
end
|
||||
end
|
||||
28
actionpack/lib/action_controller/new_base/hide_actions.rb
Normal file
28
actionpack/lib/action_controller/new_base/hide_actions.rb
Normal file
@@ -0,0 +1,28 @@
|
||||
module ActionController
|
||||
module HideActions
|
||||
def self.included(klass)
|
||||
klass.class_eval do
|
||||
extend ClassMethods
|
||||
extlib_inheritable_accessor :hidden_actions
|
||||
self.hidden_actions ||= Set.new
|
||||
end
|
||||
end
|
||||
|
||||
def action_methods() self.class.action_names end
|
||||
def action_names() action_methods end
|
||||
|
||||
module ClassMethods
|
||||
def hide_action(*args)
|
||||
args.each do |arg|
|
||||
self.hidden_actions << arg.to_s
|
||||
end
|
||||
end
|
||||
|
||||
def action_methods
|
||||
@action_names ||= Set.new(super.reject {|name| self.hidden_actions.include?(name.to_s)})
|
||||
end
|
||||
|
||||
def self.action_names() action_methods end
|
||||
end
|
||||
end
|
||||
end
|
||||
40
actionpack/lib/action_controller/new_base/url_for.rb
Normal file
40
actionpack/lib/action_controller/new_base/url_for.rb
Normal file
@@ -0,0 +1,40 @@
|
||||
module ActionController
|
||||
module UrlFor
|
||||
def initialize_current_url
|
||||
@url = UrlRewriter.new(request, params.clone)
|
||||
end
|
||||
|
||||
# Overwrite to implement a number of default options that all url_for-based methods will use. The default options should come in
|
||||
# the form of a hash, just like the one you would use for url_for directly. Example:
|
||||
#
|
||||
# def default_url_options(options)
|
||||
# { :project => @project.active? ? @project.url_name : "unknown" }
|
||||
# end
|
||||
#
|
||||
# As you can infer from the example, this is mostly useful for situations where you want to centralize dynamic decisions about the
|
||||
# urls as they stem from the business domain. Please note that any individual url_for call can always override the defaults set
|
||||
# by this method.
|
||||
def default_url_options(options = nil)
|
||||
end
|
||||
|
||||
def rewrite_options(options) #:nodoc:
|
||||
if defaults = default_url_options(options)
|
||||
defaults.merge(options)
|
||||
else
|
||||
options
|
||||
end
|
||||
end
|
||||
|
||||
def url_for(options = {})
|
||||
options ||= {}
|
||||
case options
|
||||
when String
|
||||
options
|
||||
when Hash
|
||||
@url.rewrite(rewrite_options(options))
|
||||
else
|
||||
polymorphic_url(options)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
317
actionpack/test/new_base/base_test.rb
Normal file
317
actionpack/test/new_base/base_test.rb
Normal file
@@ -0,0 +1,317 @@
|
||||
$:.unshift(File.dirname(__FILE__) + '/../../lib')
|
||||
$:.unshift(File.dirname(__FILE__) + '/../../../activesupport/lib')
|
||||
|
||||
require 'test/unit'
|
||||
require 'active_support'
|
||||
require 'active_support/test_case'
|
||||
require 'action_controller'
|
||||
require 'action_view/base'
|
||||
|
||||
begin
|
||||
require 'ruby-debug'
|
||||
Debugger.settings[:autoeval] = true
|
||||
Debugger.start
|
||||
rescue LoadError
|
||||
# Debugging disabled. `gem install ruby-debug` to enable.
|
||||
end
|
||||
|
||||
require 'action_controller/abstract'
|
||||
require 'action_controller/new_base'
|
||||
require 'pp' # require 'pp' early to prevent hidden_methods from not picking up the pretty-print methods until too late
|
||||
|
||||
require 'rubygems'
|
||||
require 'rack/test'
|
||||
|
||||
module ActionController
|
||||
module TestProcess
|
||||
def process(action, parameters = nil, session = nil, flash = nil, http_method = 'GET')
|
||||
# Sanity check for required instance variables so we can give an
|
||||
# understandable error message.
|
||||
%w(@controller @request @response).each do |iv_name|
|
||||
if !(instance_variable_names.include?(iv_name) || instance_variable_names.include?(iv_name.to_sym)) || instance_variable_get(iv_name).nil?
|
||||
raise "#{iv_name} is nil: make sure you set it in your test's setup method."
|
||||
end
|
||||
end
|
||||
|
||||
@request.recycle!
|
||||
@response.recycle!
|
||||
|
||||
@html_document = nil
|
||||
@request.env['REQUEST_METHOD'] = http_method
|
||||
|
||||
@request.action = action.to_s
|
||||
|
||||
parameters ||= {}
|
||||
@request.assign_parameters(@controller.class.controller_path, action.to_s, parameters)
|
||||
|
||||
@request.session = ActionController::TestSession.new(session) unless session.nil?
|
||||
@request.session["flash"] = ActionController::Flash::FlashHash.new.update(flash) if flash
|
||||
build_request_uri(action, parameters)
|
||||
|
||||
# Base.class_eval { include ProcessWithTest } unless Base < ProcessWithTest
|
||||
@controller.request = @request
|
||||
@controller.response = @response
|
||||
@controller.process(action)
|
||||
end
|
||||
end
|
||||
|
||||
class Base2 < AbstractBase
|
||||
include AbstractController::Callbacks
|
||||
include AbstractController::Renderer
|
||||
include AbstractController::Helpers
|
||||
include AbstractController::Layouts
|
||||
include AbstractController::Logger
|
||||
|
||||
include ActionController::HideActions
|
||||
include ActionController::UrlFor
|
||||
|
||||
CORE_METHODS = self.public_instance_methods
|
||||
end
|
||||
end
|
||||
|
||||
# Provide some controller to run the tests on.
|
||||
module Submodule
|
||||
class ContainedEmptyController < ActionController::Base2
|
||||
end
|
||||
class ContainedNonEmptyController < ActionController::Base2
|
||||
def public_action
|
||||
render :nothing => true
|
||||
end
|
||||
|
||||
hide_action :hidden_action
|
||||
def hidden_action
|
||||
raise "Noooo!"
|
||||
end
|
||||
|
||||
def another_hidden_action
|
||||
end
|
||||
hide_action :another_hidden_action
|
||||
end
|
||||
class SubclassedController < ContainedNonEmptyController
|
||||
hide_action :public_action # Hiding it here should not affect the superclass.
|
||||
end
|
||||
end
|
||||
class EmptyController < ActionController::Base2
|
||||
end
|
||||
class NonEmptyController < ActionController::Base2
|
||||
def public_action
|
||||
end
|
||||
|
||||
hide_action :hidden_action
|
||||
def hidden_action
|
||||
end
|
||||
end
|
||||
|
||||
class MethodMissingController < ActionController::Base
|
||||
|
||||
hide_action :shouldnt_be_called
|
||||
def shouldnt_be_called
|
||||
raise "NO WAY!"
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def method_missing(selector)
|
||||
render :text => selector.to_s
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class DefaultUrlOptionsController < ActionController::Base2
|
||||
def default_url_options_action
|
||||
end
|
||||
|
||||
def default_url_options(options = nil)
|
||||
{ :host => 'www.override.com', :action => 'new', :bacon => 'chunky' }
|
||||
end
|
||||
end
|
||||
|
||||
class ControllerClassTests < Test::Unit::TestCase
|
||||
def test_controller_path
|
||||
assert_equal 'empty', EmptyController.controller_path
|
||||
assert_equal EmptyController.controller_path, EmptyController.new.controller_path
|
||||
assert_equal 'submodule/contained_empty', Submodule::ContainedEmptyController.controller_path
|
||||
assert_equal Submodule::ContainedEmptyController.controller_path, Submodule::ContainedEmptyController.new.controller_path
|
||||
end
|
||||
def test_controller_name
|
||||
assert_equal 'empty', EmptyController.controller_name
|
||||
assert_equal 'contained_empty', Submodule::ContainedEmptyController.controller_name
|
||||
end
|
||||
end
|
||||
|
||||
class ControllerInstanceTests < Test::Unit::TestCase
|
||||
def setup
|
||||
@empty = EmptyController.new
|
||||
@contained = Submodule::ContainedEmptyController.new
|
||||
@empty_controllers = [@empty, @contained, Submodule::SubclassedController.new]
|
||||
|
||||
@non_empty_controllers = [NonEmptyController.new,
|
||||
Submodule::ContainedNonEmptyController.new]
|
||||
end
|
||||
|
||||
def test_action_methods
|
||||
@empty_controllers.each do |c|
|
||||
hide_mocha_methods_from_controller(c)
|
||||
assert_equal Set.new, c.__send__(:action_methods), "#{c.controller_path} should be empty!"
|
||||
end
|
||||
@non_empty_controllers.each do |c|
|
||||
hide_mocha_methods_from_controller(c)
|
||||
assert_equal Set.new(%w(public_action)), c.__send__(:action_methods), "#{c.controller_path} should not be empty!"
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
# Mocha adds some public instance methods to Object that would be
|
||||
# considered actions, so explicitly hide_action them.
|
||||
def hide_mocha_methods_from_controller(controller)
|
||||
mocha_methods = [
|
||||
:expects, :mocha, :mocha_inspect, :reset_mocha, :stubba_object,
|
||||
:stubba_method, :stubs, :verify, :__metaclass__, :__is_a__, :to_matcher,
|
||||
]
|
||||
controller.class.__send__(:hide_action, *mocha_methods)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
class PerformActionTest < ActiveSupport::TestCase
|
||||
class MockLogger
|
||||
attr_reader :logged
|
||||
|
||||
def initialize
|
||||
@logged = []
|
||||
end
|
||||
|
||||
def method_missing(method, *args)
|
||||
@logged << args.first
|
||||
end
|
||||
end
|
||||
|
||||
def use_controller(controller_class)
|
||||
@controller = controller_class.new
|
||||
|
||||
# enable a logger so that (e.g.) the benchmarking stuff runs, so we can get
|
||||
# a more accurate simulation of what happens in "real life".
|
||||
@controller.logger = Logger.new(nil)
|
||||
|
||||
@request = ActionController::TestRequest.new
|
||||
@response = ActionController::TestResponse.new
|
||||
|
||||
@request.host = "www.nxtangle.com"
|
||||
|
||||
rescue_action_in_public!
|
||||
end
|
||||
|
||||
attr_accessor :app
|
||||
include Rack::Test::Methods
|
||||
|
||||
def with_routing
|
||||
real_routes = ActionController::Routing::Routes
|
||||
ActionController::Routing.module_eval { remove_const :Routes }
|
||||
|
||||
temporary_routes = ActionController::Routing::RouteSet.new
|
||||
ActionController::Routing.module_eval { const_set :Routes, temporary_routes }
|
||||
|
||||
yield temporary_routes
|
||||
ensure
|
||||
if ActionController::Routing.const_defined? :Routes
|
||||
ActionController::Routing.module_eval { remove_const :Routes }
|
||||
end
|
||||
ActionController::Routing.const_set(:Routes, real_routes) if real_routes
|
||||
end
|
||||
|
||||
def test_get_on_priv_should_show_selector
|
||||
ActionController::Base.session_options[:key] = "abc"
|
||||
ActionController::Base.session_options[:secret] = ("*" * 30)
|
||||
|
||||
with_routing do |set|
|
||||
set.draw do |map|
|
||||
map.connect ':controller/:action'
|
||||
end
|
||||
|
||||
@app = ActionController::Dispatcher.new
|
||||
|
||||
resp = get "/method_missing/shouldnt_be_called"
|
||||
assert_equal 'shouldnt_be_called', resp.body
|
||||
end
|
||||
|
||||
# use_controller MethodMissingController
|
||||
# get :shouldnt_be_called
|
||||
# assert_response :success
|
||||
# assert_equal 'shouldnt_be_called', @response.body
|
||||
end
|
||||
|
||||
def test_method_missing_is_not_an_action_name
|
||||
use_controller MethodMissingController
|
||||
assert ! @controller.__send__(:action_methods).include?('method_missing')
|
||||
|
||||
get :method_missing
|
||||
assert_response :success
|
||||
assert_equal 'method_missing', @response.body
|
||||
end
|
||||
|
||||
def test_get_on_hidden_should_fail
|
||||
use_controller NonEmptyController
|
||||
get :hidden_action
|
||||
assert_response 404
|
||||
|
||||
get :another_hidden_action
|
||||
assert_response 404
|
||||
end
|
||||
|
||||
def test_namespaced_action_should_log_module_name
|
||||
use_controller Submodule::ContainedNonEmptyController
|
||||
@controller.logger = MockLogger.new
|
||||
get :public_action
|
||||
assert_match /Processing\sSubmodule::ContainedNonEmptyController#public_action/, @controller.logger.logged[1]
|
||||
end
|
||||
end
|
||||
|
||||
class DefaultUrlOptionsTest < ActionController::TestCase
|
||||
tests DefaultUrlOptionsController
|
||||
|
||||
def setup
|
||||
@request.host = 'www.example.com'
|
||||
rescue_action_in_public!
|
||||
end
|
||||
|
||||
def test_default_url_options_are_used_if_set
|
||||
ActionController::Routing::Routes.draw do |map|
|
||||
map.default_url_options 'default_url_options', :controller => 'default_url_options'
|
||||
map.connect ':controller/:action/:id'
|
||||
end
|
||||
|
||||
get :default_url_options_action # Make a dummy request so that the controller is initialized properly.
|
||||
|
||||
assert_equal 'http://www.override.com/default_url_options/new?bacon=chunky', @controller.url_for(:controller => 'default_url_options')
|
||||
assert_equal 'http://www.override.com/default_url_options?bacon=chunky', @controller.send(:default_url_options_url)
|
||||
ensure
|
||||
ActionController::Routing::Routes.load!
|
||||
end
|
||||
end
|
||||
|
||||
class EmptyUrlOptionsTest < ActionController::TestCase
|
||||
tests NonEmptyController
|
||||
|
||||
def setup
|
||||
@request.host = 'www.example.com'
|
||||
rescue_action_in_public!
|
||||
end
|
||||
|
||||
def test_ensure_url_for_works_as_expected_when_called_with_no_options_if_default_url_options_is_not_set
|
||||
get :public_action
|
||||
assert_equal "http://www.example.com/non_empty/public_action", @controller.url_for
|
||||
end
|
||||
end
|
||||
|
||||
class EnsureNamedRoutesWorksTicket22BugTest < Test::Unit::TestCase
|
||||
def test_named_routes_still_work
|
||||
ActionController::Routing::Routes.draw do |map|
|
||||
map.resources :things
|
||||
end
|
||||
EmptyController.send :include, ActionController::UrlWriter
|
||||
|
||||
assert_equal '/things', EmptyController.new.send(:things_path)
|
||||
ensure
|
||||
ActionController::Routing::Routes.load!
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user