erubi 1.9.0 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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