2017-07-23 11:36:41 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2016-08-06 12:48:35 -04:00
|
|
|
require "concurrent/map"
|
|
|
|
require "active_support/core_ext/module/attribute_accessors"
|
2017-10-21 09:21:02 -04:00
|
|
|
require "action_view/template/resolver"
|
2010-03-08 14:39:15 -05:00
|
|
|
|
2010-03-08 09:19:03 -05:00
|
|
|
module ActionView
|
2010-06-16 14:27:50 -04:00
|
|
|
# = Action View Lookup Context
|
|
|
|
#
|
2015-07-17 14:15:35 -04:00
|
|
|
# <tt>LookupContext</tt> is the object responsible for holding all information
|
|
|
|
# required for looking up templates, i.e. view paths and details.
|
|
|
|
# <tt>LookupContext</tt> is also responsible for generating a key, given to
|
|
|
|
# view paths, used in the resolver cache lookup. Since this key is generated
|
|
|
|
# only once during the request, it speeds up all cache accesses.
|
2010-03-08 09:19:03 -05:00
|
|
|
class LookupContext #:nodoc:
|
2012-02-21 20:55:56 -05:00
|
|
|
attr_accessor :prefixes, :rendered_format
|
2011-06-05 11:34:40 -04:00
|
|
|
|
2021-06-26 21:50:59 -04:00
|
|
|
singleton_class.attr_accessor :registered_details
|
|
|
|
self.registered_details = []
|
2010-03-08 14:39:15 -05:00
|
|
|
|
2015-09-13 12:24:10 -04:00
|
|
|
def self.register_detail(name, &block)
|
2016-08-07 19:05:28 -04:00
|
|
|
registered_details << name
|
2016-02-11 18:42:45 -05:00
|
|
|
Accessors::DEFAULT_PROCS[name] = block
|
2010-06-07 04:13:41 -04:00
|
|
|
|
2018-12-20 11:39:18 -05:00
|
|
|
Accessors.define_method(:"default_#{name}", &block)
|
2010-03-19 12:20:15 -04:00
|
|
|
Accessors.module_eval <<-METHOD, __FILE__, __LINE__ + 1
|
|
|
|
def #{name}
|
2019-07-30 17:29:30 -04:00
|
|
|
@details[:#{name}] || []
|
2010-03-19 12:20:15 -04:00
|
|
|
end
|
2010-03-11 06:45:05 -05:00
|
|
|
|
2010-03-19 12:20:15 -04:00
|
|
|
def #{name}=(value)
|
2012-01-05 15:18:54 -05:00
|
|
|
value = value.present? ? Array(value) : default_#{name}
|
2010-06-07 04:13:41 -04:00
|
|
|
_set_detail(:#{name}, value) if value != @details[:#{name}]
|
2010-03-11 06:45:05 -05:00
|
|
|
end
|
2010-03-12 05:50:45 -05:00
|
|
|
METHOD
|
2010-03-08 14:39:15 -05:00
|
|
|
end
|
|
|
|
|
2010-03-19 12:20:15 -04:00
|
|
|
# Holds accessors for the registered details.
|
|
|
|
module Accessors #:nodoc:
|
2016-02-11 18:42:45 -05:00
|
|
|
DEFAULT_PROCS = {}
|
2010-03-11 06:45:05 -05:00
|
|
|
end
|
|
|
|
|
2013-03-14 17:02:20 -04:00
|
|
|
register_detail(:locale) do
|
|
|
|
locales = [I18n.locale]
|
|
|
|
locales.concat(I18n.fallbacks[I18n.locale]) if I18n.respond_to? :fallbacks
|
|
|
|
locales << I18n.default_locale
|
|
|
|
locales.uniq!
|
|
|
|
locales
|
|
|
|
end
|
2012-06-15 14:36:09 -04:00
|
|
|
register_detail(:formats) { ActionView::Base.default_formats || [:html, :text, :js, :css, :xml, :json] }
|
2013-12-03 05:17:01 -05:00
|
|
|
register_detail(:variants) { [] }
|
2015-09-13 12:24:10 -04:00
|
|
|
register_detail(:handlers) { Template::Handlers.extensions }
|
2010-03-08 14:39:15 -05:00
|
|
|
|
2010-03-08 09:19:03 -05:00
|
|
|
class DetailsKey #:nodoc:
|
|
|
|
alias :eql? :equal?
|
|
|
|
|
2015-09-19 09:56:26 -04:00
|
|
|
@details_keys = Concurrent::Map.new
|
2019-02-07 16:30:58 -05:00
|
|
|
@digest_cache = Concurrent::Map.new
|
2019-12-12 16:46:19 -05:00
|
|
|
@view_context_mutex = Mutex.new
|
2019-02-07 16:30:58 -05:00
|
|
|
|
|
|
|
def self.digest_cache(details)
|
2019-02-08 18:16:00 -05:00
|
|
|
@digest_cache[details_cache_key(details)] ||= Concurrent::Map.new
|
2019-02-07 16:30:58 -05:00
|
|
|
end
|
2010-03-08 09:19:03 -05:00
|
|
|
|
2019-02-07 16:30:58 -05:00
|
|
|
def self.details_cache_key(details)
|
2013-11-30 20:02:53 -05:00
|
|
|
if details[:formats]
|
|
|
|
details = details.dup
|
2016-01-16 13:17:59 -05:00
|
|
|
details[:formats] &= Template::Types.symbols
|
2013-11-30 20:02:53 -05:00
|
|
|
end
|
2019-02-07 16:30:58 -05:00
|
|
|
@details_keys[details] ||= Object.new
|
2010-03-08 09:19:03 -05:00
|
|
|
end
|
|
|
|
|
2011-12-14 03:23:34 -05:00
|
|
|
def self.clear
|
2019-02-08 17:43:22 -05:00
|
|
|
ActionView::ViewPaths.all_view_paths.each do |path_set|
|
|
|
|
path_set.each(&:clear_cache)
|
|
|
|
end
|
2019-01-23 17:19:50 -05:00
|
|
|
@view_context_class = nil
|
2011-12-14 03:23:34 -05:00
|
|
|
@details_keys.clear
|
2019-02-07 16:30:58 -05:00
|
|
|
@digest_cache.clear
|
2011-12-14 03:23:34 -05:00
|
|
|
end
|
2016-02-18 11:23:26 -05:00
|
|
|
|
|
|
|
def self.digest_caches
|
2019-02-07 16:30:58 -05:00
|
|
|
@digest_cache.values
|
2016-02-18 11:23:26 -05:00
|
|
|
end
|
2019-01-23 17:19:50 -05:00
|
|
|
|
|
|
|
def self.view_context_class(klass)
|
2019-12-12 16:46:19 -05:00
|
|
|
@view_context_mutex.synchronize do
|
|
|
|
@view_context_class ||= klass.with_empty_template_cache
|
|
|
|
end
|
2019-01-23 17:19:50 -05:00
|
|
|
end
|
2010-03-08 09:19:03 -05:00
|
|
|
end
|
|
|
|
|
2011-09-21 18:28:05 -04:00
|
|
|
# Add caching behavior on top of Details.
|
|
|
|
module DetailsCache
|
|
|
|
attr_accessor :cache
|
2010-06-07 04:13:41 -04:00
|
|
|
|
2011-09-21 18:28:05 -04:00
|
|
|
# Calculate the details key. Remove the handlers from calculation to improve performance
|
|
|
|
# since the user cannot modify it explicitly.
|
|
|
|
def details_key #:nodoc:
|
2019-02-07 16:30:58 -05:00
|
|
|
@details_key ||= DetailsKey.details_cache_key(@details) if @cache
|
2011-09-21 18:28:05 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
# Temporary skip passing the details_key forward.
|
|
|
|
def disable_cache
|
|
|
|
old_value, @cache = @cache, false
|
|
|
|
yield
|
|
|
|
ensure
|
|
|
|
@cache = old_value
|
|
|
|
end
|
|
|
|
|
2016-12-19 05:30:36 -05:00
|
|
|
private
|
|
|
|
def _set_detail(key, value) # :doc:
|
2019-02-07 16:30:58 -05:00
|
|
|
@details = @details.dup if @digest_cache || @details_key
|
|
|
|
@digest_cache = nil
|
2011-09-21 18:28:05 -04:00
|
|
|
@details_key = nil
|
2011-12-13 14:13:03 -05:00
|
|
|
@details[key] = value
|
2010-06-07 04:13:41 -04:00
|
|
|
end
|
2010-03-08 09:19:03 -05:00
|
|
|
end
|
|
|
|
|
2011-09-21 18:28:05 -04:00
|
|
|
# Helpers related to template lookup using the lookup context information.
|
2010-03-08 14:39:15 -05:00
|
|
|
module ViewPaths
|
2012-07-11 04:18:52 -04:00
|
|
|
attr_reader :view_paths, :html_fallback_for_js
|
2010-03-08 09:19:03 -05:00
|
|
|
|
2011-09-22 05:54:13 -04:00
|
|
|
def find(name, prefixes = [], partial = false, keys = [], options = {})
|
2021-07-13 17:09:36 -04:00
|
|
|
name, prefixes = normalize_name(name, prefixes)
|
|
|
|
details, details_key = detail_args_for(options)
|
|
|
|
@view_paths.find(name, prefixes, partial, details, details_key, keys)
|
2010-03-08 14:39:15 -05:00
|
|
|
end
|
2010-03-12 08:25:10 -05:00
|
|
|
alias :find_template :find
|
2010-03-08 09:19:03 -05:00
|
|
|
|
2011-09-22 05:54:13 -04:00
|
|
|
def find_all(name, prefixes = [], partial = false, keys = [], options = {})
|
2021-07-13 17:09:36 -04:00
|
|
|
name, prefixes = normalize_name(name, prefixes)
|
|
|
|
details, details_key = detail_args_for(options)
|
|
|
|
@view_paths.find_all(name, prefixes, partial, details, details_key, keys)
|
2010-03-08 14:57:33 -05:00
|
|
|
end
|
|
|
|
|
2015-03-17 10:36:21 -04:00
|
|
|
def exists?(name, prefixes = [], partial = false, keys = [], **options)
|
2021-07-13 17:09:36 -04:00
|
|
|
name, prefixes = normalize_name(name, prefixes)
|
|
|
|
details, details_key = detail_args_for(options)
|
|
|
|
@view_paths.exists?(name, prefixes, partial, details, details_key, keys)
|
2010-03-08 14:39:15 -05:00
|
|
|
end
|
2010-03-12 08:25:10 -05:00
|
|
|
alias :template_exists? :exists?
|
2010-03-08 09:19:03 -05:00
|
|
|
|
Lock down new `ImplicitRender` behavior for 5.0 RC
1. Conceptually revert #20276
The feature was implemented for the `responders` gem. In the end,
they did not need that feature, and have found a better fix (see
plataformatec/responders#131).
`ImplicitRender` is the place where Rails specifies our default
policies for the case where the user did not explicitly tell us
what to render, essentially describing a set of heuristics. If
the gem (or the user) knows exactly what they want, they could
just perform the correct `render` to avoid falling through to
here, as `responders` did (the user called `respond_with`).
Reverting the patch allows us to avoid exploding the complexity
and defining “the fallback for a fallback” policies.
2. `respond_to` and templates are considered exhaustive enumerations
If the user specified a list of formats/variants in a `respond_to`
block, anything that is not explicitly included should result
in an `UnknownFormat` error (which is then caught upstream to
mean “406 Not Acceptable” by default). This is already how it
works before this commit.
Same goes for templates – if the user defined a set of templates
(usually in the file system), that set is now considered exhaustive,
which means that “missing” templates are considered `UnknownFormat`
errors (406).
3. To keep API endpoints simple, the implicit render behavior for
actions with no templates defined at all (regardless of formats,
locales, variants, etc) are defaulted to “204 No Content”. This
is a strictly narrower version of the feature landed in #19036 and
#19377.
4. To avoid confusion when interacting in the browser, these actions
will raise an `UnknownFormat` error for “interactive” requests
instead. (The precise definition of “interactive” requests might
change – the spirit here is to give helpful messages and avoid
confusions.)
Closes #20666, #23062, #23077, #23564
[Godfrey Chan, Jon Moss, Kasper Timm Hansen, Mike Clark, Matthew Draper]
2016-02-23 12:41:26 -05:00
|
|
|
def any?(name, prefixes = [], partial = false)
|
2021-07-13 17:09:36 -04:00
|
|
|
name, prefixes = normalize_name(name, prefixes)
|
|
|
|
details, details_key = detail_args_for_any
|
|
|
|
@view_paths.exists?(name, prefixes, partial, details, details_key, [])
|
Lock down new `ImplicitRender` behavior for 5.0 RC
1. Conceptually revert #20276
The feature was implemented for the `responders` gem. In the end,
they did not need that feature, and have found a better fix (see
plataformatec/responders#131).
`ImplicitRender` is the place where Rails specifies our default
policies for the case where the user did not explicitly tell us
what to render, essentially describing a set of heuristics. If
the gem (or the user) knows exactly what they want, they could
just perform the correct `render` to avoid falling through to
here, as `responders` did (the user called `respond_with`).
Reverting the patch allows us to avoid exploding the complexity
and defining “the fallback for a fallback” policies.
2. `respond_to` and templates are considered exhaustive enumerations
If the user specified a list of formats/variants in a `respond_to`
block, anything that is not explicitly included should result
in an `UnknownFormat` error (which is then caught upstream to
mean “406 Not Acceptable” by default). This is already how it
works before this commit.
Same goes for templates – if the user defined a set of templates
(usually in the file system), that set is now considered exhaustive,
which means that “missing” templates are considered `UnknownFormat`
errors (406).
3. To keep API endpoints simple, the implicit render behavior for
actions with no templates defined at all (regardless of formats,
locales, variants, etc) are defaulted to “204 No Content”. This
is a strictly narrower version of the feature landed in #19036 and
#19377.
4. To avoid confusion when interacting in the browser, these actions
will raise an `UnknownFormat` error for “interactive” requests
instead. (The precise definition of “interactive” requests might
change – the spirit here is to give helpful messages and avoid
confusions.)
Closes #20666, #23062, #23077, #23564
[Godfrey Chan, Jon Moss, Kasper Timm Hansen, Mike Clark, Matthew Draper]
2016-02-23 12:41:26 -05:00
|
|
|
end
|
|
|
|
alias :any_templates? :any?
|
|
|
|
|
2016-12-19 05:30:36 -05:00
|
|
|
private
|
2019-01-28 14:47:53 -05:00
|
|
|
# Whenever setting view paths, makes a copy so that we can manipulate them in
|
|
|
|
# instance objects as we wish.
|
|
|
|
def build_view_paths(paths)
|
|
|
|
ActionView::PathSet.new(Array(paths))
|
|
|
|
end
|
|
|
|
|
2011-09-22 05:54:13 -04:00
|
|
|
# Compute details hash and key according to user options (e.g. passed from #render).
|
2016-12-19 05:30:36 -05:00
|
|
|
def detail_args_for(options) # :doc:
|
2011-09-22 05:54:13 -04:00
|
|
|
return @details, details_key if options.empty? # most common path.
|
|
|
|
user_details = @details.merge(options)
|
2014-03-14 16:28:31 -04:00
|
|
|
|
|
|
|
if @cache
|
2019-02-07 16:30:58 -05:00
|
|
|
details_key = DetailsKey.details_cache_key(user_details)
|
2014-03-14 16:28:31 -04:00
|
|
|
else
|
|
|
|
details_key = nil
|
|
|
|
end
|
|
|
|
|
|
|
|
[user_details, details_key]
|
Lock down new `ImplicitRender` behavior for 5.0 RC
1. Conceptually revert #20276
The feature was implemented for the `responders` gem. In the end,
they did not need that feature, and have found a better fix (see
plataformatec/responders#131).
`ImplicitRender` is the place where Rails specifies our default
policies for the case where the user did not explicitly tell us
what to render, essentially describing a set of heuristics. If
the gem (or the user) knows exactly what they want, they could
just perform the correct `render` to avoid falling through to
here, as `responders` did (the user called `respond_with`).
Reverting the patch allows us to avoid exploding the complexity
and defining “the fallback for a fallback” policies.
2. `respond_to` and templates are considered exhaustive enumerations
If the user specified a list of formats/variants in a `respond_to`
block, anything that is not explicitly included should result
in an `UnknownFormat` error (which is then caught upstream to
mean “406 Not Acceptable” by default). This is already how it
works before this commit.
Same goes for templates – if the user defined a set of templates
(usually in the file system), that set is now considered exhaustive,
which means that “missing” templates are considered `UnknownFormat`
errors (406).
3. To keep API endpoints simple, the implicit render behavior for
actions with no templates defined at all (regardless of formats,
locales, variants, etc) are defaulted to “204 No Content”. This
is a strictly narrower version of the feature landed in #19036 and
#19377.
4. To avoid confusion when interacting in the browser, these actions
will raise an `UnknownFormat` error for “interactive” requests
instead. (The precise definition of “interactive” requests might
change – the spirit here is to give helpful messages and avoid
confusions.)
Closes #20666, #23062, #23077, #23564
[Godfrey Chan, Jon Moss, Kasper Timm Hansen, Mike Clark, Matthew Draper]
2016-02-23 12:41:26 -05:00
|
|
|
end
|
|
|
|
|
2016-12-19 05:30:36 -05:00
|
|
|
def detail_args_for_any
|
Lock down new `ImplicitRender` behavior for 5.0 RC
1. Conceptually revert #20276
The feature was implemented for the `responders` gem. In the end,
they did not need that feature, and have found a better fix (see
plataformatec/responders#131).
`ImplicitRender` is the place where Rails specifies our default
policies for the case where the user did not explicitly tell us
what to render, essentially describing a set of heuristics. If
the gem (or the user) knows exactly what they want, they could
just perform the correct `render` to avoid falling through to
here, as `responders` did (the user called `respond_with`).
Reverting the patch allows us to avoid exploding the complexity
and defining “the fallback for a fallback” policies.
2. `respond_to` and templates are considered exhaustive enumerations
If the user specified a list of formats/variants in a `respond_to`
block, anything that is not explicitly included should result
in an `UnknownFormat` error (which is then caught upstream to
mean “406 Not Acceptable” by default). This is already how it
works before this commit.
Same goes for templates – if the user defined a set of templates
(usually in the file system), that set is now considered exhaustive,
which means that “missing” templates are considered `UnknownFormat`
errors (406).
3. To keep API endpoints simple, the implicit render behavior for
actions with no templates defined at all (regardless of formats,
locales, variants, etc) are defaulted to “204 No Content”. This
is a strictly narrower version of the feature landed in #19036 and
#19377.
4. To avoid confusion when interacting in the browser, these actions
will raise an `UnknownFormat` error for “interactive” requests
instead. (The precise definition of “interactive” requests might
change – the spirit here is to give helpful messages and avoid
confusions.)
Closes #20666, #23062, #23077, #23564
[Godfrey Chan, Jon Moss, Kasper Timm Hansen, Mike Clark, Matthew Draper]
2016-02-23 12:41:26 -05:00
|
|
|
@detail_args_for_any ||= begin
|
|
|
|
details = {}
|
|
|
|
|
2021-06-26 21:50:59 -04:00
|
|
|
LookupContext.registered_details.each do |k|
|
Lock down new `ImplicitRender` behavior for 5.0 RC
1. Conceptually revert #20276
The feature was implemented for the `responders` gem. In the end,
they did not need that feature, and have found a better fix (see
plataformatec/responders#131).
`ImplicitRender` is the place where Rails specifies our default
policies for the case where the user did not explicitly tell us
what to render, essentially describing a set of heuristics. If
the gem (or the user) knows exactly what they want, they could
just perform the correct `render` to avoid falling through to
here, as `responders` did (the user called `respond_with`).
Reverting the patch allows us to avoid exploding the complexity
and defining “the fallback for a fallback” policies.
2. `respond_to` and templates are considered exhaustive enumerations
If the user specified a list of formats/variants in a `respond_to`
block, anything that is not explicitly included should result
in an `UnknownFormat` error (which is then caught upstream to
mean “406 Not Acceptable” by default). This is already how it
works before this commit.
Same goes for templates – if the user defined a set of templates
(usually in the file system), that set is now considered exhaustive,
which means that “missing” templates are considered `UnknownFormat`
errors (406).
3. To keep API endpoints simple, the implicit render behavior for
actions with no templates defined at all (regardless of formats,
locales, variants, etc) are defaulted to “204 No Content”. This
is a strictly narrower version of the feature landed in #19036 and
#19377.
4. To avoid confusion when interacting in the browser, these actions
will raise an `UnknownFormat` error for “interactive” requests
instead. (The precise definition of “interactive” requests might
change – the spirit here is to give helpful messages and avoid
confusions.)
Closes #20666, #23062, #23077, #23564
[Godfrey Chan, Jon Moss, Kasper Timm Hansen, Mike Clark, Matthew Draper]
2016-02-23 12:41:26 -05:00
|
|
|
if k == :variants
|
|
|
|
details[k] = :any
|
|
|
|
else
|
|
|
|
details[k] = Accessors::DEFAULT_PROCS[k].call
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
if @cache
|
2019-02-07 16:30:58 -05:00
|
|
|
[details, DetailsKey.details_cache_key(details)]
|
Lock down new `ImplicitRender` behavior for 5.0 RC
1. Conceptually revert #20276
The feature was implemented for the `responders` gem. In the end,
they did not need that feature, and have found a better fix (see
plataformatec/responders#131).
`ImplicitRender` is the place where Rails specifies our default
policies for the case where the user did not explicitly tell us
what to render, essentially describing a set of heuristics. If
the gem (or the user) knows exactly what they want, they could
just perform the correct `render` to avoid falling through to
here, as `responders` did (the user called `respond_with`).
Reverting the patch allows us to avoid exploding the complexity
and defining “the fallback for a fallback” policies.
2. `respond_to` and templates are considered exhaustive enumerations
If the user specified a list of formats/variants in a `respond_to`
block, anything that is not explicitly included should result
in an `UnknownFormat` error (which is then caught upstream to
mean “406 Not Acceptable” by default). This is already how it
works before this commit.
Same goes for templates – if the user defined a set of templates
(usually in the file system), that set is now considered exhaustive,
which means that “missing” templates are considered `UnknownFormat`
errors (406).
3. To keep API endpoints simple, the implicit render behavior for
actions with no templates defined at all (regardless of formats,
locales, variants, etc) are defaulted to “204 No Content”. This
is a strictly narrower version of the feature landed in #19036 and
#19377.
4. To avoid confusion when interacting in the browser, these actions
will raise an `UnknownFormat` error for “interactive” requests
instead. (The precise definition of “interactive” requests might
change – the spirit here is to give helpful messages and avoid
confusions.)
Closes #20666, #23062, #23077, #23564
[Godfrey Chan, Jon Moss, Kasper Timm Hansen, Mike Clark, Matthew Draper]
2016-02-23 12:41:26 -05:00
|
|
|
else
|
|
|
|
[details, nil]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-05-10 19:13:37 -04:00
|
|
|
# Fix when prefix is specified as part of the template name
|
2016-12-19 05:30:36 -05:00
|
|
|
def normalize_name(name, prefixes)
|
2021-05-12 13:06:04 -04:00
|
|
|
name = name.to_s
|
2021-05-10 19:13:37 -04:00
|
|
|
idx = name.rindex("/")
|
|
|
|
return name, prefixes.presence || [""] unless idx
|
2010-09-17 16:39:14 -04:00
|
|
|
|
2021-05-10 19:13:37 -04:00
|
|
|
path_prefix = name[0, idx]
|
|
|
|
path_prefix = path_prefix.from(1) if path_prefix.start_with?("/")
|
|
|
|
name = name.from(idx + 1)
|
2011-12-08 09:23:23 -05:00
|
|
|
|
2021-05-10 19:13:37 -04:00
|
|
|
if !prefixes || prefixes.empty?
|
|
|
|
prefixes = [path_prefix]
|
|
|
|
else
|
|
|
|
prefixes = prefixes.map { |p| "#{p}/#{path_prefix}" }
|
|
|
|
end
|
2010-12-27 03:14:13 -05:00
|
|
|
|
|
|
|
return name, prefixes
|
2010-03-15 21:08:34 -04:00
|
|
|
end
|
2010-03-08 09:19:03 -05:00
|
|
|
end
|
|
|
|
|
2011-09-21 18:28:05 -04:00
|
|
|
include Accessors
|
|
|
|
include DetailsCache
|
|
|
|
include ViewPaths
|
2010-03-08 14:39:15 -05:00
|
|
|
|
2011-09-21 18:28:05 -04:00
|
|
|
def initialize(view_paths, details = {}, prefixes = [])
|
2016-02-11 18:42:45 -05:00
|
|
|
@details_key = nil
|
2019-02-07 16:30:58 -05:00
|
|
|
@digest_cache = nil
|
2011-09-21 18:28:05 -04:00
|
|
|
@cache = true
|
|
|
|
@prefixes = prefixes
|
2010-03-27 15:51:25 -04:00
|
|
|
|
2016-02-11 18:42:45 -05:00
|
|
|
@details = initialize_details({}, details)
|
2019-01-28 14:47:53 -05:00
|
|
|
@view_paths = build_view_paths(view_paths)
|
2011-09-21 18:28:05 -04:00
|
|
|
end
|
2010-03-08 14:39:15 -05:00
|
|
|
|
2016-02-18 11:23:26 -05:00
|
|
|
def digest_cache
|
2019-02-07 16:30:58 -05:00
|
|
|
@digest_cache ||= DetailsKey.digest_cache(@details)
|
2016-02-18 11:23:26 -05:00
|
|
|
end
|
|
|
|
|
2019-02-11 20:24:24 -05:00
|
|
|
def with_prepended_formats(formats)
|
|
|
|
details = @details.dup
|
|
|
|
details[:formats] = formats
|
|
|
|
|
|
|
|
self.class.new(@view_paths, details, @prefixes)
|
|
|
|
end
|
|
|
|
|
2016-02-11 18:42:45 -05:00
|
|
|
def initialize_details(target, details)
|
2021-06-26 21:50:59 -04:00
|
|
|
LookupContext.registered_details.each do |k|
|
2016-02-11 18:42:45 -05:00
|
|
|
target[k] = details[k] || Accessors::DEFAULT_PROCS[k].call
|
|
|
|
end
|
|
|
|
target
|
|
|
|
end
|
|
|
|
private :initialize_details
|
|
|
|
|
2011-09-21 18:28:05 -04:00
|
|
|
# Override formats= to expand ["*/*"] values and automatically
|
|
|
|
# add :html as fallback to :js.
|
|
|
|
def formats=(values)
|
|
|
|
if values
|
2019-03-19 19:34:12 -04:00
|
|
|
values = values.dup
|
2018-02-27 23:33:37 -05:00
|
|
|
values.concat(default_formats) if values.delete "*/*"
|
2019-03-18 13:13:35 -04:00
|
|
|
values.uniq!
|
|
|
|
|
2019-03-18 19:10:13 -04:00
|
|
|
invalid_values = (values - Template::Types.symbols)
|
|
|
|
unless invalid_values.empty?
|
|
|
|
raise ArgumentError, "Invalid formats: #{invalid_values.map(&:inspect).join(", ")}"
|
2019-03-18 13:18:36 -04:00
|
|
|
end
|
|
|
|
|
2012-07-11 04:18:52 -04:00
|
|
|
if values == [:js]
|
|
|
|
values << :html
|
|
|
|
@html_fallback_for_js = true
|
|
|
|
end
|
2010-03-10 16:11:48 -05:00
|
|
|
end
|
2011-09-21 18:28:05 -04:00
|
|
|
super(values)
|
|
|
|
end
|
2010-03-10 16:11:48 -05:00
|
|
|
|
2011-09-21 18:28:05 -04:00
|
|
|
# Override locale to return a symbol instead of array.
|
|
|
|
def locale
|
|
|
|
@details[:locale].first
|
|
|
|
end
|
2010-06-07 04:13:41 -04:00
|
|
|
|
2011-09-21 18:28:05 -04:00
|
|
|
# Overload locale= to also set the I18n.locale. If the current I18n.config object responds
|
2014-05-03 01:41:19 -04:00
|
|
|
# to original_config, it means that it has a copy of the original I18n configuration and it's
|
2011-09-21 18:28:05 -04:00
|
|
|
# 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
|
2010-06-04 20:28:04 -04:00
|
|
|
end
|
|
|
|
|
2014-12-29 21:46:55 -05:00
|
|
|
super(default_locale)
|
2011-09-21 18:28:05 -04:00
|
|
|
end
|
2010-03-08 09:19:03 -05:00
|
|
|
end
|
2010-09-17 16:39:14 -04:00
|
|
|
end
|