[前][次][番号順一覧][スレッド一覧]

ruby-changes:9745

From: seki <ko1@a...>
Date: Sun, 4 Jan 2009 00:36:34 +0900 (JST)
Subject: [ruby-changes:9745] Ruby:r21286 (trunk): merged r20850, r17881, r16811, r16763, r16748, r15829, r15794 and r15698 from ruby_1_8.

seki	2009-01-04 00:36:14 +0900 (Sun, 04 Jan 2009)

  New Revision: 21286

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=21286

  Log:
    merged r20850, r17881, r16811, r16763, r16748, r15829, r15794 and r15698 from ruby_1_8.

  Modified files:
    trunk/ChangeLog
    trunk/lib/erb.rb
    trunk/test/erb/test_erb.rb

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 21285)
+++ ChangeLog	(revision 21286)
@@ -1,3 +1,10 @@
+Sun Jan  4 00:30:50 2009  Masatoshi SEKI  <m_seki@m...>
+
+	* lib/erb.rb: merged r20850, r17881, r16811, r16763, r16748, r15829, 
+	  r15794 and r15698 from ruby_1_8.
+
+	* test/erb/test_erb.rb: ditto.
+
 Sat Jan  3 22:24:36 2009  NAKAMURA Usaku  <usa@r...>
 
 	* common.mk, Makefile.in, win32/Makefile.sub (INSNS): move the macro
Index: lib/erb.rb
===================================================================
--- lib/erb.rb	(revision 21285)
+++ lib/erb.rb	(revision 21286)
@@ -258,7 +258,7 @@
 
   # Returns revision information for the erb.rb module.
   def self.version
-    "erb.rb [2.0.4 #{ERB::Revision.split[1]}]"
+    "erb.rb [2.1.0 #{ERB::Revision.split[1]}]"
   end
 end
 
@@ -272,11 +272,13 @@
       end
       attr_reader :value
       alias :to_s :value
+
+      def empty?
+        @value.empty?
+      end
     end
 
     class Scanner # :nodoc:
-      SplitRegexp = /(<%%)|(%%>)|(<%=)|(<%#)|(<%)|(%>)|(\n)/
-
       @scanner_map = {}
       def self.regist_scanner(klass, trim_mode, percent)
 	@scanner_map[[trim_mode, percent]] = klass
@@ -301,8 +303,6 @@
     end
 
     class TrimScanner < Scanner # :nodoc:
-      TrimSplitRegexp = /(<%%)|(%%>)|(<%=)|(<%#)|(<%)|(%>\n)|(%>)|(\n)/
-
       def initialize(src, trim_mode, percent)
 	super
 	@trim_mode = trim_mode
@@ -326,9 +326,7 @@
 	    percent_line(line, &block)
 	  end
 	else
-	  @src.each_line do |line|
-	    @scan_line.call(line, &block)
-	  end
+          @scan_line.call(@src, &block)
 	end
 	nil
       end
@@ -347,57 +345,66 @@
       end
 
       def scan_line(line)
-	line.split(SplitRegexp).each do |token|
-	  next if token.empty?
-	  yield(token)
+        line.scan(/(.*?)(<%%|%%>|<%=|<%#|<%|%>|\n|\z)/m) do |tokens|
+          tokens.each do |token|
+            next if token.empty?
+            yield(token)
+          end
 	end
       end
 
       def trim_line1(line)
-	line.split(TrimSplitRegexp).each do |token|
-	  next if token.empty?
-	  if token == "%>\n"
-	    yield('%>')
-	    yield(:cr)
-	    break
-	  end
-	  yield(token)
+        line.scan(/(.*?)(<%%|%%>|<%=|<%#|<%|%>\n|%>|\n|\z)/m) do |tokens|
+          tokens.each do |token|
+            next if token.empty?
+            if token == "%>\n"
+              yield('%>')
+              yield(:cr)
+            else
+              yield(token)
+            end
+          end
 	end
       end
 
       def trim_line2(line)
 	head = nil
-	line.split(TrimSplitRegexp).each do |token|
-	  next if token.empty?
-	  head = token unless head
-	  if token == "%>\n"
-	    yield('%>')
-	    if  is_erb_stag?(head)
-	      yield(:cr)
-	    else
-	      yield("\n")
-	    end
-	    break
-	  end
-	  yield(token)
+        line.scan(/(.*?)(<%%|%%>|<%=|<%#|<%|%>\n|%>|\n|\z)/m) do |tokens|
+          tokens.each do |token|
+            next if token.empty?
+            head = token unless head
+            if token == "%>\n"
+              yield('%>')
+              if is_erb_stag?(head)
+                yield(:cr)
+              else
+                yield("\n")
+              end
+              head = nil
+            else
+              yield(token)
+              head = nil if token == "\n"
+            end
+          end
 	end
       end
 
-      ExplicitTrimRegexp = /(^[ \t]*<%-)|(-%>\n?\z)|(<%-)|(-%>)|(<%%)|(%%>)|(<%=)|(<%#)|(<%)|(%>)|(\n)/
       def explicit_trim_line(line)
-	line.split(ExplicitTrimRegexp).each do |token|
-	  next if token.empty?
-	  if @stag.nil? && /[ \t]*<%-/ =~ token
-	    yield('<%')
-	  elsif @stag && /-%>\n/ =~ token
-	    yield('%>')
-	    yield(:cr)
-	  elsif @stag && token == '-%>'
-	    yield('%>')
-	  else
-	    yield(token)
-	  end
-	end
+        line.scan(/(.*?)(^[ \t]*<%\-|<%\-|<%%|%%>|<%=|<%#|<%|-%>\n|-%>|%>|\z)/m) do |tokens|
+          tokens.each do |token|
+            next if token.empty?
+            if @stag.nil? && /[ \t]*<%-/ =~ token
+              yield('<%')
+            elsif @stag && token == "-%>\n"
+              yield('%>')
+              yield(:cr)
+            elsif @stag && token == '-%>'
+              yield('%>')
+            else
+              yield(token)
+            end
+          end
+        end
       end
 
       ERB_STAG = %w(<%= <%# <%)
@@ -410,11 +417,11 @@
 
     class SimpleScanner < Scanner # :nodoc:
       def scan
-	@src.each_line do |line|
-	  line.split(SplitRegexp).each do |token|
-	    next if token.empty?
-	    yield(token)
-	  end
+        @src.scan(/(.*?)(<%%|%%>|<%=|<%#|<%|%>|\n|\z)/m) do |tokens|
+          tokens.each do |token|
+            next if token.empty?
+            yield(token)
+          end
 	end
       end
     end
@@ -425,75 +432,69 @@
       require 'strscan'
       class SimpleScanner2 < Scanner # :nodoc:
         def scan
-          stag_reg = /(.*?)(<%%|<%=|<%#|<%|\n|\z)/
-          etag_reg = /(.*?)(%%>|%>|\n|\z)/
+          stag_reg = /(.*?)(<%%|<%=|<%#|<%|\z)/m
+          etag_reg = /(.*?)(%%>|%>|\z)/m
           scanner = StringScanner.new(@src)
           while ! scanner.eos?
             scanner.scan(@stag ? etag_reg : stag_reg)
-            text = scanner[1]
-            elem = scanner[2]
-            yield(text) unless text.empty?
-            yield(elem) unless elem.empty?
+            yield(scanner[1])
+            yield(scanner[2])
           end
         end
       end
       Scanner.regist_scanner(SimpleScanner2, nil, false)
 
       class PercentScanner < Scanner # :nodoc:
-	def scan
-	  new_line = true
-          stag_reg = /(.*?)(<%%|<%=|<%#|<%|\n|\z)/
-          etag_reg = /(.*?)(%%>|%>|\n|\z)/
+	def scan(&blk)
+          stag_reg = /(.*?)(^%%|^%|<%%|<%=|<%#|<%|\z)/m
+          etag_reg = /(.*?)(%%>|%>|\z)/m
           scanner = StringScanner.new(@src)
           while ! scanner.eos?
-	    if new_line && @stag.nil?
-	      if scanner.scan(/%%/)
-		yield('%')
-		new_line = false
-		next
-	      elsif scanner.scan(/%/)
-		yield(PercentLine.new(scanner.scan(/.*?(\n|\z)/).chomp))
-		next
-	      end
-	    end
 	    scanner.scan(@stag ? etag_reg : stag_reg)
-            text = scanner[1]
+            yield(scanner[1])
+
             elem = scanner[2]
-            yield(text) unless text.empty?
-            yield(elem) unless elem.empty?
-	    new_line = (elem == "\n")
+            if elem == '%%'
+              yield('%')
+              inline_scan(scanner.scan(/.*?(\n|\z)/), &blk)
+            elsif elem == '%'
+              yield(PercentLine.new(scanner.scan(/.*?(\n|\z)/).chomp))
+            else
+              yield(elem)
+            end
           end
         end
+
+        def inline_scan(line)
+          stag_reg = /(.*?)(<%%|<%=|<%#|<%|\z)/m
+          etag_reg = /(.*?)(%%>|%>|\z)/m
+          scanner = StringScanner.new(line)
+          while ! scanner.eos?
+            scanner.scan(@stag ? etag_reg : stag_reg)
+            yield(scanner[1])
+            yield(scanner[2])
+          end
+        end
       end
       Scanner.regist_scanner(PercentScanner, nil, true)
 
       class ExplicitScanner < Scanner # :nodoc:
 	def scan
-	  new_line = true
-          stag_reg = /(.*?)(<%%|<%=|<%#|<%-|<%|\n|\z)/
-          etag_reg = /(.*?)(%%>|-%>|%>|\n|\z)/
+          stag_reg = /(.*?)(^[ \t]*<%-|<%%|<%=|<%#|<%-|<%|\z)/m
+          etag_reg = /(.*?)(%%>|-%>|%>|\z)/m
           scanner = StringScanner.new(@src)
           while ! scanner.eos?
-	    if new_line && @stag.nil? && scanner.scan(/[ \t]*<%-/)
-	      yield('<%')
-	      new_line = false
-	      next
-	    end
 	    scanner.scan(@stag ? etag_reg : stag_reg)
-            text = scanner[1]
+            yield(scanner[1])
+
             elem = scanner[2]
-	    new_line = (elem == "\n")
-            yield(text) unless text.empty?
-	    if elem == '-%>'
+            if /[ \t]*<%-/ =~ elem
+              yield('<%')
+            elsif elem == '-%>'
 	      yield('%>')
-	      if scanner.scan(/(\n|\z)/)
-		yield(:cr)
-		new_line = true
-	      end
-	    elsif elem == '<%-'
-	      yield('<%')
+	      yield(:cr) if scanner.scan(/(\n|\z)/)
 	    else
-	      yield(elem) unless elem.empty?
+	      yield(elem)
 	    end
           end
         end
@@ -534,6 +535,15 @@
       end
     end
 
+    def content_dump(s)
+      n = s.count("\n")
+      if n > 0
+        s.dump + "\n" * n
+      else
+        s.dump
+      end
+    end
+
     def compile(s)
       enc = s.encoding
       raise ArgumentError, "#{enc} is not ASCII compatible" if enc.dummy?
@@ -542,12 +552,14 @@
       out = Buffer.new(self, enc)
 
       content = ''
-      scanner = make_scanner(s) 
+      scanner = make_scanner(s)
       scanner.scan do |token|
+        next if token.nil? 
+        next if token == ''
 	if scanner.stag.nil?
 	  case token
           when PercentLine
-	    out.push("#{@put_cmd} #{content.dump}") if content.size > 0
+	    out.push("#{@put_cmd} #{content_dump(content)}") if content.size > 0
 	    content = ''
             out.push(token.to_s)
             out.cr
@@ -555,12 +567,11 @@
 	    out.cr
 	  when '<%', '<%=', '<%#'
 	    scanner.stag = token
-	    out.push("#{@put_cmd} #{content.dump}") if content.size > 0
+	    out.push("#{@put_cmd} #{content_dump(content)}") if content.size > 0
 	    content = ''
 	  when "\n"
 	    content << "\n"
-	    out.push("#{@put_cmd} #{content.dump}")
-	    out.cr
+	    out.push("#{@put_cmd} #{content_dump(content)}")
 	    content = ''
 	  when '<%%'
 	    content << '<%'
@@ -582,8 +593,7 @@
 	    when '<%='
 	      out.push("#{@insert_cmd}((#{content}).to_s)")
 	    when '<%#'
-	      # content = content.force_encoding(@enc)
-	      # out.push("# #{content.dump}")
+	      # out.push("# #{content_dump(content)}")
 	    end
 	    scanner.stag = nil
 	    content = ''
@@ -594,7 +604,7 @@
 	  end
 	end
       end
-      out.push("#{@put_cmd} #{content.dump}") if content.size > 0
+      out.push("#{@put_cmd} #{content_dump(content)}") if content.size > 0
       out.close
       return out.script, enc
     end
@@ -769,17 +779,23 @@
   #
   def result(b=TOPLEVEL_BINDING)
     if @safe_level
-      th = Thread.start { 
+      proc { 
 	$SAFE = @safe_level
 	eval(@src, b, (@filename || '(erb)'), 0)
-      }
-      return th.value
+      }.call
     else
-      return eval(@src, b, (@filename || '(erb)'), 0)
+      eval(@src, b, (@filename || '(erb)'), 0)
     end
   end
 
-  def def_method(mod, methodname, fname='(ERB)')  # :nodoc:
+  # Define _methodname_ as instance method of _mod_ from compiled ruby source.
+  #
+  # example:
+  #   filename = 'example.rhtml'   # 'arg1' and 'arg2' are used in example.rhtml
+  #   erb = ERB.new(File.read(filename))
+  #   erb.def_method(MyClass, 'render(arg1, arg2)', filename)
+  #   print MyClass.new.render('foo', 123)
+  def def_method(mod, methodname, fname='(ERB)')
     src = self.src
     magic_comment = "#coding:#{@enc}\n"
     mod.module_eval do
@@ -787,15 +803,38 @@
     end
   end
 
-  def def_module(methodname='erb')  # :nodoc:
+  # Create unnamed module, define _methodname_ as instance method of it, and return it.
+  #
+  # example:
+  #   filename = 'example.rhtml'   # 'arg1' and 'arg2' are used in example.rhtml
+  #   erb = ERB.new(File.read(filename))
+  #   erb.filename = filename
+  #   MyModule = erb.def_module('render(arg1, arg2)')
+  #   class MyClass
+  #     include MyModule
+  #   end
+  def def_module(methodname='erb')
     mod = Module.new
-    def_method(mod, methodname)
+    def_method(mod, methodname, @filename || '(ERB)')
     mod
   end
 
-  def def_class(superklass=Object, methodname='result')  # :nodoc:
+  # Define unnamed class which has _methodname_ as instance method, and return it.
+  #
+  # example:
+  #   class MyClass_
+  #     def initialize(arg1, arg2)
+  #       @arg1 = arg1;  @arg2 = arg2
+  #     end
+  #   end
+  #   filename = 'example.rhtml'  # @arg1 and @arg2 are used in example.rhtml
+  #   erb = ERB.new(File.read(filename))
+  #   erb.filename = filename
+  #   MyClass = erb.def_class(MyClass_, 'render()')
+  #   print MyClass.new('foo', 123).render()
+  def def_class(superklass=Object, methodname='result')
     cls = Class.new(superklass)
-    def_method(cls, methodname)
+    def_method(cls, methodname, @filename || '(ERB)')
     cls
   end
 end
@@ -851,15 +890,45 @@
 #--
 # ERB::DefMethod
 class ERB
-  module DefMethod  # :nodoc:
+  # Utility module to define eRuby script as instance method.
+  #
+  # === Example
+  #
+  # example.rhtml:
+  #   <% for item in @items %>
+  #   <b><%= item %></b>
+  #   <% end %>
+  #
+  # example.rb:
+  #   require 'erb'
+  #   class MyClass
+  #     extend ERB::DefMethod
+  #     def_erb_method('render()', 'example.rhtml')
+  #     def initialize(items)
+  #       @items = items
+  #     end
+  #   end
+  #   print MyClass.new([10,20,30]).render()
+  #
+  # result:
+  #
+  #   <b>10</b>
+  #
+  #   <b>20</b>
+  #
+  #   <b>30</b>
+  #
+  module DefMethod
     public
-    def def_erb_method(methodname, erb)
-      if erb.kind_of? String
-	fname = erb
-	File.open(fname) {|f| erb = ERB.new(f.read) }
-	erb.def_method(self, methodname, fname)
+  # define _methodname_ as instance method of current module, using ERB object or eRuby file
+    def def_erb_method(methodname, erb_or_fname)
+      if erb_or_fname.kind_of? String
+        fname = erb_or_fname
+        erb = ERB.new(File.read(fname))
+        erb.def_method(self, methodname, fname)
       else
-	erb.def_method(self, methodname)
+        erb = erb_or_fname
+        erb.def_method(self, methodname, erb.filename || '(ERB)')
       end
     end
     module_function :def_erb_method
Index: test/erb/test_erb.rb
===================================================================
--- test/erb/test_erb.rb	(revision 21285)
+++ test/erb/test_erb.rb	(revision 21286)
@@ -209,55 +209,54 @@
 n.times do |i|%>
 %% %%><%%<%= i%><%
 end%>
+%%%
 EOS
     ans = <<EOS
 % 
 % %%><%0
 % %%><%1
+%%
 EOS
     assert_equal(ans, ERB.new(src, nil, '%').result)
   end
 
-  class Bar; end
-
   def test_def_erb_method
-    assert(! Bar.new.respond_to?('hello'))
-    Bar.module_eval do
+    klass = Class.new
+    klass.module_eval do
       extend ERB::DefMethod
       fname = File.join(File.dirname(File.expand_path(__FILE__)), 'hello.erb')
       def_erb_method('hello', fname)
     end
-    assert(Bar.new.respond_to?('hello'))
+    assert(klass.new.respond_to?('hello'))
 
-    assert(! Bar.new.respond_to?('hello_world'))
+    assert(! klass.new.respond_to?('hello_world'))
     erb = @erb.new('hello, world')
-    Bar.module_eval do
+    klass.module_eval do
       def_erb_method('hello_world', erb)
     end
-    assert(Bar.new.respond_to?('hello_world'))    
+    assert(klass.new.respond_to?('hello_world'))    
   end
 
-  class DefMethodWithoutFname; end
-  class DefMethodWithFname; end
-
   def test_def_method_without_filename
+    klass = Class.new
     erb = ERB.new("<% raise ::TestERB::MyError %>")
     erb.filename = "test filename"
-    assert(! DefMethodWithoutFname.new.respond_to?('my_error'))
-    erb.def_method(DefMethodWithoutFname, 'my_error')
+    assert(! klass.new.respond_to?('my_error'))
+    erb.def_method(klass, 'my_error')
     e = assert_raise(::TestERB::MyError) {
-       DefMethodWithoutFname.new.my_error
+       klass.new.my_error
     }
     assert_match(/\A\(ERB\):1\b/, e.backtrace[0])
   end
 
   def test_def_method_with_fname
+    klass = Class.new
     erb = ERB.new("<% raise ::TestERB::MyError %>")
     erb.filename = "test filename"
-    assert(! DefMethodWithFname.new.respond_to?('my_error'))
-    erb.def_method(DefMethodWithFname, 'my_error', 'test fname')
+    assert(! klass.new.respond_to?('my_error'))
+    erb.def_method(klass, 'my_error', 'test fname')
     e = assert_raise(::TestERB::MyError) {
-       DefMethodWithFname.new.my_error
+       klass.new.my_error
     }
     assert_match(/\Atest fname:1\b/, e.backtrace[0])
   end
@@ -444,3 +443,16 @@
                  ERB::Util.url_encode("\xA5\xB5\xA5\xF3\xA5\xD7\xA5\xEB".force_encoding("EUC-JP")))
   end
 end
+
+class TestERBCoreWOStrScan < TestERBCore
+  def setup
+    @save_map = ERB::Compiler::Scanner.instance_variable_get('@scanner_map')
+    map = {[nil, false]=>ERB::Compiler::SimpleScanner}
+    ERB::Compiler::Scanner.instance_variable_set('@scanner_map', map)
+    super
+  end
+
+  def teardown
+    ERB::Compiler::Scanner.instance_variable_set('@scanner_map', @save_map)
+  end
+end

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]