DEV Community

RobL
RobL

Posted on

2

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

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

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.

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay