Skip to content
Browse files

Initial commit. Extracted module and test from action_controller/meta…

…l/hide_actions
  • Loading branch information...
0 parents commit ce88b6f233f919f1ef992ce27f78afbf88f50c5b @sikachu sikachu committed Jan 22, 2010
Showing with 288 additions and 0 deletions.
  1. +20 −0 MIT-LICENSE
  2. +22 −0 README
  3. +22 −0 Rakefile
  4. +3 −0 init.rb
  5. +1 −0 install.rb
  6. +49 −0 lib/action_controller/hide_actions.rb
  7. +112 −0 test/hide_actions_test.rb
  8. +59 −0 test/test_helper.rb
20 MIT-LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2010 David Heinemeier Hansson
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 README
@@ -0,0 +1,22 @@
+HideActions
+===========
+
+ActionController::HideActions adds the ability to prevent public methods on a controller
+to be called as actions.
+
+
+Example
+=======
+
+ class NonEmptyController < ActionController::Base
+ def public_action
+ render :nothing => true
+ end
+
+ hide_action :hidden_action
+ def hidden_action
+ end
+ end
+
+
+Copyright (c) 2010 David Heinemeier Hansson, released under the MIT license
22 Rakefile
@@ -0,0 +1,22 @@
+require 'rake'
+require 'rake/testtask'
+require 'rake/rdoctask'
+
+desc 'Default: run unit tests.'
+task :default => :test
+
+desc 'Test the hide_actions plugin.'
+Rake::TestTask.new(:test) do |t|
+ t.libs << 'lib'
+ t.libs << 'test'
+ t.pattern = 'test/**/*_test.rb'
+end
+
+desc 'Generate documentation for the hide_actions plugin.'
+Rake::RDocTask.new(:rdoc) do |rdoc|
+ rdoc.rdoc_dir = 'rdoc'
+ rdoc.title = 'HideActions'
+ rdoc.options << '--line-numbers' << '--inline-source'
+ rdoc.rdoc_files.include('README')
+ rdoc.rdoc_files.include('lib/**/*.rb')
+end
3 init.rb
@@ -0,0 +1,3 @@
+# Include hook code here
+
+require 'action_controller/hide_actions'
1 install.rb
@@ -0,0 +1 @@
+# Install hook code here
49 lib/action_controller/hide_actions.rb
@@ -0,0 +1,49 @@
+module ActionController
+ # ActionController::HideActions adds the ability to prevent public methods on a controller
+ # to be called as actions.
+ module HideActions
+ extend ActiveSupport::Concern
+
+ included do
+ extlib_inheritable_accessor(:hidden_actions) { Set.new }
+ end
+
+ private
+
+ # Overrides AbstractController::Base#action_method? to return false if the
+ # action name is in the list of hidden actions.
+ def action_method?(action_name)
+ self.class.visible_action?(action_name) do
+ !hidden_actions.include?(action_name) && super
+ end
+ end
+
+ module ClassMethods
+ # Sets all of the actions passed in as hidden actions.
+ #
+ # ==== Parameters
+ # *args<#to_s>:: A list of actions
+ def hide_action(*args)
+ hidden_actions.merge(args.map! {|a| a.to_s })
+ end
+
+ def inherited(klass)
+ klass.instance_variable_set("@visible_actions", {})
+ super
+ end
+
+ def visible_action?(action_name)
+ return @visible_actions[action_name] if @visible_actions.key?(action_name)
+ @visible_actions[action_name] = yield
+ end
+
+ # Overrides AbstractController::Base#action_methods to remove any methods
+ # that are listed as hidden methods.
+ def action_methods
+ @action_methods ||= Set.new(super.reject {|name| hidden_actions.include?(name)})
+ end
+ end
+ end
+end
+
+ActionController::Base.send :include, ActionController::HideActions
112 test/hide_actions_test.rb
@@ -0,0 +1,112 @@
+require 'test_helper'
+
+# Provide some controller to run the tests on.
+module Submodule
+ class ContainedEmptyController < ActionController::Base
+ end
+
+ class ContainedNonEmptyController < ActionController::Base
+ 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::Base
+end
+
+class NonEmptyController < ActionController::Base
+ def public_action
+ render :nothing => true
+ 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::Base
+ def from_view
+ render :inline => "<%= #{params[:route]} %>"
+ end
+
+ def default_url_options(options = nil)
+ { :host => 'www.override.com', :action => 'new', :locale => 'en' }
+ 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|
+ assert_equal Set.new, c.class.__send__(:action_methods), "#{c.controller_path} should be empty!"
+ end
+
+ @non_empty_controllers.each do |c|
+ assert_equal Set.new(%w(public_action)), c.class.__send__(:action_methods), "#{c.controller_path} should not be empty!"
+ end
+ end
+end
+
+class PerformActionTest < ActionController::TestCase
+ 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.nextangle.com"
+
+ rescue_action_in_public!
+ end
+
+ def test_get_on_priv_should_show_selector
+ use_controller MethodMissingController
+ get :shouldnt_be_called
+ assert_response :success
+ assert_equal 'shouldnt_be_called', @response.body
+ end
+
+ def test_get_on_hidden_should_fail
+ use_controller NonEmptyController
+ assert_raise(ActionController::UnknownAction) { get :hidden_action }
+ assert_raise(ActionController::UnknownAction) { get :another_hidden_action }
+ end
+end
59 test/test_helper.rb
@@ -0,0 +1,59 @@
+require 'rubygems'
+require 'test/unit'
+require 'active_support'
+require 'action_controller'
+require File.dirname(__FILE__) + '/../lib/action_controller/hide_actions'
+
+# Extracted this code from action_controller/abstract_unit.rb
+module SetupOnce
+ extend ActiveSupport::Concern
+
+ included do
+ cattr_accessor :setup_once_block
+ self.setup_once_block = nil
+
+ setup :run_setup_once
+ end
+
+ module ClassMethods
+ def setup_once(&block)
+ self.setup_once_block = block
+ end
+ end
+
+ private
+ def run_setup_once
+ if self.setup_once_block
+ self.setup_once_block.call
+ self.setup_once_block = nil
+ end
+ end
+end
+
+class ActiveSupport::TestCase
+ include SetupOnce
+
+ # Hold off drawing routes until all the possible controller classes
+ # have been loaded.
+ setup_once do
+ ActionController::Routing::Routes.draw do |map|
+ match ':controller(/:action(/:id))'
+ end
+ end
+end
+
+class ActionController::IntegrationTest < ActiveSupport::TestCase
+ def self.build_app(routes = nil)
+ ActionDispatch::Flash
+ ActionDispatch::MiddlewareStack.new { |middleware|
+ middleware.use "ActionDispatch::ShowExceptions"
+ middleware.use "ActionDispatch::Callbacks"
+ middleware.use "ActionDispatch::ParamsParser"
+ middleware.use "ActionDispatch::Cookies"
+ middleware.use "ActionDispatch::Flash"
+ middleware.use "ActionDispatch::Head"
+ }.build(routes || ActionController::Routing::Routes)
+ end
+
+ self.app = build_app
+end

0 comments on commit ce88b6f

Please sign in to comment.
Something went wrong with that request. Please try again.