Where Is Ruby's Erb Format "Officially" Defined

Where is Ruby's ERB format officially defined?

erb was developed by Masatoshi Seki as a Ruby implementation of eRuby, so its specification almost follows that of eRuby. One difference the author mentions is:

% cat hello.erb
Hello, <% print "World" %>.

% eruby hello.erb
Hello, World.

% erb hello.erb
WorldHello, .

in which case you can do:

% cat hello2.erb
Hello, <%= "World" %>.

% eruby hello2.erb
Hello, World.

% erb hello2.erb
Hello, World.

to let them work the same way.

Here is an explanation about it by the author, and here and here are documentation written by the author.

What is the difference between %, %=, %# and -% in ERB in Rails?

<% %>

Executes the ruby code within the brackets.

<%= %>

Prints something into erb file.

<%== %>

Equivalent to <%= raw %>. Prints something verbatim (i.e. w/o escaping) into erb file. (Taken from Ruby on Rails Guides.)

<% -%>

Avoids line break after expression.

<%# %>

Comments out code within brackets; not sent to client (as opposed to HTML comments).

Visit Ruby Doc for more infos about ERB.

where does the _() underscore syntax in Typo ERB files come from?

As the comments have said, it is indeed the localisation function.

It is this plugin in Typo and you can see the actual method declaration here.

How to show app data in erb template?

You forgot the <%= %> to display the value of item:

<ul>
<% @post.tags.each do |item| %>
<li><%= item %></li>
<% end %>
</ul>

Indentation in ERB templates

The only solution I can offer is hackish adding <%- 'whatever here' %> before the <%= %> entry:

<% [1,2,3].each do |f| %>
<%- 1 %><%= f %>
<% end %>

it outputs in irb

irb(main):018:0> ERB.new(File.read('f.txt'), nil, '-').result
=> "\n1\n\n2\n\n3\n\n"

Rails doc claims, that default value for ERB trim_mode is -
http://edgeguides.rubyonrails.org/configuring.html#configuring-action-view

And according to https://www.systutorials.com/docs/linux/man/1-erb/ ERB should remove spaces before <%- when - mode is enabled.

#{ } notation vs. erb notation

One downside of trying to use ERB for general string interpolation is that ERB is really aimed at generating HTML. The result will be lots of encoding issues when you forget to raw-ify everything and get confused about why your ampersands, greater-than, less-than, etc. symbols are getting mangled.

I think there'll be more computational overhead for ERB as well but this might not matter.

Furthermore, if you put inlined ERB inside Ruby will end up with Ruby inside ERB inside Ruby (and quite possibly more levels as you call methods from within ERB) and that will be a bit of a confusing mess. Think of the poor souls that will have to maintain your code, said poor soul might even be you.

UPDATE: You could use #{} for simple HTML templates (see Mustache for something like that) but it would be difficult and rather ugly to produce a repeated section; repeated sections are quite common in HTML templates so that should be easy and natural for an HTML template system. With ERB, you can just:

<% a.each do |e| %>
<!-- ... -->
<% end %>

but that would be a mess in #{} interpolation. You'd also end up doing #{html(blahblah)} all the time and most people would forget.

Also, "#" has a special meaning in URLs and a different special meaning in CSS (where braces also have a special meaning); fragment URLs and chunks of CSS are fairly common in HTML templates so you'd be constantly worrying about mixing up things up. This particular bit of nastiness would probably only be an issue when using #{} to produce a CSS selector or a fragment in a URL but that's enough to make it cumbersome.

Why is this an error with ERB?

If you look at the code outputted by erb -x -T - test.erb:

#coding:ASCII-8BIT
_erbout = ''; _erbout.concat "<div class='row'>\n "
; _erbout.concat(( form.field_container :name do ).to_s); _erbout.concat "\n"
; _erbout.concat " "; _erbout.concat(( form.label :name, raw('Name' + content_tag(:span, ' *', :class => 'required')) ).to_s); _erbout.concat "\n"
; _erbout.concat " "; _erbout.concat(( form.text_field :name, :class => 'fullwidth' ).to_s); _erbout.concat "\n"
; _erbout.concat " "; _erbout.concat(( form.error_message_on :name ).to_s); _erbout.concat "\n"
; _erbout.concat " "; end ; _erbout.concat "\n"
; _erbout.concat "</div>\n"
; _erbout.force_encoding(__ENCODING__)

You can see that on the third line, a do is followed by a ). Ruby is expecting a doend block, but gets a closing parenthesis. That’s the immediate cause of the syntax error.

The reason for erb outtputting bad code is that you are using <%= when you should be using <%. Changing your code to this fixes the syntax error:

<div class='row'>
<% form.field_container :name do %>
<%= form.label :name, raw('Name' + content_tag(:span, ' *', :class => 'required')) %>
<%= form.text_field :name, :class => 'fullwidth' %>
<%= form.error_message_on :name %>
<% end %>
</div>

I can’t run this code to test if it outputs what it should after my change, but the code generated by erb looks like it will work:

#coding:ASCII-8BIT
_erbout = ''; _erbout.concat "<div class='row'>\n "
; form.field_container :name do ; _erbout.concat "\n"
; _erbout.concat " "; _erbout.concat(( form.label :name, raw('Name' + content_tag(:span, ' *', :class => 'required')) ).to_s); _erbout.concat "\n"
# more...

Edit

Since this solution apparently does break the output, I looked into what mu is too short suggested. I checked if Erubis, which Rails 3 uses by default, behaves differently from ERB. The code outputted by erubis -x -T - test.erb (with the original, unedited test.erb):

_buf = ''; _buf << '<div class=\'row\'>
'; _buf << ( form.field_container :name do ).to_s; _buf << '
'; _buf << ' '; _buf << ( form.label :name, raw('Name' + content_tag(:span, ' *', :class => 'required')) ).to_s; _buf << '
'; _buf << ' '; _buf << ( form.text_field :name, :class => 'fullwidth' ).to_s; _buf << '
'; _buf << ' '; _buf << ( form.error_message_on :name ).to_s; _buf << '
'; end
_buf << '</div>
';
_buf.to_s

Line three has the exact same problem, and erubis -x -T - test.erb | ruby -c outputs the same syntax error. So the differences between ERB and Erubis are probably not the problem.

I also tried syntax-checking this piece of code from the official Rails documentation:

<%= form_for(zone) do |f| %>
<p>
<b>Zone name</b><br />
<%= f.text_field :name %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>

It gets the same syntax error. So it’s not that your ERB code is badly written; your code is very similar to that example.

At this point my best guess is that erb’s -x flag, which translates an ERB template into Ruby code instead of evaluating it directly, is flawed, and does not support some features it should. Though now that I think about it, I am having trouble imagining exactly what Ruby code should be outputted when you output the result of a block that itself outputs text should work. At what times should each of the outputs be written – the result first, or the block contents first?

Include ERB delimiters inside of a string in an ERB block

If I'm understanding you right, your real problem is that heredocs behave like double quotes as far as interpolation is concerned. So all you need is a quoting mechanism that behaves like single quotes. Ruby has lots of string quoting mechanisms, in particular we have %q{...}:

<% code = %q{
<div>
#{ image_tag 'image.png' }
</div>
} %>

You can use other delimiters if you'd like: %q|...|, %q(...), etc. There's still a change of course but at least you don't have to worry about interpolation problems.

If you really want to use a heredoc, you can specify the heredoc terminator with quotes and the corresponding quoting style will apply to the content:

<% code = <<'PLACE_THE_EXAMPLE_CODE_BETWEEN_THESE_TWO_LINES_EXACTLY_AS_YOU_WANT_IT_TO_APPEAR'
<div>
#{ image_tag 'image.png' }
</div>
PLACE_THE_EXAMPLE_CODE_BETWEEN_THESE_TWO_LINES_EXACTLY_AS_YOU_WANT_IT_TO_APPEAR
%>

The single quotes in <<'PLACE...' specify that single quoting rules (i.e. no interpolation) apply to the heredoc's content.


Of course none of that stuff will work with embedded ERB like this:

<% code = %q{
<div>
<% ... %>
</div>
} %>

because the ERB parser will see the first %> as the closing delimiter for the outer <% code... part. Fear not, I think I have a plan that will work without involving gross hacks or too much work.

Some preliminaries:

  • Rails uses Erubis for ERB processing.
  • Erubis allows you to change the delimiters with the :pattern option to its constructor.
  • Rails uses Tilt and Sprockets to handle the template processing pipeline, these allow you to make the right things happen to pancakes.js.coffee.erb in the right order.

Using the above you can add your own template format that is ERB with a different delimiter and you can have Rails use this new format to handle your "special" sections before the normal ERB processing can make a mess of things.

First you need to hook up Tilt. If you have a look at lib/tilt/erb.rb in your Tilt installation, you'll see the Erubis stuff in Tilt::ErubisTemplate at the bottom. You should be able to subclass Tilt::ErubisTemplate and provide a prepare override that adds, say, a :pattern => '<!--% %-->' option and punts to the superclass. Then register this with Tilt and Sprockets in a Rails initializer with something like this:

Tilt.register(Your::Template::Subclass, 'klerb') # "kl" for "kludge" :)
Rails.application.assets.register_engine('.klerb', Your::Template::Subclass)

Now your application should be able to handle .klerb files with <!--% ... %--> as the template delimiters. And you can also chain your klerb with erb using names like pancakes.html.erb.klerb and the file will go through klerb before the ERB; this means that templates like this (in a file called whatever.html.erb.klerb):

<!--% code = <<PLACE_THE_EXAMPLE_CODE_BETWEEN_THESE_TWO_LINES_EXACTLY_AS_YOU_WANT_IT_TO_APPEAR
<div>
<% image_tag 'image.png' %>
</div>
PLACE_THE_EXAMPLE_CODE_BETWEEN_THESE_TWO_LINES_EXACTLY_AS_YOU_WANT_IT_TO_APPEAR
%-->
<!--%= "code = escape_the_erb_as_needed(%q{#{code}})" %-->
<% do_normal_erb_stuff %>

will do The Right Thing.

You'd need a helper to implement the escape_the_erb_as_needed functionality of course; a little experimentation should help you sort out what needs to be escape and in what way.

All that might look a bit complicated but it is really pretty straight forward. I've added custom template processing steps using Tilt and Sprockets and it turned out to be pretty simple in the end; figuring out which simple things to do took some work but I've already done that work for you:

  1. Tilt::Template subclass, you get this by piggy backing on Tilt::ErubisTemplate.
  2. Register with Tilt by calling Tilt.register.
  3. Register with Sprockets by calling Rails.application.assets.register_engine.
  4. ...
  5. Profit.

How to write an enumeration on one line with erb

Assuming

@results = ["foo\n", "bar\n"]

Then:

<%= (@results.map  { |s| s.gsub('\n','') }.join('<br>') + "<br>").html_safe %>


Related Topics



Leave a reply



Submit