提交 f373f296 编写于 作者: J José Valim

Slightly reorganize lookup context modules in order to better isolate cache responsibilities.

上级 8aa537c9
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,12 +18,11 @@ class LookupContext #:nodoc:
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}]" }
update = registered_details.map { |n| "self.#{n} = details[:#{n}] if details.key?(:#{n})" }
Accessors.send :define_method, :"_#{name}_defaults", &block
Accessors.module_eval <<-METHOD, __FILE__, __LINE__ + 1
......@@ -34,6 +34,16 @@ def #{name}=(value)
value = Array.wrap(value.presence || _#{name}_defaults)
_set_detail(:#{name}, value) if value != @details[:#{name}]
end
remove_possible_method :initialize_details
def initialize_details(details)
#{initialize.join("\n")}
end
remove_possible_method :update_details
def update_details(details)
#{update.join("\n")}
end
METHOD
end
......@@ -60,18 +70,53 @@ def initialize
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
# 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)
if block_given?
old_details = @details.dup
super
begin
yield
ensure
@details_key = nil
@details = old_details
end
else
super
end
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
......@@ -141,111 +186,77 @@ def handlers_regexp #:nodoc:
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 = { :handlers => default_handlers }, 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(_formats_defaults) 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
super(@skip_default_locale ? I18n.locale : _locale_defaults)
end
# Do not use the default locale on template lookup.
def skip_default_locale!
@skip_default_locale = true
self.locale = nil
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])
# Override locale to return a symbol instead of array.
def locale
@details[:locale].first
end
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 : _locale_defaults)
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
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册