-
Notifications
You must be signed in to change notification settings - Fork 21.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Motivation is twofold: * We are gradually removing `require_dependency` from the framework. * Let `helper` work if `config.add_autoload_paths_to_load_path` is disabled. Co-authored-by: Jean Boussier <jean.boussier@gmail.com>
- Loading branch information
Showing
5 changed files
with
104 additions
and
83 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -74,39 +74,56 @@ def #{method}(*args, &block) # def current_user(*args, &block | |
end | ||
end | ||
|
||
# The +helper+ class method can take a series of helper module names, a block, or both. | ||
# Includes the given modules in the template class. | ||
# | ||
# ==== Options | ||
# * <tt>*args</tt> - Module, Symbol, String | ||
# * <tt>block</tt> - A block defining helper methods | ||
# Modules can be specified in different ways. All of the following calls | ||
# include +FooHelper+: | ||
# | ||
# When the argument is a module it will be included directly in the template class. | ||
# helper FooHelper # => includes FooHelper | ||
# # Module, recommended. | ||
# helper FooHelper | ||
# | ||
# 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 | ||
# # String/symbol without the "helper" suffix, camel or snake case. | ||
# helper "Foo" | ||
# helper :Foo | ||
# helper "foo" | ||
# helper :foo | ||
# | ||
# Additionally, the +helper+ class method can receive and evaluate a block, making the methods defined available | ||
# to the template. | ||
# The last two assume that <tt>"foo".camelize</tt> returns "Foo". | ||
# | ||
# # One line | ||
# helper { def hello() "Hello, world!" end } | ||
# When strings or symbols are passed, the method finds the actual module | ||
# object using +String#constantize+. Therefore, if the module has not been | ||
# yet loaded, it has to be autoloadable, which is normally the case. | ||
# | ||
# Namespaces are supported. The following calls include +Foo::BarHelper+: | ||
# | ||
# # Module, recommended. | ||
# helper Foo::BarHelper | ||
# | ||
# # String/symbol without the "helper" suffix, camel or snake case. | ||
# helper "Foo::Bar" | ||
# helper :"Foo::Bar" | ||
# helper "foo/bar" | ||
# helper :"foo/bar" | ||
# | ||
# The last two assume that <tt>"foo/bar".camelize</tt> returns "Foo::Bar". | ||
# | ||
# The method accepts a block too. If present, the block is evaluated in | ||
# the context of the controller helper module. This simple call makes the | ||
# +wadus+ method available in templates of the enclosing controller: | ||
# | ||
# # Multi-line | ||
# helper do | ||
# def foo(bar) | ||
# "#{bar} is the very best" | ||
# def wadus | ||
# "wadus" | ||
# 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. | ||
# Furthermore, all the above styles can be mixed together: | ||
# | ||
# helper(:three, BlindHelper) { def mice() 'mice' end } | ||
# helper FooHelper, "woo", "bar/baz" do | ||
# def wadus | ||
# "wadus" | ||
# end | ||
# end | ||
# | ||
def helper(*args, &block) | ||
modules_for_helpers(args).each do |mod| | ||
|
@@ -127,46 +144,17 @@ def clear_helpers | |
default_helper_module! unless anonymous? | ||
end | ||
|
||
# Returns a list of modules, normalized from the acceptable kinds of | ||
# helpers with the following behavior: | ||
# | ||
# String or Symbol:: :FooBar or "FooBar" becomes "foo_bar_helper", | ||
# and "foo_bar_helper.rb" is loaded using require_dependency. | ||
# | ||
# Module:: No further processing | ||
# | ||
# After loading the appropriate files, the corresponding modules | ||
# are returned. | ||
# | ||
# ==== Parameters | ||
# * <tt>args</tt> - An array of helpers | ||
# | ||
# ==== Returns | ||
# * <tt>Array</tt> - A normalized list of modules for the list of | ||
# helpers provided. | ||
def modules_for_helpers(args) | ||
args.flatten.map! do |arg| | ||
case arg | ||
when String, Symbol | ||
file_name = "#{arg.to_s.underscore}_helper" | ||
begin | ||
require_dependency(file_name) | ||
rescue LoadError => e | ||
raise AbstractController::Helpers::MissingHelperError.new(e, file_name) | ||
end | ||
|
||
mod_name = file_name.camelize | ||
begin | ||
mod_name.constantize | ||
rescue LoadError | ||
# dependencies.rb gives a similar error message but its wording is | ||
# not as clear because it mentions autoloading. To the user all it | ||
# matters is that a helper module couldn't be loaded, autoloading | ||
# is an internal mechanism that should not leak. | ||
raise NameError, "Couldn't find #{mod_name}, expected it to be defined in helpers/#{file_name}.rb" | ||
end | ||
# Given an array of values like the ones accepted by +helper+, this method | ||
# returns an array with the corresponding modules, in the same order. | ||
def modules_for_helpers(modules_or_helper_prefixes) | ||
modules_or_helper_prefixes.flatten.map! do |module_or_helper_prefix| | ||
case module_or_helper_prefix | ||
when Module | ||
arg | ||
module_or_helper_prefix | ||
when String, Symbol | ||
helper_prefix = module_or_helper_prefix.to_s | ||
helper_prefix = helper_prefix.camelize unless helper_prefix.start_with?(/[A-Z]/) | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
fxn
Author
Member
|
||
"#{helper_prefix}Helper".constantize | ||
else | ||
raise ArgumentError, "helper must be a String, Symbol, or Module" | ||
end | ||
|
@@ -186,13 +174,10 @@ def define_helpers_module(klass, helpers = nil) | |
end | ||
|
||
def default_helper_module! | ||
module_name = name.sub(/Controller$/, "") | ||
module_path = module_name.underscore | ||
helper module_path | ||
rescue LoadError => e | ||
raise e unless e.is_missing? "helpers/#{module_path}_helper" | ||
helper_prefix = name.delete_suffix("Controller") | ||
helper(helper_prefix) | ||
rescue NameError => e | ||
raise e unless e.missing_name? "#{module_name}Helper" | ||
raise unless e.missing_name?("#{helper_prefix}Helper") | ||
end | ||
end | ||
end | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
The unless on this row is not working if the subdirectory we're in starts with an uppercase letter, for example:
SaasySimple/application
would result in the helper_prefix variable to remain asSaasySimple/application
whereas it should be camelized so it can be transformed intoSaasySimple::Application