mirror of
https://github.com/github/rails.git
synced 2026-04-26 03:00:59 -04:00
Slightly reorganize lookup context modules in order to better isolate cache responsibilities.
This commit is contained in:
@@ -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,12 +18,11 @@ 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}]" }
|
||||
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 @@ module ActionView
|
||||
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 @@ 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
|
||||
|
||||
# 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 @@ module ActionView
|
||||
end
|
||||
end
|
||||
|
||||
module Details
|
||||
attr_accessor :cache
|
||||
include Accessors
|
||||
include DetailsCache
|
||||
include ViewPaths
|
||||
|
||||
# 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
|
||||
def initialize(view_paths, details = {}, prefixes = [])
|
||||
@details, @details_key = { :handlers => default_handlers }, nil
|
||||
@frozen_formats, @skip_default_locale = false, false
|
||||
@cache = true
|
||||
@prefixes = prefixes
|
||||
|
||||
self.view_paths = view_paths
|
||||
initialize_details(details)
|
||||
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
|
||||
|
||||
# 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
|
||||
|
||||
# Do not use the default locale on template lookup.
|
||||
def skip_default_locale!
|
||||
@skip_default_locale = true
|
||||
self.locale = nil
|
||||
end
|
||||
|
||||
# Override locale to return a symbol instead of array.
|
||||
def locale
|
||||
@details[:locale].first
|
||||
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
|
||||
|
||||
# Temporary skip passing the details_key forward.
|
||||
def disable_cache
|
||||
old_value, @cache = @cache, false
|
||||
super(@skip_default_locale ? I18n.locale : _locale_defaults)
|
||||
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
|
||||
ensure
|
||||
@cache = old_value
|
||||
end
|
||||
|
||||
# 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
|
||||
|
||||
# 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
|
||||
|
||||
# Do not use the default locale on template lookup.
|
||||
def skip_default_locale!
|
||||
@skip_default_locale = true
|
||||
self.locale = nil
|
||||
end
|
||||
|
||||
# Overload locale to return a symbol instead of array.
|
||||
def locale
|
||||
@details[:locale].first
|
||||
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
|
||||
|
||||
# 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
|
||||
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
|
||||
|
||||
registered_detail_setters.each do |key, setter|
|
||||
send(setter, new_details[key]) if new_details.key?(key)
|
||||
end
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user