Just posed the question on LinkedIn'
Potentially silly question, I am not ashamed of not knowing this... How do you mark a Haml file with the magic comment # frozen_string_literal: true. Is it even possible?
https://www.linkedin.com/feed/update/urn:li:activity:7140300572573724673/
Alek K came back with a bit of research. I'm a fan of poking something with a stick.
That's a quite interesting question, one I've never thought of myself before. As a response, I wrote a short article on my blog, describing a little experiment. I hope this can shed some light on the issue.
https://torrocus.com/blog/haml-with-frozen-string-literal-wtf/
His theory was Rubocop must know how to solve this. Sadly.
# frozen_string_literal: true
SOMETHING
Is not valid Haml. Since it's trying to render a # which would be a div with no id. Simply won't work. I thought I'd take a quick stab at this.
Suppose we have. Silly example. But all I want to prove is that with frozen_string_literal that the object_id is the same for all instances of "A" since it's the same String.
# frozen_string_literal: true
puts "--#{__FILE__}"
puts "A".object_id
puts "A".object_id
puts "A".object_id
puts "A".object_id
Here goes
% ruby frozen.rb
--/Users/roblacey/repos/personal/robl.me/frozen.rb
60
60
60
60
Yep it's the same object_id everytime. So how would we even test this in Erb?
# frozen_string_literal: true
<% puts "--#{__FILE__}" %>
<% puts "A".object_id %>
<% puts "A".object_id %>
<% puts "A".object_id %>
<% puts "A".object_id %>
I guess we do...
% irb
irb(main):001> require 'erb'
irb(main):002> ERB.new(File.read('frozen.erb')).result(binding)
--(erb)
7980
8000
8020
8040
=> "# frozen_string_literal: true\n\n\n\n\n\n"
Nope none of these are the same object_id. There is some more magic going on. Indeed our Haml file is going to fail with what we saw before.
# frozen_string_literal: true
- puts "--#{__FILE__}"
- puts "A".object_id
- puts "A".object_id
- puts "A".object_id
- puts "A".object_id
Yep fails.
require 'haml'
=> true
irb(main):005> (Haml::Template.new() { File.read('frozen.haml') }).render
(__TEMPLATE__):2:in `__tilt_18120': Illegal element: classes and ids must have values. (Haml::SyntaxError)
from /Users/roblacey/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/tilt-2.3.0/lib/tilt/template.rb:207:in `bind_call'
from /Users/roblacey/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/tilt-2.3.0/lib/tilt/template.rb:207:in `evaluate'
from /Users/roblacey/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/tilt-2.3.0/lib/tilt/template.rb:102:in `render'
from (irb):5:in `<main>'
from /Users/roblacey/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/irb-1.9.1/exe/irb:9:in `<top (required)>'
from /Users/roblacey/.asdf/installs/ruby/3.2.2/bin/irb:25:in `load'
from /Users/roblacey/.asdf/installs/ruby/3.2.2/bin/irb:25:in `<main>'
So honestly, I am not sure how this even works with ERB templates in Rails. I need to take a further dig into the Rails source to find out more.
Anyone, Bueller?
UPDATE: Cheers @castwide seems so obvious now. erb templates aren't Ruby they are just converted/eval'ed into Ruby. So this makes sense if the first line is the comment has the comment delimited.
<%# frozen_string_literal: true %>
<% puts "--#{__FILE__}" %>
<% puts "A".object_id %>
<% puts "A".object_id %>
<% puts "A".object_id %>
<% puts "A".object_id %>
require 'erb'
=> true
irb(main):003> ERB.new(File.read('frozen.erb')).result(binding)
--(erb)
27600
27600
27600
27600
Haml clearly doesn't work in the same way. As we can't just replicate it.
-# frozen_string_literal: true
- puts "--#{__FILE__}"
- puts "A".object_id
- puts "A".object_id
- puts "A".object_id
- puts "A".object_id
require 'haml'
=> true
irb(main):003> (Haml::Template.new() { File.read('frozen.haml') }).render
--(__TEMPLATE__)
48000
48020
48040
48060
Top comments (2)
In ERB, the comment needs the code tags.
When rendered, it raises
FrozenError
:Seems so obvious now. Cheers.