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:
parent
1240916075
commit
da3eba7551
3 changed files with 223 additions and 135 deletions
|
@ -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
|
||||
|
|
239
lib/erb.rb
239
lib/erb.rb
|
@ -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,27 +345,32 @@ class ERB
|
|||
end
|
||||
|
||||
def scan_line(line)
|
||||
line.split(SplitRegexp).each do |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|
|
||||
line.scan(/(.*?)(<%%|%%>|<%=|<%#|<%|%>\n|%>|\n|\z)/m) do |tokens|
|
||||
tokens.each do |token|
|
||||
next if token.empty?
|
||||
if token == "%>\n"
|
||||
yield('%>')
|
||||
yield(:cr)
|
||||
break
|
||||
end
|
||||
else
|
||||
yield(token)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def trim_line2(line)
|
||||
head = nil
|
||||
line.split(TrimSplitRegexp).each do |token|
|
||||
line.scan(/(.*?)(<%%|%%>|<%=|<%#|<%|%>\n|%>|\n|\z)/m) do |tokens|
|
||||
tokens.each do |token|
|
||||
next if token.empty?
|
||||
head = token unless head
|
||||
if token == "%>\n"
|
||||
|
@ -377,19 +380,22 @@ class ERB
|
|||
else
|
||||
yield("\n")
|
||||
end
|
||||
break
|
||||
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|
|
||||
line.scan(/(.*?)(^[ \t]*<%\-|<%\-|<%%|%%>|<%=|<%#|<%|-%>\n|-%>|%>|\z)/m) do |tokens|
|
||||
tokens.each do |token|
|
||||
next if token.empty?
|
||||
if @stag.nil? && /[ \t]*<%-/ =~ token
|
||||
yield('<%')
|
||||
elsif @stag && /-%>\n/ =~ token
|
||||
elsif @stag && token == "-%>\n"
|
||||
yield('%>')
|
||||
yield(:cr)
|
||||
elsif @stag && token == '-%>'
|
||||
|
@ -399,6 +405,7 @@ class ERB
|
|||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
ERB_STAG = %w(<%= <%# <%)
|
||||
def is_erb_stag?(s)
|
||||
|
@ -410,8 +417,8 @@ class ERB
|
|||
|
||||
class SimpleScanner < Scanner # :nodoc:
|
||||
def scan
|
||||
@src.each_line do |line|
|
||||
line.split(SplitRegexp).each do |token|
|
||||
@src.scan(/(.*?)(<%%|%%>|<%=|<%#|<%|%>|\n|\z)/m) do |tokens|
|
||||
tokens.each do |token|
|
||||
next if token.empty?
|
||||
yield(token)
|
||||
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 == '-%>'
|
||||
yield('%>')
|
||||
if scanner.scan(/(\n|\z)/)
|
||||
yield(:cr)
|
||||
new_line = true
|
||||
end
|
||||
elsif elem == '<%-'
|
||||
if /[ \t]*<%-/ =~ elem
|
||||
yield('<%')
|
||||
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?
|
||||
|
@ -544,10 +554,12 @@ class ERB
|
|||
content = ''
|
||||
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) }
|
||||
# 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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue