ゼロと無限の間に

フリーでオープンソースなJavaScriptとかPHPとか。

ユーザ用ツール

サイト用ツール


ruby-etude:40lines-template-engine

40行の Ruby製 簡易テンプレートエンジン

60行で作るPHP用テンプレートエンジンに触発されて書いた。

環境はmod_rubyで動作確認した。

テンプレートエンジンのソースコード

require "cgi"
class Template
    # テンプレートから作成したViewを取得する
    def self.get(tmpl_path, http_headers = "text/html")
        view_path = tmpl_path + ".view.rb"    # Viewのファイルパス
        view_name = "View_" + tmpl_path.gsub(/[-.]/, "_")    # Viewのクラス名
        # Viewクラスがまだ無いか、テンプレートより古い場合はViewクラスを作成する
        if !FileTest.exist?(view_path) || File::stat(tmpl_path).mtime > File::stat(view_path).mtime
            self.create_view(tmpl_path, view_path, view_name)
        end
        load view_path    #Viewクラスを読み込む
        print CGI.new.header(http_headers)    # HTTPヘッダ出力
        return eval(view_name + ".new")    # Viewのインスタンスを返す
    end
 
    # Viewクラスを定義するファイルを生成する
    def self.create_view(tmpl_path, view_path, view_name)
        vars = []    # テンプレート内で使っているインスタンス変数をここに溜める
 
        view = open(view_path, "w")
        view.puts "class #{view_name} \n"
        view.puts "  def show \n"
 
        tmpl = open(tmpl_path)
        tmpl.each do |line|
            vars.concat(line.scan(/@([_0-9a-z]+)/i))    # 使用しているインスタンス変数を洗い出す
            if line =~ /!\{.+\}/    # !{ }内はRubyのコードとして実行させる
                view.puts '    ' + line.gsub(/!\{(.+)\}/, '\1')
            else    # それ以外は加工してprintさせる
                line.gsub!(/"/, '\"')    # ダブルクォートのエスケープ
                line.gsub!(/%\{([^\}]+)\}/, '#{CGI.escapeHTML(\1.to_s)}')    # HTMLエスケープ
                view.puts '    print "' + line.rstrip + '\n"'
            end
        end
        tmpl.close
 
        view.puts "  end \n"
        view.puts "  attr_accessor :" + vars.uniq.join(", :") if vars.size > 0    # アクセサ
        view.puts "end \n"
        view.close
    end
end

dokuwikiのハイライトが途中でずれちゃってる…:-(

使い方の例

実例を見るのが分かりやすいかと。

テンプレートの例(tmpl.html)

<html>
<head>
<title>%{@title}</title>
</head>
<body>
<h1>%{@title}</h1>
<span style="color:green;">%{@message}</span> %{@message2}
<hr />
ループ
<ul>
!{@arr.each do |var|}
  <li>#{var}</li>
!{end}
</ul>
<hr />
条件
!{if @flg }
  TRUE
!{else}
  FALSE
!{end}
</body>
</html>

#{ }でそのまま出力
%{ }でHTMLエスケープして出力
!{ }内はRubyのコードとして実行する
データはインスタンス変数としてセットされるので@で使える

テンプレートを使う側の例

require "template"
 
v = Template.get("tmpl.html")
 
v.title = "<タイトル>"
v.message = "こんにちは!"
v.message2 = "こんばんは!"
v.arr = ['a', 'b', 'c']
v.flg = true
 
v.show

Template.get()でgetして、プロパティ感覚で値をセットして、show()する。

実行結果

テンプレートから作られたRubyのコード

class View_tmpl_html
  def show
    print "<html>\n"
    print "<head>\n"
    print "<title>#{CGI.escapeHTML(@title.to_s)}</title>\n"
    print "</head>\n"
    print "<body>\n"
    print "<h1>#{CGI.escapeHTML(@title.to_s)}</h1>\n"
    print "<span style=\"color:green;\">#{CGI.escapeHTML(@message.to_s)}</span> #{CGI.escapeHTML(@message2.to_s)}\n"
    print "<hr />\n"
    print "ループ\n"
    print "<ul>\n"
    @arr.each do |var|
    print "  <li>#{var}</li>\n"
    end
    print "</ul>\n"
    print "<hr />\n"
    print "条件\n"
    if @flg
    print "  TRUE\n"
    else
    print "  FALSE\n"
    end
    print "</body>\n"
    print "</html>\n"
    print "\n"
  end
  attr_writer :title, :message, :message2, :arr, :flg
end

実行結果のHTML

<html>
<head>
<title>&lt;タイトル&gt;</title>
</head>
<body>
<h1>&lt;タイトル&gt;</h1>
<span style="color:green;">こんにちは!</span> こんばんは!
<hr />
ループ
<ul>
  <li>a</li>
  <li>b</li>
  <li>c</li>
</ul>
<hr />
条件
  TRUE
</body>
</html>
ruby-etude/40lines-template-engine.txt · 最終更新: 2008/08/01 22:55 by dgbadmin

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki