roda 3.85.0 → 3.87.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/lib/roda/plugins/autoload_hash_branches.rb +1 -1
- data/lib/roda/plugins/autoload_named_routes.rb +1 -1
- data/lib/roda/plugins/conditional_sessions.rb +67 -0
- data/lib/roda/plugins/content_security_policy.rb +12 -2
- data/lib/roda/plugins/custom_block_results.rb +19 -2
- data/lib/roda/plugins/early_hints.rb +1 -2
- data/lib/roda/plugins/header_matchers.rb +4 -3
- data/lib/roda/plugins/host_routing.rb +190 -0
- data/lib/roda/plugins/permissions_policy.rb +12 -2
- data/lib/roda/version.rb +1 -1
- metadata +5 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bee7ae126ad0e6e8081bba94be0ad60e2a5f7523c483b2441571549b1bd29274
|
|
4
|
+
data.tar.gz: f5441e96617877d1347f4a5b6e54e5d48713ffc91a8ad3b9282781c0c26ca108
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 141408b4d85e7467c0b753c05180201b1a63a3096f713241b94d379bad8d65224d96f1d60978ac336a7d8b9fb3093f35c1d2887d422276cf255cd1c64c557719
|
|
7
|
+
data.tar.gz: a64207e6d0a46d22c59bc0acc9d56ed43f4dbc75a9d22737908097564a2e4e801f3c19fd3bf95a28722dbf4a828d9930146dd088e421847709948d3a8f2cf24b
|
|
@@ -68,7 +68,7 @@ class Roda
|
|
|
68
68
|
|
|
69
69
|
# Eagerly load all hash branches when freezing the application.
|
|
70
70
|
def freeze
|
|
71
|
-
opts.delete(:autoload_hash_branch_files).each{|file| require file}
|
|
71
|
+
opts.delete(:autoload_hash_branch_files).each{|file| require file} unless opts.frozen?
|
|
72
72
|
super
|
|
73
73
|
end
|
|
74
74
|
end
|
|
@@ -54,7 +54,7 @@ class Roda
|
|
|
54
54
|
|
|
55
55
|
# Eagerly load all autoloaded named routes when freezing the application.
|
|
56
56
|
def freeze
|
|
57
|
-
opts.delete(:autoload_named_route_files).each{|file| require file}
|
|
57
|
+
opts.delete(:autoload_named_route_files).each{|file| require file} unless opts.frozen?
|
|
58
58
|
super
|
|
59
59
|
end
|
|
60
60
|
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
class Roda
|
|
4
|
+
module RodaPlugins
|
|
5
|
+
# The conditional_sessions plugin loads the sessions plugin. However,
|
|
6
|
+
# it only allows sessions if the block passed to the plugin returns
|
|
7
|
+
# truthy. The block is evaluated in request context. This is designed for
|
|
8
|
+
# use in applications that want to use sessions for some requests,
|
|
9
|
+
# and want to be sure that sessions are not used for other requests.
|
|
10
|
+
# For example, if you want to make sure that sessions are not used for
|
|
11
|
+
# requests with paths starting with /static, you could do:
|
|
12
|
+
#
|
|
13
|
+
# plugin :conditional_sessions, secret: ENV["SECRET"] do
|
|
14
|
+
# !path_info.start_with?('/static')
|
|
15
|
+
# end
|
|
16
|
+
#
|
|
17
|
+
# The the request session, session_created_at, and session_updated_at methods
|
|
18
|
+
# raise a RodaError exception when sessions are not allowed. The request
|
|
19
|
+
# persist_session and route scope clear_session methods do nothing when
|
|
20
|
+
# sessions are not allowed.
|
|
21
|
+
module ConditionalSessions
|
|
22
|
+
# Pass all options to the sessions block, and use the block to define
|
|
23
|
+
# a request method for whether sessions are allowed.
|
|
24
|
+
def self.load_dependencies(app, opts=OPTS, &block)
|
|
25
|
+
app.plugin :sessions, opts
|
|
26
|
+
app::RodaRequest.class_eval do
|
|
27
|
+
define_method(:use_sessions?, &block)
|
|
28
|
+
alias use_sessions? use_sessions?
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
module InstanceMethods
|
|
33
|
+
# Do nothing if not using sessions.
|
|
34
|
+
def clear_session
|
|
35
|
+
super if @_request.use_sessions?
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
module RequestMethods
|
|
40
|
+
# Raise RodaError if not using sessions.
|
|
41
|
+
def session
|
|
42
|
+
raise RodaError, "session called on request not using sessions" unless use_sessions?
|
|
43
|
+
super
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Raise RodaError if not using sessions.
|
|
47
|
+
def session_created_at
|
|
48
|
+
raise RodaError, "session_created_at called on request not using sessions" unless use_sessions?
|
|
49
|
+
super
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Raise RodaError if not using sessions.
|
|
53
|
+
def session_updated_at
|
|
54
|
+
raise RodaError, "session_updated_at called on request not using sessions" unless use_sessions?
|
|
55
|
+
super
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Do nothing if not using sessions.
|
|
59
|
+
def persist_session(headers, session)
|
|
60
|
+
super if use_sessions?
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
register_plugin(:conditional_sessions, ConditionalSessions)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -92,7 +92,10 @@ class Roda
|
|
|
92
92
|
# content_security_policy.get_script_src
|
|
93
93
|
# # => [:self, :unsafe_eval, 'example.com', [:nonce, 'foobarbaz']]
|
|
94
94
|
#
|
|
95
|
-
# The clear method can be used to remove all settings from the policy.
|
|
95
|
+
# The clear method can be used to remove all settings from the policy. Empty policies
|
|
96
|
+
# do not set any headers. You can use +response.skip_content_security_policy!+ to skip
|
|
97
|
+
# setting a policy. This is faster than calling +content_security_policy.clear+, since
|
|
98
|
+
# it does not duplicate the default policy.
|
|
96
99
|
#
|
|
97
100
|
# The following methods to set boolean settings are also defined:
|
|
98
101
|
#
|
|
@@ -304,12 +307,19 @@ class Roda
|
|
|
304
307
|
@content_security_policy ||= roda_class.opts[:content_security_policy].dup
|
|
305
308
|
end
|
|
306
309
|
|
|
310
|
+
# Do not set a content security policy header for this response.
|
|
311
|
+
def skip_content_security_policy!
|
|
312
|
+
@skip_content_security_policy = true
|
|
313
|
+
end
|
|
314
|
+
|
|
307
315
|
private
|
|
308
316
|
|
|
309
317
|
# Set the appropriate content security policy header.
|
|
310
318
|
def set_default_headers
|
|
311
319
|
super
|
|
312
|
-
|
|
320
|
+
unless @skip_content_security_policy
|
|
321
|
+
(@content_security_policy || roda_class.opts[:content_security_policy]).set_header(headers)
|
|
322
|
+
end
|
|
313
323
|
end
|
|
314
324
|
end
|
|
315
325
|
end
|
|
@@ -28,7 +28,16 @@ class Roda
|
|
|
28
28
|
#
|
|
29
29
|
# Note that custom block result handling only occurs if the types
|
|
30
30
|
# are not handled by Roda itself. You cannot use this to modify
|
|
31
|
-
# the handling of nil, false, or string results.
|
|
31
|
+
# the handling of nil, false, or string results. Additionally,
|
|
32
|
+
# if the response body has already been written to before the the
|
|
33
|
+
# route block exits, then the result of the block is ignored,
|
|
34
|
+
# and the related +handle_block_result+ block will not be called
|
|
35
|
+
# (this is standard Roda behavior).
|
|
36
|
+
#
|
|
37
|
+
# The return value of the +handle_block_result+ block is written
|
|
38
|
+
# to the body if the block return value is a String, similar to
|
|
39
|
+
# standard Roda handling of block results. Non-String return
|
|
40
|
+
# values are ignored.
|
|
32
41
|
module CustomBlockResults
|
|
33
42
|
def self.configure(app)
|
|
34
43
|
app.opts[:custom_block_results] ||= {}
|
|
@@ -55,7 +64,15 @@ class Roda
|
|
|
55
64
|
# to get the block result.
|
|
56
65
|
def unsupported_block_result(result)
|
|
57
66
|
roda_class.opts[:custom_block_results].each do |klass, meth|
|
|
58
|
-
|
|
67
|
+
if klass === result
|
|
68
|
+
result = scope.send(meth, result)
|
|
69
|
+
|
|
70
|
+
if String === result
|
|
71
|
+
return result
|
|
72
|
+
else
|
|
73
|
+
return
|
|
74
|
+
end
|
|
75
|
+
end
|
|
59
76
|
end
|
|
60
77
|
|
|
61
78
|
super
|
|
@@ -4,8 +4,7 @@
|
|
|
4
4
|
class Roda
|
|
5
5
|
module RodaPlugins
|
|
6
6
|
# The early_hints plugin allows sending 103 Early Hints responses
|
|
7
|
-
# using the rack.early_hints environment variable.
|
|
8
|
-
# is only supported by puma 3.11+, and on other servers this is a no-op.
|
|
7
|
+
# using the rack.early_hints environment variable.
|
|
9
8
|
# Early hints allow clients to preload necessary files before receiving
|
|
10
9
|
# the response.
|
|
11
10
|
module EarlyHints
|
|
@@ -51,7 +51,8 @@ class Roda
|
|
|
51
51
|
|
|
52
52
|
# Match if the given uppercase key is present inside the environment.
|
|
53
53
|
def match_header(key)
|
|
54
|
-
key = key.upcase
|
|
54
|
+
key = key.upcase
|
|
55
|
+
key.tr!("-","_")
|
|
55
56
|
unless key == "CONTENT_TYPE" || key == "CONTENT_LENGTH"
|
|
56
57
|
key = "HTTP_#{key}"
|
|
57
58
|
end
|
|
@@ -75,8 +76,8 @@ class Roda
|
|
|
75
76
|
# Match the submitted user agent to the given pattern, capturing any
|
|
76
77
|
# regexp match groups.
|
|
77
78
|
def match_user_agent(pattern)
|
|
78
|
-
if (user_agent = @env["HTTP_USER_AGENT"]) &&
|
|
79
|
-
@captures.concat(
|
|
79
|
+
if (user_agent = @env["HTTP_USER_AGENT"]) && (match = pattern.match(user_agent))
|
|
80
|
+
@captures.concat(match.captures)
|
|
80
81
|
end
|
|
81
82
|
end
|
|
82
83
|
end
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The host_routing plugin adds support for more routing requests based on
|
|
7
|
+
# the requested host. It also adds predicate methods for checking
|
|
8
|
+
# whether a request was requested with the given host.
|
|
9
|
+
#
|
|
10
|
+
# When loading the plugin, you pass a block, which is used for configuring
|
|
11
|
+
# the plugin. For example, if you want to treat requests to api.example.com
|
|
12
|
+
# or api2.example.com as api requests, and treat other requests as www
|
|
13
|
+
# requests, you could use:
|
|
14
|
+
#
|
|
15
|
+
# plugin :host_routing do |hosts|
|
|
16
|
+
# hosts.to :api, "api.example.com", "api2.example.com"
|
|
17
|
+
# hosts.default :www
|
|
18
|
+
# end
|
|
19
|
+
#
|
|
20
|
+
# With this configuration, in your routing tree, you can call the +r.api+ and
|
|
21
|
+
# +r.www+ methods for dispatching to routing blocks only for those types of
|
|
22
|
+
# requests:
|
|
23
|
+
#
|
|
24
|
+
# route do |r|
|
|
25
|
+
# r.api do
|
|
26
|
+
# # requests to api.example.com or api2.example.com
|
|
27
|
+
# end
|
|
28
|
+
#
|
|
29
|
+
# r.www do
|
|
30
|
+
# # requests to other domains
|
|
31
|
+
# end
|
|
32
|
+
# end
|
|
33
|
+
#
|
|
34
|
+
# In addition to the routing methods, predicate methods are also added to the
|
|
35
|
+
# request object:
|
|
36
|
+
#
|
|
37
|
+
# route do |r|
|
|
38
|
+
# "#{r.api?}-#{r.www?}"
|
|
39
|
+
# end
|
|
40
|
+
# # Requests to api.example.com or api2.example.com return "true-false"
|
|
41
|
+
# # Other requests return "false-true"
|
|
42
|
+
#
|
|
43
|
+
# If the +:scope_predicates+ plugin option is given, predicate methods are also
|
|
44
|
+
# created in route block scope:
|
|
45
|
+
#
|
|
46
|
+
# plugin :host_routing, scope_predicates: true do |hosts|
|
|
47
|
+
# hosts.to :api, "api.example.com"
|
|
48
|
+
# hosts.default :www
|
|
49
|
+
# end
|
|
50
|
+
#
|
|
51
|
+
# route do |r|
|
|
52
|
+
# "#{api?}-#{www?}"
|
|
53
|
+
# end
|
|
54
|
+
#
|
|
55
|
+
# To handle hosts that match a certain format (such as all subdomains),
|
|
56
|
+
# where the specific host names are not known up front, you can provide a block
|
|
57
|
+
# when calling +hosts.default+. This block is passed the host name, or an empty
|
|
58
|
+
# string if no host name is provided, and is evaluated in route block scope.
|
|
59
|
+
# When using this support, you should also call +hosts.register+
|
|
60
|
+
# to register host types that could be returned by the block. For example, to
|
|
61
|
+
# handle api subdomains differently:
|
|
62
|
+
#
|
|
63
|
+
# plugin :host_routing do |hosts|
|
|
64
|
+
# hosts.to :api, "api.example.com"
|
|
65
|
+
# hosts.register :api_sub
|
|
66
|
+
# hosts.default :www do |host|
|
|
67
|
+
# :api_sub if host.end_with?(".api.example.com")
|
|
68
|
+
# end
|
|
69
|
+
# end
|
|
70
|
+
#
|
|
71
|
+
# This plugin uses the host method on the request to get the hostname (this method
|
|
72
|
+
# is defined by Rack).
|
|
73
|
+
module HostRouting
|
|
74
|
+
# Setup the host routing support. The block yields an object used to
|
|
75
|
+
# configure the plugin. Options:
|
|
76
|
+
#
|
|
77
|
+
# :scope_predicates :: Setup predicate methods in route block scope
|
|
78
|
+
# in addition to request scope.
|
|
79
|
+
def self.configure(app, opts=OPTS, &block)
|
|
80
|
+
hosts, host_hash, default_block, default_host = DSL.new.process(&block)
|
|
81
|
+
app.opts[:host_routing_hash] = host_hash
|
|
82
|
+
app.opts[:host_routing_default_host] = default_host
|
|
83
|
+
|
|
84
|
+
app.send(:define_method, :_host_routing_default, &default_block) if default_block
|
|
85
|
+
|
|
86
|
+
app::RodaRequest.class_exec do
|
|
87
|
+
hosts.each do |host|
|
|
88
|
+
host_sym = host.to_sym
|
|
89
|
+
define_method(host_sym){|&blk| always(&blk) if _host_routing_host == host}
|
|
90
|
+
alias_method host_sym, host_sym
|
|
91
|
+
|
|
92
|
+
meth = :"#{host}?"
|
|
93
|
+
define_method(meth){_host_routing_host == host}
|
|
94
|
+
alias_method meth, meth
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
if opts[:scope_predicates]
|
|
99
|
+
app.class_exec do
|
|
100
|
+
hosts.each do |host|
|
|
101
|
+
meth = :"#{host}?"
|
|
102
|
+
define_method(meth){@_request.send(meth)}
|
|
103
|
+
alias_method meth, meth
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
class DSL
|
|
110
|
+
def initialize
|
|
111
|
+
@hosts = []
|
|
112
|
+
@host_hash = {}
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Run the DSL for the given block.
|
|
116
|
+
def process(&block)
|
|
117
|
+
instance_exec(self, &block)
|
|
118
|
+
|
|
119
|
+
if !@default_host
|
|
120
|
+
raise RodaError, "must call default method inside host_routing plugin block to set default host"
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
@hosts.concat(@host_hash.values)
|
|
124
|
+
@hosts << @default_host
|
|
125
|
+
@hosts.uniq!
|
|
126
|
+
[@hosts.freeze, @host_hash.freeze, @default_block, @default_host].freeze
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Register hosts that can be returned. This is only needed if
|
|
130
|
+
# calling register with a block, where the block can return
|
|
131
|
+
# a value that doesn't match a host given to +to+ or +default+.
|
|
132
|
+
def register(*hosts)
|
|
133
|
+
@hosts = hosts
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Treat all given hostnames as routing to the give host.
|
|
137
|
+
def to(host, *hostnames)
|
|
138
|
+
hostnames.each do |hostname|
|
|
139
|
+
@host_hash[hostname] = host
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Register the default hostname. If a block is provided, it is
|
|
144
|
+
# called with the host if there is no match for one of the hostnames
|
|
145
|
+
# provided to +to+. If the block returns nil/false, the hostname
|
|
146
|
+
# given to this method is used.
|
|
147
|
+
def default(hostname, &block)
|
|
148
|
+
@default_host = hostname
|
|
149
|
+
@default_block = block
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
private_constant :DSL
|
|
153
|
+
|
|
154
|
+
module InstanceMethods
|
|
155
|
+
# Handle case where plugin is used without providing a block to
|
|
156
|
+
# +hosts.default+. This returns nil, ensuring that the hostname
|
|
157
|
+
# provided to +hosts.default+ will be used.
|
|
158
|
+
def _host_routing_default(_)
|
|
159
|
+
nil
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
module RequestMethods
|
|
164
|
+
private
|
|
165
|
+
|
|
166
|
+
# Cache the host to use in the host routing support, so the processing
|
|
167
|
+
# is only done once per request.
|
|
168
|
+
def _host_routing_host
|
|
169
|
+
@_host_routing_host ||= _get_host_routing_host
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# Determine the host to use for the host routing support. Tries the
|
|
173
|
+
# following, in order:
|
|
174
|
+
#
|
|
175
|
+
# * An exact match for a hostname given in +hosts.to+
|
|
176
|
+
# * The return value of the +hosts.default+ block, if given
|
|
177
|
+
# * The default value provided in the +hosts.default+ call
|
|
178
|
+
def _get_host_routing_host
|
|
179
|
+
host = self.host || ""
|
|
180
|
+
|
|
181
|
+
roda_class.opts[:host_routing_hash][host] ||
|
|
182
|
+
scope._host_routing_default(host) ||
|
|
183
|
+
roda_class.opts[:host_routing_default_host]
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
register_plugin(:host_routing, HostRouting)
|
|
189
|
+
end
|
|
190
|
+
end
|
|
@@ -99,7 +99,10 @@ class Roda
|
|
|
99
99
|
# permissions_policy.get_fullscreen
|
|
100
100
|
# # => [:self, "https://example.com", "https://*.example.com"]
|
|
101
101
|
#
|
|
102
|
-
# The clear method can be used to remove all settings from the policy.
|
|
102
|
+
# The clear method can be used to remove all settings from the policy. Empty policies
|
|
103
|
+
# do not set any headers. You can use +response.skip_permissions_policy!+ to skip
|
|
104
|
+
# setting a policy. This is faster than calling +permissions_policy.clear+, since
|
|
105
|
+
# it does not duplicate the default policy.
|
|
103
106
|
module PermissionsPolicy
|
|
104
107
|
SUPPORTED_SETTINGS = %w'
|
|
105
108
|
accelerometer
|
|
@@ -311,12 +314,19 @@ class Roda
|
|
|
311
314
|
@permissions_policy ||= roda_class.opts[:permissions_policy].dup
|
|
312
315
|
end
|
|
313
316
|
|
|
317
|
+
# Do not set a permissions policy header for this response.
|
|
318
|
+
def skip_permissions_policy!
|
|
319
|
+
@skip_permissions_policy = true
|
|
320
|
+
end
|
|
321
|
+
|
|
314
322
|
private
|
|
315
323
|
|
|
316
324
|
# Set the appropriate permissions policy header.
|
|
317
325
|
def set_default_headers
|
|
318
326
|
super
|
|
319
|
-
|
|
327
|
+
unless @skip_permissions_policy
|
|
328
|
+
(@permissions_policy || roda_class.opts[:permissions_policy]).set_header(headers)
|
|
329
|
+
end
|
|
320
330
|
end
|
|
321
331
|
end
|
|
322
332
|
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.87.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: 2024-
|
|
11
|
+
date: 2024-12-17 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rack
|
|
@@ -186,6 +186,7 @@ files:
|
|
|
186
186
|
- lib/roda/plugins/class_level_routing.rb
|
|
187
187
|
- lib/roda/plugins/class_matchers.rb
|
|
188
188
|
- lib/roda/plugins/common_logger.rb
|
|
189
|
+
- lib/roda/plugins/conditional_sessions.rb
|
|
189
190
|
- lib/roda/plugins/content_for.rb
|
|
190
191
|
- lib/roda/plugins/content_security_policy.rb
|
|
191
192
|
- lib/roda/plugins/cookie_flags.rb
|
|
@@ -224,6 +225,7 @@ files:
|
|
|
224
225
|
- lib/roda/plugins/hmac_paths.rb
|
|
225
226
|
- lib/roda/plugins/hooks.rb
|
|
226
227
|
- lib/roda/plugins/host_authorization.rb
|
|
228
|
+
- lib/roda/plugins/host_routing.rb
|
|
227
229
|
- lib/roda/plugins/hsts.rb
|
|
228
230
|
- lib/roda/plugins/indifferent_params.rb
|
|
229
231
|
- lib/roda/plugins/inject_erb.rb
|
|
@@ -326,7 +328,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
326
328
|
- !ruby/object:Gem::Version
|
|
327
329
|
version: '0'
|
|
328
330
|
requirements: []
|
|
329
|
-
rubygems_version: 3.5.
|
|
331
|
+
rubygems_version: 3.5.22
|
|
330
332
|
signing_key:
|
|
331
333
|
specification_version: 4
|
|
332
334
|
summary: Routing tree web toolkit
|