rack-mount 0.6.1 → 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
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