Permalink
Browse files

Add all the existing helpers related features to the new base

  • Loading branch information...
1 parent 1d168af commit e976c489e6416cdc4714721df78dd43dd6d13d99 @lifo lifo committed May 22, 2009
View
@@ -66,7 +66,7 @@ Rake::TestTask.new(:test_new_base_on_old_tests) do |t|
render render_json render_xml
send_file request_forgery_protection rescue url_rewriter verification webservice
http_basic_authentication http_digest_authentication
- action_pack_assertions assert_select filter_params
+ action_pack_assertions assert_select filter_params helper
).map { |name| "test/controller/#{name}_test.rb" }
end
@@ -24,11 +24,30 @@ def inherited(klass)
super
end
-
+
+ # Makes all the (instance) methods in the helper module available to templates rendered through this controller.
+ # See ActionView::Helpers (link:classes/ActionView/Helpers.html) for more about making your own helper modules
+ # available to the templates.
def add_template_helper(mod)
master_helper_module.module_eval { include mod }
end
-
+
+ # Declare a controller method as a helper. For example, the following
+ # makes the +current_user+ controller method available to the view:
+ # class ApplicationController < ActionController::Base
+ # helper_method :current_user, :logged_in?
+ #
+ # def current_user
+ # @current_user ||= User.find_by_id(session[:user])
+ # end
+ #
+ # def logged_in?
+ # current_user != nil
+ # end
+ # end
+ #
+ # In a view:
+ # <% if logged_in? -%>Welcome, <%= current_user.name %><% end -%>
def helper_method(*meths)
meths.flatten.each do |meth|
master_helper_module.class_eval <<-ruby_eval, __FILE__, __LINE__ + 1
@@ -39,14 +58,14 @@ def #{meth}(*args, &blk)
end
end
- def helper(*args, &blk)
+ def helper(*args, &block)
args.flatten.each do |arg|
case arg
when Module
add_template_helper(arg)
end
end
- master_helper_module.module_eval(&blk) if block_given?
+ master_helper_module.module_eval(&block) if block_given?
end
end
@@ -3,23 +3,19 @@
# FIXME: helper { ... } is broken on Ruby 1.9
module ActionController #:nodoc:
module Helpers #:nodoc:
- def self.included(base)
+ extend ActiveSupport::DependencyModule
+
+ included do
# Initialize the base module to aggregate its helpers.
- base.class_inheritable_accessor :master_helper_module
- base.master_helper_module = Module.new
+ class_inheritable_accessor :master_helper_module
+ self.master_helper_module = Module.new
# Set the default directory for helpers
- base.class_inheritable_accessor :helpers_dir
- base.helpers_dir = (defined?(RAILS_ROOT) ? "#{RAILS_ROOT}/app/helpers" : "app/helpers")
-
- # Extend base with class methods to declare helpers.
- base.extend(ClassMethods)
+ class_inheritable_accessor :helpers_dir
+ self.helpers_dir = (defined?(RAILS_ROOT) ? "#{RAILS_ROOT}/app/helpers" : "app/helpers")
- base.class_eval do
- # Wrap inherited to create a new master helper module for subclasses.
- class << self
- alias_method_chain :inherited, :helper
- end
+ class << self
+ alias_method_chain :inherited, :helper
end
end
@@ -13,6 +13,7 @@ module ActionController
autoload :Testing, "action_controller/new_base/testing"
autoload :UrlFor, "action_controller/new_base/url_for"
autoload :Session, "action_controller/new_base/session"
+ autoload :Helpers, "action_controller/new_base/helpers"
# Ported modules
# require 'action_controller/routing'
@@ -4,9 +4,9 @@ class Base < Http
include AbstractController::Benchmarker
include AbstractController::Callbacks
- include AbstractController::Helpers
include AbstractController::Logger
-
+
+ include ActionController::Helpers
include ActionController::HideActions
include ActionController::UrlFor
include ActionController::Redirector
@@ -0,0 +1,133 @@
+require 'active_support/core_ext/load_error'
+require 'active_support/core_ext/name_error'
+require 'active_support/dependencies'
+
+module ActionController
+ module Helpers
+ extend ActiveSupport::DependencyModule
+
+ depends_on AbstractController::Helpers
+
+ included do
+ # Set the default directory for helpers
+ class_inheritable_accessor :helpers_dir
+ self.helpers_dir = (defined?(RAILS_ROOT) ? "#{RAILS_ROOT}/app/helpers" : "app/helpers")
+ end
+
+ module ClassMethods
+ def inherited(klass)
+ # klass.master_helper_module = Module.new
+ # klass.master_helper_module.__send__ :include, master_helper_module
+ klass.__send__ :default_helper_module!
+ super
+ end
+
+ # The +helper+ class method can take a series of helper module names, a block, or both.
+ #
+ # * <tt>*args</tt>: One or more modules, strings or symbols, or the special symbol <tt>:all</tt>.
+ # * <tt>&block</tt>: A block defining helper methods.
+ #
+ # ==== Examples
+ # When the argument is a string or symbol, the method will provide the "_helper" suffix, require the file
+ # and include the module in the template class. The second form illustrates how to include custom helpers
+ # when working with namespaced controllers, or other cases where the file containing the helper definition is not
+ # in one of Rails' standard load paths:
+ # helper :foo # => requires 'foo_helper' and includes FooHelper
+ # helper 'resources/foo' # => requires 'resources/foo_helper' and includes Resources::FooHelper
+ #
+ # When the argument is a module it will be included directly in the template class.
+ # helper FooHelper # => includes FooHelper
+ #
+ # When the argument is the symbol <tt>:all</tt>, the controller will include all helpers beneath
+ # <tt>ActionController::Base.helpers_dir</tt> (defaults to <tt>app/helpers/**/*.rb</tt> under RAILS_ROOT).
+ # helper :all
+ #
+ # Additionally, the +helper+ class method can receive and evaluate a block, making the methods defined available
+ # to the template.
+ # # One line
+ # helper { def hello() "Hello, world!" end }
+ # # Multi-line
+ # helper do
+ # def foo(bar)
+ # "#{bar} is the very best"
+ # end
+ # end
+ #
+ # Finally, all the above styles can be mixed together, and the +helper+ method can be invoked with a mix of
+ # +symbols+, +strings+, +modules+ and blocks.
+ # helper(:three, BlindHelper) { def mice() 'mice' end }
+ #
+ def helper(*args, &block)
+ args.flatten.each do |arg|
+ case arg
+ when :all
+ helper all_application_helpers
+ when String, Symbol
+ file_name = arg.to_s.underscore + '_helper'
+ class_name = file_name.camelize
+
+ begin
+ require_dependency(file_name)
+ rescue LoadError => load_error
+ requiree = / -- (.*?)(\.rb)?$/.match(load_error.message).to_a[1]
+ if requiree == file_name
+ msg = "Missing helper file helpers/#{file_name}.rb"
+ raise LoadError.new(msg).copy_blame!(load_error)
+ else
+ raise
+ end
+ end
+
+ add_template_helper(class_name.constantize)
+ else
+ # Explcit 'return' here so that the supplied block ( if any ) doesn't get included twice
+ return super
+ end
+ end
+
+ # Evaluate block in template class if given.
+ master_helper_module.module_eval(&block) if block_given?
+ end
+
+ # Declares helper accessors for controller attributes. For example, the
+ # following adds new +name+ and <tt>name=</tt> instance methods to a
+ # controller and makes them available to the view:
+ # helper_attr :name
+ # attr_accessor :name
+ def helper_attr(*attrs)
+ attrs.flatten.each { |attr| helper_method(attr, "#{attr}=") }
+ end
+
+ # Provides a proxy to access helpers methods from outside the view.
+ def helpers
+ unless @helper_proxy
+ @helper_proxy = ActionView::Base.new
+ @helper_proxy.extend master_helper_module
+ else
+ @helper_proxy
+ end
+ end
+
+ private
+
+ def default_helper_module!
+ unless name.blank?
+ module_name = name.sub(/Controller$|$/, 'Helper')
+ module_path = module_name.split('::').map { |m| m.underscore }.join('/')
+ require_dependency module_path
+ helper module_name.constantize
+ end
+ rescue MissingSourceFile => e
+ raise unless e.is_missing? module_path
+ rescue NameError => e
+ raise unless e.missing_name? module_name
+ end
+
+ # Extract helper names from files in app/helpers/**/*.rb
+ def all_application_helpers
+ extract = /^#{Regexp.quote(helpers_dir)}\/?(.*)_helper.rb$/
+ Dir["#{helpers_dir}/**/*_helper.rb"].map { |file| file.sub extract, '\1' }
+ end
+ end # ClassMethods
+ end
+end
@@ -27,7 +27,7 @@ def rescue_action(e) raise end
end
end
-class ApplicationController < ActionController::Base
+class AllHelpersController < ActionController::Base
helper :all
end
@@ -127,7 +127,7 @@ def test_helper_for_acronym_controller
end
def test_all_helpers
- methods = ApplicationController.master_helper_module.instance_methods.map(&:to_s)
+ methods = AllHelpersController.master_helper_module.instance_methods.map(&:to_s)
# abc_helper.rb
assert methods.include?('bare_a')
@@ -154,7 +154,7 @@ def test_all_helpers_with_alternate_helper_dir
end
def test_helper_proxy
- methods = ApplicationController.helpers.methods.map(&:to_s)
+ methods = AllHelpersController.helpers.methods.map(&:to_s)
# ActionView
assert methods.include?('pluralize')
@@ -2,6 +2,9 @@
$:.unshift(File.dirname(__FILE__) + '/../../../activesupport/lib')
$:.unshift(File.dirname(__FILE__) + '/../lib')
+$:.unshift(File.dirname(__FILE__) + '/../fixtures/helpers')
+$:.unshift(File.dirname(__FILE__) + '/../fixtures/alternate_helpers')
+
ENV['new_base'] = "true"
$stderr.puts "Running old tests on new_base"
@@ -1,8 +1,5 @@
require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper")
-class ApplicationController < ActionController::Base
-end
-
module RenderText
class SimpleController < ActionController::Base
self.view_paths = [ActionView::Template::FixturePath.new]

0 comments on commit e976c48

Please sign in to comment.