erubi 1.10.0 → 1.12.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: 3f504eb8d1ae0f89e098de29336a69d0251cd8659a1b6fe1ab86c7f23ed44d67
4
- data.tar.gz: e54396a6eb2cf0c193089c9b2c3d5fa0f92daf5cf4f462fe09d0aea6dca49419
3
+ metadata.gz: b0cae36e4fa5e180f0934c68f04a936a6f51df57e8ef1a4436a907ab408a85a7
4
+ data.tar.gz: ceaeb0da7540a786c6e65cf8bb1c72ad60bf7309f0a9f0cdf460c32236d80a2c
5
5
  SHA512:
6
- metadata.gz: 0a789b8a528548760ac4898867588477e03c3f1410bd930538c849e167c68a346202f8c168a2a71107485c961bb41a91d549f687a4d24ebf3614821bc15b4e73
7
- data.tar.gz: 14e74f5fb8c452c0cbc15afbe51b8a86be572d8d585416f09f07d9227e06ad8d8c14d8681424dc53f9b7eaba1a1297ed72e8e7dc0c36afe6e2da1926bec742d0
6
+ metadata.gz: 3c2a45e5cbd23b6f85257fcb7139e92cd116b0854fb5386b73331b05314aa0020725ac1bd918e4156e253df1cf7f5f58e6db86874f3180dabc5d8e38d1d910d3
7
+ data.tar.gz: 54a5c8d8d72bfcc8344f9f4224d36070d90d61817deaa601f25dfee24edc4b6f408f5a00b09891075959a1a41d6fa67046594c5e5e3b65707e24f737777de716
data/CHANGELOG CHANGED
@@ -1,3 +1,17 @@
1
+ === 1.12.0 (2022-12-22)
2
+
3
+ * Use erb/escape for faster html escaping if available (jeremyevans)
4
+
5
+ * Default :freeze_template_literals option to false if running with --enable-frozen-string-literal (casperisfine) (#35)
6
+
7
+ === 1.11.0 (2022-08-02)
8
+
9
+ * Support :freeze_template_literals option for configuring whether to add .freeze to template literal strings (casperisfine) (#33)
10
+
11
+ * Support :chain_appends option for chaining appends to the buffer variable (casperisfine, jeremyevans) (#32)
12
+
13
+ * Avoid unnecessary defined? usage on Ruby 3+ when using the :ensure option (jeremyevans)
14
+
1
15
  === 1.10.0 (2020-11-13)
2
16
 
3
17
  * Improve template parsing, mostly by reducing allocations (jeremyevans)
data/MIT-LICENSE CHANGED
@@ -1,5 +1,5 @@
1
1
  copyright(c) 2006-2011 kuwata-lab.com all rights reserved.
2
- copyright(c) 2016-2020 Jeremy Evans
2
+ copyright(c) 2016-2021 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
data/README.rdoc CHANGED
@@ -9,7 +9,7 @@ the same basic algorithm, with the following differences:
9
9
  * Automatically freezes strings for template text when ruby optimizes it (on ruby 2.1+)
10
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
- * Has 86% smaller memory footprint
12
+ * Has 81% smaller memory footprint (calculated using +ObjectSpace.memsize_of_all+)
13
13
  * Does no monkey patching (Erubis adds a method to Kernel)
14
14
  * Uses an immutable design (all options passed to the constructor, which returns a frozen object)
15
15
  * Has simpler internals (1 file, <150 lines of code)
data/Rakefile CHANGED
@@ -42,7 +42,7 @@ end
42
42
 
43
43
  spec = proc do |env|
44
44
  env.each{|k,v| ENV[k] = v}
45
- sh "#{FileUtils::RUBY} test/test.rb"
45
+ sh "#{FileUtils::RUBY} #{'-w' if RUBY_VERSION >= '3'} test/test.rb"
46
46
  env.each{|k,v| ENV.delete(k)}
47
47
  end
48
48
 
@@ -57,11 +57,6 @@ desc "Run specs with coverage"
57
57
  task "spec_cov" do
58
58
  spec.call('COVERAGE'=>'1')
59
59
  end
60
-
61
- desc "Run specs with -w, some warnings filtered"
62
- task "spec_w" do
63
- sh "#{FileUtils::RUBY} test/test_w.rb"
64
- end
65
60
 
66
61
  ### Other
67
62
 
@@ -36,13 +36,19 @@ module Erubi
36
36
  rspace = nil if tailch && !tailch.empty?
37
37
  add_text(lspace) if lspace
38
38
  escape_capture = !((indicator == '|=') ^ @escape_capture)
39
- src << "begin; (#{@bufstack} ||= []) << #{@bufvar}; #{@bufvar} = #{@bufval}; #{@bufstack}.last << #{@escapefunc if escape_capture}((" << code
39
+ terminate_expression
40
+ @src << "begin; (#{@bufstack} ||= []) << #{@bufvar}; #{@bufvar} = #{@bufval}; #{@bufstack}.last << #{@escapefunc if escape_capture}((" << code
41
+ @buffer_on_stack = false
40
42
  add_text(rspace) if rspace
41
43
  when '|'
42
44
  rspace = nil if tailch && !tailch.empty?
43
45
  add_text(lspace) if lspace
44
- result = @yield_returns_buffer ? " #{@bufvar}; " : ""
45
- src << result << code << ")).to_s; ensure; #{@bufvar} = #{@bufstack}.pop; end;"
46
+ if @yield_returns_buffer
47
+ terminate_expression
48
+ @src << " #{@bufvar}; "
49
+ end
50
+ @src << code << ")).to_s; ensure; #{@bufvar} = #{@bufstack}.pop; end;"
51
+ @buffer_on_stack = false
46
52
  add_text(rspace) if rspace
47
53
  else
48
54
  super
data/lib/erubi.rb CHANGED
@@ -1,8 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Erubi
4
- VERSION = '1.10.0'
5
- RANGE_ALL = 0..-1
4
+ VERSION = '1.12.0'
6
5
 
7
6
  # :nocov:
8
7
  if RUBY_VERSION >= '1.9'
@@ -13,38 +12,49 @@ module Erubi
13
12
  RANGE_LAST = -1..-1
14
13
  end
15
14
 
16
- TEXT_END = RUBY_VERSION >= '2.1' ? "'.freeze;" : "';"
17
15
  MATCH_METHOD = RUBY_VERSION >= '2.4' ? :match? : :match
16
+ SKIP_DEFINED_FOR_INSTANCE_VARIABLE = RUBY_VERSION > '3'
17
+ FREEZE_TEMPLATE_LITERALS = !eval("''").frozen? && RUBY_VERSION >= '2.1'
18
18
  # :nocov:
19
19
 
20
20
  begin
21
- require 'cgi/escape'
21
+ require 'erb/escape'
22
22
  # :nocov:
23
- unless CGI.respond_to?(:escapeHTML) # work around for JRuby 9.1
24
- CGI = Object.new
25
- CGI.extend(defined?(::CGI::Escape) ? ::CGI::Escape : ::CGI::Util)
26
- end
23
+ define_singleton_method(:h, ERB::Escape.instance_method(:html_escape))
27
24
  # :nocov:
28
- # Escape characters with their HTML/XML equivalents.
29
- def self.h(value)
30
- CGI.escapeHTML(value.to_s)
31
- end
32
25
  rescue LoadError
33
- # :nocov:
34
- ESCAPE_TABLE = {'&' => '&amp;'.freeze, '<' => '&lt;'.freeze, '>' => '&gt;'.freeze, '"' => '&quot;'.freeze, "'" => '&#39;'.freeze}.freeze
35
- if RUBY_VERSION >= '1.9'
36
- def self.h(value)
37
- value.to_s.gsub(/[&<>"']/, ESCAPE_TABLE)
26
+ begin
27
+ require 'cgi/escape'
28
+ # :nocov:
29
+ unless CGI.respond_to?(:escapeHTML) # work around for JRuby 9.1
30
+ CGI = Object.new
31
+ CGI.extend(defined?(::CGI::Escape) ? ::CGI::Escape : ::CGI::Util)
38
32
  end
39
- else
33
+ # :nocov:
34
+ # Escape characters with their HTML/XML equivalents.
40
35
  def self.h(value)
41
- value.to_s.gsub(/[&<>"']/){|s| ESCAPE_TABLE[s]}
36
+ CGI.escapeHTML(value.to_s)
42
37
  end
38
+ rescue LoadError
39
+ # :nocov:
40
+ ESCAPE_TABLE = {'&' => '&amp;'.freeze, '<' => '&lt;'.freeze, '>' => '&gt;'.freeze, '"' => '&quot;'.freeze, "'" => '&#39;'.freeze}.freeze
41
+ if RUBY_VERSION >= '1.9'
42
+ def self.h(value)
43
+ value.to_s.gsub(/[&<>"']/, ESCAPE_TABLE)
44
+ end
45
+ else
46
+ def self.h(value)
47
+ value.to_s.gsub(/[&<>"']/){|s| ESCAPE_TABLE[s]}
48
+ end
49
+ end
50
+ # :nocov:
43
51
  end
44
- # :nocov:
45
52
  end
46
53
 
47
54
  class Engine
55
+ # The default regular expression used for scanning.
56
+ DEFAULT_REGEXP = /<%(={1,2}|-|\#|%)?(.*?)([-=])?%>([ \t]*\r?\n)?/m
57
+
48
58
  # The frozen ruby source code generated from the template, which can be evaled.
49
59
  attr_reader :src
50
60
 
@@ -57,12 +67,22 @@ module Erubi
57
67
  # Initialize a new Erubi::Engine. Options:
58
68
  # +:bufval+ :: The value to use for the buffer variable, as a string (default <tt>'::String.new'</tt>).
59
69
  # +:bufvar+ :: The variable name to use for the buffer variable, as a string.
70
+ # +:chain_appends+ :: Whether to chain <tt><<</t> calls to the buffer variable. Offers better
71
+ # performance, but can cause issues when the buffer variable is reassigned during
72
+ # template rendering (default +false+).
60
73
  # +:ensure+ :: Wrap the template in a begin/ensure block restoring the previous value of bufvar.
61
74
  # +:escapefunc+ :: The function to use for escaping, as a string (default: <tt>'::Erubi.h'</tt>).
62
75
  # +:escape+ :: Whether to make <tt><%=</tt> escape by default, and <tt><%==</tt> not escape by default.
63
76
  # +:escape_html+ :: Same as +:escape+, with lower priority.
64
77
  # +:filename+ :: The filename for the template.
65
- # +:freeze+ :: Whether to enable frozen string literals in the resulting source code.
78
+ # +:freeze+ :: Whether to enable add a <tt>frozen_string_literal: true</tt> magic comment at the top of
79
+ # the resulting source code. Note this may cause problems if you are wrapping the resulting
80
+ # source code in other code, because the magic comment only has an effect at the beginning of
81
+ # the file, and having the magic comment later in the file can trigger warnings.
82
+ # +:freeze_template_literals+ :: Whether to suffix all literal strings for template code with <tt>.freeze</tt>
83
+ # (default: +true+ on Ruby 2.1+, +false+ on Ruby 2.0 and older).
84
+ # Can be set to +false+ on Ruby 2.3+ when frozen string literals are enabled
85
+ # in order to improve performance.
66
86
  # +:literal_prefix+ :: The prefix to output when using escaped tag delimiters (default <tt>'<%'</tt>).
67
87
  # +:literal_postfix+ :: The postfix to output when using escaped tag delimiters (default <tt>'%>'</tt>).
68
88
  # +:outvar+ :: Same as +:bufvar+, with lower priority.
@@ -77,20 +97,34 @@ module Erubi
77
97
  @filename = properties[:filename]
78
98
  @bufvar = bufvar = properties[:bufvar] || properties[:outvar] || "_buf"
79
99
  bufval = properties[:bufval] || '::String.new'
80
- regexp = properties[:regexp] || /<%(={1,2}|-|\#|%)?(.*?)([-=])?%>([ \t]*\r?\n)?/m
100
+ regexp = properties[:regexp] || DEFAULT_REGEXP
81
101
  literal_prefix = properties[:literal_prefix] || '<%'
82
102
  literal_postfix = properties[:literal_postfix] || '%>'
83
103
  preamble = properties[:preamble] || "#{bufvar} = #{bufval};"
84
104
  postamble = properties[:postamble] || "#{bufvar}.to_s\n"
105
+ @chain_appends = properties[:chain_appends]
106
+ @text_end = if properties.fetch(:freeze_template_literals, FREEZE_TEMPLATE_LITERALS)
107
+ "'.freeze"
108
+ else
109
+ "'"
110
+ end
85
111
 
112
+ @buffer_on_stack = false
86
113
  @src = src = properties[:src] || String.new
87
114
  src << "# frozen_string_literal: true\n" if properties[:freeze]
88
- src << "begin; __original_outvar = #{bufvar} if defined?(#{bufvar}); " if properties[:ensure]
115
+ if properties[:ensure]
116
+ src << "begin; __original_outvar = #{bufvar}"
117
+ if SKIP_DEFINED_FOR_INSTANCE_VARIABLE && /\A@[^@]/ =~ bufvar
118
+ src << "; "
119
+ else
120
+ src << " if defined?(#{bufvar}); "
121
+ end
122
+ end
89
123
 
90
124
  unless @escapefunc = properties[:escapefunc]
91
125
  if escape
92
126
  @escapefunc = '__erubi.h'
93
- src << "__erubi = ::Erubi;"
127
+ src << "__erubi = ::Erubi; "
94
128
  else
95
129
  @escapefunc = '::Erubi.h'
96
130
  end
@@ -184,13 +218,16 @@ module Erubi
184
218
  else
185
219
  text.gsub!(/['\\]/, '\\\\\&')
186
220
  end
187
- @src << " " << @bufvar << " << '" << text << TEXT_END
221
+
222
+ with_buffer{@src << " << '" << text << @text_end}
188
223
  end
189
224
 
190
225
  # Add ruby code to the template
191
226
  def add_code(code)
227
+ terminate_expression
192
228
  @src << code
193
229
  @src << ';' unless code[RANGE_LAST] == "\n"
230
+ @buffer_on_stack = false
194
231
  end
195
232
 
196
233
  # Add the given ruby expression result to the template,
@@ -205,23 +242,52 @@ module Erubi
205
242
 
206
243
  # Add the result of Ruby expression to the template
207
244
  def add_expression_result(code)
208
- @src << ' ' << @bufvar << ' << (' << code << ').to_s;'
245
+ with_buffer{@src << ' << (' << code << ').to_s'}
209
246
  end
210
247
 
211
248
  # Add the escaped result of Ruby expression to the template
212
249
  def add_expression_result_escaped(code)
213
- @src << ' ' << @bufvar << ' << ' << @escapefunc << '((' << code << '));'
250
+ with_buffer{@src << ' << ' << @escapefunc << '((' << code << '))'}
214
251
  end
215
252
 
216
253
  # Add the given postamble to the src. Can be overridden in subclasses
217
254
  # to make additional changes to src that depend on the current state.
218
255
  def add_postamble(postamble)
219
- src << postamble
256
+ terminate_expression
257
+ @src << postamble
220
258
  end
221
259
 
222
260
  # Raise an exception, as the base engine class does not support handling other indicators.
223
261
  def handle(indicator, code, tailch, rspace, lspace)
224
262
  raise ArgumentError, "Invalid indicator: #{indicator}"
225
263
  end
264
+
265
+ # Make sure the buffer variable is the target of the next append
266
+ # before yielding to the block. Mark that the buffer is the target
267
+ # of the next append after the block executes.
268
+ #
269
+ # This method should only be called if the block will result in
270
+ # code where << will append to the bufvar.
271
+ def with_buffer
272
+ if @chain_appends
273
+ unless @buffer_on_stack
274
+ @src << '; ' << @bufvar
275
+ end
276
+ yield
277
+ @buffer_on_stack = true
278
+ else
279
+ @src << ' ' << @bufvar
280
+ yield
281
+ @src << ';'
282
+ end
283
+ end
284
+
285
+ # Make sure that any current expression has been terminated.
286
+ # The default is to terminate all expressions, but when
287
+ # the chain_appends option is used, expressions may not be
288
+ # terminated.
289
+ def terminate_expression
290
+ @src << '; ' if @chain_appends
291
+ end
226
292
  end
227
293
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: erubi
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.10.0
4
+ version: 1.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Evans
8
8
  - kuwata-lab.com
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-11-13 00:00:00.000000000 Z
12
+ date: 2022-12-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: minitest
@@ -59,9 +59,10 @@ licenses:
59
59
  - MIT
60
60
  metadata:
61
61
  bug_tracker_uri: https://github.com/jeremyevans/erubi/issues
62
+ mailing_list_uri: https://github.com/jeremyevans/erubi/discussions
62
63
  changelog_uri: https://github.com/jeremyevans/erubi/blob/master/CHANGELOG
63
64
  source_code_uri: https://github.com/jeremyevans/erubi
64
- post_install_message:
65
+ post_install_message:
65
66
  rdoc_options:
66
67
  - "--quiet"
67
68
  - "--line-numbers"
@@ -83,8 +84,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
83
84
  - !ruby/object:Gem::Version
84
85
  version: '0'
85
86
  requirements: []
86
- rubygems_version: 3.1.4
87
- signing_key:
87
+ rubygems_version: 3.3.26
88
+ signing_key:
88
89
  specification_version: 4
89
90
  summary: Small ERB Implementation
90
91
  test_files: []