roda 3.84.0 → 3.85.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: 847704410e729b17a70bb30b3da0e7a2a539320c3394947269ca00c680e57c97
4
- data.tar.gz: 8487b70418d90a811cca396a7c8fe52f87d9c6a93f34c7ca66316d8cb15a30b2
3
+ metadata.gz: a862ed0414bf90081e744ed7c50ac19806f141ebeae8c699d5f96b9a4e718e10
4
+ data.tar.gz: b1fcd622255d24044ba7f26c2c3f35e5fc8ea7f30b2ba577bec5fe306ca75c76
5
5
  SHA512:
6
- metadata.gz: 94e7e1d8318aed73f0e491d8dae066b5a0c05a759cdadd690073d1ca8600acbb6269b0d1ab0cb51e038835563568e2a83db154dcf5ab5f72d4cfc809c0e94da5
7
- data.tar.gz: 52e999ea7a16b47ad65b25ca52208f9b51d13ab8458ca24404e74606a9f3b6c9c5ea18b1bcb088b3e3495ac8f520b895af8eb23da07a85e96881f9008bafda1e
6
+ metadata.gz: '086d21f564d66b14fafabbb99c6d670559c12fed91105c1acb9e5e9147623bf15de0730d35f2b5bd098a6e26aba0d6a73497a914ee23d97d8cb58dbbf0f6dd5b'
7
+ data.tar.gz: 713dee3419ce7bf52742d7da6be4243c393b393aeb5762dcd0dc61a58d691e586226636b5df687e56e0dd280a89930a18b1e32f3c9b499516afc461cf92fcf4c
@@ -23,27 +23,28 @@ class Roda
23
23
  module IntegerMatcherMax
24
24
  def self.configure(app, max=nil)
25
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
26
+ app.class_eval do
27
+ meth = :_max_value_convert_class_Integer
28
+ define_method(meth){max}
29
+ alias_method meth, meth
30
+ private meth
30
31
  end
31
32
  end
32
33
  end
33
34
 
34
- module RequestMethods
35
+ module InstanceMethods
35
36
  private
36
37
 
37
38
  # Do not have the Integer matcher max when over the maximum
38
39
  # configured Integer value.
39
- def _match_class_convert_Integer(value)
40
+ def _convert_class_Integer(value)
40
41
  value = super
41
- value if value <= _match_class_max_Integer
42
+ value if value <= _max_value_convert_class_Integer
42
43
  end
43
44
 
44
45
  # Use 2**63-1 as the default maximum value for the Integer
45
46
  # matcher.
46
- def _match_class_max_Integer
47
+ def _max_value_convert_class_Integer
47
48
  9223372036854775807
48
49
  end
49
50
  end
@@ -52,7 +52,7 @@ class Roda
52
52
  end
53
53
  end
54
54
  elsif matcher == Integer
55
- if (matchdata = /\A\/(\d{1,100})(?=\/|\z)/.match(@remaining_path)) && (value = _match_class_convert_Integer(matchdata[1]))
55
+ if (matchdata = /\A\/(\d{1,100})(?=\/|\z)/.match(@remaining_path)) && (value = scope.send(:_convert_class_Integer, matchdata[1]))
56
56
  @remaining_path = matchdata.post_match
57
57
  always{yield(value)}
58
58
  end
@@ -151,7 +151,7 @@ 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)) && (value = _match_class_convert_Integer(matchdata[1]))
154
+ if (matchdata = /\A\/(\d{1,100})\z/.match(@remaining_path)) && (value = scope.send(:_convert_class_Integer, matchdata[1]))
155
155
  @remaining_path = ''
156
156
  always{yield(value)}
157
157
  end
@@ -0,0 +1,107 @@
1
+ # frozen-string-literal: true
2
+
3
+ #
4
+ class Roda
5
+ module RodaPlugins
6
+ module SymbolClassMatchers_
7
+ module ClassMethods
8
+ private
9
+
10
+ # Backend of symbol_matcher and class_matcher.
11
+ def _symbol_class_matcher(expected_class, obj, matcher, block, &request_class_block)
12
+ unless obj.is_a?(expected_class)
13
+ raise RodaError, "Invalid type passed to class_matcher or symbol_matcher: #{matcher.inspect}"
14
+ end
15
+
16
+ if obj.is_a?(Symbol)
17
+ type = "symbol"
18
+ meth = :"match_symbol_#{obj}"
19
+ else
20
+ type = "class"
21
+ meth = :"_match_class_#{obj}"
22
+ end
23
+
24
+ case matcher
25
+ when Regexp
26
+ regexp = matcher
27
+ consume_regexp = self::RodaRequest.send(:consume_pattern, regexp)
28
+ when Symbol
29
+ unless opts[:symbol_matchers]
30
+ raise RodaError, "cannot provide Symbol matcher to class_matcher unless using symbol_matchers plugin: #{matcher.inspect}"
31
+ end
32
+
33
+ regexp, consume_regexp, matcher_block = opts[:symbol_matchers][matcher]
34
+
35
+ unless regexp
36
+ raise RodaError, "unregistered symbol matcher given to #{type}_matcher: #{matcher.inspect}"
37
+ end
38
+
39
+ block = _merge_matcher_blocks(type, obj, block, matcher_block)
40
+ when Class
41
+ unless opts[:class_matchers]
42
+ raise RodaError, "cannot provide Class matcher to symbol_matcher unless using class_matchers plugin: #{matcher.inspect}"
43
+ end
44
+
45
+ regexp, consume_regexp, matcher_block = opts[:class_matchers][matcher]
46
+ unless regexp
47
+ raise RodaError, "unregistered class matcher given to #{type}_matcher: #{matcher.inspect}"
48
+ end
49
+ block = _merge_matcher_blocks(type, obj, block, matcher_block)
50
+ else
51
+ raise RodaError, "unsupported matcher given to #{type}_matcher: #{matcher.inspect}"
52
+ end
53
+
54
+ if block.is_a?(Symbol)
55
+ convert_meth = block
56
+ elsif block
57
+ convert_meth = :"_convert_#{type}_#{obj}"
58
+ define_method(convert_meth, &block)
59
+ private convert_meth
60
+ end
61
+
62
+ array = opts[:"#{type}_matchers"][obj] = [regexp, consume_regexp, convert_meth].freeze
63
+
64
+ self::RodaRequest.class_eval do
65
+ class_exec(meth, array, &request_class_block)
66
+ private meth
67
+ end
68
+
69
+ nil
70
+ end
71
+
72
+ # If both block and matche_meth are given,
73
+ # define a method for block, and then return a
74
+ # proc that calls matcher_meth first, and only calls
75
+ # the newly defined method with the return values of matcher_meth
76
+ # if matcher_method returns a truthy value.
77
+ # Otherwise, return matcher_meth or block.
78
+ def _merge_matcher_blocks(type, obj, block, matcher_meth)
79
+ if matcher_meth
80
+ if block
81
+ convert_meth = :"_convert_merge_#{type}_#{obj}"
82
+ define_method(convert_meth, &block)
83
+ private convert_meth
84
+
85
+ proc do |*a|
86
+ if captures = send(matcher_meth, *a)
87
+ if captures.is_a?(Array)
88
+ send(convert_meth, *captures)
89
+ else
90
+ send(convert_meth, captures)
91
+ end
92
+ end
93
+ end
94
+ else
95
+ matcher_meth
96
+ end
97
+ else
98
+ block
99
+ end
100
+ end
101
+ end
102
+ end
103
+
104
+ register_plugin(:_symbol_class_matchers, SymbolClassMatchers_)
105
+ end
106
+ end
107
+
@@ -16,10 +16,11 @@ class Roda
16
16
  # to wrap template blocks with arbitrary output and then inject the
17
17
  # wrapped output into the template.
18
18
  #
19
- # If the output buffer object responds to +capture+ (e.g. when
20
- # +erubi/capture_block+ is being used as the template engine),
21
- # this will call +capture+ on the output buffer object, instead
22
- # of setting the output buffer object temporarily to a new object.
19
+ # If the output buffer object responds to +capture+ and is not
20
+ # an instance of String (e.g. when +erubi/capture_block+ is being
21
+ # used as the template engine), this will call +capture+ on the
22
+ # output buffer object, instead of setting the output buffer object
23
+ # temporarily to a new object.
23
24
  module CaptureERB
24
25
  def self.load_dependencies(app)
25
26
  app.plugin :render
@@ -34,7 +35,7 @@ class Roda
34
35
  outvar = render_opts[:template_opts][:outvar]
35
36
  buf_was = instance_variable_get(outvar)
36
37
 
37
- if buf_was.respond_to?(:capture)
38
+ if buf_was.respond_to?(:capture) && !buf_was.instance_of?(String)
38
39
  buf_was.capture(&block)
39
40
  else
40
41
  begin
@@ -12,11 +12,10 @@ class Roda
12
12
  # # ...
13
13
  # end
14
14
  #
15
- # You can register a Date class matcher for that regexp (note that
16
- # the block must return an array):
15
+ # You can register a Date class matcher for that regexp:
17
16
  #
18
17
  # class_matcher(Date, /(\d\d\d\d)-(\d\d)-(\d\d)/) do |y, m, d|
19
- # [Date.new(y.to_i, m.to_i, d.to_i)]
18
+ # Date.new(y.to_i, m.to_i, d.to_i)
20
19
  # end
21
20
  #
22
21
  # And then use the Date class as a matcher, and it will yield a Date object:
@@ -26,7 +25,8 @@ class Roda
26
25
  # end
27
26
  #
28
27
  # This is useful to DRY up code if you are using the same type of pattern and
29
- # type conversion in multiple places in your application.
28
+ # type conversion in multiple places in your application. You can have the
29
+ # block return an array to yield multiple captures.
30
30
  #
31
31
  # If you have a segment match the passed regexp, but decide during block
32
32
  # processing that you do not want to treat it as a match, you can have the
@@ -37,22 +37,99 @@ class Roda
37
37
  # y = y.to_i
38
38
  # m = m.to_i
39
39
  # d = d.to_i
40
- # [Date.new(y, m, d)] if Date.valid_date?(y, m, d)
40
+ # Date.new(y, m, d) if Date.valid_date?(y, m, d)
41
41
  # end
42
42
  #
43
+ # The second argument to class_matcher can be a class already registered
44
+ # as a class matcher. This can DRY up code that wants a conversion
45
+ # performed by an existing class matcher:
46
+ #
47
+ # class_matcher Employee, Integer do |id|
48
+ # Employee[id]
49
+ # end
50
+ #
51
+ # With the above example, the Integer matcher performs the conversion to
52
+ # integer, so +id+ is yielded as an integer. The block then looks up the
53
+ # employee with that id. If there is no employee with that id, then
54
+ # the Employee matcher will not match.
55
+ #
56
+ # If using the symbol_matchers plugin, you can provide a recognized symbol
57
+ # matcher as the second argument to class_matcher, and it will work in
58
+ # a similar manner:
59
+ #
60
+ # symbol_matcher(:employee_id, /E-(\d{6})/) do |employee_id|
61
+ # employee_id.to_i
62
+ # end
63
+ # class_matcher Employee, :employee_id do |id|
64
+ # Employee[id]
65
+ # end
66
+ #
67
+ # Blocks passed to the class_matchers plugin are evaluated in route
68
+ # block context.
69
+ #
43
70
  # This plugin does not work with the params_capturing plugin, as it does not
44
71
  # offer the ability to associate block arguments with named keys.
45
72
  module ClassMatchers
73
+ def self.load_dependencies(app)
74
+ app.plugin :_symbol_class_matchers
75
+ end
76
+
77
+ def self.configure(app)
78
+ app.opts[:class_matchers] ||= {
79
+ Integer=>[/(\d{1,100})/, /\A\/(\d{1,100})(?=\/|\z)/, :_convert_class_Integer].freeze,
80
+ String=>[/([^\/]+)/, nil, nil].freeze
81
+ }
82
+ end
83
+
46
84
  module ClassMethods
47
- # Set the regexp to use for the given class. The block given will be
48
- # called with all matched values from the regexp, and should return an
49
- # array with the captures to yield to the match block.
50
- def class_matcher(klass, re, &block)
51
- meth = :"_match_class_#{klass}"
52
- self::RodaRequest.class_eval do
53
- consume_re = consume_pattern(re)
54
- define_method(meth){consume(consume_re, &block)}
55
- private meth
85
+ # Set the matcher and block to use for the given class.
86
+ # The matcher can be a regexp, registered class matcher, or registered symbol
87
+ # matcher (if using the symbol_matchers plugin).
88
+ #
89
+ # If providing a regexp, the block given will be called with all regexp captures.
90
+ # If providing a registered class or symbol, the block will be called with the
91
+ # captures returned by the block for the registered class or symbol, or the regexp
92
+ # captures if no block was registered with the class or symbol. In either case,
93
+ # if a block is given, it should return an array with the captures to yield to
94
+ # the match block.
95
+ def class_matcher(klass, matcher, &block)
96
+ _symbol_class_matcher(Class, klass, matcher, block) do |meth, (_, regexp, convert_meth)|
97
+ if regexp
98
+ define_method(meth){consume(regexp, convert_meth)}
99
+ else
100
+ define_method(meth){_consume_segment(convert_meth)}
101
+ end
102
+ end
103
+ end
104
+
105
+ # Freeze the class_matchers hash when freezing the app.
106
+ def freeze
107
+ opts[:class_matchers].freeze
108
+ super
109
+ end
110
+ end
111
+
112
+ module RequestMethods
113
+ # Use faster approach for segment matching. This is used for
114
+ # matchers based on the String class matcher, and avoids the
115
+ # use of regular expressions for scanning.
116
+ def _consume_segment(convert_meth)
117
+ rp = @remaining_path
118
+ if _match_class_String
119
+ if convert_meth
120
+ if captures = scope.send(convert_meth, @captures.pop)
121
+ if captures.is_a?(Array)
122
+ @captures.concat(captures)
123
+ else
124
+ @captures << captures
125
+ end
126
+ else
127
+ @remaining_path = rp
128
+ nil
129
+ end
130
+ else
131
+ true
132
+ end
56
133
  end
57
134
  end
58
135
  end
@@ -21,6 +21,10 @@ class Roda
21
21
  #
22
22
  # r.is "foo", String
23
23
  # r.is "foo", :bar
24
+ #
25
+ # If used with the symbol_matchers plugin, this plugin respects the regexps
26
+ # for the registered symbols, but it does not perform the conversions, the
27
+ # captures for the regexp are used directly as the captures for the match method.
24
28
  module PlaceholderStringMatchers
25
29
  def self.load_dependencies(app)
26
30
  app.plugin :_symbol_regexp_matchers
@@ -42,12 +42,12 @@ class Roda
42
42
  # end
43
43
  module Public
44
44
  SPLIT = Regexp.union(*[File::SEPARATOR, File::ALT_SEPARATOR].compact)
45
- PARSER = URI::DEFAULT_PARSER
46
45
  RACK_FILES = defined?(Rack::Files) ? Rack::Files : Rack::File
47
46
  ENCODING_MAP = {:zstd=>'zstd', :brotli=>'br', :gzip=>'gzip'}.freeze
48
47
  ENCODING_EXTENSIONS = {'br'=>'.br', 'gzip'=>'.gz', 'zstd'=>'.zst'}.freeze
49
48
 
50
49
  # :nocov:
50
+ PARSER = defined?(::URI::RFC2396_PARSER) ? ::URI::RFC2396_PARSER : ::URI::DEFAULT_PARSER
51
51
  MATCH_METHOD = RUBY_VERSION >= '2.4' ? :match? : :match
52
52
  # :nocov:
53
53
 
@@ -48,7 +48,7 @@ class Roda
48
48
  #
49
49
  # :allowed_paths :: Set the template paths to allow. Attempts to render paths outside
50
50
  # of these paths will raise an error. Defaults to the +:views+ directory.
51
- # :cache :: nil/false to explicitly disable premanent template caching. By default, permanent
51
+ # :cache :: nil/false to explicitly disable permanent template caching. By default, permanent
52
52
  # template caching is disabled by default if RACK_ENV is development. When permanent
53
53
  # template caching is disabled, for templates with paths in the file system, the
54
54
  # modification time of the file will be checked on every render, and if it has changed,
@@ -23,7 +23,7 @@ class Roda
23
23
  #
24
24
  # :d :: <tt>/(\d+)/</tt>, a decimal segment
25
25
  # :rest :: <tt>/(.*)/</tt>, all remaining characters, if any
26
- # :w :: <tt>/(\w+)/</tt>, a alphanumeric segment
26
+ # :w :: <tt>/(\w+)/</tt>, an alphanumeric segment
27
27
  #
28
28
  # If the placeholder_string_matchers plugin is loaded, this feature also applies to
29
29
  # placeholders in strings, so the following:
@@ -39,11 +39,10 @@ class Roda
39
39
  # be loaded first.
40
40
  #
41
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:
42
+ # for all matches to allow for type conversion:
44
43
  #
45
44
  # 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)]
45
+ # Date.new(y.to_i, m.to_i, d.to_i)
47
46
  # end
48
47
  #
49
48
  # route do |r|
@@ -61,29 +60,80 @@ class Roda
61
60
  # y = y.to_i
62
61
  # m = m.to_i
63
62
  # d = d.to_i
64
- # [Date.new(y, m, d)] if Date.valid_date?(y, m, d)
63
+ # Date.new(y, m, d) if Date.valid_date?(y, m, d)
65
64
  # end
66
65
  #
67
- # However, if providing a block to the symbol_matchers plugin, the symbol may
68
- # not work with the params_capturing plugin.
66
+ # You can have the block return an array to yield multiple captures.
67
+ #
68
+ # The second argument to symbol_matcher can be a symbol already registered
69
+ # as a symbol matcher. This can DRY up code that wants a conversion
70
+ # performed by an existing class matcher or to use the same regexp:
71
+ #
72
+ # symbol_matcher :employee_id, :d do |id|
73
+ # id.to_i
74
+ # end
75
+ # symbol_matcher :employee, :employee_id do |id|
76
+ # Employee[id]
77
+ # end
78
+ #
79
+ # With the above example, the :d matcher matches only decimal strings, but
80
+ # yields them as string. The registered :employee_id matcher converts the
81
+ # decimal string to an integer. The registered :employee matcher builds
82
+ # on that and uses the integer to lookup the related employee. If there is
83
+ # no employee with that id, then the :employee matcher will not match.
84
+ #
85
+ # If using the class_matchers plugin, you can provide a recognized class
86
+ # matcher as the second argument to symbol_matcher, and it will work in
87
+ # a similar manner:
88
+ #
89
+ # symbol_matcher :employee, Integer do |id|
90
+ # Employee[id]
91
+ # end
92
+ #
93
+ # Blocks passed to the symbol matchers plugin are evaluated in route
94
+ # block context.
95
+ #
96
+ # If providing a block to the symbol_matchers plugin, the symbol may
97
+ # not work with the params_capturing plugin. Note that the use of
98
+ # symbol matchers inside strings when using the placeholder_string_matchers
99
+ # plugin only uses the regexp, it does not respect the conversion blocks
100
+ # registered with the symbols.
69
101
  module SymbolMatchers
70
102
  def self.load_dependencies(app)
71
103
  app.plugin :_symbol_regexp_matchers
104
+ app.plugin :_symbol_class_matchers
72
105
  end
73
106
 
74
107
  def self.configure(app)
108
+ app.opts[:symbol_matchers] ||= {}
75
109
  app.symbol_matcher(:d, /(\d+)/)
76
110
  app.symbol_matcher(:w, /(\w+)/)
77
111
  app.symbol_matcher(:rest, /(.*)/)
78
112
  end
79
113
 
80
114
  module ClassMethods
81
- # Set the regexp to use for the given symbol, instead of the default.
82
- def symbol_matcher(s, re, &block)
83
- meth = :"match_symbol_#{s}"
84
- array = [re, block].freeze
85
- self::RodaRequest.send(:define_method, meth){array}
86
- self::RodaRequest.send(:private, meth)
115
+ # Set the matcher and block to use for the given class.
116
+ # The matcher can be a regexp, registered symbol matcher, or registered class
117
+ # matcher (if using the class_matchers plugin).
118
+ #
119
+ # If providing a regexp, the block given will be called with all regexp captures.
120
+ # If providing a registered symbol or class, the block will be called with the
121
+ # captures returned by the block for the registered symbol or class, or the regexp
122
+ # captures if no block was registered with the symbol or class. In either case,
123
+ # if a block is given, it should return an array with the captures to yield to
124
+ # the match block.
125
+ def symbol_matcher(s, matcher, &block)
126
+ _symbol_class_matcher(Symbol, s, matcher, block) do |meth, array|
127
+ define_method(meth){array}
128
+ end
129
+
130
+ nil
131
+ end
132
+
133
+ # Freeze the class_matchers hash when freezing the app.
134
+ def freeze
135
+ opts[:symbol_matchers].freeze
136
+ super
87
137
  end
88
138
  end
89
139
 
@@ -97,8 +147,13 @@ class Roda
97
147
  meth = :"match_symbol_#{s}"
98
148
  if respond_to?(meth, true)
99
149
  # Allow calling private match methods
100
- re, block = send(meth)
101
- consume(self.class.cached_matcher(re){re}, &block)
150
+ _, re, convert_meth = send(meth)
151
+ if re
152
+ consume(re, convert_meth)
153
+ else
154
+ # defined in class_matchers plugin
155
+ _consume_segment(convert_meth)
156
+ end
102
157
  else
103
158
  super
104
159
  end
data/lib/roda/request.rb CHANGED
@@ -443,16 +443,7 @@ 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)/) 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
446
+ consume(/\A\/(\d{1,100})(?=\/|\z)/, :_convert_class_Integer)
456
447
  end
457
448
 
458
449
  # Match only if all of the arguments in the given array match.
@@ -555,14 +546,26 @@ class Roda
555
546
  # match, returns false without changes. Otherwise, modifies
556
547
  # SCRIPT_NAME to include the matched path, removes the matched
557
548
  # path from PATH_INFO, and updates captures with any regex captures.
558
- def consume(pattern)
549
+ def consume(pattern, meth=nil)
559
550
  if matchdata = pattern.match(@remaining_path)
560
551
  captures = matchdata.captures
561
- if defined?(yield)
552
+
553
+ if meth
554
+ return unless captures = scope.send(meth, *captures)
555
+ # :nocov:
556
+ elsif defined?(yield)
557
+ # RODA4: Remove
562
558
  return unless captures = yield(*captures)
559
+ # :nocov:
563
560
  end
561
+
564
562
  @remaining_path = matchdata.post_match
565
- @captures.concat(captures)
563
+
564
+ if captures.is_a?(Array)
565
+ @captures.concat(captures)
566
+ else
567
+ @captures << captures
568
+ end
566
569
  end
567
570
  end
568
571
 
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 = 84
7
+ RodaMinorVersion = 85
8
8
 
9
9
  # The patch version of Roda, updated only for bug fixes from the last
10
10
  # feature release.
data/lib/roda.rb CHANGED
@@ -570,6 +570,13 @@ WARNING
570
570
  def session
571
571
  @_request.session
572
572
  end
573
+
574
+ private
575
+
576
+ # Convert the segment matched by the Integer matcher to an integer.
577
+ def _convert_class_Integer(value)
578
+ value.to_i
579
+ end
573
580
  end
574
581
  end
575
582
  end
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.84.0
4
+ version: 3.85.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-09-12 00:00:00.000000000 Z
11
+ date: 2024-10-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -167,6 +167,7 @@ files:
167
167
  - lib/roda/plugins/_base64.rb
168
168
  - lib/roda/plugins/_before_hook.rb
169
169
  - lib/roda/plugins/_optimized_matching.rb
170
+ - lib/roda/plugins/_symbol_class_matchers.rb
170
171
  - lib/roda/plugins/_symbol_regexp_matchers.rb
171
172
  - lib/roda/plugins/additional_render_engines.rb
172
173
  - lib/roda/plugins/additional_view_directories.rb