1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

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

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@21286 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
seki 2009-01-03 15:36:14 +00:00
parent 1240916075
commit da3eba7551
3 changed files with 223 additions and 135 deletions

View file

@ -1,3 +1,10 @@
Sun Jan 4 00:30:50 2009 Masatoshi SEKI <m_seki@mva.biglobe.ne.jp>
* 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@ruby-lang.org>
* common.mk, Makefile.in, win32/Makefile.sub (INSNS): move the macro

View file

@ -258,7 +258,7 @@ class ERB
# 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 @@ class ERB
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 @@ class ERB
end
class TrimScanner < Scanner # :nodoc:
TrimSplitRegexp = /(<%%)|(%%>)|(<%=)|(<%#)|(<%)|(%>\n)|(%>)|(\n)/
def initialize(src, trim_mode, percent)
super
@trim_mode = trim_mode
@ -326,9 +326,7 @@ class ERB
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 @@ class ERB
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 ERB
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,43 +432,47 @@ class ERB
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
@ -469,31 +480,21 @@ class ERB
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 @@ class ERB
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 @@ class ERB
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 @@ class ERB
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 @@ class ERB
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 @@ class ERB
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 @@ class ERB
#
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 @@ class ERB
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 @@ end
#--
# 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

View file

@ -209,55 +209,54 @@ EOS
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 @@ EOS
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