Erubis Users' Guide

2   Tutorial

2-1   Basic Example

Here is a basic example of Erubis.

example1.eruby
<ul>
  <% for item in list %>
  <li><%= item %></li>
  <% end %>
  <%# here is ignored because starting with '#' %>
</ul>
example1.rb
require 'erubis'
input = File.read('example1.eruby')
eruby = Erubis::Eruby.new(input)    # create Eruby object

puts "---------- script source ---"
puts eruby.src                      # print script source

puts "---------- result ----------"
list = ['aaa', 'bbb', 'ccc']
puts eruby.result(binding())        # get result
## or puts eruby.result(:list=>list)  # or pass Hash instead of Binding

## # or
## eruby = Erubis::Eruby.new
## input = File.read('example1.eruby')
## src = eruby.convert(input)
## eval src
output
$ ruby example1.rb
---------- script source ---
_buf = ''; _buf << '<ul>
';   for item in list 
 _buf << '  <li>'; _buf << ( item ).to_s; _buf << '</li>
';   end 

 _buf << '</ul>
';
_buf.to_s
---------- result ----------
<ul>
  <li>aaa</li>
  <li>bbb</li>
  <li>ccc</li>
</ul>

Erubis has command 'erubis'. Command-line option '-x' shows the compiled source code of eRuby script.

example of command-line option '-x'
$ erubis -x example1.eruby
_buf = ''; _buf << '<ul>
';   for item in list 
 _buf << '  <li>'; _buf << ( item ).to_s; _buf << '</li>
';   end 

 _buf << '</ul>
';
_buf.to_s

2-2   Trimming Spaces

Erubis deletes spaces around '<% %>' automatically, while it leaves spaces around '<%= %>'.

example2.eruby
<ul>
  <% for item in list %>      # trimmed
  <li>
    <%= item %>               # not trimmed
  </li>
  <% end %>                   # trimmed
</ul>
compiled source code
$ erubis -x example2.eruby
_buf = ''; _buf << '<ul>
';   for item in list 
 _buf << '  <li>
    '; _buf << ( item ).to_s; _buf << '
'; _buf << '  </li>
';   end 
 _buf << '</ul>
';
_buf.to_s

If you want leave spaces around '<% %>', add command-line property '--trim=false'.

compiled source code with command-line property '--trim=false'
$ erubis -x --trim=false example2.eruby
_buf = ''; _buf << '<ul>
'; _buf << '  '; for item in list ; _buf << '
'; _buf << '  <li>
    '; _buf << ( item ).to_s; _buf << '
'; _buf << '  </li>
'; _buf << '  '; end ; _buf << '
'; _buf << '</ul>
';
_buf.to_s

Or add option :trim=>false to Erubis::Eruby.new().

example2.rb
require 'erubis'
input = File.read('example2.eruby')
eruby = Erubis::Eruby.new(input, :trim=>false)

puts "----- script source ---"
puts eruby.src                            # print script source

puts "----- result ----------"
list = ['aaa', 'bbb', 'ccc']
puts eruby.result(binding())              # get result
output
$ ruby example2.rb
----- script source ---
_buf = ''; _buf << '<ul>
'; _buf << '  '; for item in list ; _buf << '
'; _buf << '  <li>
    '; _buf << ( item ).to_s; _buf << '
'; _buf << '  </li>
'; _buf << '  '; end ; _buf << '
'; _buf << '</ul>
';
_buf.to_s
----- result ----------
<ul>
  
  <li>
    aaa
  </li>
  
  <li>
    bbb
  </li>
  
  <li>
    ccc
  </li>
  
</ul>

2-3   Escape

Erubis has ability to escape (sanitize) expression. Erubis::Eruby class act as the following:

  • <%= expr %> - not escaped.
  • <%== expr %> - escaped.
  • <%=== expr %> - out to $stderr.
  • <%==== expr %> - ignored.

Erubis::EscapedEruby(*1) class handle '<%= %>' as escaped and '<%== %>' as not escaped. It means that using Erubis::EscapedEruby you can escape expression by default. Also Erubis::XmlEruby class (which is equivalent to Erubis::EscapedEruby) is provided for compatibility with Erubis 1.1.

example3.eruby
<% for item in list %>
  <p><%= item %></p>
  <p><%== item %></p>
  <p><%=== item %></p>

<% end %>
example3.rb
require 'erubis'
input = File.read('example3.eruby')
eruby = Erubis::EscapedEruby.new(input)    # or Erubis::XmlEruby

puts "----- script source ---"
puts eruby.src                             # print script source

puts "----- result ----------"
list = ['<aaa>', 'b&b', '"ccc"']
puts eruby.result(binding())               # get result
output
$ ruby example3.rb 2> stderr.log
----- script source ---
_buf = ''; for item in list 
 _buf << '  <p>'; _buf << Erubis::XmlHelper.escape_xml( item ); _buf << '</p>
  <p>'; _buf << ( item ).to_s; _buf << '</p>
  <p>'; $stderr.puts("*** debug: item=#{(item).inspect}"); _buf << '</p>

'; end 
_buf.to_s
----- result ----------
  <p>&lt;aaa&gt;</p>
  <p><aaa></p>
  <p></p>

  <p>b&amp;b</p>
  <p>b&b</p>
  <p></p>

  <p>&quot;ccc&quot;</p>
  <p>"ccc"</p>
  <p></p>

$ cat stderr.log
*** debug: item="<aaa>"
*** debug: item="b&b"
*** debug: item="\"ccc\""

The command-line option '-e' will do the same action as Erubis::EscapedEruby. This option is available for any language.

$ erubis -l ruby -e example3.eruby
_buf = ''; for item in list 
 _buf << '  <p>'; _buf << Erubis::XmlHelper.escape_xml( item ); _buf << '</p>
  <p>'; _buf << ( item ).to_s; _buf << '</p>
  <p>'; $stderr.puts("*** debug: item=#{(item).inspect}"); _buf << '</p>

'; end 
_buf.to_s

Escaping function (default 'Erubis::XmlHelper.escape_xml()') can be changed by command-line property '--escapefunc=xxx' or by overriding Erubis::Eruby#escaped_expr() in subclass.

example to override Erubis::Eruby#escaped_expr()
class CGIEruby < Erubis::Eruby
  def escaped_expr(code)
    return "CGI.escapeHTML((#{code.strip}).to_s)"
    #return "h(#{code.strip})"
  end
end

class LatexEruby < Erubi::Eruby
  def escaped_expr(code)
    return "(#{code}).gsub(/[%\\]/,'\\\\\&')"
  end
end
(*1)
Erubis::EscapedEruby class includes Erubis::EscapeEnhancer which swtches the action of '<%= %>' and '<%== %>'.

2-4   Embedded Pattern

You can change embedded pattern '<% %>' to another by command-line option '-p' or option ':pattern=>...' of Erubis::Eruby.new().

example4.eruby
<!--% for item in list %-->
  <p><!--%= item %--></p>
<!--% end %-->
compiled source code with command-line option '-p'
$ erubis -x -p '<!--% %-->' example4.eruby
_buf = ''; for item in list 
 _buf << '  <p>'; _buf << ( item ).to_s; _buf << '</p>
'; end 
_buf.to_s
example4.rb
require 'erubis'
input = File.read('example4.eruby')
eruby = Erubis::Eruby.new(input, :pattern=>'<!--% %-->')
                                      # or '<(?:!--)?% %(?:--)?>'

puts "---------- script source ---"
puts eruby.src                            # print script source

puts "---------- result ----------"
list = ['aaa', 'bbb', 'ccc']
puts eruby.result(binding())              # get result
output
$ ruby example4.rb
---------- script source ---
_buf = ''; for item in list 
 _buf << '  <p>'; _buf << ( item ).to_s; _buf << '</p>
'; end 
_buf.to_s
---------- result ----------
  <p>aaa</p>
  <p>bbb</p>
  <p>ccc</p>

It is able to specify regular expression with :pattern option. Notice that you must use '(?: )' instead of '( )' for grouping. For example, '<(!--)?% %(--)?>' will not work while '<(?:!--)?% %(?:--)?>' will work.

2-5   Context Object

Context object is a set of data which are used in eRuby script. Using context object makes clear which data to be used. In Erubis, Hash object and Erubis::Context object are available as context object.

Context data can be accessible via instance variables in eRuby script.

example5.eruby
<span><%= @val %></span>
<ul>
 <% for item in @list %>
  <li><%= item %></li>
 <% end %>
</ul>
example5.rb
require 'erubis'
input = File.read('example5.eruby')
eruby = Erubis::Eruby.new(input)      # create Eruby object

## create context object
## (key means var name, which may be string or symbol.)
context = {
  :val   => 'Erubis Example',
  'list' => ['aaa', 'bbb', 'ccc'],
}
## or
# context = Erubis::Context.new()
# context['val'] = 'Erubis Example'
# context[:list] = ['aaa', 'bbb', 'ccc'],

puts eruby.evaluate(context)         # get result
output
$ ruby example5.rb
<span>Erubis Example</span>
<ul>
  <li>aaa</li>
  <li>bbb</li>
  <li>ccc</li>
</ul>

The difference between Erubis#result(binding) and Erubis#evaluate(context) is that the former invokes 'eval @src, binding' and the latter invokes 'context.instance_eval @src'. This means that data is passed into eRuby script via local variables when Eruby::binding() is called, or passed via instance variables when Eruby::evaluate() is called.

Here is the definition of Erubis#result() and Erubis#evaluate().

definition of result(binding) and evaluate(context)
def result(_binding=TOPLEVEL_BINDING)
  if _binding.is_a?(Hash)
    # load hash data as local variable
    _h = _binding
    _binding = binding()
    eval _h.collect{|k,v| "#{k} = _h[#{k.inspect}];"}.join, _binding
  end
  return eval(@src, _binding)
end

def evaluate(_context=Erubis::Context.new)
  if _context.is_a?(Hash)
    # convert hash object to Context object
    _hash = _context
    _context = Erubis::Context.new
    _hash.each {|k, v| _context[k] = v }
  end
  return _context.instance_eval(@src)
end

instance_eval() is defined at Object class so it is able to use any object as a context object as well as Hash or Erubis::Context.

example6.rb
class MyData
  attr_accessor :val, :list
end

## any object can be a context object
mydata = MyData.new
mydata.val = 'Erubis Example'
mydata.list = ['aaa', 'bbb', 'ccc']

require 'erubis'
eruby = Erubis::Eruby.new(File.read('example5.eruby'))
puts eruby.evaluate(mydata)
output
$ ruby example6.rb
<span>Erubis Example</span>
<ul>
  <li>aaa</li>
  <li>bbb</li>
  <li>ccc</li>
</ul>

It is recommended to use 'Erubis::Eruby#evaluate(context)' rather than 'Erubis::Eruby#result(binding())' because the latter has some problems. See evaluate(context) v.s. result(binding) section for details.

2-6   Context Data File

Command-line option '-f' specifies context data file. Erubis load context data file and use it as context data. Context data file can be YAML file ('*.yaml' or '*.yml') or Ruby script ('*.rb').

example7.eruby
<h1><%= @title %></h1>
<ul>
 <% for user in @users %>
  <li>
    <a href="mailto:<%= user['mail']%>"><%= user['name'] %></a>
  </li>
 <% end %>
</ul>
context.yaml
title: Users List
users:
  - name:  foo
    mail:  foo@mail.com
  - name:  bar
    mail:  bar@mail.net
  - name:  baz
    mail:  baz@mail.org
context.rb
@title = 'Users List'
@users = [
   { 'name'=>'foo', 'mail'=>'foo@mail.com' },
   { 'name'=>'bar', 'mail'=>'bar@mail.net' },
   { 'name'=>'baz', 'mail'=>'baz@mail.org' },
]
example of command-line option '-f'
$ erubis -f context.yaml example7.eruby
<h1>Users List</h1>
<ul>
  <li>
    <a href="mailto:foo@mail.com">foo</a>
  </li>
  <li>
    <a href="mailto:bar@mail.net">bar</a>
  </li>
  <li>
    <a href="mailto:baz@mail.org">baz</a>
  </li>
</ul>
$ erubis -f context.rb example7.eruby
<h1>Users List</h1>
<ul>
  <li>
    <a href="mailto:foo@mail.com">foo</a>
  </li>
  <li>
    <a href="mailto:bar@mail.net">bar</a>
  </li>
  <li>
    <a href="mailto:baz@mail.org">baz</a>
  </li>
</ul>

Command-line option '-S' converts keys of mapping in YAML data file from string into symbol. Command-line option '-B' invokes 'Erubis::Eruby#result(binding())' instead of 'Erubis::Eruby#evaluate(context)'.

2-7   Context Data String

Command-line option '-c str' enables you to specify context data in command-line. str can be YAML flow-style or Ruby code.

example8.eruby
<h1><%= @title %></h1>
<ul>
<% for item in @list %>
 <li><%= item %></li>
<% end %>
</ul>
example of YAML flow style
$ erubis -c '{title: Example, list: [AAA, BBB, CCC]}' example8.eruby
<h1>Example</h1>
<ul>
 <li>AAA</li>
 <li>BBB</li>
 <li>CCC</li>
</ul>
example of Ruby code
$ erubis -c '@title="Example"; @list=%w[AAA BBB CCC]' example8.eruby
<h1>Example</h1>
<ul>
 <li>AAA</li>
 <li>BBB</li>
 <li>CCC</li>
</ul>

2-8   Preamble and Postamble

The first line ('_buf = '';') in the compiled source code is called preamble and the last line ('_buf.to_s') is called postamble.

Command-line option '-b' skips the output of preamble and postamble.

example9.eruby
<% for item in @list %>
 <b><%= item %></b>
<% end %>
compiled source code with and without command-line option '-b'
$ erubis -x example9.eruby
_buf = ''; for item in @list 
 _buf << ' <b>'; _buf << ( item ).to_s; _buf << '</b>
'; end 
_buf.to_s
$ erubis -x -b example9.eruby
 for item in @list 
 _buf << ' <b>'; _buf << ( item ).to_s; _buf << '</b>
'; end 

Erubis::Eruby.new option ':preamble=>false' and ':postamble=>false' also suppress output of preamble or postamle.

example9.rb
require 'erubis'
input = File.read('example9.eruby')
eruby1 = Erubis::Eruby.new(input)
eruby2 = Erubis::Eruby.new(input, :preamble=>false, :postamble=>false)

puts eruby1.src   # print preamble and postamble
puts "--------------"
puts eruby2.src   # don't print preamble and postamble
output
$ ruby example9.rb
_buf = ''; for item in @list 
 _buf << ' <b>'; _buf << ( item ).to_s; _buf << '</b>
'; end 
_buf.to_s
--------------
 for item in @list 
 _buf << ' <b>'; _buf << ( item ).to_s; _buf << '</b>
'; end 

2-9   Processing Instruction (PI) Converter

Erubis can parse Processing Instructions (PI) as embedded pattern.

  • '<?rb ... ?>' represents Ruby statement.
  • '@{...}@' represents escaped expression value.
  • '@!{...}@' represents normal expression value.
  • '@!!{...}@' prints expression value to standard output.
  • (experimental) '<%= ... %>' is also available to print expression value.

This is more useful than basic embedded pattern ('<% ... >') because PI doesn't break XML or HTML at all. For example the following XHTML file is well-formed and HTML validator got no errors on this example.

example10.xhtml
<?xml version="1.0" ?>
<?rb
  lang = 'en'
  list = ['<aaa>', 'b&b', '"ccc"']
?>
<html lang="@!{lang}@">
 <body>
  <ul>
  <?rb for item in list ?>
   <li>@{item}@</li>
  <?rb end ?>
  </ul>
 </body>
</html>

If the command-line property '--pi=name' is specified, erubis command parses input with PI converter. If name is omitted then the following name is used according to '-l lang'.

'-l' option PI name
-l ruby <?rb ... ?>
-l php <?php ... ?>
-l perl <?perl ... ?>
-l java <?java ... ?>
-l javascript <?js ... ?>
-l scheme <?scheme ... ?>
output
$ erubis -x --pi example10.xhtml
_buf = ''; _buf << '<?xml version="1.0" ?>
';
  lang = 'en'
  list = ['<aaa>', 'b&b', '"ccc"']

 _buf << '<html lang="'; _buf << (lang).to_s; _buf << '">
 <body>
  <ul>
';   for item in list 
 _buf << '   <li>'; _buf << Erubis::XmlHelper.escape_xml(item); _buf << '</li>
';   end 
 _buf << '  </ul>
 </body>
</html>
';
_buf.to_s

Expression character can be changeable by command-line property '--embchar=char. Default is '@'.

Use Erubis::PI::Eruby instead of Erubis::Eruby if you want to use PI as embedded pattern.

example10.rb
require 'erubis'
input = File.read('example10.xhtml')
eruby = Erubis::PI::Eruby.new(input)
print eruby.src
output
$ ruby example10.rb
_buf = ''; _buf << '<?xml version="1.0" ?>
';
  lang = 'en'
  list = ['<aaa>', 'b&b', '"ccc"']

 _buf << '<html lang="'; _buf << (lang).to_s; _buf << '">
 <body>
  <ul>
';   for item in list 
 _buf << '   <li>'; _buf << Erubis::XmlHelper.escape_xml(item); _buf << '</li>
';   end 
 _buf << '  </ul>
 </body>
</html>
';
_buf.to_s

(experimental) Erubis supports '<%= ... %>' pattern with PI pattern.

example of Rails view template
<table>
  <tr>
<?rb for item in @list ?>
    <td>@{item.id}@</td>
    <td>@{item.name}@</td>
    <td>
       <%= link_to 'Destroy', {:action=>'destroy', :id=>item.id},
                       :confirm=>'Are you OK?' %>
    </td>
<?rb end ?>
  </tr>
</table>

2-10   Retrieve Ruby Code

Similar to '-x', ommand-line option '-X' shows converted Ruby source code. The difference between '-x' and 'X' is that the former converts text part but the latter ignores it. It means that you can retrieve Ruby code from eRuby script by '-X' option.

For example, see the following eRuby script. This is some complex, so it is difficult to grasp the program code.

example11.rhtml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <body>
    <h3>List</h3>
    <% if @list.nil? || @list.empty? %>
    <p>not found.</p>
    <% else %>
    <table>
      <tbody>
        <% @list.each_with_index do |item, i| %>
        <tr bgcolor="<%= i % 2 == 0 ? '#FCC' : '#CCF' %>">
          <td><%= item %></td>
        </tr>
        <% end %>
      </tbody>
    </table>
    <% end %>
  </body>
</html>

Command-line option '-X' extracts only the ruby code from eRuby script.

result
$ erubis -X example11.rhtml
_buf = '';





     if @list.nil? || @list.empty? 

     else 


         @list.each_with_index do |item, i| 
                      _buf << ( i % 2 == 0 ? '#FCC' : '#CCF' ).to_s;
               _buf << ( item ).to_s;

         end 


     end 


_buf.to_s

Command-line option '-C' (cmpact) deletes empty lines.

result
$ erubis -XC example11.rhtml
_buf = '';
     if @list.nil? || @list.empty? 
     else 
         @list.each_with_index do |item, i| 
                      _buf << ( i % 2 == 0 ? '#FCC' : '#CCF' ).to_s;
               _buf << ( item ).to_s;
         end 
     end 
_buf.to_s

Option '-U' (unique) converts empty lines into a line.

result
$ erubis -XU example11.rhtml
_buf = '';

     if @list.nil? || @list.empty? 

     else 

         @list.each_with_index do |item, i| 
                      _buf << ( i % 2 == 0 ? '#FCC' : '#CCF' ).to_s;
               _buf << ( item ).to_s;

         end 

     end 

_buf.to_s

Option '-N' (number) adds line number. It is available with '-C' or '-U'.

result
$ erubis -XNU example11.rhtml
    1:  _buf = '';

    7:       if @list.nil? || @list.empty? 

    9:       else 

   12:           @list.each_with_index do |item, i| 
   13:                        _buf << ( i % 2 == 0 ? '#FCC' : '#CCF' ).to_s;
   14:                 _buf << ( item ).to_s;

   16:           end 

   19:       end 

   22:  _buf.to_s

Command-line option '-X' is available with PHP script.

example11.php
<?xml version="1.0"?>
<html>
  <body>
    <h3>List</h3>
    <?php if (!$list) { ?>
    <p>not found.</p>
    <?php } else { ?>
    <table>
      <tbody>
        <?php $i = 0; ?>
        <?php foreach ($list as $item) { ?>
        <tr bgcolor="<?php echo ++$i % 2 == 1 ? '#FCC' : '#CCF'; ?>">
          <td><?php echo $item; ?></td>
        </tr>
        <?php } ?>
      </tbody>
    </table>
    <?php } ?>
  </body>
</html>
result
$ erubis -XNU -l php --pi=php --trim=false example11.php

    5:      <?php if (!$list) { ?>

    7:      <?php } else { ?>

   10:          <?php $i = 0; ?>
   11:          <?php foreach ($list as $item) { ?>
   12:                       <?php echo ++$i % 2 == 1 ? '#FCC' : '#CCF'; ?>
   13:                <?php echo $item; ?>

   15:          <?php } ?>

   18:      <?php } ?>