roda 3.48.0 → 3.52.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 +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
|