Can we use frozen_string_literal in Haml? WTF?
One of the Rails developers on LinkedIn (Ruby on Rails group) asked a non-silly question:
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?– Rob Lacey
My initial thought was that it’s impossible. Haml is a templating language for creating HTML. Therefore, there is no need to add a Ruby magic comment to it. This is where I could end this discussion.
Experiment
I wouldn’t be myself if I didn’t conduct a short experiment. I think we can use RuboCop, which has the Style/FrozenStringLiteralComment cop.
Disclaimer! I openly admit that what I’m doing here is for the purpose of mental exercise.
For this experiment, my environment looked like this:
$ ruby --version
ruby 3.2.2 [x86_64-linux]
$ rubocop --version
1.59.0
$ haml-lint --version
haml-lint 0.52.0
I created a simple, yet not empty, Haml file.
echo "Seeking a new Ruby on Rails project" > hire_me.haml
I’ll note that a valid Haml file doesn’t have to include HTML tags. I also emphasize that I used only letters and spaces here, without special characters and punctuation. This is a unique case, but it will allowed me to experiment from start to finish. In short, I wanted to avoid characters interpreted by Haml, such as hash, dot, and percent.
Here is the hire_me.haml
file:
Seeking a new Ruby on Rails project
BTW I shared this article with the question author - Rob Lacey. I also received a response from him in an article form. So I allow myself a small clarification.
The initial file (the one above) is a valid Haml-formatted file. I verified this by using a Haml linter.
$ haml-lint hire_me.haml
1 file inspected, 0 lints detected
I ran RuboCop on this file.
$ rubocop hire_me.haml --only Style/FrozenStringLiteralComment
Inspecting 1 file
C
Offenses:
hire_me.haml:1:1: C: [Correctable] Style/FrozenStringLiteralComment:
Missing frozen string literal comment.
Seeking a new Ruby on Rails project
^
1 file inspected, 1 offense detected, 1 offense autocorrectable
I noticed that RuboCop allows for auto-correction of this file. Why not give it a try? The fact that it is possible doesn’t necessarily mean that the result will be a valid Haml file. That’s the essence of a true experiment.
$ rubocop hire_me.haml -A
Inspecting 1 file
C
Offenses:
hire_me.haml:1:1: C: [Corrected] Style/FrozenStringLiteralComment:
Missing frozen string literal comment.
Seeking a new Ruby on Rails project
^
hire_me.haml:2:1: C: [Corrected] Layout/EmptyLineAfterMagicComment:
Add an empty line after magic comments.
Seeking a new Ruby on Rails project
^
1 file inspected, 2 offenses detected, 2 offenses corrected
It wasn’t flagged as a safe auto-correction, but it doesn’t matter, and it’s correct because this process was successful.
I checked the content of the file after the correction.
$ cat hire_me.haml
# frozen_string_literal: true
Seeking a new Ruby on Rails project
And I rerun RuboCop on the file.
$ rubocop hire_me.haml --only Style/FrozenStringLiteralComment
Inspecting 1 file
.
1 file inspected, no offenses detected
It seems that using the magic comment like # frozen_string_literal: true
in a Haml file is possible, and RuboCop is satisfied with it.
However, I agree with Rob Lacey that the result is not a valid Haml file.
I see where you’re going with this. Rubocop must know how to fix this. The problem is that # frozen_string_literal: true is not valid Haml.
$ haml-lint hire_me.haml
hire_me.haml:0 [E] Syntax: hire_me.haml - Illegal element:
classes and ids must have values.
1 file inspected, 1 lint detected
Continuing further, I commented out the line with the Ruby magic comment according to Haml syntax.
$ cat hire_me.haml
-# frozen_string_literal: true
Seeking a new Ruby on Rails project
After making the change, I ensured that the Haml file syntax is correct.
$ haml-lint hire_me.haml
1 file inspected, 0 lints detected
And what does RuboCop think about it?
$ rubocop hire_me.haml --only Style/FrozenStringLiteralComment
Inspecting 1 file
F
Offenses:
hire_me.haml:3:9: F: Lint/Syntax: unexpected token tIDENTIFIER
(Using Ruby 3.2 parser; configure using TargetRubyVersion parameter, under AllCops)
Seeking a new Ruby on Rails project
^
1 file inspected, 1 offense detected
As you can see, RuboCop is not happy about it. Rob also mentioned this in his article:
His theory was Rubocop must know how to solve this. Sadly.
# frozen_string_literal: true SOMETHING
Is not valid Haml.
As I mentioned before, I know this is not a valid Haml file. If I understood Rob correctly, I also believe that RuboCop should not suggest auto-correction in such a case. However, we need to remember that RuboCop is just a tool. The programmer makes the final decisions. Just because we can, doesn’t necessarily mean we should. Personally, I would exclude all Haml files from RuboCop analysis.
# .rubocop.yml
AllCops:
Exclude:
- '**/*.haml'
I’m just expressing my opinion. But I don’t have the full context of the issue, so I might be missing something. I think I now better understand the context of what Rob meant when asking his question. Rob wants to leverage the behavior provided by frozen_string_literal
so that the same strings in templates (Haml, Slim, Erb) are the same object in memory. I think this expectation makes a lot of sense. How to achieve this? That is a much deeper and another question.
Thank you to Rob, the question author, for inspiring this little experiment.