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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5dbdf55425a681a0cb32fa0b4a44cd50bf5be6f85c78c1ea1adbdd19e28c2d61
4
- data.tar.gz: e91ee695e5f8648f4269a2c229b794ef2ee921f4291102519d4ca2cadd9bf13a
3
+ metadata.gz: 5fd9ea4a9be8072ffc96e5bab91a845e99cc9a9d6641571167badd4146c93318
4
+ data.tar.gz: ed062be1d4b922ba39456f3868e599e3c6134fecfedaa3bfc780667bfec5c5f2
5
5
  SHA512:
6
- metadata.gz: aa46429e09091c3cf0112c251a9863845c69d4245674dcaddaec030244213d8b9ac1aae96cfa6093680c33f87c732ee4464e4cbe2572d192eb0a9f7e09acd43b
7
- data.tar.gz: 57cf84f7db6e6334918f0c01f7308c4c48db7e0ba9f2a14fe87420c3b2bd17471a229ec02a2ad9242ec6fd4aa67848f6dff04b319fea361a985dd264b52252ab
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
@@ -13,7 +13,6 @@ Website :: http://roda.jeremyevans.net
13
13
  Source :: http://github.com/jeremyevans/roda
14
14
  Bugs :: http://github.com/jeremyevans/roda/issues
15
15
  Google Group :: http://groups.google.com/group/ruby-roda
16
- IRC :: irc://chat.freenode.net/#roda
17
16
 
18
17
  == Goals
19
18
 
@@ -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 to set data. Overwrite is default, use
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
- def real_remaining_path
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
@@ -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 = 45
7
+ RodaMinorVersion = 46
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.45.0
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-06-14 00:00:00.000000000 Z
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.15
415
+ rubygems_version: 3.2.22
413
416
  signing_key:
414
417
  specification_version: 4
415
418
  summary: Routing tree web toolkit