Pass source to template handler and deprecate old style handler
This commit passes the mutated source to the template handler as a parameter and deprecates the old handlers. Old handlers required that templates contain a reference to mutated source code, but we would like to make template objects "read only". This change lets the template remain "read only" while still giving template handlers access to the source code after mutations.
This commit is contained in:
parent
2169bd3d2a
commit
28f88e0074
|
@ -2,7 +2,6 @@
|
|||
|
||||
require "active_support/core_ext/object/try"
|
||||
require "active_support/core_ext/kernel/singleton_class"
|
||||
require "active_support/deprecation"
|
||||
require "thread"
|
||||
require "delegate"
|
||||
|
||||
|
@ -304,7 +303,7 @@ module ActionView
|
|||
# regardless of the original source encoding.
|
||||
def compile(mod)
|
||||
source = encode!
|
||||
code = @handler.call(LegacyTemplate.new(self, source))
|
||||
code = @handler.call(self, source)
|
||||
|
||||
# Make sure that the resulting String to be eval'd is in the
|
||||
# encoding of the code
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "active_support/deprecation"
|
||||
|
||||
module ActionView #:nodoc:
|
||||
# = Action View Template Handlers
|
||||
class Template #:nodoc:
|
||||
|
@ -14,7 +16,7 @@ module ActionView #:nodoc:
|
|||
base.register_template_handler :erb, ERB.new
|
||||
base.register_template_handler :html, Html.new
|
||||
base.register_template_handler :builder, Builder.new
|
||||
base.register_template_handler :ruby, :source.to_proc
|
||||
base.register_template_handler :ruby, lambda { |_, source| source }
|
||||
end
|
||||
|
||||
@@template_handlers = {}
|
||||
|
@ -24,11 +26,35 @@ module ActionView #:nodoc:
|
|||
@@template_extensions ||= @@template_handlers.keys
|
||||
end
|
||||
|
||||
class LegacyHandlerWrapper < SimpleDelegator # :nodoc:
|
||||
def call(view, source)
|
||||
__getobj__.call(ActionView::Template::LegacyTemplate.new(view, source))
|
||||
end
|
||||
end
|
||||
|
||||
# Register an object that knows how to handle template files with the given
|
||||
# extensions. This can be used to implement new template types.
|
||||
# The handler must respond to +:call+, which will be passed the template
|
||||
# and should return the rendered template as a String.
|
||||
def register_template_handler(*extensions, handler)
|
||||
params = if handler.is_a?(Proc)
|
||||
handler.parameters
|
||||
else
|
||||
handler.method(:call).parameters
|
||||
end
|
||||
|
||||
unless params.find_all { |type, _| type == :req }.length >= 2
|
||||
ActiveSupport::Deprecation.warn <<~eowarn
|
||||
Single arity template handlers are deprecated. Template handlers must
|
||||
now accept two parameters, the view object and the source for the view object.
|
||||
Change:
|
||||
>> #{handler.class}#call(#{params.map(&:last).join(", ")})
|
||||
To:
|
||||
>> #{handler.class}#call(#{params.map(&:last).join(", ")}, source)
|
||||
eowarn
|
||||
handler = LegacyHandlerWrapper.new(handler)
|
||||
end
|
||||
|
||||
raise(ArgumentError, "Extension is required") if extensions.empty?
|
||||
extensions.each do |extension|
|
||||
@@template_handlers[extension.to_sym] = handler
|
||||
|
|
|
@ -5,11 +5,11 @@ module ActionView
|
|||
class Builder
|
||||
class_attribute :default_format, default: :xml
|
||||
|
||||
def call(template)
|
||||
def call(template, source)
|
||||
require_engine
|
||||
"xml = ::Builder::XmlMarkup.new(:indent => 2);" \
|
||||
"self.output_buffer = xml.target!;" +
|
||||
template.source +
|
||||
source +
|
||||
";xml.target!;"
|
||||
end
|
||||
|
||||
|
|
|
@ -28,8 +28,8 @@ module ActionView
|
|||
|
||||
ENCODING_TAG = Regexp.new("\\A(<%#{ENCODING_FLAG}-?%>)[ \\t]*")
|
||||
|
||||
def self.call(template)
|
||||
new.call(template)
|
||||
def self.call(template, source)
|
||||
new.call(template, source)
|
||||
end
|
||||
|
||||
def supports_streaming?
|
||||
|
@ -40,17 +40,17 @@ module ActionView
|
|||
true
|
||||
end
|
||||
|
||||
def call(template)
|
||||
def call(template, source)
|
||||
# First, convert to BINARY, so in case the encoding is
|
||||
# wrong, we can still find an encoding tag
|
||||
# (<%# encoding %>) inside the String using a regular
|
||||
# expression
|
||||
template_source = template.source.dup.force_encoding(Encoding::ASCII_8BIT)
|
||||
template_source = source.dup.force_encoding(Encoding::ASCII_8BIT)
|
||||
|
||||
erb = template_source.gsub(ENCODING_TAG, "")
|
||||
encoding = $2
|
||||
|
||||
erb.force_encoding valid_encoding(template.source.dup, encoding)
|
||||
erb.force_encoding valid_encoding(source.dup, encoding)
|
||||
|
||||
# Always make sure we return a String in the default_internal
|
||||
erb.encode!
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
module ActionView
|
||||
module Template::Handlers
|
||||
class Html < Raw
|
||||
def call(template)
|
||||
def call(template, source)
|
||||
"ActionView::OutputBuffer.new #{super}"
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
module ActionView
|
||||
module Template::Handlers
|
||||
class Raw
|
||||
def call(template)
|
||||
"#{template.source.inspect}.html_safe;"
|
||||
def call(template, source)
|
||||
"#{source.inspect}.html_safe;"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -58,7 +58,7 @@ module RenderERBUtils
|
|||
template = ActionView::Template.new(
|
||||
string.strip,
|
||||
"test template",
|
||||
ActionView::Template::Handlers::ERB,
|
||||
ActionView::Template.handler_for_extension(:erb),
|
||||
{})
|
||||
|
||||
template.render(ActionView::Base.empty, {}).strip
|
||||
|
|
|
@ -70,7 +70,7 @@ class LayoutAutoDiscoveryTest < ActionController::TestCase
|
|||
end
|
||||
|
||||
def test_third_party_template_library_auto_discovers_layout
|
||||
with_template_handler :mab, lambda { |template| template.source.inspect } do
|
||||
with_template_handler :mab, lambda { |template, source| source.inspect } do
|
||||
@controller = ThirdPartyTemplateLibraryController.new
|
||||
get :hello
|
||||
assert_response :success
|
||||
|
@ -212,7 +212,7 @@ class LayoutSetInResponseTest < ActionController::TestCase
|
|||
end
|
||||
|
||||
def test_layout_set_when_using_render
|
||||
with_template_handler :mab, lambda { |template| template.source.inspect } do
|
||||
with_template_handler :mab, lambda { |template, source| source.inspect } do
|
||||
@controller = SetsLayoutInRenderController.new
|
||||
get :hello
|
||||
assert_includes @response.body, "layouts/third_party_template_library.mab"
|
||||
|
|
|
@ -17,8 +17,8 @@ class FakeTemplate
|
|||
end
|
||||
end
|
||||
|
||||
Neckbeard = lambda { |template| template.source }
|
||||
Bowtie = lambda { |template| template.source }
|
||||
Neckbeard = lambda { |template, source| source }
|
||||
Bowtie = lambda { |template, source| source }
|
||||
|
||||
class DependencyTrackerTest < ActionView::TestCase
|
||||
def tracker
|
||||
|
|
|
@ -450,13 +450,22 @@ module RenderTestCases
|
|||
assert_equal "Hello, World!", @view.render(inline: "Hello, World!", type: :bar)
|
||||
end
|
||||
|
||||
CustomHandler = lambda do |template|
|
||||
CustomHandler = lambda do |template, source|
|
||||
"@output_buffer = ''.dup\n" \
|
||||
"@output_buffer << 'source: #{template.source.inspect}'\n"
|
||||
"@output_buffer << 'source: #{source.inspect}'\n"
|
||||
end
|
||||
|
||||
def test_render_inline_with_render_from_to_proc
|
||||
ActionView::Template.register_template_handler :ruby_handler, :source.to_proc
|
||||
ActionView::Template.register_template_handler :ruby_handler, lambda { |_, source| source }
|
||||
assert_equal "3", @view.render(inline: "(1 + 2).to_s", type: :ruby_handler)
|
||||
ensure
|
||||
ActionView::Template.unregister_template_handler :ruby_handler
|
||||
end
|
||||
|
||||
def test_render_inline_with_render_from_to_proc_deprecated
|
||||
assert_deprecated do
|
||||
ActionView::Template.register_template_handler :ruby_handler, :source.to_proc
|
||||
end
|
||||
assert_equal "3", @view.render(inline: "(1 + 2).to_s", type: :ruby_handler)
|
||||
ensure
|
||||
ActionView::Template.unregister_template_handler :ruby_handler
|
||||
|
|
Loading…
Reference in New Issue