rack-mount 0.6.1 → 0.6.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.
Files changed (30) hide show
  1. data/lib/rack/mount.rb +3 -13
  2. data/lib/rack/mount/analysis/frequency.rb +0 -2
  3. data/lib/rack/mount/analysis/splitting.rb +2 -2
  4. data/lib/rack/mount/code_generation.rb +113 -0
  5. data/lib/rack/mount/generatable_regexp.rb +1 -1
  6. data/lib/rack/mount/route.rb +69 -5
  7. data/lib/rack/mount/route_set.rb +289 -46
  8. data/lib/rack/mount/strexp.rb +53 -50
  9. data/lib/rack/mount/utils.rb +7 -7
  10. data/lib/rack/mount/vendor/reginald/reginald.rb +2 -1
  11. data/lib/rack/mount/vendor/reginald/reginald/alternation.rb +11 -1
  12. data/lib/rack/mount/vendor/reginald/reginald/atom.rb +17 -5
  13. data/lib/rack/mount/vendor/reginald/reginald/character.rb +11 -2
  14. data/lib/rack/mount/vendor/reginald/reginald/character_class.rb +8 -20
  15. data/lib/rack/mount/vendor/reginald/reginald/collection.rb +10 -6
  16. data/lib/rack/mount/vendor/reginald/reginald/expression.rb +30 -20
  17. data/lib/rack/mount/vendor/reginald/reginald/group.rb +22 -8
  18. data/lib/rack/mount/vendor/reginald/reginald/options.rb +47 -0
  19. data/lib/rack/mount/vendor/reginald/reginald/parser.rb +137 -273
  20. data/lib/rack/mount/vendor/reginald/reginald/tokenizer.rb +1 -1
  21. data/lib/rack/mount/vendor/reginald/reginald/version.rb +3 -0
  22. data/lib/rack/mount/version.rb +1 -1
  23. metadata +6 -10
  24. data/lib/rack/mount/exceptions.rb +0 -3
  25. data/lib/rack/mount/generation/route.rb +0 -59
  26. data/lib/rack/mount/generation/route_set.rb +0 -200
  27. data/lib/rack/mount/mixover.rb +0 -60
  28. data/lib/rack/mount/recognition/code_generation.rb +0 -124
  29. data/lib/rack/mount/recognition/route.rb +0 -62
  30. data/lib/rack/mount/recognition/route_set.rb +0 -121
@@ -1,65 +1,68 @@
1
1
  require 'rack/mount/strexp/parser'
2
2
 
3
3
  module Rack::Mount
4
- class Strexp < Regexp
5
- # Parses segmented string expression and converts it into a Regexp
6
- #
7
- # Strexp.compile('foo')
8
- # # => %r{\Afoo\Z}
9
- #
10
- # Strexp.compile('foo/:bar', {}, ['/'])
11
- # # => %r{\Afoo/(?<bar>[^/]+)\Z}
12
- #
13
- # Strexp.compile(':foo.example.com')
14
- # # => %r{\A(?<foo>.+)\.example\.com\Z}
15
- #
16
- # Strexp.compile('foo/:bar', {:bar => /[a-z]+/}, ['/'])
17
- # # => %r{\Afoo/(?<bar>[a-z]+)\Z}
18
- #
19
- # Strexp.compile('foo(.:extension)')
20
- # # => %r{\Afoo(\.(?<extension>.+))?\Z}
21
- #
22
- # Strexp.compile('src/*files')
23
- # # => %r{\Asrc/(?<files>.+)\Z}
24
- def initialize(str, requirements = {}, separators = [], anchor = true)
25
- return super(str) if str.is_a?(Regexp)
4
+ class Strexp
5
+ class << self
6
+ # Parses segmented string expression and converts it into a Regexp
7
+ #
8
+ # Strexp.compile('foo')
9
+ # # => %r{\Afoo\Z}
10
+ #
11
+ # Strexp.compile('foo/:bar', {}, ['/'])
12
+ # # => %r{\Afoo/(?<bar>[^/]+)\Z}
13
+ #
14
+ # Strexp.compile(':foo.example.com')
15
+ # # => %r{\A(?<foo>.+)\.example\.com\Z}
16
+ #
17
+ # Strexp.compile('foo/:bar', {:bar => /[a-z]+/}, ['/'])
18
+ # # => %r{\Afoo/(?<bar>[a-z]+)\Z}
19
+ #
20
+ # Strexp.compile('foo(.:extension)')
21
+ # # => %r{\Afoo(\.(?<extension>.+))?\Z}
22
+ #
23
+ # Strexp.compile('src/*files')
24
+ # # => %r{\Asrc/(?<files>.+)\Z}
25
+ def compile(str, requirements = {}, separators = [], anchor = true)
26
+ return Regexp.compile(str) if str.is_a?(Regexp)
26
27
 
27
- requirements = requirements ? requirements.dup : {}
28
- normalize_requirements!(requirements, separators)
28
+ requirements = requirements ? requirements.dup : {}
29
+ normalize_requirements!(requirements, separators)
29
30
 
30
- parser = StrexpParser.new
31
- parser.anchor = anchor
32
- parser.requirements = requirements
31
+ parser = StrexpParser.new
32
+ parser.anchor = anchor
33
+ parser.requirements = requirements
33
34
 
34
- begin
35
- re = parser.scan_str(str)
36
- rescue Racc::ParseError => e
37
- raise RegexpError, e.message
38
- end
35
+ begin
36
+ re = parser.scan_str(str)
37
+ rescue Racc::ParseError => e
38
+ raise RegexpError, e.message
39
+ end
39
40
 
40
- super(re)
41
- end
41
+ Regexp.compile(re)
42
+ end
43
+ alias_method :new, :compile
42
44
 
43
- private
44
- def normalize_requirements!(requirements, separators)
45
- requirements.each do |key, value|
46
- if value.is_a?(Regexp)
47
- if regexp_has_modifiers?(value)
48
- requirements[key] = value
45
+ private
46
+ def normalize_requirements!(requirements, separators)
47
+ requirements.each do |key, value|
48
+ if value.is_a?(Regexp)
49
+ if regexp_has_modifiers?(value)
50
+ requirements[key] = value
51
+ else
52
+ requirements[key] = value.source
53
+ end
49
54
  else
50
- requirements[key] = value.source
55
+ requirements[key] = Regexp.escape(value)
51
56
  end
52
- else
53
- requirements[key] = Regexp.escape(value)
54
57
  end
58
+ requirements.default ||= separators.any? ?
59
+ "[^#{separators.join}]+" : '.+'
60
+ requirements
55
61
  end
56
- requirements.default ||= separators.any? ?
57
- "[^#{separators.join}]+" : '.+'
58
- requirements
59
- end
60
62
 
61
- def regexp_has_modifiers?(regexp)
62
- regexp.options & (Regexp::IGNORECASE | Regexp::EXTENDED) != 0
63
- end
63
+ def regexp_has_modifiers?(regexp)
64
+ regexp.options & (Regexp::IGNORECASE | Regexp::EXTENDED) != 0
65
+ end
66
+ end
64
67
  end
65
68
  end
@@ -124,13 +124,13 @@ module Rack::Mount
124
124
 
125
125
  unless Reginald.regexp_supports_named_captures?
126
126
  tag_captures = Proc.new do |group|
127
- group.each do |child|
128
- if child.is_a?(Reginald::Group)
129
- child.name = regexp.names[child.index] if child.index
130
- tag_captures.call(child)
131
- elsif child.is_a?(Reginald::Expression)
132
- tag_captures.call(child)
133
- end
127
+ case group
128
+ when Reginald::Group
129
+ # TODO: dup instead of mutating
130
+ group.instance_variable_set('@name', regexp.names[group.index]) if group.index
131
+ tag_captures.call(group.expression)
132
+ when Reginald::Expression
133
+ group.each { |child| tag_captures.call(child) }
134
134
  end
135
135
  end
136
136
  tag_captures.call(expression)
@@ -7,6 +7,7 @@ module Reginald
7
7
  autoload :Collection, 'reginald/collection'
8
8
  autoload :Expression, 'reginald/expression'
9
9
  autoload :Group, 'reginald/group'
10
+ autoload :Options, 'reginald/options'
10
11
  autoload :Parser, 'reginald/parser'
11
12
 
12
13
  class << self
@@ -38,7 +39,7 @@ module Reginald
38
39
  def compile(source)
39
40
  regexp = Regexp.compile(source)
40
41
  expression = parse(regexp)
41
- Regexp.compile(expression.to_s(true), expression.options)
42
+ Regexp.compile(expression.to_s(true), expression.flags)
42
43
  end
43
44
  end
44
45
  end
@@ -11,11 +11,17 @@ module Reginald
11
11
  end
12
12
 
13
13
  def initialize(*args)
14
+ args, options = extract_options(args)
15
+
14
16
  if args.length == 1 && args.first.instance_of?(Array)
15
17
  super(args.first)
16
18
  else
17
19
  super(args)
18
20
  end
21
+
22
+ if options.key?(:ignorecase)
23
+ map! { |e| e.dup(:ignorecase => options[:ignorecase]) }
24
+ end
19
25
  end
20
26
 
21
27
  # Returns true if expression could be treated as a literal string.
@@ -25,10 +31,14 @@ module Reginald
25
31
  false
26
32
  end
27
33
 
28
- def options
34
+ def flags
29
35
  0
30
36
  end
31
37
 
38
+ def dup(options = {})
39
+ self.class.new(to_a, options)
40
+ end
41
+
32
42
  def to_s(parent = false)
33
43
  map { |e| e.to_s(parent) }.join('|')
34
44
  end
@@ -1,10 +1,14 @@
1
1
  module Reginald
2
- class Atom < Struct.new(:value)
3
- attr_accessor :ignorecase
2
+ class Atom
3
+ attr_reader :value, :ignorecase
4
4
 
5
- def initialize(*args)
6
- @ignorecase = nil
7
- super
5
+ def initialize(value, options = {})
6
+ @value = value
7
+ @ignorecase = options[:ignorecase]
8
+ end
9
+
10
+ def option_names
11
+ %w( ignorecase )
8
12
  end
9
13
 
10
14
  # Returns true if expression could be treated as a literal string.
@@ -16,6 +20,14 @@ module Reginald
16
20
  ignorecase ? true : false
17
21
  end
18
22
 
23
+ def dup(options = {})
24
+ original_options = option_names.inject({}) do |h, m|
25
+ h[m.to_sym] = send(m)
26
+ h
27
+ end
28
+ self.class.new(value, original_options.merge(options))
29
+ end
30
+
19
31
  def to_s(parent = false)
20
32
  "#{value}"
21
33
  end
@@ -1,6 +1,15 @@
1
1
  module Reginald
2
2
  class Character < Atom
3
- attr_accessor :quantifier
3
+ attr_reader :quantifier
4
+
5
+ def initialize(value, options = {})
6
+ @quantifier = options[:quantifier]
7
+ super
8
+ end
9
+
10
+ def option_names
11
+ %w( quantifier ) + super
12
+ end
4
13
 
5
14
  # Returns true if expression could be treated as a literal string.
6
15
  #
@@ -38,7 +47,7 @@ module Reginald
38
47
  end
39
48
 
40
49
  def freeze #:nodoc:
41
- quantifier.freeze
50
+ quantifier.freeze if quantifier
42
51
  super
43
52
  end
44
53
  end
@@ -1,27 +1,15 @@
1
1
  module Reginald
2
2
  class CharacterClass < Character
3
- ALNUM = new(':alnum:').freeze
4
- ALPHA = new(':alpha:').freeze
5
- ASCII = new(':ascii:').freeze
6
- BLANK = new(':blank:').freeze
7
- CNTRL = new(':cntrl:').freeze
8
- DIGIT = new(':digit:').freeze
9
- GRAPH = new(':graph:').freeze
10
- LOWER = new(':lower:').freeze
11
- PRINT = new(':print:').freeze
12
- PUNCT = new(':punct:').freeze
13
- SPACE = new(':space:').freeze
14
- UPPER = new(':upper:').freeze
15
- WORD = new(':word:').freeze
16
- XDIGIT = new(':xdigit:').freeze
3
+ def initialize(value, options = {})
4
+ @negate = options[:negate]
5
+ super
6
+ end
17
7
 
18
- def ignorecase=(ignorecase)
19
- if to_s !~ /\A\[:.*:\]\Z/
20
- super
21
- end
8
+ def option_names
9
+ %w( negate ) + super
22
10
  end
23
11
 
24
- attr_accessor :negate
12
+ attr_reader :negate
25
13
 
26
14
  def negated?
27
15
  negate ? true : false
@@ -60,7 +48,7 @@ module Reginald
60
48
  end
61
49
 
62
50
  def freeze #:nodoc:
63
- negate.freeze
51
+ negate.freeze if negate
64
52
  super
65
53
  end
66
54
  end
@@ -1,12 +1,7 @@
1
1
  module Reginald
2
2
  class Collection < Array
3
- def ignorecase=(ignorecase)
4
- each { |e| e.ignorecase = ignorecase }
5
- ignorecase
6
- end
7
-
8
3
  def to_regexp
9
- Regexp.compile("\\A#{to_s(true)}\\Z", options)
4
+ Regexp.compile("\\A#{to_s(true)}\\Z", flags)
10
5
  end
11
6
 
12
7
  def match(char)
@@ -36,5 +31,14 @@ module Reginald
36
31
  each { |e| e.freeze }
37
32
  super
38
33
  end
34
+
35
+ protected
36
+ def extract_options(args)
37
+ if args.last.is_a?(Hash)
38
+ return args[0..-2], args.last
39
+ else
40
+ return args, {}
41
+ end
42
+ end
39
43
  end
40
44
  end
@@ -15,6 +15,8 @@ module Reginald
15
15
  end
16
16
 
17
17
  def initialize(*args)
18
+ args, options = extract_options(args)
19
+
18
20
  @multiline = @ignorecase = @extended = nil
19
21
 
20
22
  if args.length == 1 && args.first.instance_of?(Array)
@@ -23,15 +25,10 @@ module Reginald
23
25
  args = args.map { |e| e.instance_of?(String) ? Character.new(e) : e }
24
26
  super(args)
25
27
  end
26
- end
27
28
 
28
- def ignorecase=(ignorecase)
29
- if @ignorecase.nil?
30
- super
31
- @ignorecase = ignorecase
32
- else
33
- false
34
- end
29
+ self.multiline = options[:multiline] if options.key?(:multiline)
30
+ self.ignorecase = options[:ignorecase] if options.key?(:ignorecase)
31
+ self.extended = options[:extended] if options.key?(:extended)
35
32
  end
36
33
 
37
34
  # Returns true if expression could be treated as a literal string.
@@ -65,23 +62,24 @@ module Reginald
65
62
  anchored_to_end? || (last.is_a?(Anchor) && last == '$')
66
63
  end
67
64
 
68
- def options
69
- flag = 0
70
- flag |= Regexp::MULTILINE if multiline
71
- flag |= Regexp::IGNORECASE if ignorecase
72
- flag |= Regexp::EXTENDED if extended
73
- flag
65
+ def options?
66
+ options.any?(true)
67
+ end
68
+
69
+ def flags
70
+ options.to_i
74
71
  end
75
72
 
76
- def options=(flag)
77
- self.multiline = flag & Regexp::MULTILINE != 0
78
- self.ignorecase = flag & Regexp::IGNORECASE != 0
79
- self.extended = flag & Regexp::EXTENDED != 0
80
- nil
73
+ def dup(options = {})
74
+ expression = super()
75
+ expression.multiline = options[:multiline] if options.key?(:multiline)
76
+ expression.ignorecase = options[:ignorecase] if options.key?(:ignorecase)
77
+ expression.extended = options[:extended] if options.key?(:extended)
78
+ expression
81
79
  end
82
80
 
83
81
  def to_s(parent = false)
84
- if parent || options == 0
82
+ if parent || !options?
85
83
  map { |e| e.to_s(parent) }.join
86
84
  else
87
85
  with, without = [], []
@@ -110,5 +108,17 @@ module Reginald
110
108
  !!self.ignorecase == !!other.ignorecase &&
111
109
  !!self.extended == !!other.extended
112
110
  end
111
+
112
+ protected
113
+ def options
114
+ Options.new(multiline, ignorecase, extended)
115
+ end
116
+
117
+ def ignorecase=(ignorecase)
118
+ if @ignorecase.nil?
119
+ map! { |e| e.dup(:ignorecase => ignorecase) }
120
+ @ignorecase = ignorecase
121
+ end
122
+ end
113
123
  end
114
124
  end
@@ -1,14 +1,20 @@
1
1
  module Reginald
2
- class Group < Struct.new(:expression)
3
- attr_accessor :quantifier, :capture, :index, :name
2
+ class Group
3
+ attr_reader :expression, :quantifier, :capture, :index, :name
4
4
 
5
- def initialize(*args)
5
+ def initialize(expression, options = {})
6
+ @quantifier = @index = @name = nil
6
7
  @capture = true
7
- super
8
+ @expression = expression.dup(options)
9
+
10
+ @quantifier = options[:quantifier] if options.key?(:quantifier)
11
+ @capture = options[:capture] if options.key?(:capture)
12
+ @index = options[:index] if options.key?(:index)
13
+ @name = options[:name] if options.key?(:name)
8
14
  end
9
15
 
10
- def ignorecase=(ignorecase)
11
- expression.ignorecase = ignorecase
16
+ def option_names
17
+ %w( quantifier capture index name )
12
18
  end
13
19
 
14
20
  # Returns true if expression could be treated as a literal string.
@@ -19,7 +25,7 @@ module Reginald
19
25
  end
20
26
 
21
27
  def to_s(parent = false)
22
- if expression.options == 0
28
+ if !expression.options?
23
29
  "(#{capture ? '' : '?:'}#{expression.to_s(parent)})#{quantifier}"
24
30
  elsif capture == false
25
31
  "#{expression.to_s}#{quantifier}"
@@ -32,6 +38,14 @@ module Reginald
32
38
  Regexp.compile("\\A#{to_s}\\Z")
33
39
  end
34
40
 
41
+ def dup(options = {})
42
+ original_options = option_names.inject({}) do |h, m|
43
+ h[m.to_sym] = send(m)
44
+ h
45
+ end
46
+ self.class.new(expression, original_options.merge(options))
47
+ end
48
+
35
49
  def inspect #:nodoc:
36
50
  to_s.inspect
37
51
  end
@@ -67,7 +81,7 @@ module Reginald
67
81
  end
68
82
 
69
83
  def freeze #:nodoc:
70
- expression.freeze
84
+ expression.freeze if expression
71
85
  super
72
86
  end
73
87
  end