erubi 1.12.0 → 1.13.1

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: b0cae36e4fa5e180f0934c68f04a936a6f51df57e8ef1a4436a907ab408a85a7
4
- data.tar.gz: ceaeb0da7540a786c6e65cf8bb1c72ad60bf7309f0a9f0cdf460c32236d80a2c
3
+ metadata.gz: 547aa741f72fd87ac7747c597614f457b3880d01d3b3aa161c24e62c93f00cc7
4
+ data.tar.gz: d465d4b57e9abe24de9cf5859773691dfee9198ca0c4d05a5ca8f0903b2acefd
5
5
  SHA512:
6
- metadata.gz: 3c2a45e5cbd23b6f85257fcb7139e92cd116b0854fb5386b73331b05314aa0020725ac1bd918e4156e253df1cf7f5f58e6db86874f3180dabc5d8e38d1d910d3
7
- data.tar.gz: 54a5c8d8d72bfcc8344f9f4224d36070d90d61817deaa601f25dfee24edc4b6f408f5a00b09891075959a1a41d6fa67046594c5e5e3b65707e24f737777de716
6
+ metadata.gz: 109432844ed8df5daab8e5b6e6aa2404c314009f968129ec02c920f6c75094f4a484207751d34cb2255d6c3d5f286e14c369ba54dc398e06266d22e84e2f4e24
7
+ data.tar.gz: 5eab140a49714dd65c67b9eb7e196a86f25c9a3a59348b04dc3d7b57db8c0cbccbca28f94dae2ae69c04382e5ab6c4350c7f8dd99db2dbbd0121ba0759bd0ca1
data/CHANGELOG CHANGED
@@ -1,3 +1,13 @@
1
+ === 1.13.1 (2024-12-19)
2
+
3
+ * Avoid spurious frozen string literal warnings for chilled strings when using Ruby 3.4 (jeremyevans)
4
+
5
+ === 1.13.0 (2024-06-13)
6
+
7
+ * Define Erubi.h as a module function (jeremyevans)
8
+
9
+ * Add erubi/capture_block, supporting capturing block output via standard <%= and <%== tags (jeremyevans)
10
+
1
11
  === 1.12.0 (2022-12-22)
2
12
 
3
13
  * Use erb/escape for faster html escaping if available (jeremyevans)
data/README.rdoc CHANGED
@@ -8,7 +8,7 @@ the same basic algorithm, with the following differences:
8
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
10
  * Escapes <tt>'</tt> (apostrophe) when escaping for better XSS protection
11
- * Has 6x faster escaping on ruby 2.3+ by using cgi/escape
11
+ * Has 15x-6x faster escaping by using erb/escape or cgi/escape
12
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)
@@ -42,33 +42,75 @@ erb template handler in Tilt 2.0.6+ and Rails 5.1+.
42
42
  == Capturing
43
43
 
44
44
  Erubi does not support capturing block output into the template by default.
45
- However, it comes with an +erubi/capture_end+ file that supports capturing
46
- via <tt><%|=</tt> and <tt><%|==</tt> tags which are closed with a
47
- <tt><%|</tt> tag:
45
+ It currently ships with two implementations that allow it.
48
46
 
49
- <%|= form do %>
47
+ === Erubi::CaptureBlockEngine
48
+
49
+ The recommended implementation can be required via +erubi/capture_block+,
50
+ which allows capturing to work with normal <tt><%=</tt> and <tt><%==</tt>
51
+ tags.
52
+
53
+ <%= form do %>
50
54
  <input>
51
- <%| end %>
55
+ <% end %>
56
+
57
+ When using the capture_block support, capture methods should just return
58
+ the text it emit into the template, and call +capture+ on the buffer value.
59
+ Since the buffer variable is a local variable and not an instance variable
60
+ by default, you'll probably want to set the +:bufvar+ variable when using
61
+ the capture_block support to an instance variable, and have any methods
62
+ used call capture on that instance variable. Example:
63
+
64
+ def form(&block)
65
+ "<form>#{@_buf.capture(&block)}</form>"
66
+ end
52
67
 
53
- This offers similar functionality to that offered by Rails' <tt><%=</tt>
54
- tags, but without the corner cases with that approach (which are due to
55
- attempting to parse ruby code via a regexp). Similar to the <tt><%=</tt>
56
- and <tt><%==</tt> tags, <tt><%|=</tt> captures by default and
57
- <tt><%|==</tt> captures and escapes by default, but this can be reversed
58
- via the +:escape_capture+ or +:escape+ options.
68
+ puts eval(Erubi::CaptureBlockEngine.new(<<-END, bufvar: '@_buf', trim: false).src)
69
+ before
70
+ <%= form do %>
71
+ inside
72
+ <% end %>
73
+ after
74
+ END
75
+
76
+ # Output:
77
+ # before
78
+ # <form>
79
+ # inside
80
+ # </form>
81
+ # after
59
82
 
60
- To use the capture_end support with tilt:
83
+ To use the capture_block support with tilt:
61
84
 
62
85
  require 'tilt'
63
- require 'erubi/capture_end'
64
- Tilt.new("filename.erb", :engine_class=>Erubi::CaptureEndEngine).render
86
+ require 'erubi/capture_block'
87
+ Tilt.new("filename.erb", :engine_class=>Erubi::CaptureBlockEngine).render
88
+
89
+ Note that the capture_block support, while very compatible with the default
90
+ support, is not 100% compatible. One area where behavior differs is when
91
+ using multiple statements inside <tt><%=</tt> and <tt><%==</tt> tags:
92
+
93
+ <%= 1; 2 %>
94
+
95
+ The default support will output 2, but the capture_block support will output
96
+ 1.
97
+
98
+ === Erubi::CaptureEndEngine
99
+
100
+ An alternative capture implementation can be required via +erubi/capture_end+,
101
+ which supports it via <tt><%|=</tt> and <tt><%|==</tt> tags which are
102
+ closed with a <tt><%|</tt> tag:
103
+
104
+ <%|= form do %>
105
+ <input>
106
+ <%| end %>
107
+
108
+ It is only recommended to use +erubi/capture_end+ for backwards
109
+ compatibilty.
65
110
 
66
- When using the capture_end support, any methods (such as +form+ in the example
67
- above) should return the (potentially modified) buffer. Since the buffer
68
- variable is a local variable and not an instance variable by default, you'll
69
- probably want to set the +:bufvar+ variable when using the capture_end
70
- support to an instance variable, and have any methods used access that
71
- instance variable. Example:
111
+ When using the capture_end support, capture methods (such as +form+ in the example
112
+ above) should return the (potentially modified) buffer. Similar to the
113
+ capture_block support, using an instance variable is recommended. Example:
72
114
 
73
115
  def form
74
116
  @_buf << "<form>"
@@ -77,7 +119,7 @@ instance variable. Example:
77
119
  @_buf
78
120
  end
79
121
 
80
- puts eval(Erubi::CaptureEndEngine.new(<<-END, :bufvar=>:@_buf).src)
122
+ puts eval(Erubi::CaptureEndEngine.new(<<-END, bufvar: '@_buf').src)
81
123
  before
82
124
  <%|= form do %>
83
125
  inside
data/Rakefile CHANGED
@@ -16,7 +16,7 @@ end
16
16
  RDOC_DEFAULT_OPTS = ["--line-numbers", "--inline-source", '--title', 'Erubi: Small ERB Implementation']
17
17
 
18
18
  begin
19
- gem 'hanna-nouveau'
19
+ gem 'hanna'
20
20
  RDOC_DEFAULT_OPTS.concat(['-f', 'hanna'])
21
21
  rescue Gem::LoadError
22
22
  end
@@ -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} #{'-w' if RUBY_VERSION >= '3'} test/test.rb"
45
+ sh "#{FileUtils::RUBY} #{'-w' if RUBY_VERSION >= '3'} #{'-W:strict_unused_block' if RUBY_VERSION >= '3.4'} test/test.rb"
46
46
  env.each{|k,v| ENV.delete(k)}
47
47
  end
48
48
 
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'erubi'
4
+
5
+ module Erubi
6
+ # An engine class that supports capturing blocks via the <tt><%=</tt> and <tt><%==</tt> tags:
7
+ #
8
+ # <%= upcase_form do %>
9
+ # <%= 'foo' %>
10
+ # <% end %>
11
+ #
12
+ # Where +upcase_form+ is defined like:
13
+ #
14
+ # def upcase_form(&block)
15
+ # "<form>#{@bufvar.capture(&block).upcase}</form>"
16
+ # end
17
+ #
18
+ # With output being:
19
+ #
20
+ # <form>
21
+ # FOO
22
+ # </form>
23
+ #
24
+ # This requires using a string subclass as the buffer value, provided by the
25
+ # CaptureBlockEngine::Buffer class.
26
+ #
27
+ # This engine does not support the :escapefunc option. To change the escaping function,
28
+ # use a subclass of CaptureBlockEngine::Buffer and override the #| method.
29
+ #
30
+ # This engine does not support the :chain_appends option, and ignores it if present.
31
+ class CaptureBlockEngine < Engine
32
+ class Buffer < ::String
33
+
34
+ # Convert argument to string when concatening
35
+ def <<(v)
36
+ concat(v.to_s)
37
+ end
38
+
39
+ # Escape argument using Erubi.h then then concatenate it to the receiver.
40
+ def |(v)
41
+ concat(h(v))
42
+ end
43
+
44
+ # Temporarily clear the receiver before yielding to the block, yield the
45
+ # given args to the block, return any data captured by the receiver, and
46
+ # restore the original data the receiver contained before returning.
47
+ def capture(*args)
48
+ prev = dup
49
+ replace("") # 1.8 support!
50
+ yield(*args)
51
+ dup
52
+ ensure
53
+ replace(prev)
54
+ end
55
+
56
+ private
57
+
58
+ if RUBY_VERSION >= '2'
59
+ define_method(:h, ::Erubi.instance_method(:h))
60
+ # :nocov:
61
+ else
62
+ def h(v)
63
+ ::Erubi.h(v)
64
+ end
65
+ end
66
+ # :nocov:
67
+ end
68
+
69
+ def initialize(input, properties={})
70
+ properties = Hash[properties]
71
+ properties[:bufval] ||= '::Erubi::CaptureBlockEngine::Buffer.new'
72
+ properties[:chain_appends] = false
73
+ super
74
+ end
75
+
76
+ private
77
+
78
+ def add_expression_result(code)
79
+ add_expression_op(' <<= ', code)
80
+ end
81
+
82
+ def add_expression_result_escaped(code)
83
+ add_expression_op(' |= ', code)
84
+ end
85
+
86
+ def add_expression_op(op, code)
87
+ check = /\A\s*\z/.send(MATCH_METHOD, code) ? "''" : ''
88
+ with_buffer{@src << op << check << code}
89
+ end
90
+ end
91
+ end
data/lib/erubi.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Erubi
4
- VERSION = '1.12.0'
4
+ VERSION = '1.13.1'
5
5
 
6
6
  # :nocov:
7
7
  if RUBY_VERSION >= '1.9'
@@ -19,37 +19,34 @@ module Erubi
19
19
 
20
20
  begin
21
21
  require 'erb/escape'
22
- # :nocov:
23
- define_singleton_method(:h, ERB::Escape.instance_method(:html_escape))
24
- # :nocov:
22
+ define_method(:h, ERB::Escape.instance_method(:html_escape))
23
+ # :nocov:
25
24
  rescue LoadError
26
25
  begin
27
26
  require 'cgi/escape'
28
- # :nocov:
29
27
  unless CGI.respond_to?(:escapeHTML) # work around for JRuby 9.1
30
28
  CGI = Object.new
31
29
  CGI.extend(defined?(::CGI::Escape) ? ::CGI::Escape : ::CGI::Util)
32
30
  end
33
- # :nocov:
34
31
  # Escape characters with their HTML/XML equivalents.
35
- def self.h(value)
32
+ def h(value)
36
33
  CGI.escapeHTML(value.to_s)
37
34
  end
38
35
  rescue LoadError
39
- # :nocov:
40
36
  ESCAPE_TABLE = {'&' => '&amp;'.freeze, '<' => '&lt;'.freeze, '>' => '&gt;'.freeze, '"' => '&quot;'.freeze, "'" => '&#39;'.freeze}.freeze
41
37
  if RUBY_VERSION >= '1.9'
42
- def self.h(value)
38
+ def h(value)
43
39
  value.to_s.gsub(/[&<>"']/, ESCAPE_TABLE)
44
40
  end
45
41
  else
46
- def self.h(value)
42
+ def h(value)
47
43
  value.to_s.gsub(/[&<>"']/){|s| ESCAPE_TABLE[s]}
48
44
  end
49
45
  end
50
- # :nocov:
51
46
  end
52
47
  end
48
+ # :nocov:
49
+ module_function :h
53
50
 
54
51
  class Engine
55
52
  # The default regular expression used for scanning.
@@ -208,16 +205,25 @@ module Erubi
208
205
 
209
206
  private
210
207
 
208
+ if RUBY_VERSION >= '2.3'
209
+ def _dup_string_if_frozen(string)
210
+ +string
211
+ end
212
+ # :nocov:
213
+ else
214
+ def _dup_string_if_frozen(string)
215
+ string.frozen? ? string.dup : string
216
+ end
217
+ end
218
+ # :nocov:
219
+
211
220
  # Add raw text to the template. Modifies argument if argument is mutable as a memory optimization.
212
221
  # Must be called with a string, cannot be called with nil (Rails's subclass depends on it).
213
222
  def add_text(text)
214
223
  return if text.empty?
215
224
 
216
- if text.frozen?
217
- text = text.gsub(/['\\]/, '\\\\\&')
218
- else
219
- text.gsub!(/['\\]/, '\\\\\&')
220
- end
225
+ text = _dup_string_if_frozen(text)
226
+ text.gsub!(/['\\]/, '\\\\\&')
221
227
 
222
228
  with_buffer{@src << " << '" << text << @text_end}
223
229
  end
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.12.0
4
+ version: 1.13.1
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: 2022-12-22 00:00:00.000000000 Z
12
+ date: 2024-12-19 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: minitest
@@ -53,6 +53,7 @@ files:
53
53
  - README.rdoc
54
54
  - Rakefile
55
55
  - lib/erubi.rb
56
+ - lib/erubi/capture_block.rb
56
57
  - lib/erubi/capture_end.rb
57
58
  homepage: https://github.com/jeremyevans/erubi
58
59
  licenses:
@@ -84,7 +85,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
84
85
  - !ruby/object:Gem::Version
85
86
  version: '0'
86
87
  requirements: []
87
- rubygems_version: 3.3.26
88
+ rubygems_version: 3.5.22
88
89
  signing_key:
89
90
  specification_version: 4
90
91
  summary: Small ERB Implementation