ERB More

このページでは1.8系に付属するlib/erb.rbとbin/erbについて説明します。

ERB

ERBはeRubyをスクリプトをあつかうクラスライブラリです。 ERBはeRubyスクリプトをアプリケーションに組み込んで使うことを 想定して作られました。単体でフィルタとして使うコマンドも用意されます。

eRuby

eRubyは任意のテキストファイルにRubyスクリプトを埋め込む書式です。 JSP、ASPのRuby版をイメージするとわかりやすいでしょう。 次のマークアップを使ってRubyスクリプトを埋め込みます。

  • <% ... %> --- Rubyスクリプト片をその場で実行
  • <%= ... %> --- 式を評価した結果をその場に挿入
  • これ以外 --- 文字列をその場に挿入

eRubyはhtmlに限らず、任意のテキストファイルの出力に使用できます。 html以外にも使用できる反面、文法として壊れたhtmlファイルを出力する可能性もあります。

eRubyを試す

ruby-1.8系をインストールするとrubyインタプリタと同時にerbコマンドがインストールされます。 この章ではerbコマンドを使ってeRubyスクリプトの紹介をします。

簡単なeRubyスクリプト(0.erb)を示します。 <%と%>で囲まれた部分がRubyスクリプト片です。 <%=と%>で囲まれた式の結果はその場所に文字列として挿入されます。

% cat 0.erb
<% user = "m_seki" %>
<h2>Hello, World</h2>
<p>Hello, <%= user %>. (<%= Time.now.strftime("%Y-%m-%d") %>)</p>

このスクリプトをerbを使って変換してみましょう。bin/erbを実行します。

% erb 0.erb

<h2>Hello, World</h2>
<p>Hello, m_seki. (2003-01-31)</p>

分岐や繰り返しなどの制御構造を含めることもできます。 次のスクリプト(1.erb)はライブラリの検索順を示す変数$.を順に印字するものです。 each_with_indexとendの間の<li>...</li>を繰り返し実行します。

% cat 1.erb
<ul>
<% $:.each_with_index do |dir, n| %>
<ii><%= n %>  <%= dir %></li>
<% end %>
</ul>

erbコマンドで実行してみましょう。

% erb 1.erb
<ul>

<ii>0  /usr/local/lib/ruby/site_ruby/1.8</li>

<ii>1  /usr/local/lib/ruby/site_ruby/1.8/powerpc-darwin6.3</li>

<ii>2  /usr/local/lib/ruby/site_ruby</li>

<ii>3  /usr/local/lib/ruby/1.8</li>

<ii>4  /usr/local/lib/ruby/1.8/powerpc-darwin6.3</li>

<ii>5  .</li>

</ul>

元の文書と<% .. %>間の空行によって、空行が入っています。 出力をhtmlとしてWebブラウザで表示させた場合、空白や空行は見えなくなって しまうので気付きませんが、エディタなどで表示させるとちょっと気になります。

trimモードによる改行の制御

余計な改行問題はeRubyが紹介されてしばらくすると知られるようになりました。

いくつかのアイデアがERBのオプションとして取り込まれました。 ERBでの改行の制御はtrimモードと呼ばれるオプションで指定します。

%ではじまる行

%で始まる行はRubyスクリプトとして扱い、末尾の改行を取り除くというオプションを追加しました。 erbコマンドではデフォルトでonになっています。

%を使うとどうなるか試してみましょう。 1.erbスクリプトの2行を変更して、行頭を%に変えた2.erbを試します。

% cat 2.erb
<ul>
% $:.each_with_index do |dir, n| 
<ii><%= n %>  <%= dir %></li>
% end
</ul>

これをerbで処理すると次のようになります。

% erb 2.erb
<ul>
<ii>0  /usr/local/lib/ruby/site_ruby/1.8</li>
<ii>1  /usr/local/lib/ruby/site_ruby/1.8/powerpc-darwin6.3</li>
<ii>2  /usr/local/lib/ruby/site_ruby</li>
<ii>3  /usr/local/lib/ruby/1.8</li>
<ii>4  /usr/local/lib/ruby/1.8/powerpc-darwin6.3</li>
<ii>5  .</li>
</ul>

いい感じに空行がなくなっています。

%>直後の改行の削除

%>の直後の改行を削除するオプションが -T 1、 <%ではじまる行の%>の直後の改行を削除するのが-T 2です。

次のスクリプト(3.erb)で試してみましょう。

% cat 3.erb
<% 3.times do |n| %>
* <%= n %>
<% end %>

% erb 3.erb

* 0

* 1

* 2

% erb -T 1 3.erb
* 0* 1* 2

% erb -T 2 3.erb
* 0
* 1
* 2

オプション-T 2は「%ではじまる行」による制御とよく似た動作をします。

ERBの制限

eRubyではRubyスクリプト片での標準出力への印字はその場所への文字列の挿入となります。 しかし、ERBでは文字列の挿入ではなく本当に標準出力への印字となります。 *1

ERBでは標準出力に対応しないかわりに$stdoutなどを汚さずにすみますし、 低いコストでマルチスレッドに対応できるようになります。

標準出力の印字の振る舞いがどのように違うのか、erubyコマンドとerbコマンドを比べてみましょう。

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

% eruby 4.erb
Hello, World.

% erb 4.erb
WorldHello, .

erubyではprintしたその場所に文字が挿入されているのに対し、 erbコマンドでは"World"が先に表示されています。 erbコマンドではprintがその場所への挿入でなく、標準出力への印字となるためです。

erbコマンドに-xを与えると、変換したスクリプトを印字します。 4.erbを処理させると次のようになります。

% erb -x 4.erb
_erbout = ''; _erbout.concat "Hello, ";  print "World"; _erbout.concat ".\n"
_erbout.concat "\n"
_erbout; 

変数_erboutが指すStringに "Hello, "などeRubyスクリプトに現れた文字列を連結していくのが わかると思います。途中にprint "World"があります。"World"は文字列に連結されずにそのまま 出力されてしまいます。最後に_erboutを返してスクリプトは終了します。 erbコマンドはこのスクリプトを評価した結果ーつまりここでは_erboutーを印字して終了します。

class ERB

この章ではERBをライブラリとして使用する方法について説明します。

ERBはeRubyスクリプトを実行して印字するだけでなく、 文字列への変換やRubyスクリプトへの変換を行なえます。

よく使われるメソッドのリファレンスを示します。

ERB.new(eruby_script, safe_level=nil, trim_mode=nil)

eruby_scriptからERBを生成する。eval時の$SAFE、trim_mode(後述)を指定できる。

ERB#run(b=TOPLEVEL_BINDING)

ERBをbのbindingで実行し、印字する。

ERB#result(b=TOPLEVEL_BINDING)

ERBをbのbindingで実行し、文字列を返す。

ERB#src

変換したRubyスクリプトを取得する。

より詳細なリファレンスは次のページにあります。

ERBを使った簡単なスクリプト(疑似コード)を示します。

001: require 'erb'
...
002: erb = ERB.new(eruby_script)
...
003: erb.run

001: ERBを使用するには'erb'をrequireします。 erbはruby-1.8系には標準で含まれていますが、 ruby-1.6系では別途インストールが必要です。

002: eRubyスクリプトからERBオブジェクトerbを生成します。 ERB.newではまだスクリプトは実行されません。

003: 次にeRubyスクリプトを実行し、結果を印字するならrunメソッドを、 文字列に変換するならresultメソッドを使います。

eRubyスクリプトの評価は通常、$SAFE=0、TOPLEVEL_BINDINGで行われます。 セーフレベルを設定するにはERB.newの第二引数で指定します。 evalのbindingを指定するにはresult・runメソッドの引数で指定します。

ERB使用例

次のスクリプトはCGIスクリプトでERBをライブラリとして使用する例です。 resultのbindingによって、MyCGIオブジェクトのスコープでeRubyスクリプトを 実行しています。

require 'erb'
require 'cgi'
class MyCGI
  def initialize
    @cgi = CGI.new
    @erb = ERB.new(eruby_script)
    @foo = 'bar'
  end

  def do_it
    # your_logic
  end

  def build_page
    begin
      return @erb.result(binding)
    rescue
      return FAILED_PAGE
    end
  end
  .....
end
....
app = MyCGI.new
app.do_it
page = app.build_page
....

このサンプルではERB#resultメソッドを使用してeRubyスクリプトを評価しています。 評価中にエラーが発生した場合、rescue句が実行され FAILED_PAGEを返します。 eRubyスクリプトで全て行なう場合に比べて、エラー処理などがシンプルになります。

begin
  return erb.result(binding)
rescue
  return エラーページ
end

このスタイルでは次のメリットがあります。

  • CGIスクリプトがすっきりする
  • eRubyスクリプトにエラー処理を記述する必要がなくなる *2

注意

eRubyスクリプトの中でさらにeRubyスクリプトを処理させる場合には 注意が必要です。ERBの評価中(result/run)にERBをさらに評価する場合、 この変数名が同じであると文字列が初期化されてしまい、思わぬバグに遭遇します。 。 スコープが異なれば (呼び出したメソッドの中でERBを評価する場合など) 問題ありません。

おわりに


*1erb-1.x系のERbLightと同様な仕様です。
*2eRubyだけ版のサンプルスクリプトが要る?