roda 3.89.0 → 3.91.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: 5c056e15afde950dcb27063296ba5b911fe3b900d16c121dd8833374731cdbaa
4
- data.tar.gz: 95225a9c11b07979b50359df7451283eff570557c926f82c49cc34b67d1868fb
3
+ metadata.gz: e89aa3dd4e7c27d33d8b989c87a661a42e28c771aa8c96109279cc8131a4c5f5
4
+ data.tar.gz: e54282de7adf4827dcda2e29c82bbec6d8d76bbbefe29185d3d35b92f3390a50
5
5
  SHA512:
6
- metadata.gz: e38354627d456f2b2bd593703d4ef64f5e934c071d439f1d9647cc8ef010de5fb463d001068ce2e06fd57b0cbccd926005d199b76761ebadefeda699937f5501
7
- data.tar.gz: d542a024a5dd63bfa069baa38d2929bc0925d410641e303839f4a408139614249f223c3054f1f827550522aa21c0f52429184d3484001f7ed6996bbb9b366add
6
+ metadata.gz: a403baf3ca83c6e636c59c1a598319aa41254ad8bffb6e18ba0f81eebf1260674c30f3954b471da60be605d397496d0c2bb96ff286d5e094ea17a4745dc67f82
7
+ data.tar.gz: 2caeb451da13d935c1e14e7009304a16e256942926237704cd80baf32f9fa9d534b58830d8d4092cefec4940cc40fe90e01b33152183d43877900d479135e710
@@ -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
@@ -56,14 +56,15 @@ class Roda
56
56
 
57
57
  env = @_request.env
58
58
 
59
- line = "#{env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-"} - #{env["REMOTE_USER"] || "-"} [#{Time.now.strftime("%d/%b/%Y:%H:%M:%S %z")}] \"#{env["REQUEST_METHOD"]} #{env["SCRIPT_NAME"]}#{env["PATH_INFO"]}#{"?#{env["QUERY_STRING"]}" if ((qs = env["QUERY_STRING"]) && !qs.empty?)} #{@_request.http_version}\" #{status} #{((length = headers[RodaResponseHeaders::CONTENT_LENGTH]) && (length unless length == '0')) || '-'} #{elapsed_time}\n"
59
+ line = "#{env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-"} - #{env["REMOTE_USER"] || "-"} [#{Time.now.strftime("%d/%b/%Y:%H:%M:%S %z")}] \"#{env["REQUEST_METHOD"]} #{env["SCRIPT_NAME"]}#{env["PATH_INFO"]}#{"?#{env["QUERY_STRING"]}" if ((qs = env["QUERY_STRING"]) && !qs.empty?)} #{@_request.http_version}\" #{status} #{((length = headers[RodaResponseHeaders::CONTENT_LENGTH]) && (length unless length == '0')) || '-'} #{elapsed_time} "
60
60
  if MUTATE_LINE
61
- line.gsub!(/[^[:print:]\n]/){|c| sprintf("\\x%x", c.ord)}
61
+ line.gsub!(/[^[:print:]]/){|c| sprintf("\\x%x", c.ord)}
62
62
  # :nocov:
63
63
  else
64
- line = line.gsub(/[^[:print:]\n]/){|c| sprintf("\\x%x", c.ord)}
64
+ line = line.gsub(/[^[:print:]]/){|c| sprintf("\\x%x", c.ord)}
65
65
  # :nocov:
66
66
  end
67
+ line[-1] = "\n"
67
68
  opts[:common_logger_meth].call(line)
68
69
  end
69
70
 
@@ -134,9 +134,7 @@ class Roda
134
134
  # and store +app+ as the next middleware to call.
135
135
  def initialize(mid, app, *args, &block)
136
136
  @mid = Class.new(mid)
137
- # :nocov:
138
- @mid.set_temporary_name("#{mid.name}(middleware)") if mid.name && RUBY_VERSION >= "3.3"
139
- # :nocov:
137
+ RodaPlugins.set_temp_name(@mid){"#{mid}::middleware_subclass"}
140
138
  if @mid.opts[:middleware_next_if_not_found]
141
139
  @mid.plugin(:not_found, &NEXT_PROC)
142
140
  end
@@ -79,6 +79,7 @@ class Roda
79
79
  mod = instance_variable_get(iv)
80
80
  else
81
81
  mod = instance_variable_set(iv, Module.new)
82
+ RodaPlugins.set_temp_name(mod){"#{klass}::module_include"}
82
83
  klass.send(:include, mod)
83
84
  end
84
85
 
@@ -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,15 +77,15 @@ 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
 
@@ -67,14 +99,22 @@ class Roda
67
99
  locals[as] = nil
68
100
 
69
101
  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)
102
+ return _optimized_render_each(enum, optimized_template, as, locals, &block)
71
103
  end
72
104
  end
73
105
 
74
- enum.map do |v|
75
- locals[as] = v if as
76
- render_template(template, opts)
77
- end.join
106
+ if defined?(yield)
107
+ enum.each do |v|
108
+ locals[as] = v if as
109
+ yield render_template(template, opts)
110
+ end
111
+ nil
112
+ else
113
+ enum.map do |v|
114
+ locals[as] = v if as
115
+ render_template(template, opts)
116
+ end.join
117
+ end
78
118
  end
79
119
 
80
120
  private
@@ -103,10 +143,18 @@ class Roda
103
143
 
104
144
  # Use an optimized render for each value in the enum.
105
145
  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
146
+ if defined?(yield)
147
+ enum.each do |v|
148
+ locals[as] = v
149
+ yield _call_optimized_template_method(optimized_template, locals)
150
+ end
151
+ nil
152
+ else
153
+ enum.map do |v|
154
+ locals[as] = v
155
+ _call_optimized_template_method(optimized_template, locals)
156
+ end.join
157
+ end
110
158
  end
111
159
  else
112
160
  def _cached_render_each_template_method(template)
@@ -354,9 +354,7 @@ class Roda
354
354
  res.status = opts[:status] || s
355
355
  headers.delete(RodaResponseHeaders::CONTENT_LENGTH)
356
356
  headers.replace(h.merge!(headers))
357
- res.body = b
358
-
359
- halt
357
+ halt res.finish_with_body(b)
360
358
  rescue Errno::ENOENT
361
359
  not_found
362
360
  end
data/lib/roda/plugins.rb CHANGED
@@ -49,5 +49,20 @@ class Roda
49
49
  end
50
50
  # :nocov:
51
51
  end
52
+
53
+ if RUBY_VERSION >= '3.3'
54
+ # Create a new module using the block, and set the temporary name
55
+ # on it using the given a containing module and name.
56
+ def self.set_temp_name(mod)
57
+ mod.set_temporary_name(yield)
58
+ mod
59
+ end
60
+ # :nocov:
61
+ else
62
+ def self.set_temp_name(mod)
63
+ mod
64
+ end
65
+ end
66
+ # :nocov:
52
67
  end
53
68
  end
@@ -159,6 +159,7 @@ class RodaSessionMiddleware
159
159
  # Setup the middleware, passing +opts+ as the Roda sessions plugin options.
160
160
  def initialize(app, opts)
161
161
  mid = Class.new(Roda)
162
+ Roda::RodaPlugins.set_temp_name(mid){"RodaSessionMiddleware::_RodaSubclass"}
162
163
  mid.plugin :sessions, opts
163
164
  @req_class = mid::RodaRequest
164
165
  @req_class.send(:include, RequestMethods)
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 = 89
7
+ RodaMinorVersion = 91
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.89.0
4
+ version: 3.91.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Evans
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-02-12 00:00:00.000000000 Z
10
+ date: 2025-04-11 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: rack