ruby-changes:41340
From: seki <ko1@a...>
Date: Sat, 2 Jan 2016 16:19:55 +0900 (JST)
Subject: [ruby-changes:41340] seki:r53412 (trunk): Allow ERB subclass to add token easily. [Feature #11936]
seki 2016-01-02 16:19:58 +0900 (Sat, 02 Jan 2016) New Revision: 53412 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=53412 Log: Allow ERB subclass to add token easily. [Feature #11936] Modified files: trunk/ChangeLog trunk/lib/erb.rb trunk/test/erb/test_erb.rb Index: ChangeLog =================================================================== --- ChangeLog (revision 53411) +++ ChangeLog (revision 53412) @@ -1,3 +1,10 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Sat Jan 2 16:16:14 2016 Masatoshi SEKI <m_seki@m...> + + * lib/erb.rb: Allow ERB subclass to add token easily. + [Feature #11936] + + * test/erb/test_erb.rb: ditto. + Sat Jan 2 14:44:31 2016 Nobuyoshi Nakada <nobu@r...> * parse.y (regexp): set_yylval_num sets u1, should use nd_tag Index: test/erb/test_erb.rb =================================================================== --- test/erb/test_erb.rb (revision 53411) +++ test/erb/test_erb.rb (revision 53412) @@ -481,6 +481,59 @@ EOS https://github.com/ruby/ruby/blob/trunk/test/erb/test_erb.rb#L481 def test_percent_after_etag assert_equal("1%", @erb.new("<%= 1 %>%", nil, "%").result) end + + def test_token_extension + extended_erb = Class.new(ERB) + extended_erb.module_eval do + def make_compiler(trim_mode) + compiler = Class.new(ERB::Compiler) + compiler.module_eval do + def compile_stag(stag, out, scanner) + case stag + when '<%==' + scanner.stag = stag + add_put_cmd(out, content) if content.size > 0 + self.content = '' + else + super + end + end + + def compile_content(stag, out) + case stag + when '<%==' + out.push("#{@insert_cmd}(::ERB::Util.html_escape(#{content}))") + else + super + end + end + + def make_scanner(src) + scanner = Class.new(ERB::Compiler::SimpleScanner) + scanner.module_eval do + def stags + ['<%=='] + super + end + end + scanner.new(src, @trim_mode, @percent) + end + end + compiler.new(trim_mode) + end + end + + src = <<~EOS + <% tag = '<>' %> + <%= tag %> + <%== tag %> + EOS + ans = <<~EOS + + <> + <> + EOS + assert_equal(ans, extended_erb.new(src).result) + end end class TestERBCoreWOStrScan < TestERBCore Index: lib/erb.rb =================================================================== --- lib/erb.rb (revision 53411) +++ lib/erb.rb (revision 53412) @@ -371,8 +371,11 @@ class ERB https://github.com/ruby/ruby/blob/trunk/lib/erb.rb#L371 def initialize(src, trim_mode, percent) @src = src @stag = nil + @stags = %w(<%% <%= <%# <%).freeze + @etags = %w(%%> %>).freeze end attr_accessor :stag + attr_reader :stags, :etags def scan; end end @@ -383,12 +386,16 @@ class ERB https://github.com/ruby/ruby/blob/trunk/lib/erb.rb#L386 @trim_mode = trim_mode @percent = percent if @trim_mode == '>' + @scan_reg = /(.*?)(%>\n|#{(stags + etags).join('|')}|\n|\z)/m @scan_line = self.method(:trim_line1) elsif @trim_mode == '<>' + @scan_reg = /(.*?)(%>\n|#{(stags + etags).join('|')}|\n|\z)/m @scan_line = self.method(:trim_line2) elsif @trim_mode == '-' + @scan_reg = /(.*?)(^[ \t]*<%\-|<%\-|-%>\n|-%>|#{(stags + etags).join('|')}|\z)/m @scan_line = self.method(:explicit_trim_line) else + @scan_reg = /(.*?)(#{(stags + etags).join('|')}|\n|\z)/m @scan_line = self.method(:scan_line) end end @@ -420,7 +427,7 @@ class ERB https://github.com/ruby/ruby/blob/trunk/lib/erb.rb#L427 end def scan_line(line) - line.scan(/(.*?)(<%%|%%>|<%=|<%#|<%|%>|\n|\z)/m) do |tokens| + line.scan(@scan_reg) do |tokens| tokens.each do |token| next if token.empty? yield(token) @@ -429,7 +436,7 @@ class ERB https://github.com/ruby/ruby/blob/trunk/lib/erb.rb#L436 end def trim_line1(line) - line.scan(/(.*?)(<%%|%%>|<%=|<%#|<%|%>\n|%>|\n|\z)/m) do |tokens| + line.scan(@scan_reg) do |tokens| tokens.each do |token| next if token.empty? if token == "%>\n" @@ -444,7 +451,7 @@ class ERB https://github.com/ruby/ruby/blob/trunk/lib/erb.rb#L451 def trim_line2(line) head = nil - line.scan(/(.*?)(<%%|%%>|<%=|<%#|<%|%>\n|%>|\n|\z)/m) do |tokens| + line.scan(@scan_reg) do |tokens| tokens.each do |token| next if token.empty? head = token unless head @@ -465,7 +472,7 @@ class ERB https://github.com/ruby/ruby/blob/trunk/lib/erb.rb#L472 end def explicit_trim_line(line) - line.scan(/(.*?)(^[ \t]*<%\-|<%\-|<%%|%%>|<%=|<%#|<%|-%>\n|-%>|%>|\z)/m) do |tokens| + line.scan(@scan_reg) do |tokens| tokens.each do |token| next if token.empty? if @stag.nil? && /[ \t]*<%-/ =~ token @@ -492,7 +499,7 @@ class ERB https://github.com/ruby/ruby/blob/trunk/lib/erb.rb#L499 class SimpleScanner < Scanner # :nodoc: def scan - @src.scan(/(.*?)(<%%|%%>|<%=|<%#|<%|%>|\n|\z)/m) do |tokens| + @src.scan(/(.*?)(#{(stags + etags).join('|')}|\n|\z)/m) do |tokens| tokens.each do |token| next if token.empty? yield(token) @@ -507,8 +514,8 @@ class ERB https://github.com/ruby/ruby/blob/trunk/lib/erb.rb#L514 require 'strscan' class SimpleScanner2 < Scanner # :nodoc: def scan - stag_reg = /(.*?)(<%[%=#]?|\z)/m - etag_reg = /(.*?)(%%?>|\z)/m + stag_reg = /(.*?)(#{stags.join('|')}|\z)/m + etag_reg = /(.*?)(#{etags.join('|')}|\z)/m scanner = StringScanner.new(@src) while ! scanner.eos? scanner.scan(@stag ? etag_reg : stag_reg) @@ -521,8 +528,8 @@ class ERB https://github.com/ruby/ruby/blob/trunk/lib/erb.rb#L528 class ExplicitScanner < Scanner # :nodoc: def scan - stag_reg = /(.*?)(^[ \t]*<%-|<%%|<%=|<%#|<%-|<%|\z)/m - etag_reg = /(.*?)(%%>|-%>|%>|\z)/m + stag_reg = /(.*?)(^[ \t]*<%-|<%-|#{stags.join('|')}|\z)/m + etag_reg = /(.*?)(-%>|#{etags.join('|')}|\z)/m scanner = StringScanner.new(@src) while ! scanner.eos? scanner.scan(@stag ? etag_reg : stag_reg) @@ -602,57 +609,15 @@ class ERB https://github.com/ruby/ruby/blob/trunk/lib/erb.rb#L609 enc = detect_magic_comment(s) || enc out = Buffer.new(self, enc) - content = '' + self.content = '' scanner = make_scanner(s) scanner.scan do |token| next if token.nil? next if token == '' if scanner.stag.nil? - case token - when PercentLine - add_put_cmd(out, content) if content.size > 0 - content = '' - out.push(token.to_s) - out.cr - when :cr - out.cr - when '<%', '<%=', '<%#' - scanner.stag = token - add_put_cmd(out, content) if content.size > 0 - content = '' - when "\n" - content << "\n" - add_put_cmd(out, content) - content = '' - when '<%%' - content << '<%' - else - content << token - end + compile_stag(token, out, scanner) else - case token - when '%>' - case scanner.stag - when '<%' - if content[-1] == ?\n - content.chop! - out.push(content) - out.cr - else - out.push(content) - end - when '<%=' - add_insert_cmd(out, content) - when '<%#' - # out.push("# #{content_dump(content)}") - end - scanner.stag = nil - content = '' - when '%%>' - content << '%>' - else - content << token - end + compile_etag(token, out, scanner) end end add_put_cmd(out, content) if content.size > 0 @@ -660,6 +625,60 @@ class ERB https://github.com/ruby/ruby/blob/trunk/lib/erb.rb#L625 return out.script, enc end + def compile_stag(stag, out, scanner) + case stag + when PercentLine + add_put_cmd(out, content) if content.size > 0 + self.content = '' + out.push(stag.to_s) + out.cr + when :cr + out.cr + when '<%', '<%=', '<%#' + scanner.stag = stag + add_put_cmd(out, content) if content.size > 0 + self.content = '' + when "\n" + content << "\n" + add_put_cmd(out, content) + self.content = '' + when '<%%' + content << '<%' + else + content << stag + end + end + + def compile_etag(etag, out, scanner) + case etag + when '%>' + compile_content(scanner.stag, out) + scanner.stag = nil + self.content = '' + when '%%>' + content << '%>' + else + content << etag + end + end + + def compile_content(stag, out) + case stag + when '<%' + if content[-1] == ?\n + content.chop! + out.push(content) + out.cr + else + out.push(content) + end + when '<%=' + add_insert_cmd(out, content) + when '<%#' + # out.push("# #{content_dump(content)}") + end + end + def prepare_trim_mode(mode) # :nodoc: case mode when 1 @@ -712,6 +731,10 @@ class ERB https://github.com/ruby/ruby/blob/trunk/lib/erb.rb#L731 attr_accessor :post_cmd private + + # A buffered text in #compile + attr_accessor :content + def detect_magic_comment(s) if /\A<%#(.*)%>/ =~ s or (@percent and /\A%#(.*)/ =~ s) comment = $1 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/