erubi-1.9.0/0000755000004100000410000000000013567017750012672 5ustar www-datawww-dataerubi-1.9.0/test/0000755000004100000410000000000013567017750013651 5ustar www-datawww-dataerubi-1.9.0/test/test.rb0000644000004100000410000004113713567017750015163 0ustar www-datawww-datarequire '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(< <% i = 0 list.each_with_index do |item, i| %> <%= i+1 %> <%== item %> <% end %> <%== i+1 %> END1 _buf = ::String.new; _buf << ' '; i = 0 list.each_with_index do |item, i| _buf << ' '; end _buf << '
'; _buf << ( i+1 ).to_s; _buf << ' '; _buf << ::Erubi.h(( item )); _buf << '
'; _buf << ::Erubi.h(( i+1 )); _buf << ' '; _buf.to_s END2
1 &'<>"2
1 END3 end it "should strip only whitespace for <%, <%- and <%# tags" do check_output(< 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(< <% i = 0 list.each_with_index do |item, i| %> <%= i+1 %> <%== item %> <% end %> <%== i+1 %> END1 begin; __original_outvar = @a if defined?(@a); @a = ::String.new; @a << ' '; i = 0 list.each_with_index do |item, i| @a << ' '; end @a << '
'; @a << ( i+1 ).to_s; @a << ' '; @a << ::Erubi.h(( item )); @a << '
'; @a << ::Erubi.h(( i+1 )); @a << ' '; @a.to_s ; ensure @a = __original_outvar end END2
1 &'<>"2
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 '&' eval(::Erubi::CaptureEndEngine.new('<%|= "&" %><%| %>', :escape_capture=>true).src).must_equal '&' end it "should have <%|== with CaptureEndEngine escape by default" do eval(::Erubi::CaptureEndEngine.new('<%|== "&" %><%| %>').src).must_equal '&' 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 '&' eval(::Erubi::CaptureEndEngine.new('<%|== "&" %><%| %>', :escape_capture=>false).src).must_equal '&' 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(< <%|=#{ind} bar do %> <%=#{ind} '&' %> <%| end %> END1 #{'__erubi = ::Erubi;' unless escape}@a = ::String.new; @a << ' '; @a << ' ';begin; (__erubi_stack ||= []) << @a; @a = ::String.new; __erubi_stack.last << (( bar do @a << ' '; @a << ' '; @a << #{!escape ? '__erubi' : '::Erubi'}.h(( '&' )); @a << ' '; @a << ' '; end )).to_s; ensure; @a = __erubi_stack.pop; end; @a << ' '; @a << '
'; @a.to_s END2 A & B
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(< <%|=#{ind} bar do %> <%=#{ind} '&' %> <%| end %> END1 #{'__erubi = ::Erubi;' if escape}@a = ::String.new; @a << ' '; @a << ' ';begin; (__erubi_stack ||= []) << @a; @a = ::String.new; __erubi_stack.last << #{escape ? '__erubi' : '::Erubi'}.h(( bar do @a << ' '; @a << ' '; @a << #{escape ? '__erubi' : '::Erubi'}.h(( '&' )); @a << ' '; @a << ' '; end )).to_s; ensure; @a = __erubi_stack.pop; end; @a << ' '; @a << '
'; @a.to_s END2 A <B>&AMP;</B> B
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(< <%|=#{ind} quux do |i| %> <%=#{ind} "\#{i}&" %> <%| end %> END1 #{'__erubi = ::Erubi;' if escape}@a = ::String.new; @a << ' '; @a << ' ';begin; (__erubi_stack ||= []) << @a; @a = ::String.new; __erubi_stack.last << #{escape ? '__erubi' : '::Erubi'}.h(( quux do |i| @a << ' '; @a << ' '; @a << #{escape ? '__erubi' : '::Erubi'}.h(( "\#{i}&" )); @a << ' '; @a << ' '; end )).to_s; ensure; @a = __erubi_stack.pop; end; @a << ' '; @a << '
'; @a.to_s END2 AC0 <B>0&AMP;</B> D0C1 <B>1&AMP;</B> D1C2 <B>2&AMP;</B> D2B
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(< <%|=#{ind} bar do %> <%=#{ind} '&' %> <%|=#{ind} baz do %>e<%| end %> <%| end %> END1 #{'__erubi = ::Erubi;' if escape}@a = ::String.new; @a << ' '; @a << ' ';begin; (__erubi_stack ||= []) << @a; @a = ::String.new; __erubi_stack.last << #{escape ? '__erubi' : '::Erubi'}.h(( bar do @a << ' '; @a << ' '; @a << #{escape ? '__erubi' : '::Erubi'}.h(( '&' )); @a << ' '; @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 << '
'; @a.to_s END2 A <B>&AMP;</B> CEDCED B
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(< <% for item in @items %> <%= i+1 %> <%== item %> <% end %> END1 # frozen_string_literal: true @_out_buf = ::String.new; @_out_buf << ' '; for item in @items @_out_buf << ' '; end @_out_buf << '
'; @_out_buf << ( i+1 ).to_s; @_out_buf << ' '; @_out_buf << ::Erubi.h(( item )); @_out_buf << '
'; @_out_buf.to_s END2
1 2
END3 end end it "should handle <%% and <%# syntax" do @items = [2] i = 0 check_output(< <%% for item in @items %> <%# i+1 %> <%# item %> <%% end %> END1 _buf = ::String.new; _buf << ' '; _buf << '<% for item in @items %> '; _buf << ' '; _buf << ' <% end %> '; _buf << '
';; _buf << ' ';; _buf << '
'; _buf.to_s END2 <% for item in @items %> <% end %>
END3 end it "should handle :trim => false option" do @options[:trim] = false @items = [2] i = 0 check_output(< <% for item in @items %> <%# i+1 %> <%== item %> <% end %><%#%> <% i %>a <% i %> END1 _buf = ::String.new; _buf << ' '; _buf << ' '; for item in @items ; _buf << ' '; _buf << ' '; _buf << ' '; end ; _buf << ' '; _buf << ' '; i ; _buf << 'a '; _buf << ' '; i ; _buf << ' '; _buf << '
'; _buf << ' '; _buf << ::Erubi.h(( item )); _buf << '
'; _buf.to_s END2 a
2
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(< <% i = 0 list.each_with_index do |item, i| %> <%= i+1 %> <%== item %> <% end %> <%== i+1 %> END1 _buf = ::String.new; _buf << ' '; i = 0 list.each_with_index do |item, i| _buf << ' '; end _buf << '
'; _buf << h.call(( i+1 )); _buf << ' '; _buf << ( item ).to_s; _buf << '
'; _buf << ( i+1 ).to_s; _buf << ' '; _buf.to_s END2
11 2
1 END3 end end it "should handle :escape option without :escapefunc option" do @options[:escape] = true list = ['&\'<>"2'] check_output(< <% i = 0 list.each_with_index do |item, i| %> <%== i+1 %> <%= item %> <% end %> END1 __erubi = ::Erubi;_buf = ::String.new; _buf << ' '; i = 0 list.each_with_index do |item, i| _buf << ' '; end _buf << '
'; _buf << ( i+1 ).to_s; _buf << ' '; _buf << __erubi.h(( item )); _buf << '
'; _buf.to_s END2
1 &'<>"2
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(< <% i = 0 list.each_with_index do |item, i| %> <%= i+1 %> <%== item %> <% end %> <%== i+1 %> END1 _buf = String.new("1"); _buf << ' '; i = 0 list.each_with_index do |item, i| _buf << ' '; end _buf << '
'; _buf << ( i+1 ).to_s; _buf << ' '; _buf << ::Erubi.h(( item )); _buf << '
'; _buf << ::Erubi.h(( i+1 )); _buf << ' '; _buf[0...18] END2 1 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(< 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(< 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(< 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(< 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 erubi-1.9.0/Rakefile0000644000004100000410000000344413567017750014344 0ustar www-datawww-datarequire "rake" require "rake/clean" NAME = 'erubi' CLEAN.include ["#{NAME}-*.gem", "rdoc", "coverage"] # Gem Packaging and Release desc "Packages #{NAME}" task :package=>[:clean] do |p| sh %{gem build #{NAME}.gemspec} end ### RDoc RDOC_DEFAULT_OPTS = ["--line-numbers", "--inline-source", '--title', 'Erubi: Small ERB Implementation'] begin gem 'hanna-nouveau' RDOC_DEFAULT_OPTS.concat(['-f', 'hanna']) rescue Gem::LoadError end rdoc_task_class = begin require "rdoc/task" RDoc::Task rescue LoadError require "rake/rdoctask" Rake::RDocTask end RDOC_OPTS = RDOC_DEFAULT_OPTS + ['--main', 'README.rdoc'] RDOC_FILES = %w"README.rdoc CHANGELOG MIT-LICENSE lib/**/*.rb" rdoc_task_class.new do |rdoc| rdoc.rdoc_dir = "rdoc" rdoc.options += RDOC_OPTS rdoc.rdoc_files.add RDOC_FILES end ### Specs spec = proc do |env| env.each{|k,v| ENV[k] = v} sh "#{FileUtils::RUBY} test/test.rb" env.each{|k,v| ENV.delete(k)} end desc "Run specs" task "spec" do spec.call({}) end task :default=>:spec 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 desc "Start an IRB shell using the extension" task :irb do require 'rbconfig' ruby = ENV['RUBY'] || File.join(RbConfig::CONFIG['bindir'], RbConfig::CONFIG['ruby_install_name']) irb = ENV['IRB'] || File.join(RbConfig::CONFIG['bindir'], File.basename(ruby).sub('ruby', 'irb')) sh %{#{irb} -I lib -r #{NAME}} end erubi-1.9.0/lib/0000755000004100000410000000000013567017750013440 5ustar www-datawww-dataerubi-1.9.0/lib/erubi/0000755000004100000410000000000013567017750014546 5ustar www-datawww-dataerubi-1.9.0/lib/erubi/capture_end.rb0000644000004100000410000000453413567017750017372 0ustar www-datawww-data# frozen_string_literal: true require 'erubi' module Erubi # An engine class that supports capturing blocks via the <%|= and <%|== tags, # explicitly ending the captures using <%| end %> 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, # 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 # 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, # and therefore a different object will be returned. def initialize(input, properties={}) properties = Hash[properties] escape = properties.fetch(:escape){properties.fetch(:escape_html, false)} @escape_capture = properties.fetch(:escape_capture, escape) @yield_returns_buffer = properties.fetch(:yield_returns_buffer, false) @bufval = properties[:bufval] ||= '::String.new' @bufstack = '__erubi_stack' properties[:regexp] ||= /<%(\|?={1,2}|-|\#|%|\|)?(.*?)([-=])?%>([ \t]*\r?\n)?/m super end private # Handle the <%|= and <%|== tags def handle(indicator, code, tailch, rspace, lspace) case indicator when '|=', '|==' 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 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;" add_text(rspace) if rspace else super end end end end erubi-1.9.0/lib/erubi.rb0000644000004100000410000001563013567017750015100 0ustar www-datawww-data# frozen_string_literal: true module Erubi VERSION = '1.9.0' RANGE_ALL = 0..-1 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 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 rescue LoadError ESCAPE_TABLE = {'&' => '&'.freeze, '<' => '<'.freeze, '>' => '>'.freeze, '"' => '"'.freeze, "'" => '''.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) end else def self.h(value) value.to_s.gsub(/[&<>"']/){|s| ESCAPE_TABLE[s]} end end end class Engine # The frozen ruby source code generated from the template, which can be evaled. attr_reader :src # The filename of the template, if one was given. attr_reader :filename # The variable name used for the buffer variable. 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. 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 preamble = properties[:preamble] || "#{bufvar} = #{bufval};" postamble = properties[:postamble] || "#{bufvar}.to_s\n" @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] unless @escapefunc = properties[:escapefunc] if escape @escapefunc = '__erubi.h' src << "__erubi = ::Erubi;" else @escapefunc = '::Erubi.h' end end src << preamble pos = 0 is_bol = true input.scan(regexp) do |indicator, code, tailch, rspace| match = Regexp.last_match len = match.begin(0) - pos text = input[pos, len] pos = match.end(0) ch = indicator ? indicator[RANGE_FIRST] : nil lspace = nil unless ch == '=' if text.empty? lspace = "" if is_bol elsif text[RANGE_LAST] == "\n" lspace = "" else rindex = text.rindex("\n") if rindex range = rindex+1..-1 s = text[range] if s =~ /\A[ \t]*\z/ lspace = s text[range] = '' end else if is_bol && text =~ /\A[ \t]*\z/ lspace = text.dup text[RANGE_ALL] = '' end end end end is_bol = rspace add_text(text) if text && !text.empty? 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) if trim && lspace && rspace add_code("\n" * n) else add_text(lspace) if lspace add_code("\n" * n) add_text(rspace) if rspace end when '%' add_text("#{lspace}#{prefix||='<%'}#{code}#{tailch}#{postfix||='%>'}#{rspace}") when nil, '-' if trim && lspace && rspace add_code("#{lspace}#{code}#{rspace}") else add_text(lspace) if lspace add_code(code) add_text(rspace) if rspace end else handle(indicator, code, tailch, rspace, lspace) end end rest = pos == 0 ? input : input[pos..-1] add_text(rest) src << "\n" unless src[RANGE_LAST] == "\n" add_postamble(postamble) src << "; ensure\n #{bufvar} = __original_outvar\nend\n" if properties[:ensure] src.freeze freeze end private # Add raw text to the template def add_text(text) @src << " #{@bufvar} << '" << text.gsub(/['\\]/, '\\\\\&') << TEXT_END unless text.empty? end # Add ruby code to the template def add_code(code) @src << code @src << ';' unless code[RANGE_LAST] == "\n" end # Add the given ruby expression result to the template, # escaping it based on the indicator given and escape flag. def add_expression(indicator, code) if ((indicator == '=') ^ @escape) add_expression_result(code) else add_expression_result_escaped(code) end end # Add the result of Ruby expression to the template def add_expression_result(code) @src << " #{@bufvar} << (" << code << ').to_s;' end # Add the escaped result of Ruby expression to the template def add_expression_result_escaped(code) @src << " #{@bufvar} << #{@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 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 end end erubi-1.9.0/README.rdoc0000644000004100000410000000643113567017750014504 0ustar www-datawww-data= Erubi Erubi is a ERB template engine for ruby. It is a simplified fork of Erubis, using the same basic algorithm, with the following differences: * Handles postfix conditionals when using escaping (e.g. <%= foo if bar %>) * Supports frozen_string_literal: true in templates via :freeze option * Works with ruby's --enable-frozen-string-literal option * Automatically freezes strings for template text when ruby optimizes it (on ruby 2.1+) * Escapes ' (apostrophe) when escaping for better XSS protection * Has 6x faster escaping on ruby 2.3+ by using cgi/escape * Has 86% smaller memory footprint * 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) * Is not dead (Erubis hasn't been updated since 2011) It is not designed with Erubis API compatibility in mind, though most Erubis ERB syntax works, with the following exceptions: * No support for <%=== for debug output = Installation gem install erubi = Source Code Source code is available on GitHub at https://github.com/jeremyevans/erubi = Usage Erubi only has built in support for retrieving the generated source for a file: require 'erubi' eval(Erubi::Engine.new(File.read('filename.erb')).src) Most users will probably use Erubi via Rails or Tilt. Erubi is the default erb template handler in Tilt 2.0.6+ and Rails 5.1+. == Capturing Erubi does not support capturing block output into the template by default. However, it comes with an +erubi/capture_end+ file that supports capturing via <%|= and <%|== tags which are closed with a <%| tag: <%|= form do %> <%| end %> This offers similar functionality to that offered by Rails' <%= tags, but without the corner cases with that approach (which are due to attempting to parse ruby code via a regexp). Similar to the <%= and <%== tags, <%|= captures by default and <%|== captures and escapes by default, but this can be reversed via the +:escape_capture+ or +:escape+ options. To use the capture_end support with tilt: require 'tilt' require 'erubi/capture_end' Tilt.new("filename.erb", :engine_class=>Erubi::CaptureEndEngine).render When using the capture_end support, any methods (such as +form+ in the example above) should return the (potentially modified) buffer. Since the buffer variable is a local variable and not an instance variable by default, you'll probably want to set the +:bufvar+ variable when using the capture_end support to an instance variable, and have any methods used access that instance variable. Example: def form @_buf << "
" yield @_buf << "" @_buf end puts eval(Erubi::CaptureEndEngine.new(<<-END, :bufvar=>:@_buf).src) before <%|= form do %> inside <%| end %> after END # Output: # before #
# inside # # after Alternatively, passing the option +:yield_returns_buffer => true+ will return the buffer captured by the block instead of the last expression in the block. = Reporting Bugs The bug tracker is located at https://github.com/jeremyevans/erubi/issues = License MIT = Authors Jeremy Evans kuwata-lab.com erubi-1.9.0/erubi.gemspec0000644000004100000410000000356713567017750015360 0ustar www-datawww-data######################################################### # This file has been automatically generated by gem2tgz # ######################################################### # -*- encoding: utf-8 -*- # stub: erubi 1.9.0 ruby lib Gem::Specification.new do |s| s.name = "erubi".freeze s.version = "1.9.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Jeremy Evans".freeze, "kuwata-lab.com".freeze] s.date = "2019-09-25" 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.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.summary = "Small ERB Implementation".freeze if s.respond_to? :specification_version then s.specification_version = 4 if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) end else s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) end end erubi-1.9.0/MIT-LICENSE0000644000004100000410000000213713567017750014331 0ustar www-datawww-datacopyright(c) 2006-2011 kuwata-lab.com all rights reserved. copyright(c) 2016-2018 Jeremy Evans Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. erubi-1.9.0/CHANGELOG0000644000004100000410000000522213567017750014105 0ustar www-datawww-data=== 1.9.0 (2019-09-25) * Change default :bufvar from 'String.new' to '::String.new' to work with BasicObject (jeremyevans) === 1.8.0 (2018-12-18) * Support :yield_returns_buffer option in capture_end for always returning the (potentially modified) buffer in <%|= tags (evanleck) (#15) === 1.7.1 (2018-03-05) * Make whitespace handling for <%# %> tags more compatible with Erubis (jeremyevans) (#14) === 1.7.0 (2017-10-09) * Fix escaping in erubi/capture_end, the setting was previously inverted (jeremyevans) (#10) === 1.6.1 (2017-06-27) * Fix usage on newer versions of JRuby 9.1 (jeremyevans) === 1.6.0 (2017-02-27) * Use cgi/escape if available for 6x faster HTML escaping (k0kubun, jeremyevans) (#4) === 1.5.0 (2017-01-26) * Drop tilt/erubi file, as tilt now ships with Erubi support (jeremyevans) * Drop erubi/capture file, Erubi::CaptureEngine support (jeremyevans) === 1.4.0 (2017-01-20) * Allow postambles to depend on internal state of engine (jeremyevans) * Allow overriding of behavior for <%= and <%== tags to depend on which indicator was used (jeremyevans) * Make whitespace handling for <% %> tags more compatible with Erubis for subclasses overriding add_text (jeremyevans) === 1.3.0 (2016-12-29) * Support :capture=>:explicit option in tilt support to use Erubi::CaptureEndEngine (jeremyevans) * Add erubi/capture_end containing Erubi::CaptureEndEngine, allowing <%|= and <%|== for opening capture tags, and <%| for closing capture tags (jeremyevans) === 1.2.1 (2016-11-21) * Don't automatically freeze template text strings on ruby 1.9 or 2.0 (jeremyevans) === 1.2.0 (2016-11-21) * Engine#src now returns a frozen string (jeremyevans) * Automatically freeze template text strings on ruby 2.1+, reducing garbage generated (jeremyevans) * Allow overriding of behavior for <%= and <%== tags (ujifgc) (#1) === 1.1.0 (2016-11-14) * Add :ensure option to supporting restoring bufvar to original value (jeremyevans) * Don't have tilt support require erb (jeremyevans) * Support :engine_class option in tilt support to override engine class used (jeremyevans) * Support :capture option in tilt support to use Erubi::CaptureEngine (jeremyevans) * Add erubi/capture file containing Erubi::CaptureEngine, allowing <%|= and <%|== for capture (and escaping) blocks in templates (jeremyevans) * Raise ArgumentError if template source code contains indicators matched by regexp but not handled (jeremyevans) * Add :bufval option to support arbitrary buffer values (jeremyevans) * Add :regexp option to specify regexp used for scanning (jeremyevans) * Add :src option to specify initial template source (jeremyevans) === 1.0.0 (2016-11-10) * Initial Public Release