roda 3.67.0 → 3.69.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0ea9212a800294ebf286d593e230ac925aced0d5e7c118fa7541b3fd6a5cc983
4
- data.tar.gz: 9a591fdf0b2b481f71cbf871a70b3f83a8cac4bca4c3fe399348dfeee2447a13
3
+ metadata.gz: 2871ec8db3a18a77238fdae1aeb786c7a7eb93f14b0827428fab1b07f6e7bee8
4
+ data.tar.gz: 75db2ec79978055f407c2270cfd9119782322402c2c536a504fbfc08f4fedac7
5
5
  SHA512:
6
- metadata.gz: 7f5887a701034ac935d6bb1f14a454f6dfe03751ec7842e383f401555f46d021d8bb502658959a5edae9d4199d8e8bfc785721d3386b76f0b6b280c7731fad3d
7
- data.tar.gz: eb7de74ded26221a86664644ceddda6428e877bdf158acd988319c56bdc335955b506623cc9d8fb3c71376c877d4e00254c018c4341debd221a6439d9557e6ed
6
+ metadata.gz: 1ca4fdcac9bcba88309b8ccb4315ea2243530b08313135f97a643b81600b98821521fbbe08e9c7ab757732887326e8af492f0f3e883a3f54e7be73f0811d19e6
7
+ data.tar.gz: 6b313eecbd4f62d07bca53fa23db2325b4f53f3faf55344c86d8f543ff92c5dcba94235f963582ce227d3602e3ea8633e981393ef6aedcbe20fb8152e6409c08
data/CHANGELOG CHANGED
@@ -1,3 +1,11 @@
1
+ = 3.69.0 (2023-06-13)
2
+
3
+ * Allow symbol_matcher in symbol_matchers plugin to take a block to allow type conversion (jeremyevans)
4
+
5
+ = 3.68.0 (2023-05-11)
6
+
7
+ * Make Roda.run in multi_run plugin accept blocks to allow autoloading the apps to dispatch to (jeremyevans)
8
+
1
9
  = 3.67.0 (2023-04-12)
2
10
 
3
11
  * Add custom_block_results plugin for registering custom block result handlers (jeremyevans)
@@ -0,0 +1,21 @@
1
+ = New Feature
2
+
3
+ * Roda.run in the multi_run plugin now accepts blocks, to allow
4
+ autoloading of apps to dispatch to:
5
+
6
+ class App < Roda
7
+ plugin :multi_run
8
+
9
+ run("other_app"){OtherApp}
10
+
11
+ route do |r|
12
+ r.multi_run
13
+ end
14
+ end
15
+
16
+ With the above example, the block is not evaluated until a
17
+ request for the /other_app branch is received. If OtherApp is
18
+ autoloaded, this can speed up application startup and partial
19
+ testing. When freezing the application (for production use),
20
+ the block is eagerly loaded, so that requests to the
21
+ /other_app branch do not call the block on every request.
@@ -0,0 +1,33 @@
1
+ = New Feature
2
+
3
+ * The symbol_matcher method in the symbol_matchers plugin now
4
+ supports a block to allow for type conversion of matched
5
+ segments:
6
+
7
+ symbol_matcher(:date, /(\d\d\d\d)-(\d\d)-(\d\d)/) do |y, m, d|
8
+ [Date.new(y.to_i, m.to_i, d.to_i)]
9
+ end
10
+
11
+ route do |r|
12
+ r.on :date do |date|
13
+ # date is an instance of Date
14
+ end
15
+ end
16
+
17
+ As shown above, the block should return an array of objects to yield
18
+ to the match block.
19
+
20
+ If you have a segment match the passed regexp, but decide during block
21
+ processing that you do not want to treat it as a match, you can have the
22
+ block return nil or false. This is useful if you want to make sure you
23
+ are using valid data:
24
+
25
+ symbol_matcher(:date, /(\d\d\d\d)-(\d\d)-(\d\d)/) do |y, m, d|
26
+ y = y.to_i
27
+ m = m.to_i
28
+ d = d.to_i
29
+ [Date.new(y, m, d)] if Date.valid_date?(y, m, d)
30
+ end
31
+
32
+ When providing a block when using the symbol_matchers method, that
33
+ symbol may not work with the params_capturing plugin.
@@ -33,7 +33,7 @@ class Roda
33
33
  # block return nil or false. This is useful if you want to make sure you
34
34
  # are using valid data:
35
35
  #
36
- # class_matcher(Date, /(\dd\d)-(\d\d)-(\d\d)/) do |y, m, d|
36
+ # class_matcher(Date, /(\d\d\d\d)-(\d\d)-(\d\d)/) do |y, m, d|
37
37
  # y = y.to_i
38
38
  # m = m.to_i
39
39
  # d = d.to_i
@@ -17,7 +17,7 @@ class Roda
17
17
  # App.run "ro", OtherRodaApp
18
18
  # App.run "si", SinatraApp
19
19
  #
20
- # Inside your route block, you can call r.multi_run to dispatch to all
20
+ # Inside your route block, you can call +r.multi_run+ to dispatch to all
21
21
  # three rack applications based on the prefix:
22
22
  #
23
23
  # App.route do |r|
@@ -28,7 +28,7 @@ class Roda
28
28
  # starting with +/ro+ to +OtherRodaApp+, and routes starting with +/si+ to
29
29
  # SinatraApp.
30
30
  #
31
- # You can pass a block to +multi_run+ that will be called with the prefix,
31
+ # You can pass a block to +r.multi_run+ that will be called with the prefix,
32
32
  # before dispatching to the rack app:
33
33
  #
34
34
  # App.route do |r|
@@ -39,12 +39,26 @@ class Roda
39
39
  #
40
40
  # This is useful for modifying the environment before passing it to the rack app.
41
41
  #
42
- # The multi_run plugin is similar to the multi_route plugin, with the difference
43
- # being the multi_route plugin keeps all routing subtrees in the same Roda app/class,
44
- # while multi_run dispatches to other rack apps. If you want to isolate your routing
45
- # subtrees, multi_run is a better approach, but it does not let you set instance
46
- # variables in the main Roda app and have those instance variables usable in
47
- # the routing subtrees.
42
+ # You can also call +Roda.run+ with a block:
43
+ #
44
+ # App.run("ra"){PlainRackApp}
45
+ # App.run("ro"){OtherRodaApp}
46
+ # App.run("si"){SinatraApp}
47
+ #
48
+ # When called with a block, Roda will call the block to get the app to dispatch to
49
+ # every time the block is called. The expected usage is with autoloaded classes,
50
+ # so that the related classes are not loaded until there is a request for the
51
+ # related route. This can sigficantly speedup startup or testing a subset of the
52
+ # application. When freezing an application, the blocks are called once to get the
53
+ # app to dispatch to, and that is cached, to ensure the any autoloads are completed
54
+ # before the application is frozen.
55
+ #
56
+ # The multi_run plugin is similar to the hash_branches and multi_route plugins, with
57
+ # the difference being the hash_branches and multi_route plugins keep all routing
58
+ # subtrees in the same Roda app/class, while multi_run dispatches to other rack apps.
59
+ # If you want to isolate your routing subtrees, multi_run is a better approach, but
60
+ # it does not let you set instance variables in the main Roda app and have those
61
+ # instance variables usable in the routing subtrees.
48
62
  #
49
63
  # To handle development environments that reload code, you can call the
50
64
  # +run+ class method without an app to remove dispatching for the prefix.
@@ -52,12 +66,21 @@ class Roda
52
66
  # Initialize the storage for the dispatched applications
53
67
  def self.configure(app)
54
68
  app.opts[:multi_run_apps] ||= {}
69
+ app.opts[:multi_run_app_blocks] ||= {}
55
70
  end
56
71
 
57
72
  module ClassMethods
73
+ # Convert app blocks into apps by calling them, in order to force autoloads
74
+ # and to speed up subsequent calls.
58
75
  # Freeze the multi_run apps so that there can be no thread safety issues at runtime.
59
76
  def freeze
60
- opts[:multi_run_apps].freeze
77
+ app_blocks = opts[:multi_run_app_blocks]
78
+ apps = opts[:multi_run_apps]
79
+ app_blocks.each do |prefix, block|
80
+ apps[prefix] = block.call
81
+ end
82
+ app_blocks.clear.freeze
83
+ apps.freeze
61
84
  self::RodaRequest.refresh_multi_run_regexp!
62
85
  super
63
86
  end
@@ -69,12 +92,22 @@ class Roda
69
92
  end
70
93
 
71
94
  # Add a rack application to dispatch to for the given prefix when
72
- # r.multi_run is called.
73
- def run(prefix, app=nil)
74
- if app
75
- multi_run_apps[prefix.to_s] = app
95
+ # r.multi_run is called. If a block is given, it is called every time
96
+ # there is a request for the route to get the app to call. If neither
97
+ # a block or an app is provided, any stored route for the prefix is
98
+ # removed. It is an error to provide both an app and block in the same call.
99
+ def run(prefix, app=nil, &block)
100
+ prefix = prefix.to_s
101
+ if app
102
+ raise Roda::RodaError, "cannot provide both app and block to Roda.run" if block
103
+ opts[:multi_run_apps][prefix] = app
104
+ opts[:multi_run_app_blocks].delete(prefix)
105
+ elsif block
106
+ opts[:multi_run_apps].delete(prefix)
107
+ opts[:multi_run_app_blocks][prefix] = block
76
108
  else
77
- multi_run_apps.delete(prefix.to_s)
109
+ opts[:multi_run_apps].delete(prefix)
110
+ opts[:multi_run_app_blocks].delete(prefix)
78
111
  end
79
112
  self::RodaRequest.refresh_multi_run_regexp!
80
113
  end
@@ -84,7 +117,7 @@ class Roda
84
117
  # Refresh the multi_run_regexp, using the stored route prefixes,
85
118
  # preferring longer routes before shorter routes.
86
119
  def refresh_multi_run_regexp!
87
- @multi_run_regexp = /(#{Regexp.union(roda_class.multi_run_apps.keys.sort.reverse)})/
120
+ @multi_run_regexp = /(#{Regexp.union((roda_class.opts[:multi_run_apps].keys + roda_class.opts[:multi_run_app_blocks].keys).sort.reverse)})/
88
121
  end
89
122
 
90
123
  # Refresh the multi_run_regexp if it hasn't been loaded yet.
@@ -95,11 +128,12 @@ class Roda
95
128
 
96
129
  module RequestMethods
97
130
  # If one of the stored route prefixes match the current request,
98
- # dispatch the request to the stored rack application.
131
+ # dispatch the request to the appropriate rack application.
99
132
  def multi_run
100
133
  on self.class.multi_run_regexp do |prefix|
101
134
  yield prefix if defined?(yield)
102
- run scope.class.multi_run_apps[prefix]
135
+ opts = scope.opts
136
+ run(opts[:multi_run_apps][prefix] || opts[:multi_run_app_blocks][prefix].call)
103
137
  end
104
138
  end
105
139
  end
@@ -37,6 +37,35 @@ class Roda
37
37
  #
38
38
  # If using this plugin with the params_capturing plugin, this plugin should
39
39
  # be loaded first.
40
+ #
41
+ # You can provide a block when calling +symbol_matcher+, and it will be called
42
+ # for all matches to allow for type conversion. The block must return an
43
+ # array:
44
+ #
45
+ # symbol_matcher(:date, /(\d\d\d\d)-(\d\d)-(\d\d)/) do |y, m, d|
46
+ # [Date.new(y.to_i, m.to_i, d.to_i)]
47
+ # end
48
+ #
49
+ # route do |r|
50
+ # r.on :date do |date|
51
+ # # date is an instance of Date
52
+ # end
53
+ # end
54
+ #
55
+ # If you have a segment match the passed regexp, but decide during block
56
+ # processing that you do not want to treat it as a match, you can have the
57
+ # block return nil or false. This is useful if you want to make sure you
58
+ # are using valid data:
59
+ #
60
+ # symbol_matcher(:date, /(\d\d\d\d)-(\d\d)-(\d\d)/) do |y, m, d|
61
+ # y = y.to_i
62
+ # m = m.to_i
63
+ # d = d.to_i
64
+ # [Date.new(y, m, d)] if Date.valid_date?(y, m, d)
65
+ # end
66
+ #
67
+ # However, if providing a block to the symbol_matchers plugin, the symbol may
68
+ # not work with the params_capturing plugin.
40
69
  module SymbolMatchers
41
70
  def self.load_dependencies(app)
42
71
  app.plugin :_symbol_regexp_matchers
@@ -50,9 +79,10 @@ class Roda
50
79
 
51
80
  module ClassMethods
52
81
  # Set the regexp to use for the given symbol, instead of the default.
53
- def symbol_matcher(s, re)
82
+ def symbol_matcher(s, re, &block)
54
83
  meth = :"match_symbol_#{s}"
55
- self::RodaRequest.send(:define_method, meth){re}
84
+ array = [re, block].freeze
85
+ self::RodaRequest.send(:define_method, meth){array}
56
86
  self::RodaRequest.send(:private, meth)
57
87
  end
58
88
  end
@@ -67,8 +97,8 @@ class Roda
67
97
  meth = :"match_symbol_#{s}"
68
98
  if respond_to?(meth, true)
69
99
  # Allow calling private match methods
70
- re = send(meth)
71
- consume(self.class.cached_matcher(re){re})
100
+ re, block = send(meth)
101
+ consume(self.class.cached_matcher(re){re}, &block)
72
102
  else
73
103
  super
74
104
  end
@@ -80,7 +110,8 @@ class Roda
80
110
  meth = :"match_symbol_#{s}"
81
111
  if respond_to?(meth, true)
82
112
  # Allow calling private match methods
83
- send(meth)
113
+ re, = send(meth)
114
+ re
84
115
  else
85
116
  super
86
117
  end
data/lib/roda/version.rb CHANGED
@@ -4,7 +4,7 @@ class Roda
4
4
  RodaMajorVersion = 3
5
5
 
6
6
  # The minor version of Roda, updated for new feature releases of Roda.
7
- RodaMinorVersion = 67
7
+ RodaMinorVersion = 69
8
8
 
9
9
  # The patch version of Roda, updated only for bug fixes from the last
10
10
  # feature release.
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.67.0
4
+ version: 3.69.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: 2023-04-12 00:00:00.000000000 Z
11
+ date: 2023-06-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -240,6 +240,8 @@ extra_rdoc_files:
240
240
  - doc/release_notes/3.65.0.txt
241
241
  - doc/release_notes/3.66.0.txt
242
242
  - doc/release_notes/3.67.0.txt
243
+ - doc/release_notes/3.68.0.txt
244
+ - doc/release_notes/3.69.0.txt
243
245
  - doc/release_notes/3.7.0.txt
244
246
  - doc/release_notes/3.8.0.txt
245
247
  - doc/release_notes/3.9.0.txt
@@ -314,6 +316,8 @@ files:
314
316
  - doc/release_notes/3.65.0.txt
315
317
  - doc/release_notes/3.66.0.txt
316
318
  - doc/release_notes/3.67.0.txt
319
+ - doc/release_notes/3.68.0.txt
320
+ - doc/release_notes/3.69.0.txt
317
321
  - doc/release_notes/3.7.0.txt
318
322
  - doc/release_notes/3.8.0.txt
319
323
  - doc/release_notes/3.9.0.txt