diff options
-rw-r--r-- | actionview/lib/action_view.rb | 1 | ||||
-rw-r--r-- | actionview/lib/action_view/template/resolver.rb | 29 | ||||
-rw-r--r-- | actionview/lib/action_view/unbound_template.rb | 32 | ||||
-rw-r--r-- | actionview/test/template/resolver_shared_tests.rb | 30 |
4 files changed, 82 insertions, 10 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..1be82f5df5 100644 --- a/actionview/lib/action_view/template/resolver.rb +++ b/actionview/lib/action_view/template/resolver.rb @@ -169,6 +169,12 @@ module ActionView else @pattern = DEFAULT_PATTERN end + @unbound_templates = Concurrent::Map.new + super() + end + + def clear_cache + @unbound_templates.clear super() end @@ -189,16 +195,19 @@ module ActionView end def build_template(template, virtual_path, locals) - handler, format, variant = extract_handler_and_format_and_variant(template) - - filename = File.expand_path(template) - source = Template::Sources::File.new(filename) - Template.new(source, filename, handler, - virtual_path: virtual_path, - format: format, - variant: variant, - locals: locals - ) + @unbound_templates.compute_if_absent([template, virtual_path]) do + handler, format, variant = extract_handler_and_format_and_variant(template) + source = Template::Sources::File.new(template) + + UnboundTemplate.new( + source, + template, + handler, + virtual_path: virtual_path, + format: format, + variant: variant, + ) + end.bind_locals(locals) end def reject_files_external_to_app(files) 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 diff --git a/actionview/test/template/resolver_shared_tests.rb b/actionview/test/template/resolver_shared_tests.rb index dee6a69c66..37bdf4b22c 100644 --- a/actionview/test/template/resolver_shared_tests.rb +++ b/actionview/test/template/resolver_shared_tests.rb @@ -13,6 +13,10 @@ module ResolverSharedTests File.write(path, source) end + def context + @context ||= ActionView::LookupContext.new(resolver) + end + def test_can_find_with_no_extensions with_file "test/hello_world", "Hello default!" @@ -82,4 +86,30 @@ module ResolverSharedTests templates = resolver.find_all("hello_world", "test", false, locale: [], formats: [:xml], variants: :any, handlers: [:erb]) assert_equal 0, templates.size end + + def test_found_template_is_cached + with_file "test/hello_world.html.erb", "Hello HTML!" + + a = context.find("hello_world", "test", false, [], {}) + b = context.find("hello_world", "test", false, [], {}) + assert_same a, b + end + + def test_same_template_from_different_details_is_same_object + with_file "test/hello_world.html.erb", "Hello plain text!" + + a = context.find("hello_world", "test", false, [], locale: [:en]) + b = context.find("hello_world", "test", false, [], locale: [:fr]) + assert_same a, b + end + + def test_virtual_path_is_preserved_with_dot + with_file "test/hello_world.html.erb", "Hello html!" + + template = context.find("hello_world.html", "test", false, [], {}) + assert_equal "test/hello_world.html", template.virtual_path + + template = context.find("hello_world", "test", false, [], {}) + assert_equal "test/hello_world", template.virtual_path + end end |