lgierth-rack-mount 0.6.13

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 (37) hide show
  1. data/LICENSE +20 -0
  2. data/README.rdoc +36 -0
  3. data/lib/rack/mount.rb +32 -0
  4. data/lib/rack/mount/analysis/frequency.rb +60 -0
  5. data/lib/rack/mount/analysis/histogram.rb +74 -0
  6. data/lib/rack/mount/analysis/splitting.rb +159 -0
  7. data/lib/rack/mount/code_generation.rb +117 -0
  8. data/lib/rack/mount/generatable_regexp.rb +210 -0
  9. data/lib/rack/mount/multimap.rb +53 -0
  10. data/lib/rack/mount/prefix.rb +36 -0
  11. data/lib/rack/mount/regexp_with_named_groups.rb +69 -0
  12. data/lib/rack/mount/route.rb +130 -0
  13. data/lib/rack/mount/route_set.rb +420 -0
  14. data/lib/rack/mount/strexp.rb +68 -0
  15. data/lib/rack/mount/strexp/parser.rb +160 -0
  16. data/lib/rack/mount/strexp/parser.y +34 -0
  17. data/lib/rack/mount/strexp/tokenizer.rb +83 -0
  18. data/lib/rack/mount/strexp/tokenizer.rex +12 -0
  19. data/lib/rack/mount/utils.rb +162 -0
  20. data/lib/rack/mount/vendor/multimap/multimap.rb +569 -0
  21. data/lib/rack/mount/vendor/multimap/multiset.rb +185 -0
  22. data/lib/rack/mount/vendor/multimap/nested_multimap.rb +158 -0
  23. data/lib/rack/mount/vendor/regin/regin.rb +75 -0
  24. data/lib/rack/mount/vendor/regin/regin/alternation.rb +40 -0
  25. data/lib/rack/mount/vendor/regin/regin/anchor.rb +4 -0
  26. data/lib/rack/mount/vendor/regin/regin/atom.rb +54 -0
  27. data/lib/rack/mount/vendor/regin/regin/character.rb +51 -0
  28. data/lib/rack/mount/vendor/regin/regin/character_class.rb +50 -0
  29. data/lib/rack/mount/vendor/regin/regin/collection.rb +77 -0
  30. data/lib/rack/mount/vendor/regin/regin/expression.rb +126 -0
  31. data/lib/rack/mount/vendor/regin/regin/group.rb +85 -0
  32. data/lib/rack/mount/vendor/regin/regin/options.rb +55 -0
  33. data/lib/rack/mount/vendor/regin/regin/parser.rb +520 -0
  34. data/lib/rack/mount/vendor/regin/regin/tokenizer.rb +246 -0
  35. data/lib/rack/mount/vendor/regin/regin/version.rb +3 -0
  36. data/lib/rack/mount/version.rb +3 -0
  37. metadata +140 -0
@@ -0,0 +1,4 @@
1
+ module Regin
2
+ class Anchor < Atom
3
+ end
4
+ end
@@ -0,0 +1,54 @@
1
+ module Regin
2
+ class Atom
3
+ attr_reader :value, :ignorecase
4
+
5
+ def initialize(value, options = {})
6
+ @value = value
7
+ @ignorecase = options[:ignorecase]
8
+ end
9
+
10
+ def option_names
11
+ %w( ignorecase )
12
+ end
13
+
14
+ # Returns true if expression could be treated as a literal string.
15
+ def literal?
16
+ false
17
+ end
18
+
19
+ def casefold?
20
+ ignorecase ? true : false
21
+ end
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
+
31
+ def to_s(parent = false)
32
+ "#{value}"
33
+ end
34
+
35
+ def inspect #:nodoc:
36
+ "#<#{self.class.to_s.sub('Regin::', '')} #{to_s.inspect}>"
37
+ end
38
+
39
+ def ==(other) #:nodoc:
40
+ case other
41
+ when String
42
+ other == to_s
43
+ else
44
+ eql?(other)
45
+ end
46
+ end
47
+
48
+ def eql?(other) #:nodoc:
49
+ other.instance_of?(self.class) &&
50
+ self.value.eql?(other.value) &&
51
+ (!!self.ignorecase).eql?(!!other.ignorecase)
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,51 @@
1
+ module Regin
2
+ class Character < Atom
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
13
+
14
+ # Returns true if expression could be treated as a literal string.
15
+ #
16
+ # A Character is literal is there is no quantifier attached to it.
17
+ def literal?
18
+ quantifier.nil? && !ignorecase
19
+ end
20
+
21
+ def to_s(parent = false)
22
+ if !parent && ignorecase
23
+ "(?i-mx:#{value})#{quantifier}"
24
+ else
25
+ "#{value}#{quantifier}"
26
+ end
27
+ end
28
+
29
+ def to_regexp(anchored = false)
30
+ re = to_s(true)
31
+ re = "\\A#{re}\\Z" if anchored
32
+ Regexp.compile(re, ignorecase)
33
+ end
34
+
35
+ def match(char)
36
+ to_regexp(true).match(char)
37
+ end
38
+
39
+ def include?(char)
40
+ if ignorecase
41
+ value.downcase == char.downcase
42
+ else
43
+ value == char
44
+ end
45
+ end
46
+
47
+ def eql?(other) #:nodoc:
48
+ super && quantifier.eql?(other.quantifier)
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,50 @@
1
+ module Regin
2
+ class CharacterClass < Character
3
+ def initialize(value, options = {})
4
+ @negate = options[:negate]
5
+ super
6
+ end
7
+
8
+ def option_names
9
+ %w( negate ) + super
10
+ end
11
+
12
+ attr_reader :negate
13
+
14
+ def negated?
15
+ negate ? true : false
16
+ end
17
+
18
+ # Returns true if expression could be treated as a literal string.
19
+ #
20
+ # A CharacterClass is never literal.
21
+ def literal?
22
+ false
23
+ end
24
+
25
+ def bracketed?
26
+ value != '.' && value !~ /^\\[dDsSwW]$/
27
+ end
28
+
29
+ def to_s(parent = false)
30
+ if bracketed?
31
+ if !parent && ignorecase
32
+ "(?i-mx:[#{negate && '^'}#{value}])#{quantifier}"
33
+ else
34
+ "[#{negate && '^'}#{value}]#{quantifier}"
35
+ end
36
+ else
37
+ super
38
+ end
39
+ end
40
+
41
+ def include?(char)
42
+ re = quantifier ? to_s.sub(/#{Regexp.escape(quantifier)}$/, '') : to_s
43
+ Regexp.compile("\\A#{re}\\Z").match(char)
44
+ end
45
+
46
+ def eql?(other) #:nodoc:
47
+ super && negate == other.negate
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,77 @@
1
+ module Regin
2
+ class Collection
3
+ include Enumerable
4
+
5
+ def initialize(*args)
6
+ @array = Array.new(*args)
7
+ end
8
+
9
+ def each
10
+ @array.each{ |item| yield item }
11
+ end
12
+
13
+ def [](i)
14
+ @array[i]
15
+ end
16
+
17
+ def length
18
+ @array.length
19
+ end
20
+ alias_method :size, :length
21
+
22
+ def first
23
+ @array.first
24
+ end
25
+
26
+ def last
27
+ @array.last
28
+ end
29
+
30
+ def +(other)
31
+ ary = other.is_a?(self.class) ? other.internal_array : other
32
+ self.class.new(@array + ary)
33
+ end
34
+
35
+ def to_regexp(anchored = false)
36
+ re = to_s(true)
37
+ re = "\\A#{re}\\Z" if anchored
38
+ Regexp.compile(re, flags)
39
+ end
40
+
41
+ def match(char)
42
+ to_regexp.match(char)
43
+ end
44
+
45
+ def include?(char)
46
+ any? { |e| e.include?(char) }
47
+ end
48
+
49
+ def ==(other) #:nodoc:
50
+ case other
51
+ when String
52
+ other == to_s
53
+ when Array
54
+ other == @array
55
+ else
56
+ eql?(other)
57
+ end
58
+ end
59
+
60
+ def eql?(other) #:nodoc:
61
+ other.instance_of?(self.class) && @array.eql?(other.internal_array)
62
+ end
63
+
64
+ protected
65
+ def internal_array #:nodoc:
66
+ @array
67
+ end
68
+
69
+ def extract_options(args)
70
+ if args.last.is_a?(Hash)
71
+ return args[0..-2], args.last
72
+ else
73
+ return args, {}
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,126 @@
1
+ module Regin
2
+ class Expression < Collection
3
+ attr_reader :ignorecase, :multiline, :extended
4
+
5
+ def initialize(*args)
6
+ args, options = extract_options(args)
7
+
8
+ @multiline = @ignorecase = @extended = nil
9
+
10
+ if args.length == 1 && args.first.instance_of?(Array)
11
+ super(args.first)
12
+ else
13
+ args = args.map { |e| e.instance_of?(String) ? Character.new(e) : e }
14
+ super(args)
15
+ end
16
+
17
+ self.multiline = options[:multiline] if options.key?(:multiline)
18
+ self.ignorecase = options[:ignorecase] if options.key?(:ignorecase)
19
+ self.extended = options[:extended] if options.key?(:extended)
20
+ end
21
+
22
+ # Returns true if expression could be treated as a literal string.
23
+ #
24
+ # A Expression is literal if all its elements are literal.
25
+ def literal?
26
+ !ignorecase && all? { |e| e.literal? }
27
+ end
28
+
29
+ def anchored?
30
+ anchored_to_start? && anchored_to_end?
31
+ end
32
+
33
+ def anchored_to_start?
34
+ first.is_a?(Anchor) && first == '\A'
35
+ end
36
+
37
+ def anchored_to_end?
38
+ last.is_a?(Anchor) && last == '\Z'
39
+ end
40
+
41
+ def anchored_to_line?
42
+ anchored_to_start_of_line? && anchored_to_end_of_line?
43
+ end
44
+
45
+ def anchored_to_start_of_line?
46
+ anchored_to_start? || (first.is_a?(Anchor) && first == '^')
47
+ end
48
+
49
+ def anchored_to_end_of_line?
50
+ anchored_to_end? || (last.is_a?(Anchor) && last == '$')
51
+ end
52
+
53
+ def options?
54
+ options.any?(true)
55
+ end
56
+
57
+ def flags
58
+ options.to_i
59
+ end
60
+
61
+ def +(other)
62
+ ary = other.is_a?(self.class) ? other.internal_array : other
63
+ ary = @array + ary + [options.to_h(true)]
64
+ self.class.new(*ary)
65
+ end
66
+
67
+ def dup(options = {})
68
+ expression = super()
69
+ expression.multiline = options[:multiline] if options.key?(:multiline)
70
+ expression.ignorecase = options[:ignorecase] if options.key?(:ignorecase)
71
+ expression.extended = options[:extended] if options.key?(:extended)
72
+ expression
73
+ end
74
+
75
+ def to_s(parent = false)
76
+ if parent || !options?
77
+ map { |e| e.to_s(parent) }.join
78
+ else
79
+ with, without = [], []
80
+ multiline ? (with << 'm') : (without << 'm')
81
+ ignorecase ? (with << 'i') : (without << 'i')
82
+ extended ? (with << 'x') : (without << 'x')
83
+
84
+ with = with.join
85
+ without = without.any? ? "-#{without.join}" : ''
86
+
87
+ "(?#{with}#{without}:#{map { |e| e.to_s(true) }.join})"
88
+ end
89
+ end
90
+
91
+ def inspect #:nodoc:
92
+ "#<Expression #{to_s.inspect}>"
93
+ end
94
+
95
+ def casefold?
96
+ ignorecase
97
+ end
98
+
99
+ def eql?(other) #:nodoc:
100
+ super &&
101
+ !!self.multiline == !!other.multiline &&
102
+ !!self.ignorecase == !!other.ignorecase &&
103
+ !!self.extended == !!other.extended
104
+ end
105
+
106
+ protected
107
+ def options
108
+ Options.new(multiline, ignorecase, extended)
109
+ end
110
+
111
+ def multiline=(multiline)
112
+ @multiline = multiline
113
+ end
114
+
115
+ def ignorecase=(ignorecase)
116
+ if @ignorecase.nil?
117
+ @array.map! { |e| e.dup(:ignorecase => ignorecase) }
118
+ @ignorecase = ignorecase
119
+ end
120
+ end
121
+
122
+ def extended=(extended)
123
+ @extended = extended
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,85 @@
1
+ module Regin
2
+ class Group
3
+ attr_reader :expression, :quantifier, :capture, :index, :name
4
+
5
+ def initialize(expression, options = {})
6
+ @quantifier = @index = @name = nil
7
+ @capture = true
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)
14
+ end
15
+
16
+ def option_names
17
+ %w( quantifier capture index name )
18
+ end
19
+
20
+ # Returns true if expression could be treated as a literal string.
21
+ #
22
+ # A Group is literal if its expression is literal and it has no quantifier.
23
+ def literal?
24
+ quantifier.nil? && expression.literal?
25
+ end
26
+
27
+ def to_s(parent = false)
28
+ if !expression.options?
29
+ "(#{capture ? '' : '?:'}#{expression.to_s(parent)})#{quantifier}"
30
+ elsif capture == false
31
+ "#{expression.to_s}#{quantifier}"
32
+ else
33
+ "(#{expression.to_s})#{quantifier}"
34
+ end
35
+ end
36
+
37
+ def to_regexp(anchored = false)
38
+ re = to_s
39
+ re = "\\A#{re}\\Z" if anchored
40
+ Regexp.compile(re)
41
+ end
42
+
43
+ def dup(options = {})
44
+ original_options = option_names.inject({}) do |h, m|
45
+ h[m.to_sym] = send(m)
46
+ h
47
+ end
48
+ self.class.new(expression, original_options.merge(options))
49
+ end
50
+
51
+ def inspect #:nodoc:
52
+ to_s.inspect
53
+ end
54
+
55
+ def match(char)
56
+ to_regexp.match(char)
57
+ end
58
+
59
+ def include?(char)
60
+ expression.include?(char)
61
+ end
62
+
63
+ def capture?
64
+ capture
65
+ end
66
+
67
+ def ==(other) #:nodoc:
68
+ case other
69
+ when String
70
+ other == to_s
71
+ else
72
+ eql?(other)
73
+ end
74
+ end
75
+
76
+ def eql?(other) #:nodoc:
77
+ other.is_a?(self.class) &&
78
+ self.expression == other.expression &&
79
+ self.quantifier == other.quantifier &&
80
+ self.capture == other.capture &&
81
+ self.index == other.index &&
82
+ self.name == other.name
83
+ end
84
+ end
85
+ end