aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_view/lookup_context.rb
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib/action_view/lookup_context.rb')
-rw-r--r--actionpack/lib/action_view/lookup_context.rb229
1 files changed, 112 insertions, 117 deletions
diff --git a/actionpack/lib/action_view/lookup_context.rb b/actionpack/lib/action_view/lookup_context.rb
index 560df15e82..fa4bf70f77 100644
--- a/actionpack/lib/action_view/lookup_context.rb
+++ b/actionpack/lib/action_view/lookup_context.rb
@@ -1,5 +1,6 @@
require 'active_support/core_ext/array/wrap'
require 'active_support/core_ext/object/blank'
+require 'active_support/core_ext/module/remove_method'
module ActionView
# = Action View Lookup Context
@@ -17,23 +18,25 @@ module ActionView
mattr_accessor :registered_details
self.registered_details = []
- mattr_accessor :registered_detail_setters
- self.registered_detail_setters = []
-
def self.register_detail(name, options = {}, &block)
self.registered_details << name
- self.registered_detail_setters << [name, "#{name}="]
+ initialize = registered_details.map { |n| "self.#{n} = details[:#{n}]" }
- Accessors.send :define_method, :"_#{name}_defaults", &block
+ Accessors.send :define_method, :"default_#{name}", &block
Accessors.module_eval <<-METHOD, __FILE__, __LINE__ + 1
def #{name}
@details[:#{name}]
end
def #{name}=(value)
- value = Array.wrap(value.presence || _#{name}_defaults)
+ value = Array.wrap(value.presence || default_#{name})
_set_detail(:#{name}, value) if value != @details[:#{name}]
end
+
+ remove_possible_method :initialize_details
+ def initialize_details(details)
+ #{initialize.join("\n")}
+ end
METHOD
end
@@ -41,8 +44,9 @@ module ActionView
module Accessors #:nodoc:
end
- register_detail(:formats) { Mime::SET.symbols }
register_detail(:locale) { [I18n.locale, I18n.default_locale] }
+ register_detail(:formats) { Mime::SET.symbols }
+ register_detail(:handlers){ Template::Handlers.extensions }
class DetailsKey #:nodoc:
alias :eql? :equal?
@@ -60,38 +64,54 @@ module ActionView
end
end
- def initialize(view_paths, details = {}, prefixes = [])
- @details, @details_key = { :handlers => default_handlers }, nil
- @frozen_formats, @skip_default_locale = false, false
- @cache = true
- @prefixes = prefixes
+ # Add caching behavior on top of Details.
+ module DetailsCache
+ attr_accessor :cache
- self.view_paths = view_paths
- self.registered_detail_setters.each do |key, setter|
- send(setter, details[key])
+ # Calculate the details key. Remove the handlers from calculation to improve performance
+ # since the user cannot modify it explicitly.
+ def details_key #:nodoc:
+ @details_key ||= DetailsKey.get(@details) if @cache
+ end
+
+ # Temporary skip passing the details_key forward.
+ def disable_cache
+ old_value, @cache = @cache, false
+ yield
+ ensure
+ @cache = old_value
+ end
+
+ protected
+
+ def _set_detail(key, value)
+ @details_key = nil
+ @details = @details.dup if @details.frozen?
+ @details[key] = value.freeze
end
end
+ # Helpers related to template lookup using the lookup context information.
module ViewPaths
attr_reader :view_paths
# Whenever setting view paths, makes a copy so we can manipulate then in
# instance objects as we wish.
def view_paths=(paths)
- @view_paths = ActionView::Base.process_view_paths(paths)
+ @view_paths = ActionView::PathSet.new(Array.wrap(paths))
end
- def find(name, prefixes = [], partial = false, keys = [])
- @view_paths.find(*args_for_lookup(name, prefixes, partial, keys))
+ def find(name, prefixes = [], partial = false, keys = [], options = {})
+ @view_paths.find(*args_for_lookup(name, prefixes, partial, keys, options))
end
alias :find_template :find
- def find_all(name, prefixes = [], partial = false, keys = [])
- @view_paths.find_all(*args_for_lookup(name, prefixes, partial, keys))
+ def find_all(name, prefixes = [], partial = false, keys = [], options = {})
+ @view_paths.find_all(*args_for_lookup(name, prefixes, partial, keys, options))
end
- def exists?(name, prefixes = [], partial = false, keys = [])
- @view_paths.exists?(*args_for_lookup(name, prefixes, partial, keys))
+ def exists?(name, prefixes = [], partial = false, keys = [], options = {})
+ @view_paths.exists?(*args_for_lookup(name, prefixes, partial, keys, options))
end
alias :template_exists? :exists?
@@ -110,16 +130,29 @@ module ActionView
protected
- def args_for_lookup(name, prefixes, partial, keys) #:nodoc:
+ def args_for_lookup(name, prefixes, partial, keys, details_options) #:nodoc:
name, prefixes = normalize_name(name, prefixes)
- [name, prefixes, partial || false, @details, details_key, keys]
+ details, details_key = detail_args_for(details_options)
+ [name, prefixes, partial || false, details, details_key, keys]
+ end
+
+ # Compute details hash and key according to user options (e.g. passed from #render).
+ def detail_args_for(options)
+ return @details, details_key if options.empty? # most common path.
+ user_details = @details.merge(options)
+ [user_details, DetailsKey.get(user_details)]
end
# Support legacy foo.erb names even though we now ignore .erb
# as well as incorrectly putting part of the path in the template
# name instead of the prefix.
def normalize_name(name, prefixes) #:nodoc:
- name = name.to_s.gsub(handlers_regexp, '')
+ name = name.to_s.sub(handlers_regexp) do |match|
+ ActiveSupport::Deprecation.warn "Passing a template handler in the template name is deprecated. " \
+ "You can simply remove the handler name or pass render :handlers => [:#{match[1..-1]}] instead.", caller
+ ""
+ end
+
parts = name.split('/')
name = parts.pop
@@ -132,120 +165,82 @@ module ActionView
return name, prefixes
end
- def default_handlers #:nodoc:
- @@default_handlers ||= Template::Handlers.extensions
- end
-
def handlers_regexp #:nodoc:
@@handlers_regexp ||= /\.(?:#{default_handlers.join('|')})$/
end
end
- module Details
- attr_accessor :cache
-
- # Calculate the details key. Remove the handlers from calculation to improve performance
- # since the user cannot modify it explicitly.
- def details_key #:nodoc:
- @details_key ||= DetailsKey.get(@details) if @cache
- end
-
- # Temporary skip passing the details_key forward.
- def disable_cache
- old_value, @cache = @cache, false
- yield
- ensure
- @cache = old_value
- end
+ include Accessors
+ include DetailsCache
+ include ViewPaths
- # Freeze the current formats in the lookup context. By freezing them, you are guaranteeing
- # that next template lookups are not going to modify the formats. The controller can also
- # use this, to ensure that formats won't be further modified (as it does in respond_to blocks).
- def freeze_formats(formats, unless_frozen=false) #:nodoc:
- return if unless_frozen && @frozen_formats
- self.formats = formats
- @frozen_formats = true
- end
+ def initialize(view_paths, details = {}, prefixes = [])
+ @details, @details_key = {}, nil
+ @frozen_formats, @skip_default_locale = false, false
+ @cache = true
+ @prefixes = prefixes
- # Overload formats= to expand ["*/*"] values and automatically
- # add :html as fallback to :js.
- def formats=(values)
- if values
- values.concat(_formats_defaults) if values.delete "*/*"
- values << :html if values == [:js]
- end
- super(values)
- end
+ self.view_paths = view_paths
+ initialize_details(details)
+ end
- # Do not use the default locale on template lookup.
- def skip_default_locale!
- @skip_default_locale = true
- self.locale = nil
- end
+ # Freeze the current formats in the lookup context. By freezing them, you
+ # that next template lookups are not going to modify the formats. The con
+ # use this, to ensure that formats won't be further modified (as it does
+ def freeze_formats(formats, unless_frozen=false) #:nodoc:
+ return if unless_frozen && @frozen_formats
+ self.formats = formats
+ @frozen_formats = true
+ end
- # Overload locale to return a symbol instead of array.
- def locale
- @details[:locale].first
+ # Override formats= to expand ["*/*"] values and automatically
+ # add :html as fallback to :js.
+ def formats=(values)
+ if values
+ values.concat(default_formats) if values.delete "*/*"
+ values << :html if values == [:js]
end
+ super(values)
+ end
- # Overload locale= to also set the I18n.locale. If the current I18n.config object responds
- # to original_config, it means that it's has a copy of the original I18n configuration and it's
- # acting as proxy, which we need to skip.
- def locale=(value)
- if value
- config = I18n.config.respond_to?(:original_config) ? I18n.config.original_config : I18n.config
- config.locale = value
- end
+ # Do not use the default locale on template lookup.
+ def skip_default_locale!
+ @skip_default_locale = true
+ self.locale = nil
+ end
- super(@skip_default_locale ? I18n.locale : _locale_defaults)
- end
+ # Override locale to return a symbol instead of array.
+ def locale
+ @details[:locale].first
+ end
- # A method which only uses the first format in the formats array for layout lookup.
- # This method plays straight with instance variables for performance reasons.
- def with_layout_format
- if formats.size == 1
- yield
- else
- old_formats = formats
- _set_detail(:formats, formats[0,1])
-
- begin
- yield
- ensure
- _set_detail(:formats, old_formats)
- end
- end
+ # Overload locale= to also set the I18n.locale. If the current I18n.config object responds
+ # to original_config, it means that it's has a copy of the original I18n configuration and it's
+ # acting as proxy, which we need to skip.
+ def locale=(value)
+ if value
+ config = I18n.config.respond_to?(:original_config) ? I18n.config.original_config : I18n.config
+ config.locale = value
end
- # Update the details keys by merging the given hash into the current
- # details hash. If a block is given, the details are modified just during
- # the execution of the block and reverted to the previous value after.
- def update_details(new_details)
- old_details = @details.dup
+ super(@skip_default_locale ? I18n.locale : default_locale)
+ end
- registered_detail_setters.each do |key, setter|
- send(setter, new_details[key]) if new_details.key?(key)
- end
+ # A method which only uses the first format in the formats array for layout lookup.
+ # This method plays straight with instance variables for performance reasons.
+ def with_layout_format
+ if formats.size == 1
+ yield
+ else
+ old_formats = formats
+ _set_detail(:formats, formats[0,1])
begin
yield
ensure
- @details_key = nil
- @details = old_details
+ _set_detail(:formats, old_formats)
end
end
-
- protected
-
- def _set_detail(key, value)
- @details_key = nil
- @details = @details.dup if @details.frozen?
- @details[key] = value.freeze
- end
end
-
- include Accessors
- include Details
- include ViewPaths
end
end