人気ブログランキング | 話題のタグを見る

RoR レイアウトの yield に文書を流し込める理由

app/views/layouts/users.html.erb の body の中には、<%= yield %> が一行書いてあるだけだった。

users.html.erb を再掲すると次のようになる。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
       "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
  <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
  <title>Users: <%= controller.action_name %></title>
  <%= stylesheet_link_tag 'scaffold' %>
</head>
<body>

<p style="color: green"><%= flash[:notice] %></p>

<%= yield  %>

</body>
</html>

これでどうして body のなかに文書を流し込めるのだろうと不思議に思ったので調べていたら、るびまのこの記事を読んだら erb の文書を関数にできると書いてあった。そこで、簡単な実験をしてみた。まずbodyのなかにyieldだけを書き込んだ erb 文書 yield.erb を作る。

<html>
<body>
<%= yield %>
</body>
</html>

それから、irb を起動し、require 'erb' して、次の手順で Foo クラスに、インスタンスメソッド say を導入する。そうして、Foo.new.say {'<h1>hello</h1>' } を実行するとレイアウトのなかに文書を埋め込めた。

$ irb
irb(main):001:0> require 'erb'
=> true
irb(main):002:0> class Foo
irb(main):003:1>   extend ERB::DefMethod
irb(main):004:1>   def_erb_method('say', 'yield.erb')
irb(main):005:1> end
=> nil
irb(main):006:0> puts Foo.new.say { '<h1>hello</h1>' }
<html>
<body>
<h1>hello</h1>
</body>
</html>

本当はもっとスマートなやり方をしているのだろうが、とにかく yield で文書を流し込めることが確認できた。

そうすると、レイアウトの文書 layaut.erb とテンプレート文書 template.erb からどうやってHTML文書をつくるのだろうという疑問がわく。

試してみる気力はなくなったが、layout.erb から、Foo.new.layout メソッドを作り、template.erb から、erb = ERB.new(IO.read('template.erb')) のようにして ERB のインスタンスを作り、これを { erb.result } というブロックにして、Foo.new.layout {erb.result } で流し込んでやればいいような気がする。

RoRはこんなメタメタメタプログラムの塊のようなものなのだろうか。
by tnomura9 | 2008-10-15 21:50 | Ruby | Comments(0)
<< 特異メソッドと特異クラス RoR config/data... >>