New Upstream Release - ruby-erubi

Ready changes

Summary

Merged new upstream version: 1.12.0 (was: 1.9.0).

Resulting package

Built on 2023-05-11T21:30 (took 3m52s)

The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:

apt install -t fresh-releases ruby-erubi

Lintian Result

Diff

diff --git a/CHANGELOG b/CHANGELOG
index f9b13bf..41c8815 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,25 @@
+=== 1.12.0 (2022-12-22)
+
+* Use erb/escape for faster html escaping if available (jeremyevans)
+
+* Default :freeze_template_literals option to false if running with --enable-frozen-string-literal (casperisfine) (#35)
+
+=== 1.11.0 (2022-08-02)
+
+* Support :freeze_template_literals option for configuring whether to add .freeze to template literal strings (casperisfine) (#33)
+
+* Support :chain_appends option for chaining appends to the buffer variable (casperisfine, jeremyevans) (#32)
+
+* Avoid unnecessary defined? usage on Ruby 3+ when using the :ensure option (jeremyevans)
+
+=== 1.10.0 (2020-11-13)
+
+* Improve template parsing, mostly by reducing allocations (jeremyevans)
+
+* Do not ship tests in the gem, reducing gem size about 20% (jeremyevans)
+
+* Support :literal_prefix and :literal_postfix options for how to output literal tags (e.g. <%% code %>) (jaredcwhite) (#26, #27)
+
 === 1.9.0 (2019-09-25)
 
 * Change default :bufvar from 'String.new' to '::String.new' to work with BasicObject (jeremyevans)
diff --git a/MIT-LICENSE b/MIT-LICENSE
index 036808e..a8950e2 100644
--- a/MIT-LICENSE
+++ b/MIT-LICENSE
@@ -1,5 +1,5 @@
 copyright(c) 2006-2011 kuwata-lab.com all rights reserved.
-copyright(c) 2016-2018 Jeremy Evans
+copyright(c) 2016-2021 Jeremy Evans
 
 Permission is hereby granted, free of charge, to any person obtaining
 a copy of this software and associated documentation files (the
diff --git a/README.rdoc b/README.rdoc
index b87a685..1502aad 100644
--- a/README.rdoc
+++ b/README.rdoc
@@ -5,11 +5,11 @@ the same basic algorithm, with the following differences:
 
 * Handles postfix conditionals when using escaping (e.g. <tt><%= foo if bar %></tt>)
 * Supports frozen_string_literal: true in templates via :freeze option
-* Works with ruby's --enable-frozen-string-literal option
+* Works with ruby's <tt>--enable-frozen-string-literal</tt> option
 * Automatically freezes strings for template text when ruby optimizes it (on ruby 2.1+)
-* Escapes ' (apostrophe) when escaping for better XSS protection 
+* Escapes <tt>'</tt> (apostrophe) when escaping for better XSS protection 
 * Has 6x faster escaping on ruby 2.3+ by using cgi/escape
-* Has 86% smaller memory footprint
+* Has 81% smaller memory footprint (calculated using +ObjectSpace.memsize_of_all+)
 * Does no monkey patching (Erubis adds a method to Kernel)
 * Uses an immutable design (all options passed to the constructor, which returns a frozen object)
 * Has simpler internals (1 file, <150 lines of code)
@@ -92,7 +92,7 @@ instance variable.  Example:
   # </form>
   # after
 
-Alternatively, passing the option +:yield_returns_buffer => true+ will return the
+Alternatively, passing the option <tt>:yield_returns_buffer => true</tt> will return the
 buffer captured by the block instead of the last expression in the block.
 
 = Reporting Bugs
diff --git a/Rakefile b/Rakefile
index 753ff1b..4497485 100644
--- a/Rakefile
+++ b/Rakefile
@@ -42,7 +42,7 @@ end
 
 spec = proc do |env|
   env.each{|k,v| ENV[k] = v}
-  sh "#{FileUtils::RUBY} test/test.rb"
+  sh "#{FileUtils::RUBY} #{'-w' if RUBY_VERSION >= '3'} test/test.rb"
   env.each{|k,v| ENV.delete(k)}
 end
 
@@ -57,13 +57,6 @@ desc "Run specs with coverage"
 task "spec_cov" do
   spec.call('COVERAGE'=>'1')
 end
-  
-desc "Run specs with -w, some warnings filtered"
-task "spec_w" do
-  ENV['RUBYOPT'] ? (ENV['RUBYOPT'] += " -w") : (ENV['RUBYOPT'] = '-w')
-  rake = ENV['RAKE'] || "#{FileUtils::RUBY} -S rake"
-  sh %{#{rake} 2>&1 | egrep -v \": warning: instance variable @.* not initialized|: warning: method redefined; discarding old|: warning: previous definition of|: warning: statement not reached"}
-end
 
 ### Other
 
diff --git a/debian/changelog b/debian/changelog
index c68893e..7548075 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+ruby-erubi (1.12.0-1) UNRELEASED; urgency=low
+
+  * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Thu, 11 May 2023 21:26:37 -0000
+
 ruby-erubi (1.9.0-2) unstable; urgency=medium
 
   * Team Upload
diff --git a/erubi.gemspec b/erubi.gemspec
index def0102..7839906 100644
--- a/erubi.gemspec
+++ b/erubi.gemspec
@@ -2,36 +2,34 @@
 # This file has been automatically generated by gem2tgz #
 #########################################################
 # -*- encoding: utf-8 -*-
-# stub: erubi 1.9.0 ruby lib
+# stub: erubi 1.12.0 ruby lib
 
 Gem::Specification.new do |s|
   s.name = "erubi".freeze
-  s.version = "1.9.0"
+  s.version = "1.12.0"
 
   s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
+  s.metadata = { "bug_tracker_uri" => "https://github.com/jeremyevans/erubi/issues", "changelog_uri" => "https://github.com/jeremyevans/erubi/blob/master/CHANGELOG", "mailing_list_uri" => "https://github.com/jeremyevans/erubi/discussions", "source_code_uri" => "https://github.com/jeremyevans/erubi" } if s.respond_to? :metadata=
   s.require_paths = ["lib".freeze]
   s.authors = ["Jeremy Evans".freeze, "kuwata-lab.com".freeze]
-  s.date = "2019-09-25"
+  s.date = "2022-12-22"
   s.description = "Erubi is a ERB template engine for ruby. It is a simplified fork of Erubis".freeze
   s.email = "code@jeremyevans.net".freeze
   s.extra_rdoc_files = ["CHANGELOG".freeze, "MIT-LICENSE".freeze, "README.rdoc".freeze]
-  s.files = ["CHANGELOG".freeze, "MIT-LICENSE".freeze, "README.rdoc".freeze, "Rakefile".freeze, "lib/erubi.rb".freeze, "lib/erubi/capture_end.rb".freeze, "test/test.rb".freeze]
+  s.files = ["CHANGELOG".freeze, "MIT-LICENSE".freeze, "README.rdoc".freeze, "Rakefile".freeze, "lib/erubi.rb".freeze, "lib/erubi/capture_end.rb".freeze]
   s.homepage = "https://github.com/jeremyevans/erubi".freeze
   s.licenses = ["MIT".freeze]
   s.rdoc_options = ["--quiet".freeze, "--line-numbers".freeze, "--inline-source".freeze, "--title".freeze, "Erubi: Small ERB Implementation".freeze, "--main".freeze, "README.rdoc".freeze]
-  s.rubygems_version = "2.5.2.1".freeze
+  s.rubygems_version = "3.2.5".freeze
   s.summary = "Small ERB Implementation".freeze
 
   if s.respond_to? :specification_version then
     s.specification_version = 4
+  end
 
-    if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
-      s.add_development_dependency(%q<minitest>.freeze, [">= 0"])
-      s.add_development_dependency(%q<minitest-global_expectations>.freeze, [">= 0"])
-    else
-      s.add_dependency(%q<minitest>.freeze, [">= 0"])
-      s.add_dependency(%q<minitest-global_expectations>.freeze, [">= 0"])
-    end
+  if s.respond_to? :add_runtime_dependency then
+    s.add_development_dependency(%q<minitest>.freeze, [">= 0"])
+    s.add_development_dependency(%q<minitest-global_expectations>.freeze, [">= 0"])
   else
     s.add_dependency(%q<minitest>.freeze, [">= 0"])
     s.add_dependency(%q<minitest-global_expectations>.freeze, [">= 0"])
diff --git a/lib/erubi.rb b/lib/erubi.rb
index 0d5e738..e419d36 100644
--- a/lib/erubi.rb
+++ b/lib/erubi.rb
@@ -1,45 +1,60 @@
 # frozen_string_literal: true
 
 module Erubi
-  VERSION = '1.9.0'
-  RANGE_ALL = 0..-1
+  VERSION = '1.12.0'
 
+  # :nocov:
   if RUBY_VERSION >= '1.9'
     RANGE_FIRST = 0
     RANGE_LAST = -1
-    TEXT_END = RUBY_VERSION >= '2.1' ? "'.freeze;" : "';"
   else
-    # :nocov:
     RANGE_FIRST = 0..0
     RANGE_LAST = -1..-1
-    TEXT_END = "';"
   end
 
+  MATCH_METHOD = RUBY_VERSION >= '2.4' ? :match? : :match
+  SKIP_DEFINED_FOR_INSTANCE_VARIABLE = RUBY_VERSION > '3'
+  FREEZE_TEMPLATE_LITERALS = !eval("''").frozen? && RUBY_VERSION >= '2.1'
+  # :nocov:
+
   begin
-    require 'cgi/escape'
-    unless CGI.respond_to?(:escapeHTML) # work around for JRuby 9.1
-      CGI = Object.new
-      CGI.extend(defined?(::CGI::Escape) ? ::CGI::Escape : ::CGI::Util)
-    end
-    def self.h(value)
-      CGI.escapeHTML(value.to_s)
-    end
+    require 'erb/escape'
+    # :nocov:
+    define_singleton_method(:h, ERB::Escape.instance_method(:html_escape))
+    # :nocov:
   rescue LoadError
-    ESCAPE_TABLE = {'&' => '&amp;'.freeze, '<' => '&lt;'.freeze, '>' => '&gt;'.freeze, '"' => '&quot;'.freeze, "'" => '&#39;'.freeze}.freeze
-    if RUBY_VERSION >= '1.9'
-      # Escape the following characters with their HTML/XML
-      # equivalents.
-      def self.h(value)
-        value.to_s.gsub(/[&<>"']/, ESCAPE_TABLE)
+    begin
+      require 'cgi/escape'
+      # :nocov:
+      unless CGI.respond_to?(:escapeHTML) # work around for JRuby 9.1
+        CGI = Object.new
+        CGI.extend(defined?(::CGI::Escape) ? ::CGI::Escape : ::CGI::Util)
       end
-    else
+      # :nocov:
+      # Escape characters with their HTML/XML equivalents.
       def self.h(value)
-        value.to_s.gsub(/[&<>"']/){|s| ESCAPE_TABLE[s]}
+        CGI.escapeHTML(value.to_s)
+      end
+    rescue LoadError
+      # :nocov:
+      ESCAPE_TABLE = {'&' => '&amp;'.freeze, '<' => '&lt;'.freeze, '>' => '&gt;'.freeze, '"' => '&quot;'.freeze, "'" => '&#39;'.freeze}.freeze
+      if RUBY_VERSION >= '1.9'
+        def self.h(value)
+          value.to_s.gsub(/[&<>"']/, ESCAPE_TABLE)
+        end
+      else
+        def self.h(value)
+          value.to_s.gsub(/[&<>"']/){|s| ESCAPE_TABLE[s]}
+        end
       end
+      # :nocov:
     end
   end
 
   class Engine
+    # The default regular expression used for scanning.
+    DEFAULT_REGEXP = /<%(={1,2}|-|\#|%)?(.*?)([-=])?%>([ \t]*\r?\n)?/m
+    
     # The frozen ruby source code generated from the template, which can be evaled.
     attr_reader :src
 
@@ -50,38 +65,66 @@ module Erubi
     attr_reader :bufvar
 
     # Initialize a new Erubi::Engine.  Options:
-    # :bufval :: The value to use for the buffer variable, as a string.
-    # :bufvar :: The variable name to use for the buffer variable, as a string (default '::String.new')
-    # :ensure :: Wrap the template in a begin/ensure block restoring the previous value of bufvar.
-    # :escapefunc :: The function to use for escaping, as a string (default: '::Erubi.h').
-    # :escape :: Whether to make <%= escape by default, and <%== not escape by default.
-    # :escape_html :: Same as :escape, with lower priority.
-    # :filename :: The filename for the template.
-    # :freeze :: Whether to enable frozen string literals in the resulting source code.
-    # :outvar :: Same as bufvar, with lower priority.
-    # :postamble :: The postamble for the template, by default returns the resulting source code.
-    # :preamble :: The preamble for the template, by default initializes up the buffer variable.
-    # :regexp :: The regexp to use for scanning.
-    # :src :: The initial value to use for the source code
-    # :trim :: Whether to trim leading and trailing whitespace, true by default.
+    # +:bufval+ :: The value to use for the buffer variable, as a string (default <tt>'::String.new'</tt>).
+    # +:bufvar+ :: The variable name to use for the buffer variable, as a string.
+    # +:chain_appends+ :: Whether to chain <tt><<</t> calls to the buffer variable. Offers better
+    #                     performance, but can cause issues when the buffer variable is reassigned during
+    #                     template rendering (default +false+).
+    # +:ensure+ :: Wrap the template in a begin/ensure block restoring the previous value of bufvar.
+    # +:escapefunc+ :: The function to use for escaping, as a string (default: <tt>'::Erubi.h'</tt>).
+    # +:escape+ :: Whether to make <tt><%=</tt> escape by default, and <tt><%==</tt> not escape by default.
+    # +:escape_html+ :: Same as +:escape+, with lower priority.
+    # +:filename+ :: The filename for the template.
+    # +:freeze+ :: Whether to enable add a <tt>frozen_string_literal: true</tt> magic comment at the top of
+    #              the resulting source code.  Note this may cause problems if you are wrapping the resulting
+    #              source code in other code, because the magic comment only has an effect at the beginning of
+    #              the file, and having the magic comment later in the file can trigger warnings.
+    # +:freeze_template_literals+ :: Whether to suffix all literal strings for template code with <tt>.freeze</tt>
+    #                                (default: +true+ on Ruby 2.1+, +false+ on Ruby 2.0 and older).
+    #                                Can be set to +false+ on Ruby 2.3+ when frozen string literals are enabled
+    #                                in order to improve performance.
+    # +:literal_prefix+ :: The prefix to output when using escaped tag delimiters (default <tt>'<%'</tt>).
+    # +:literal_postfix+ :: The postfix to output when using escaped tag delimiters (default <tt>'%>'</tt>).
+    # +:outvar+ :: Same as +:bufvar+, with lower priority.
+    # +:postamble+ :: The postamble for the template, by default returns the resulting source code.
+    # +:preamble+ :: The preamble for the template, by default initializes the buffer variable.
+    # +:regexp+ :: The regexp to use for scanning.
+    # +:src+ :: The initial value to use for the source code, an empty string by default.
+    # +:trim+ :: Whether to trim leading and trailing whitespace, true by default.
     def initialize(input, properties={})
       @escape = escape = properties.fetch(:escape){properties.fetch(:escape_html, false)}
       trim       = properties[:trim] != false
       @filename  = properties[:filename]
       @bufvar = bufvar = properties[:bufvar] || properties[:outvar] || "_buf"
       bufval = properties[:bufval] || '::String.new'
-      regexp = properties[:regexp] || /<%(={1,2}|-|\#|%)?(.*?)([-=])?%>([ \t]*\r?\n)?/m
+      regexp = properties[:regexp] || DEFAULT_REGEXP
+      literal_prefix = properties[:literal_prefix] || '<%'
+      literal_postfix = properties[:literal_postfix] || '%>'
       preamble   = properties[:preamble] || "#{bufvar} = #{bufval};"
       postamble  = properties[:postamble] || "#{bufvar}.to_s\n"
+      @chain_appends = properties[:chain_appends]
+      @text_end = if properties.fetch(:freeze_template_literals, FREEZE_TEMPLATE_LITERALS)
+        "'.freeze"
+      else
+        "'"
+      end
 
+      @buffer_on_stack = false
       @src = src = properties[:src] || String.new
       src << "# frozen_string_literal: true\n" if properties[:freeze]
-      src << "begin; __original_outvar = #{bufvar} if defined?(#{bufvar}); " if properties[:ensure]
+      if properties[:ensure]
+        src << "begin; __original_outvar = #{bufvar}"
+        if SKIP_DEFINED_FOR_INSTANCE_VARIABLE && /\A@[^@]/ =~ bufvar
+          src << "; "
+        else
+          src << " if defined?(#{bufvar}); "
+        end
+      end
 
       unless @escapefunc = properties[:escapefunc]
         if escape
           @escapefunc = '__erubi.h'
-          src << "__erubi = ::Erubi;"
+          src << "__erubi = ::Erubi; "
         else
           @escapefunc = '::Erubi.h'
         end
@@ -110,46 +153,45 @@ module Erubi
             if rindex
               range = rindex+1..-1
               s = text[range]
-              if s =~ /\A[ \t]*\z/
+              if /\A[ \t]*\z/.send(MATCH_METHOD, s)
                 lspace = s
                 text[range] = ''
               end
             else
-              if is_bol && text =~ /\A[ \t]*\z/
-                lspace = text.dup
-                text[RANGE_ALL] = ''
+              if is_bol && /\A[ \t]*\z/.send(MATCH_METHOD, text)
+                lspace = text
+                text = ''
               end
             end
           end
         end
 
         is_bol = rspace
-        add_text(text) if text && !text.empty?
+        add_text(text)
         case ch
         when '='
           rspace = nil if tailch && !tailch.empty?
-          add_text(lspace) if lspace
           add_expression(indicator, code)
           add_text(rspace) if rspace
-        when '#'
-          n = code.count("\n") + (rspace ? 1 : 0)
+        when nil, '-'
           if trim && lspace && rspace
-            add_code("\n" * n)
+            add_code("#{lspace}#{code}#{rspace}")
           else
             add_text(lspace) if lspace
-            add_code("\n" * n)
+            add_code(code)
             add_text(rspace) if rspace
           end
-        when '%'
-          add_text("#{lspace}#{prefix||='<%'}#{code}#{tailch}#{postfix||='%>'}#{rspace}")
-        when nil, '-'
+        when '#'
+          n = code.count("\n") + (rspace ? 1 : 0)
           if trim && lspace && rspace
-            add_code("#{lspace}#{code}#{rspace}")
+            add_code("\n" * n)
           else
             add_text(lspace) if lspace
-            add_code(code)
+            add_code("\n" * n)
             add_text(rspace) if rspace
           end
+        when '%'
+          add_text("#{lspace}#{literal_prefix}#{code}#{tailch}#{literal_postfix}#{rspace}")
         else
           handle(indicator, code, tailch, rspace, lspace)
         end
@@ -159,22 +201,33 @@ module Erubi
 
       src << "\n" unless src[RANGE_LAST] == "\n"
       add_postamble(postamble)
-      src << "; ensure\n  #{bufvar} = __original_outvar\nend\n" if properties[:ensure]
+      src << "; ensure\n  " << bufvar << " = __original_outvar\nend\n" if properties[:ensure]
       src.freeze
       freeze
     end
 
     private
 
-    # Add raw text to the template
+    # Add raw text to the template.  Modifies argument if argument is mutable as a memory optimization.
+    # Must be called with a string, cannot be called with nil (Rails's subclass depends on it).
     def add_text(text)
-      @src << " #{@bufvar} << '" << text.gsub(/['\\]/, '\\\\\&') << TEXT_END unless text.empty?
+      return if text.empty?
+
+      if text.frozen?
+        text = text.gsub(/['\\]/, '\\\\\&')
+      else
+        text.gsub!(/['\\]/, '\\\\\&')
+      end
+
+      with_buffer{@src << " << '" << text << @text_end}
     end
 
     # Add ruby code to the template
     def add_code(code)
+      terminate_expression
       @src << code
       @src << ';' unless code[RANGE_LAST] == "\n"
+      @buffer_on_stack = false
     end
 
     # Add the given ruby expression result to the template,
@@ -189,23 +242,52 @@ module Erubi
 
     # Add the result of Ruby expression to the template
     def add_expression_result(code)
-      @src << " #{@bufvar} << (" << code << ').to_s;'
+      with_buffer{@src << ' << (' << code << ').to_s'}
     end
 
     # Add the escaped result of Ruby expression to the template
     def add_expression_result_escaped(code)
-      @src << " #{@bufvar} << #{@escapefunc}((" << code << '));'
+      with_buffer{@src << ' << ' << @escapefunc << '((' << code << '))'}
     end
 
     # Add the given postamble to the src.  Can be overridden in subclasses
     # to make additional changes to src that depend on the current state.
     def add_postamble(postamble)
-      src << postamble
+      terminate_expression
+      @src << postamble
     end
 
     # Raise an exception, as the base engine class does not support handling other indicators.
     def handle(indicator, code, tailch, rspace, lspace)
       raise ArgumentError, "Invalid indicator: #{indicator}"
     end
+
+    # Make sure the buffer variable is the target of the next append
+    # before yielding to the block. Mark that the buffer is the target
+    # of the next append after the block executes.
+    #
+    # This method should only be called if the block will result in
+    # code where << will append to the bufvar.
+    def with_buffer
+      if @chain_appends
+        unless @buffer_on_stack
+          @src << '; ' << @bufvar
+        end
+        yield
+        @buffer_on_stack = true
+      else
+        @src << ' ' << @bufvar
+        yield
+        @src << ';'
+      end
+    end
+
+    # Make sure that any current expression has been terminated.
+    # The default is to terminate all expressions, but when
+    # the chain_appends option is used, expressions may not be
+    # terminated.
+    def terminate_expression
+      @src << '; ' if @chain_appends
+    end
   end
 end
diff --git a/lib/erubi/capture_end.rb b/lib/erubi/capture_end.rb
index 5bc04f7..e381dfb 100644
--- a/lib/erubi/capture_end.rb
+++ b/lib/erubi/capture_end.rb
@@ -3,15 +3,15 @@
 require 'erubi'
 
 module Erubi
-  # An engine class that supports capturing blocks via the <%|= and <%|== tags,
-  # explicitly ending the captures using <%| end %> blocks.
+  # An engine class that supports capturing blocks via the <tt><%|=</tt> and <tt><%|==</tt> tags,
+  # explicitly ending the captures using <tt><%|</tt> end <tt>%></tt> blocks.
   class CaptureEndEngine < Engine
     # Initializes the engine.  Accepts the same arguments as ::Erubi::Engine, and these
     # additional options:
-    # :escape_capture :: Whether to make <%|= escape by default, and <%|== not escape by default,
+    # :escape_capture :: Whether to make <tt><%|=</tt> escape by default, and <tt><%|==</tt> not escape by default,
     #                    defaults to the same value as :escape.
-    # :yield_returns_buffer :: Whether to have <%| tags insert the buffer as an expression, so that
-    #                          <%| end %> tags will have the buffer be the last expression inside
+    # :yield_returns_buffer :: Whether to have <tt><%|</tt> tags insert the buffer as an expression, so that
+    #                          <tt><%| end %></tt> tags will have the buffer be the last expression inside
     #                          the block, and therefore have the buffer be returned by the yield
     #                          expression.  Normally the buffer will be returned anyway, but there
     #                          are cases where the last expression will not be the buffer,
@@ -36,13 +36,19 @@ module Erubi
         rspace = nil if tailch && !tailch.empty?
         add_text(lspace) if lspace
         escape_capture = !((indicator == '|=') ^ @escape_capture)
-        src << "begin; (#{@bufstack} ||= []) << #{@bufvar}; #{@bufvar} = #{@bufval}; #{@bufstack}.last << #{@escapefunc if escape_capture}((" << code
+        terminate_expression
+        @src << "begin; (#{@bufstack} ||= []) << #{@bufvar}; #{@bufvar} = #{@bufval}; #{@bufstack}.last << #{@escapefunc if escape_capture}((" << code
+        @buffer_on_stack = false
         add_text(rspace) if rspace
       when '|'
         rspace = nil if tailch && !tailch.empty?
         add_text(lspace) if lspace
-        result = @yield_returns_buffer ? " #{@bufvar}; " : ""
-        src << result << code << ")).to_s; ensure; #{@bufvar} = #{@bufstack}.pop; end;"
+        if @yield_returns_buffer
+          terminate_expression
+          @src << " #{@bufvar}; "
+        end
+        @src << code << ")).to_s; ensure; #{@bufvar} = #{@bufstack}.pop; end;"
+        @buffer_on_stack = false
         add_text(rspace) if rspace
       else
         super
diff --git a/test/test.rb b/test/test.rb
deleted file mode 100644
index 940e5d7..0000000
--- a/test/test.rb
+++ /dev/null
@@ -1,780 +0,0 @@
-require 'rubygems'
-
-unless defined?(TESTDIR)
-  TESTDIR = File.dirname(__FILE__)
-  LIBDIR  = TESTDIR == '.' ? '../lib' : File.dirname(TESTDIR) + '/lib'
-  $: << TESTDIR
-  $: << LIBDIR
-end
-
-if ENV['COVERAGE']
-  require 'coverage'
-  require 'simplecov'
-
-  ENV.delete('COVERAGE')
-  SimpleCov.instance_eval do
-    start do
-      add_filter "/test/"
-      add_group('Missing'){|src| src.covered_percent < 100}
-      add_group('Covered'){|src| src.covered_percent == 100}
-    end
-  end
-end
-
-require 'erubi'
-require 'erubi/capture_end'
-
-ENV['MT_NO_PLUGINS'] = '1' # Work around stupid autoloading of plugins
-gem 'minitest'
-require 'minitest/global_expectations/autorun'
-
-describe Erubi::Engine do
-  before do
-    @options = {}
-  end
-
-  def check_output(input, src, result, &block)
-    t = (@options[:engine] || Erubi::Engine).new(input, @options)
-    tsrc = t.src
-    eval(tsrc, block.binding).must_equal result
-    tsrc = tsrc.gsub("'.freeze;", "';") if RUBY_VERSION >= '2.1'
-    tsrc.must_equal src
-  end
-
-  def setup_foo
-    @foo = Object.new
-    @foo.instance_variable_set(:@t, self)
-    def self.a; @a; end
-    def @foo.bar
-      @t.a << "a"
-      yield
-      @t.a << 'b'
-      @t.a.buffer.upcase!
-    end
-  end
-
-  def setup_bar
-    def self.bar
-      @a << "a"
-      yield
-      @a << 'b'
-      @a.upcase
-    end
-    def self.baz
-      @a << "c"
-      yield
-      @a << 'd'
-      @a * 2
-    end
-    def self.quux
-      @a << "a"
-      3.times do |i|
-        @a << "c#{i}"
-        yield i
-        @a << "d#{i}"
-      end
-      @a << "b"
-      @a.upcase
-    end
-  end
-
-  it "should handle no options" do
-    list = ['&\'<>"2']
-    check_output(<<END1, <<END2, <<END3){}
-<table>
- <tbody>
-  <% i = 0
-     list.each_with_index do |item, i| %>
-  <tr>
-   <td><%= i+1 %></td>
-   <td><%== item %></td>
-  </tr>
- <% end %>
- </tbody>
-</table>
-<%== i+1 %>
-END1
-_buf = ::String.new; _buf << '<table>
- <tbody>
-';   i = 0
-     list.each_with_index do |item, i| 
- _buf << '  <tr>
-   <td>'; _buf << ( i+1 ).to_s; _buf << '</td>
-   <td>'; _buf << ::Erubi.h(( item )); _buf << '</td>
-  </tr>
-';  end 
- _buf << ' </tbody>
-</table>
-'; _buf << ::Erubi.h(( i+1 )); _buf << '
-';
-_buf.to_s
-END2
-<table>
- <tbody>
-  <tr>
-   <td>1</td>
-   <td>&amp;&#39;&lt;&gt;&quot;2</td>
-  </tr>
- </tbody>
-</table>
-1
-END3
-  end
-
-  it "should strip only whitespace for <%, <%- and <%# tags" do
-    check_output(<<END1, <<END2, <<END3){}
-  <% 1 %>  
-a
-  <%- 2 %>  
-b
-  <%# 3 %>  
-c
- /<% 1 %>  
-a
-/ <%- 2 %>  
-b
-//<%# 3 %>  
-c
-  <% 1 %> /
-a
-  <%- 2 %>/ 
-b
-  <%# 3 %>//
-c
-END1
-_buf = ::String.new;   1   
- _buf << 'a
-';   2   
- _buf << 'b
-';
- _buf << 'c
- /'; 1 ; _buf << '  
-'; _buf << 'a
-/ '; 2 ; _buf << '  
-'; _buf << 'b
-//';
- _buf << '  
-'; _buf << 'c
-'; _buf << '  '; 1 ; _buf << ' /
-a
-'; _buf << '  '; 2 ; _buf << '/ 
-b
-'; _buf << '  ';; _buf << '//
-c
-';
-_buf.to_s
-END2
-a
-b
-c
- /  
-a
-/   
-b
-//  
-c
-   /
-a
-  / 
-b
-  //
-c
-END3
-  end
-
-  it "should handle ensure option" do
-    list = ['&\'<>"2']
-    @options[:ensure] = true
-    @options[:bufvar] = '@a'
-    @a = 'bar'
-    check_output(<<END1, <<END2, <<END3){}
-<table>
- <tbody>
-  <% i = 0
-     list.each_with_index do |item, i| %>
-  <tr>
-   <td><%= i+1 %></td>
-   <td><%== item %></td>
-  </tr>
- <% end %>
- </tbody>
-</table>
-<%== i+1 %>
-END1
-begin; __original_outvar = @a if defined?(@a); @a = ::String.new; @a << '<table>
- <tbody>
-';   i = 0
-     list.each_with_index do |item, i| 
- @a << '  <tr>
-   <td>'; @a << ( i+1 ).to_s; @a << '</td>
-   <td>'; @a << ::Erubi.h(( item )); @a << '</td>
-  </tr>
-';  end 
- @a << ' </tbody>
-</table>
-'; @a << ::Erubi.h(( i+1 )); @a << '
-';
-@a.to_s
-; ensure
-  @a = __original_outvar
-end
-END2
-<table>
- <tbody>
-  <tr>
-   <td>1</td>
-   <td>&amp;&#39;&lt;&gt;&quot;2</td>
-  </tr>
- </tbody>
-</table>
-1
-END3
-    @a.must_equal 'bar'
-  end
-
-  it "should have <%|= with CaptureEndEngine not escape by default" do
-    eval(::Erubi::CaptureEndEngine.new('<%|= "&" %><%| %>').src).must_equal '&'
-    eval(::Erubi::CaptureEndEngine.new('<%|= "&" %><%| %>', :escape=>false).src).must_equal '&'
-    eval(::Erubi::CaptureEndEngine.new('<%|= "&" %><%| %>', :escape_capture=>false).src).must_equal '&'
-    eval(::Erubi::CaptureEndEngine.new('<%|= "&" %><%| %>', :escape=>true).src).must_equal '&amp;'
-    eval(::Erubi::CaptureEndEngine.new('<%|= "&" %><%| %>', :escape_capture=>true).src).must_equal '&amp;'
-  end
-
-  it "should have <%|== with CaptureEndEngine escape by default" do
-    eval(::Erubi::CaptureEndEngine.new('<%|== "&" %><%| %>').src).must_equal '&amp;'
-    eval(::Erubi::CaptureEndEngine.new('<%|== "&" %><%| %>', :escape=>true).src).must_equal '&'
-    eval(::Erubi::CaptureEndEngine.new('<%|== "&" %><%| %>', :escape_capture=>true).src).must_equal '&'
-    eval(::Erubi::CaptureEndEngine.new('<%|== "&" %><%| %>', :escape=>false).src).must_equal '&amp;'
-    eval(::Erubi::CaptureEndEngine.new('<%|== "&" %><%| %>', :escape_capture=>false).src).must_equal '&amp;'
-  end
-
-  [['', false], ['=', true]].each do |ind, escape|
-    it "should allow <%|=#{ind} and <%| for capturing with CaptureEndEngine with :escape_capture => #{escape} and :escape => #{!escape}" do
-      @options[:bufvar] = '@a'
-      @options[:capture] = true
-      @options[:escape_capture] = escape
-      @options[:escape] = !escape
-      @options[:engine] = ::Erubi::CaptureEndEngine
-      setup_bar
-      check_output(<<END1, <<END2, <<END3){}
-<table>
- <tbody>
-  <%|=#{ind} bar do %>
-   <b><%=#{ind} '&' %></b>
- <%| end %>
- </tbody>
-</table>
-END1
-#{'__erubi = ::Erubi;' unless escape}@a = ::String.new; @a << '<table>
- <tbody>
-'; @a << '  ';begin; (__erubi_stack ||= []) << @a; @a = ::String.new; __erubi_stack.last << (( bar do  @a << '
-'; @a << '   <b>'; @a << #{!escape ? '__erubi' : '::Erubi'}.h(( '&' )); @a << '</b>
-'; @a << ' '; end )).to_s; ensure; @a = __erubi_stack.pop; end; @a << '
-'; @a << ' </tbody>
-</table>
-';
-@a.to_s
-END2
-<table>
- <tbody>
-  A
-   <B>&AMP;</B>
- B
- </tbody>
-</table>
-END3
-    end
-  end
-
-  [['', true], ['=', false]].each do |ind, escape|
-    it "should allow <%|=#{ind} and <%| for capturing with CaptureEndEngine when with :escape => #{escape}" do
-      @options[:bufvar] = '@a'
-      @options[:escape] = escape
-      @options[:engine] = ::Erubi::CaptureEndEngine
-      setup_bar
-      check_output(<<END1, <<END2, <<END3){}
-<table>
- <tbody>
-  <%|=#{ind} bar do %>
-   <b><%=#{ind} '&' %></b>
- <%| end %>
- </tbody>
-</table>
-END1
-#{'__erubi = ::Erubi;' if escape}@a = ::String.new; @a << '<table>
- <tbody>
-'; @a << '  ';begin; (__erubi_stack ||= []) << @a; @a = ::String.new; __erubi_stack.last << #{escape ? '__erubi' : '::Erubi'}.h(( bar do  @a << '
-'; @a << '   <b>'; @a << #{escape ? '__erubi' : '::Erubi'}.h(( '&' )); @a << '</b>
-'; @a << ' '; end )).to_s; ensure; @a = __erubi_stack.pop; end; @a << '
-'; @a << ' </tbody>
-</table>
-';
-@a.to_s
-END2
-<table>
- <tbody>
-  A
-   &lt;B&gt;&amp;AMP;&lt;/B&gt;
- B
- </tbody>
-</table>
-END3
-    end
-
-    it "should handle loops in <%|=#{ind} and <%| for capturing with CaptureEndEngine when with :escape => #{escape}" do
-      @options[:bufvar] = '@a'
-      @options[:escape] = escape
-      @options[:engine] = ::Erubi::CaptureEndEngine
-      setup_bar
-      check_output(<<END1, <<END2, <<END3){}
-<table>
- <tbody>
-  <%|=#{ind} quux do |i| %>
-   <b><%=#{ind} "\#{i}&" %></b>
- <%| end %>
- </tbody>
-</table>
-END1
-#{'__erubi = ::Erubi;' if escape}@a = ::String.new; @a << '<table>
- <tbody>
-'; @a << '  ';begin; (__erubi_stack ||= []) << @a; @a = ::String.new; __erubi_stack.last << #{escape ? '__erubi' : '::Erubi'}.h(( quux do |i|  @a << '
-'; @a << '   <b>'; @a << #{escape ? '__erubi' : '::Erubi'}.h(( "\#{i}&" )); @a << '</b>
-'; @a << ' '; end )).to_s; ensure; @a = __erubi_stack.pop; end; @a << '
-'; @a << ' </tbody>
-</table>
-';
-@a.to_s
-END2
-<table>
- <tbody>
-  AC0
-   &lt;B&gt;0&amp;AMP;&lt;/B&gt;
- D0C1
-   &lt;B&gt;1&amp;AMP;&lt;/B&gt;
- D1C2
-   &lt;B&gt;2&amp;AMP;&lt;/B&gt;
- D2B
- </tbody>
-</table>
-END3
-    end
-
-    it "should allow <%|=#{ind} and <%| for nested capturing with CaptureEndEngine when with :escape => #{escape}" do
-      @options[:bufvar] = '@a'
-      @options[:escape] = escape
-      @options[:engine] = ::Erubi::CaptureEndEngine
-      setup_bar
-      check_output(<<END1, <<END2, <<END3){}
-<table>
- <tbody>
-  <%|=#{ind} bar do %>
-   <b><%=#{ind} '&' %></b>
-   <%|=#{ind} baz do %>e<%| end %>
- <%| end %>
- </tbody>
-</table>
-END1
-#{'__erubi = ::Erubi;' if escape}@a = ::String.new; @a << '<table>
- <tbody>
-'; @a << '  ';begin; (__erubi_stack ||= []) << @a; @a = ::String.new; __erubi_stack.last << #{escape ? '__erubi' : '::Erubi'}.h(( bar do  @a << '
-'; @a << '   <b>'; @a << #{escape ? '__erubi' : '::Erubi'}.h(( '&' )); @a << '</b>
-'; @a << '   ';begin; (__erubi_stack ||= []) << @a; @a = ::String.new; __erubi_stack.last << #{escape ? '__erubi' : '::Erubi'}.h(( baz do  @a << 'e'; end )).to_s; ensure; @a = __erubi_stack.pop; end; @a << '
-'; @a << ' '; end )).to_s; ensure; @a = __erubi_stack.pop; end; @a << '
-'; @a << ' </tbody>
-</table>
-';
-@a.to_s
-END2
-<table>
- <tbody>
-  A
-   &lt;B&gt;&amp;AMP;&lt;/B&gt;
-   CEDCED
- B
- </tbody>
-</table>
-END3
-    end
-  end
-
-  [:outvar, :bufvar].each do |var|
-    it "should handle :#{var} and :freeze options" do
-      @options[var] = "@_out_buf"
-      @options[:freeze] = true
-      @items = [2]
-      i = 0
-      check_output(<<END1, <<END2, <<END3){}
-<table>
-  <% for item in @items %>
-  <tr>
-    <td><%= i+1 %></td>
-    <td><%== item %></td>
-  </tr>
-  <% end %>
-</table>
-END1
-# frozen_string_literal: true
-@_out_buf = ::String.new; @_out_buf << '<table>
-';   for item in @items 
- @_out_buf << '  <tr>
-    <td>'; @_out_buf << ( i+1 ).to_s; @_out_buf << '</td>
-    <td>'; @_out_buf << ::Erubi.h(( item )); @_out_buf << '</td>
-  </tr>
-';   end 
- @_out_buf << '</table>
-';
-@_out_buf.to_s
-END2
-<table>
-  <tr>
-    <td>1</td>
-    <td>2</td>
-  </tr>
-</table>
-END3
-    end
-  end
-
-  it "should handle <%% and <%# syntax" do
-    @items = [2]
-    i = 0
-    check_output(<<END1, <<END2, <<END3){}
-<table>
-<%% for item in @items %>
-  <tr>
-    <td><%# i+1 %></td>
-    <td><%# item %></td>
-  </tr>
-  <%% end %>
-</table>
-END1
-_buf = ::String.new; _buf << '<table>
-'; _buf << '<% for item in @items %>
-'; _buf << '  <tr>
-    <td>';; _buf << '</td>
-    <td>';; _buf << '</td>
-  </tr>
-'; _buf << '  <% end %>
-'; _buf << '</table>
-';
-_buf.to_s
-END2
-<table>
-<% for item in @items %>
-  <tr>
-    <td></td>
-    <td></td>
-  </tr>
-  <% end %>
-</table>
-END3
-  end
-
-  it "should handle :trim => false option" do
-    @options[:trim] = false
-    @items = [2]
-    i = 0
-    check_output(<<END1, <<END2, <<END3){}
-<table>
-  <% for item in @items %>
-  <tr>
-    <td><%# 
-    i+1
-    %></td>
-    <td><%== item %></td>
-  </tr>
-  <% end %><%#%>
-  <% i %>a
-  <% i %>
-</table>
-END1
-_buf = ::String.new; _buf << '<table>
-'; _buf << '  '; for item in @items ; _buf << '
-'; _buf << '  <tr>
-    <td>';
-
- _buf << '</td>
-    <td>'; _buf << ::Erubi.h(( item )); _buf << '</td>
-  </tr>
-'; _buf << '  '; end ;
- _buf << '
-'; _buf << '  '; i ; _buf << 'a
-'; _buf << '  '; i ; _buf << '
-'; _buf << '</table>
-';
-_buf.to_s
-END2
-<table>
-  
-  <tr>
-    <td></td>
-    <td>2</td>
-  </tr>
-  
-  a
-  
-</table>
-END3
-  end
-
-  [:escape, :escape_html].each do  |opt|
-    it "should handle :#{opt} and :escapefunc options" do
-      @options[opt] = true
-      @options[:escapefunc] = 'h.call'
-      h = proc{|s| s.to_s*2}
-      list = ['2']
-      check_output(<<END1, <<END2, <<END3){}
-<table>
- <tbody>
-  <% i = 0
-     list.each_with_index do |item, i| %>
-  <tr>
-   <td><%= i+1 %></td>
-   <td><%== item %></td>
-  </tr>
- <% end %>
- </tbody>
-</table>
-<%== i+1 %>
-END1
-_buf = ::String.new; _buf << '<table>
- <tbody>
-';   i = 0
-     list.each_with_index do |item, i| 
- _buf << '  <tr>
-   <td>'; _buf << h.call(( i+1 )); _buf << '</td>
-   <td>'; _buf << ( item ).to_s; _buf << '</td>
-  </tr>
-';  end 
- _buf << ' </tbody>
-</table>
-'; _buf << ( i+1 ).to_s; _buf << '
-';
-_buf.to_s
-END2
-<table>
- <tbody>
-  <tr>
-   <td>11</td>
-   <td>2</td>
-  </tr>
- </tbody>
-</table>
-1
-END3
-    end
-  end
-
-  it "should handle :escape option without :escapefunc option" do
-    @options[:escape] = true
-    list = ['&\'<>"2']
-    check_output(<<END1, <<END2, <<END3){}
-<table>
- <tbody>
-  <% i = 0
-     list.each_with_index do |item, i| %>
-  <tr>
-   <td><%== i+1 %></td>
-   <td><%= item %></td>
-  </tr>
- <% end %>
- </tbody>
-</table>
-END1
-__erubi = ::Erubi;_buf = ::String.new; _buf << '<table>
- <tbody>
-';   i = 0
-     list.each_with_index do |item, i| 
- _buf << '  <tr>
-   <td>'; _buf << ( i+1 ).to_s; _buf << '</td>
-   <td>'; _buf << __erubi.h(( item )); _buf << '</td>
-  </tr>
-';  end 
- _buf << ' </tbody>
-</table>
-';
-_buf.to_s
-END2
-<table>
- <tbody>
-  <tr>
-   <td>1</td>
-   <td>&amp;&#39;&lt;&gt;&quot;2</td>
-  </tr>
- </tbody>
-</table>
-END3
-  end
-
-  it "should handle :preamble and :postamble options" do
-    @options[:preamble] = '_buf = String.new("1");'
-    @options[:postamble] = "_buf[0...18]\n"
-    list = ['2']
-    check_output(<<END1, <<END2, <<END3){}
-<table>
- <tbody>
-  <% i = 0
-     list.each_with_index do |item, i| %>
-  <tr>
-   <td><%= i+1 %></td>
-   <td><%== item %></td>
-  </tr>
- <% end %>
- </tbody>
-</table>
-<%== i+1 %>
-END1
-_buf = String.new("1"); _buf << '<table>
- <tbody>
-';   i = 0
-     list.each_with_index do |item, i| 
- _buf << '  <tr>
-   <td>'; _buf << ( i+1 ).to_s; _buf << '</td>
-   <td>'; _buf << ::Erubi.h(( item )); _buf << '</td>
-  </tr>
-';  end 
- _buf << ' </tbody>
-</table>
-'; _buf << ::Erubi.h(( i+1 )); _buf << '
-';
-_buf[0...18]
-END2
-1<table>
- <tbody>
-END3
-  end
-
-  it "should have working filename accessor" do
-    Erubi::Engine.new('', :filename=>'foo.rb').filename.must_equal 'foo.rb'
-  end
-
-  it "should have working bufvar accessor" do
-    Erubi::Engine.new('', :bufvar=>'foo').bufvar.must_equal 'foo'
-    Erubi::Engine.new('', :outvar=>'foo').bufvar.must_equal 'foo'
-  end
-
-  it "should work with BasicObject methods" do
-    c = Class.new(BasicObject)
-    c.class_eval("def a; #{Erubi::Engine.new('2').src} end")
-    c.new.a.must_equal '2'
-  end if defined?(BasicObject)
-
-  it "should return frozen object" do
-    Erubi::Engine.new('').frozen?.must_equal true
-  end
-
-  it "should have frozen src" do
-    Erubi::Engine.new('').src.frozen?.must_equal true
-  end
-
-  it "should raise an error if a tag is not handled when a custom regexp is used" do
-    proc{Erubi::Engine.new('<%] %>', :regexp =>/<%(={1,2}|\]|-|\#|%)?(.*?)([-=])?%>([ \t]*\r?\n)?/m)}.must_raise ArgumentError
-    proc{Erubi::CaptureEndEngine.new('<%] %>', :regexp =>/<%(={1,2}|\]|-|\#|%)?(.*?)([-=])?%>([ \t]*\r?\n)?/m)}.must_raise ArgumentError
-  end
-
-  it "should respect the :yield_returns_buffer option for making templates return the (potentially modified) buffer" do
-    @options[:engine] = ::Erubi::CaptureEndEngine
-    @options[:bufvar] = '@a'
-
-    def self.bar
-      a = String.new
-      a << "a"
-      yield 'burgers'
-      case b = (yield 'salads')
-      when String
-        a << b
-        a << 'b'
-        a.upcase
-      end
-    end
-
-    check_output(<<END1, <<END2, <<END3){}
-<%|= bar do |item| %>
-Let's eat <%= item %>!
-<% nil %><%| end %>
-END1
-@a = ::String.new;begin; (__erubi_stack ||= []) << @a; @a = ::String.new; __erubi_stack.last << (( bar do |item|  @a << '
-'; @a << 'Let\\'s eat '; @a << ( item ).to_s; @a << '!
-'; nil ; end )).to_s; ensure; @a = __erubi_stack.pop; end; @a << '
-';
-@a.to_s
-END2
-
-END3
-
-    @options[:yield_returns_buffer] = true
-
-    check_output(<<END1, <<END2, <<END3) {}
-<%|= bar do |item| %>
-Let's eat <%= item %>!
-<% nil %><%| end %>
-END1
-@a = ::String.new;begin; (__erubi_stack ||= []) << @a; @a = ::String.new; __erubi_stack.last << (( bar do |item|  @a << '
-'; @a << 'Let\\'s eat '; @a << ( item ).to_s; @a << '!
-'; nil ; @a;  end )).to_s; ensure; @a = __erubi_stack.pop; end; @a << '
-';
-@a.to_s
-END2
-A
-LET'S EAT BURGERS!
-
-LET'S EAT SALADS!
-B
-END3
-  end
-
-  it "should respect the :yield_returns_buffer option for making templates return the (potentially modified) buffer as the result of the block" do
-    @options[:engine] = ::Erubi::CaptureEndEngine
-    @options[:yield_returns_buffer] = true
-
-    def self.bar(foo = nil)
-      if foo.nil?
-        yield
-      else
-        foo
-      end
-    end
-
-    check_output(<<END1, <<END2, <<END3) {}
-<%|= bar do %>
-Let's eat the tacos!
-<%| end %>
-
-Delicious!
-END1
-_buf = ::String.new;begin; (__erubi_stack ||= []) << _buf; _buf = ::String.new; __erubi_stack.last << (( bar do  _buf << '
-'; _buf << 'Let\\'s eat the tacos!
-'; _buf;  end )).to_s; ensure; _buf = __erubi_stack.pop; end; _buf << '
-'; _buf << '
-Delicious!
-';
-_buf.to_s
-END2
-
-Let's eat the tacos!
-
-
-Delicious!
-END3
-
-    check_output(<<END1, <<END2, <<END3) {}
-<%|= bar("Don't eat the burgers!") do %>
-Let's eat burgers!
-<%| end %>
-
-Delicious!
-END1
-_buf = ::String.new;begin; (__erubi_stack ||= []) << _buf; _buf = ::String.new; __erubi_stack.last << (( bar(\"Don't eat the burgers!\") do  _buf << '
-'; _buf << 'Let\\'s eat burgers!
-'; _buf;  end )).to_s; ensure; _buf = __erubi_stack.pop; end; _buf << '
-'; _buf << '
-Delicious!
-';
-_buf.to_s
-END2
-Don't eat the burgers!
-
-Delicious!
-END3
-  end
-end

Debdiff

[The following lists of changes regard files as different if they have different names, permissions or owners.]

Files in second set of .debs but not in first

-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/erubi-1.12.0/lib/erubi.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/erubi-1.12.0/lib/erubi/capture_end.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/specifications/erubi-1.12.0.gemspec

Files in first set of .debs but not in second

-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/erubi-1.9.0/lib/erubi.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/erubi-1.9.0/lib/erubi/capture_end.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/specifications/erubi-1.9.0.gemspec

No differences were encountered in the control files

More details

Full run details