roda 3.90.0 → 3.92.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: c42c5f4d45d0f7fe64602e9d2a32bec3c690606c98709f7bd0bde537dd7a6463
4
- data.tar.gz: c5f4edfdf88244770bd0184220df443ea5183c017f11c7342b4192db158d8d6c
3
+ metadata.gz: 63e0c8b5dc16e1652a1bbe309c046b681c8f11a90a31c2b2bd8368baa1b85f43
4
+ data.tar.gz: b81857ea9bc5ac7667f19fb730982d7b1259e95e1ff1b049d0c619fddf08a1be
5
5
  SHA512:
6
- metadata.gz: 19ccf7e44d75f36bc372f2dcad01bb9bf23831c12397d142ea94d1e5f10d0cfe1be3f62f8f45e584ab9e4d0510c8d6acba7dd13e5d9df0680dece3838a43f5a6
7
- data.tar.gz: 48e7c8fc21d75df1adfb616fa5fa88c2b410b290168b2fa1b14ab2c53f8f33167e039f310007dc19831e0571c4ce2b2d34c023b8b88c07d4ff666afe4b426ce9
6
+ metadata.gz: ca7712b09048602d91378cdb22ecf30e2d03cf43a215ad52d6aa697151abd88fe4873f4e162b617782f89b434f733d0230f7a3b8bacf252880450dc65308e4ac
7
+ data.tar.gz: 625b03ba51df7bc895b69e09a739584ae5ff6c15f7701e98a5e55fec301ed0e97353f503565811ae335534c1e6e0634916246fae99493851e472148c5c666789
@@ -60,7 +60,7 @@ class Roda
60
60
  # <%= assets(:css, media: 'print') %>
61
61
  #
62
62
  # The assets method will respect the application's +:add_script_name+ option,
63
- # if it set it will automatically prefix the path with the +SCRIPT_NAME+ for
63
+ # if it is set it will automatically prefix the path with the +SCRIPT_NAME+ for
64
64
  # the request.
65
65
  #
66
66
  # == Asset Paths
@@ -21,26 +21,66 @@ class Roda
21
21
  # used as the template engine), this will call +capture+ on the
22
22
  # output buffer object, instead of setting the output buffer object
23
23
  # temporarily to a new object.
24
+ #
25
+ # By default, capture_erb returns the value of the block, converted
26
+ # to a string. However, that can cause issues with code such as:
27
+ #
28
+ # <% value = capture_erb do %>
29
+ # Some content here.
30
+ # <% if something %>
31
+ # Some more content here.
32
+ # <% end %>
33
+ # <% end %>
34
+ #
35
+ # In this case, the block may return nil, instead of the content of
36
+ # the template. To handle this case, you can provide the
37
+ # <tt>returns: :buffer</tt> option when calling the method (to handle
38
+ # that specific call, or when loading the plugin (to default to that
39
+ # behavior). Note that if the output buffer object responds to
40
+ # +capture+ and is not an instance of String, the <tt>returns: :buffer</tt>
41
+ # behavior is the default and cannot be changed.
24
42
  module CaptureERB
25
- def self.load_dependencies(app)
43
+ def self.load_dependencies(app, opts=OPTS)
26
44
  app.plugin :render
27
45
  end
28
46
 
47
+ # Support <tt>returns: :buffer</tt> to default to returning buffer
48
+ # object.
49
+ def self.configure(app, opts=OPTS)
50
+ # RODA4: make returns: :buffer the default behavior
51
+ app.opts[:capture_erb_returns] = opts[:returns] if opts.has_key?(:returns)
52
+ end
53
+
29
54
  module InstanceMethods
30
55
  # Temporarily replace the ERB output buffer
31
56
  # with an empty string, and then yield to the block.
32
57
  # Return the value of the block, converted to a string.
33
58
  # Restore the previous ERB output buffer before returning.
34
- def capture_erb(&block)
59
+ #
60
+ # Options:
61
+ # :returns :: If set to :buffer, returns the value of the
62
+ # template output variable, instead of the return
63
+ # value of the block converted to a string. This
64
+ # is the default behavior if the template output
65
+ # variable supports the +capture+ method and is not
66
+ # a String instance.
67
+ def capture_erb(opts=OPTS, &block)
35
68
  outvar = render_opts[:template_opts][:outvar]
36
69
  buf_was = instance_variable_get(outvar)
37
70
 
38
71
  if buf_was.respond_to?(:capture) && !buf_was.instance_of?(String)
39
72
  buf_was.capture(&block)
40
73
  else
74
+ returns = opts.fetch(:returns) { self.opts[:capture_erb_returns] }
75
+
41
76
  begin
42
77
  instance_variable_set(outvar, String.new)
43
- yield.to_s
78
+ if returns == :buffer
79
+ yield
80
+ instance_variable_get(outvar).to_s
81
+ else
82
+ yield.to_s
83
+ end
44
84
  ensure
45
85
  instance_variable_set(outvar, buf_was) if outvar && buf_was
46
86
  end
@@ -0,0 +1,87 @@
1
+ # frozen-string-literal: true
2
+
3
+ #
4
+ class Roda
5
+ module RodaPlugins
6
+ # The each_part plugin adds an each_part method, which is a
7
+ # render_each-like method that treats all keywords as locals.
8
+ #
9
+ # # Can replace this:
10
+ # render_each(enum, :template, locals: {foo: 'bar'})
11
+ #
12
+ # # With this:
13
+ # each_part(enum, :template, foo: 'bar')
14
+ #
15
+ # On Ruby 2.7+, the part method takes a keyword splat, so you
16
+ # must pass keywords and not a positional hash for the locals.
17
+ #
18
+ # If you are using the :assume_fixed_locals render plugin option,
19
+ # template caching is enabled, you are using Ruby 3+, and you
20
+ # are freezing your Roda application, in addition to providing a
21
+ # simpler API, this also provides a performance improvement.
22
+ module EachPart
23
+ def self.load_dependencies(app)
24
+ app.plugin :render_each
25
+ end
26
+
27
+ module ClassMethods
28
+ # When freezing, optimize the part method if assuming fixed locals
29
+ # and caching templates.
30
+ def freeze
31
+ if render_opts[:assume_fixed_locals] && !render_opts[:check_template_mtime]
32
+ include AssumeFixedLocalsInstanceMethods
33
+ end
34
+
35
+ super
36
+ end
37
+ end
38
+
39
+ module InstanceMethods
40
+ if RUBY_VERSION >= '2.7'
41
+ class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
42
+ def each_part(enum, template, **locals, &block)
43
+ render_each(enum, template, :locals=>locals, &block)
44
+ end
45
+ RUBY
46
+ # :nocov:
47
+ else
48
+ def each_part(enum, template, locals=OPTS, &block)
49
+ render_each(enum, template, :locals=>locals, &block)
50
+ end
51
+ end
52
+ # :nocov:
53
+ end
54
+
55
+ module AssumeFixedLocalsInstanceMethods
56
+ # :nocov:
57
+ if RUBY_VERSION >= '3.0'
58
+ # :nocov:
59
+ class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
60
+ def each_part(enum, template, **locals, &block)
61
+ if optimized_method = _cached_render_each_template_method(template)
62
+ optimized_method = optimized_method[0]
63
+ as = render_each_default_local(template)
64
+ if defined?(yield)
65
+ enum.each do |v|
66
+ locals[as] = v
67
+ yield send(optimized_method, **locals)
68
+ end
69
+ nil
70
+ else
71
+ enum.map do |v|
72
+ locals[as] = v
73
+ send(optimized_method, **locals)
74
+ end.join
75
+ end
76
+ else
77
+ render_each(enum, template, :locals=>locals, &block)
78
+ end
79
+ end
80
+ RUBY
81
+ end
82
+ end
83
+ end
84
+
85
+ register_plugin(:each_part, EachPart)
86
+ end
87
+ end
@@ -103,7 +103,7 @@ class Roda
103
103
  #
104
104
  # Mailer.sendmail('/welcome/1', 'foo@example.com')
105
105
  #
106
- # r.mail 'welcome' do |user_id, mail_from|
106
+ # r.mail 'welcome', Integer do |user_id, mail_from|
107
107
  # from mail_from
108
108
  # to User[user_id].email
109
109
  # # ...
@@ -15,6 +15,38 @@ class Roda
15
15
  # is rendered, the local variable +foo+ will contain the given
16
16
  # value (e.g. on the first rendering +foo+ is 1).
17
17
  #
18
+ # If you provide a block when calling the method, it will yield
19
+ # each rendering instead of returning a concatentation of the
20
+ # renderings. This is useful if you want to wrap each rendering in
21
+ # something else. For example, instead of calling +render+ multiple
22
+ # times in a loop:
23
+ #
24
+ # <% [1,2,3].each do |v| %>
25
+ # <p><%= render(:foo, locals: {foo: v}) %></p>
26
+ # <% end %>
27
+ #
28
+ # You can use +render_each+, allowing for simpler and more optimized
29
+ # code:
30
+ #
31
+ # <% render_each([1,2,3], :foo) do |text| %>
32
+ # <p><%= text %></p>
33
+ # <% end %>
34
+ #
35
+ # You can also provide a block to avoid excess memory usage. For
36
+ # example, if you are calling the method inside an erb template,
37
+ # instead of doing:
38
+ #
39
+ # <%= render_each([1,2,3], :foo) %>
40
+ #
41
+ # You can do:
42
+ #
43
+ # <% render_each([1,2,3], :foo) %><%= body %><% end %>
44
+ #
45
+ # This results in the same behavior, but avoids building a large
46
+ # intermediate string just to concatenate to the template result.
47
+ #
48
+ # When passing a block, +render_each+ returns +nil+.
49
+ #
18
50
  # You can pass additional render options via an options hash:
19
51
  #
20
52
  # render_each([1,2,3], :foo, views: 'partials')
@@ -45,36 +77,48 @@ class Roda
45
77
  # :local :: The local variable to use for the current enum value
46
78
  # inside the template. An explicit +nil+ value does not
47
79
  # set a local variable. If not set, uses the template name.
48
- def render_each(enum, template, opts=(no_opts = true; optimized_template = _cached_render_each_template_method(template); OPTS))
80
+ def render_each(enum, template, opts=(no_opts = true; optimized_template = _cached_render_each_template_method(template); OPTS), &block)
49
81
  if optimized_template
50
- return _optimized_render_each(enum, optimized_template, render_each_default_local(template), {})
82
+ return _optimized_render_each(enum, optimized_template, render_each_default_local(template), {}, &block)
51
83
  elsif opts.has_key?(:local)
52
84
  as = opts[:local]
53
85
  else
54
86
  as = render_each_default_local(template)
55
87
  if no_opts && optimized_template.nil? && (optimized_template = _optimized_render_method_for_locals(template, (locals = {as=>nil})))
56
- return _optimized_render_each(enum, optimized_template, as, locals)
88
+ return _optimized_render_each(enum, optimized_template, as, locals, &block)
57
89
  end
58
90
  end
59
91
 
60
92
  if as
61
93
  opts = opts.dup
62
- if locals = opts[:locals]
63
- locals = opts[:locals] = Hash[locals]
94
+ if locals
95
+ opts[:locals] = locals
64
96
  else
65
- locals = opts[:locals] = {}
97
+ locals = opts[:locals] = if locals = opts[:locals]
98
+ Hash[locals]
99
+ else
100
+ {}
101
+ end
102
+ locals[as] = nil
66
103
  end
67
- locals[as] = nil
68
104
 
69
105
  if (opts.keys - ALLOWED_KEYS).empty? && (optimized_template = _optimized_render_method_for_locals(template, locals))
70
- return _optimized_render_each(enum, optimized_template, as, locals)
106
+ return _optimized_render_each(enum, optimized_template, as, locals, &block)
71
107
  end
72
108
  end
73
109
 
74
- enum.map do |v|
75
- locals[as] = v if as
76
- render_template(template, opts)
77
- end.join
110
+ if defined?(yield)
111
+ enum.each do |v|
112
+ locals[as] = v if as
113
+ yield render_template(template, opts)
114
+ end
115
+ nil
116
+ else
117
+ enum.map do |v|
118
+ locals[as] = v if as
119
+ render_template(template, opts)
120
+ end.join
121
+ end
78
122
  end
79
123
 
80
124
  private
@@ -94,7 +138,8 @@ class Roda
94
138
  case template
95
139
  when String, Symbol
96
140
  if (method_cache = render_opts[:template_method_cache])
97
- _cached_template_method_lookup(method_cache, [:_render_locals, template, [template.to_sym]])
141
+ key = render_opts[:assume_fixed_locals] ? template : [:_render_locals, template, [template.to_sym]]
142
+ _cached_template_method_lookup(method_cache, key)
98
143
  end
99
144
  else
100
145
  false
@@ -103,10 +148,18 @@ class Roda
103
148
 
104
149
  # Use an optimized render for each value in the enum.
105
150
  def _optimized_render_each(enum, optimized_template, as, locals)
106
- enum.map do |v|
107
- locals[as] = v
108
- _call_optimized_template_method(optimized_template, locals)
109
- end.join
151
+ if defined?(yield)
152
+ enum.each do |v|
153
+ locals[as] = v
154
+ yield _call_optimized_template_method(optimized_template, locals)
155
+ end
156
+ nil
157
+ else
158
+ enum.map do |v|
159
+ locals[as] = v
160
+ _call_optimized_template_method(optimized_template, locals)
161
+ end.join
162
+ end
110
163
  end
111
164
  else
112
165
  def _cached_render_each_template_method(template)
data/lib/roda/version.rb CHANGED
@@ -4,7 +4,7 @@ class Roda
4
4
  RodaMajorVersion = 3
5
5
 
6
6
  # The minor version of Roda, updated for new feature releases of Roda.
7
- RodaMinorVersion = 90
7
+ RodaMinorVersion = 92
8
8
 
9
9
  # The patch version of Roda, updated only for bug fixes from the last
10
10
  # feature release.
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: roda
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.90.0
4
+ version: 3.92.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Evans
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-03-11 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: rack
@@ -200,6 +200,7 @@ files:
200
200
  - lib/roda/plugins/direct_call.rb
201
201
  - lib/roda/plugins/disallow_file_uploads.rb
202
202
  - lib/roda/plugins/drop_body.rb
203
+ - lib/roda/plugins/each_part.rb
203
204
  - lib/roda/plugins/early_hints.rb
204
205
  - lib/roda/plugins/empty_root.rb
205
206
  - lib/roda/plugins/environments.rb
@@ -326,7 +327,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
326
327
  - !ruby/object:Gem::Version
327
328
  version: '0'
328
329
  requirements: []
329
- rubygems_version: 3.6.2
330
+ rubygems_version: 3.6.7
330
331
  specification_version: 4
331
332
  summary: Routing tree web toolkit
332
333
  test_files: []