roda 3.45.0 → 3.46.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +4 -0
- data/README.rdoc +0 -1
- data/doc/release_notes/3.46.0.txt +19 -0
- data/lib/roda.rb +4 -0
- data/lib/roda/plugins/_optimized_matching.rb +137 -0
- data/lib/roda/plugins/content_for.rb +1 -2
- data/lib/roda/request.rb +5 -7
- data/lib/roda/version.rb +1 -1
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5fd9ea4a9be8072ffc96e5bab91a845e99cc9a9d6641571167badd4146c93318
|
4
|
+
data.tar.gz: ed062be1d4b922ba39456f3868e599e3c6134fecfedaa3bfc780667bfec5c5f2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 59e5677db771776107744f2438505b467363b410d6b2c8d19b1b11e802bfd15b22974997b20185e9ba3a1c9a7b8721bb5e3dbc1481a575f0812300c9c3241cac
|
7
|
+
data.tar.gz: 6233ec5251cfbeeaabdb44a7cba75d4831910215ae8239ec19873f58a62f14722bb6b57059f0814ae07e7ccc50977e3a2fbf74bb3b423a253b7dace5773c6887
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
= 3.46.0 (2021-07-12)
|
2
|
+
|
3
|
+
* Automatically optimize r.on/r.is/r.get/r.post methods with a single string, String, Integer, or regexp argument (jeremyevans)
|
4
|
+
|
1
5
|
= 3.45.0 (2021-06-14)
|
2
6
|
|
3
7
|
* Make typecast_params plugin check for null bytes in strings by default, with :allow_null_bytes option for previous behavior (jeremyevans)
|
data/README.rdoc
CHANGED
@@ -0,0 +1,19 @@
|
|
1
|
+
= Improvements
|
2
|
+
|
3
|
+
* The r.on, r.is, r.get and r.post methods (and other verb methods
|
4
|
+
if using the all_verbs plugin) have now been optimized when using
|
5
|
+
a single string or regexp matcher, or the String or Integer class
|
6
|
+
matcher. Since those four matchers are the most common types of
|
7
|
+
matchers passed to the methods, this can significantly improve
|
8
|
+
routing performance (about 50% in the r10k benchmark).
|
9
|
+
|
10
|
+
This optimization is automatically applied when freezing
|
11
|
+
applications, if the related methods have not been modified by
|
12
|
+
plugins.
|
13
|
+
|
14
|
+
This optimization does come at the expense of a small decrease
|
15
|
+
in routing performance (3-4%) for unoptimized cases, but the
|
16
|
+
majority of applications will see a overall performance benefit
|
17
|
+
from this change.
|
18
|
+
|
19
|
+
* Other minor performance improvements have been made.
|
data/lib/roda.rb
CHANGED
@@ -212,6 +212,10 @@ class Roda
|
|
212
212
|
if @middleware.empty? && use_new_dispatch_api?
|
213
213
|
plugin :direct_call
|
214
214
|
end
|
215
|
+
|
216
|
+
if ([:on, :is, :_verb, :_match_class_String, :_match_class_Integer, :_match_string, :_match_regexp, :empty_path?]).all?{|m| self::RodaRequest.instance_method(m).owner == RequestMethods}
|
217
|
+
plugin :_optimized_matching
|
218
|
+
end
|
215
219
|
end
|
216
220
|
|
217
221
|
build_rack_app
|
@@ -0,0 +1,137 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
class Roda
|
5
|
+
module RodaPlugins
|
6
|
+
# The _optimized_matching plugin is automatically used internally to speed
|
7
|
+
# up matching when a single argument String instance, String class, Integer
|
8
|
+
# class, or Regexp matcher is passed to +r.on+, +r.is_+, or a verb method
|
9
|
+
# such as +r.get+ or +r.post+.
|
10
|
+
#
|
11
|
+
# The optimization works by avoiding the +if_match+ method if possible.
|
12
|
+
# Instead of clearing the captures array on every call, and having the
|
13
|
+
# matching append to the captures, it checks directly for the match,
|
14
|
+
# and on succesful match, it yields directly to the block without using
|
15
|
+
# the captures array.
|
16
|
+
module OptimizedMatching
|
17
|
+
TERM = Base::RequestMethods::TERM
|
18
|
+
|
19
|
+
module RequestMethods
|
20
|
+
# Optimize the r.is method handling of a single string, String, Integer,
|
21
|
+
# regexp, or true, argument.
|
22
|
+
def is(*args, &block)
|
23
|
+
case args.length
|
24
|
+
when 1
|
25
|
+
_is1(args, &block)
|
26
|
+
when 0
|
27
|
+
always(&block) if @remaining_path.empty?
|
28
|
+
else
|
29
|
+
if_match(args << TERM, &block)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Optimize the r.on method handling of a single string, String, Integer,
|
34
|
+
# or regexp argument. Inline the related matching code to avoid the
|
35
|
+
# need to modify @captures.
|
36
|
+
def on(*args, &block)
|
37
|
+
case args.length
|
38
|
+
when 1
|
39
|
+
case matcher = args[0]
|
40
|
+
when String
|
41
|
+
always{yield} if _match_string(matcher)
|
42
|
+
when Class
|
43
|
+
if matcher == String
|
44
|
+
rp = @remaining_path
|
45
|
+
if rp.getbyte(0) == 47
|
46
|
+
if last = rp.index('/', 1)
|
47
|
+
@remaining_path = rp[last, rp.length]
|
48
|
+
always{yield rp[1, last-1]}
|
49
|
+
elsif (len = rp.length) > 1
|
50
|
+
@remaining_path = ""
|
51
|
+
always{yield rp[1, len]}
|
52
|
+
end
|
53
|
+
end
|
54
|
+
elsif matcher == Integer
|
55
|
+
if matchdata = @remaining_path.match(/\A\/(\d+)(?=\/|\z)/)
|
56
|
+
@remaining_path = matchdata.post_match
|
57
|
+
always{yield(matchdata[1].to_i)}
|
58
|
+
end
|
59
|
+
else
|
60
|
+
if_match(args, &block)
|
61
|
+
end
|
62
|
+
when Regexp
|
63
|
+
if matchdata = @remaining_path.match(self.class.cached_matcher(matcher){matcher})
|
64
|
+
@remaining_path = matchdata.post_match
|
65
|
+
always{yield(*matchdata.captures)}
|
66
|
+
end
|
67
|
+
else
|
68
|
+
if_match(args, &block)
|
69
|
+
end
|
70
|
+
when 0
|
71
|
+
always(&block)
|
72
|
+
else
|
73
|
+
if_match(args, &block)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
# Optimize the r.get/r.post method handling of a single string, String, Integer,
|
80
|
+
# regexp, or true, argument.
|
81
|
+
def _verb(args, &block)
|
82
|
+
case args.length
|
83
|
+
when 0
|
84
|
+
always(&block)
|
85
|
+
when 1
|
86
|
+
_is1(args, &block)
|
87
|
+
else
|
88
|
+
if_match(args << TERM, &block)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# Internals of r.is/r.get/r.post optimization. Inline the related matching
|
93
|
+
# code to avoid the need to modify @captures.
|
94
|
+
def _is1(args, &block)
|
95
|
+
case matcher = args[0]
|
96
|
+
when String
|
97
|
+
rp = @remaining_path
|
98
|
+
if _match_string(matcher)
|
99
|
+
if @remaining_path.empty?
|
100
|
+
always{yield}
|
101
|
+
else
|
102
|
+
@remaining_path = rp
|
103
|
+
nil
|
104
|
+
end
|
105
|
+
end
|
106
|
+
when Class
|
107
|
+
if matcher == String
|
108
|
+
rp = @remaining_path
|
109
|
+
if rp.getbyte(0) == 47 && !rp.index('/', 1) && (len = rp.length) > 1
|
110
|
+
@remaining_path = ''
|
111
|
+
always{yield rp[1, len]}
|
112
|
+
end
|
113
|
+
elsif matcher == Integer
|
114
|
+
if matchdata = @remaining_path.match(/\A\/(\d+)\z/)
|
115
|
+
@remaining_path = ''
|
116
|
+
always{yield(matchdata[1].to_i)}
|
117
|
+
end
|
118
|
+
else
|
119
|
+
if_match(args << TERM, &block)
|
120
|
+
end
|
121
|
+
when Regexp
|
122
|
+
if (matchdata = @remaining_path.match(self.class.cached_matcher(matcher){matcher})) && (post_match = matchdata.post_match).empty?
|
123
|
+
@remaining_path = ''
|
124
|
+
always{yield(*matchdata.captures)}
|
125
|
+
end
|
126
|
+
when true
|
127
|
+
always(&block) if @remaining_path.empty?
|
128
|
+
else
|
129
|
+
if_match(args << TERM, &block)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
register_plugin(:_optimized_matching, OptimizedMatching)
|
136
|
+
end
|
137
|
+
end
|
@@ -62,8 +62,7 @@ class Roda
|
|
62
62
|
end
|
63
63
|
|
64
64
|
# Configure whether to append or overwrite if content_for
|
65
|
-
# is called multiple times
|
66
|
-
# the :append option to append.
|
65
|
+
# is called multiple times with the same key.
|
67
66
|
def self.configure(app, opts = OPTS)
|
68
67
|
app.opts[:append_content_for] = opts.fetch(:append, true)
|
69
68
|
end
|
data/lib/roda/request.rb
CHANGED
@@ -24,7 +24,7 @@ class Roda
|
|
24
24
|
|
25
25
|
# Return the cached pattern for the given object. If the object is
|
26
26
|
# not already cached, yield to get the basic pattern, and convert the
|
27
|
-
# basic pattern to a pattern that does not partial segments.
|
27
|
+
# basic pattern to a pattern that does not match partial segments.
|
28
28
|
def cached_matcher(obj)
|
29
29
|
cache = @match_pattern_cache
|
30
30
|
|
@@ -234,9 +234,7 @@ class Roda
|
|
234
234
|
|
235
235
|
# An alias of remaining_path. If a plugin changes remaining_path then
|
236
236
|
# it should override this method to return the untouched original.
|
237
|
-
|
238
|
-
remaining_path
|
239
|
-
end
|
237
|
+
alias real_remaining_path remaining_path
|
240
238
|
|
241
239
|
# Match POST requests. If no arguments are provided, matches all POST
|
242
240
|
# requests, otherwise, matches only POST requests where the arguments
|
@@ -336,7 +334,7 @@ class Roda
|
|
336
334
|
# Use <tt>r.get true</tt> to handle +GET+ requests where the current
|
337
335
|
# path is empty.
|
338
336
|
def root(&block)
|
339
|
-
if remaining_path == "/" && is_get?
|
337
|
+
if @remaining_path == "/" && is_get?
|
340
338
|
always(&block)
|
341
339
|
end
|
342
340
|
end
|
@@ -519,7 +517,7 @@ class Roda
|
|
519
517
|
# SCRIPT_NAME to include the matched path, removes the matched
|
520
518
|
# path from PATH_INFO, and updates captures with any regex captures.
|
521
519
|
def consume(pattern)
|
522
|
-
if matchdata = remaining_path.match(pattern)
|
520
|
+
if matchdata = @remaining_path.match(pattern)
|
523
521
|
@remaining_path = matchdata.post_match
|
524
522
|
captures = matchdata.captures
|
525
523
|
captures = yield(*captures) if block_given?
|
@@ -548,7 +546,7 @@ class Roda
|
|
548
546
|
|
549
547
|
# Whether the current path is considered empty.
|
550
548
|
def empty_path?
|
551
|
-
remaining_path.empty?
|
549
|
+
@remaining_path.empty?
|
552
550
|
end
|
553
551
|
|
554
552
|
# If all of the arguments match, yields to the match block and
|
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.46.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: 2021-
|
11
|
+
date: 2021-07-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -216,6 +216,7 @@ extra_rdoc_files:
|
|
216
216
|
- doc/release_notes/3.43.0.txt
|
217
217
|
- doc/release_notes/3.44.0.txt
|
218
218
|
- doc/release_notes/3.45.0.txt
|
219
|
+
- doc/release_notes/3.46.0.txt
|
219
220
|
- doc/release_notes/3.5.0.txt
|
220
221
|
- doc/release_notes/3.6.0.txt
|
221
222
|
- doc/release_notes/3.7.0.txt
|
@@ -268,6 +269,7 @@ files:
|
|
268
269
|
- doc/release_notes/3.43.0.txt
|
269
270
|
- doc/release_notes/3.44.0.txt
|
270
271
|
- doc/release_notes/3.45.0.txt
|
272
|
+
- doc/release_notes/3.46.0.txt
|
271
273
|
- doc/release_notes/3.5.0.txt
|
272
274
|
- doc/release_notes/3.6.0.txt
|
273
275
|
- doc/release_notes/3.7.0.txt
|
@@ -278,6 +280,7 @@ files:
|
|
278
280
|
- lib/roda/plugins.rb
|
279
281
|
- lib/roda/plugins/_after_hook.rb
|
280
282
|
- lib/roda/plugins/_before_hook.rb
|
283
|
+
- lib/roda/plugins/_optimized_matching.rb
|
281
284
|
- lib/roda/plugins/_symbol_regexp_matchers.rb
|
282
285
|
- lib/roda/plugins/all_verbs.rb
|
283
286
|
- lib/roda/plugins/assets.rb
|
@@ -409,7 +412,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
409
412
|
- !ruby/object:Gem::Version
|
410
413
|
version: '0'
|
411
414
|
requirements: []
|
412
|
-
rubygems_version: 3.2.
|
415
|
+
rubygems_version: 3.2.22
|
413
416
|
signing_key:
|
414
417
|
specification_version: 4
|
415
418
|
summary: Routing tree web toolkit
|