erubi 1.10.0 → 1.12.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: 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: []