roda 3.16.0 → 3.17.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|