roda 3.48.0 → 3.52.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +34 -0
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -2
- data/doc/release_notes/3.49.0.txt +18 -0
- data/doc/release_notes/3.50.0.txt +21 -0
- data/doc/release_notes/3.51.0.txt +20 -0
- data/doc/release_notes/3.52.0.txt +20 -0
- data/lib/roda/plugins/_optimized_matching.rb +40 -2
- data/lib/roda/plugins/assets.rb +10 -2
- data/lib/roda/plugins/capture_erb.rb +41 -0
- data/lib/roda/plugins/content_for.rb +7 -13
- data/lib/roda/plugins/content_security_policy.rb +2 -2
- data/lib/roda/plugins/error_handler.rb +1 -0
- data/lib/roda/plugins/hash_routes.rb +16 -4
- data/lib/roda/plugins/inject_erb.rb +33 -0
- data/lib/roda/plugins/module_include.rb +1 -1
- data/lib/roda/plugins/multi_route.rb +2 -1
- data/lib/roda/plugins/multi_run.rb +10 -3
- data/lib/roda/plugins/named_routes.rb +10 -2
- data/lib/roda/plugins/path.rb +11 -2
- data/lib/roda/plugins/render.rb +81 -3
- data/lib/roda/plugins/run_handler.rb +1 -1
- data/lib/roda/plugins/shared_vars.rb +1 -1
- data/lib/roda/plugins/sinatra_helpers.rb +1 -1
- data/lib/roda/plugins/status_303.rb +1 -2
- data/lib/roda/plugins/typecast_params.rb +41 -3
- data/lib/roda/request.rb +1 -1
- data/lib/roda/version.rb +1 -1
- metadata +14 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: df634d0506d88725400ff1b82d04da87928761e9b65937c443e95cd0c084b18f
|
4
|
+
data.tar.gz: fd7e182f69a5f01cc33a654f2a94602aa121562c7b0e46b75c6bfb3e28b320bf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9985fce952a85040aca26f103d82ae5762c0fb70d2c31ee9539bd053bbb700fcb97461114ca6c7f17f7be68eaa2a9e79e89826a54c5caad7c0004ea0d3eaefb5
|
7
|
+
data.tar.gz: baf99483bd37a9c74c38c3a28bb78d030e5107fceae437065cd7d7237db3ac106535ded55727b339898c398d6198872fbd6ec8c2be23854c88d7a908502c89a4
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,37 @@
|
|
1
|
+
= 3.52.0 (2022-01-14)
|
2
|
+
|
3
|
+
* Fix return value of Roda.freeze when multi_route plugin is used (jeremyevans) (#240)
|
4
|
+
|
5
|
+
* Use faster OpenSSL::Digest instead of Digest for assets plugin SRI support (jeremyevans)
|
6
|
+
|
7
|
+
* Drop development dependency on haml (jeremyevans)
|
8
|
+
|
9
|
+
* Make the path method in the path plugin handle blocks that accept keyword arguments in Ruby 3+ (adam12) (#227)
|
10
|
+
|
11
|
+
* Support typecast_params :date_parse_input_handler plugin option for handling input to date parsing methods (jeremyevans)
|
12
|
+
|
13
|
+
= 3.51.0 (2021-12-15)
|
14
|
+
|
15
|
+
* Avoid method redefinition warning in error_handler plugin in verbose warning mode (jeremyevans)
|
16
|
+
|
17
|
+
* Allow run in multi_run plugin to be called without an app to remove existing handler (jeremyevans)
|
18
|
+
|
19
|
+
* Allow route in named_routes plugin to be called without a block to remove existing handler (jeremyevans)
|
20
|
+
|
21
|
+
= 3.50.0 (2021-11-12)
|
22
|
+
|
23
|
+
* Add capture_erb plugin for capturing ERB template blocks, instead of injecting them into the template output (jeremyevans)
|
24
|
+
|
25
|
+
* Add inject_erb plugin for injecting content directly into ERB template output (jeremyevans)
|
26
|
+
|
27
|
+
* Allow hash_branch and hash_path in hash_routes plugin to be called without a block to remove existing handler (jeremyevans)
|
28
|
+
|
29
|
+
= 3.49.0 (2021-10-13)
|
30
|
+
|
31
|
+
* Switch block_given? to defined?(yield) (jeremyevans)
|
32
|
+
|
33
|
+
* Automatically optimize remaining r.is/r.get/r.post calls with a single argument (jeremyevans)
|
34
|
+
|
1
35
|
= 3.48.0 (2021-09-13)
|
2
36
|
|
3
37
|
* Extract named_routes plugin from multi_route plugin (jeremyevans)
|
data/MIT-LICENSE
CHANGED
data/README.rdoc
CHANGED
@@ -12,7 +12,8 @@ maintainable web applications in ruby.
|
|
12
12
|
Website :: http://roda.jeremyevans.net
|
13
13
|
Source :: http://github.com/jeremyevans/roda
|
14
14
|
Bugs :: http://github.com/jeremyevans/roda/issues
|
15
|
-
|
15
|
+
Discussion Forum (GitHub Discussions) :: https://github.com/jeremyevans/roda/discussions
|
16
|
+
Alternate Discussion Forum (Google Group) :: http://groups.google.com/group/ruby-roda
|
16
17
|
|
17
18
|
== Goals
|
18
19
|
|
@@ -1109,7 +1110,8 @@ Roda's plugin system is based on the plugin system used by
|
|
1109
1110
|
Roda fully supports the currently supported versions of Ruby (MRI) and JRuby. It may
|
1110
1111
|
support unsupported versions of Ruby or JRuby, but such support may be dropped in any
|
1111
1112
|
minor version if keeping it becomes a support issue. The minimum Ruby version
|
1112
|
-
required to run the current version of Roda is 1.9.2
|
1113
|
+
required to run the current version of Roda is 1.9.2, and the minimum JRuby version is
|
1114
|
+
9.0.0.0.
|
1113
1115
|
|
1114
1116
|
== License
|
1115
1117
|
|
@@ -0,0 +1,18 @@
|
|
1
|
+
= Improvements
|
2
|
+
|
3
|
+
* The r.is optimization added in 3.46.0 has been extended to optimize
|
4
|
+
all single argument calls. This results in the following speedups
|
5
|
+
based on argument type:
|
6
|
+
|
7
|
+
* Hash/Class matching: 20%
|
8
|
+
* Symbol matching: 25%
|
9
|
+
* Array matching: 35%
|
10
|
+
* Proc matching: 50%
|
11
|
+
* false/nil matching: 65%
|
12
|
+
|
13
|
+
* Roda now uses defined?(yield) instead of block_given? internally
|
14
|
+
for better performance on CRuby. defined?(yield) is faster as it is
|
15
|
+
built into the VM, while block_given? is a regular method and has
|
16
|
+
the overhead of calling a regular method. Note that defined?(yield)
|
17
|
+
is not implemented correctly on JRuby before 9.0.0.0, so this
|
18
|
+
release of Roda drops support for JRuby versions before 9.0.0.0.
|
@@ -0,0 +1,21 @@
|
|
1
|
+
= New Features
|
2
|
+
|
3
|
+
* An inject_erb plugin has been added, adding an inject_erb method
|
4
|
+
that allows for injecting content directly into the template output
|
5
|
+
for the template currently being rendered. This allows you to more
|
6
|
+
easily wrap blocks in templates, by calling methods that accept
|
7
|
+
template blocks and injecting content before and after the block.
|
8
|
+
|
9
|
+
* A capture_erb plugin has been added, adding a capture_erb method
|
10
|
+
for capturing a template block in an erb template and returning
|
11
|
+
the content appended during the block as a string, instead of
|
12
|
+
having the content of the template block be included directly into
|
13
|
+
the template output. This can be combined with the inject_erb
|
14
|
+
plugin to inject modified versions of captured blocks into template
|
15
|
+
output.
|
16
|
+
|
17
|
+
* The hash_routes plugin now allows calling hash_branch and hash_path
|
18
|
+
without a block in order to remove the existing route handler. This
|
19
|
+
is designed to be used with code reloading libraries, so that if a
|
20
|
+
route file is deleted, the related hash branches/paths are also
|
21
|
+
removed, without having to reload all route files.
|
@@ -0,0 +1,20 @@
|
|
1
|
+
= New Features
|
2
|
+
|
3
|
+
* The named_routes plugin now allows calling route without a block
|
4
|
+
to remove the existing route handler. The multi_run plugin
|
5
|
+
now allows calling run without an app to remove an existing handler.
|
6
|
+
These changes are designed to better support code reloading
|
7
|
+
libraries, so that if the related file is deleted, the related
|
8
|
+
handlers are also removed, without having to reload the entire
|
9
|
+
application.
|
10
|
+
|
11
|
+
= Other Improvements
|
12
|
+
|
13
|
+
* The error_handler plugin now avoids a method redefinition warning
|
14
|
+
in verbose warning mode.
|
15
|
+
|
16
|
+
= Other
|
17
|
+
|
18
|
+
* Roda's primary discussion forum is now GitHub Discussions. The
|
19
|
+
ruby-roda Google Group is still available for users who would
|
20
|
+
prefer to use that instead.
|
@@ -0,0 +1,20 @@
|
|
1
|
+
= New Features
|
2
|
+
|
3
|
+
* The typecast_params plugin now supports a :date_parse_input_handler
|
4
|
+
option that will be called with all input that will be passed to
|
5
|
+
the date parsing methods. You can use this option to automatically
|
6
|
+
truncate input, if that is perferable to raising an error (which is
|
7
|
+
how recent versions of Ruby handle too-long input).
|
8
|
+
|
9
|
+
= Other Improvements
|
10
|
+
|
11
|
+
* The path helper methods added by the path plugin now support
|
12
|
+
blocks that use keyword arguments on Ruby 3+.
|
13
|
+
|
14
|
+
* The assets plugin now uses OpenSSL::Digest instead of Digest (if
|
15
|
+
available) for calculating SRI digests. This is faster on Ruby 3+,
|
16
|
+
where Digest no longer uses the faster OpenSSL::Digest automatically
|
17
|
+
if available.
|
18
|
+
|
19
|
+
* Roda.freeze now returns self when the multi_route plugin is used.
|
20
|
+
This was broken (not returning self) starting in 3.48.0.
|
@@ -156,7 +156,21 @@ class Roda
|
|
156
156
|
always{yield(matchdata[1].to_i)}
|
157
157
|
end
|
158
158
|
else
|
159
|
-
|
159
|
+
path = @remaining_path
|
160
|
+
captures = @captures.clear
|
161
|
+
meth = :"_match_class_#{matcher}"
|
162
|
+
if respond_to?(meth, true)
|
163
|
+
# Allow calling private methods, as match methods are generally private
|
164
|
+
if send(meth, &block) && @remaining_path.empty?
|
165
|
+
block_result(yield(*captures))
|
166
|
+
throw :halt, response.finish
|
167
|
+
else
|
168
|
+
@remaining_path = path
|
169
|
+
false
|
170
|
+
end
|
171
|
+
else
|
172
|
+
unsupported_matcher(matcher)
|
173
|
+
end
|
160
174
|
end
|
161
175
|
when Regexp
|
162
176
|
if (matchdata = self.class.cached_matcher(matcher){matcher}.match(@remaining_path)) && matchdata.post_match.empty?
|
@@ -165,8 +179,32 @@ class Roda
|
|
165
179
|
end
|
166
180
|
when true
|
167
181
|
always(&block) if @remaining_path.empty?
|
182
|
+
when false, nil
|
183
|
+
# nothing
|
168
184
|
else
|
169
|
-
|
185
|
+
path = @remaining_path
|
186
|
+
captures = @captures.clear
|
187
|
+
|
188
|
+
matched = case matcher
|
189
|
+
when Array
|
190
|
+
_match_array(matcher)
|
191
|
+
when Hash
|
192
|
+
_match_hash(matcher)
|
193
|
+
when Symbol
|
194
|
+
_match_symbol(matcher)
|
195
|
+
when Proc
|
196
|
+
matcher.call
|
197
|
+
else
|
198
|
+
unsupported_matcher(matcher)
|
199
|
+
end
|
200
|
+
|
201
|
+
if matched && @remaining_path.empty?
|
202
|
+
block_result(yield(*captures))
|
203
|
+
throw :halt, response.finish
|
204
|
+
else
|
205
|
+
@remaining_path = path
|
206
|
+
false
|
207
|
+
end
|
170
208
|
end
|
171
209
|
end
|
172
210
|
end
|
data/lib/roda/plugins/assets.rb
CHANGED
@@ -641,9 +641,17 @@ class Roda
|
|
641
641
|
# a different digest type or to return a static string if you don't
|
642
642
|
# want to use a unique value.
|
643
643
|
def asset_digest(content)
|
644
|
-
require 'digest/sha2'
|
645
644
|
algo = assets_opts[:sri] || :sha256
|
646
|
-
|
645
|
+
digest = begin
|
646
|
+
require 'openssl'
|
647
|
+
::OpenSSL::Digest
|
648
|
+
# :nocov:
|
649
|
+
rescue LoadError
|
650
|
+
require 'digest/sha2'
|
651
|
+
::Digest
|
652
|
+
# :nocov:
|
653
|
+
end
|
654
|
+
digest.const_get(algo.to_s.upcase).hexdigest(content)
|
647
655
|
end
|
648
656
|
end
|
649
657
|
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
class Roda
|
5
|
+
module RodaPlugins
|
6
|
+
# The capture_erb plugin allows you to capture the content of a block
|
7
|
+
# in an ERB template, and return it as a value, instead of
|
8
|
+
# injecting the template block into the template output.
|
9
|
+
#
|
10
|
+
# <% value = capture_erb do %>
|
11
|
+
# Some content here.
|
12
|
+
# <% end %>
|
13
|
+
#
|
14
|
+
# +capture_erb+ can be used inside other methods that are called
|
15
|
+
# inside templates. It can be combined with the inject_erb plugin
|
16
|
+
# to wrap template blocks with arbitrary output and then inject the
|
17
|
+
# wrapped output into the template.
|
18
|
+
module CaptureERB
|
19
|
+
def self.load_dependencies(app)
|
20
|
+
app.plugin :render
|
21
|
+
end
|
22
|
+
|
23
|
+
module InstanceMethods
|
24
|
+
# Temporarily replace the ERB output buffer
|
25
|
+
# with an empty string, and then yield to the block.
|
26
|
+
# Return the value of the block, converted to a string.
|
27
|
+
# Restore the previous ERB output buffer before returning.
|
28
|
+
def capture_erb
|
29
|
+
outvar = render_opts[:template_opts][:outvar]
|
30
|
+
buf_was = instance_variable_get(outvar)
|
31
|
+
instance_variable_set(outvar, String.new)
|
32
|
+
yield.to_s
|
33
|
+
ensure
|
34
|
+
instance_variable_set(outvar, buf_was) if outvar && buf_was
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
register_plugin(:capture_erb, CaptureERB)
|
40
|
+
end
|
41
|
+
end
|
@@ -55,10 +55,10 @@ class Roda
|
|
55
55
|
#
|
56
56
|
# plugin :content_for, append: false
|
57
57
|
module ContentFor
|
58
|
-
# Depend on the
|
59
|
-
#
|
58
|
+
# Depend on the capture_erb plugin, since it uses capture_erb
|
59
|
+
# to capture the content.
|
60
60
|
def self.load_dependencies(app, _opts = OPTS)
|
61
|
-
app.plugin :
|
61
|
+
app.plugin :capture_erb
|
62
62
|
end
|
63
63
|
|
64
64
|
# Configure whether to append or overwrite if content_for
|
@@ -72,18 +72,12 @@ class Roda
|
|
72
72
|
# under the given key. If called without a block, retrieve
|
73
73
|
# stored content with the given key, or return nil if there
|
74
74
|
# is no content stored with that key.
|
75
|
-
def content_for(key, value=nil)
|
75
|
+
def content_for(key, value=nil, &block)
|
76
76
|
append = opts[:append_content_for]
|
77
77
|
|
78
|
-
if
|
79
|
-
if
|
80
|
-
|
81
|
-
buf_was = instance_variable_get(outvar)
|
82
|
-
|
83
|
-
# Use temporary output buffer for ERB-based rendering systems
|
84
|
-
instance_variable_set(outvar, String.new)
|
85
|
-
value = yield.to_s
|
86
|
-
instance_variable_set(outvar, buf_was)
|
78
|
+
if block || value
|
79
|
+
if block
|
80
|
+
value = capture_erb(&block)
|
87
81
|
end
|
88
82
|
|
89
83
|
@_content_for ||= {}
|
@@ -278,7 +278,7 @@ class Roda
|
|
278
278
|
Policy.new
|
279
279
|
end
|
280
280
|
|
281
|
-
yield policy if
|
281
|
+
yield policy if defined?(yield)
|
282
282
|
policy.freeze
|
283
283
|
end
|
284
284
|
|
@@ -287,7 +287,7 @@ class Roda
|
|
287
287
|
# current content security policy.
|
288
288
|
def content_security_policy
|
289
289
|
policy = @_response.content_security_policy
|
290
|
-
yield policy if
|
290
|
+
yield policy if defined?(yield)
|
291
291
|
policy
|
292
292
|
end
|
293
293
|
end
|
@@ -394,20 +394,32 @@ class Roda
|
|
394
394
|
dsl
|
395
395
|
end
|
396
396
|
|
397
|
-
# Add branch handler for the given namespace and segment.
|
397
|
+
# Add branch handler for the given namespace and segment. If called without
|
398
|
+
# a block, removes the existing branch handler if it exists.
|
398
399
|
def hash_branch(namespace='', segment, &block)
|
399
400
|
segment = "/#{segment}"
|
400
401
|
routes = opts[:hash_branches][namespace] ||= {}
|
401
|
-
|
402
|
+
if block
|
403
|
+
routes[segment] = define_roda_method(routes[segment] || "hash_branch_#{namespace}_#{segment}", 1, &convert_route_block(block))
|
404
|
+
elsif meth = routes[segment]
|
405
|
+
routes.delete(segment)
|
406
|
+
remove_method(meth)
|
407
|
+
end
|
402
408
|
end
|
403
409
|
|
404
410
|
# Add path handler for the given namespace and path. When the
|
405
411
|
# r.hash_paths method is called, checks the matching namespace
|
406
412
|
# for the full remaining path, and dispatch to that block if
|
407
|
-
# there is one.
|
413
|
+
# there is one. If called without a block, removes the existing
|
414
|
+
# path handler if it exists.
|
408
415
|
def hash_path(namespace='', path, &block)
|
409
416
|
routes = opts[:hash_paths][namespace] ||= {}
|
410
|
-
|
417
|
+
if block
|
418
|
+
routes[path] = define_roda_method(routes[path] || "hash_path_#{namespace}_#{path}", 1, &convert_route_block(block))
|
419
|
+
elsif meth = routes[path]
|
420
|
+
routes.delete(path)
|
421
|
+
remove_method(meth)
|
422
|
+
end
|
411
423
|
end
|
412
424
|
end
|
413
425
|
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
class Roda
|
5
|
+
module RodaPlugins
|
6
|
+
# The inject_erb plugin allows you to inject content directly
|
7
|
+
# into the template output:
|
8
|
+
#
|
9
|
+
# <% inject_erb("Some HTML Here") %>
|
10
|
+
#
|
11
|
+
# This will inject <tt>Some HTML Here</tt> into the template output,
|
12
|
+
# even though the tag being used is <tt><%</tt> and not <tt><%=</tt>.
|
13
|
+
#
|
14
|
+
# This method can be used inside methods, such as to wrap calls to
|
15
|
+
# methods that accept template blocks, to inject code before and after
|
16
|
+
# the template blocks.
|
17
|
+
module InjectERB
|
18
|
+
def self.load_dependencies(app)
|
19
|
+
app.plugin :render
|
20
|
+
end
|
21
|
+
|
22
|
+
module InstanceMethods
|
23
|
+
# Inject into the template output for the template currently being
|
24
|
+
# rendered.
|
25
|
+
def inject_erb(value)
|
26
|
+
instance_variable_get(render_opts[:template_opts][:outvar]) << value.to_s
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
register_plugin(:inject_erb, InjectERB)
|
32
|
+
end
|
33
|
+
end
|
@@ -72,7 +72,7 @@ class Roda
|
|
72
72
|
end
|
73
73
|
|
74
74
|
if mod
|
75
|
-
raise RodaError, "can't provide both argument and block to response_module" if
|
75
|
+
raise RodaError, "can't provide both argument and block to response_module" if defined?(yield)
|
76
76
|
klass.send(:include, mod)
|
77
77
|
else
|
78
78
|
if instance_variable_defined?(iv)
|
@@ -98,6 +98,7 @@ class Roda
|
|
98
98
|
self::RodaRequest.named_route_regexp(k)
|
99
99
|
end
|
100
100
|
self::RodaRequest.instance_variable_get(:@namespaced_route_regexps).freeze
|
101
|
+
self
|
101
102
|
end
|
102
103
|
|
103
104
|
# Copy the named routes into the subclass when inheriting.
|
@@ -140,7 +141,7 @@ class Roda
|
|
140
141
|
def multi_route(namespace=nil)
|
141
142
|
on self.class.named_route_regexp(namespace) do |section|
|
142
143
|
res = route(section, namespace)
|
143
|
-
if
|
144
|
+
if defined?(yield)
|
144
145
|
yield
|
145
146
|
else
|
146
147
|
res
|
@@ -45,6 +45,9 @@ class Roda
|
|
45
45
|
# subtrees, multi_run is a better approach, but it does not let you set instance
|
46
46
|
# variables in the main Roda app and have those instance variables usable in
|
47
47
|
# the routing subtrees.
|
48
|
+
#
|
49
|
+
# To handle development environments that reload code, you can call the
|
50
|
+
# +run+ class method without an app to remove dispatching for the prefix.
|
48
51
|
module MultiRun
|
49
52
|
# Initialize the storage for the dispatched applications
|
50
53
|
def self.configure(app)
|
@@ -67,8 +70,12 @@ class Roda
|
|
67
70
|
|
68
71
|
# Add a rack application to dispatch to for the given prefix when
|
69
72
|
# r.multi_run is called.
|
70
|
-
def run(prefix, app)
|
71
|
-
|
73
|
+
def run(prefix, app=nil)
|
74
|
+
if app
|
75
|
+
multi_run_apps[prefix.to_s] = app
|
76
|
+
else
|
77
|
+
multi_run_apps.delete(prefix.to_s)
|
78
|
+
end
|
72
79
|
self::RodaRequest.refresh_multi_run_regexp!
|
73
80
|
end
|
74
81
|
end
|
@@ -91,7 +98,7 @@ class Roda
|
|
91
98
|
# dispatch the request to the stored rack application.
|
92
99
|
def multi_run
|
93
100
|
on self.class.multi_run_regexp do |prefix|
|
94
|
-
yield prefix if
|
101
|
+
yield prefix if defined?(yield)
|
95
102
|
run scope.class.multi_run_apps[prefix]
|
96
103
|
end
|
97
104
|
end
|
@@ -38,6 +38,9 @@ class Roda
|
|
38
38
|
# Note that in multi-threaded code, you should not attempt to add a
|
39
39
|
# named route after accepting requests.
|
40
40
|
#
|
41
|
+
# To handle development environments that reload code, you can call the
|
42
|
+
# +route+ class method without a block to remove an existing named route.
|
43
|
+
#
|
41
44
|
# == Routing Files
|
42
45
|
#
|
43
46
|
# The convention when using the named_routes plugin is to have a single
|
@@ -124,7 +127,7 @@ class Roda
|
|
124
127
|
# The names for the currently stored named routes
|
125
128
|
def named_routes(namespace=nil)
|
126
129
|
unless routes = opts[:namespaced_routes][namespace]
|
127
|
-
raise RodaError, "unsupported
|
130
|
+
raise RodaError, "unsupported named_routes namespace used: #{namespace.inspect}"
|
128
131
|
end
|
129
132
|
routes.keys
|
130
133
|
end
|
@@ -140,7 +143,12 @@ class Roda
|
|
140
143
|
def route(name=nil, namespace=nil, &block)
|
141
144
|
if name
|
142
145
|
routes = opts[:namespaced_routes][namespace] ||= {}
|
143
|
-
|
146
|
+
if block
|
147
|
+
routes[name] = define_roda_method(routes[name] || "named_routes_#{namespace}_#{name}", 1, &convert_route_block(block))
|
148
|
+
elsif meth = routes[name]
|
149
|
+
routes.delete(name)
|
150
|
+
remove_method(meth)
|
151
|
+
end
|
144
152
|
else
|
145
153
|
super(&block)
|
146
154
|
end
|
data/lib/roda/plugins/path.rb
CHANGED
@@ -41,12 +41,12 @@ class Roda
|
|
41
41
|
# end
|
42
42
|
#
|
43
43
|
# r.post 'baz' do
|
44
|
-
#
|
44
|
+
# baz = Baz[1]
|
45
45
|
# r.redirect path(baz, 'c', 'd') # /baz/1/c/d
|
46
46
|
# end
|
47
47
|
#
|
48
48
|
# r.post 'quux' do
|
49
|
-
#
|
49
|
+
# quux = Quux[1]
|
50
50
|
# r.redirect url(quux, '/bar') # http://example.com/quux/1/bar
|
51
51
|
# end
|
52
52
|
# end
|
@@ -148,11 +148,17 @@ class Roda
|
|
148
148
|
# Allow calling private _method to get path
|
149
149
|
relative_path(request.script_name.to_s + send(_meth, *a, &blk))
|
150
150
|
end
|
151
|
+
# :nocov:
|
152
|
+
ruby2_keywords(meth) if respond_to?(:ruby2_keywords, true)
|
153
|
+
# :nocov:
|
151
154
|
elsif add_script_name
|
152
155
|
define_method(meth) do |*a, &blk|
|
153
156
|
# Allow calling private _method to get path
|
154
157
|
request.script_name.to_s + send(_meth, *a, &blk)
|
155
158
|
end
|
159
|
+
# :nocov:
|
160
|
+
ruby2_keywords(meth) if respond_to?(:ruby2_keywords, true)
|
161
|
+
# :nocov:
|
156
162
|
else
|
157
163
|
define_method(meth, &block)
|
158
164
|
end
|
@@ -171,6 +177,9 @@ class Roda
|
|
171
177
|
end
|
172
178
|
|
173
179
|
define_method(url_meth, &url_block)
|
180
|
+
# :nocov:
|
181
|
+
ruby2_keywords(url_meth) if respond_to?(:ruby2_keywords, true)
|
182
|
+
# :nocov:
|
174
183
|
end
|
175
184
|
|
176
185
|
nil
|
data/lib/roda/plugins/render.rb
CHANGED
@@ -47,7 +47,7 @@ class Roda
|
|
47
47
|
# The following plugin options are supported:
|
48
48
|
#
|
49
49
|
# :allowed_paths :: Set the template paths to allow. Attempts to render paths outside
|
50
|
-
# of
|
50
|
+
# of these paths will raise an error. Defaults to the +:views+ directory.
|
51
51
|
# :cache :: nil/false to explicitly disable premanent template caching. By default, permanent
|
52
52
|
# template caching is disabled by default if RACK_ENV is development. When permanent
|
53
53
|
# template caching is disabled, for templates with paths in the file system, the
|
@@ -59,9 +59,9 @@ class Roda
|
|
59
59
|
# templates, defaults to 'erb'.
|
60
60
|
# :escape :: Use Erubi as the ERB template engine, and enable escaping by default,
|
61
61
|
# which makes <tt><%= %></tt> escape output and <tt><%== %></tt> not escape output.
|
62
|
-
# If given, sets the <tt
|
62
|
+
# If given, sets the <tt>escape: true</tt> option for all template engines, which
|
63
63
|
# can break some non-ERB template engines. You can use a string or array of strings
|
64
|
-
# as the value for this option to only set the <tt
|
64
|
+
# as the value for this option to only set the <tt>escape: true</tt> option for those
|
65
65
|
# specific template engines.
|
66
66
|
# :layout :: The base name of the layout file, defaults to 'layout'. This can be provided as a hash
|
67
67
|
# with the :template or :inline options.
|
@@ -130,6 +130,84 @@ class Roda
|
|
130
130
|
# only argument, you can speed things up by specifying a +:cache_key+ option in
|
131
131
|
# the hash, making sure the +:cache_key+ is unique to the template you are
|
132
132
|
# rendering.
|
133
|
+
#
|
134
|
+
# = Accepting Template Blocks in Methods
|
135
|
+
#
|
136
|
+
# If you are used to Rails, you may be surprised that this type of template code
|
137
|
+
# doesn't work in Roda:
|
138
|
+
#
|
139
|
+
# <%= some_method do %>
|
140
|
+
# Some HTML
|
141
|
+
# <% end %>
|
142
|
+
#
|
143
|
+
# The reason this doesn't work is that this is not valid ERB syntax, it is Rails syntax,
|
144
|
+
# and requires attempting to parse the <tt>some_method do</tt> Ruby code with a regular
|
145
|
+
# expression. Since Roda uses ERB syntax, it does not support this.
|
146
|
+
#
|
147
|
+
# In general, these methods are used to wrap the content of the block and
|
148
|
+
# inject the content into the output. To get similar behavior with Roda, you have
|
149
|
+
# a few different options you can use.
|
150
|
+
#
|
151
|
+
# == Directly Inject Template Output
|
152
|
+
#
|
153
|
+
# You can switch from a <tt><%=</tt> tag to using a <tt><%</tt> tag:
|
154
|
+
#
|
155
|
+
# <% some_method do %>
|
156
|
+
# Some HTML
|
157
|
+
# <% end %>
|
158
|
+
#
|
159
|
+
# While this would output <tt>Some HTML</tt> into the template, it would not be able
|
160
|
+
# to inject content before or after the block. However, you can use the inject_erb_plugin
|
161
|
+
# to handle the injection:
|
162
|
+
#
|
163
|
+
# def some_method
|
164
|
+
# inject_erb "content before block"
|
165
|
+
# yield
|
166
|
+
# inject_erb "content after block"
|
167
|
+
# end
|
168
|
+
#
|
169
|
+
# If you need to modify the captured block before injecting it, you can use the
|
170
|
+
# capture_erb plugin to capture content from the template block, and modify that content,
|
171
|
+
# then use inject_erb to inject it into the template output:
|
172
|
+
#
|
173
|
+
# def some_method(&block)
|
174
|
+
# inject_erb "content before block"
|
175
|
+
# inject_erb capture_erb(&block).upcase
|
176
|
+
# inject_erb "content after block"
|
177
|
+
# end
|
178
|
+
#
|
179
|
+
# This is the recommended approach for handling this type of method, if you want to keep
|
180
|
+
# the template block in the same template.
|
181
|
+
#
|
182
|
+
# == Separate Block Output Into Separate Template
|
183
|
+
#
|
184
|
+
# By moving the <tt>Some HTML</tt> into a separate template, you can render that
|
185
|
+
# template inside the block:
|
186
|
+
#
|
187
|
+
# <%= some_method{render('template_name')} %>
|
188
|
+
#
|
189
|
+
# It's also possible to use an inline template:
|
190
|
+
#
|
191
|
+
# <%= some_method do render(:inline=><<-END)
|
192
|
+
# Some HTML
|
193
|
+
# END
|
194
|
+
# end %>
|
195
|
+
#
|
196
|
+
# This approach is useful if it makes sense to separate the template block into its
|
197
|
+
# own template. You lose the ability to use local variable from outside the
|
198
|
+
# template block inside the template block with this approach.
|
199
|
+
#
|
200
|
+
# == Separate Header and Footer
|
201
|
+
#
|
202
|
+
# You can define two separate methods, one that outputs the content before the block,
|
203
|
+
# and one that outputs the content after the block, and use those instead of a single
|
204
|
+
# call:
|
205
|
+
#
|
206
|
+
# <%= some_method_before %>
|
207
|
+
# Some HTML
|
208
|
+
# <%= some_method_after %>
|
209
|
+
#
|
210
|
+
# This is the simplest option to setup, but it is fairly tedious to use.
|
133
211
|
module Render
|
134
212
|
# Support for using compiled methods directly requires Ruby 2.3 for the
|
135
213
|
# method binding to work, and Tilt 1.2 for Tilt::Template#compiled_method.
|
@@ -384,7 +384,7 @@ class Roda
|
|
384
384
|
|
385
385
|
# Set or retrieve the response body. When a block is given,
|
386
386
|
# evaluation is deferred until the body is needed.
|
387
|
-
def body(value = (return @body unless
|
387
|
+
def body(value = (return @body unless defined?(yield); nil), &block)
|
388
388
|
if block
|
389
389
|
@body = DelayedBody.new(&block)
|
390
390
|
else
|
@@ -6,8 +6,7 @@ class Roda
|
|
6
6
|
# The status_303 plugin sets the default redirect status to be 303
|
7
7
|
# rather than 302 when the request is not a GET and the
|
8
8
|
# redirection occurs on an HTTP 1.1 connection as per RFC 7231.
|
9
|
-
#
|
10
|
-
# practice.
|
9
|
+
# There are some frontend frameworks that require this behavior.
|
11
10
|
#
|
12
11
|
# Example:
|
13
12
|
#
|
@@ -265,6 +265,23 @@ class Roda
|
|
265
265
|
# If you would like to skip this check and allow null bytes in param string values,
|
266
266
|
# you can do by passing the <tt>:allow_null_bytes</tt> option when loading the plugin.
|
267
267
|
#
|
268
|
+
# You can use the :date_parse_input_handler option to specify custom handling of date
|
269
|
+
# parsing input. Modern versions of Ruby and the date gem internally raise if the input to
|
270
|
+
# date parsing methods is too large to prevent denial of service. If you are using an
|
271
|
+
# older version of Ruby, you can use this option to enforce the same check:
|
272
|
+
#
|
273
|
+
# plugin :typecast_params, date_parse_input_handler: proc {|string|
|
274
|
+
# raise ArgumentError, "too big" if string.bytesize > 128
|
275
|
+
# string
|
276
|
+
# }
|
277
|
+
#
|
278
|
+
# You can also use this option to modify the input, such as truncating it to the first
|
279
|
+
# 128 bytes:
|
280
|
+
#
|
281
|
+
# plugin :typecast_params, date_parse_input_handler: proc {|string|
|
282
|
+
# string.b[0, 128]
|
283
|
+
# }
|
284
|
+
#
|
268
285
|
# By design, typecast_params only deals with string keys, it is not possible to use
|
269
286
|
# symbol keys as arguments to the conversion methods and have them converted.
|
270
287
|
module TypecastParams
|
@@ -384,6 +401,14 @@ class Roda
|
|
384
401
|
end
|
385
402
|
end
|
386
403
|
|
404
|
+
module DateParseInputHandler
|
405
|
+
# Pass input string to date parsing through handle_date_parse_input.
|
406
|
+
def _string_parse!(klass, v)
|
407
|
+
v = handle_date_parse_input(v)
|
408
|
+
super
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
387
412
|
# Class handling conversion of submitted parameters to desired types.
|
388
413
|
class Params
|
389
414
|
# Handle conversions for the given type using the given block.
|
@@ -564,7 +589,7 @@ class Roda
|
|
564
589
|
end
|
565
590
|
|
566
591
|
v = @obj[key]
|
567
|
-
v = yield if v.nil? &&
|
592
|
+
v = yield if v.nil? && defined?(yield)
|
568
593
|
|
569
594
|
begin
|
570
595
|
sub = self.class.nest(v, Array(@nesting) + [key])
|
@@ -580,7 +605,7 @@ class Roda
|
|
580
605
|
# Return the nested value for key. If there is no nested_value for +key+,
|
581
606
|
# calls the block to return the value, or returns nil if there is no block given.
|
582
607
|
def fetch(key)
|
583
|
-
send(:[], key){return(yield if
|
608
|
+
send(:[], key){return(yield if defined?(yield))}
|
584
609
|
end
|
585
610
|
|
586
611
|
# Captures conversions inside the given block, and returns a hash of all conversions,
|
@@ -999,11 +1024,16 @@ class Roda
|
|
999
1024
|
when ''
|
1000
1025
|
nil
|
1001
1026
|
when String
|
1002
|
-
klass
|
1027
|
+
_string_parse!(klass, v)
|
1003
1028
|
else
|
1004
1029
|
raise Error, "unexpected value received: #{v.inspect}"
|
1005
1030
|
end
|
1006
1031
|
end
|
1032
|
+
|
1033
|
+
# Handle parsing for string values passed to parse!.
|
1034
|
+
def _string_parse!(klass, v)
|
1035
|
+
klass.parse(v)
|
1036
|
+
end
|
1007
1037
|
end
|
1008
1038
|
|
1009
1039
|
# Set application-specific Params subclass unless one has been set,
|
@@ -1019,6 +1049,14 @@ class Roda
|
|
1019
1049
|
if opts[:allow_null_bytes]
|
1020
1050
|
app::TypecastParams.send(:include, AllowNullByte)
|
1021
1051
|
end
|
1052
|
+
if opts[:date_parse_input_handler]
|
1053
|
+
app::TypecastParams.class_eval do
|
1054
|
+
include DateParseInputHandler
|
1055
|
+
define_method(:handle_date_parse_input, &opts[:date_parse_input_handler])
|
1056
|
+
private :handle_date_parse_input
|
1057
|
+
alias handle_date_parse_input handle_date_parse_input
|
1058
|
+
end
|
1059
|
+
end
|
1022
1060
|
end
|
1023
1061
|
|
1024
1062
|
module ClassMethods
|
data/lib/roda/request.rb
CHANGED
@@ -520,7 +520,7 @@ class Roda
|
|
520
520
|
if matchdata = pattern.match(@remaining_path)
|
521
521
|
@remaining_path = matchdata.post_match
|
522
522
|
captures = matchdata.captures
|
523
|
-
captures = yield(*captures) if
|
523
|
+
captures = yield(*captures) if defined?(yield)
|
524
524
|
@captures.concat(captures)
|
525
525
|
end
|
526
526
|
end
|
data/lib/roda/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: roda
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.52.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Evans
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-01-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -94,20 +94,6 @@ dependencies:
|
|
94
94
|
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
|
-
- !ruby/object:Gem::Dependency
|
98
|
-
name: haml
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
100
|
-
requirements:
|
101
|
-
- - ">="
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version: '0'
|
104
|
-
type: :development
|
105
|
-
prerelease: false
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
107
|
-
requirements:
|
108
|
-
- - ">="
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: '0'
|
111
97
|
- !ruby/object:Gem::Dependency
|
112
98
|
name: rack_csrf
|
113
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -219,7 +205,11 @@ extra_rdoc_files:
|
|
219
205
|
- doc/release_notes/3.46.0.txt
|
220
206
|
- doc/release_notes/3.47.0.txt
|
221
207
|
- doc/release_notes/3.48.0.txt
|
208
|
+
- doc/release_notes/3.49.0.txt
|
222
209
|
- doc/release_notes/3.5.0.txt
|
210
|
+
- doc/release_notes/3.50.0.txt
|
211
|
+
- doc/release_notes/3.51.0.txt
|
212
|
+
- doc/release_notes/3.52.0.txt
|
223
213
|
- doc/release_notes/3.6.0.txt
|
224
214
|
- doc/release_notes/3.7.0.txt
|
225
215
|
- doc/release_notes/3.8.0.txt
|
@@ -274,7 +264,11 @@ files:
|
|
274
264
|
- doc/release_notes/3.46.0.txt
|
275
265
|
- doc/release_notes/3.47.0.txt
|
276
266
|
- doc/release_notes/3.48.0.txt
|
267
|
+
- doc/release_notes/3.49.0.txt
|
277
268
|
- doc/release_notes/3.5.0.txt
|
269
|
+
- doc/release_notes/3.50.0.txt
|
270
|
+
- doc/release_notes/3.51.0.txt
|
271
|
+
- doc/release_notes/3.52.0.txt
|
278
272
|
- doc/release_notes/3.6.0.txt
|
279
273
|
- doc/release_notes/3.7.0.txt
|
280
274
|
- doc/release_notes/3.8.0.txt
|
@@ -292,6 +286,7 @@ files:
|
|
292
286
|
- lib/roda/plugins/backtracking_array.rb
|
293
287
|
- lib/roda/plugins/branch_locals.rb
|
294
288
|
- lib/roda/plugins/caching.rb
|
289
|
+
- lib/roda/plugins/capture_erb.rb
|
295
290
|
- lib/roda/plugins/chunked.rb
|
296
291
|
- lib/roda/plugins/class_level_routing.rb
|
297
292
|
- lib/roda/plugins/class_matchers.rb
|
@@ -327,6 +322,7 @@ files:
|
|
327
322
|
- lib/roda/plugins/hooks.rb
|
328
323
|
- lib/roda/plugins/host_authorization.rb
|
329
324
|
- lib/roda/plugins/indifferent_params.rb
|
325
|
+
- lib/roda/plugins/inject_erb.rb
|
330
326
|
- lib/roda/plugins/json.rb
|
331
327
|
- lib/roda/plugins/json_parser.rb
|
332
328
|
- lib/roda/plugins/mail_processor.rb
|
@@ -400,7 +396,7 @@ metadata:
|
|
400
396
|
bug_tracker_uri: https://github.com/jeremyevans/roda/issues
|
401
397
|
changelog_uri: http://roda.jeremyevans.net/rdoc/files/CHANGELOG.html
|
402
398
|
documentation_uri: http://roda.jeremyevans.net/documentation.html
|
403
|
-
mailing_list_uri: https://
|
399
|
+
mailing_list_uri: https://github.com/jeremyevans/roda/discussions
|
404
400
|
source_code_uri: https://github.com/jeremyevans/roda
|
405
401
|
post_install_message:
|
406
402
|
rdoc_options: []
|
@@ -417,7 +413,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
417
413
|
- !ruby/object:Gem::Version
|
418
414
|
version: '0'
|
419
415
|
requirements: []
|
420
|
-
rubygems_version: 3.
|
416
|
+
rubygems_version: 3.3.3
|
421
417
|
signing_key:
|
422
418
|
specification_version: 4
|
423
419
|
summary: Routing tree web toolkit
|