Skip to content

Conversation

@felixefelip
Copy link

@felixefelip felixefelip commented Sep 8, 2025

ERB to Ruby code conversion is needed to type-check ERB.

Input:

<html>
  <body>
    <ul>
    <% languages.each do |langage| %>
      <li><%= language %>
    <% end %>
    </ul>
  </body>
</html>

Output: (replace HTML tags with whitespace)

      
        
        
       languages.each do |langage|   
              language   
       end   
         
         
       

refs: #1409

Use class << self for private methods
@felixefelip felixefelip force-pushed the support_erb/convert_erb_code_into_ruby_before_type_checking branch from fd6e3c4 to 63cbedc Compare September 8, 2025 15:34
@ParadoxV5
Copy link
Contributor

Good idea, but I suggest making use of ERB::Compiler so you don’t have to parse things yourself.

Additionally, ERB isn’t limited to Rails, let alone HTML.
Your parser probably doesn’t care, but the test appears designed for Rails only.

@felixefelip
Copy link
Author

@ParadoxV5 thanks for the review!

Good idea, but I suggest making use of ERB::Compiler so you don’t have to parse things yourself.

The ERB::Compiler looks great, I'm going to use it.

Additionally, ERB isn’t limited to Rails, let alone HTML. Your parser probably doesn’t care, but the test appears designed for Rails only.

My fault, I'm used ERB only with Rails, I'm going to adjust the tests examples.

Regarding moving this to RBS, I will analyze the projects better to give an opinion.

@felixefelip
Copy link
Author

felixefelip commented Oct 19, 2025

@ParadoxV5 I have not found a way to use ERB::Compiler for the proposal of this PR. Could you instruct me on how to use it, please?

Alternatively, I found the Herb that almost provides the parser we need. Herb just doesn't provide a public API with Ruby code with semicolons, but I'm trying to make a contribution to doing that here. It's ok to use that?

@ParadoxV5
Copy link
Contributor

ParadoxV5 commented Oct 25, 2025

@felixefelip:

Could you instruct me on how to use it, please?

The documentation above class ERB::Compiler reads: (formatting mine)

expand/collapse section

Internally ERB does something like this to generate the code returned by ERB#src:

compiler = ERB::Compiler.new('<>')
compiler.pre_cmd    = ["_erbout=+''"]
compiler.put_cmd    = "_erbout.<<"
compiler.insert_cmd = "_erbout.<<"
compiler.post_cmd   = ["_erbout"]

code, enc = compiler.compile("Got <%= obj %>!\n")
puts code

Generates:

  #coding:UTF-8
  _erbout=+''; _erbout.<< "Got ".freeze; _erbout.<<(( obj ).to_s); _erbout.<< "!\n".freeze; _erbout

By default the output is sent to the print method. For example:

compiler = ERB::Compiler.new('<>')
code, enc = compiler.compile("Got <%= obj %>!\n")
puts code

Generates:

#coding:UTF-8
print "Got ".freeze; print(( obj ).to_s); print "!\n".freeze

That means, ERB::Compiler.new(flags).compile(erb_file).first generates a string containing code that ERB executes to process ERB files, with Ruby instructions as-is and ERB text (e.g., HTML) outputted via Kernel#print.
You can pass this generated code to some Steep API (or dump to a temporary file if all fails).
You can also optionally configure an ERB::Compiler to be more Steep-user-friendly.
(There might be a way to completely ignore the verbatim texts, too.)

erb = ERB::Compiler.new nil
erb.put_cmd = erb.insert_cmd= "\n"
puts erb.compile('Got <%= process(obj) %>!').first
#coding:UTF-8

 "Got ".freeze;
(( process(obj) ).to_s);
 "!".freeze

It's ok to use that?

Assuming Herb.extract_ruby works with non-HTML as well, then my only concern is that ERB is still preferable for its popularity and StdLib status.

@felixefelip
Copy link
Author

felixefelip commented Oct 27, 2025

Thanks for the instructions @ParadoxV5!

I might have misunderstood some part, but I still couldn't to handle the verbatim texts like .freeze with the ERB::Compiler, and it's important the parsed code to preserve the exact number and position characters of original source code to display the Steep diagnostics. ERB::Compiler seems to be more designed to use for Kernel#print and not for a parser.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants