diff options
author | makoto kuwata <kwa@kuwata-lab.com> | 2006-01-29 12:24:10 +0000 |
---|---|---|
committer | makoto kuwata <kwa@kuwata-lab.com> | 2006-01-29 12:24:10 +0000 |
commit | 670ad2e8ceaf9383d0721bc5865fb1d4481f9ecc (patch) | |
tree | 7935e37d10da3fcf8f31a228abe52bbc5b230e71 /doc | |
parent | 9ae106b90202c4109ecd3cf4eae8de79a4488504 (diff) | |
download | erubis-670ad2e8ceaf9383d0721bc5865fb1d4481f9ecc.tar.gz |
- [bugfix] FastEruby prints empty text
- [bugfix] error occurs when input has no embedded pattern
- [enhance] add bin/erubis
- [enhance] add test/test-bin.rb
- [change] rename XxxFixture to XxxEnhancer
Diffstat (limited to 'doc')
-rw-r--r-- | doc/eruby.html | 356 | ||||
-rw-r--r-- | doc/eruby.txt | 246 |
2 files changed, 442 insertions, 160 deletions
diff --git a/doc/eruby.html b/doc/eruby.html index 087c29c..60ae764 100644 --- a/doc/eruby.html +++ b/doc/eruby.html @@ -232,7 +232,7 @@ class Eruby end ## 残りのテキストを処理 - rest = $' + rest = $' || input rest.each_line do |line| src << "_out << #{line.dump}" << (line[-1] == ?\n ? "\n" : "; ") end @@ -249,13 +249,11 @@ example1.rb</div> <pre class="program">list = ['aaa', 'bbb', 'ccc'] input = <<END -<table> +<ul> <% for item in list %> - <tr> - <td><%= item %></td> - </tr> + <li><%= item %></li> <% end %> -</table> +</ul> END require 'eruby1' @@ -268,30 +266,22 @@ puts eruby.result <div class="output_caption"> output</div> <pre class="output">--- source --- -_out = ''; _out << "<table>\n" +_out = ''; _out << "<ul>\n" _out << " "; for item in list ; _out << "\n" -_out << " <tr>\n" -_out << " <td>"; _out << ( item ).to_s; _out << "</td>\n" -_out << " </tr>\n" +_out << " <li>"; _out << ( item ).to_s; _out << "</li>\n" _out << " "; end ; _out << "\n" -_out << "</table>\n" +_out << "</ul>\n" _out --- result --- -<table> +<ul> - <tr> - <td>aaa</td> - </tr> + <li>aaa</li> - <tr> - <td>bbb</td> - </tr> + <li>bbb</li> - <tr> - <td>ccc</td> - </tr> + <li>ccc</li> -</table> +</ul> </pre> <br> @@ -339,7 +329,7 @@ class Eruby end ## 残りのテキストを処理 - rest = $' + rest = $' || input <strong>add_src_text(src, rest)</strong> <strong>finalize_src(src)</strong> @@ -353,6 +343,7 @@ class Eruby <strong>end</strong> <strong>def add_src_text(src, text)</strong> + <strong>return if text.empty?</strong> <strong>text.each_line do |line|</strong> <strong>src << "_out << #{line.dump}" << (line[-1] == ?\n ? "\n" : "; ")</strong> <strong>end</strong> @@ -401,6 +392,7 @@ fast-eruby.rb : 高速化した Eruby</div> class FastEruby < Eruby def add_src_text(src, text) + return if text.empty? src << "_out << #{text.dump}" << "; " src << ("\n" * text.count("\n")) end @@ -423,16 +415,27 @@ input = <<END END require 'eruby2' -require 'fast-eruby' -eruby = FastEruby.new(input) -puts "--- source ---" +eruby = Eruby.new(input) +puts "--- source (Eruby) ---" puts eruby.src -puts "--- result ---" -puts eruby.result + +require 'fast-eruby' +fasteruby = FastEruby.new(input) +puts "--- source (FastEruby) ---" +puts fasteruby.src </pre> <div class="output_caption"> output</div> -<pre class="output">--- source --- +<pre class="output">--- source (Eruby) --- +_out = ''; _out << "<table>\n" +_out << " "; for item in list ; _out << "\n" +_out << " <tr>\n" +_out << " <td>"; _out << ( item ).to_s; _out << "</td>\n" +_out << " </tr>\n" +_out << " "; end ; _out << "\n" +_out << "</table>\n" +_out +--- source (FastEruby) --- _out = ''; _out << "<table>\n "; for item in list ; _out << "\n <tr>\n <td>"; @@ -441,22 +444,6 @@ _out << ( item ).to_s; _out << "</td>\n </tr>\n "; end ; _out << "\n</table>\n"; _out ---- result --- -<table> - - <tr> - <td>aaa</td> - </tr> - - <tr> - <td>bbb</td> - </tr> - - <tr> - <td>ccc</td> - </tr> - -</table> </pre> <br> @@ -522,7 +509,7 @@ class Eruby end ## 残りのテキストを処理 - rest = $' + rest = $' || input add_src_text(src, rest) finalize_src(src) @@ -536,6 +523,7 @@ class Eruby end def add_src_text(src, text) + return if text.empty? text.each_line do |line| src << "_out << #{line.dump}" << (line[-1] == ?\n ? "\n" : "; ") end @@ -562,15 +550,12 @@ example3.rb</div> <pre class="program">list = ['aaa', 'bbb', 'ccc'] input = <<END -<table> +<ul> <% for item in list %> - <tr> - <td> - <%= item %> - </td> - </tr> + <li> + <%= item %> + </li> <% end %> -</table> </ul> END @@ -584,35 +569,25 @@ puts eruby.result <div class="output_caption"> output</div> <pre class="output">--- source --- -_out = ''; _out << "<table>\n" +_out = ''; _out << "<ul>\n" for item in list -_out << " <tr>\n" -_out << " <td>\n" -_out << " "; _out << ( item ).to_s; _out << "\n" -_out << " </td>\n" -_out << " </tr>\n" +_out << " <li>\n" +_out << " "; _out << ( item ).to_s; _out << "\n" +_out << " </li>\n" end -_out << "</table>\n" _out << "</ul>\n" _out --- result --- -<table> - <tr> - <td> - aaa - </td> - </tr> - <tr> - <td> - bbb - </td> - </tr> - <tr> - <td> - ccc - </td> - </tr> -</table> +<ul> + <li> + aaa + </li> + <li> + bbb + </li> + <li> + ccc + </li> </ul> </pre> <br> @@ -679,7 +654,7 @@ class Eruby end ## 残りのテキストを処理 - rest = $' + rest = $' || input add_src_text(src, rest) finalize_src(src) @@ -693,6 +668,7 @@ class Eruby end def add_src_text(src, text) + return if text.empty? text.each_line do |line| src << "_out << #{line.dump}" << (line[-1] == ?\n ? "\n" : "; ") end @@ -750,14 +726,12 @@ example4.rb</div> <pre class="program">list = ['<aaa>', 'b&b', '"ccc"'] input = <<END -<table> +<ul> <% for item in list %> - <tr> - <td><%= item %></td> - <td><%== item %></td> - </tr> + <li><%= item %></li> + <li><%== item %></li> <% end %> -</table> +</ul> END require 'eruby4' @@ -771,30 +745,22 @@ puts eruby.result <div class="output_caption"> output</div> <pre class="output">--- source --- -_out = ''; _out << "<table>\n" +_out = ''; _out << "<ul>\n" for item in list -_out << " <tr>\n" -_out << " <td>"; _out << XmlEruby.escape( item ); _out << "</td>\n" -_out << " <td>"; _out << ( item ).to_s; _out << "</td>\n" -_out << " </tr>\n" +_out << " <li>"; _out << XmlEruby.escape( item ); _out << "</li>\n" +_out << " <li>"; _out << ( item ).to_s; _out << "</li>\n" end -_out << "</table>\n" +_out << "</ul>\n" _out --- result --- -<table> - <tr> - <td>&lt;aaa&gt;</td> - <td><aaa></td> - </tr> - <tr> - <td>b&amp;b</td> - <td>b&b</td> - </tr> - <tr> - <td>&quot;ccc&quot;</td> - <td>"ccc"</td> - </tr> -</table> +<ul> + <li>&lt;aaa&gt;</li> + <li><aaa></li> + <li>b&amp;b</li> + <li>b&b</li> + <li>&quot;ccc&quot;</li> + <li>"ccc"</li> +</ul> </pre> <br> @@ -863,7 +829,7 @@ class Eruby end ## 残りのテキストを処理 - rest = $' + rest = $' || input add_src_text(src, rest) finalize_src(src) @@ -877,6 +843,7 @@ class Eruby end def add_src_text(src, text) + return if text.empty? text.each_line do |line| src << "_out << #{line.dump}" << (line[-1] == ?\n ? "\n" : "; ") end @@ -903,13 +870,11 @@ example5.rb</div> <pre class="program">list = ['aaa', 'bbb', 'ccc'] input = <<END -<table> +<ul> <!--% for item in list %--> - <tr> - <td><!--%= item %--></td> - </tr> + <li><!--%= item %--></li> <!--% end %--> -</table> +</ul> END require 'eruby5' @@ -923,26 +888,165 @@ print eruby.result() <div class="output_caption"> output</div> <pre class="output">--- source --- -_out = ''; _out << "<table>\n" +_out = ''; _out << "<ul>\n" for item in list -_out << " <tr>\n" -_out << " <td>"; _out << ( item ).to_s; _out << "</td>\n" -_out << " </tr>\n" +_out << " <li>"; _out << ( item ).to_s; _out << "</li>\n" end -_out << "</table>\n" +_out << "</ul>\n" _out --- result --- -<table> - <tr> - <td>aaa</td> - </tr> - <tr> - <td>bbb</td> - </tr> - <tr> - <td>ccc</td> - </tr> -</table> +<ul> + <li>aaa</li> + <li>bbb</li> + <li>ccc</li> +</ul> +</pre> +<br> + + +<a name="コンテキストを指定できるようにする"></a> +<h2 class="section1">コンテキストを指定できるようにする</h2> +<a name="eruby6.rb"></a> +<div class="program_caption"> +eruby6.rb</div> +<pre class="program">## +## eRuby の実装 +## +class Eruby + + ## eRuby 形式の文字列を受け取る + def initialize(input, options={}) + @input = input + @options = options + @pattern = options[:pattern] || '<% %>' + @src = compile(@input) + end + attr_reader :src + + ## 実行した結果 (文字列) を返す + def result(binding=TOPLEVEL_BINDING) + filename = '(eruby)' + eval @src, binding, filename + end + + <strong>## コンテキストを指定して result() を呼び出す</strong> + <strong>def evaluate(_context={})</strong> + <strong>_evalstr = ''</strong> + <strong>_context.keys.each do |key|</strong> + <strong>_evalstr << "#{key.to_s} = _context[#{key.inspect}]\n"</strong> + <strong>end</strong> + <strong>eval _evalstr</strong> + <strong>return result(binding())</strong> + <strong>end</strong> + + private + + ## eRuby 形式の文字列を Ruby コードに変換する + def compile(input=@input) + src = "" + initialize_src(src) + prefix, postfix = @pattern.split() # 埋め込みパターン + regexp = /(.*?)(^[ \t]*)?#{prefix}(=*)(.*?)#{postfix}([ \t]*\r?\n)?/m + input.scan(regexp) do |text, head_space, kind, code, tail_space| + ## * <%= %> のときは、何もしない + ## * <% %> のときは、 + ## * 前後が空白だけのときは、その空白を削除 + ## * そうでないときは、何もしない(空白を残す) + flag_trim = kind.empty? && head_space && tail_space + + ## テキストを処理 + add_src_text(src, text) + + ## 前の空白を処理 + unless flag_trim + add_src_text(src, head_space) if head_space + end + + ## 埋め込み Ruby コードを処理 + if !kind.empty? # <%= %> の場合 + add_src_expr(src, code, kind.length) + else # <% %> の場合 + ## 改行を含めた前後の空白をコードに足す + code = "#{head_space}#{code}#{tail_space}" if flag_trim + add_src_code(src, code) + end + + ## 後ろの空白を処理 + unless flag_trim + add_src_text(src, tail_space) if tail_space + end + end + + ## 残りのテキストを処理 + rest = $' || input + add_src_text(src, rest) + + finalize_src(src) + return src + end + + protected + + def initialize_src(src) + src << "_out = ''; " + end + + def add_src_text(src, text) + return if text.empty? + text.each_line do |line| + src << "_out << #{line.dump}" << (line[-1] == ?\n ? "\n" : "; ") + end + end + + def add_src_expr(src, code, length) + src << "_out << (#{code}).to_s; " + end + + def add_src_code(src, code) + code.each_line { |line| src << line } + src << "; " unless code[-1] == ?\n + end + + def finalize_src(src) + src << "_out\n" + end + +end + +</pre> +<a name="example6.rb"></a> +<div class="program_caption"> +example6.rb</div> +<pre class="program">## eRuby スクリプト +input = <<END +<h2><%= title %></h2> +<ul> + <% for item in list %> + <li><%= item %></li> + <% end %> +</ul> +END + +## コンテキストオブジェクトを作成する。 +## 変数名は文字列または Symbol で指定する。 +## また YAML ファイルを読み込んでそれをコンテキストとして使ってもよい。 +context = {} +context['title'] = "Context Example" +context[:list] = ['aaa', 'bbb', 'ccc'] + +## eRuby を実行する +require 'eruby6' +eruby = Eruby.new(input) +print eruby.evaluate(context) +</pre> +<div class="output_caption"> +output</div> +<pre class="output"><h2>Context Example</h2> +<ul> + <li>aaa</li> + <li>bbb</li> + <li>ccc</li> +</ul> </pre> <br> diff --git a/doc/eruby.txt b/doc/eruby.txt index bdd0ce9..d5098e3 100644 --- a/doc/eruby.txt +++ b/doc/eruby.txt @@ -48,7 +48,7 @@ class Eruby end ## 残りのテキストを処理 - rest = $' + rest = $' || input rest.each_line do |line| src << "_out << #{line.dump}" << (line[-1] == ?\n ? "\n" : "; ") end @@ -66,13 +66,18 @@ end list = ['aaa', 'bbb', 'ccc'] input = <<END -<table> +<ul> <% for item in list %> - <tr> - <td><%= item %></td> - </tr> + <li><%= item %></li> <% end %> -</table> +</ul> +.#<table> +.# <% for item in list %> +.# <tr> +.# <td><%= item %></td> +.# </tr> +.# <% end %> +.#</table> END require 'eruby1' @@ -134,7 +139,7 @@ class Eruby end ## 残りのテキストを処理 - rest = $' + rest = $' || input {{*add_src_text(src, rest)*}} {{*finalize_src(src)*}} @@ -148,6 +153,7 @@ class Eruby {{*end*}} {{*def add_src_text(src, text)*}} + {{*return if text.empty?*}} {{*text.each_line do |line|*}} {{*src << "_out << #{line.dump}" << (line[-1] == ?\n ? "\n" : "; ")*}} {{*end*}} @@ -174,7 +180,7 @@ end .-------------------- stdout-eruby.rb ## ## 文字列ではなく標準出力を使う Eruby -## (「<% print var %>」が問題なく使えるようになる) +## (「<% print expr %>」が使えるようになる) ## class StdoutEruby < Eruby @@ -198,6 +204,7 @@ end class FastEruby < Eruby def add_src_text(src, text) + return if text.empty? src << "_out << #{text.dump}" << "; " src << ("\n" * text.count("\n")) end @@ -211,6 +218,11 @@ end list = ['aaa', 'bbb', 'ccc'] input = <<END +.#<ul> +.# <% for item in list %> +.# <li><%= item %></li> +.# <% end %> +.#</ul> <table> <% for item in list %> <tr> @@ -221,12 +233,14 @@ input = <<END END require 'eruby2' -require 'fast-eruby' -eruby = FastEruby.new(input) -puts "--- source ---" +eruby = Eruby.new(input) +puts "--- source (Eruby) ---" puts eruby.src -puts "--- result ---" -puts eruby.result + +require 'fast-eruby' +fasteruby = FastEruby.new(input) +puts "--- source (FastEruby) ---" +puts fasteruby.src .-------------------- .? output @@ -297,7 +311,7 @@ class Eruby end ## 残りのテキストを処理 - rest = $' + rest = $' || input add_src_text(src, rest) finalize_src(src) @@ -311,6 +325,7 @@ class Eruby end def add_src_text(src, text) + return if text.empty? text.each_line do |line| src << "_out << #{line.dump}" << (line[-1] == ?\n ? "\n" : "; ") end @@ -338,16 +353,22 @@ end list = ['aaa', 'bbb', 'ccc'] input = <<END -<table> +<ul> <% for item in list %> - <tr> - <td> - <%= item %> - </td> - </tr> + <li> + <%= item %> + </li> <% end %> -</table> </ul> +.#<table> +.# <% for item in list %> +.# <tr> +.# <td> +.# <%= item %> +.# </td> +.# </tr> +.# <% end %> +.#</table> END require 'eruby3' @@ -426,7 +447,7 @@ class Eruby end ## 残りのテキストを処理 - rest = $' + rest = $' || input add_src_text(src, rest) finalize_src(src) @@ -440,6 +461,7 @@ class Eruby end def add_src_text(src, text) + return if text.empty? text.each_line do |line| src << "_out << #{line.dump}" << (line[-1] == ?\n ? "\n" : "; ") end @@ -499,14 +521,20 @@ end list = ['<aaa>', 'b&b', '"ccc"'] input = <<END -<table> +<ul> <% for item in list %> - <tr> - <td><%= item %></td> - <td><%== item %></td> - </tr> + <li><%= item %></li> + <li><%== item %></li> <% end %> -</table> +</ul> +.#<table> +.# <% for item in list %> +.# <tr> +.# <td><%= item %></td> +.# <td><%== item %></td> +.# </tr> +.# <% end %> +.#</table> END require 'eruby4' @@ -591,7 +619,7 @@ class Eruby end ## 残りのテキストを処理 - rest = $' + rest = $' || input add_src_text(src, rest) finalize_src(src) @@ -605,6 +633,7 @@ class Eruby end def add_src_text(src, text) + return if text.empty? text.each_line do |line| src << "_out << #{line.dump}" << (line[-1] == ?\n ? "\n" : "; ") end @@ -632,13 +661,18 @@ end list = ['aaa', 'bbb', 'ccc'] input = <<END -<table> +<ul> <!--% for item in list %--> - <tr> - <td><!--%= item %--></td> - </tr> + <li><!--%= item %--></li> <!--% end %--> -</table> +</ul> +.#<table> +.# <!--% for item in list %--> +.# <tr> +.# <td><!--%= item %--></td> +.# </tr> +.# <!--% end %--> +.#</table> END require 'eruby5' @@ -656,3 +690,147 @@ print eruby.result() .<<<:! ruby example5.rb .____________________ + + + +●コンテキストを指定できるようにする + +.? eruby6.rb +.-------------------- eruby6.rb +## +## eRuby の実装 +## +class Eruby + + ## eRuby 形式の文字列を受け取る + def initialize(input, options={}) + @input = input + @options = options + @pattern = options[:pattern] || '<% %>' + @src = compile(@input) + end + attr_reader :src + + ## 実行した結果 (文字列) を返す + def result(binding=TOPLEVEL_BINDING) + filename = '(eruby)' + eval @src, binding, filename + end + + {{*## コンテキストを指定して result() を呼び出す*}} + {{*def evaluate(_context={})*}} + {{*_evalstr = ''*}} + {{*_context.keys.each do |key|*}} + {{*_evalstr << "#{key.to_s} = _context[#{key.inspect}]\n"*}} + {{*end*}} + {{*eval _evalstr*}} + {{*return result(binding())*}} + {{*end*}} + + private + + ## eRuby 形式の文字列を Ruby コードに変換する + def compile(input=@input) + src = "" + initialize_src(src) + prefix, postfix = @pattern.split() # 埋め込みパターン + regexp = /(.*?)(^[ \t]*)?#{prefix}(=*)(.*?)#{postfix}([ \t]*\r?\n)?/m + input.scan(regexp) do |text, head_space, kind, code, tail_space| + ## * <%= %> のときは、何もしない + ## * <% %> のときは、 + ## * 前後が空白だけのときは、その空白を削除 + ## * そうでないときは、何もしない(空白を残す) + flag_trim = kind.empty? && head_space && tail_space + + ## テキストを処理 + add_src_text(src, text) + + ## 前の空白を処理 + unless flag_trim + add_src_text(src, head_space) if head_space + end + + ## 埋め込み Ruby コードを処理 + if !kind.empty? # <%= %> の場合 + add_src_expr(src, code, kind.length) + else # <% %> の場合 + ## 改行を含めた前後の空白をコードに足す + code = "#{head_space}#{code}#{tail_space}" if flag_trim + add_src_code(src, code) + end + + ## 後ろの空白を処理 + unless flag_trim + add_src_text(src, tail_space) if tail_space + end + end + + ## 残りのテキストを処理 + rest = $' || input + add_src_text(src, rest) + + finalize_src(src) + return src + end + + protected + + def initialize_src(src) + src << "_out = ''; " + end + + def add_src_text(src, text) + return if text.empty? + text.each_line do |line| + src << "_out << #{line.dump}" << (line[-1] == ?\n ? "\n" : "; ") + end + end + + def add_src_expr(src, code, length) + src << "_out << (#{code}).to_s; " + end + + def add_src_code(src, code) + code.each_line { |line| src << line } + src << "; " unless code[-1] == ?\n + end + + def finalize_src(src) + src << "_out\n" + end + +end + +.-------------------- + + +.? example6.rb +.-------------------- example6.rb +## eRuby スクリプト +input = <<END +<h2><%= title %></h2> +<ul> + <% for item in list %> + <li><%= item %></li> + <% end %> +</ul> +END + +## コンテキストオブジェクトを作成する。 +## 変数名は文字列または Symbol で指定する。 +## また YAML ファイルを読み込んでそれをコンテキストとして使ってもよい。 +context = {} +context['title'] = "Context Example" +context[:list] = ['aaa', 'bbb', 'ccc'] + +## eRuby を実行する +require 'eruby6' +eruby = Eruby.new(input) +print eruby.evaluate(context) +.-------------------- + + +.? output +.____________________ +.<<<:! ruby example6.rb +.____________________ |