diff options
author | makoto kuwata <kwa@kuwata-lab.com> | 2006-05-03 10:10:13 +0000 |
---|---|---|
committer | makoto kuwata <kwa@kuwata-lab.com> | 2006-05-03 10:10:13 +0000 |
commit | 675a3fd420e4e72b2a9846eb93269ae24c554850 (patch) | |
tree | 5a1cc1ab97030619d836be24bcbab6f21f25559e | |
parent | 118f9b3afb9cc26fd64fae6924c8b3b4742eb96f (diff) | |
download | erubis-675a3fd420e4e72b2a9846eb93269ae24c554850.tar.gz |
- [change] 'simplest.rb' is renamed to 'tiny.rb'
- [enhance] add Context class
- [enahnce] Engine#enhacne() now support Context object
- [enhance] new command-line option '-X' (convert to context obj) added
-rw-r--r-- | ChangeLog.txt | 6 | ||||
-rw-r--r-- | benchmark/erubybench-lib.rb | 4 | ||||
-rw-r--r-- | benchmark/erubybench.rb | 12 | ||||
-rw-r--r-- | doc/Rookbook.yaml | 4 | ||||
-rw-r--r-- | doc/users-guide.html | 183 | ||||
-rw-r--r-- | doc/users-guide.txt | 166 | ||||
-rw-r--r-- | lib/erubis.rb | 2 | ||||
-rw-r--r-- | lib/erubis/engine.rb | 49 | ||||
-rw-r--r-- | lib/erubis/main.rb | 135 | ||||
-rw-r--r-- | lib/erubis/tiny.rb (renamed from lib/erubis/simplest.rb) | 14 | ||||
-rw-r--r-- | test/test-bin.rb | 33 | ||||
-rw-r--r-- | test/test-erubis.rb | 31 |
12 files changed, 448 insertions, 191 deletions
diff --git a/ChangeLog.txt b/ChangeLog.txt index 35beca5..4683d23 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -2,6 +2,12 @@ .?lastupdate: $Date$ .?version: $Rev$ +.: Rev.16 + .- [change] 'simplest.rb' is renamed to 'tiny.rb' + .- [enhance] add Context class + .- [enahnce] Engine#enhacne() now support Context object + .- [enhance] new command-line option '-X' (convert to context obj) added + .: Rev.15 (2006-05-02) .- [refactor] Engine#compile() refactored .- [refactor] XxxxXmlEruby classes are removed diff --git a/benchmark/erubybench-lib.rb b/benchmark/erubybench-lib.rb index 8d2ea73..32ca299 100644 --- a/benchmark/erubybench-lib.rb +++ b/benchmark/erubybench-lib.rb @@ -18,7 +18,7 @@ module Erubis ## ## use $stdout ## - class SimplestStdoutEruby + class TinyStdoutEruby def initialize(input) @src = compile(input) @@ -60,7 +60,7 @@ module Erubis ## ## use print statement ## - class SimplestPrintEruby + class TinyPrintEruby def initialize(input) @src = compile(input) diff --git a/benchmark/erubybench.rb b/benchmark/erubybench.rb index 0073375..2eaa166 100644 --- a/benchmark/erubybench.rb +++ b/benchmark/erubybench.rb @@ -163,18 +163,18 @@ testdefs_str = <<END return: str skip: no -- name: ErubisSimplest - class: Erubis::SimplestEruby +- name: ErubisTiny + class: Erubis::TinyEruby return: yes skip: no -- name: ErubisSimplestStdout - class: Erubis::SimplestStdoutEruby +- name: ErubisTinyStdout + class: Erubis::TinyStdoutEruby return: null skip: no -- name: ErubisSimplestPrint - class: Erubis::SimplestPrintEruby +- name: ErubisTinyPrint + class: Erubis::TinyPrintEruby return: null skip: no diff --git a/doc/Rookbook.yaml b/doc/Rookbook.yaml index a051c23..4cb0434 100644 --- a/doc/Rookbook.yaml +++ b/doc/Rookbook.yaml @@ -21,9 +21,9 @@ recipes: rm_rf "guide.d" mkdir_p "guide.d" cmd "retrieve -d guide.d #{@ingred}" - cmd "kwaser -t $(tagfile) -T #{@ingred} > #{@byprods[0]}" + cmd "kwaser -t $(tagfile) -T #{@ingred} > #{@byprod}" cmd "kwaser -t $(tagfile) #{@ingred} > #{@product}" - rm "#{@byprods[0]}" + rm "#{@byprod}" diff --git a/doc/users-guide.html b/doc/users-guide.html index 864d7c0..d707c7f 100644 --- a/doc/users-guide.html +++ b/doc/users-guide.html @@ -37,7 +37,7 @@ It has the following features. </li> <li>Print statement available </li> -<li>Easy to expand in subclass +<li>Easy to extend in subclass </li> </ul> <p>Erubis is implemented in pure Ruby. It requires Ruby 1.8 or higher. @@ -65,6 +65,8 @@ It has the following features. </li> <li><a href="#tut-context">Context Object</a> </li> + <li><a href="#tut-datafile">Context Data File</a> + </li> <li><a href="#Preamble and Postamble">Preamble and Postamble</a> </li> </ul> @@ -367,6 +369,14 @@ $ cat stderr.log This is available in any language. </p> <pre class="terminal">$ erubis -l ruby <b>-e Escape</b> example3.eruby +_out = []; for item in list +; _out << ' - '; _out << Erubis::XmlHelper.escape_xml( item ); _out << ' +'; _out << ' - '; _out << ( item ).to_s; _out << ' +'; _out << ' - '; $stderr.puts("*** debug: item=#{(item).inspect}"); _out << ' +'; _out << ' +'; end +; +_out.join </pre> <p>Escaping function (default 'Erubis::XmlHelper.escape_xml()') can be changed by command-line property '--escape=xxx' or by overriding Erubis::Eruby#escaped_expr() in subclass. </p> @@ -445,9 +455,10 @@ For example, '<code><(!--)?% %(--)?></code>' will not work while '<code>&l <h3 class="section2">Context Object</h3> <p>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. </p> -<p>In Erubis, Hash object is used as context object. -Hash key means variable name and it can be string or symbol. +<p>When using Hash as context object, +hash key means variable name and it should be string or symbol. </p> <a name="example5.eruby"></a> <div class="program_caption"> @@ -484,11 +495,69 @@ output</div> <li>ccc</li> </ul> </pre> -<p>It is very useful to import YAML document data into context object. +<p>When using Erubis::Context object, context data is accessible via instance variables in eRuby template. </p> -<a name="example6.yaml"></a> +<a name="example6.eruby"></a> +<div class="program_caption"> +example6.eruby</div> +<pre class="program"><span><%= <b>@val</b> %></span> +<ul> + <% for item in <b>@list</b> %> + <li><%= item %></li> + <% end %> +</ul> +</pre> +<a name="example6.rb"></a> <div class="program_caption"> -example6.yaml</div> +example6.rb</div> +<pre class="program">require 'erubis' +input = File.read('example6.eruby') +eruby = Erubis::Eruby.new(input) # create Eruby object + +## create context object +## (key means var name, which may be string or symbol.) +<b>context = Erubis::Context.new</b> +<b>context[:val] = 'Erubis Example'</b> +<b>context['list'] = ['aaa', 'bbb', 'ccc']</b> + +puts <b>eruby.evaluate(context)</b> # get result +</pre> +<div class="terminal_caption"> +output</div> +<pre class="terminal">$ ruby example6.rb +<span>Erubis Example</span> +<ul> + <li>aaa</li> + <li>bbb</li> + <li>ccc</li> +</ul> +</pre> +<p><code>eruby.evaluate(context)</code> is almost equivalent to <code>context.instance_eval(eruby.src)</code>. +In fact, eruby.evaluate() can take any object. +</p> +<pre class="program">class MyData + def initialize(val, list) + @val = val + @list = list + end +end + +<b>mydata = MyData.new</b>('Erubis Example', ['aaa', 'bbb', 'ccc']) + +require 'erubis' +eruby = Erubis::Eruby.new(File.read('example6.eruby')) +puts eruby.evaluate(<b>mydata</b>) +</pre> +<br> + + +<a name="tut-datafile"></a> +<h3 class="section2">Context Data File</h3> +<p>It is very useful to import YAML document data into Hash context object. +</p> +<a name="example7.yaml"></a> +<div class="program_caption"> +example7.yaml</div> <pre class="program">title: Users List users: - name: foo @@ -498,9 +567,9 @@ users: - name: baz mail: baz@mail.org </pre> -<a name="example6.eruby"></a> +<a name="example7.eruby"></a> <div class="program_caption"> -example6.eruby</div> +example7.eruby</div> <pre class="program"><h1><%= title %></h1> <ul> <% for user in users %> @@ -510,22 +579,41 @@ example6.eruby</div> <% end %> </ul> </pre> -<a name="example6.rb"></a> +<a name="example7.rb"></a> <div class="program_caption"> -example6.rb</div> +example7.rb</div> <pre class="program">require 'erubis' -input = File.read('example6.eruby') +input = File.read('example7.eruby') eruby = Erubis::Eruby.new(input) # create Eruby object ## load YAML document as context object <b>require 'yaml'</b> -<b>context = YAML.load_file('example6.yaml')</b> +<b>context = YAML.load_file('example7.yaml')</b> puts <b>eruby.evaluate(context)</b> # get result </pre> <div class="terminal_caption"> output</div> -<pre class="terminal">$ ruby example6.rb +<pre class="terminal">$ ruby example7.rb +<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> +</pre> +<p>It is able to specify YAML data file with the command-line option '-f'. +You don't have to write ruby script such as 'example7.rb'. +</p> +<div class="terminal_caption"> +example of command-line option '-f'</div> +<pre class="terminal">$ erubis <b>-f example7.yaml</b> example7.eruby <h1>Users List</h1> <ul> <li> @@ -539,6 +627,9 @@ output</div> </li> </ul> </pre> +<p>Command-line option '-S' converts keys of mapping in YAML data file from string into symbol. +Command-line option '-X' use Erubis::Context as context object. +</p> <br> @@ -549,18 +640,18 @@ and the last line ('_out.join') is called postamble. </p> <p>You can specify Eruby not to print preamble nor postamble with option :preamble and :postamble. </p> -<a name="example7.eruby"></a> +<a name="example8.eruby"></a> <div class="program_caption"> -example7.eruby</div> +example8.eruby</div> <pre class="program"><% for item in list %> <b><%= item %></b> <% end %> </pre> -<a name="example7.rb"></a> +<a name="example8.rb"></a> <div class="program_caption"> -example7.rb</div> +example8.rb</div> <pre class="program">require 'erubis' -input = File.read('example7.eruby') +input = File.read('example8.eruby') eruby1 = Erubis::Eruby.new(input) eruby2 = Erubis::Eruby.new(input, <b>:preamble=>false, :postamble=>false</b>) @@ -570,7 +661,7 @@ puts eruby2.src # don't print preamble and postamble </pre> <div class="terminal_caption"> output</div> -<pre class="terminal">$ ruby example7.rb +<pre class="terminal">$ ruby example8.rb _out = []; for item in list ; _out << ' <b>'; _out << ( item ).to_s; _out << '</b> '; end @@ -1564,35 +1655,35 @@ Here is an example result of benchmark. </p> <div class="output_caption"> Env: Linux FedoraCore4, Celeron 667MHz, Mem512MB, Ruby1.8.4</div> -<pre class="output"> user system total real -ERuby 138.280000 1.900000 140.180000 (141.470426) -ERB 402.220000 3.190000 405.410000 (408.886894) -Erubis::Eruby 147.080000 2.400000 149.480000 (150.752255) -Erubis::StringBufferEruby 186.130000 2.600000 188.730000 (190.374098) -Erubis::SimplifiedEruby 130.100000 2.210000 132.310000 (133.426010) -Erubis::StdoutEruby 106.010000 2.130000 108.140000 (108.999193) -Erubis::StdoutSimplifiedEruby 97.130000 2.180000 99.310000 (100.104433) -Erubis::PrintOutEruby 109.900000 2.090000 111.990000 (112.854442) -Erubis::PrintOutSimplifiedEruby 93.120000 2.140000 95.260000 ( 96.002970) -Erubis::SimplestEruby 118.740000 2.360000 121.100000 (122.141380) -Erubis::SimplestStdoutEruby 86.140000 1.840000 87.980000 ( 88.679196) -Erubis::SimplestPrintEruby 86.540000 1.970000 88.510000 ( 89.208078) +<pre class="output"> user system total real +ERuby 138.280000 1.900000 140.180000 (141.470426) +ERB 402.220000 3.190000 405.410000 (408.886894) +Erubis::Eruby 147.080000 2.400000 149.480000 (150.752255) +Erubis::StringBufferEruby 186.130000 2.600000 188.730000 (190.374098) +Erubis::SimplifiedEruby 130.100000 2.210000 132.310000 (133.426010) +Erubis::StdoutEruby 106.010000 2.130000 108.140000 (108.999193) +Erubis::StdoutSimplifiedEruby 97.130000 2.180000 99.310000 (100.104433) +Erubis::PrintOutEruby 109.900000 2.090000 111.990000 (112.854442) +Erubis::PrintOutSimplifiedEruby 93.120000 2.140000 95.260000 ( 96.002970) +Erubis::TinyEruby 118.740000 2.360000 121.100000 (122.141380) +Erubis::TinyStdoutEruby 86.140000 1.840000 87.980000 ( 88.679196) +Erubis::TinyPrintEruby 86.540000 1.970000 88.510000 ( 89.208078) </pre> <div class="output_caption"> Env: MacOS X 10.4, PowerPC 1.42GHz, Mem1.5GB, Ruby1.8.4</div> -<pre class="output"> user system total real -ERuby 55.040000 2.120000 57.160000 ( 89.311397) -ERB 103.960000 3.480000 107.440000 (159.231792) -Erubis::Eruby 36.130000 1.570000 37.700000 ( 52.188574) -Erubis::StringBufferEruby 47.270000 1.980000 49.250000 ( 73.867537) -Erubis::SimplifiedEruby 34.310000 1.600000 35.910000 ( 51.762841) -Erubis::StdoutEruby 26.240000 1.490000 27.730000 ( 41.840430) -Erubis::StdoutSimplifiedEruby 25.380000 1.340000 26.720000 ( 37.231918) -Erubis::PrintOutEruby 26.850000 1.260000 28.110000 ( 38.378227) -Erubis::PrintOutSimplifiedEruby 24.160000 1.280000 25.440000 ( 40.048199) -Erubis::SimplestEruby 31.690000 1.590000 33.280000 ( 49.862091) -Erubis::SimplestStdoutEruby 22.550000 1.230000 23.780000 ( 33.316978) -Erubis::SimplestPrintEruby 22.340000 1.150000 23.490000 ( 33.577150) +<pre class="output"> user system total real +ERuby 55.040000 2.120000 57.160000 ( 89.311397) +ERB 103.960000 3.480000 107.440000 (159.231792) +Erubis::Eruby 36.130000 1.570000 37.700000 ( 52.188574) +Erubis::StringBufferEruby 47.270000 1.980000 49.250000 ( 73.867537) +Erubis::SimplifiedEruby 34.310000 1.600000 35.910000 ( 51.762841) +Erubis::StdoutEruby 26.240000 1.490000 27.730000 ( 41.840430) +Erubis::StdoutSimplifiedEruby 25.380000 1.340000 26.720000 ( 37.231918) +Erubis::PrintOutEruby 26.850000 1.260000 28.110000 ( 38.378227) +Erubis::PrintOutSimplifiedEruby 24.160000 1.280000 25.440000 ( 40.048199) +Erubis::TinyEruby 31.690000 1.590000 33.280000 ( 49.862091) +Erubis::TinyStdoutEruby 22.550000 1.230000 23.780000 ( 33.316978) +Erubis::TinyPrintEruby 22.340000 1.150000 23.490000 ( 33.577150) </pre> <p>This shows that: </p> @@ -1607,7 +1698,7 @@ Erubis::SimplestPrintEruby 22.340000 1.150000 23.490000 ( 33.5771 </li> <li>Using print statement or $stdout is faster than array buffer and string buffer. </li> -<li>Erubis::SimplestEruby (at 'erubis/simples.rb') and it's subclasses are the fastest in all eRuby implementation. +<li>Erubis::TinyEruby (at 'erubis/tiny.rb') and it's subclasses are the fastest in all eRuby implementation. </li> </ul> <br> diff --git a/doc/users-guide.txt b/doc/users-guide.txt index 6666913..b6453bb 100644 --- a/doc/users-guide.txt +++ b/doc/users-guide.txt @@ -16,7 +16,7 @@ It has the following features. .* Support multi-language (Ruby/PHP/C/Java/Scheme/Perl/Javascript) .* Context object available and easy to combine eRuby template with YAML datafile .* Print statement available -.* Easy to expand in subclass +.* Easy to extend in subclass Erubis is implemented in pure Ruby. It requires Ruby 1.8 or higher. @@ -246,7 +246,7 @@ This is available in any language. .==================== $ erubis -l ruby {{*-e Escape*}} example3.eruby -.<<<:! erubis -e Escape -l ruby example3.eruby +.<<<:! (cd guide.d; erubis -e Escape -l ruby example3.eruby) .==================== Escaping function (default 'Erubis::XmlHelper.escape_xml()') can be changed by command-line property '--escape=xxx' or by overriding Erubis::Eruby#escaped_expr() in subclass. @@ -311,9 +311,10 @@ For example, '{{,<(!--)?% %(--)?>,}}' will not work while '{{,<(?:!--)?% %(?:--) 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. -In Erubis, Hash object is used as context object. -Hash key means variable name and it can be string or symbol. +When using Hash as context object, +hash key means variable name and it should be string or symbol. .? example5.eruby .-------------------- example5.eruby @@ -346,10 +347,65 @@ $ ruby example5.rb .<<<:! (cd guide.d; ruby example5.rb) .==================== -It is very useful to import YAML document data into context object. +When using Erubis::Context object, context data is accessible via instance variables in eRuby template. -.? example6.yaml -.-------------------- example6.yaml +.? example6.eruby +.-------------------- example6.eruby +<span><%= {{*@val*}} %></span> +<ul> + <% for item in {{*@list*}} %> + <li><%= item %></li> + <% end %> +</ul> +.-------------------- + +.? example6.rb +.-------------------- example6.rb +require 'erubis' +input = File.read('example6.eruby') +eruby = Erubis::Eruby.new(input) # create Eruby object + +## create context object +## (key means var name, which may be string or symbol.) +{{*context = Erubis::Context.new*}} +{{*context[:val] = 'Erubis Example'*}} +{{*context['list'] = ['aaa', 'bbb', 'ccc']*}} + +puts {{*eruby.evaluate(context)*}} # get result +.-------------------- + +.? output +.==================== +$ ruby example6.rb +.<<<:! (cd guide.d; ruby example6.rb) +.==================== + +{{,eruby.evaluate(context),}} is almost equivalent to {{,context.instance_eval(eruby.src),}}. +In fact, eruby.evaluate() can take any object. + +.-------------------- +class MyData + def initialize(val, list) + @val = val + @list = list + end +end + +{{*mydata = MyData.new*}}('Erubis Example', ['aaa', 'bbb', 'ccc']) + +require 'erubis' +eruby = Erubis::Eruby.new(File.read('example6.eruby')) +puts eruby.evaluate({{*mydata*}}) +.-------------------- + + + +.$$ Context Data File | tut-datafile + +It is very useful to import YAML document data into Hash context object. + +.? example7.yaml +.-------------------- example7.yaml title: Users List users: - name: foo @@ -360,8 +416,8 @@ users: mail: baz@mail.org .-------------------- -.? example6.eruby -.-------------------- example6.eruby +.? example7.eruby +.-------------------- example7.eruby <h1><%= title %></h1> <ul> <% for user in users %> @@ -372,25 +428,37 @@ users: </ul> .-------------------- -.? example6.rb -.-------------------- example6.rb +.? example7.rb +.-------------------- example7.rb require 'erubis' -input = File.read('example6.eruby') +input = File.read('example7.eruby') eruby = Erubis::Eruby.new(input) # create Eruby object ## load YAML document as context object {{*require 'yaml'*}} -{{*context = YAML.load_file('example6.yaml')*}} +{{*context = YAML.load_file('example7.yaml')*}} puts {{*eruby.evaluate(context)*}} # get result .-------------------- .? output .==================== -$ ruby example6.rb -.<<<:! (cd guide.d; ruby example6.rb) +$ ruby example7.rb +.<<<:! (cd guide.d; ruby example7.rb) +.==================== + +It is able to specify YAML data file with the command-line option '-f'. +You don't have to write ruby script such as 'example7.rb'. + +.? example of command-line option '-f' +.==================== +$ erubis {{*-f example7.yaml*}} example7.eruby +.<<<:! (cd guide.d; erubis -f example7.yaml example7.eruby) .==================== +Command-line option '-S' converts keys of mapping in YAML data file from string into symbol. +Command-line option '-X' use Erubis::Context as context object. + .$$ Preamble and Postamble @@ -400,17 +468,17 @@ and the last line ('_out.join') is called postamble. You can specify Eruby not to print preamble nor postamble with option :preamble and :postamble. -.? example7.eruby -.-------------------- example7.eruby +.? example8.eruby +.-------------------- example8.eruby <% for item in list %> <b><%= item %></b> <% end %> .-------------------- -.? example7.rb -.-------------------- example7.rb +.? example8.rb +.-------------------- example8.rb require 'erubis' -input = File.read('example7.eruby') +input = File.read('example8.eruby') eruby1 = Erubis::Eruby.new(input) eruby2 = Erubis::Eruby.new(input, {{*:preamble=>false, :postamble=>false*}}) @@ -421,8 +489,8 @@ puts eruby2.src # don't print preamble and postamble .? output .==================== -$ ruby example7.rb -.<<<:! (cd guide.d; ruby example7.rb) +$ ruby example8.rb +.<<<:! (cd guide.d; ruby example8.rb) .==================== The command-line option '-b' specify both :preamble and :postamble to false. @@ -1130,36 +1198,36 @@ Here is an example result of benchmark. .? Env: Linux FedoraCore4, Celeron 667MHz, Mem512MB, Ruby1.8.4 .____________________ - user system total real -ERuby 138.280000 1.900000 140.180000 (141.470426) -ERB 402.220000 3.190000 405.410000 (408.886894) -Erubis::Eruby 147.080000 2.400000 149.480000 (150.752255) -Erubis::StringBufferEruby 186.130000 2.600000 188.730000 (190.374098) -Erubis::SimplifiedEruby 130.100000 2.210000 132.310000 (133.426010) -Erubis::StdoutEruby 106.010000 2.130000 108.140000 (108.999193) -Erubis::StdoutSimplifiedEruby 97.130000 2.180000 99.310000 (100.104433) -Erubis::PrintOutEruby 109.900000 2.090000 111.990000 (112.854442) -Erubis::PrintOutSimplifiedEruby 93.120000 2.140000 95.260000 ( 96.002970) -Erubis::SimplestEruby 118.740000 2.360000 121.100000 (122.141380) -Erubis::SimplestStdoutEruby 86.140000 1.840000 87.980000 ( 88.679196) -Erubis::SimplestPrintEruby 86.540000 1.970000 88.510000 ( 89.208078) + user system total real +ERuby 138.280000 1.900000 140.180000 (141.470426) +ERB 402.220000 3.190000 405.410000 (408.886894) +Erubis::Eruby 147.080000 2.400000 149.480000 (150.752255) +Erubis::StringBufferEruby 186.130000 2.600000 188.730000 (190.374098) +Erubis::SimplifiedEruby 130.100000 2.210000 132.310000 (133.426010) +Erubis::StdoutEruby 106.010000 2.130000 108.140000 (108.999193) +Erubis::StdoutSimplifiedEruby 97.130000 2.180000 99.310000 (100.104433) +Erubis::PrintOutEruby 109.900000 2.090000 111.990000 (112.854442) +Erubis::PrintOutSimplifiedEruby 93.120000 2.140000 95.260000 ( 96.002970) +Erubis::TinyEruby 118.740000 2.360000 121.100000 (122.141380) +Erubis::TinyStdoutEruby 86.140000 1.840000 87.980000 ( 88.679196) +Erubis::TinyPrintEruby 86.540000 1.970000 88.510000 ( 89.208078) .____________________ .? Env: MacOS X 10.4, PowerPC 1.42GHz, Mem1.5GB, Ruby1.8.4 .____________________ - user system total real -ERuby 55.040000 2.120000 57.160000 ( 89.311397) -ERB 103.960000 3.480000 107.440000 (159.231792) -Erubis::Eruby 36.130000 1.570000 37.700000 ( 52.188574) -Erubis::StringBufferEruby 47.270000 1.980000 49.250000 ( 73.867537) -Erubis::SimplifiedEruby 34.310000 1.600000 35.910000 ( 51.762841) -Erubis::StdoutEruby 26.240000 1.490000 27.730000 ( 41.840430) -Erubis::StdoutSimplifiedEruby 25.380000 1.340000 26.720000 ( 37.231918) -Erubis::PrintOutEruby 26.850000 1.260000 28.110000 ( 38.378227) -Erubis::PrintOutSimplifiedEruby 24.160000 1.280000 25.440000 ( 40.048199) -Erubis::SimplestEruby 31.690000 1.590000 33.280000 ( 49.862091) -Erubis::SimplestStdoutEruby 22.550000 1.230000 23.780000 ( 33.316978) -Erubis::SimplestPrintEruby 22.340000 1.150000 23.490000 ( 33.577150) + user system total real +ERuby 55.040000 2.120000 57.160000 ( 89.311397) +ERB 103.960000 3.480000 107.440000 (159.231792) +Erubis::Eruby 36.130000 1.570000 37.700000 ( 52.188574) +Erubis::StringBufferEruby 47.270000 1.980000 49.250000 ( 73.867537) +Erubis::SimplifiedEruby 34.310000 1.600000 35.910000 ( 51.762841) +Erubis::StdoutEruby 26.240000 1.490000 27.730000 ( 41.840430) +Erubis::StdoutSimplifiedEruby 25.380000 1.340000 26.720000 ( 37.231918) +Erubis::PrintOutEruby 26.850000 1.260000 28.110000 ( 38.378227) +Erubis::PrintOutSimplifiedEruby 24.160000 1.280000 25.440000 ( 40.048199) +Erubis::TinyEruby 31.690000 1.590000 33.280000 ( 49.862091) +Erubis::TinyStdoutEruby 22.550000 1.230000 23.780000 ( 33.316978) +Erubis::TinyPrintEruby 22.340000 1.150000 23.490000 ( 33.577150) .____________________ This shows that: @@ -1168,7 +1236,7 @@ This shows that: .* Erubis::SimplifiedEruby (which incudes SimplifiedEnhander) is faster than ERuby. .* String buffer (StringBufferEnhancer) is slower than array buffer (ArrayBufferEnhancer which Erubis::Eruby includes) .* Using print statement or $stdout is faster than array buffer and string buffer. -.* Erubis::SimplestEruby (at 'erubis/simples.rb') and it's subclasses are the fastest in all eRuby implementation. +.* Erubis::TinyEruby (at 'erubis/tiny.rb') and it's subclasses are the fastest in all eRuby implementation. diff --git a/lib/erubis.rb b/lib/erubis.rb index 7cca5cb..75f4895 100644 --- a/lib/erubis.rb +++ b/lib/erubis.rb @@ -55,7 +55,7 @@ require 'erubis/engine' require 'erubis/helper' require 'erubis/enhancer' -#require 'erubis/simplest' +#require 'erubis/tiny' require 'erubis/engine/ruby' #require 'erubis/engine/enhanced' # enhanced eruby engines #require 'erubis/engine/optimized' # generates optimized ruby code diff --git a/lib/erubis/engine.rb b/lib/erubis/engine.rb index 2724259..205b7b4 100644 --- a/lib/erubis/engine.rb +++ b/lib/erubis/engine.rb @@ -16,6 +16,41 @@ module Erubis ## + ## context object for Engine#evaluate + ## + ## ex. + ## template = <<'END' + ## Hello <%= @user %>! + ## <% for item in @list %> + ## - <%= item %> + ## <% end %> + ## END + ## + ## context = Erubis::Context.new + ## context[:user] = 'World' + ## context[:list] = ['aaa', 'bbb', 'ccc'] + ## + ## eruby = Erubis::Eruby.new(template) + ## print eruby.evaluate(context) + ## + class Context + + def [](key) + return instance_variable_get("@#{key}") + end + + def []=(key, value) + return instance_variable_set("@#{key}", value) + end + + def keys + return instance_variables.collect { |name| name[1,name.length-1] } + end + + end + + + ## ## base engine class ## class Engine @@ -53,14 +88,18 @@ module Erubis end def result(_binding=TOPLEVEL_BINDING) - _filename = @filename || '(erubis)' - eval @src, _binding, _filename + return eval(@src, _binding, (@filename || '(erubis)')) end def evaluate(_context={}) - ## load _context data as local variables by eval - eval _context.keys.inject("") { |s, k| s << "#{k.to_s} = _context[#{k.inspect}];" } - return result(binding()) + _filename = @filename || '(erubis)' + if _context.is_a?(Hash) + ## load _context data as local variables by eval + eval _context.keys.inject("") { |s, k| s << "#{k.to_s} = _context[#{k.inspect}];" } + return eval(@src, binding(), _filename) + else + return _context.instance_eval(@src, _filename) + end end DEFAULT_REGEXP = /(.*?)(^[ \t]*)?<%(=+|\#)?(.*?)-?%>([ \t]*\r?\n)?/m diff --git a/lib/erubis/main.rb b/lib/erubis/main.rb index ff944ef..7a31b20 100644 --- a/lib/erubis/main.rb +++ b/lib/erubis/main.rb @@ -6,7 +6,7 @@ require 'yaml' require 'erubis' -require 'erubis/simplest' +require 'erubis/tiny' require 'erubis/engine/enhanced' require 'erubis/engine/optimized' require 'erubis/engine/ruby' @@ -50,7 +50,7 @@ module Erubis def execute(argv=ARGV) ## parse command-line options - options, properties = parse_argv(argv, "hvsxTtSbE", "pcrfKIlae") + options, properties = parse_argv(argv, "hvsxTtSbEX", "pcrfKIlae") filenames = argv options[?h] = true if properties[:help] @@ -84,66 +84,23 @@ module Erubis ## class name of Eruby classname = options[?c] - unless classname - classname = lang =~ /\Axml(.*)/ ? "EscapedE#{$1}" : "E#{lang}" - end - begin - klass = Erubis.const_get(classname) - rescue NameError - klass = nil - end - unless klass - if lang - msg = "-l #{lang}: invalid language name (class Erubis::#{classname} not found)." - else - msg = "-c #{classname}: invalid class name." - end - raise CommandOptionError.new(msg) - end + klass = get_classobj(classname, lang) ## kanji code $KCODE = options[?K] if options[?K] ## read context values from yaml file yamlfiles = options[?f] - if yamlfiles - hash = {} - yamlfiles.split(/,/).each do |yamlfile| - str = yamlfile == '-' ? $stdin.read() : File.read(yamlfile) - str = untabify(str) if options[?t] - ydoc = YAML.load(str) - unless ydoc.is_a?(Hash) - raise CommandOptionError.new("#{yamlfile}: root object is not a mapping.") - end - convert_mapping_key_from_string_to_symbol(ydoc) if options[?S] - hash.update(ydoc) - end - #hash.update(context) - context = hash - else - context = {} - end + context = load_yamlfiles(yamlfiles, options) ## properties for engine - properties[:pattern] = options[?p] if options[?p] - properties[:trim] = false if options[?T] + properties[:pattern] = options[?p] if options[?p] + properties[:trim] = false if options[?T] properties[:preamble] = properties[:postamble] = false if options[?b] - ## enhancers - enhancers = [] - if options[?e] - enhancer_name = nil - begin - options[?e].split(/,/).each do |shortname| - enhancers << Erubis.const_get("#{shortname}Enhancer") - end - rescue NameError - raise CommandOptionError.new("#{shortname}: no such Enhancer (try '-E' to show all enhancers).") - end - end - - ## create engine + ## create engine and extend enhancers engine = klass.new(nil, properties) + enhancers = get_enhancers(options[?e]) enhancers.each do |enhancer| engine.extend(enhancer) engine.bipattern = properties[:bipattern] if enhancer == Erubis::BiPatternEnhancer @@ -153,13 +110,12 @@ module Erubis val = nil if filenames && !filenames.empty? filenames.each do |filename| - #engine = klass.load_file(filename, properties) engine.filename = filename engine.compile!(File.read(filename)) print val if val = do_action(action, engine, context, options) end else - #engine = klass.new(input, properties) + engine.filename = '(stdin)' engine.compile!($stdin.read()) print val if val = do_action(action, engine, context, options) end @@ -200,6 +156,7 @@ Usage: #{command} [..options..] [file ...] -f file.yaml : YAML file for context values (read stdin if filename is '-') -t : expand tab character in YAML file -S : convert mapping key from string to symbol in YAML file + -X : set mapping data in YAML file into instance variables END # -r library : require library @@ -255,7 +212,8 @@ END end name = $1; value = $2 name = name.gsub(/-/, '_').intern - value = value == nil ? true : to_value(value) + #value = value.nil? ? true : YAML.load(value) # error, why? + value = value.nil? ? true : YAML.load("---\n#{value}\n") context[name] = value # else # options @@ -284,19 +242,6 @@ END return options, context end - def to_value(str) - case str - when nil, "null", "nil" ; return nil - when "true", "yes" ; return true - when "false", "no" ; return false - when /\A\d+\z/ ; return str.to_i - when /\A\d+\.\d+\z/ ; return str.to_f - when /\/(.*)\// ; return Regexp.new($1) - when /\A'.*'\z/, /\A".*"\z/ ; return eval(str) - else ; return str - end - end - def untabify(text, width=8) sb = '' text.scan(/(.*?)\t/m) do |s, | @@ -306,6 +251,62 @@ END return $' ? (sb << $') : text end + def get_classobj(classname, lang) + unless classname + classname = lang =~ /\Axml(.*)/ ? "EscapedE#{$1}" : "E#{lang}" + end + begin + klass = Erubis.const_get(classname) + rescue NameError + klass = nil + end + unless klass + if lang + msg = "-l #{lang}: invalid language name (class Erubis::#{classname} not found)." + else + msg = "-c #{classname}: invalid class name." + end + raise CommandOptionError.new(msg) + end + return klass + end + + def get_enhancers(enhancer_names) + return [] unless enhancer_names + enhancers = [] + shortname = nil + begin + enhancer_names.split(/,/).each do |shortname| + enhancers << Erubis.const_get("#{shortname}Enhancer") + end + rescue NameError + raise CommandOptionError.new("#{shortname}: no such Enhancer (try '-E' to show all enhancers).") + end + return enhancers + end + + def load_yamlfiles(yamlfiles, options) + hash = {} + return hash unless yamlfiles + yamlfiles.split(/,/).each do |yamlfile| + str = yamlfile == '-' ? $stdin.read() : File.read(yamlfile) + str = untabify(str) if options[?t] + ydoc = YAML.load(str) + unless ydoc.is_a?(Hash) + raise CommandOptionError.new("#{yamlfile}: root object is not a mapping.") + end + convert_mapping_key_from_string_to_symbol(ydoc) if options[?S] + hash.update(ydoc) + end + if options[?X] # conver hash to context object + context = Context.new + hash.each { |name, value| context[name] = value } + else + context = hash + end + return context + end + def convert_mapping_key_from_string_to_symbol(ydoc) if ydoc.is_a?(Hash) ydoc.each do |key, val| diff --git a/lib/erubis/simplest.rb b/lib/erubis/tiny.rb index 151c521..d3a1a23 100644 --- a/lib/erubis/simplest.rb +++ b/lib/erubis/tiny.rb @@ -7,24 +7,20 @@ module Erubis ## - ## the simplest implementation of eRuby + ## tiny and the simplest implementation of eRuby ## ## ex. - ## eruby = SimplestEruby.new(File.read('example.rhtml')) + ## eruby = TinyEruby.new(File.read('example.rhtml')) ## print eruby.src # print ruby code ## print eruby.result(binding()) # eval ruby code ## - class SimplestEruby + class TinyEruby def initialize(input) @src = compile(input) end attr_reader :src - def result(binding=TOPLEVEL_BINDING) - eval @src, binding - end - EMBEDDED_PATTERN = /(.*?)<%(=+|\#)?(.*?)-?%>/m def compile(input) @@ -50,6 +46,10 @@ module Erubis return text.gsub!(/['\\]/, '\\\\\&') || text end + def result(binding=TOPLEVEL_BINDING) + eval @src, binding + end + end end diff --git a/test/test-bin.rb b/test/test-bin.rb index 23537c3..f01632b 100644 --- a/test/test-bin.rb +++ b/test/test-bin.rb @@ -263,6 +263,39 @@ END end + def test_context1 # -X + yamlfile = "test.context4.yaml" + # + @input = <<'END' +user = <%= @user %> +<% for item in @list %> + - <%= item %> +<% end %> +END + @expected = <<'END' +user = World + - aaa + - bbb + - ccc +END + @options = "-f #{yamlfile} -X " + # + yaml = <<-END +user: World +list: + - aaa + - bbb + - ccc +END + File.open(yamlfile, 'w') { |f| f.write(yaml) } + begin + _test() + ensure + File.unlink(yamlfile) if test(?f, yamlfile) + end + end + + def test_include1 # -I dir = 'foo' lib = 'bar' diff --git a/test/test-erubis.rb b/test/test-erubis.rb index 5c59ec2..3c6665b 100644 --- a/test/test-erubis.rb +++ b/test/test-erubis.rb @@ -11,7 +11,7 @@ require 'stringio' require 'erubis' require 'erubis/engine/enhanced' require 'erubis/engine/optimized' -require 'erubis/simplest' +require 'erubis/tiny' class ErubisTest < Test::Unit::TestCase @@ -37,7 +37,7 @@ class ErubisTest < Test::Unit::TestCase end if @chomp if @testopt != 'load_file' - if @klass == Erubis::SimplestEruby + if @klass == Erubis::TinyEruby eruby = @klass.new(@input) else eruby = @klass.new(@input, @options) @@ -55,8 +55,9 @@ class ErubisTest < Test::Unit::TestCase return if @testopt == 'skip_output' - context = {} - context[:list] = list = ['<aaa>', 'b&b', '"ccc"'] + list = ['<aaa>', 'b&b', '"ccc"'] + context = @testopt == 'context' ? Erubis::Context.new : {} + context[:list] = list case @testopt when/\Aeval\(/ @@ -156,6 +157,24 @@ __END__ <ul><li><aaa></li><li>b&b</li><li>"ccc"</li> </ul> ## +- name: context1 + testopt: context + input: | + <ul> + <% for item in @list %> + <li><%= item %></li> + <% end %> + </ul> + src: | + _out = []; _out << '<ul> + '; for item in @list + ; _out << ' <li>'; _out << ( item ).to_s; _out << '</li> + '; end + ; _out << '</ul> + '; + _out.join + output: *basic1_output +## - name: ignore1 input: | <ul> @@ -782,8 +801,8 @@ __END__ _out output: *optimized4_input ## -- name: simplest1 - class: SimplestEruby +- name: tiny1 + class: TinyEruby testopt: result input: | <ul> |