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 irbirb(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 do
…end
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.
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:
Tilt::Template
subclass, you get this by piggy backing onTilt::ErubisTemplate
.- Register with Tilt by calling
Tilt.register
. - Register with Sprockets by calling
Rails.application.assets.register_engine
. - ...
- 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
Ruby 1.9 How to Convert Array to String Without Brackets
What Is Ruby's Stringio Class Really
Reading Files in a Zip Archive, Without Unzipping The Archive
Using Ruby with Mechanize to Log into a Website
Using Rails with Paperclip and Swfupload
Typeerror: Can't Convert Net::Httpok into String
Sorting Hash of Hashes by Value (And Return The Hash, Not an Array)
Starting with Redmine Locally - How Easy Is Migration to Server Later
Need Help Installing Ruby 2.7.2 on Mac
How to Update All of My Products to a Specific User When Seeding
Is 'Respond_To_Missing''s Second Argument Useful for Anything
What Ruby Technique Does Rails Use to Make My Controller Methods Render Views
Accessing Microsoft Exchange Server from Ruby
Obtaining Number of Block Parameters
How to Deploy a Threadsafe Asynchronous Rails App