diff options
author | Rafael França <rafaelmfranca@gmail.com> | 2019-04-15 17:57:39 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-04-15 17:57:39 -0400 |
commit | ddf471a163e96e52e1a1cc507bde5a0cfe9f643f (patch) | |
tree | d4cf5686244e0b64a59253cc5efe7f650b3edbf2 /actionview/lib | |
parent | 62b7a521a41011c108815041a975ae3177dfcc09 (diff) | |
parent | 2455d16a5a975fa5bf75bdb023df61047b055e3d (diff) | |
download | rails-ddf471a163e96e52e1a1cc507bde5a0cfe9f643f.tar.gz rails-ddf471a163e96e52e1a1cc507bde5a0cfe9f643f.tar.bz2 rails-ddf471a163e96e52e1a1cc507bde5a0cfe9f643f.zip |
Merge pull request #35959 from jhawthorn/unbound_templates
De-duplicate templates, introduce UnboundTemplate
Diffstat (limited to 'actionview/lib')
-rw-r--r-- | actionview/lib/action_view.rb | 1 | ||||
-rw-r--r-- | actionview/lib/action_view/template/resolver.rb | 44 | ||||
-rw-r--r-- | actionview/lib/action_view/testing/resolvers.rb | 4 | ||||
-rw-r--r-- | actionview/lib/action_view/unbound_template.rb | 32 |
4 files changed, 67 insertions, 14 deletions
diff --git a/actionview/lib/action_view.rb b/actionview/lib/action_view.rb index 5ee14bfc78..7f85bf2a5e 100644 --- a/actionview/lib/action_view.rb +++ b/actionview/lib/action_view.rb @@ -44,6 +44,7 @@ module ActionView autoload :Rendering autoload :RoutingUrlFor autoload :Template + autoload :UnboundTemplate autoload :ViewPaths autoload_under "renderer" do diff --git a/actionview/lib/action_view/template/resolver.rb b/actionview/lib/action_view/template/resolver.rb index e291dc268a..ce53eb046d 100644 --- a/actionview/lib/action_view/template/resolver.rb +++ b/actionview/lib/action_view/template/resolver.rb @@ -118,7 +118,7 @@ module ActionView locals = locals.map(&:to_s).sort!.freeze cached(key, [name, prefix, partial], details, locals) do - find_templates(name, prefix, partial, details, locals) + _find_all(name, prefix, partial, details, key, locals) end end @@ -131,6 +131,10 @@ module ActionView private + def _find_all(name, prefix, partial, details, key, locals) + find_templates(name, prefix, partial, details, locals) + end + delegate :caching?, to: :class # This is what child classes implement. No defaults are needed @@ -169,35 +173,51 @@ module ActionView else @pattern = DEFAULT_PATTERN end + @unbound_templates = Concurrent::Map.new + super() + end + + def clear_cache + @unbound_templates.clear super() end private - def find_templates(name, prefix, partial, details, locals) + def _find_all(name, prefix, partial, details, key, locals) path = Path.build(name, prefix, partial) - query(path, details, details[:formats], locals) + query(path, details, details[:formats], locals, cache: !!key) end - def query(path, details, formats, locals) + def query(path, details, formats, locals, cache:) template_paths = find_template_paths_from_details(path, details) template_paths = reject_files_external_to_app(template_paths) template_paths.map do |template| - build_template(template, path.virtual, locals) + unbound_template = + if cache + @unbound_templates.compute_if_absent([template, path.virtual]) do + build_unbound_template(template, path.virtual) + end + else + build_unbound_template(template, path.virtual) + end + + unbound_template.bind_locals(locals) end end - def build_template(template, virtual_path, locals) + def build_unbound_template(template, virtual_path) handler, format, variant = extract_handler_and_format_and_variant(template) + source = Template::Sources::File.new(template) - filename = File.expand_path(template) - source = Template::Sources::File.new(filename) - Template.new(source, filename, handler, + UnboundTemplate.new( + source, + template, + handler, virtual_path: virtual_path, format: format, variant: variant, - locals: locals ) end @@ -363,8 +383,8 @@ module ActionView [new(""), new("/")] end - def build_template(template, virtual_path, locals) - super(template, nil, locals) + def build_unbound_template(template, _) + super(template, nil) end def reject_files_external_to_app(files) diff --git a/actionview/lib/action_view/testing/resolvers.rb b/actionview/lib/action_view/testing/resolvers.rb index a97fb71b26..1bedf44934 100644 --- a/actionview/lib/action_view/testing/resolvers.rb +++ b/actionview/lib/action_view/testing/resolvers.rb @@ -23,7 +23,7 @@ module ActionView #:nodoc: private - def query(path, exts, _, locals) + def query(path, exts, _, locals, cache:) query = +"" EXTENSIONS.each do |ext, prefix| query << "(" << exts[ext].map { |e| e && Regexp.escape("#{prefix}#{e}") }.join("|") << "|)" @@ -47,7 +47,7 @@ module ActionView #:nodoc: end class NullResolver < PathResolver - def query(path, exts, _, locals) + def query(path, exts, _, locals, cache:) handler, format, variant = extract_handler_and_format_and_variant(path) [ActionView::Template.new("Template generated by Null Resolver", path.virtual, handler, virtual_path: path.virtual, format: format, variant: variant, locals: locals)] end diff --git a/actionview/lib/action_view/unbound_template.rb b/actionview/lib/action_view/unbound_template.rb new file mode 100644 index 0000000000..db69b6d016 --- /dev/null +++ b/actionview/lib/action_view/unbound_template.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +require "concurrent/map" + +module ActionView + class UnboundTemplate + def initialize(source, identifer, handler, options) + @source = source + @identifer = identifer + @handler = handler + @options = options + + @templates = Concurrent::Map.new(initial_capacity: 2) + end + + def bind_locals(locals) + @templates[locals] ||= build_template(locals) + end + + private + + def build_template(locals) + options = @options.merge(locals: locals) + Template.new( + @source, + @identifer, + @handler, + options + ) + end + end +end |