erubi 1.12.0 → 1.13.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: b0cae36e4fa5e180f0934c68f04a936a6f51df57e8ef1a4436a907ab408a85a7
4
- data.tar.gz: ceaeb0da7540a786c6e65cf8bb1c72ad60bf7309f0a9f0cdf460c32236d80a2c
3
+ metadata.gz: 9364047dc0b7365bae5a6f9ee75c748a0ef02bf4e516331c2d0533da9fe49e04
4
+ data.tar.gz: 9416aeee2c6c4556c3f19f7b918819cbe076493601efd9470815870fac1a2625
5
5
  SHA512:
6
- metadata.gz: 3c2a45e5cbd23b6f85257fcb7139e92cd116b0854fb5386b73331b05314aa0020725ac1bd918e4156e253df1cf7f5f58e6db86874f3180dabc5d8e38d1d910d3
7
- data.tar.gz: 54a5c8d8d72bfcc8344f9f4224d36070d90d61817deaa601f25dfee24edc4b6f408f5a00b09891075959a1a41d6fa67046594c5e5e3b65707e24f737777de716
6
+ metadata.gz: ecd851eb258b2a0302d6a46b747722100aad3a145c4c22b6d1d14f856f094507ebbc84e151a1b9cd9795bb59b0154866e38a08798c75e9726c45b4d987ec48e5
7
+ data.tar.gz: 0c1f32494ca8a192de037c1497065e1f0901cf646fbb090972de215bf66f0fbf2e0774fa38309c50eab288d60dfe59a634e431395912275ec75a2aa3bf4c66be
data/CHANGELOG CHANGED
@@ -1,3 +1,9 @@
1
+ === 1.13.0 (2024-06-13)
2
+
3
+ * Define Erubi.h as a module function (jeremyevans)
4
+
5
+ * Add erubi/capture_block, supporting capturing block output via standard <%= and <%== tags (jeremyevans)
6
+
1
7
  === 1.12.0 (2022-12-22)
2
8
 
3
9
  * 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
@@ -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.0'
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.
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.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: 2022-12-22 00:00:00.000000000 Z
12
+ date: 2024-06-13 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.9
88
89
  signing_key:
89
90
  specification_version: 4
90
91
  summary: Small ERB Implementation