Skip to content

Commit a797083

Browse files
authored
Merge pull request rails#43725 from Shopify/erubi-frozen-string-literals
Action View: compile ERB templates with `# frozen_string_literal: true`
2 parents bd6f580 + 6dc9e33 commit a797083

File tree

4 files changed

+44
-1
lines changed

4 files changed

+44
-1
lines changed

actionview/lib/action_view/railtie.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ class Railtie < Rails::Engine # :nodoc:
4747
end
4848
end
4949

50+
config.after_initialize do |app|
51+
frozen_string_literal = app.config.action_view.delete(:frozen_string_literal)
52+
ActionView::Template.frozen_string_literal = frozen_string_literal
53+
end
54+
5055
config.after_initialize do |app|
5156
ActionView::Helpers::AssetTagHelper.image_loading = app.config.action_view.delete(:image_loading)
5257
ActionView::Helpers::AssetTagHelper.image_decoding = app.config.action_view.delete(:image_decoding)

actionview/lib/action_view/template.rb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,9 @@ class Template
114114

115115
extend Template::Handlers
116116

117+
singleton_class.attr_accessor :frozen_string_literal
118+
@frozen_string_literal = false
119+
117120
attr_reader :identifier, :handler
118121
attr_reader :variable, :format, :variant, :locals, :virtual_path
119122

@@ -297,7 +300,11 @@ def #{method_name}(local_assigns, output_buffer)
297300
end
298301

299302
begin
300-
mod.module_eval(source, identifier, 0)
303+
if Template.frozen_string_literal
304+
mod.module_eval("# frozen_string_literal: true\n#{source}", identifier, -1)
305+
else
306+
mod.module_eval(source, identifier, 0)
307+
end
301308
rescue SyntaxError
302309
# Account for when code in the template is not syntactically valid; e.g. if we're using
303310
# ERB and the user writes <%= foo( %>, attempting to call a helper `foo` and interpolate

actionview/test/template/render_test.rb

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,33 @@ def test_render_object
702702
@view.render(TestRenderable.new)
703703
)
704704
end
705+
706+
def test_render_mutate_string_literal
707+
assert_equal "foobar", @view.render(inline: "'foo' << 'bar'", type: :ruby)
708+
end
709+
end
710+
711+
class FrozenStringLiteralEnabledViewRenderTest < ActiveSupport::TestCase
712+
include RenderTestCases
713+
714+
def setup
715+
@previous_frozen_literal = ActionView::Template.frozen_string_literal
716+
ActionView::Template.frozen_string_literal = true
717+
view_paths = ActionController::Base.view_paths
718+
setup_view(view_paths)
719+
end
720+
721+
def teardown
722+
super
723+
ActionView::Template.frozen_string_literal = @previous_frozen_literal
724+
end
725+
726+
def test_render_mutate_string_literal
727+
error = assert_raise ActionView::Template::Error do
728+
@view.render(inline: "'foo' << 'bar'", type: :ruby)
729+
end
730+
assert_includes(error.message, "can't modify frozen String")
731+
end
705732
end
706733

707734
class CachedViewRenderTest < ActiveSupport::TestCase

guides/source/configuring.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1105,6 +1105,10 @@ Accepts a logger conforming to the interface of Log4r or the default Ruby Logger
11051105

11061106
Gives the trim mode to be used by ERB. It defaults to `'-'`, which turns on trimming of tail spaces and newline when using `<%= -%>` or `<%= =%>`. See the [Erubis documentation](http://www.kuwata-lab.com/erubis/users-guide.06.html#topics-trimspaces) for more information.
11071107

1108+
#### `config.action_view.frozen_string_literal`
1109+
1110+
Compiles the ERB template with the `# frozen_string_literal: true` magic comment, making all string literals frozen and saving allocations. Set to `true` to enable it for all views.
1111+
11081112
#### `config.action_view.embed_authenticity_token_in_remote_forms`
11091113

11101114
Allows you to set the default behavior for `authenticity_token` in forms with

0 commit comments

Comments
 (0)