roda 3.61.0 → 3.63.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: 337e7cc074ffe0c300a4dbf9a14f72552caa5b9446fdf0ca04b9f22d9117c9c7
4
- data.tar.gz: 53a8b4ec124df8ef0efdc7efcc7bec3e0e7ea7d13fa60fb5d6adf06f50ed081e
3
+ metadata.gz: 6e19674abcd02c79572ada44fe13fc8188a4cc91b780a3fbaa39da206cf7457f
4
+ data.tar.gz: ffd0e850b4aab5e82b3f5cf307145853df9d420389ff8eb6170ec53d3e29ca57
5
5
  SHA512:
6
- metadata.gz: 78671d90145cf431a7deff333e6b75ad681252cae159b5ff09dfaba70d4b3fc17ec1f7362c52454c3f8e94e2343bd4b4d419a5c23738a6b525e9fdd79dc8846c
7
- data.tar.gz: 55b5bc0be878d58d66e0834110b47313f522e1f109b95c23348b2cb09430b01383595197db8f8db6587f10d3d9e4a7a353a2d70fb1ed4a099573309a5aabcae6
6
+ metadata.gz: d91087a996b037de3c0ecc3ca5e029f6b4bb40c5da1618048d70c0aa42ac5dcc581b6ed67e55cd9236da5463c3c224c62b09f85797daeffcb9a8fb98a16bca03
7
+ data.tar.gz: 62d2e2fdb0efa867299a764d4f7b36fc1a1e680147d32703d29451e29d2e3090a0f337c2c87ac46929a5a504b6461f92d18b50a14c62f422de4c114e43892c91
data/CHANGELOG CHANGED
@@ -1,3 +1,21 @@
1
+ = 3.63.0 (2022-12-16)
2
+
3
+ * Make mailer plugin set configured content type for body part for emails with attachments when using mail 2.8+ (jeremyevans)
4
+
5
+ * Add autoload_hash_branches plugin for autoloading file for a hash branch when there is a request for that branch (jeremyevans)
6
+
7
+ * Add mailer plugin :terminal option to make r.mail use a terminal match when provided arguments (jeremyevans)
8
+
9
+ = 3.62.0 (2022-11-14)
10
+
11
+ * Add typecast_params_sized_integers plugin for converting parameters to sized integers (jeremyevans)
12
+
13
+ * Add Integer_matcher_max plugin for setting maximum integer value matched by the Integer matcher (jeremyevans)
14
+
15
+ * Allow class matchers in the class_matchers plugin to skip matching based on regexp match values (jeremyevans)
16
+
17
+ * Fix RodaRequest#matched_path when using unescape_path plugin (jeremyevans) (#286)
18
+
1
19
  = 3.61.0 (2022-10-12)
2
20
 
3
21
  * Make Integer matcher limit integer segments to 100 characters by default (jeremyevans)
@@ -0,0 +1,41 @@
1
+ = New Features
2
+
3
+ * An Integer_matcher_max plugin has been added for setting the
4
+ maximum value matched by the Integer matcher (the minimum is
5
+ always 0, since the Integer matcher does not match negative
6
+ integers). The default maximum value when using the plugin
7
+ is 2**63-1, the maximum value for a signed 64-bit integer.
8
+ You can specify a different maximum value by passing an argument
9
+ when loading the plugin.
10
+
11
+ * A typecast_params_sized_integers plugin has been added for
12
+ converting parameters to integers only if the integer is within a
13
+ specific size. By default, the plugin supports 8-bit, 16-bit,
14
+ 32-bit, and 64-bit signed and unsigned integer types, with the
15
+ following typecast_params methods added by the plugin:
16
+
17
+ * int8, uint8, pos_int8, pos_uint8, Integer8, Integeru8
18
+ * int16, uint16, pos_int16, pos_uint16, Integer16, Integeru16
19
+ * int32, uint32, pos_int32, pos_uint32, Integer32, Integeru32
20
+ * int64, uint64, pos_int64, pos_uint64, Integer64, Integeru64
21
+
22
+ You can override what sizes are added by default by using the
23
+ :sizes option. You can also specify a :default_size option,
24
+ in which case the default int, pos_int, and Integer conversions
25
+ will use the given size. So if you want to change the default
26
+ typecast_params integer conversion behavior to only support
27
+ integer values that can fit in 64-bit signed integers, you can
28
+ use:
29
+
30
+ plugin :typecast_params_sized_integers, sizes: [64],
31
+ default_size: 64
32
+
33
+ = Other Improvements
34
+
35
+ * The block passed to the class_matcher method in the class_matchers
36
+ plugin can now return nil/false to signal that it should not match.
37
+ This is useful when the regexp argument provided matches segments
38
+ not valid for the class.
39
+
40
+ * RodaRequest#matched_path now works correctly when using the
41
+ unescape_path plugin.
@@ -0,0 +1,36 @@
1
+ = New Features
2
+
3
+ * An autoload_hash_branches plugin has been added for autoloading
4
+ route files for each hash branch, instead of requiring the route
5
+ files be loaded up front. For example, to automatically load a
6
+ route file for a hash branch on the first request to that branch:
7
+
8
+ plugin :autoload_hash_branches
9
+ autoload_hash_branch('branch_name', '/path/to/file')
10
+ autoload_hash_branch('namespace', 'branch_name', '/path/to/file')
11
+
12
+ The route file loaded should define the expected hash branch.
13
+
14
+ It is common to have route files stored in a directory, with the
15
+ file name matching the branch name. In that case, you can set
16
+ autoloading for all route files in a given directory:
17
+
18
+ plugin :autoload_hash_branches
19
+ autoload_hash_branch_dir('/path/to/dir')
20
+ autoload_hash_branch_dir('namespace', '/path/to/dir')
21
+
22
+ Note that autoloading hash branches does not work if the application
23
+ is frozen. This plugin should only be used in development mode for
24
+ faster startup, or when running tests on a subset of the application
25
+ in order to avoid loading parts of the application unrelated to what
26
+ is being tested.
27
+
28
+ * The mailer plugin now supports a :terminal plugin option to make
29
+ the r.mail method force a terminal match, similar to how r.get
30
+ and other HTTP verb methods work in standard Roda. This behavior
31
+ will become the default in Roda 4.
32
+
33
+ = Other Improvements
34
+
35
+ * The mailer plugin now correctly sets the content_type of the body
36
+ for emails with attachments when using mail 2.8.0+.
@@ -0,0 +1,54 @@
1
+ # frozen-string-literal: true
2
+
3
+ #
4
+ class Roda
5
+ module RodaPlugins
6
+ # The Integer_matcher_max plugin sets the maximum integer value
7
+ # value that the Integer class matcher will match by default.
8
+ # By default, loading this plugin sets the maximum value to
9
+ # 2**63-1, the largest signed 64-bit integer value:
10
+ #
11
+ # plugin :Integer_matcher_max
12
+ # route do |r|
13
+ # r.is Integer do
14
+ # # Matches /9223372036854775807
15
+ # # Does not match /9223372036854775808
16
+ # end
17
+ # end
18
+ #
19
+ # To specify a different maximum value, you can pass a different
20
+ # maximum value when loading the plugin:
21
+ #
22
+ # plugin :Integer_matcher_max, 2**64-1
23
+ module IntegerMatcherMax
24
+ def self.configure(app, max=nil)
25
+ if max
26
+ app::RodaRequest.class_eval do
27
+ define_method(:_match_class_max_Integer){max}
28
+ alias_method :_match_class_max_Integer, :_match_class_max_Integer
29
+ private :_match_class_max_Integer
30
+ end
31
+ end
32
+ end
33
+
34
+ module RequestMethods
35
+ private
36
+
37
+ # Do not have the Integer matcher max when over the maximum
38
+ # configured Integer value.
39
+ def _match_class_convert_Integer(value)
40
+ value = super
41
+ value if value <= _match_class_max_Integer
42
+ end
43
+
44
+ # Use 2**63-1 as the default maximum value for the Integer
45
+ # matcher.
46
+ def _match_class_max_Integer
47
+ 9223372036854775807
48
+ end
49
+ end
50
+ end
51
+
52
+ register_plugin(:Integer_matcher_max, IntegerMatcherMax)
53
+ end
54
+ end
@@ -52,9 +52,9 @@ class Roda
52
52
  end
53
53
  end
54
54
  elsif matcher == Integer
55
- if matchdata = /\A\/(\d{1,100})(?=\/|\z)/.match(@remaining_path)
55
+ if (matchdata = /\A\/(\d{1,100})(?=\/|\z)/.match(@remaining_path)) && (value = _match_class_convert_Integer(matchdata[1]))
56
56
  @remaining_path = matchdata.post_match
57
- always{yield(matchdata[1].to_i)}
57
+ always{yield(value)}
58
58
  end
59
59
  else
60
60
  path = @remaining_path
@@ -151,9 +151,9 @@ class Roda
151
151
  always{yield rp[1, len]}
152
152
  end
153
153
  elsif matcher == Integer
154
- if matchdata = /\A\/(\d{1,100})\z/.match(@remaining_path)
154
+ if (matchdata = /\A\/(\d{1,100})\z/.match(@remaining_path)) && (value = _match_class_convert_Integer(matchdata[1]))
155
155
  @remaining_path = ''
156
- always{yield(matchdata[1].to_i)}
156
+ always{yield(value)}
157
157
  end
158
158
  else
159
159
  path = @remaining_path
@@ -0,0 +1,67 @@
1
+ # frozen-string-literal: true
2
+
3
+ #
4
+ class Roda
5
+ module RodaPlugins
6
+ # The autoload_hash_branches plugin builds on the hash_branches plugin and allows for
7
+ # delaying loading of a file containing a hash branch for an application until there
8
+ # is a request that uses the hash branch. This can be useful in development
9
+ # to improvement startup time by not loading all branches up front. It can also be
10
+ # useful in testing subsets of an application by only loading the hash branches being
11
+ # tested.
12
+ #
13
+ # You can specify a single hash branch for autoloading:
14
+ #
15
+ # plugin :autoload_hash_branches
16
+ # autoload_hash_branch('branch_name', '/path/to/file')
17
+ # autoload_hash_branch('namespace', 'branch_name', '/path/to/file')
18
+ #
19
+ # You can also set the plugin to autoload load all hash branch files in a given directory.
20
+ # This will look at each .rb file in the directory, and add an autoload for it, using the
21
+ # filename without the .rb as the branch name:
22
+ #
23
+ # autoload_hash_branch_dir('/path/to/dir')
24
+ # autoload_hash_branch_dir('namespace', '/path/to/dir')
25
+ #
26
+ # In both cases, when the autoloaded file is required, it should redefine the same
27
+ # hash branch. If it does not, requests to the hash branch will result in a 404 error.
28
+ #
29
+ # This plugin will not work correctly when freezing applications, because it requires
30
+ # modifying the class at runtime as hash branches are autoloaded.
31
+ module AutoloadHashBranches
32
+ def self.load_dependencies(app)
33
+ app.plugin :hash_branches
34
+ end
35
+
36
+ module ClassMethods
37
+ # Autoload the given file when there is request for the hash branch.
38
+ # The given file should configure the hash branch specified.
39
+ def autoload_hash_branch(namespace='', segment, file)
40
+ segment = "/#{segment}"
41
+ routes = opts[:hash_branches][namespace] ||= {}
42
+ meth = routes[segment] = define_roda_method(routes[segment] || "hash_branch_#{namespace}_#{segment}", 1) do |r|
43
+ loc = method(routes[segment]).source_location
44
+ require file
45
+ # Avoid infinite loop in case method is not overridden
46
+ if method(meth).source_location != loc
47
+ send(meth, r)
48
+ end
49
+ end
50
+ nil
51
+ end
52
+
53
+ # For each .rb file in the given directory, add an autoloaded hash branch
54
+ # based on the file name.
55
+ def autoload_hash_branch_dir(namespace='', dir)
56
+ Dir.new(dir).entries.each do |file|
57
+ if file =~ /\.rb\z/i
58
+ autoload_hash_branch(namespace, file.sub(/\.rb\z/i, ''), File.join(dir, file))
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ register_plugin(:autoload_hash_branches, AutoloadHashBranches)
66
+ end
67
+ end
@@ -28,6 +28,18 @@ class Roda
28
28
  # This is useful to DRY up code if you are using the same type of pattern and
29
29
  # type conversion in multiple places in your application.
30
30
  #
31
+ # If you have a segment match the passed regexp, but decide during block
32
+ # processing that you do not want to treat it as a match, you can have the
33
+ # block return nil or false. This is useful if you want to make sure you
34
+ # are using valid data:
35
+ #
36
+ # class_matcher(Date, /(\dd\d)-(\d\d)-(\d\d)/) do |y, m, d|
37
+ # y = y.to_i
38
+ # m = m.to_i
39
+ # d = d.to_i
40
+ # [Date.new(y, m, d)] if Date.valid_date?(y, m, d)
41
+ # end
42
+ #
31
43
  # This plugin does not work with the params_capturing plugin, as it does not
32
44
  # offer the ability to associate block arguments with named keys.
33
45
  module ClassMatchers
@@ -56,7 +56,7 @@ class Roda
56
56
  # r.halt(:template) if r.params['a']
57
57
  #
58
58
  # # symbol_views plugin, specifying status code, headers, and template file to render as body
59
- # r.halt(500, 'header=>'value', :other_template) if r.params['c']
59
+ # r.halt(500, {'header'=>'value'}, :other_template) if r.params['c']
60
60
  #
61
61
  # # json plugin, specifying status code and JSON body
62
62
  # r.halt(500, [{'error'=>'foo'}]) if r.params['b']
@@ -115,6 +115,11 @@ class Roda
115
115
  #
116
116
  # plugin :mailer, content_type: 'text/html'
117
117
  #
118
+ # For backwards compatibility reasons, the +r.mail+ method does not do
119
+ # a terminal match by default if provided arguments (unlike +r.get+ and
120
+ # +r.post+). You can pass the :terminal option to make +r.mail+ enforce
121
+ # a terminal match if provided arguments.
122
+ #
118
123
  # The mailer plugin does support being used inside a Roda application
119
124
  # that is handling web requests, where the routing block for mails and
120
125
  # web requests is shared. However, it's recommended that you create a
@@ -163,7 +168,8 @@ class Roda
163
168
  # any arguments passed to the +mail+ or +sendmail+ Roda class methods.
164
169
  def mail(*args)
165
170
  if @env["REQUEST_METHOD"] == "MAIL"
166
- if_match(args) do |*vs|
171
+ # RODA4: Make terminal match the default
172
+ send(roda_class.opts[:mailer][:terminal] ? :_verb : :if_match, args) do |*vs|
167
173
  yield(*(vs + @env['roda.mail_args']))
168
174
  end
169
175
  end
@@ -190,9 +196,9 @@ class Roda
190
196
 
191
197
  if content_type = header_content_type || roda_class.opts[:mailer][:content_type]
192
198
  if mail.multipart?
193
- if mail.content_type =~ /multipart\/mixed/ &&
199
+ if /multipart\/mixed/ =~ mail.content_type &&
194
200
  mail.parts.length >= 2 &&
195
- (part = mail.parts.find{|p| !p.attachment && p.content_type == "text/plain"})
201
+ (part = mail.parts.find{|p| !p.attachment && (p.encoded; /text\/plain/ =~ p.content_type)})
196
202
  part.content_type = content_type
197
203
  end
198
204
  else
@@ -526,9 +526,10 @@ class Roda
526
526
  handle_type(:int, :max_input_bytesize=>100) do |v|
527
527
  string_or_numeric!(v) && v.to_i
528
528
  end
529
+ alias base_convert_int convert_int
529
530
 
530
531
  handle_type(:pos_int, :max_input_bytesize=>100) do |v|
531
- if (v = convert_int(v)) && v > 0
532
+ if (v = base_convert_int(v)) && v > 0
532
533
  v
533
534
  end
534
535
  end
@@ -547,6 +548,7 @@ class Roda
547
548
  end
548
549
  end
549
550
  end
551
+ alias base_convert_Integer convert_Integer
550
552
 
551
553
  handle_type(:float, :max_input_bytesize=>1000) do |v|
552
554
  string_or_numeric!(v) && v.to_f
@@ -0,0 +1,107 @@
1
+ # frozen-string-literal: true
2
+
3
+ #
4
+ class Roda
5
+ module RodaPlugins
6
+ # The typecast_params_sized_integers plugin adds sized integer conversion
7
+ # methods to typecast_params:
8
+ #
9
+ # * int8, uint8, pos_int8, pos_uint8, Integer8, Integeru8
10
+ # * int16, uint16, pos_int16, pos_uint16, Integer16, Integeru16
11
+ # * int32, uint32, pos_int32, pos_uint32, Integer32, Integeru32
12
+ # * int64, uint64, pos_int64, pos_uint64, Integer64, Integeru64
13
+ #
14
+ # The int*, pos_int*, and Integer* methods operate the same as the
15
+ # standard int, pos_int, and Integer methods in typecast_params,
16
+ # except that they will only handle parameter values in the given
17
+ # range for the signed integer type. The uint*, pos_int*, and
18
+ # Integeru* methods are similar to the int*, pos_int*, and
19
+ # Integer* methods, except they use the range of the unsigned
20
+ # integer type instead of the range of the signed integer type.
21
+ #
22
+ # Here are the signed and unsigned integer type ranges:
23
+ # 8 :: [-128, 127], [0, 255]
24
+ # 16 :: [-32768, 32767], [0, 65535]
25
+ # 32 :: [-2147483648, 2147483647], [0, 4294967295]
26
+ # 64 :: [-9223372036854775808, 9223372036854775807], [0, 18446744073709551615]
27
+ #
28
+ # To only create methods for certain integer sizes, you can pass a
29
+ # :sizes option when loading the plugin, and it will only create
30
+ # methods for the sizes you specify.
31
+ #
32
+ # You can provide a :default_size option when loading the plugin,
33
+ # in which case the int, uint, pos_int, pos_uint, Integer, and Integeru,
34
+ # typecast_params conversion methods will be aliases to the conversion
35
+ # methods for the given sized type:
36
+ #
37
+ # plugin :typecast_params_sized_integers, default_size: 64
38
+ #
39
+ # route do |r|
40
+ # # Returns nil unless param.to_i > 0 && param.to_i <= 9223372036854775807
41
+ # typecast_params.pos_int('param_name')
42
+ # end
43
+ module TypecastParamsSizedIntegers
44
+ def self.load_dependencies(app, opts=OPTS)
45
+ app.plugin :typecast_params do
46
+ (opts[:sizes] || [8, 16, 32, 64]).each do |i|
47
+ # Avoid defining the same methods more than once
48
+ next if method_defined?(:"pos_int#{i}")
49
+
50
+ min_signed = -(2**(i-1))
51
+ max_signed = 2**(i-1)-1
52
+ max_unsigned = 2**i-1
53
+
54
+ handle_type(:"int#{i}", :max_input_bytesize=>100) do |v|
55
+ if (v = base_convert_int(v)) && v >= min_signed && v <= max_signed
56
+ v
57
+ end
58
+ end
59
+
60
+ handle_type(:"uint#{i}", :max_input_bytesize=>100) do |v|
61
+ if (v = base_convert_int(v)) && v >= 0 && v <= max_unsigned
62
+ v
63
+ end
64
+ end
65
+
66
+ handle_type(:"pos_int#{i}", :max_input_bytesize=>100) do |v|
67
+ if (v = base_convert_int(v)) && v > 0 && v <= max_signed
68
+ v
69
+ end
70
+ end
71
+
72
+ handle_type(:"pos_uint#{i}", :max_input_bytesize=>100) do |v|
73
+ if (v = base_convert_int(v)) && v > 0 && v <= max_unsigned
74
+ v
75
+ end
76
+ end
77
+
78
+ handle_type(:"Integer#{i}", :max_input_bytesize=>100) do |v|
79
+ if (v = base_convert_Integer(v)) && v >= min_signed && v <= max_signed
80
+ v
81
+ end
82
+ end
83
+
84
+ handle_type(:"Integeru#{i}", :max_input_bytesize=>100) do |v|
85
+ if (v = base_convert_Integer(v)) && v >= 0 && v <= max_unsigned
86
+ v
87
+ end
88
+ end
89
+ end
90
+ end
91
+
92
+ if default = opts[:default_size]
93
+ app::TypecastParams.class_eval do
94
+ %w[int uint pos_int pos_uint Integer Integeru].each do |type|
95
+ ['', 'convert_', '_convert_array_', '_max_input_bytesize_for_'].each do |prefix|
96
+ alias_method :"#{prefix}#{type}", :"#{prefix}#{type}#{default}"
97
+ end
98
+ alias_method :"#{type}!", :"#{type}#{default}!"
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
104
+
105
+ register_plugin(:typecast_params_sized_integers, TypecastParamsSizedIntegers)
106
+ end
107
+ end
@@ -20,6 +20,13 @@ class Roda
20
20
  # end
21
21
  module UnescapePath
22
22
  module RequestMethods
23
+ # Make sure the matched path calculation handles the unescaping
24
+ # of the remaining path.
25
+ def matched_path
26
+ e = @env
27
+ Rack::Utils.unescape(e["SCRIPT_NAME"] + e["PATH_INFO"]).chomp(@remaining_path)
28
+ end
29
+
23
30
  private
24
31
 
25
32
  # Unescape the path.
data/lib/roda/request.rb CHANGED
@@ -443,7 +443,16 @@ class Roda
443
443
  # Match integer segment of up to 100 decimal characters, and yield resulting value as an
444
444
  # integer.
445
445
  def _match_class_Integer
446
- consume(/\A\/(\d{1,100})(?=\/|\z)/){|i| [i.to_i]}
446
+ consume(/\A\/(\d{1,100})(?=\/|\z)/) do |i|
447
+ if i = _match_class_convert_Integer(i)
448
+ [i]
449
+ end
450
+ end
451
+ end
452
+
453
+ # Convert the segment matched by the Integer matcher to an integer.
454
+ def _match_class_convert_Integer(value)
455
+ value.to_i
447
456
  end
448
457
 
449
458
  # Match only if all of the arguments in the given array match.
@@ -548,9 +557,11 @@ class Roda
548
557
  # path from PATH_INFO, and updates captures with any regex captures.
549
558
  def consume(pattern)
550
559
  if matchdata = pattern.match(@remaining_path)
551
- @remaining_path = matchdata.post_match
552
560
  captures = matchdata.captures
553
- captures = yield(*captures) if defined?(yield)
561
+ if defined?(yield)
562
+ return unless captures = yield(*captures)
563
+ end
564
+ @remaining_path = matchdata.post_match
554
565
  @captures.concat(captures)
555
566
  end
556
567
  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 = 61
7
+ RodaMinorVersion = 63
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.61.0
4
+ version: 3.63.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: 2022-10-12 00:00:00.000000000 Z
11
+ date: 2022-12-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -234,6 +234,8 @@ extra_rdoc_files:
234
234
  - doc/release_notes/3.6.0.txt
235
235
  - doc/release_notes/3.60.0.txt
236
236
  - doc/release_notes/3.61.0.txt
237
+ - doc/release_notes/3.62.0.txt
238
+ - doc/release_notes/3.63.0.txt
237
239
  - doc/release_notes/3.7.0.txt
238
240
  - doc/release_notes/3.8.0.txt
239
241
  - doc/release_notes/3.9.0.txt
@@ -302,12 +304,15 @@ files:
302
304
  - doc/release_notes/3.6.0.txt
303
305
  - doc/release_notes/3.60.0.txt
304
306
  - doc/release_notes/3.61.0.txt
307
+ - doc/release_notes/3.62.0.txt
308
+ - doc/release_notes/3.63.0.txt
305
309
  - doc/release_notes/3.7.0.txt
306
310
  - doc/release_notes/3.8.0.txt
307
311
  - doc/release_notes/3.9.0.txt
308
312
  - lib/roda.rb
309
313
  - lib/roda/cache.rb
310
314
  - lib/roda/plugins.rb
315
+ - lib/roda/plugins/Integer_matcher_max.rb
311
316
  - lib/roda/plugins/_after_hook.rb
312
317
  - lib/roda/plugins/_before_hook.rb
313
318
  - lib/roda/plugins/_optimized_matching.rb
@@ -317,6 +322,7 @@ files:
317
322
  - lib/roda/plugins/all_verbs.rb
318
323
  - lib/roda/plugins/assets.rb
319
324
  - lib/roda/plugins/assets_preloading.rb
325
+ - lib/roda/plugins/autoload_hash_branches.rb
320
326
  - lib/roda/plugins/backtracking_array.rb
321
327
  - lib/roda/plugins/branch_locals.rb
322
328
  - lib/roda/plugins/caching.rb
@@ -423,6 +429,7 @@ files:
423
429
  - lib/roda/plugins/timestamp_public.rb
424
430
  - lib/roda/plugins/type_routing.rb
425
431
  - lib/roda/plugins/typecast_params.rb
432
+ - lib/roda/plugins/typecast_params_sized_integers.rb
426
433
  - lib/roda/plugins/unescape_path.rb
427
434
  - lib/roda/plugins/view_options.rb
428
435
  - lib/roda/request.rb
@@ -453,7 +460,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
453
460
  - !ruby/object:Gem::Version
454
461
  version: '0'
455
462
  requirements: []
456
- rubygems_version: 3.3.7
463
+ rubygems_version: 3.3.26
457
464
  signing_key:
458
465
  specification_version: 4
459
466
  summary: Routing tree web toolkit