erubi 1.9.0 → 1.10.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '0929d05c25dcdf116a4629c9803bbf70e4abac132acec9d831a3492a5903c5c6'
4
- data.tar.gz: d95fccdac8f5755b1137b4cd652be69f23db18729f972cd017b613e2e2b80426
3
+ metadata.gz: 3f504eb8d1ae0f89e098de29336a69d0251cd8659a1b6fe1ab86c7f23ed44d67
4
+ data.tar.gz: e54396a6eb2cf0c193089c9b2c3d5fa0f92daf5cf4f462fe09d0aea6dca49419
5
5
  SHA512:
6
- metadata.gz: 54b160b258687a50dfc541b9f9c59fbbe3e8cff020432003b00e7cfa950c81d1a7ae0eef978c8e53b2c49c85995f40600395ffaccb578e1e07b303f5f7bb3298
7
- data.tar.gz: 5d9a63e80b79f2afc48cdb42016ec937556dc62d98987fe0fa9d87e0bad7e744d8f710860f188e500bb0718ca0eb0d5779d6e65de7f2d3664833e86f1802e68d
6
+ metadata.gz: 0a789b8a528548760ac4898867588477e03c3f1410bd930538c849e167c68a346202f8c168a2a71107485c961bb41a91d549f687a4d24ebf3614821bc15b4e73
7
+ data.tar.gz: 14e74f5fb8c452c0cbc15afbe51b8a86be572d8d585416f09f07d9227e06ad8d8c14d8681424dc53f9b7eaba1a1297ed72e8e7dc0c36afe6e2da1926bec742d0
data/CHANGELOG CHANGED
@@ -1,3 +1,11 @@
1
+ === 1.10.0 (2020-11-13)
2
+
3
+ * Improve template parsing, mostly by reducing allocations (jeremyevans)
4
+
5
+ * Do not ship tests in the gem, reducing gem size about 20% (jeremyevans)
6
+
7
+ * Support :literal_prefix and :literal_postfix options for how to output literal tags (e.g. <%% code %>) (jaredcwhite) (#26, #27)
8
+
1
9
  === 1.9.0 (2019-09-25)
2
10
 
3
11
  * Change default :bufvar from 'String.new' to '::String.new' to work with BasicObject (jeremyevans)
@@ -1,5 +1,5 @@
1
1
  copyright(c) 2006-2011 kuwata-lab.com all rights reserved.
2
- copyright(c) 2016-2018 Jeremy Evans
2
+ copyright(c) 2016-2020 Jeremy Evans
3
3
 
4
4
  Permission is hereby granted, free of charge, to any person obtaining
5
5
  a copy of this software and associated documentation files (the
@@ -5,9 +5,9 @@ the same basic algorithm, with the following differences:
5
5
 
6
6
  * Handles postfix conditionals when using escaping (e.g. <tt><%= foo if bar %></tt>)
7
7
  * Supports frozen_string_literal: true in templates via :freeze option
8
- * Works with ruby's --enable-frozen-string-literal option
8
+ * Works with ruby's <tt>--enable-frozen-string-literal</tt> option
9
9
  * Automatically freezes strings for template text when ruby optimizes it (on ruby 2.1+)
10
- * Escapes ' (apostrophe) when escaping for better XSS protection
10
+ * Escapes <tt>'</tt> (apostrophe) when escaping for better XSS protection
11
11
  * Has 6x faster escaping on ruby 2.3+ by using cgi/escape
12
12
  * Has 86% smaller memory footprint
13
13
  * Does no monkey patching (Erubis adds a method to Kernel)
@@ -92,7 +92,7 @@ instance variable. Example:
92
92
  # </form>
93
93
  # after
94
94
 
95
- Alternatively, passing the option +:yield_returns_buffer => true+ will return the
95
+ Alternatively, passing the option <tt>:yield_returns_buffer => true</tt> will return the
96
96
  buffer captured by the block instead of the last expression in the block.
97
97
 
98
98
  = Reporting Bugs
data/Rakefile CHANGED
@@ -60,9 +60,7 @@ end
60
60
 
61
61
  desc "Run specs with -w, some warnings filtered"
62
62
  task "spec_w" do
63
- ENV['RUBYOPT'] ? (ENV['RUBYOPT'] += " -w") : (ENV['RUBYOPT'] = '-w')
64
- rake = ENV['RAKE'] || "#{FileUtils::RUBY} -S rake"
65
- sh %{#{rake} 2>&1 | egrep -v \": warning: instance variable @.* not initialized|: warning: method redefined; discarding old|: warning: previous definition of|: warning: statement not reached"}
63
+ sh "#{FileUtils::RUBY} test/test_w.rb"
66
64
  end
67
65
 
68
66
  ### Other
@@ -1,34 +1,38 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Erubi
4
- VERSION = '1.9.0'
4
+ VERSION = '1.10.0'
5
5
  RANGE_ALL = 0..-1
6
6
 
7
+ # :nocov:
7
8
  if RUBY_VERSION >= '1.9'
8
9
  RANGE_FIRST = 0
9
10
  RANGE_LAST = -1
10
- TEXT_END = RUBY_VERSION >= '2.1' ? "'.freeze;" : "';"
11
11
  else
12
- # :nocov:
13
12
  RANGE_FIRST = 0..0
14
13
  RANGE_LAST = -1..-1
15
- TEXT_END = "';"
16
14
  end
17
15
 
16
+ TEXT_END = RUBY_VERSION >= '2.1' ? "'.freeze;" : "';"
17
+ MATCH_METHOD = RUBY_VERSION >= '2.4' ? :match? : :match
18
+ # :nocov:
19
+
18
20
  begin
19
21
  require 'cgi/escape'
22
+ # :nocov:
20
23
  unless CGI.respond_to?(:escapeHTML) # work around for JRuby 9.1
21
24
  CGI = Object.new
22
25
  CGI.extend(defined?(::CGI::Escape) ? ::CGI::Escape : ::CGI::Util)
23
26
  end
27
+ # :nocov:
28
+ # Escape characters with their HTML/XML equivalents.
24
29
  def self.h(value)
25
30
  CGI.escapeHTML(value.to_s)
26
31
  end
27
32
  rescue LoadError
33
+ # :nocov:
28
34
  ESCAPE_TABLE = {'&' => '&amp;'.freeze, '<' => '&lt;'.freeze, '>' => '&gt;'.freeze, '"' => '&quot;'.freeze, "'" => '&#39;'.freeze}.freeze
29
35
  if RUBY_VERSION >= '1.9'
30
- # Escape the following characters with their HTML/XML
31
- # equivalents.
32
36
  def self.h(value)
33
37
  value.to_s.gsub(/[&<>"']/, ESCAPE_TABLE)
34
38
  end
@@ -37,6 +41,7 @@ module Erubi
37
41
  value.to_s.gsub(/[&<>"']/){|s| ESCAPE_TABLE[s]}
38
42
  end
39
43
  end
44
+ # :nocov:
40
45
  end
41
46
 
42
47
  class Engine
@@ -50,20 +55,22 @@ module Erubi
50
55
  attr_reader :bufvar
51
56
 
52
57
  # Initialize a new Erubi::Engine. Options:
53
- # :bufval :: The value to use for the buffer variable, as a string.
54
- # :bufvar :: The variable name to use for the buffer variable, as a string (default '::String.new')
55
- # :ensure :: Wrap the template in a begin/ensure block restoring the previous value of bufvar.
56
- # :escapefunc :: The function to use for escaping, as a string (default: '::Erubi.h').
57
- # :escape :: Whether to make <%= escape by default, and <%== not escape by default.
58
- # :escape_html :: Same as :escape, with lower priority.
59
- # :filename :: The filename for the template.
60
- # :freeze :: Whether to enable frozen string literals in the resulting source code.
61
- # :outvar :: Same as bufvar, with lower priority.
62
- # :postamble :: The postamble for the template, by default returns the resulting source code.
63
- # :preamble :: The preamble for the template, by default initializes up the buffer variable.
64
- # :regexp :: The regexp to use for scanning.
65
- # :src :: The initial value to use for the source code
66
- # :trim :: Whether to trim leading and trailing whitespace, true by default.
58
+ # +:bufval+ :: The value to use for the buffer variable, as a string (default <tt>'::String.new'</tt>).
59
+ # +:bufvar+ :: The variable name to use for the buffer variable, as a string.
60
+ # +:ensure+ :: Wrap the template in a begin/ensure block restoring the previous value of bufvar.
61
+ # +:escapefunc+ :: The function to use for escaping, as a string (default: <tt>'::Erubi.h'</tt>).
62
+ # +:escape+ :: Whether to make <tt><%=</tt> escape by default, and <tt><%==</tt> not escape by default.
63
+ # +:escape_html+ :: Same as +:escape+, with lower priority.
64
+ # +:filename+ :: The filename for the template.
65
+ # +:freeze+ :: Whether to enable frozen string literals in the resulting source code.
66
+ # +:literal_prefix+ :: The prefix to output when using escaped tag delimiters (default <tt>'<%'</tt>).
67
+ # +:literal_postfix+ :: The postfix to output when using escaped tag delimiters (default <tt>'%>'</tt>).
68
+ # +:outvar+ :: Same as +:bufvar+, with lower priority.
69
+ # +:postamble+ :: The postamble for the template, by default returns the resulting source code.
70
+ # +:preamble+ :: The preamble for the template, by default initializes the buffer variable.
71
+ # +:regexp+ :: The regexp to use for scanning.
72
+ # +:src+ :: The initial value to use for the source code, an empty string by default.
73
+ # +:trim+ :: Whether to trim leading and trailing whitespace, true by default.
67
74
  def initialize(input, properties={})
68
75
  @escape = escape = properties.fetch(:escape){properties.fetch(:escape_html, false)}
69
76
  trim = properties[:trim] != false
@@ -71,6 +78,8 @@ module Erubi
71
78
  @bufvar = bufvar = properties[:bufvar] || properties[:outvar] || "_buf"
72
79
  bufval = properties[:bufval] || '::String.new'
73
80
  regexp = properties[:regexp] || /<%(={1,2}|-|\#|%)?(.*?)([-=])?%>([ \t]*\r?\n)?/m
81
+ literal_prefix = properties[:literal_prefix] || '<%'
82
+ literal_postfix = properties[:literal_postfix] || '%>'
74
83
  preamble = properties[:preamble] || "#{bufvar} = #{bufval};"
75
84
  postamble = properties[:postamble] || "#{bufvar}.to_s\n"
76
85
 
@@ -110,46 +119,45 @@ module Erubi
110
119
  if rindex
111
120
  range = rindex+1..-1
112
121
  s = text[range]
113
- if s =~ /\A[ \t]*\z/
122
+ if /\A[ \t]*\z/.send(MATCH_METHOD, s)
114
123
  lspace = s
115
124
  text[range] = ''
116
125
  end
117
126
  else
118
- if is_bol && text =~ /\A[ \t]*\z/
119
- lspace = text.dup
120
- text[RANGE_ALL] = ''
127
+ if is_bol && /\A[ \t]*\z/.send(MATCH_METHOD, text)
128
+ lspace = text
129
+ text = ''
121
130
  end
122
131
  end
123
132
  end
124
133
  end
125
134
 
126
135
  is_bol = rspace
127
- add_text(text) if text && !text.empty?
136
+ add_text(text)
128
137
  case ch
129
138
  when '='
130
139
  rspace = nil if tailch && !tailch.empty?
131
- add_text(lspace) if lspace
132
140
  add_expression(indicator, code)
133
141
  add_text(rspace) if rspace
134
- when '#'
135
- n = code.count("\n") + (rspace ? 1 : 0)
142
+ when nil, '-'
136
143
  if trim && lspace && rspace
137
- add_code("\n" * n)
144
+ add_code("#{lspace}#{code}#{rspace}")
138
145
  else
139
146
  add_text(lspace) if lspace
140
- add_code("\n" * n)
147
+ add_code(code)
141
148
  add_text(rspace) if rspace
142
149
  end
143
- when '%'
144
- add_text("#{lspace}#{prefix||='<%'}#{code}#{tailch}#{postfix||='%>'}#{rspace}")
145
- when nil, '-'
150
+ when '#'
151
+ n = code.count("\n") + (rspace ? 1 : 0)
146
152
  if trim && lspace && rspace
147
- add_code("#{lspace}#{code}#{rspace}")
153
+ add_code("\n" * n)
148
154
  else
149
155
  add_text(lspace) if lspace
150
- add_code(code)
156
+ add_code("\n" * n)
151
157
  add_text(rspace) if rspace
152
158
  end
159
+ when '%'
160
+ add_text("#{lspace}#{literal_prefix}#{code}#{tailch}#{literal_postfix}#{rspace}")
153
161
  else
154
162
  handle(indicator, code, tailch, rspace, lspace)
155
163
  end
@@ -159,16 +167,24 @@ module Erubi
159
167
 
160
168
  src << "\n" unless src[RANGE_LAST] == "\n"
161
169
  add_postamble(postamble)
162
- src << "; ensure\n #{bufvar} = __original_outvar\nend\n" if properties[:ensure]
170
+ src << "; ensure\n " << bufvar << " = __original_outvar\nend\n" if properties[:ensure]
163
171
  src.freeze
164
172
  freeze
165
173
  end
166
174
 
167
175
  private
168
176
 
169
- # Add raw text to the template
177
+ # Add raw text to the template. Modifies argument if argument is mutable as a memory optimization.
178
+ # Must be called with a string, cannot be called with nil (Rails's subclass depends on it).
170
179
  def add_text(text)
171
- @src << " #{@bufvar} << '" << text.gsub(/['\\]/, '\\\\\&') << TEXT_END unless text.empty?
180
+ return if text.empty?
181
+
182
+ if text.frozen?
183
+ text = text.gsub(/['\\]/, '\\\\\&')
184
+ else
185
+ text.gsub!(/['\\]/, '\\\\\&')
186
+ end
187
+ @src << " " << @bufvar << " << '" << text << TEXT_END
172
188
  end
173
189
 
174
190
  # Add ruby code to the template
@@ -189,12 +205,12 @@ module Erubi
189
205
 
190
206
  # Add the result of Ruby expression to the template
191
207
  def add_expression_result(code)
192
- @src << " #{@bufvar} << (" << code << ').to_s;'
208
+ @src << ' ' << @bufvar << ' << (' << code << ').to_s;'
193
209
  end
194
210
 
195
211
  # Add the escaped result of Ruby expression to the template
196
212
  def add_expression_result_escaped(code)
197
- @src << " #{@bufvar} << #{@escapefunc}((" << code << '));'
213
+ @src << ' ' << @bufvar << ' << ' << @escapefunc << '((' << code << '));'
198
214
  end
199
215
 
200
216
  # Add the given postamble to the src. Can be overridden in subclasses
@@ -3,15 +3,15 @@
3
3
  require 'erubi'
4
4
 
5
5
  module Erubi
6
- # An engine class that supports capturing blocks via the <%|= and <%|== tags,
7
- # explicitly ending the captures using <%| end %> blocks.
6
+ # An engine class that supports capturing blocks via the <tt><%|=</tt> and <tt><%|==</tt> tags,
7
+ # explicitly ending the captures using <tt><%|</tt> end <tt>%></tt> blocks.
8
8
  class CaptureEndEngine < Engine
9
9
  # Initializes the engine. Accepts the same arguments as ::Erubi::Engine, and these
10
10
  # additional options:
11
- # :escape_capture :: Whether to make <%|= escape by default, and <%|== not escape by default,
11
+ # :escape_capture :: Whether to make <tt><%|=</tt> escape by default, and <tt><%|==</tt> not escape by default,
12
12
  # defaults to the same value as :escape.
13
- # :yield_returns_buffer :: Whether to have <%| tags insert the buffer as an expression, so that
14
- # <%| end %> tags will have the buffer be the last expression inside
13
+ # :yield_returns_buffer :: Whether to have <tt><%|</tt> tags insert the buffer as an expression, so that
14
+ # <tt><%| end %></tt> tags will have the buffer be the last expression inside
15
15
  # the block, and therefore have the buffer be returned by the yield
16
16
  # expression. Normally the buffer will be returned anyway, but there
17
17
  # are cases where the last expression will not be the buffer,
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: erubi
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.0
4
+ version: 1.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Evans
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-09-25 00:00:00.000000000 Z
12
+ date: 2020-11-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: minitest
@@ -54,11 +54,13 @@ files:
54
54
  - Rakefile
55
55
  - lib/erubi.rb
56
56
  - lib/erubi/capture_end.rb
57
- - test/test.rb
58
57
  homepage: https://github.com/jeremyevans/erubi
59
58
  licenses:
60
59
  - MIT
61
- metadata: {}
60
+ metadata:
61
+ bug_tracker_uri: https://github.com/jeremyevans/erubi/issues
62
+ changelog_uri: https://github.com/jeremyevans/erubi/blob/master/CHANGELOG
63
+ source_code_uri: https://github.com/jeremyevans/erubi
62
64
  post_install_message:
63
65
  rdoc_options:
64
66
  - "--quiet"
@@ -81,7 +83,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
81
83
  - !ruby/object:Gem::Version
82
84
  version: '0'
83
85
  requirements: []
84
- rubygems_version: 3.0.3
86
+ rubygems_version: 3.1.4
85
87
  signing_key:
86
88
  specification_version: 4
87
89
  summary: Small ERB Implementation
@@ -1,780 +0,0 @@
1
- require 'rubygems'
2
-
3
- unless defined?(TESTDIR)
4
- TESTDIR = File.dirname(__FILE__)
5
- LIBDIR = TESTDIR == '.' ? '../lib' : File.dirname(TESTDIR) + '/lib'
6
- $: << TESTDIR
7
- $: << LIBDIR
8
- end
9
-
10
- if ENV['COVERAGE']
11
- require 'coverage'
12
- require 'simplecov'
13
-
14
- ENV.delete('COVERAGE')
15
- SimpleCov.instance_eval do
16
- start do
17
- add_filter "/test/"
18
- add_group('Missing'){|src| src.covered_percent < 100}
19
- add_group('Covered'){|src| src.covered_percent == 100}
20
- end
21
- end
22
- end
23
-
24
- require 'erubi'
25
- require 'erubi/capture_end'
26
-
27
- ENV['MT_NO_PLUGINS'] = '1' # Work around stupid autoloading of plugins
28
- gem 'minitest'
29
- require 'minitest/global_expectations/autorun'
30
-
31
- describe Erubi::Engine do
32
- before do
33
- @options = {}
34
- end
35
-
36
- def check_output(input, src, result, &block)
37
- t = (@options[:engine] || Erubi::Engine).new(input, @options)
38
- tsrc = t.src
39
- eval(tsrc, block.binding).must_equal result
40
- tsrc = tsrc.gsub("'.freeze;", "';") if RUBY_VERSION >= '2.1'
41
- tsrc.must_equal src
42
- end
43
-
44
- def setup_foo
45
- @foo = Object.new
46
- @foo.instance_variable_set(:@t, self)
47
- def self.a; @a; end
48
- def @foo.bar
49
- @t.a << "a"
50
- yield
51
- @t.a << 'b'
52
- @t.a.buffer.upcase!
53
- end
54
- end
55
-
56
- def setup_bar
57
- def self.bar
58
- @a << "a"
59
- yield
60
- @a << 'b'
61
- @a.upcase
62
- end
63
- def self.baz
64
- @a << "c"
65
- yield
66
- @a << 'd'
67
- @a * 2
68
- end
69
- def self.quux
70
- @a << "a"
71
- 3.times do |i|
72
- @a << "c#{i}"
73
- yield i
74
- @a << "d#{i}"
75
- end
76
- @a << "b"
77
- @a.upcase
78
- end
79
- end
80
-
81
- it "should handle no options" do
82
- list = ['&\'<>"2']
83
- check_output(<<END1, <<END2, <<END3){}
84
- <table>
85
- <tbody>
86
- <% i = 0
87
- list.each_with_index do |item, i| %>
88
- <tr>
89
- <td><%= i+1 %></td>
90
- <td><%== item %></td>
91
- </tr>
92
- <% end %>
93
- </tbody>
94
- </table>
95
- <%== i+1 %>
96
- END1
97
- _buf = ::String.new; _buf << '<table>
98
- <tbody>
99
- '; i = 0
100
- list.each_with_index do |item, i|
101
- _buf << ' <tr>
102
- <td>'; _buf << ( i+1 ).to_s; _buf << '</td>
103
- <td>'; _buf << ::Erubi.h(( item )); _buf << '</td>
104
- </tr>
105
- '; end
106
- _buf << ' </tbody>
107
- </table>
108
- '; _buf << ::Erubi.h(( i+1 )); _buf << '
109
- ';
110
- _buf.to_s
111
- END2
112
- <table>
113
- <tbody>
114
- <tr>
115
- <td>1</td>
116
- <td>&amp;&#39;&lt;&gt;&quot;2</td>
117
- </tr>
118
- </tbody>
119
- </table>
120
- 1
121
- END3
122
- end
123
-
124
- it "should strip only whitespace for <%, <%- and <%# tags" do
125
- check_output(<<END1, <<END2, <<END3){}
126
- <% 1 %>
127
- a
128
- <%- 2 %>
129
- b
130
- <%# 3 %>
131
- c
132
- /<% 1 %>
133
- a
134
- / <%- 2 %>
135
- b
136
- //<%# 3 %>
137
- c
138
- <% 1 %> /
139
- a
140
- <%- 2 %>/
141
- b
142
- <%# 3 %>//
143
- c
144
- END1
145
- _buf = ::String.new; 1
146
- _buf << 'a
147
- '; 2
148
- _buf << 'b
149
- ';
150
- _buf << 'c
151
- /'; 1 ; _buf << '
152
- '; _buf << 'a
153
- / '; 2 ; _buf << '
154
- '; _buf << 'b
155
- //';
156
- _buf << '
157
- '; _buf << 'c
158
- '; _buf << ' '; 1 ; _buf << ' /
159
- a
160
- '; _buf << ' '; 2 ; _buf << '/
161
- b
162
- '; _buf << ' ';; _buf << '//
163
- c
164
- ';
165
- _buf.to_s
166
- END2
167
- a
168
- b
169
- c
170
- /
171
- a
172
- /
173
- b
174
- //
175
- c
176
- /
177
- a
178
- /
179
- b
180
- //
181
- c
182
- END3
183
- end
184
-
185
- it "should handle ensure option" do
186
- list = ['&\'<>"2']
187
- @options[:ensure] = true
188
- @options[:bufvar] = '@a'
189
- @a = 'bar'
190
- check_output(<<END1, <<END2, <<END3){}
191
- <table>
192
- <tbody>
193
- <% i = 0
194
- list.each_with_index do |item, i| %>
195
- <tr>
196
- <td><%= i+1 %></td>
197
- <td><%== item %></td>
198
- </tr>
199
- <% end %>
200
- </tbody>
201
- </table>
202
- <%== i+1 %>
203
- END1
204
- begin; __original_outvar = @a if defined?(@a); @a = ::String.new; @a << '<table>
205
- <tbody>
206
- '; i = 0
207
- list.each_with_index do |item, i|
208
- @a << ' <tr>
209
- <td>'; @a << ( i+1 ).to_s; @a << '</td>
210
- <td>'; @a << ::Erubi.h(( item )); @a << '</td>
211
- </tr>
212
- '; end
213
- @a << ' </tbody>
214
- </table>
215
- '; @a << ::Erubi.h(( i+1 )); @a << '
216
- ';
217
- @a.to_s
218
- ; ensure
219
- @a = __original_outvar
220
- end
221
- END2
222
- <table>
223
- <tbody>
224
- <tr>
225
- <td>1</td>
226
- <td>&amp;&#39;&lt;&gt;&quot;2</td>
227
- </tr>
228
- </tbody>
229
- </table>
230
- 1
231
- END3
232
- @a.must_equal 'bar'
233
- end
234
-
235
- it "should have <%|= with CaptureEndEngine not escape by default" do
236
- eval(::Erubi::CaptureEndEngine.new('<%|= "&" %><%| %>').src).must_equal '&'
237
- eval(::Erubi::CaptureEndEngine.new('<%|= "&" %><%| %>', :escape=>false).src).must_equal '&'
238
- eval(::Erubi::CaptureEndEngine.new('<%|= "&" %><%| %>', :escape_capture=>false).src).must_equal '&'
239
- eval(::Erubi::CaptureEndEngine.new('<%|= "&" %><%| %>', :escape=>true).src).must_equal '&amp;'
240
- eval(::Erubi::CaptureEndEngine.new('<%|= "&" %><%| %>', :escape_capture=>true).src).must_equal '&amp;'
241
- end
242
-
243
- it "should have <%|== with CaptureEndEngine escape by default" do
244
- eval(::Erubi::CaptureEndEngine.new('<%|== "&" %><%| %>').src).must_equal '&amp;'
245
- eval(::Erubi::CaptureEndEngine.new('<%|== "&" %><%| %>', :escape=>true).src).must_equal '&'
246
- eval(::Erubi::CaptureEndEngine.new('<%|== "&" %><%| %>', :escape_capture=>true).src).must_equal '&'
247
- eval(::Erubi::CaptureEndEngine.new('<%|== "&" %><%| %>', :escape=>false).src).must_equal '&amp;'
248
- eval(::Erubi::CaptureEndEngine.new('<%|== "&" %><%| %>', :escape_capture=>false).src).must_equal '&amp;'
249
- end
250
-
251
- [['', false], ['=', true]].each do |ind, escape|
252
- it "should allow <%|=#{ind} and <%| for capturing with CaptureEndEngine with :escape_capture => #{escape} and :escape => #{!escape}" do
253
- @options[:bufvar] = '@a'
254
- @options[:capture] = true
255
- @options[:escape_capture] = escape
256
- @options[:escape] = !escape
257
- @options[:engine] = ::Erubi::CaptureEndEngine
258
- setup_bar
259
- check_output(<<END1, <<END2, <<END3){}
260
- <table>
261
- <tbody>
262
- <%|=#{ind} bar do %>
263
- <b><%=#{ind} '&' %></b>
264
- <%| end %>
265
- </tbody>
266
- </table>
267
- END1
268
- #{'__erubi = ::Erubi;' unless escape}@a = ::String.new; @a << '<table>
269
- <tbody>
270
- '; @a << ' ';begin; (__erubi_stack ||= []) << @a; @a = ::String.new; __erubi_stack.last << (( bar do @a << '
271
- '; @a << ' <b>'; @a << #{!escape ? '__erubi' : '::Erubi'}.h(( '&' )); @a << '</b>
272
- '; @a << ' '; end )).to_s; ensure; @a = __erubi_stack.pop; end; @a << '
273
- '; @a << ' </tbody>
274
- </table>
275
- ';
276
- @a.to_s
277
- END2
278
- <table>
279
- <tbody>
280
- A
281
- <B>&AMP;</B>
282
- B
283
- </tbody>
284
- </table>
285
- END3
286
- end
287
- end
288
-
289
- [['', true], ['=', false]].each do |ind, escape|
290
- it "should allow <%|=#{ind} and <%| for capturing with CaptureEndEngine when with :escape => #{escape}" do
291
- @options[:bufvar] = '@a'
292
- @options[:escape] = escape
293
- @options[:engine] = ::Erubi::CaptureEndEngine
294
- setup_bar
295
- check_output(<<END1, <<END2, <<END3){}
296
- <table>
297
- <tbody>
298
- <%|=#{ind} bar do %>
299
- <b><%=#{ind} '&' %></b>
300
- <%| end %>
301
- </tbody>
302
- </table>
303
- END1
304
- #{'__erubi = ::Erubi;' if escape}@a = ::String.new; @a << '<table>
305
- <tbody>
306
- '; @a << ' ';begin; (__erubi_stack ||= []) << @a; @a = ::String.new; __erubi_stack.last << #{escape ? '__erubi' : '::Erubi'}.h(( bar do @a << '
307
- '; @a << ' <b>'; @a << #{escape ? '__erubi' : '::Erubi'}.h(( '&' )); @a << '</b>
308
- '; @a << ' '; end )).to_s; ensure; @a = __erubi_stack.pop; end; @a << '
309
- '; @a << ' </tbody>
310
- </table>
311
- ';
312
- @a.to_s
313
- END2
314
- <table>
315
- <tbody>
316
- A
317
- &lt;B&gt;&amp;AMP;&lt;/B&gt;
318
- B
319
- </tbody>
320
- </table>
321
- END3
322
- end
323
-
324
- it "should handle loops in <%|=#{ind} and <%| for capturing with CaptureEndEngine when with :escape => #{escape}" do
325
- @options[:bufvar] = '@a'
326
- @options[:escape] = escape
327
- @options[:engine] = ::Erubi::CaptureEndEngine
328
- setup_bar
329
- check_output(<<END1, <<END2, <<END3){}
330
- <table>
331
- <tbody>
332
- <%|=#{ind} quux do |i| %>
333
- <b><%=#{ind} "\#{i}&" %></b>
334
- <%| end %>
335
- </tbody>
336
- </table>
337
- END1
338
- #{'__erubi = ::Erubi;' if escape}@a = ::String.new; @a << '<table>
339
- <tbody>
340
- '; @a << ' ';begin; (__erubi_stack ||= []) << @a; @a = ::String.new; __erubi_stack.last << #{escape ? '__erubi' : '::Erubi'}.h(( quux do |i| @a << '
341
- '; @a << ' <b>'; @a << #{escape ? '__erubi' : '::Erubi'}.h(( "\#{i}&" )); @a << '</b>
342
- '; @a << ' '; end )).to_s; ensure; @a = __erubi_stack.pop; end; @a << '
343
- '; @a << ' </tbody>
344
- </table>
345
- ';
346
- @a.to_s
347
- END2
348
- <table>
349
- <tbody>
350
- AC0
351
- &lt;B&gt;0&amp;AMP;&lt;/B&gt;
352
- D0C1
353
- &lt;B&gt;1&amp;AMP;&lt;/B&gt;
354
- D1C2
355
- &lt;B&gt;2&amp;AMP;&lt;/B&gt;
356
- D2B
357
- </tbody>
358
- </table>
359
- END3
360
- end
361
-
362
- it "should allow <%|=#{ind} and <%| for nested capturing with CaptureEndEngine when with :escape => #{escape}" do
363
- @options[:bufvar] = '@a'
364
- @options[:escape] = escape
365
- @options[:engine] = ::Erubi::CaptureEndEngine
366
- setup_bar
367
- check_output(<<END1, <<END2, <<END3){}
368
- <table>
369
- <tbody>
370
- <%|=#{ind} bar do %>
371
- <b><%=#{ind} '&' %></b>
372
- <%|=#{ind} baz do %>e<%| end %>
373
- <%| end %>
374
- </tbody>
375
- </table>
376
- END1
377
- #{'__erubi = ::Erubi;' if escape}@a = ::String.new; @a << '<table>
378
- <tbody>
379
- '; @a << ' ';begin; (__erubi_stack ||= []) << @a; @a = ::String.new; __erubi_stack.last << #{escape ? '__erubi' : '::Erubi'}.h(( bar do @a << '
380
- '; @a << ' <b>'; @a << #{escape ? '__erubi' : '::Erubi'}.h(( '&' )); @a << '</b>
381
- '; @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 << '
382
- '; @a << ' '; end )).to_s; ensure; @a = __erubi_stack.pop; end; @a << '
383
- '; @a << ' </tbody>
384
- </table>
385
- ';
386
- @a.to_s
387
- END2
388
- <table>
389
- <tbody>
390
- A
391
- &lt;B&gt;&amp;AMP;&lt;/B&gt;
392
- CEDCED
393
- B
394
- </tbody>
395
- </table>
396
- END3
397
- end
398
- end
399
-
400
- [:outvar, :bufvar].each do |var|
401
- it "should handle :#{var} and :freeze options" do
402
- @options[var] = "@_out_buf"
403
- @options[:freeze] = true
404
- @items = [2]
405
- i = 0
406
- check_output(<<END1, <<END2, <<END3){}
407
- <table>
408
- <% for item in @items %>
409
- <tr>
410
- <td><%= i+1 %></td>
411
- <td><%== item %></td>
412
- </tr>
413
- <% end %>
414
- </table>
415
- END1
416
- # frozen_string_literal: true
417
- @_out_buf = ::String.new; @_out_buf << '<table>
418
- '; for item in @items
419
- @_out_buf << ' <tr>
420
- <td>'; @_out_buf << ( i+1 ).to_s; @_out_buf << '</td>
421
- <td>'; @_out_buf << ::Erubi.h(( item )); @_out_buf << '</td>
422
- </tr>
423
- '; end
424
- @_out_buf << '</table>
425
- ';
426
- @_out_buf.to_s
427
- END2
428
- <table>
429
- <tr>
430
- <td>1</td>
431
- <td>2</td>
432
- </tr>
433
- </table>
434
- END3
435
- end
436
- end
437
-
438
- it "should handle <%% and <%# syntax" do
439
- @items = [2]
440
- i = 0
441
- check_output(<<END1, <<END2, <<END3){}
442
- <table>
443
- <%% for item in @items %>
444
- <tr>
445
- <td><%# i+1 %></td>
446
- <td><%# item %></td>
447
- </tr>
448
- <%% end %>
449
- </table>
450
- END1
451
- _buf = ::String.new; _buf << '<table>
452
- '; _buf << '<% for item in @items %>
453
- '; _buf << ' <tr>
454
- <td>';; _buf << '</td>
455
- <td>';; _buf << '</td>
456
- </tr>
457
- '; _buf << ' <% end %>
458
- '; _buf << '</table>
459
- ';
460
- _buf.to_s
461
- END2
462
- <table>
463
- <% for item in @items %>
464
- <tr>
465
- <td></td>
466
- <td></td>
467
- </tr>
468
- <% end %>
469
- </table>
470
- END3
471
- end
472
-
473
- it "should handle :trim => false option" do
474
- @options[:trim] = false
475
- @items = [2]
476
- i = 0
477
- check_output(<<END1, <<END2, <<END3){}
478
- <table>
479
- <% for item in @items %>
480
- <tr>
481
- <td><%#
482
- i+1
483
- %></td>
484
- <td><%== item %></td>
485
- </tr>
486
- <% end %><%#%>
487
- <% i %>a
488
- <% i %>
489
- </table>
490
- END1
491
- _buf = ::String.new; _buf << '<table>
492
- '; _buf << ' '; for item in @items ; _buf << '
493
- '; _buf << ' <tr>
494
- <td>';
495
-
496
- _buf << '</td>
497
- <td>'; _buf << ::Erubi.h(( item )); _buf << '</td>
498
- </tr>
499
- '; _buf << ' '; end ;
500
- _buf << '
501
- '; _buf << ' '; i ; _buf << 'a
502
- '; _buf << ' '; i ; _buf << '
503
- '; _buf << '</table>
504
- ';
505
- _buf.to_s
506
- END2
507
- <table>
508
-
509
- <tr>
510
- <td></td>
511
- <td>2</td>
512
- </tr>
513
-
514
- a
515
-
516
- </table>
517
- END3
518
- end
519
-
520
- [:escape, :escape_html].each do |opt|
521
- it "should handle :#{opt} and :escapefunc options" do
522
- @options[opt] = true
523
- @options[:escapefunc] = 'h.call'
524
- h = proc{|s| s.to_s*2}
525
- list = ['2']
526
- check_output(<<END1, <<END2, <<END3){}
527
- <table>
528
- <tbody>
529
- <% i = 0
530
- list.each_with_index do |item, i| %>
531
- <tr>
532
- <td><%= i+1 %></td>
533
- <td><%== item %></td>
534
- </tr>
535
- <% end %>
536
- </tbody>
537
- </table>
538
- <%== i+1 %>
539
- END1
540
- _buf = ::String.new; _buf << '<table>
541
- <tbody>
542
- '; i = 0
543
- list.each_with_index do |item, i|
544
- _buf << ' <tr>
545
- <td>'; _buf << h.call(( i+1 )); _buf << '</td>
546
- <td>'; _buf << ( item ).to_s; _buf << '</td>
547
- </tr>
548
- '; end
549
- _buf << ' </tbody>
550
- </table>
551
- '; _buf << ( i+1 ).to_s; _buf << '
552
- ';
553
- _buf.to_s
554
- END2
555
- <table>
556
- <tbody>
557
- <tr>
558
- <td>11</td>
559
- <td>2</td>
560
- </tr>
561
- </tbody>
562
- </table>
563
- 1
564
- END3
565
- end
566
- end
567
-
568
- it "should handle :escape option without :escapefunc option" do
569
- @options[:escape] = true
570
- list = ['&\'<>"2']
571
- check_output(<<END1, <<END2, <<END3){}
572
- <table>
573
- <tbody>
574
- <% i = 0
575
- list.each_with_index do |item, i| %>
576
- <tr>
577
- <td><%== i+1 %></td>
578
- <td><%= item %></td>
579
- </tr>
580
- <% end %>
581
- </tbody>
582
- </table>
583
- END1
584
- __erubi = ::Erubi;_buf = ::String.new; _buf << '<table>
585
- <tbody>
586
- '; i = 0
587
- list.each_with_index do |item, i|
588
- _buf << ' <tr>
589
- <td>'; _buf << ( i+1 ).to_s; _buf << '</td>
590
- <td>'; _buf << __erubi.h(( item )); _buf << '</td>
591
- </tr>
592
- '; end
593
- _buf << ' </tbody>
594
- </table>
595
- ';
596
- _buf.to_s
597
- END2
598
- <table>
599
- <tbody>
600
- <tr>
601
- <td>1</td>
602
- <td>&amp;&#39;&lt;&gt;&quot;2</td>
603
- </tr>
604
- </tbody>
605
- </table>
606
- END3
607
- end
608
-
609
- it "should handle :preamble and :postamble options" do
610
- @options[:preamble] = '_buf = String.new("1");'
611
- @options[:postamble] = "_buf[0...18]\n"
612
- list = ['2']
613
- check_output(<<END1, <<END2, <<END3){}
614
- <table>
615
- <tbody>
616
- <% i = 0
617
- list.each_with_index do |item, i| %>
618
- <tr>
619
- <td><%= i+1 %></td>
620
- <td><%== item %></td>
621
- </tr>
622
- <% end %>
623
- </tbody>
624
- </table>
625
- <%== i+1 %>
626
- END1
627
- _buf = String.new("1"); _buf << '<table>
628
- <tbody>
629
- '; i = 0
630
- list.each_with_index do |item, i|
631
- _buf << ' <tr>
632
- <td>'; _buf << ( i+1 ).to_s; _buf << '</td>
633
- <td>'; _buf << ::Erubi.h(( item )); _buf << '</td>
634
- </tr>
635
- '; end
636
- _buf << ' </tbody>
637
- </table>
638
- '; _buf << ::Erubi.h(( i+1 )); _buf << '
639
- ';
640
- _buf[0...18]
641
- END2
642
- 1<table>
643
- <tbody>
644
- END3
645
- end
646
-
647
- it "should have working filename accessor" do
648
- Erubi::Engine.new('', :filename=>'foo.rb').filename.must_equal 'foo.rb'
649
- end
650
-
651
- it "should have working bufvar accessor" do
652
- Erubi::Engine.new('', :bufvar=>'foo').bufvar.must_equal 'foo'
653
- Erubi::Engine.new('', :outvar=>'foo').bufvar.must_equal 'foo'
654
- end
655
-
656
- it "should work with BasicObject methods" do
657
- c = Class.new(BasicObject)
658
- c.class_eval("def a; #{Erubi::Engine.new('2').src} end")
659
- c.new.a.must_equal '2'
660
- end if defined?(BasicObject)
661
-
662
- it "should return frozen object" do
663
- Erubi::Engine.new('').frozen?.must_equal true
664
- end
665
-
666
- it "should have frozen src" do
667
- Erubi::Engine.new('').src.frozen?.must_equal true
668
- end
669
-
670
- it "should raise an error if a tag is not handled when a custom regexp is used" do
671
- proc{Erubi::Engine.new('<%] %>', :regexp =>/<%(={1,2}|\]|-|\#|%)?(.*?)([-=])?%>([ \t]*\r?\n)?/m)}.must_raise ArgumentError
672
- proc{Erubi::CaptureEndEngine.new('<%] %>', :regexp =>/<%(={1,2}|\]|-|\#|%)?(.*?)([-=])?%>([ \t]*\r?\n)?/m)}.must_raise ArgumentError
673
- end
674
-
675
- it "should respect the :yield_returns_buffer option for making templates return the (potentially modified) buffer" do
676
- @options[:engine] = ::Erubi::CaptureEndEngine
677
- @options[:bufvar] = '@a'
678
-
679
- def self.bar
680
- a = String.new
681
- a << "a"
682
- yield 'burgers'
683
- case b = (yield 'salads')
684
- when String
685
- a << b
686
- a << 'b'
687
- a.upcase
688
- end
689
- end
690
-
691
- check_output(<<END1, <<END2, <<END3){}
692
- <%|= bar do |item| %>
693
- Let's eat <%= item %>!
694
- <% nil %><%| end %>
695
- END1
696
- @a = ::String.new;begin; (__erubi_stack ||= []) << @a; @a = ::String.new; __erubi_stack.last << (( bar do |item| @a << '
697
- '; @a << 'Let\\'s eat '; @a << ( item ).to_s; @a << '!
698
- '; nil ; end )).to_s; ensure; @a = __erubi_stack.pop; end; @a << '
699
- ';
700
- @a.to_s
701
- END2
702
-
703
- END3
704
-
705
- @options[:yield_returns_buffer] = true
706
-
707
- check_output(<<END1, <<END2, <<END3) {}
708
- <%|= bar do |item| %>
709
- Let's eat <%= item %>!
710
- <% nil %><%| end %>
711
- END1
712
- @a = ::String.new;begin; (__erubi_stack ||= []) << @a; @a = ::String.new; __erubi_stack.last << (( bar do |item| @a << '
713
- '; @a << 'Let\\'s eat '; @a << ( item ).to_s; @a << '!
714
- '; nil ; @a; end )).to_s; ensure; @a = __erubi_stack.pop; end; @a << '
715
- ';
716
- @a.to_s
717
- END2
718
- A
719
- LET'S EAT BURGERS!
720
-
721
- LET'S EAT SALADS!
722
- B
723
- END3
724
- end
725
-
726
- it "should respect the :yield_returns_buffer option for making templates return the (potentially modified) buffer as the result of the block" do
727
- @options[:engine] = ::Erubi::CaptureEndEngine
728
- @options[:yield_returns_buffer] = true
729
-
730
- def self.bar(foo = nil)
731
- if foo.nil?
732
- yield
733
- else
734
- foo
735
- end
736
- end
737
-
738
- check_output(<<END1, <<END2, <<END3) {}
739
- <%|= bar do %>
740
- Let's eat the tacos!
741
- <%| end %>
742
-
743
- Delicious!
744
- END1
745
- _buf = ::String.new;begin; (__erubi_stack ||= []) << _buf; _buf = ::String.new; __erubi_stack.last << (( bar do _buf << '
746
- '; _buf << 'Let\\'s eat the tacos!
747
- '; _buf; end )).to_s; ensure; _buf = __erubi_stack.pop; end; _buf << '
748
- '; _buf << '
749
- Delicious!
750
- ';
751
- _buf.to_s
752
- END2
753
-
754
- Let's eat the tacos!
755
-
756
-
757
- Delicious!
758
- END3
759
-
760
- check_output(<<END1, <<END2, <<END3) {}
761
- <%|= bar("Don't eat the burgers!") do %>
762
- Let's eat burgers!
763
- <%| end %>
764
-
765
- Delicious!
766
- END1
767
- _buf = ::String.new;begin; (__erubi_stack ||= []) << _buf; _buf = ::String.new; __erubi_stack.last << (( bar(\"Don't eat the burgers!\") do _buf << '
768
- '; _buf << 'Let\\'s eat burgers!
769
- '; _buf; end )).to_s; ensure; _buf = __erubi_stack.pop; end; _buf << '
770
- '; _buf << '
771
- Delicious!
772
- ';
773
- _buf.to_s
774
- END2
775
- Don't eat the burgers!
776
-
777
- Delicious!
778
- END3
779
- end
780
- end