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.
- data/LICENSE +20 -0
- data/README.rdoc +36 -0
- data/lib/rack/mount.rb +32 -0
- data/lib/rack/mount/analysis/frequency.rb +60 -0
- data/lib/rack/mount/analysis/histogram.rb +74 -0
- data/lib/rack/mount/analysis/splitting.rb +159 -0
- data/lib/rack/mount/code_generation.rb +117 -0
- data/lib/rack/mount/generatable_regexp.rb +210 -0
- data/lib/rack/mount/multimap.rb +53 -0
- data/lib/rack/mount/prefix.rb +36 -0
- data/lib/rack/mount/regexp_with_named_groups.rb +69 -0
- data/lib/rack/mount/route.rb +130 -0
- data/lib/rack/mount/route_set.rb +420 -0
- data/lib/rack/mount/strexp.rb +68 -0
- data/lib/rack/mount/strexp/parser.rb +160 -0
- data/lib/rack/mount/strexp/parser.y +34 -0
- data/lib/rack/mount/strexp/tokenizer.rb +83 -0
- data/lib/rack/mount/strexp/tokenizer.rex +12 -0
- data/lib/rack/mount/utils.rb +162 -0
- data/lib/rack/mount/vendor/multimap/multimap.rb +569 -0
- data/lib/rack/mount/vendor/multimap/multiset.rb +185 -0
- data/lib/rack/mount/vendor/multimap/nested_multimap.rb +158 -0
- data/lib/rack/mount/vendor/regin/regin.rb +75 -0
- data/lib/rack/mount/vendor/regin/regin/alternation.rb +40 -0
- data/lib/rack/mount/vendor/regin/regin/anchor.rb +4 -0
- data/lib/rack/mount/vendor/regin/regin/atom.rb +54 -0
- data/lib/rack/mount/vendor/regin/regin/character.rb +51 -0
- data/lib/rack/mount/vendor/regin/regin/character_class.rb +50 -0
- data/lib/rack/mount/vendor/regin/regin/collection.rb +77 -0
- data/lib/rack/mount/vendor/regin/regin/expression.rb +126 -0
- data/lib/rack/mount/vendor/regin/regin/group.rb +85 -0
- data/lib/rack/mount/vendor/regin/regin/options.rb +55 -0
- data/lib/rack/mount/vendor/regin/regin/parser.rb +520 -0
- data/lib/rack/mount/vendor/regin/regin/tokenizer.rb +246 -0
- data/lib/rack/mount/vendor/regin/regin/version.rb +3 -0
- data/lib/rack/mount/version.rb +3 -0
- metadata +140 -0
@@ -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
|