roda 3.16.0 → 3.17.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 +10 -0
- data/doc/release_notes/3.17.0.txt +62 -0
- data/lib/roda.rb +71 -12
- data/lib/roda/plugins/_after_hook.rb +10 -12
- data/lib/roda/plugins/_before_hook.rb +2 -40
- data/lib/roda/plugins/class_level_routing.rb +2 -5
- data/lib/roda/plugins/common_logger.rb +0 -5
- data/lib/roda/plugins/flash.rb +0 -4
- data/lib/roda/plugins/head.rb +0 -4
- data/lib/roda/plugins/heartbeat.rb +0 -4
- data/lib/roda/plugins/hooks.rb +0 -5
- data/lib/roda/plugins/mail_processor.rb +1 -1
- data/lib/roda/plugins/mailer.rb +1 -1
- data/lib/roda/plugins/multi_route.rb +1 -1
- data/lib/roda/plugins/render.rb +1 -1
- data/lib/roda/plugins/route_block_args.rb +49 -0
- data/lib/roda/plugins/sessions.rb +0 -4
- data/lib/roda/plugins/static_routing.rb +1 -5
- data/lib/roda/plugins/status_handler.rb +3 -5
- data/lib/roda/version.rb +1 -1
- data/spec/plugin/_after_hook_spec.rb +19 -0
- data/spec/plugin/class_level_routing_spec.rb +27 -0
- data/spec/plugin/mail_processor_spec.rb +49 -0
- data/spec/plugin/mailer_spec.rb +34 -0
- data/spec/plugin/multi_route_spec.rb +14 -18
- data/spec/plugin/render_spec.rb +2 -2
- data/spec/plugin/route_block_args_spec.rb +86 -0
- data/spec/plugin/static_routing_spec.rb +22 -0
- data/spec/plugin/view_options_spec.rb +44 -0
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ea47f91d6b930ef7822fef3781ef11f959ace8f9e6a907f24481c5f797678482
|
4
|
+
data.tar.gz: 13b182e1651d996e1493078301888b6671dd91ea0516f441ad1bc59cba940d6d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2bc04891739a93f46839abf14fd915b2f470e835e6c200fa1f8fd8a168cda13406c424fa0e1cc1eee5ce0e1e50b0dfbbe6440d27bec2112a2c6cf3dc83951ffc
|
7
|
+
data.tar.gz: 68a1ec7f9ead2ce2fda252d36c7edf0df3c53d1aa02a246669d8d0700afd65d1a010179be92c1973b9c511386df39e2b7d1fd041228add83d2ef344e9d49a475
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
= 3.17.0 (2019-02-15)
|
2
|
+
|
3
|
+
* Improve performance in the common case for RodaResponse#finish (jeremyevans)
|
4
|
+
|
5
|
+
* Support before hooks in the hooks plugin in the mailer and mail_processor plugins (jeremyevans)
|
6
|
+
|
7
|
+
* Allow set_layout_opts in view_options plugin to override layout if render plugin :layout option is given (jeremyevans)
|
8
|
+
|
9
|
+
* Add route_block_args plugin to control which arguments are yielded to the route block (jeremyevans, chrisfrank) (#159)
|
10
|
+
|
1
11
|
= 3.16.0 (2019-01-18)
|
2
12
|
|
3
13
|
* Add mail_processor plugin for processing mail using a routing tree (jeremyevans)
|
@@ -0,0 +1,62 @@
|
|
1
|
+
= New Features
|
2
|
+
|
3
|
+
* A route_block_args plugin has been added, allowing you to customize
|
4
|
+
which objects are yielded to the the route block. You call the
|
5
|
+
plugin with a block, which is evaluated in the context of the
|
6
|
+
instance and should return an array of arguments for the instance
|
7
|
+
to yield to the route block.
|
8
|
+
|
9
|
+
To yield both the request and response objects, you can do:
|
10
|
+
|
11
|
+
plugin :route_block_args do |r|
|
12
|
+
[r, response]
|
13
|
+
end
|
14
|
+
|
15
|
+
route do |r, response|
|
16
|
+
# ...
|
17
|
+
end
|
18
|
+
|
19
|
+
In addition to the main route block, using this plugin also affects
|
20
|
+
the arguments passed to routing blocks in the following plugins:
|
21
|
+
|
22
|
+
* class_level_routing
|
23
|
+
* mailer
|
24
|
+
* mail_processor
|
25
|
+
* multi_route
|
26
|
+
* static_routing
|
27
|
+
|
28
|
+
= Other Improvements
|
29
|
+
|
30
|
+
* The set_layout_opts method in the view_options plugin can now
|
31
|
+
override the layout template even if the render plugin :layout
|
32
|
+
option is given.
|
33
|
+
|
34
|
+
* The mailer and mail_processor plugin now integrate with the hooks
|
35
|
+
plugin to support before/after hooks.
|
36
|
+
|
37
|
+
* Dispatching to the route block and RodaResponse#finish are both
|
38
|
+
slightly faster.
|
39
|
+
|
40
|
+
* Internal before hook handling has been moved from an internal
|
41
|
+
plugin into the core, and modified so that if you are not using
|
42
|
+
the internal before hook in any plugin, there is no runtime cost.
|
43
|
+
|
44
|
+
* The core now recognizes when plugins are using the internal after
|
45
|
+
hook, and automatically loads the internal plugin supporting the
|
46
|
+
after hook.
|
47
|
+
|
48
|
+
= Backwards Compatibility
|
49
|
+
|
50
|
+
* When using the render plugin with a :layout option, the render_opts
|
51
|
+
:layout option will be set to true if the layout is enabled.
|
52
|
+
Previously, the render_opts :layout option would retain the value
|
53
|
+
given as the plugin option. Options for the layout (including the
|
54
|
+
template) are still available in the render_opts :layout_opts
|
55
|
+
option. This change was made to fix the set_layout_opts bug in the
|
56
|
+
view_options plugin.
|
57
|
+
|
58
|
+
* RodaResponse#initialize no longer sets the response status to nil
|
59
|
+
if it was already set.
|
60
|
+
|
61
|
+
* RodaResponse#finish no longer sets the status on the receiver, it
|
62
|
+
just uses the receiver's status to set the rack response status.
|
data/lib/roda.rb
CHANGED
@@ -60,7 +60,9 @@ class Roda
|
|
60
60
|
@inherit_middleware = true
|
61
61
|
@middleware = []
|
62
62
|
@opts = {}
|
63
|
+
@raw_route_block = nil
|
63
64
|
@route_block = nil
|
65
|
+
@rack_app_route_block = nil
|
64
66
|
|
65
67
|
# Module in which all Roda plugins should be stored. Also contains logic for
|
66
68
|
# registering and loading plugins.
|
@@ -161,6 +163,15 @@ class Roda
|
|
161
163
|
super
|
162
164
|
end
|
163
165
|
|
166
|
+
# Rebuild the _roda_before and _roda_after methods whenever a plugin might
|
167
|
+
# have added a _roda_before_* or _roda_after_* method.
|
168
|
+
def include(*a)
|
169
|
+
res = super
|
170
|
+
def_roda_before
|
171
|
+
def_roda_after
|
172
|
+
res
|
173
|
+
end
|
174
|
+
|
164
175
|
# When inheriting Roda, copy the shared data into the subclass,
|
165
176
|
# and setup the request and response subclasses.
|
166
177
|
def inherited(subclass)
|
@@ -174,8 +185,9 @@ class Roda
|
|
174
185
|
subclass.opts[k] = v.dup
|
175
186
|
end
|
176
187
|
end
|
177
|
-
|
178
|
-
|
188
|
+
if block = @raw_route_block
|
189
|
+
subclass.route(&block)
|
190
|
+
end
|
179
191
|
|
180
192
|
request_class = Class.new(self::RodaRequest)
|
181
193
|
request_class.roda_class = subclass
|
@@ -221,7 +233,9 @@ class Roda
|
|
221
233
|
# This should only be called once per class, and if called multiple
|
222
234
|
# times will overwrite the previous routing.
|
223
235
|
def route(&block)
|
224
|
-
@
|
236
|
+
@raw_route_block = block
|
237
|
+
@route_block = block = convert_route_block(block)
|
238
|
+
@rack_app_route_block = rack_app_route_block(block)
|
225
239
|
build_rack_app
|
226
240
|
end
|
227
241
|
|
@@ -238,8 +252,7 @@ class Roda
|
|
238
252
|
|
239
253
|
# Build the rack app to use
|
240
254
|
def build_rack_app
|
241
|
-
if block = @
|
242
|
-
block = rack_app_route_block(block)
|
255
|
+
if block = @rack_app_route_block
|
243
256
|
app = lambda{|env| new(env).call(&block)}
|
244
257
|
@middleware.reverse_each do |args, bl|
|
245
258
|
mid, *args = args
|
@@ -250,11 +263,54 @@ class Roda
|
|
250
263
|
end
|
251
264
|
end
|
252
265
|
|
253
|
-
#
|
266
|
+
# Modify the route block to use for any route block provided as input,
|
267
|
+
# which can include route blocks that are delegated to by the main route block.
|
254
268
|
# Can be modified by plugins.
|
255
|
-
def
|
269
|
+
def convert_route_block(block)
|
256
270
|
block
|
257
271
|
end
|
272
|
+
|
273
|
+
# Build a _roda_before method that calls each _roda_before_* method
|
274
|
+
# in order, if any _roda_before_* methods are defined. Also, rebuild
|
275
|
+
# the route block if a _roda_before method is defined.
|
276
|
+
def def_roda_before
|
277
|
+
meths = private_instance_methods.grep(/\A_roda_before_\d\d/).sort.join(';')
|
278
|
+
unless meths.empty?
|
279
|
+
class_eval("def _roda_before; #{meths} end", __FILE__, __LINE__)
|
280
|
+
private :_roda_before
|
281
|
+
if @raw_route_block
|
282
|
+
route(&@raw_route_block)
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
# Build a _roda_after method that calls each _roda_after_* method
|
288
|
+
# in order, if any _roda_after_* methods are defined. Also, use
|
289
|
+
# the internal after hook plugin if the _roda_after method is defined.
|
290
|
+
def def_roda_after
|
291
|
+
meths = private_instance_methods.grep(/\A_roda_after_\d\d/).sort.map{|s| "#{s}(res)"}.join(';')
|
292
|
+
unless meths.empty?
|
293
|
+
plugin :_after_hook unless private_method_defined?(:_roda_after)
|
294
|
+
class_eval("def _roda_after(res); #{meths} end", __FILE__, __LINE__)
|
295
|
+
private :_roda_after
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
# The route block to use when building the rack app (or other initial
|
300
|
+
# entry point to the route block).
|
301
|
+
# By default, modifies the rack app route block to support before hooks
|
302
|
+
# if any before hooks are defined.
|
303
|
+
# Can be modified by plugins.
|
304
|
+
def rack_app_route_block(block)
|
305
|
+
if private_method_defined?(:_roda_before)
|
306
|
+
lambda do |r|
|
307
|
+
_roda_before
|
308
|
+
instance_exec(r, &block)
|
309
|
+
end
|
310
|
+
else
|
311
|
+
block
|
312
|
+
end
|
313
|
+
end
|
258
314
|
end
|
259
315
|
|
260
316
|
# Instance methods for the Roda class.
|
@@ -936,7 +992,6 @@ class Roda
|
|
936
992
|
|
937
993
|
# Set the default headers when creating a response.
|
938
994
|
def initialize
|
939
|
-
@status = nil
|
940
995
|
@headers = {}
|
941
996
|
@body = []
|
942
997
|
@length = 0
|
@@ -986,14 +1041,18 @@ class Roda
|
|
986
1041
|
# # []]
|
987
1042
|
def finish
|
988
1043
|
b = @body
|
989
|
-
empty = b.empty?
|
990
|
-
s = (@status ||= empty ? 404 : default_status)
|
991
1044
|
set_default_headers
|
992
1045
|
h = @headers
|
993
1046
|
|
994
|
-
if empty
|
995
|
-
|
1047
|
+
if b.empty?
|
1048
|
+
s = @status || 404
|
1049
|
+
if (s == 304 || s == 204 || s == 205 || (s >= 100 && s <= 199))
|
1050
|
+
h.delete("Content-Type")
|
1051
|
+
else
|
1052
|
+
h["Content-Length"] ||= '0'
|
1053
|
+
end
|
996
1054
|
else
|
1055
|
+
s = @status || default_status
|
997
1056
|
h["Content-Length"] ||= @length.to_s
|
998
1057
|
end
|
999
1058
|
|
@@ -7,19 +7,10 @@ class Roda
|
|
7
7
|
# Allows for plugins to configure the order in which
|
8
8
|
# after processing is done by using _roda_after_*
|
9
9
|
# private instance methods that are called in sorted order.
|
10
|
+
# Loaded automatically by the base library if any _roda_after_*
|
11
|
+
# methods are defined.
|
10
12
|
module AfterHook # :nodoc:
|
11
|
-
|
12
|
-
# Rebuild the _roda_after method whenever a plugin might
|
13
|
-
# have added a _roda_after_* method.
|
14
|
-
def include(*)
|
15
|
-
res = super
|
16
|
-
meths = private_instance_methods.grep(/\A_roda_after_\d\d/).sort.map{|s| "#{s}(res)"}.join(';')
|
17
|
-
class_eval("def _roda_after(res); #{meths} end", __FILE__, __LINE__)
|
18
|
-
private :_roda_after
|
19
|
-
res
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
13
|
+
# Module for internal after hook support.
|
23
14
|
module InstanceMethods
|
24
15
|
# Run internal after hooks with the response
|
25
16
|
def call
|
@@ -27,6 +18,13 @@ class Roda
|
|
27
18
|
ensure
|
28
19
|
_roda_after(res)
|
29
20
|
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
# Empty roda_after method, so nothing breaks if the module is included.
|
25
|
+
# This method will be overridden in most classes using this module.
|
26
|
+
def _roda_after(res)
|
27
|
+
end
|
30
28
|
end
|
31
29
|
end
|
32
30
|
|
@@ -3,47 +3,9 @@
|
|
3
3
|
#
|
4
4
|
class Roda
|
5
5
|
module RodaPlugins
|
6
|
-
#
|
7
|
-
#
|
8
|
-
# before processing is done by using _roda_before_*
|
9
|
-
# private instance methods that are called in sorted order.
|
6
|
+
# Deprecated plugin, only exists for backwards compatibility.
|
7
|
+
# Features are now part of base library.
|
10
8
|
module BeforeHook # :nodoc:
|
11
|
-
# Rebuild the rack app if the rack app already exists,
|
12
|
-
# so the before hooks are setup inside the rack app
|
13
|
-
# route block.
|
14
|
-
def self.configure(app)
|
15
|
-
app.instance_exec do
|
16
|
-
build_rack_app if @app
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
module ClassMethods
|
21
|
-
# Rebuild the _roda_before method whenever a plugin might
|
22
|
-
# have added a _roda_before_* method.
|
23
|
-
def include(*a)
|
24
|
-
res = super
|
25
|
-
def_roda_before
|
26
|
-
res
|
27
|
-
end
|
28
|
-
|
29
|
-
private
|
30
|
-
|
31
|
-
# Build a _roda_before method that calls each _roda_before_* method
|
32
|
-
# in order.
|
33
|
-
def def_roda_before
|
34
|
-
meths = private_instance_methods.grep(/\A_roda_before_\d\d/).sort.join(';')
|
35
|
-
class_eval("def _roda_before; #{meths} end", __FILE__, __LINE__)
|
36
|
-
private :_roda_before
|
37
|
-
end
|
38
|
-
|
39
|
-
# Modify rack app route block to use before hook.
|
40
|
-
def rack_app_route_block(block)
|
41
|
-
lambda do |r|
|
42
|
-
_roda_before
|
43
|
-
instance_exec(r, &block)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
9
|
end
|
48
10
|
|
49
11
|
register_plugin(:_before_hook, BeforeHook)
|
@@ -52,10 +52,6 @@ class Roda
|
|
52
52
|
# the normal +route+ class method to define your routing tree. This plugin does make it simpler to
|
53
53
|
# add additional routes after the routing tree has already been defined, though.
|
54
54
|
module ClassLevelRouting
|
55
|
-
def self.load_dependencies(app)
|
56
|
-
app.plugin :_after_hook
|
57
|
-
end
|
58
|
-
|
59
55
|
# Initialize the class_routes array when the plugin is loaded. Also, if the application doesn't
|
60
56
|
# currently have a routing block, setup an empty routing block so that things will still work if
|
61
57
|
# a routing block isn't added.
|
@@ -68,7 +64,7 @@ class Roda
|
|
68
64
|
# Define routing methods that will store class level routes.
|
69
65
|
[:root, :on, :is, :get, :post, :delete, :head, :options, :link, :patch, :put, :trace, :unlink].each do |meth|
|
70
66
|
define_method(meth) do |*args, &block|
|
71
|
-
opts[:class_level_routes] << [meth, args, block].freeze
|
67
|
+
opts[:class_level_routes] << [meth, args, convert_route_block(block)].freeze
|
72
68
|
end
|
73
69
|
end
|
74
70
|
|
@@ -94,6 +90,7 @@ class Roda
|
|
94
90
|
# Reset the response so it doesn't inherit the status or any headers from
|
95
91
|
# the original response.
|
96
92
|
@_response.send(:initialize)
|
93
|
+
@_response.status = nil
|
97
94
|
result.replace(_call do |r|
|
98
95
|
opts[:class_level_routes].each do |meth, args, blk|
|
99
96
|
r.instance_variable_set(:@remaining_path, @_original_remaining_path)
|
@@ -19,11 +19,6 @@ class Roda
|
|
19
19
|
# plugin :common_logger, $stdout
|
20
20
|
# plugin :common_logger, Logger.new('filename')
|
21
21
|
module CommonLogger
|
22
|
-
def self.load_dependencies(app, _=nil)
|
23
|
-
app.plugin :_after_hook
|
24
|
-
app.plugin :_before_hook
|
25
|
-
end
|
26
|
-
|
27
22
|
def self.configure(app, logger=nil)
|
28
23
|
app.opts[:common_logger] = logger || app.opts[:common_logger] || $stderr
|
29
24
|
app.opts[:common_logger_meth] = app.opts[:common_logger].method(logger.respond_to?(:write) ? :write : :<<)
|
data/lib/roda/plugins/flash.rb
CHANGED
@@ -36,10 +36,6 @@ class Roda
|
|
36
36
|
# flash['a'] # = >'b'
|
37
37
|
# end
|
38
38
|
module Flash
|
39
|
-
def self.load_dependencies(app)
|
40
|
-
app.plugin :_after_hook
|
41
|
-
end
|
42
|
-
|
43
39
|
# Simple flash hash, where assiging to the hash updates the flash
|
44
40
|
# used in the following request.
|
45
41
|
class FlashHash < DelegateClass(Hash)
|
data/lib/roda/plugins/head.rb
CHANGED
@@ -37,10 +37,6 @@ class Roda
|
|
37
37
|
# this plugin those HEAD requests will return a 404 status, which
|
38
38
|
# may prevent search engines from crawling your website.
|
39
39
|
module Head
|
40
|
-
def self.load_dependencies(app)
|
41
|
-
app.plugin :_after_hook
|
42
|
-
end
|
43
|
-
|
44
40
|
# used to ensure proper resource release on HEAD requests
|
45
41
|
# we do not respond to a to_path method, here.
|
46
42
|
class CloseLater
|
@@ -16,10 +16,6 @@ class Roda
|
|
16
16
|
module Heartbeat
|
17
17
|
HEARTBEAT_RESPONSE = [200, {'Content-Type'=>'text/plain'}.freeze, ['OK'.freeze].freeze].freeze
|
18
18
|
|
19
|
-
def self.load_dependencies(app, opts=OPTS)
|
20
|
-
app.plugin :_before_hook
|
21
|
-
end
|
22
|
-
|
23
19
|
# Set the heartbeat path to the given path.
|
24
20
|
def self.configure(app, opts=OPTS)
|
25
21
|
app.opts[:heartbeat_path] = (opts[:path] || app.opts[:heartbeat_path] || "/heartbeat").dup.freeze
|
data/lib/roda/plugins/hooks.rb
CHANGED
@@ -33,11 +33,6 @@ class Roda
|
|
33
33
|
# an after block will not affect the returned status. Note that after
|
34
34
|
# hooks can be called with nil if an exception is raised during routing.
|
35
35
|
module Hooks
|
36
|
-
def self.load_dependencies(app)
|
37
|
-
app.plugin :_before_hook
|
38
|
-
app.plugin :_after_hook
|
39
|
-
end
|
40
|
-
|
41
36
|
def self.configure(app)
|
42
37
|
app.opts[:before_hook] ||= nil
|
43
38
|
app.opts[:after_hook] ||= nil
|
data/lib/roda/plugins/mailer.rb
CHANGED
@@ -140,7 +140,7 @@ class Roda
|
|
140
140
|
def mail(path, *args)
|
141
141
|
mail = ::Mail.new
|
142
142
|
catch(:no_mail) do
|
143
|
-
unless mail.equal?(new("PATH_INFO"=>path, 'SCRIPT_NAME'=>'', "REQUEST_METHOD"=>"MAIL", 'rack.input'=>StringIO.new, 'roda.mail'=>mail, 'roda.mail_args'=>args).call(
|
143
|
+
unless mail.equal?(new("PATH_INFO"=>path, 'SCRIPT_NAME'=>'', "REQUEST_METHOD"=>"MAIL", 'rack.input'=>StringIO.new, 'roda.mail'=>mail, 'roda.mail_args'=>args).call(&@rack_app_route_block))
|
144
144
|
raise Error, "route did not return mail instance for #{path.inspect}, #{args.inspect}"
|
145
145
|
end
|
146
146
|
mail
|
@@ -170,7 +170,7 @@ class Roda
|
|
170
170
|
def route(name=nil, namespace=nil, &block)
|
171
171
|
if name
|
172
172
|
opts[:namespaced_routes][namespace] ||= {}
|
173
|
-
opts[:namespaced_routes][namespace][name] = block
|
173
|
+
opts[:namespaced_routes][namespace][name] = convert_route_block(block)
|
174
174
|
self::RodaRequest.clear_named_route_regexp!(namespace)
|
175
175
|
else
|
176
176
|
super(&block)
|
data/lib/roda/plugins/render.rb
CHANGED
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
class Roda
|
5
|
+
module RodaPlugins
|
6
|
+
# The route_block_args plugin lets you customize what arguments are passed to
|
7
|
+
# the +route+ block. So if you have an application that always needs access
|
8
|
+
# to the +response+, the +params+, the +env+, or the +session+, you can use
|
9
|
+
# this plugin so that any of those can be arguments to the route block.
|
10
|
+
# Example:
|
11
|
+
#
|
12
|
+
# class App < Roda
|
13
|
+
# plugin :route_block_args do
|
14
|
+
# [request, request.params, response]
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# route do |r, params, res|
|
18
|
+
# r.post do
|
19
|
+
# artist = Artist.create(name: params['name'].to_s)
|
20
|
+
# res.status = 201
|
21
|
+
# artist.id.to_s
|
22
|
+
# end
|
23
|
+
# end
|
24
|
+
# end
|
25
|
+
module RouteBlockArgs
|
26
|
+
def self.configure(app, &block)
|
27
|
+
app.instance_exec do
|
28
|
+
opts[:route_block_args] = block
|
29
|
+
route(&@raw_route_block) if @raw_route_block
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Override the route block input so that the block
|
34
|
+
# given is passed the arguments specified by the
|
35
|
+
# block given to the route_block_args plugin.
|
36
|
+
module ClassMethods
|
37
|
+
private
|
38
|
+
|
39
|
+
def convert_route_block(block)
|
40
|
+
proc do |r|
|
41
|
+
instance_exec(*instance_exec(&opts[:route_block_args]), &block)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
register_plugin :route_block_args, RouteBlockArgs
|
48
|
+
end
|
49
|
+
end
|
@@ -148,10 +148,6 @@ class Roda
|
|
148
148
|
class CookieTooLarge < RodaError
|
149
149
|
end
|
150
150
|
|
151
|
-
def self.load_dependencies(app, opts=OPTS)
|
152
|
-
app.plugin :_after_hook
|
153
|
-
end
|
154
|
-
|
155
151
|
# Split given secret into a cipher secret and an hmac secret.
|
156
152
|
def self.split_secret(name, secret)
|
157
153
|
raise RodaError, "sessions plugin :#{name} option must be a String" unless secret.is_a?(String)
|
@@ -49,10 +49,6 @@ class Roda
|
|
49
49
|
# static_route block to have shared behavior for different request methods,
|
50
50
|
# while still handling the request methods differently.
|
51
51
|
module StaticRouting
|
52
|
-
def self.load_dependencies(app)
|
53
|
-
app.plugin :_before_hook
|
54
|
-
end
|
55
|
-
|
56
52
|
def self.configure(app)
|
57
53
|
app.opts[:static_routes] = {}
|
58
54
|
end
|
@@ -100,7 +96,7 @@ class Roda
|
|
100
96
|
|
101
97
|
# Add a static route for the given method.
|
102
98
|
def add_static_route(method, path, &block)
|
103
|
-
(opts[:static_routes][path] ||= {})[method] = block
|
99
|
+
(opts[:static_routes][path] ||= {})[method] = convert_route_block(block)
|
104
100
|
end
|
105
101
|
end
|
106
102
|
|
@@ -23,10 +23,6 @@ class Roda
|
|
23
23
|
# cleared. So if you want to be sure the headers are set even in your block,
|
24
24
|
# you need to reset them in the block.
|
25
25
|
module StatusHandler
|
26
|
-
def self.load_dependencies(app)
|
27
|
-
app.plugin :_after_hook
|
28
|
-
end
|
29
|
-
|
30
26
|
def self.configure(app)
|
31
27
|
app.opts[:status_handler] ||= {}
|
32
28
|
end
|
@@ -50,7 +46,9 @@ class Roda
|
|
50
46
|
# If routing returns a response we have a handler for, call that handler.
|
51
47
|
def _roda_after_20__status_handler(result)
|
52
48
|
if result && (block = opts[:status_handler][result[0]]) && (v = result[2]).is_a?(Array) && v.empty?
|
53
|
-
@_response
|
49
|
+
res = @_response
|
50
|
+
res.headers.clear
|
51
|
+
res.status = result[0]
|
54
52
|
result.replace(_call(&block))
|
55
53
|
end
|
56
54
|
end
|
data/lib/roda/version.rb
CHANGED
@@ -0,0 +1,19 @@
|
|
1
|
+
require_relative "../spec_helper"
|
2
|
+
|
3
|
+
describe "deprecated _after_hook plugin" do
|
4
|
+
it "shouldn't break things" do
|
5
|
+
x = []
|
6
|
+
app(:_after_hook) do |r|
|
7
|
+
x << 0
|
8
|
+
'a'
|
9
|
+
end
|
10
|
+
@app.send(:include, Module.new do
|
11
|
+
define_method(:_roda_after_00_test){|_| x << 1}
|
12
|
+
private :_roda_after_00_test
|
13
|
+
end)
|
14
|
+
|
15
|
+
body.must_equal 'a'
|
16
|
+
x.must_equal [0, 1]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
@@ -161,4 +161,31 @@ describe "class_level_routing plugin" do
|
|
161
161
|
|
162
162
|
proc{app.on{}}.must_raise
|
163
163
|
end
|
164
|
+
|
165
|
+
it 'works with route_block_args plugin' do
|
166
|
+
app(:bare) do
|
167
|
+
plugin :class_level_routing
|
168
|
+
plugin :route_block_args do
|
169
|
+
[request.path]
|
170
|
+
end
|
171
|
+
|
172
|
+
root do |path|
|
173
|
+
"root-#{path}"
|
174
|
+
end
|
175
|
+
|
176
|
+
get do |path|
|
177
|
+
"GET-#{path}"
|
178
|
+
end
|
179
|
+
|
180
|
+
route do |path|
|
181
|
+
request.get('foo') do
|
182
|
+
path
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
body.must_equal 'root-/'
|
188
|
+
body('/a').must_equal 'GET-/a'
|
189
|
+
body('/foo').must_equal '/foo'
|
190
|
+
end
|
164
191
|
end
|
@@ -398,5 +398,54 @@ describe "mail_processor plugin" do
|
|
398
398
|
check{app.process_mail(new_mail{|m| m.body "Found bar\n--\nFound foo"})}.must_equal [:f, 'foo']
|
399
399
|
check{app.process_mail(new_mail{|m| m.body "> Found baz\nFound quux"})}.must_equal [:f2, 'quux', "Found quux"]
|
400
400
|
end
|
401
|
+
|
402
|
+
it "works with route_block_args plugin" do
|
403
|
+
@processed = processed = []
|
404
|
+
app(:bare) do
|
405
|
+
plugin :mail_processor
|
406
|
+
plugin :route_block_args do
|
407
|
+
[to, from]
|
408
|
+
end
|
409
|
+
route do |t, f|
|
410
|
+
request.handle do
|
411
|
+
processed << t << f
|
412
|
+
end
|
413
|
+
end
|
414
|
+
handled_mail do
|
415
|
+
# processed << :h << mail.to.first
|
416
|
+
end
|
417
|
+
end
|
418
|
+
check{app.process_mail(new_mail)}.must_equal [["a@example.com"], ["b@example.com"]]
|
419
|
+
end
|
420
|
+
|
421
|
+
it "works with hooks plugin, calling after hook before *_mail hooks" do
|
422
|
+
@processed = processed = []
|
423
|
+
app(:bare) do
|
424
|
+
plugin :mail_processor
|
425
|
+
plugin :hooks
|
426
|
+
before do
|
427
|
+
processed << 1
|
428
|
+
end
|
429
|
+
after do
|
430
|
+
processed << 2
|
431
|
+
end
|
432
|
+
route do |r|
|
433
|
+
processed << 3
|
434
|
+
r.handle_to('a@example.com') do
|
435
|
+
end
|
436
|
+
end
|
437
|
+
handled_mail do
|
438
|
+
processed << 4
|
439
|
+
end
|
440
|
+
unhandled_mail do
|
441
|
+
processed << 5
|
442
|
+
end
|
443
|
+
after_mail do
|
444
|
+
processed << 6
|
445
|
+
end
|
446
|
+
end
|
447
|
+
check{app.process_mail(new_mail)}.must_equal [1, 3, 2, 4, 6]
|
448
|
+
check{app.process_mail(new_mail{|m| m.to 'x@example.com'})}.must_equal [1, 3, 2, 5, 6]
|
449
|
+
end
|
401
450
|
end
|
402
451
|
end
|
data/spec/plugin/mailer_spec.rb
CHANGED
@@ -244,5 +244,39 @@ describe "mailer plugin" do
|
|
244
244
|
m.parts.last.content_type.must_match(/\Atext\/css/)
|
245
245
|
m.parts.last.body.decoded.gsub("\r\n", "\n").must_equal File.read('spec/assets/css/raw.css')
|
246
246
|
end
|
247
|
+
|
248
|
+
it "works with route_block_args plugin" do
|
249
|
+
app(:bare) do
|
250
|
+
plugin :mailer
|
251
|
+
plugin :route_block_args do
|
252
|
+
[request.path]
|
253
|
+
end
|
254
|
+
route do |path|
|
255
|
+
path
|
256
|
+
end
|
257
|
+
end
|
258
|
+
app.mail('/').body.decoded.must_equal '/'
|
259
|
+
app.mail('/foo').body.decoded.must_equal '/foo'
|
260
|
+
end
|
261
|
+
|
262
|
+
it "works with hooks plugin" do
|
263
|
+
x = []
|
264
|
+
app(:bare) do
|
265
|
+
plugin :mailer
|
266
|
+
plugin :hooks
|
267
|
+
before do
|
268
|
+
x << 1
|
269
|
+
end
|
270
|
+
after do
|
271
|
+
x << 2
|
272
|
+
end
|
273
|
+
route do
|
274
|
+
x << 3
|
275
|
+
''
|
276
|
+
end
|
277
|
+
end
|
278
|
+
app.mail('/').body.decoded.must_equal ''
|
279
|
+
x.must_equal [1, 3, 2]
|
280
|
+
end
|
247
281
|
end
|
248
282
|
end
|
@@ -234,27 +234,23 @@ describe "multi_route plugin" do
|
|
234
234
|
end
|
235
235
|
|
236
236
|
it "handles namespaces in r.multi_route" do
|
237
|
-
app
|
238
|
-
|
239
|
-
|
240
|
-
@p
|
237
|
+
app(:multi_route) do |path|
|
238
|
+
request.multi_route
|
239
|
+
path
|
241
240
|
end
|
242
|
-
|
243
|
-
|
244
|
-
@p = 'b'
|
245
|
-
r.multi_route("bar")
|
246
|
-
@p
|
241
|
+
app.plugin :route_block_args do
|
242
|
+
[request.path, request]
|
247
243
|
end
|
248
|
-
|
249
|
-
|
250
|
-
|
244
|
+
app.route("foo") do |path, r|
|
245
|
+
r.multi_route("foo")
|
246
|
+
"f-#{path}"
|
247
|
+
end
|
248
|
+
app.route("bar", "foo") do |path|
|
249
|
+
"b-#{path}"
|
251
250
|
end
|
252
251
|
|
253
|
-
body
|
254
|
-
body('/foo
|
255
|
-
body('/foo/bar').must_equal '
|
256
|
-
body('/bar').must_equal 'b'
|
257
|
-
body('/bar/foo').must_equal 'bbf'
|
258
|
-
body('/bar/bar').must_equal 'bbb'
|
252
|
+
body.must_equal '/'
|
253
|
+
body('/foo').must_equal 'f-/foo'
|
254
|
+
body('/foo/bar').must_equal 'b-/foo/bar'
|
259
255
|
end
|
260
256
|
end
|
data/spec/plugin/render_spec.rb
CHANGED
@@ -515,9 +515,9 @@ describe "render plugin" do
|
|
515
515
|
|
516
516
|
it "render plugin call should not override existing options" do
|
517
517
|
c = Class.new(Roda)
|
518
|
-
c.plugin :render, :
|
518
|
+
c.plugin :render, :layout_opts=>{:template=>'foo'}
|
519
519
|
c.plugin :render
|
520
|
-
c.render_opts[:
|
520
|
+
c.render_opts[:layout_opts][:template].must_equal 'foo'
|
521
521
|
end
|
522
522
|
|
523
523
|
it "should not use cache by default in subclass if not caching by default in superclass" do
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require_relative "../spec_helper"
|
2
|
+
|
3
|
+
describe "route_block_args plugin" do
|
4
|
+
it "works with hooks when loaded last" do
|
5
|
+
a = []
|
6
|
+
app(:bare) do
|
7
|
+
plugin :hooks
|
8
|
+
before { a << 1 }
|
9
|
+
after { a << 2 }
|
10
|
+
plugin :route_block_args do
|
11
|
+
[request, response]
|
12
|
+
end
|
13
|
+
route do |req, res|
|
14
|
+
response.status = 401
|
15
|
+
a << req.path << res.status
|
16
|
+
"1"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
body.must_equal "1"
|
20
|
+
a.must_equal [1, '/', 401, 2]
|
21
|
+
end
|
22
|
+
|
23
|
+
it "works with hooks when loaded first" do
|
24
|
+
a = []
|
25
|
+
app(:bare) do
|
26
|
+
plugin :route_block_args do
|
27
|
+
[request, response]
|
28
|
+
end
|
29
|
+
plugin :hooks
|
30
|
+
before { a << 1 }
|
31
|
+
after { a << 2 }
|
32
|
+
route do |req, res|
|
33
|
+
response.status = 401
|
34
|
+
a << req.path << res.status
|
35
|
+
"1"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
body.must_equal "1"
|
39
|
+
a.must_equal [1, '/', 401, 2]
|
40
|
+
end
|
41
|
+
|
42
|
+
it "still supports a single route block argument" do
|
43
|
+
app(:bare) do
|
44
|
+
plugin :route_block_args do
|
45
|
+
request
|
46
|
+
end
|
47
|
+
route { |r| "OK" }
|
48
|
+
end
|
49
|
+
|
50
|
+
status('/').must_equal(200)
|
51
|
+
end
|
52
|
+
|
53
|
+
it "supports many route block arguments" do
|
54
|
+
app(:bare) do
|
55
|
+
plugin :route_block_args do
|
56
|
+
[request.params, request.env, response.headers, response.body]
|
57
|
+
end
|
58
|
+
route do |p, e, h, b|
|
59
|
+
h['Foo'] = 'Bar'
|
60
|
+
b << "#{p['a']}-#{e['B']}"
|
61
|
+
"x"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
header('Foo', 'rack.input'=>StringIO.new).must_equal('Bar')
|
66
|
+
body('rack.input'=>StringIO.new).must_equal('-')
|
67
|
+
body('QUERY_STRING'=>'a=c', 'B'=>'D', 'rack.input'=>StringIO.new).must_equal('c-D')
|
68
|
+
end
|
69
|
+
|
70
|
+
it "works if given after the route block" do
|
71
|
+
app(:bare) do
|
72
|
+
route do |p, e, h, b|
|
73
|
+
h['Foo'] = 'Bar'
|
74
|
+
b << "#{p['a']}-#{e['B']}"
|
75
|
+
"x"
|
76
|
+
end
|
77
|
+
plugin :route_block_args do
|
78
|
+
[request.params, request.env, response.headers, response.body]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
header('Foo', 'rack.input'=>StringIO.new).must_equal('Bar')
|
83
|
+
body('rack.input'=>StringIO.new).must_equal('-')
|
84
|
+
body('QUERY_STRING'=>'a=c', 'B'=>'D', 'rack.input'=>StringIO.new).must_equal('c-D')
|
85
|
+
end
|
86
|
+
end
|
@@ -145,4 +145,26 @@ describe "static_routing plugin" do
|
|
145
145
|
end.must_raise
|
146
146
|
end
|
147
147
|
end
|
148
|
+
|
149
|
+
it 'works with route_block_args plugin' do
|
150
|
+
app(:bare) do
|
151
|
+
plugin :static_routing
|
152
|
+
plugin :route_block_args do
|
153
|
+
[request.request_method, request.path]
|
154
|
+
end
|
155
|
+
|
156
|
+
static_route "/foo" do |meth, path|
|
157
|
+
"#{path}-#{meth}"
|
158
|
+
end
|
159
|
+
|
160
|
+
static_get "/bar" do |meth, path|
|
161
|
+
"#{path}-#{meth}-bar"
|
162
|
+
end
|
163
|
+
|
164
|
+
route{'a'}
|
165
|
+
end
|
166
|
+
|
167
|
+
body('/foo').must_equal '/foo-GET'
|
168
|
+
body('/bar').must_equal '/bar-GET-bar'
|
169
|
+
end
|
148
170
|
end
|
@@ -60,6 +60,50 @@ describe "view_options plugin" do
|
|
60
60
|
body.strip.must_equal "<title>Alternative Layout: Home</title>\n<h1>Subdir: About Roda</h1>"
|
61
61
|
end
|
62
62
|
|
63
|
+
it "should allow overriding :layout plugin option with set_layout_options :template" do
|
64
|
+
app(:bare) do
|
65
|
+
plugin :render, :views=>'spec/views', :allowed_paths=>['spec/views']
|
66
|
+
plugin :view_options
|
67
|
+
|
68
|
+
route do
|
69
|
+
set_view_options :views=>'spec/views/about'
|
70
|
+
set_layout_options :template=>'layout-alternative'
|
71
|
+
view('_test', :locals=>{:title=>'About Roda'}, :layout_opts=>{:locals=>{:title=>'Home'}})
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
body.strip.must_equal "<title>Alternative Layout: Home</title>\n<h1>Subdir: About Roda</h1>"
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should allow overriding :layout_opts :template plugin option with set_layout_options :template" do
|
79
|
+
app(:bare) do
|
80
|
+
plugin :render, :views=>'spec/views', :allowed_paths=>['spec/views'], :layout_opts=>{:template=>'layout'}
|
81
|
+
plugin :view_options
|
82
|
+
|
83
|
+
route do
|
84
|
+
set_view_options :views=>'spec/views/about', :layout=>'layout-alternative'
|
85
|
+
set_layout_options :template=>'layout-alternative'
|
86
|
+
view('_test', :locals=>{:title=>'About Roda'}, :layout_opts=>{:locals=>{:title=>'Home'}})
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
body.strip.must_equal "<title>Alternative Layout: Home</title>\n<h1>Subdir: About Roda</h1>"
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should allow overriding :layout plugin option with set_view_options :layout" do
|
94
|
+
app(:bare) do
|
95
|
+
plugin :render, :views=>'spec/views', :allowed_paths=>['spec/views'], :layout=>'layout'
|
96
|
+
plugin :view_options
|
97
|
+
|
98
|
+
route do
|
99
|
+
set_view_options :views=>'spec/views/about', :layout=>'layout-alternative'
|
100
|
+
view('_test', :locals=>{:title=>'About Roda'}, :layout_opts=>{:locals=>{:title=>'Home'}})
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
body.strip.must_equal "<title>Alternative Layout: Home</title>\n<h1>Subdir: About Roda</h1>"
|
105
|
+
end
|
106
|
+
|
63
107
|
it "should set view and layout options to use" do
|
64
108
|
app(:bare) do
|
65
109
|
plugin :render, :allowed_paths=>['spec/views']
|
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.17.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: 2019-
|
11
|
+
date: 2019-02-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -213,6 +213,7 @@ extra_rdoc_files:
|
|
213
213
|
- doc/release_notes/3.14.1.txt
|
214
214
|
- doc/release_notes/3.15.0.txt
|
215
215
|
- doc/release_notes/3.16.0.txt
|
216
|
+
- doc/release_notes/3.17.0.txt
|
216
217
|
files:
|
217
218
|
- CHANGELOG
|
218
219
|
- MIT-LICENSE
|
@@ -264,6 +265,7 @@ files:
|
|
264
265
|
- doc/release_notes/3.14.1.txt
|
265
266
|
- doc/release_notes/3.15.0.txt
|
266
267
|
- doc/release_notes/3.16.0.txt
|
268
|
+
- doc/release_notes/3.17.0.txt
|
267
269
|
- doc/release_notes/3.2.0.txt
|
268
270
|
- doc/release_notes/3.3.0.txt
|
269
271
|
- doc/release_notes/3.4.0.txt
|
@@ -345,6 +347,7 @@ files:
|
|
345
347
|
- lib/roda/plugins/request_aref.rb
|
346
348
|
- lib/roda/plugins/request_headers.rb
|
347
349
|
- lib/roda/plugins/response_request.rb
|
350
|
+
- lib/roda/plugins/route_block_args.rb
|
348
351
|
- lib/roda/plugins/route_csrf.rb
|
349
352
|
- lib/roda/plugins/run_append_slash.rb
|
350
353
|
- lib/roda/plugins/run_handler.rb
|
@@ -379,6 +382,7 @@ files:
|
|
379
382
|
- spec/integration_spec.rb
|
380
383
|
- spec/matchers_spec.rb
|
381
384
|
- spec/opts_spec.rb
|
385
|
+
- spec/plugin/_after_hook_spec.rb
|
382
386
|
- spec/plugin/all_verbs_spec.rb
|
383
387
|
- spec/plugin/assets_preloading_spec.rb
|
384
388
|
- spec/plugin/assets_spec.rb
|
@@ -448,6 +452,7 @@ files:
|
|
448
452
|
- spec/plugin/request_aref_spec.rb
|
449
453
|
- spec/plugin/request_headers_spec.rb
|
450
454
|
- spec/plugin/response_request_spec.rb
|
455
|
+
- spec/plugin/route_block_args_spec.rb
|
451
456
|
- spec/plugin/route_csrf_spec.rb
|
452
457
|
- spec/plugin/run_append_slash_spec.rb
|
453
458
|
- spec/plugin/run_handler_spec.rb
|