mustermann19 0.3.1 → 0.3.1.1
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 +7 -0
- data/.travis.yml +4 -3
- data/README.md +680 -376
- data/lib/mustermann/ast/compiler.rb +13 -7
- data/lib/mustermann/ast/expander.rb +11 -5
- data/lib/mustermann/ast/node.rb +27 -1
- data/lib/mustermann/ast/param_scanner.rb +20 -0
- data/lib/mustermann/ast/parser.rb +131 -12
- data/lib/mustermann/ast/pattern.rb +45 -6
- data/lib/mustermann/ast/template_generator.rb +28 -0
- data/lib/mustermann/ast/validation.rb +5 -3
- data/lib/mustermann/composite.rb +103 -0
- data/lib/mustermann/expander.rb +1 -1
- data/lib/mustermann/express.rb +34 -0
- data/lib/mustermann/flask.rb +204 -0
- data/lib/mustermann/identity.rb +54 -0
- data/lib/mustermann/pattern.rb +186 -12
- data/lib/mustermann/pattern_cache.rb +49 -0
- data/lib/mustermann/pyramid.rb +25 -0
- data/lib/mustermann/regexp_based.rb +18 -1
- data/lib/mustermann/regular.rb +1 -1
- data/lib/mustermann/shell.rb +8 -0
- data/lib/mustermann/simple.rb +1 -1
- data/lib/mustermann/simple_match.rb +5 -0
- data/lib/mustermann/sinatra.rb +19 -5
- data/lib/mustermann/string_scanner.rb +314 -0
- data/lib/mustermann/template.rb +10 -0
- data/lib/mustermann/to_pattern.rb +11 -6
- data/lib/mustermann/version.rb +1 -1
- data/lib/mustermann.rb +52 -3
- data/mustermann.gemspec +1 -1
- data/spec/composite_spec.rb +147 -0
- data/spec/expander_spec.rb +15 -0
- data/spec/express_spec.rb +209 -0
- data/spec/flask_spec.rb +361 -0
- data/spec/flask_subclass_spec.rb +368 -0
- data/spec/identity_spec.rb +44 -0
- data/spec/mustermann_spec.rb +14 -0
- data/spec/pattern_spec.rb +7 -3
- data/spec/pyramid_spec.rb +101 -0
- data/spec/rails_spec.rb +76 -2
- data/spec/regular_spec.rb +25 -0
- data/spec/shell_spec.rb +33 -0
- data/spec/simple_spec.rb +25 -0
- data/spec/sinatra_spec.rb +184 -9
- data/spec/string_scanner_spec.rb +271 -0
- data/spec/support/expand_matcher.rb +7 -5
- data/spec/support/generate_template_matcher.rb +27 -0
- data/spec/support/pattern.rb +3 -0
- data/spec/support/scan_matcher.rb +63 -0
- data/spec/support.rb +2 -1
- data/spec/template_spec.rb +22 -0
- data/spec/to_pattern_spec.rb +49 -0
- metadata +47 -61
- data/internals.md +0 -64
data/spec/rails_spec.rb
CHANGED
@@ -11,6 +11,11 @@ describe Mustermann::Rails do
|
|
11
11
|
|
12
12
|
it { should expand.to('') }
|
13
13
|
it { should_not expand(a: 1) }
|
14
|
+
|
15
|
+
it { should generate_template('') }
|
16
|
+
|
17
|
+
it { should respond_to(:expand) }
|
18
|
+
it { should respond_to(:to_templates) }
|
14
19
|
end
|
15
20
|
|
16
21
|
pattern '/' do
|
@@ -62,6 +67,8 @@ describe Mustermann::Rails do
|
|
62
67
|
it { should_not expand(foo: 'foo', bar: 'bar') }
|
63
68
|
it { should_not expand(bar: 'bar') }
|
64
69
|
it { should_not expand }
|
70
|
+
|
71
|
+
it { should generate_template('/{foo}') }
|
65
72
|
end
|
66
73
|
|
67
74
|
pattern '/föö' do
|
@@ -86,23 +93,29 @@ describe Mustermann::Rails do
|
|
86
93
|
it { should expand(foo: 'foo', bar: 'bar').to('/foo/bar') }
|
87
94
|
it { should_not expand(foo: 'foo') }
|
88
95
|
it { should_not expand(bar: 'bar') }
|
96
|
+
|
97
|
+
it { should generate_template('/{foo}/{bar}') }
|
89
98
|
end
|
90
99
|
|
91
100
|
pattern '/hello/:person' do
|
92
101
|
it { should match('/hello/Frank').capturing person: 'Frank' }
|
93
102
|
it { should expand(person: 'Frank') .to '/hello/Frank' }
|
94
103
|
it { should expand(person: 'Frank?') .to '/hello/Frank%3F' }
|
104
|
+
|
105
|
+
it { should generate_template('/hello/{person}') }
|
95
106
|
end
|
96
107
|
|
97
108
|
pattern '/?:foo?/?:bar?' do
|
98
109
|
it { should match('/?hello?/?world?').capturing foo: 'hello', bar: 'world' }
|
99
110
|
it { should_not match('/hello/world/') }
|
100
111
|
it { should expand(foo: 'hello', bar: 'world').to('/%3Fhello%3F/%3Fworld%3F') }
|
112
|
+
it { should generate_template('/?{foo}?/?{bar}?') }
|
101
113
|
end
|
102
114
|
|
103
115
|
pattern '/:foo_bar' do
|
104
116
|
it { should match('/hello').capturing foo_bar: 'hello' }
|
105
117
|
it { should expand(foo_bar: 'hello').to('/hello') }
|
118
|
+
it { should generate_template('/{foo_bar}') }
|
106
119
|
end
|
107
120
|
|
108
121
|
pattern '/*foo' do
|
@@ -116,6 +129,15 @@ describe Mustermann::Rails do
|
|
116
129
|
it { should expand(foo: 'foo') .to('/foo') }
|
117
130
|
it { should expand(foo: 'foo/bar') .to('/foo/bar') }
|
118
131
|
it { should expand(foo: 'foo.bar') .to('/foo.bar') }
|
132
|
+
|
133
|
+
it { should generate_template('/{+foo}') }
|
134
|
+
end
|
135
|
+
|
136
|
+
pattern '/*splat' do
|
137
|
+
it { should match('/') .capturing splat: '' }
|
138
|
+
it { should match('/foo') .capturing splat: 'foo' }
|
139
|
+
it { should match('/foo/bar') .capturing splat: 'foo/bar' }
|
140
|
+
it { should generate_template('/{+splat}') }
|
119
141
|
end
|
120
142
|
|
121
143
|
pattern '/:foo/*bar' do
|
@@ -129,6 +151,8 @@ describe Mustermann::Rails do
|
|
129
151
|
it { should expand(foo: 'foo', bar: 'bar') .to('/foo/bar') }
|
130
152
|
it { should expand(foo: 'foo', bar: 'foo/bar') .to('/foo/foo/bar') }
|
131
153
|
it { should expand(foo: 'foo/bar', bar: 'bar') .to('/foo%2Fbar/bar') }
|
154
|
+
|
155
|
+
it { should generate_template('/{foo}/{+bar}') }
|
132
156
|
end
|
133
157
|
|
134
158
|
pattern '/test$/' do
|
@@ -148,6 +172,8 @@ describe Mustermann::Rails do
|
|
148
172
|
it { should match('/path%2Bwith%2Bspaces') }
|
149
173
|
it { should match('/path+with+spaces') }
|
150
174
|
it { should expand.to('/path%20with%20spaces') }
|
175
|
+
|
176
|
+
it { should generate_template('/path%20with%20spaces') }
|
151
177
|
end
|
152
178
|
|
153
179
|
pattern '/foo&bar' do
|
@@ -158,6 +184,7 @@ describe Mustermann::Rails do
|
|
158
184
|
it { should match('/bar/foo/bling/baz/boom').capturing a: 'bar', foo: 'foo', b: 'bling', c: 'baz/boom' }
|
159
185
|
example { pattern.params('/bar/foo/bling/baz/boom').should be == { "a" => 'bar', "foo" => 'foo', "b" => 'bling', "c" => 'baz/boom' } }
|
160
186
|
it { should expand(a: 'bar', foo: 'foo', b: 'bling', c: 'baz/boom').to('/bar/foo/bling/baz/boom') }
|
187
|
+
it { should generate_template('/{+a}/{foo}/{+b}/{+c}') }
|
161
188
|
end
|
162
189
|
|
163
190
|
pattern '/test.bar' do
|
@@ -189,6 +216,9 @@ describe Mustermann::Rails do
|
|
189
216
|
it { should match('/axaxx') .capturing a: 'axax' }
|
190
217
|
it { should expand(a: 'x').to('/xx') }
|
191
218
|
it { should expand(a: 'a').to('/ax') }
|
219
|
+
|
220
|
+
it { should generate_template('/{a}x') }
|
221
|
+
it { should generate_template('/{a}') }
|
192
222
|
end
|
193
223
|
|
194
224
|
pattern '/:user(@:host)' do
|
@@ -198,6 +228,9 @@ describe Mustermann::Rails do
|
|
198
228
|
|
199
229
|
it { should expand(user: 'foo') .to('/foo') }
|
200
230
|
it { should expand(user: 'foo', host: 'bar') .to('/foo@bar') }
|
231
|
+
|
232
|
+
it { should generate_template('/{user}') }
|
233
|
+
it { should generate_template('/{user}@{host}') }
|
201
234
|
end
|
202
235
|
|
203
236
|
pattern '/:file(.:ext)' do
|
@@ -211,6 +244,9 @@ describe Mustermann::Rails do
|
|
211
244
|
|
212
245
|
it { should expand(file: 'pony') .to('/pony') }
|
213
246
|
it { should expand(file: 'pony', ext: 'jpg') .to('/pony.jpg') }
|
247
|
+
|
248
|
+
it { should generate_template('/{file}') }
|
249
|
+
it { should generate_template('/{file}.{ext}') }
|
214
250
|
end
|
215
251
|
|
216
252
|
pattern '/:id/test.bar' do
|
@@ -245,6 +281,10 @@ describe Mustermann::Rails do
|
|
245
281
|
|
246
282
|
it { should expand(a: ?a, b: ?b) .to('/a/b.') }
|
247
283
|
it { should expand(a: ?a, b: ?b, c: ?c) .to('/a/b.c') }
|
284
|
+
|
285
|
+
it { should generate_template('/{a}/{b}') }
|
286
|
+
it { should generate_template('/{a}/{b}.') }
|
287
|
+
it { should generate_template('/{a}/{b}.{c}') }
|
248
288
|
end
|
249
289
|
|
250
290
|
pattern '/:a(foo:b)' do
|
@@ -255,6 +295,10 @@ describe Mustermann::Rails do
|
|
255
295
|
|
256
296
|
it { should expand(a: ?a) .to('/a') }
|
257
297
|
it { should expand(a: ?a, b: ?b) .to('/afoob') }
|
298
|
+
|
299
|
+
it { should generate_template('/{a}foo{b}') }
|
300
|
+
it { should generate_template('/{a}') }
|
301
|
+
it { should_not generate_template('/{a}foo') }
|
258
302
|
end
|
259
303
|
|
260
304
|
pattern '/fo(o)' do
|
@@ -512,11 +556,41 @@ describe Mustermann::Rails do
|
|
512
556
|
end
|
513
557
|
|
514
558
|
describe :to_regexp do
|
515
|
-
example('empty pattern') { Mustermann::Rails.new('').to_regexp.should be == /\A\Z/ }
|
559
|
+
example('empty pattern') { Mustermann::Rails.new('').to_regexp.should be == /\A(?-mix:)\Z/ }
|
516
560
|
|
517
561
|
context 'Regexp.try_convert' do
|
518
|
-
example('empty pattern') { Regexp.try_convert(Mustermann::Rails.new('')).should be == /\A\Z/ }
|
562
|
+
example('empty pattern') { Regexp.try_convert(Mustermann::Rails.new('')).should be == /\A(?-mix:)\Z/ }
|
519
563
|
end
|
520
564
|
end
|
521
565
|
end
|
566
|
+
|
567
|
+
context 'Proc compatibility' do
|
568
|
+
describe :to_proc do
|
569
|
+
example { Mustermann::Rails.new("/").to_proc.should be_a(Proc) }
|
570
|
+
example('non-matching') { Mustermann::Rails.new("/") .to_proc.call('/foo').should be == false }
|
571
|
+
example('matching') { Mustermann::Rails.new("/:foo") .to_proc.call('/foo').should be == true }
|
572
|
+
end
|
573
|
+
end
|
574
|
+
|
575
|
+
context "peeking" do
|
576
|
+
subject(:pattern) { Mustermann::Rails.new(":name") }
|
577
|
+
|
578
|
+
describe :peek_size do
|
579
|
+
example { pattern.peek_size("foo bar/blah") .should be == "foo bar".size }
|
580
|
+
example { pattern.peek_size("foo%20bar/blah") .should be == "foo%20bar".size }
|
581
|
+
example { pattern.peek_size("/foo bar") .should be_nil }
|
582
|
+
end
|
583
|
+
|
584
|
+
describe :peek_match do
|
585
|
+
example { pattern.peek_match("foo bar/blah") .to_s .should be == "foo bar" }
|
586
|
+
example { pattern.peek_match("foo%20bar/blah") .to_s .should be == "foo%20bar" }
|
587
|
+
example { pattern.peek_match("/foo bar") .should be_nil }
|
588
|
+
end
|
589
|
+
|
590
|
+
describe :peek_params do
|
591
|
+
example { pattern.peek_params("foo bar/blah") .should be == [{"name" => "foo bar"}, "foo bar".size] }
|
592
|
+
example { pattern.peek_params("foo%20bar/blah") .should be == [{"name" => "foo bar"}, "foo%20bar".size] }
|
593
|
+
example { pattern.peek_params("/foo bar") .should be_nil }
|
594
|
+
end
|
595
|
+
end
|
522
596
|
end
|
data/spec/regular_spec.rb
CHANGED
@@ -7,6 +7,9 @@ describe Mustermann::Regular do
|
|
7
7
|
pattern '' do
|
8
8
|
it { should match('') }
|
9
9
|
it { should_not match('/') }
|
10
|
+
|
11
|
+
it { should_not respond_to(:expand) }
|
12
|
+
it { should_not respond_to(:to_templates) }
|
10
13
|
end
|
11
14
|
|
12
15
|
pattern '/' do
|
@@ -33,4 +36,26 @@ describe Mustermann::Regular do
|
|
33
36
|
it { should match('/%0Afoo') .capturing foo: '%0Afoo' }
|
34
37
|
it { should match('/foo%2Fbar') .capturing foo: 'foo%2Fbar' }
|
35
38
|
end
|
39
|
+
|
40
|
+
context "peeking" do
|
41
|
+
subject(:pattern) { Mustermann::Regular.new("(?<name>[^/]+)") }
|
42
|
+
|
43
|
+
describe :peek_size do
|
44
|
+
example { pattern.peek_size("foo bar/blah") .should be == "foo bar".size }
|
45
|
+
example { pattern.peek_size("foo%20bar/blah") .should be == "foo%20bar".size }
|
46
|
+
example { pattern.peek_size("/foo bar") .should be_nil }
|
47
|
+
end
|
48
|
+
|
49
|
+
describe :peek_match do
|
50
|
+
example { pattern.peek_match("foo bar/blah") .to_s .should be == "foo bar" }
|
51
|
+
example { pattern.peek_match("foo%20bar/blah") .to_s .should be == "foo%20bar" }
|
52
|
+
example { pattern.peek_match("/foo bar") .should be_nil }
|
53
|
+
end
|
54
|
+
|
55
|
+
describe :peek_params do
|
56
|
+
example { pattern.peek_params("foo bar/blah") .should be == [{"name" => "foo bar"}, "foo bar".size] }
|
57
|
+
example { pattern.peek_params("foo%20bar/blah") .should be == [{"name" => "foo bar"}, "foo%20bar".size] }
|
58
|
+
example { pattern.peek_params("/foo bar") .should be_nil }
|
59
|
+
end
|
60
|
+
end
|
36
61
|
end
|
data/spec/shell_spec.rb
CHANGED
@@ -8,6 +8,9 @@ describe Mustermann::Shell do
|
|
8
8
|
pattern '' do
|
9
9
|
it { should match('') }
|
10
10
|
it { should_not match('/') }
|
11
|
+
|
12
|
+
it { should_not respond_to(:expand) }
|
13
|
+
it { should_not respond_to(:to_templates) }
|
11
14
|
end
|
12
15
|
|
13
16
|
pattern '/' do
|
@@ -106,4 +109,34 @@ describe Mustermann::Shell do
|
|
106
109
|
describe :=~ do
|
107
110
|
example { '/foo'.should be =~ Mustermann::Shell.new('/foo') }
|
108
111
|
end
|
112
|
+
|
113
|
+
context "peeking", :skip => true do
|
114
|
+
subject(:pattern) { Mustermann::Shell.new("foo*/") }
|
115
|
+
|
116
|
+
describe :peek_size do
|
117
|
+
example { pattern.peek_size("foo bar/blah") .should be == "foo bar/".size }
|
118
|
+
example { pattern.peek_size("foo%20bar/blah") .should be == "foo%20bar/".size }
|
119
|
+
example { pattern.peek_size("/foo bar") .should be_nil }
|
120
|
+
|
121
|
+
context 'with just * as pattern' do
|
122
|
+
subject(:pattern) { Mustermann::Shell.new('*') }
|
123
|
+
example { pattern.peek_size('foo') .should be == 3 }
|
124
|
+
example { pattern.peek_size('foo/bar') .should be == 3 }
|
125
|
+
example { pattern.peek_size('foo/bar/baz') .should be == 3 }
|
126
|
+
example { pattern.peek_size('foo/bar/baz/blah') .should be == 3 }
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
describe :peek_match do
|
131
|
+
example { pattern.peek_match("foo bar/blah") .to_s .should be == "foo bar/" }
|
132
|
+
example { pattern.peek_match("foo%20bar/blah") .to_s .should be == "foo%20bar/" }
|
133
|
+
example { pattern.peek_match("/foo bar") .should be_nil }
|
134
|
+
end
|
135
|
+
|
136
|
+
describe :peek_params do
|
137
|
+
example { pattern.peek_params("foo bar/blah") .should be == [{}, "foo bar/".size] }
|
138
|
+
example { pattern.peek_params("foo%20bar/blah") .should be == [{}, "foo%20bar/".size] }
|
139
|
+
example { pattern.peek_params("/foo bar") .should be_nil }
|
140
|
+
end
|
141
|
+
end
|
109
142
|
end
|
data/spec/simple_spec.rb
CHANGED
@@ -8,6 +8,9 @@ describe Mustermann::Simple do
|
|
8
8
|
pattern '' do
|
9
9
|
it { should match('') }
|
10
10
|
it { should_not match('/') }
|
11
|
+
|
12
|
+
it { should_not respond_to(:expand) }
|
13
|
+
it { should_not respond_to(:to_templates) }
|
11
14
|
end
|
12
15
|
|
13
16
|
pattern '/' do
|
@@ -234,4 +237,26 @@ describe Mustermann::Simple do
|
|
234
237
|
to raise_error(Mustermann::CompileError)
|
235
238
|
end
|
236
239
|
end
|
240
|
+
|
241
|
+
context "peeking" do
|
242
|
+
subject(:pattern) { Mustermann::Simple.new(":name") }
|
243
|
+
|
244
|
+
describe :peek_size do
|
245
|
+
example { pattern.peek_size("foo bar/blah") .should be == "foo bar".size }
|
246
|
+
example { pattern.peek_size("foo%20bar/blah") .should be == "foo%20bar".size }
|
247
|
+
example { pattern.peek_size("/foo bar") .should be_nil }
|
248
|
+
end
|
249
|
+
|
250
|
+
describe :peek_match do
|
251
|
+
example { pattern.peek_match("foo bar/blah") .to_s .should be == "foo bar" }
|
252
|
+
example { pattern.peek_match("foo%20bar/blah") .to_s .should be == "foo%20bar" }
|
253
|
+
example { pattern.peek_match("/foo bar") .should be_nil }
|
254
|
+
end
|
255
|
+
|
256
|
+
describe :peek_params do
|
257
|
+
example { pattern.peek_params("foo bar/blah") .should be == [{"name" => "foo bar"}, "foo bar".size] }
|
258
|
+
example { pattern.peek_params("foo%20bar/blah") .should be == [{"name" => "foo bar"}, "foo%20bar".size] }
|
259
|
+
example { pattern.peek_params("/foo bar") .should be_nil }
|
260
|
+
end
|
261
|
+
end
|
237
262
|
end
|
data/spec/sinatra_spec.rb
CHANGED
@@ -8,6 +8,11 @@ describe Mustermann::Sinatra do
|
|
8
8
|
pattern '' do
|
9
9
|
it { should match('') }
|
10
10
|
it { should_not match('/') }
|
11
|
+
|
12
|
+
it { should generate_template('') }
|
13
|
+
|
14
|
+
it { should respond_to(:expand) }
|
15
|
+
it { should respond_to(:to_templates) }
|
11
16
|
end
|
12
17
|
|
13
18
|
pattern '/' do
|
@@ -44,6 +49,8 @@ describe Mustermann::Sinatra do
|
|
44
49
|
it { should_not match('/foo/bar') }
|
45
50
|
it { should_not match('/') }
|
46
51
|
it { should_not match('/foo/') }
|
52
|
+
|
53
|
+
it { should generate_template('/{foo}') }
|
47
54
|
end
|
48
55
|
|
49
56
|
pattern '/föö' do
|
@@ -62,10 +69,34 @@ describe Mustermann::Sinatra do
|
|
62
69
|
|
63
70
|
example { pattern.params('/bar/foo').should be == {"foo" => "bar", "bar" => "foo"} }
|
64
71
|
example { pattern.params('').should be_nil }
|
72
|
+
|
73
|
+
it { should generate_template('/{foo}/{bar}') }
|
74
|
+
end
|
75
|
+
|
76
|
+
pattern "/{foo}/{bar}" do
|
77
|
+
it { should match('/foo/bar') .capturing foo: 'foo', bar: 'bar' }
|
78
|
+
it { should match('/foo.bar/bar.foo') .capturing foo: 'foo.bar', bar: 'bar.foo' }
|
79
|
+
it { should match('/user@example.com/name') .capturing foo: 'user@example.com', bar: 'name' }
|
80
|
+
it { should match('/10.1/te.st') .capturing foo: '10.1', bar: 'te.st' }
|
81
|
+
it { should match('/10.1.2/te.st') .capturing foo: '10.1.2', bar: 'te.st' }
|
82
|
+
|
83
|
+
it { should_not match('/foo%2Fbar') }
|
84
|
+
it { should_not match('/foo%2fbar') }
|
85
|
+
|
86
|
+
example { pattern.params('/bar/foo').should be == {"foo" => "bar", "bar" => "foo"} }
|
87
|
+
example { pattern.params('').should be_nil }
|
88
|
+
|
89
|
+
it { should generate_template('/{foo}/{bar}') }
|
65
90
|
end
|
66
91
|
|
67
92
|
pattern '/hello/:person' do
|
68
93
|
it { should match('/hello/Frank').capturing person: 'Frank' }
|
94
|
+
it { should generate_template('/hello/{person}') }
|
95
|
+
end
|
96
|
+
|
97
|
+
pattern '/hello/{person}' do
|
98
|
+
it { should match('/hello/Frank').capturing person: 'Frank' }
|
99
|
+
it { should generate_template('/hello/{person}') }
|
69
100
|
end
|
70
101
|
|
71
102
|
pattern '/?:foo?/?:bar?' do
|
@@ -74,23 +105,40 @@ describe Mustermann::Sinatra do
|
|
74
105
|
it { should match('/') .capturing foo: nil, bar: nil }
|
75
106
|
it { should match('') .capturing foo: nil, bar: nil }
|
76
107
|
|
77
|
-
it {
|
108
|
+
it { should expand(foo: 'hello') .to('/hello/') }
|
109
|
+
it { should expand(foo: 'hello', bar: 'world') .to('/hello/world') }
|
110
|
+
it { should expand(bar: 'world') .to('//world') }
|
111
|
+
it { should expand .to('//') }
|
112
|
+
it { should_not expand(baz: '') }
|
78
113
|
|
79
|
-
|
80
|
-
|
81
|
-
# it { should expand(bar: 'world') .to('//world') }
|
82
|
-
# it { should expand .to('') }
|
83
|
-
# it { should_not expand(baz: '') }
|
114
|
+
it { should_not match('/hello/world/') }
|
115
|
+
it { should generate_templates("", "/", "//", "//{bar}", "/{bar}", "/{foo}", "/{foo}/", "/{foo}/{bar}", "/{foo}{bar}", "{bar}", "{foo}", "{foo}/", "{foo}/{bar}", "{foo}{bar}") }
|
84
116
|
end
|
85
117
|
|
86
118
|
pattern '/:foo_bar' do
|
87
119
|
it { should match('/hello').capturing foo_bar: 'hello' }
|
120
|
+
it { should generate_template('/{foo_bar}') }
|
121
|
+
end
|
122
|
+
|
123
|
+
pattern '/{foo.bar}' do
|
124
|
+
it { should match('/hello').capturing :"foo.bar" => 'hello' }
|
125
|
+
it { should generate_template('/{foo.bar}') }
|
88
126
|
end
|
89
127
|
|
90
128
|
pattern '/*' do
|
91
129
|
it { should match('/') .capturing splat: '' }
|
92
130
|
it { should match('/foo') .capturing splat: 'foo' }
|
93
131
|
it { should match('/foo/bar') .capturing splat: 'foo/bar' }
|
132
|
+
it { should generate_template('/{+splat}') }
|
133
|
+
|
134
|
+
example { pattern.params('/foo').should be == {"splat" => ["foo"]} }
|
135
|
+
end
|
136
|
+
|
137
|
+
pattern '/{+splat}' do
|
138
|
+
it { should match('/') .capturing splat: '' }
|
139
|
+
it { should match('/foo') .capturing splat: 'foo' }
|
140
|
+
it { should match('/foo/bar') .capturing splat: 'foo/bar' }
|
141
|
+
it { should generate_template('/{+splat}') }
|
94
142
|
|
95
143
|
example { pattern.params('/foo').should be == {"splat" => ["foo"]} }
|
96
144
|
end
|
@@ -99,6 +147,17 @@ describe Mustermann::Sinatra do
|
|
99
147
|
it { should match('/') .capturing foo: '' }
|
100
148
|
it { should match('/foo') .capturing foo: 'foo' }
|
101
149
|
it { should match('/foo/bar') .capturing foo: 'foo/bar' }
|
150
|
+
it { should generate_template('/{+foo}') }
|
151
|
+
|
152
|
+
example { pattern.params('/foo') .should be == {"foo" => "foo" } }
|
153
|
+
example { pattern.params('/foo/bar') .should be == {"foo" => "foo/bar" } }
|
154
|
+
end
|
155
|
+
|
156
|
+
pattern '/{+foo}' do
|
157
|
+
it { should match('/') .capturing foo: '' }
|
158
|
+
it { should match('/foo') .capturing foo: 'foo' }
|
159
|
+
it { should match('/foo/bar') .capturing foo: 'foo/bar' }
|
160
|
+
it { should generate_template('/{+foo}') }
|
102
161
|
|
103
162
|
example { pattern.params('/foo') .should be == {"foo" => "foo" } }
|
104
163
|
example { pattern.params('/foo/bar') .should be == {"foo" => "foo/bar" } }
|
@@ -106,6 +165,12 @@ describe Mustermann::Sinatra do
|
|
106
165
|
|
107
166
|
pattern '/*foo/*bar' do
|
108
167
|
it { should match('/foo/bar') .capturing foo: 'foo', bar: 'bar' }
|
168
|
+
it { should generate_template('/{+foo}/{+bar}') }
|
169
|
+
end
|
170
|
+
|
171
|
+
pattern '/{+foo}/{+bar}' do
|
172
|
+
it { should match('/foo/bar') .capturing foo: 'foo', bar: 'bar' }
|
173
|
+
it { should generate_template('/{+foo}/{+bar}') }
|
109
174
|
end
|
110
175
|
|
111
176
|
pattern '/:foo/*' do
|
@@ -113,6 +178,18 @@ describe Mustermann::Sinatra do
|
|
113
178
|
it { should match("/foo/") .capturing foo: 'foo', splat: '' }
|
114
179
|
it { should match('/h%20w/h%20a%20y') .capturing foo: 'h%20w', splat: 'h%20a%20y' }
|
115
180
|
it { should_not match('/foo') }
|
181
|
+
it { should generate_template('/{foo}/{+splat}') }
|
182
|
+
|
183
|
+
example { pattern.params('/bar/foo').should be == {"splat" => ["foo"], "foo" => "bar"} }
|
184
|
+
example { pattern.params('/bar/foo/f%20o').should be == {"splat" => ["foo/f o"], "foo" => "bar"} }
|
185
|
+
end
|
186
|
+
|
187
|
+
pattern '/{foo}/*' do
|
188
|
+
it { should match("/foo/bar/baz") .capturing foo: 'foo', splat: 'bar/baz' }
|
189
|
+
it { should match("/foo/") .capturing foo: 'foo', splat: '' }
|
190
|
+
it { should match('/h%20w/h%20a%20y') .capturing foo: 'h%20w', splat: 'h%20a%20y' }
|
191
|
+
it { should_not match('/foo') }
|
192
|
+
it { should generate_template('/{foo}/{+splat}') }
|
116
193
|
|
117
194
|
example { pattern.params('/bar/foo').should be == {"splat" => ["foo"], "foo" => "bar"} }
|
118
195
|
example { pattern.params('/bar/foo/f%20o').should be == {"splat" => ["foo/f o"], "foo" => "bar"} }
|
@@ -132,12 +209,18 @@ describe Mustermann::Sinatra do
|
|
132
209
|
it { should match('/path%20with%20spaces') }
|
133
210
|
it { should match('/path%2Bwith%2Bspaces') }
|
134
211
|
it { should match('/path+with+spaces') }
|
212
|
+
|
213
|
+
it { should generate_template('/path%20with%20spaces') }
|
135
214
|
end
|
136
215
|
|
137
216
|
pattern '/foo&bar' do
|
138
217
|
it { should match('/foo&bar') }
|
139
218
|
end
|
140
219
|
|
220
|
+
pattern '/foo\{bar' do
|
221
|
+
it { should match('/foo%7Bbar') }
|
222
|
+
end
|
223
|
+
|
141
224
|
pattern '/*/:foo/*/*' do
|
142
225
|
it { should match('/bar/foo/bling/baz/boom') }
|
143
226
|
|
@@ -154,13 +237,29 @@ describe Mustermann::Sinatra do
|
|
154
237
|
end
|
155
238
|
end
|
156
239
|
|
240
|
+
pattern '/{+splat}/{foo}/{+splat}/{+splat}' do
|
241
|
+
it { should match('/bar/foo/bling/baz/boom') }
|
242
|
+
|
243
|
+
it "should capture all splat parts" do
|
244
|
+
match = pattern.match('/bar/foo/bling/baz/boom')
|
245
|
+
match.captures.should be == ['bar', 'foo', 'bling', 'baz/boom']
|
246
|
+
match.names.should be == ['splat', 'foo']
|
247
|
+
end
|
248
|
+
|
249
|
+
it 'should map to proper params' do
|
250
|
+
pattern.params('/bar/foo/bling/baz/boom').should be == {
|
251
|
+
"foo" => "foo", "splat" => ['bar', 'bling', 'baz/boom']
|
252
|
+
}
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
157
256
|
pattern '/test.bar' do
|
158
257
|
it { should match('/test.bar') }
|
159
258
|
it { should_not match('/test0bar') }
|
160
259
|
end
|
161
260
|
|
162
261
|
pattern '/:file.:ext' do
|
163
|
-
it { should match('/pony.jpg')
|
262
|
+
it { should match('/pony.jpg') .capturing file: 'pony', ext: 'jpg' }
|
164
263
|
it { should match('/pony%2Ejpg') .capturing file: 'pony', ext: 'jpg' }
|
165
264
|
it { should match('/pony%2ejpg') .capturing file: 'pony', ext: 'jpg' }
|
166
265
|
|
@@ -180,12 +279,18 @@ describe Mustermann::Sinatra do
|
|
180
279
|
it { should match('/ax') .capturing a: 'a' }
|
181
280
|
it { should match('/axax') .capturing a: 'axa' }
|
182
281
|
it { should match('/axaxx') .capturing a: 'axax' }
|
282
|
+
|
283
|
+
it { should generate_template('/{a}x') }
|
284
|
+
it { should generate_template('/{a}') }
|
183
285
|
end
|
184
286
|
|
185
287
|
pattern '/:user(@:host)?' do
|
186
288
|
it { should match('/foo@bar') .capturing user: 'foo', host: 'bar' }
|
187
289
|
it { should match('/foo.foo@bar') .capturing user: 'foo.foo', host: 'bar' }
|
188
290
|
it { should match('/foo@bar.bar') .capturing user: 'foo', host: 'bar.bar' }
|
291
|
+
|
292
|
+
it { should generate_template('/{user}') }
|
293
|
+
it { should generate_template('/{user}@{host}') }
|
189
294
|
end
|
190
295
|
|
191
296
|
pattern '/:file(.:ext)?' do
|
@@ -196,6 +301,10 @@ describe Mustermann::Sinatra do
|
|
196
301
|
it { should match('/pony.png.jpg') .capturing file: 'pony.png', ext: 'jpg' }
|
197
302
|
it { should match('/pony.') .capturing file: 'pony.' }
|
198
303
|
it { should_not match('/.jpg') }
|
304
|
+
|
305
|
+
it { should generate_template('/{file}') }
|
306
|
+
it { should generate_template('/{file}.{ext}') }
|
307
|
+
it { should_not generate_template('/{file}.') }
|
199
308
|
end
|
200
309
|
|
201
310
|
pattern '/:id/test.bar' do
|
@@ -324,6 +433,37 @@ describe Mustermann::Sinatra do
|
|
324
433
|
it { should match('/foo/bar/baz').capturing foo: 'foo', bar: 'bar', baz: 'baz' }
|
325
434
|
end
|
326
435
|
|
436
|
+
pattern "/(foo|bar)" do
|
437
|
+
it { should match("/foo") }
|
438
|
+
it { should match("/bar") }
|
439
|
+
|
440
|
+
it { should generate_template('/foo') }
|
441
|
+
it { should generate_template('/bar') }
|
442
|
+
end
|
443
|
+
|
444
|
+
pattern "/(foo\\|bar)" do
|
445
|
+
it { should match "/foo%7Cbar" }
|
446
|
+
it { should generate_template "/foo%7Cbar" }
|
447
|
+
|
448
|
+
it { should_not match("/foo") }
|
449
|
+
it { should_not match("/bar") }
|
450
|
+
|
451
|
+
it { should_not generate_template('/foo') }
|
452
|
+
it { should_not generate_template('/bar') }
|
453
|
+
end
|
454
|
+
|
455
|
+
pattern "/(:a/:b|:c)" do
|
456
|
+
it { should match("/foo") .capturing c: 'foo' }
|
457
|
+
it { should match("/foo/bar") .capturing a: 'foo', b: 'bar' }
|
458
|
+
|
459
|
+
it { should generate_template('/{a}/{b}') }
|
460
|
+
it { should generate_template('/{c}') }
|
461
|
+
|
462
|
+
it { should expand(a: 'foo', b: 'bar') .to('/foo/bar') }
|
463
|
+
it { should expand(c: 'foo') .to('/foo') }
|
464
|
+
it { should_not expand(a: 'foo', b: 'bar', c: 'baz') }
|
465
|
+
end
|
466
|
+
|
327
467
|
pattern '/:foo', capture: /\d+/ do
|
328
468
|
it { should match('/1') .capturing foo: '1' }
|
329
469
|
it { should match('/123') .capturing foo: '123' }
|
@@ -509,6 +649,11 @@ describe Mustermann::Sinatra do
|
|
509
649
|
to raise_error(Mustermann::ParseError, 'unexpected ? while parsing "foo??bar"')
|
510
650
|
end
|
511
651
|
|
652
|
+
example '| outside of group' do
|
653
|
+
expect { Mustermann::Sinatra.new('foo|bar') }.
|
654
|
+
to raise_error(Mustermann::ParseError, 'unexpected | while parsing "foo|bar"')
|
655
|
+
end
|
656
|
+
|
512
657
|
example 'dangling escape' do
|
513
658
|
expect { Mustermann::Sinatra.new('foo\\') }.
|
514
659
|
to raise_error(Mustermann::ParseError, 'unexpected end of string while parsing "foo\\\\"')
|
@@ -564,11 +709,41 @@ describe Mustermann::Sinatra do
|
|
564
709
|
end
|
565
710
|
|
566
711
|
describe :to_regexp do
|
567
|
-
example('empty pattern') { Mustermann::Sinatra.new('').to_regexp.should be == /\A\Z/ }
|
712
|
+
example('empty pattern') { Mustermann::Sinatra.new('').to_regexp.should be == /\A(?-mix:)\Z/ }
|
568
713
|
|
569
714
|
context 'Regexp.try_convert' do
|
570
|
-
example('empty pattern') { Regexp.try_convert(Mustermann::Sinatra.new('')).should be == /\A\Z/ }
|
715
|
+
example('empty pattern') { Regexp.try_convert(Mustermann::Sinatra.new('')).should be == /\A(?-mix:)\Z/ }
|
571
716
|
end
|
572
717
|
end
|
573
718
|
end
|
719
|
+
|
720
|
+
context 'Proc compatibility' do
|
721
|
+
describe :to_proc do
|
722
|
+
example { Mustermann::Sinatra.new("/").to_proc.should be_a(Proc) }
|
723
|
+
example('non-matching') { Mustermann::Sinatra.new("/") .to_proc.call('/foo').should be == false }
|
724
|
+
example('matching') { Mustermann::Sinatra.new("/:foo") .to_proc.call('/foo').should be == true }
|
725
|
+
end
|
726
|
+
end
|
727
|
+
|
728
|
+
context "peeking" do
|
729
|
+
subject(:pattern) { Mustermann::Sinatra.new(":name") }
|
730
|
+
|
731
|
+
describe :peek_size do
|
732
|
+
example { pattern.peek_size("foo bar/blah") .should be == "foo bar".size }
|
733
|
+
example { pattern.peek_size("foo%20bar/blah") .should be == "foo%20bar".size }
|
734
|
+
example { pattern.peek_size("/foo bar") .should be_nil }
|
735
|
+
end
|
736
|
+
|
737
|
+
describe :peek_match do
|
738
|
+
example { pattern.peek_match("foo bar/blah") .to_s .should be == "foo bar" }
|
739
|
+
example { pattern.peek_match("foo%20bar/blah") .to_s .should be == "foo%20bar" }
|
740
|
+
example { pattern.peek_match("/foo bar") .should be_nil }
|
741
|
+
end
|
742
|
+
|
743
|
+
describe :peek_params do
|
744
|
+
example { pattern.peek_params("foo bar/blah") .should be == [{"name" => "foo bar"}, "foo bar".size] }
|
745
|
+
example { pattern.peek_params("foo%20bar/blah") .should be == [{"name" => "foo bar"}, "foo%20bar".size] }
|
746
|
+
example { pattern.peek_params("/foo bar") .should be_nil }
|
747
|
+
end
|
748
|
+
end
|
574
749
|
end
|