DEV Community

RobL
RobL

Posted on

How do you test frozen_string_literal in Ruby?

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 
Enter fullscreen mode Exit fullscreen mode

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 
Enter fullscreen mode Exit fullscreen mode

Here goes

% ruby frozen.rb --/Users/roblacey/repos/personal/robl.me/frozen.rb 60 60 60 60 
Enter fullscreen mode Exit fullscreen mode

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 %> 
Enter fullscreen mode Exit fullscreen mode

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" 
Enter fullscreen mode Exit fullscreen mode

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 
Enter fullscreen mode Exit fullscreen mode

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>' 
Enter fullscreen mode Exit fullscreen mode

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 %> 
Enter fullscreen mode Exit fullscreen mode
require 'erb' => true irb(main):003> ERB.new(File.read('frozen.erb')).result(binding) --(erb) 27600 27600 27600 27600 
Enter fullscreen mode Exit fullscreen mode

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 
Enter fullscreen mode Exit fullscreen mode
require 'haml' => true irb(main):003> (Haml::Template.new() { File.read('frozen.haml') }).render --(__TEMPLATE__) 48000 48020 48040 48060 
Enter fullscreen mode Exit fullscreen mode

Top comments (2)

Collapse
 
castwide profile image
Fred Snyder • Edited

In ERB, the comment needs the code tags.

<%# frozen_string_literal: true %> <%= 'hi'.upcase! %> 
Enter fullscreen mode Exit fullscreen mode

When rendered, it raises FrozenError:

(erb):3:in `upcase!': can't modify frozen String: "hi" (FrozenError) 
Enter fullscreen mode Exit fullscreen mode
Collapse
 
braindeaf profile image
RobL

Seems so obvious now. Cheers.