roda 3.45.0 → 3.46.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/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
|