summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormakoto kuwata <kwa@kuwata-lab.com>2007-07-19 04:13:21 +0000
committermakoto kuwata <kwa@kuwata-lab.com>2007-07-19 04:13:21 +0000
commit204983a9e68b4d0be44842a4f98fc36d1aced035 (patch)
tree613b5465a7180ebf1a0aecaa5f8bffbff9e36038
parent21a11d1c629e9696425334edf42edee3b30083c2 (diff)
downloaderubis-204983a9e68b4d0be44842a4f98fc36d1aced035.tar.gz
- [enhance] RubyEvaluator#def_method() can take instance object as well was module object
-rw-r--r--CHANGES25
-rw-r--r--ChangeLog.txt3
-rw-r--r--ReleaseNote.txt31
-rw-r--r--Rookbook.yaml8
-rw-r--r--doc/users-guide.html51
-rw-r--r--doc/users-guide.txt58
-rw-r--r--erubis.gemspec5
-rw-r--r--lib/erubis/evaluator.rb8
-rw-r--r--lib/erubis/main.rb2
-rw-r--r--test/test-erubis.rb38
10 files changed, 203 insertions, 26 deletions
diff --git a/CHANGES b/CHANGES
index b32b345..a5319fd 100644
--- a/CHANGES
+++ b/CHANGES
@@ -14,7 +14,7 @@
For example,
- [%= link_to 'Show', :action=>'show', :id=_?('@user.id') %]
+ [%= link_to 'Show', :action=>'show', :id=>_?('@user.id') %]
is evaluate by preprocessor and expanded into the following
when template file is loaded.
@@ -27,7 +27,7 @@
See User's Guide for details.
- |
- Erubis::Eruby#evaluate() (or Erubis::RubyEvaluator#evaluate())
+ Erubis::Eruby#evaluate() (or Erubis::RubyEvaluator#evaluate()) now
creates Proc object from @src and eval it.
def evaluate(context=Context.new)
@@ -40,11 +40,22 @@
- |
Erubis::Eruby#def_method() is supported.
- This method defines ruby code as module's instance method.
-
- def def_method(module_object, method_name, filename=nil)
- module_object.module_eval("def #{method_name}; #{@src}; end", filename || @filename)
- end
+ This method defines ruby code as instance method or singleton metod.
+
+ require 'erubis'
+ s = "hello <%= name %>"
+ eruby = Erubis::Eruby.new(s)
+ filename = 'hello.rhtml'
+
+ ## define instance method to Dummy class (or module)
+ class Dummy; end
+ eruby.def_method(Dummy, 'render(name)', filename) # filename is optional
+ p Dummy.new.render('world') #=> "hello world"
+
+ ## define singleton method to an object
+ obj = Object.new
+ eruby.def_method(obj, 'render(name)', filename) # filename is optional
+ p obj.render('world') #=> "hello world"
This is equivarent to ERB#def_method().
diff --git a/ChangeLog.txt b/ChangeLog.txt
index 89f1be8..37b2558 100644
--- a/ChangeLog.txt
+++ b/ChangeLog.txt
@@ -2,6 +2,9 @@
.?lastupdate: $Date$
.?version: $Rev$
+: Rev.91 (2007-07-19)
+ .- [enhance] RubyEvaluator#def_method() can take instance object as well was module object
+
: Rev.90 (2007-07-19)
.- [update] document updated
diff --git a/ReleaseNote.txt b/ReleaseNote.txt
index d0549ae..fedbc82 100644
--- a/ReleaseNote.txt
+++ b/ReleaseNote.txt
@@ -2,8 +2,8 @@ $ [ANN] Erubis 2.4.0 released - a fast eRuby implementation
Erubis 2.4.0 released.
http://www.kuwata-lab.com/erubis/
-In this release, Erubis provides important feature for Ruby on Rails
-application.
+In this release, Erubis provides an important feature for
+Ruby on Rails application.
Enhancements:
@@ -13,7 +13,7 @@ Enhancements:
For example,
- [%= link_to 'Show', :action=>'show', :id=_?('@user.id') %]
+ [%= link_to 'Show', :action=>'show', :id=>_?('@user.id') %]
is evaluate by preprocessor and expanded into the following
when template file is loaded.
@@ -40,11 +40,22 @@ Enhancements:
- |
Erubis::Eruby#def_method() is supported.
- This method defines ruby code as module's instance method.
-
- def def_method(module_object, method_name, filename=nil)
- module_object.module_eval("def #{method_name}; #{@src}; end", filename || @filename)
- end
+ This method defines ruby code as instance method or singleton metod.
+
+ require 'erubis'
+ s = "hello <%= name %>"
+ eruby = Erubis::Eruby.new(s)
+ filename = 'hello.rhtml'
+
+ ## define instance method to Dummy class (or module)
+ class Dummy; end
+ eruby.def_method(Dummy, 'render(name)', filename) # filename is optional
+ p Dummy.new.render('world') #=> "hello world"
+
+ ## define singleton method to an object
+ obj = Object.new
+ eruby.def_method(obj, 'render(name)', filename) # filename is optional
+ p obj.render('world') #=> "hello world"
This is equivarent to ERB#def_method().
@@ -61,7 +72,9 @@ Bugfix:
- 'def method()' was not availabe in template file. Fixed.
-
+--
+regards,
+kwatch
--------------------------------------------------------------------------------
diff --git a/Rookbook.yaml b/Rookbook.yaml
index 5d2dbaf..b3c7bf9 100644
--- a/Rookbook.yaml
+++ b/Rookbook.yaml
@@ -35,6 +35,10 @@ recipes:
desc: create packages
ingreds: [ $(base).tar.gz, $(base).tar.bz2, $(base).zip, $(base2).gem ]
+ - product: :doc
+ method*: |
+ chdir 'doc' do sys "#{rook_command()} :doc" end
+
- product: :test
method*: |
#sys "ruby test/test-erubis.rb"
@@ -157,7 +161,9 @@ recipes:
begin
cp abstract_rb, "#{dir}/lib"
chdir dir do
- sys "RUBYLIB= ruby $(inline_require_script) -I lib bin/erubis > contrib/erubis"
+ rubybin = '/opt/local/bin/ruby'
+ rubybin = 'ruby' unless test(?f, rubybin)
+ sys "RUBYLIB= #{rubybin} $(inline_require_script) -I lib bin/erubis > contrib/erubis"
end
ensure
rm "#{dir}/lib/abstract.rb"
diff --git a/doc/users-guide.html b/doc/users-guide.html
index dcb80ae..a8706ce 100644
--- a/doc/users-guide.html
+++ b/doc/users-guide.html
@@ -163,6 +163,8 @@ It has the following features.
</li>
<li><a href="#topcs-modruby">Helper Class for mod_ruby</a>
</li>
+ <li><a href="#topics-defmethod">Define method</a>
+ </li>
<li><a href="#topics-benchmark">Benchmark</a>
</li>
</ul>
@@ -2387,7 +2389,7 @@ It means that link_to() method is not called when template is rendered.
</p>
<p>If link_to() method have variable arguments, use <code>_?()</code> helper method.
</p>
-<pre class="program">&lt;% for use in @users %&gt;
+<pre class="program">&lt;% for user in @users %&gt;
[%= link_to <strong>_?('user.name')</strong>, :action=&gt;'show', :id=&gt;<strong>_?('user.id')</strong> %]
&lt;% end %&gt;
</pre>
@@ -2453,6 +2455,30 @@ because tag helpers generate different html code when form parameter has errors
<p>If it is nil (default), Erubis prints converted Ruby code into log file only when development mode.
It is useful for debugging.
</p>
+<ul type="disc">
+<li>ERB::Util.h() is redefined if you require 'erubis/helpers/rails_helper.rb'.
+ Original definition of ERB::Util.h() is the following and it is slow
+ because it scans string four times.
+<pre class="program"> def html_escape(s)
+ s.to_s.gsub(/&amp;/, "&amp;amp;").gsub(/\"/, "&amp;quot;").gsub(/&gt;/, "&amp;gt;").gsub(/&lt;/, "&amp;lt;")
+ end
+ alias h html_escape
+</pre>
+</li>
+</ul>
+<p> New definition in 'erubis/helpers/rails_helper.rb' is faster than the above
+ because it scans string only once.
+</p>
+<pre class="program"> ESCAPE_TABLE = { '&amp;'=&gt;'&amp;amp;', '&lt;'=&gt;'&amp;lt;', '&gt;'=&gt;'&amp;gt;', '"'=&gt;'&amp;quot;', "'"=&gt;'&amp;#039;', }
+ def h(value)
+ value.to_s.gsub(/[&amp;&lt;&gt;"]/) { |s| ESCAPE_TABLE[s] }
+ end
+</pre>
+<p> Notice that the new definition may be slow if string contains
+ many '&lt; &gt; &amp; "' characters because block is call many time.
+ You should use ERB::Util.html_hscape() if string contains a lot of '&lt; &gt; &amp; "'
+ characters.
+</p>
<br>
@@ -2734,6 +2760,29 @@ in the same directory in which '*.rhtml' file exists.
<br>
+<a name="topics-defmethod"></a>
+<h3 class="section2">Define method</h3>
+<p>Erubis::Eruby#def_method() defines instance method or singleton method.
+</p>
+<a name="def_method.rb"></a>
+<pre class="program">require 'erubis'
+s = "hello &lt;%= name %&gt;"
+eruby = Erubis::Eruby.new(s)
+filename = 'hello.rhtml'
+
+## define instance method to Dummy class (or module)
+class Dummy; end
+<strong>eruby.def_method(Dummy, 'render(name)', filename)</strong> # filename is optional
+p Dummy.new.render('world') #=&gt; "hello world"
+
+## define singleton method to dummy object
+obj = Object.new
+<strong>eruby.def_method(obj, 'render(name)', filename)</strong> # filename is optional
+p obj.render('world') #=&gt; "hello world"
+</pre>
+<br>
+
+
<a name="topics-benchmark"></a>
<h3 class="section2">Benchmark</h3>
<p>A benchmark script is included in Erubis package at 'erubis-$Release$/benchark/' directory.
diff --git a/doc/users-guide.txt b/doc/users-guide.txt
index 291fb99..5dcd267 100644
--- a/doc/users-guide.txt
+++ b/doc/users-guide.txt
@@ -2498,7 +2498,7 @@ It means that link_to() method is not called when template is rendered.
If link_to() method have variable arguments, use {{,_?(),}} helper method.
.--------------------
-<% for use in @users %>
+<% for user in @users %>
[%= link_to {{*_?('user.name')*}}, :action=>'show', :id=>{{*_?('user.id')*}} %]
<% end %>
.--------------------
@@ -2558,6 +2558,32 @@ Helper methods of Ruby on Rails are divided into two groups.
If it is nil (default), Erubis prints converted Ruby code into log file only when development mode.
It is useful for debugging.
+.* ERB::Util.h() is redefined if you require 'erubis/helpers/rails_helper.rb'.
+ Original definition of ERB::Util.h() is the following and it is slow
+ because it scans string four times.
+
+ .--------------------
+ def html_escape(s)
+ s.to_s.gsub(/&/, "&amp;").gsub(/\"/, "&quot;").gsub(/>/, "&gt;").gsub(/</, "&lt;")
+ end
+ alias h html_escape
+ .--------------------
+
+ New definition in 'erubis/helpers/rails_helper.rb' is faster than the above
+ because it scans string only once.
+
+ .--------------------
+ ESCAPE_TABLE = { '&'=>'&amp;', '<'=>'&lt;', '>'=>'&gt;', '"'=>'&quot;', "'"=>'&#039;', }
+ def h(value)
+ value.to_s.gsub(/[&<>"]/) { |s| ESCAPE_TABLE[s] }
+ end
+ .--------------------
+
+ Notice that the new definition may be slow if string contains
+ many '< > & "' characters because block is call many time.
+ You should use ERB::Util.html_hscape() if string contains a lot of '< > & "'
+ characters.
+
.$ Other Topics | topics
@@ -2829,6 +2855,36 @@ in the same directory in which '*.rhtml' file exists.
+.$$ Define method | topics-defmethod
+
+Erubis::Eruby#def_method() defines instance method or singleton method.
+
+.-------------------- def_method.rb
+require 'erubis'
+s = "hello <%= name %>"
+eruby = Erubis::Eruby.new(s)
+filename = 'hello.rhtml'
+
+## define instance method to Dummy class (or module)
+class Dummy; end
+{{*eruby.def_method(Dummy, 'render(name)', filename)*}} # filename is optional
+p Dummy.new.render('world') #=> "hello world"
+
+## define singleton method to dummy object
+obj = Object.new
+{{*eruby.def_method(obj, 'render(name)', filename)*}} # filename is optional
+p obj.render('world') #=> "hello world"
+.--------------------
+
+.#+++
+.==================== def_method.result
+$ ruby def_method.rb
+"hello world"
+"hello world"
+.====================
+.#---
+
+
.$$ Benchmark | topics-benchmark
A benchmark script is included in Erubis package at 'erubis-$Release$/benchark/' directory.
diff --git a/erubis.gemspec b/erubis.gemspec
index f870da9..a8ad887 100644
--- a/erubis.gemspec
+++ b/erubis.gemspec
@@ -14,7 +14,7 @@ spec = Gem::Specification.new do |s|
s.author = "makoto kuwata"
s.version = "$Release$"
s.platform = Gem::Platform::RUBY
- s.homepage = "http://rubyforge.org/projects/erubis"
+ s.homepage = "http://www.kuwata-lab.com/erubis/"
s.summary = "a fast and extensible eRuby implementation which supports multi-language"
s.description = <<-'END'
Erubis is an implementation of eRuby and has the following features:
@@ -36,8 +36,7 @@ spec = Gem::Specification.new do |s|
files += Dir.glob('lib/**/*')
files += Dir.glob('bin/*')
files += Dir.glob('examples/**/*')
- files += Dir.glob('test/*.rb')
- files += Dir.glob('test/data/**/*')
+ files += Dir.glob('test/**/*')
files += Dir.glob('doc/**/*')
files += %w[README.txt CHANGES MIT-LICENSE setup.rb]
files += Dir.glob('contrib/**/*')
diff --git a/lib/erubis/evaluator.rb b/lib/erubis/evaluator.rb
index 889fa49..f946af1 100644
--- a/lib/erubis/evaluator.rb
+++ b/lib/erubis/evaluator.rb
@@ -68,9 +68,11 @@ module Erubis
return context.instance_eval(&@_proc)
end
- ## define method to module_object. this is equivarent to ERB#def_method.
- def def_method(module_object, method_name, filename=nil)
- module_object.module_eval("def #{method_name}; #{@src}; end", filename || @filename)
+ ## if object is an Class or Module then define instance method to it,
+ ## else define singleton method to it.
+ def def_method(object, method_name, filename=nil)
+ m = object.is_a?(Module) ? :module_eval : :instance_eval
+ object.__send__(m, "def #{method_name}; #{@src}; end", filename || @filename || '(erubis)')
end
diff --git a/lib/erubis/main.rb b/lib/erubis/main.rb
index 6e38e39..76ddb2c 100644
--- a/lib/erubis/main.rb
+++ b/lib/erubis/main.rb
@@ -173,7 +173,7 @@ module Erubis
msg = nil if val
end
else
- engine.filename = '(stdin)'
+ engine.filename = filename = '(stdin)'
engine.convert!($stdin.read())
val = do_action(action, engine, context, filename, opts)
msg = nil if val
diff --git a/test/test-erubis.rb b/test/test-erubis.rb
index 9b699c2..1642a71 100644
--- a/test/test-erubis.rb
+++ b/test/test-erubis.rb
@@ -154,6 +154,44 @@ END
end
+ class Dummy
+ end
+
+ def test_def_method1
+ s = "<%for i in list%>i=<%=i%>\n<%end%>"
+ eruby = Erubis::Eruby.new(s)
+ assert(! Dummy.instance_methods.include?('render'))
+ eruby.def_method(Dummy, 'render(list)', 'foo.rhtml')
+ assert(Dummy.instance_methods.include?('render'))
+ actual = Dummy.new().render(%w[1 2 3])
+ assert_equal("i=1\ni=2\ni=3\n", actual)
+ end
+
+ def test_def_method2
+ s = "<%for i in list%>i=<%=i%>\n<%end%>"
+ eruby = Erubis::Eruby.new(s)
+ assert(! (eruby.respond_to? :render))
+ eruby.def_method(eruby, 'render(list)', 'foo.rhtml')
+ assert eruby.respond_to?(:render)
+ actual = eruby.render([1, 2, 3])
+ assert_equal("i=1\ni=2\ni=3\n", actual)
+ assert !(eruby.class.instance_methods.include? :render)
+ end
+
+ def test_evaluate_creates_proc
+ s = "hello <%= @name %>"
+ eruby = Erubis::Eruby.new(s)
+ assert_nil(eruby.instance_variable_get('@_proc'))
+ actual1 = eruby.evaluate(:name=>'world')
+ assert_not_nil(eruby.instance_variable_get('@_proc'))
+ assert_instance_of(Proc, eruby.instance_variable_get('@_proc'))
+ actual2 = eruby.evaluate(:name=>'world')
+ assert_equal(actual1, actual2)
+ # convert() must clear @_proc
+ eruby.convert(s)
+ assert_nil(eruby.instance_variable_get('@_proc'))
+ end
+
end
__END__