roda-cj 0.9.1 → 0.9.2

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
  SHA1:
3
- metadata.gz: 00b2172bd61961f3176d6c3b058c2f01b67366c3
4
- data.tar.gz: 0892c32cefa17382cea92d15ac5520f5a0342939
3
+ metadata.gz: 2f2740123aa0c6fafe4c1665f9c83e408cef9105
4
+ data.tar.gz: 74ec8c03a23405c2ac18eb23ceea5ccb3f4813c1
5
5
  SHA512:
6
- metadata.gz: ac35c86664a528718846cfde26d78cdd33c41238b53b06cf73775fd7e86afd257a1ca36b7b6c57efa0460f53f95e0d2da49d5a0a7e5b457a5e696b6c15313ca5
7
- data.tar.gz: 1546b8958db7fb24ec76483259686d90b65908a29a321795a7717c16dccc371f172bd9c8ac9b5dc8ad88fb97758fedc0d14e95d99bc451d2679b2b3b553b95af
6
+ metadata.gz: 876514335f729d2beeea7b218bc14d7cac1772f5b568a4a985457b01321c16ef33116bb3dd605e218d3512185d34dffaca426b9e803d0e860c56619eb2838359
7
+ data.tar.gz: d046733fe6737ccabc612523c7812b1be778cea3675223a1a5bc3c202a91fad2da26e2fac842789542368fcb95e0b8d201cff9235de3410c3e1e5e414314f1f0
data/CHANGELOG CHANGED
@@ -1,5 +1,7 @@
1
1
  = HEAD
2
2
 
3
+ * Optimize matching by caching consume regexp for strings, regexp, symbol, and :extension matchers (jeremyevans)
4
+
3
5
  * Add r.root for matching root (path "/"), for easier to read version of r.is "" (jeremyevans)
4
6
 
5
7
  * Optimize r.is terminal matcher, remove :term hash matcher (jeremyevans)
@@ -22,19 +22,19 @@ class Roda
22
22
  # Or set the response body and return:
23
23
  #
24
24
  # route do |r|
25
- # r.halt("body')
25
+ # r.halt('body')
26
26
  # end
27
27
  #
28
28
  # Or set both:
29
29
  #
30
30
  # route do |r|
31
- # r.halt(403, "body')
31
+ # r.halt(403, 'body')
32
32
  # end
33
33
  #
34
34
  # Or set response status, headers, and body:
35
35
  #
36
36
  # route do |r|
37
- # r.halt(403, {'Content-Type'=>'text/csv'}, "body')
37
+ # r.halt(403, {'Content-Type'=>'text/csv'}, 'body')
38
38
  # end
39
39
  #
40
40
  # Note that there is a difference between provide status, headers, and body as separate
data/lib/roda/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  class Roda
2
- RodaVersion = '0.9.1'.freeze
2
+ RodaVersion = '0.9.2'.freeze
3
3
  end
data/lib/roda.rb CHANGED
@@ -14,6 +14,43 @@ class Roda
14
14
  # only contains the class methods.
15
15
  class RodaRequest < ::Rack::Request;
16
16
  @roda_class = ::Roda
17
+ @match_pattern_cache = {}
18
+
19
+ if defined?(RUBY_ENGINE) && RUBY_ENGINE != 'ruby'
20
+ # :nocov:
21
+ @match_pattern_mutex = Mutex.new
22
+
23
+ def self.cached_matcher(obj)
24
+ unless pattern = @match_pattern_mutex.synchronize{@match_pattern_cache[obj]}
25
+ pattern = consume_pattern(yield)
26
+ @match_pattern_mutex.synchronize{@match_pattern_cache[obj] = pattern}
27
+ end
28
+ pattern
29
+ end
30
+
31
+ def self.inherited(subclass)
32
+ super
33
+ subclass.instance_variable_set(:@match_pattern_cache, {})
34
+ subclass.instance_variable_set(:@match_pattern_mutex, Mutex.new)
35
+ end
36
+ # :nocov:
37
+ else
38
+ # Return the cached pattern for the given object. If the object is
39
+ # not already cached, yield to get the basic pattern, and convert the
40
+ # basic pattern to a pattern that does not partial segments.
41
+ def self.cached_matcher(obj)
42
+ unless pattern = @match_pattern_cache[obj]
43
+ pattern = @match_pattern_cache[obj] = consume_pattern(yield)
44
+ end
45
+ pattern
46
+ end
47
+
48
+ # Initialize the match_pattern cache in the subclass.
49
+ def self.inherited(subclass)
50
+ super
51
+ subclass.instance_variable_set(:@match_pattern_cache, {})
52
+ end
53
+ end
17
54
 
18
55
  class << self
19
56
  # Reference to the Roda class related to this request class.
@@ -25,6 +62,15 @@ class Roda
25
62
  def inspect
26
63
  "#{roda_class.inspect}::RodaRequest"
27
64
  end
65
+
66
+ private
67
+
68
+ # The pattern to use for consuming, based on the given argument. The returned
69
+ # pattern requires the path starts with a string and does not match partial
70
+ # segments.
71
+ def consume_pattern(pattern)
72
+ /\A(\/(?:#{pattern}))(\/|\z)/
73
+ end
28
74
  end
29
75
  end
30
76
 
@@ -390,12 +436,49 @@ class Roda
390
436
  throw :halt, response
391
437
  end
392
438
 
439
+ # Match any of the elements in the given array. Return at the
440
+ # first match without evaluating future matches. Returns false
441
+ # if no elements in the array match.
442
+ def _match_array(matcher)
443
+ matcher.any? do |m|
444
+ if matched = match(m)
445
+ if m.is_a?(String)
446
+ captures.push(m)
447
+ end
448
+ end
449
+
450
+ matched
451
+ end
452
+ end
453
+
454
+ # Match the given regexp exactly if it matches a full segment.
455
+ def _match_regexp(re)
456
+ consume(self.class.cached_matcher(re){re})
457
+ end
458
+
459
+ # Match the given hash if all hash matchers match.
460
+ def _match_hash(hash)
461
+ hash.all?{|k,v| send("match_#{k}", v)}
462
+ end
463
+
464
+ # Match the given string to the request path. Regexp escapes the
465
+ # string so that regexp metacharacters are not matched, and recognizes
466
+ # colon tokens for placeholders.
467
+ def _match_string(str)
468
+ consume(self.class.cached_matcher(str){Regexp.escape(str).gsub(/:\w+/, SEGMENT)})
469
+ end
470
+
471
+ # Match the given symbol if any segment matches.
472
+ def _match_symbol(sym)
473
+ consume(self.class.cached_matcher(sym){SEGMENT})
474
+ end
475
+
393
476
  # Attempts to match the pattern to the current path. If there is no
394
477
  # match, returns false without changes. Otherwise, modifies
395
478
  # SCRIPT_NAME to include the matched path, removes the matched
396
479
  # path from PATH_INFO, and updates captures with any regex captures.
397
480
  def consume(pattern)
398
- matchdata = env[PATH_INFO].match(/\A(\/(?:#{pattern}))(\/|\z)/)
481
+ matchdata = env[PATH_INFO].match(pattern)
399
482
 
400
483
  return false unless matchdata
401
484
 
@@ -423,17 +506,17 @@ class Roda
423
506
  def match(matcher)
424
507
  case matcher
425
508
  when String
426
- match_string(matcher)
509
+ _match_string(matcher)
427
510
  when Regexp
428
- consume(matcher)
511
+ _match_regexp(matcher)
429
512
  when Symbol
430
- consume(SEGMENT)
513
+ _match_symbol(matcher)
431
514
  when TERM
432
515
  env[PATH_INFO] == EMPTY_STRING
433
516
  when Hash
434
- matcher.all?{|k,v| send("match_#{k}", v)}
517
+ _match_hash(matcher)
435
518
  when Array
436
- match_array(matcher)
519
+ _match_array(matcher)
437
520
  when Proc
438
521
  matcher.call
439
522
  else
@@ -441,25 +524,10 @@ class Roda
441
524
  end
442
525
  end
443
526
 
444
- # Match any of the elements in the given array. Return at the
445
- # first match without evaluating future matches. Returns false
446
- # if no elements in the array match.
447
- def match_array(matcher)
448
- matcher.any? do |m|
449
- if matched = match(m)
450
- if m.is_a?(String)
451
- captures.push(m)
452
- end
453
- end
454
-
455
- matched
456
- end
457
- end
458
-
459
527
  # Match files with the given extension. Requires that the
460
528
  # request path end with the extension.
461
529
  def match_extension(ext)
462
- consume("([^\\/]+?)\.#{ext}\\z")
530
+ consume(self.class.cached_matcher(ext){"([^\\/]+?)\.#{ext}\\z"})
463
531
  end
464
532
 
465
533
  # Match by request method. This can be an array if you want
@@ -488,15 +556,6 @@ class Roda
488
556
  end
489
557
  end
490
558
 
491
- # Match the given string to the request path. Regexp escapes the
492
- # string so that regexp metacharacters are not matched, and recognizes
493
- # colon tokens for placeholders.
494
- def match_string(str)
495
- str = Regexp.escape(str)
496
- str.gsub!(/:\w+/, SEGMENT)
497
- consume(str)
498
- end
499
-
500
559
  # Yield to the given block, clearing any captures before
501
560
  # yielding and restoring the SCRIPT_NAME and PATH_INFO on exit.
502
561
  def try
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: roda-cj
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.1
4
+ version: 0.9.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Evans
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-08-10 00:00:00.000000000 Z
11
+ date: 2014-08-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack