mustermann 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +429 -672
  3. data/lib/mustermann.rb +95 -20
  4. data/lib/mustermann/ast/boundaries.rb +44 -0
  5. data/lib/mustermann/ast/compiler.rb +13 -7
  6. data/lib/mustermann/ast/expander.rb +22 -12
  7. data/lib/mustermann/ast/node.rb +69 -5
  8. data/lib/mustermann/ast/param_scanner.rb +20 -0
  9. data/lib/mustermann/ast/parser.rb +138 -19
  10. data/lib/mustermann/ast/pattern.rb +59 -7
  11. data/lib/mustermann/ast/template_generator.rb +28 -0
  12. data/lib/mustermann/ast/transformer.rb +2 -2
  13. data/lib/mustermann/ast/translator.rb +20 -0
  14. data/lib/mustermann/ast/validation.rb +4 -3
  15. data/lib/mustermann/composite.rb +101 -0
  16. data/lib/mustermann/expander.rb +2 -2
  17. data/lib/mustermann/identity.rb +56 -0
  18. data/lib/mustermann/pattern.rb +185 -10
  19. data/lib/mustermann/pattern_cache.rb +49 -0
  20. data/lib/mustermann/regexp.rb +1 -0
  21. data/lib/mustermann/regexp_based.rb +18 -1
  22. data/lib/mustermann/regular.rb +4 -1
  23. data/lib/mustermann/simple_match.rb +5 -0
  24. data/lib/mustermann/sinatra.rb +22 -5
  25. data/lib/mustermann/to_pattern.rb +11 -6
  26. data/lib/mustermann/version.rb +1 -1
  27. data/mustermann.gemspec +1 -14
  28. data/spec/ast_spec.rb +14 -0
  29. data/spec/composite_spec.rb +147 -0
  30. data/spec/expander_spec.rb +15 -0
  31. data/spec/identity_spec.rb +44 -0
  32. data/spec/mustermann_spec.rb +17 -2
  33. data/spec/pattern_spec.rb +7 -3
  34. data/spec/regular_spec.rb +25 -0
  35. data/spec/sinatra_spec.rb +184 -9
  36. data/spec/to_pattern_spec.rb +49 -0
  37. metadata +15 -180
  38. data/.gitignore +0 -18
  39. data/.rspec +0 -2
  40. data/.travis.yml +0 -4
  41. data/.yardopts +0 -1
  42. data/Gemfile +0 -2
  43. data/LICENSE +0 -22
  44. data/Rakefile +0 -6
  45. data/internals.md +0 -64
  46. data/lib/mustermann/ast/tree_renderer.rb +0 -29
  47. data/lib/mustermann/rails.rb +0 -17
  48. data/lib/mustermann/shell.rb +0 -29
  49. data/lib/mustermann/simple.rb +0 -35
  50. data/lib/mustermann/template.rb +0 -47
  51. data/spec/rails_spec.rb +0 -521
  52. data/spec/shell_spec.rb +0 -108
  53. data/spec/simple_spec.rb +0 -236
  54. data/spec/support.rb +0 -5
  55. data/spec/support/coverage.rb +0 -16
  56. data/spec/support/env.rb +0 -16
  57. data/spec/support/expand_matcher.rb +0 -27
  58. data/spec/support/match_matcher.rb +0 -39
  59. data/spec/support/pattern.rb +0 -39
  60. data/spec/template_spec.rb +0 -814
@@ -1,39 +0,0 @@
1
- require 'timeout'
2
-
3
- module Support
4
- module Pattern
5
- def pattern(pattern, options = nil, &block)
6
- description = "pattern %p" % pattern
7
-
8
- if options
9
- description << " with options %p" % [options]
10
- instance = subject_for(pattern, options)
11
- else
12
- instance = subject_for(pattern)
13
- end
14
-
15
- context description do
16
- subject(:pattern, &instance)
17
- its(:to_s) { should be == pattern }
18
- its(:inspect) { should be == "#<#{described_class}:#{pattern.inspect}>" }
19
- its(:names) { should be_an(Array) }
20
-
21
- example 'string should be immune to external change' do
22
- subject.to_s.replace "NOT THE PATTERN"
23
- subject.to_s.should be == pattern
24
- end
25
-
26
- instance_eval(&block)
27
- end
28
- end
29
-
30
- def subject_for(pattern, *args)
31
- instance = Timeout.timeout(1) { described_class.new(pattern, *args) }
32
- proc { instance }
33
- rescue Timeout::Error => error
34
- proc { raise Timeout::Error, "could not compile #{pattern.inspect} in time", error.backtrace }
35
- rescue Exception => error
36
- proc { raise error }
37
- end
38
- end
39
- end
@@ -1,814 +0,0 @@
1
- require 'support'
2
- require 'mustermann/template'
3
-
4
- describe Mustermann::Template do
5
- extend Support::Pattern
6
-
7
- pattern '' do
8
- it { should match('') }
9
- it { should_not match('/') }
10
- end
11
-
12
- pattern '/' do
13
- it { should match('/') }
14
- it { should_not match('/foo') }
15
- end
16
-
17
- pattern '/foo' do
18
- it { should match('/foo') }
19
- it { should_not match('/bar') }
20
- it { should_not match('/foo.bar') }
21
- end
22
-
23
- pattern '/foo/bar' do
24
- it { should match('/foo/bar') }
25
- it { should_not match('/foo%2Fbar') }
26
- it { should_not match('/foo%2fbar') }
27
- end
28
-
29
- pattern '/:foo' do
30
- it { should match('/:foo') }
31
- it { should match('/%3Afoo') }
32
- it { should_not match('/foo') }
33
- it { should_not match('/foo?') }
34
- it { should_not match('/foo/bar') }
35
- it { should_not match('/') }
36
- it { should_not match('/foo/') }
37
- end
38
-
39
- pattern '/föö' do
40
- it { should match("/f%C3%B6%C3%B6") }
41
- end
42
-
43
- pattern '/test$/' do
44
- it { should match('/test$/') }
45
- end
46
-
47
- pattern '/te+st/' do
48
- it { should match('/te+st/') }
49
- it { should_not match('/test/') }
50
- it { should_not match('/teest/') }
51
- end
52
-
53
- pattern "/path with spaces" do
54
- it { should match('/path%20with%20spaces') }
55
- it { should match('/path%2Bwith%2Bspaces') }
56
- it { should match('/path+with+spaces') }
57
- end
58
-
59
- pattern '/foo&bar' do
60
- it { should match('/foo&bar') }
61
- end
62
-
63
- pattern '/test.bar' do
64
- it { should match('/test.bar') }
65
- it { should_not match('/test0bar') }
66
- end
67
-
68
- pattern "/path with spaces", space_matches_plus: false do
69
- it { should match('/path%20with%20spaces') }
70
- it { should_not match('/path%2Bwith%2Bspaces') }
71
- it { should_not match('/path+with+spaces') }
72
- end
73
-
74
- pattern "/path with spaces", uri_decode: false do
75
- it { should_not match('/path%20with%20spaces') }
76
- it { should_not match('/path%2Bwith%2Bspaces') }
77
- it { should_not match('/path+with+spaces') }
78
- end
79
-
80
- context 'level 1' do
81
- context 'without operator' do
82
- pattern '/hello/{person}' do
83
- it { should match('/hello/Frank').capturing person: 'Frank' }
84
- it { should match('/hello/a_b~c').capturing person: 'a_b~c' }
85
- it { should match('/hello/a.%20').capturing person: 'a.%20' }
86
-
87
- it { should_not match('/hello/:') }
88
- it { should_not match('/hello//') }
89
- it { should_not match('/hello/?') }
90
- it { should_not match('/hello/#') }
91
- it { should_not match('/hello/[') }
92
- it { should_not match('/hello/]') }
93
- it { should_not match('/hello/@') }
94
- it { should_not match('/hello/!') }
95
- it { should_not match('/hello/*') }
96
- it { should_not match('/hello/+') }
97
- it { should_not match('/hello/,') }
98
- it { should_not match('/hello/;') }
99
- it { should_not match('/hello/=') }
100
-
101
- example { pattern.params('/hello/Frank').should be == {'person' => 'Frank'} }
102
- end
103
-
104
- pattern "/{foo}/{bar}" do
105
- it { should match('/foo/bar') .capturing foo: 'foo', bar: 'bar' }
106
- it { should match('/foo.bar/bar.foo') .capturing foo: 'foo.bar', bar: 'bar.foo' }
107
- it { should match('/10.1/te.st') .capturing foo: '10.1', bar: 'te.st' }
108
- it { should match('/10.1.2/te.st') .capturing foo: '10.1.2', bar: 'te.st' }
109
-
110
- it { should_not match('/foo%2Fbar') }
111
- it { should_not match('/foo%2fbar') }
112
- end
113
- end
114
- end
115
-
116
- context 'level 2' do
117
- context 'operator +' do
118
- pattern '/hello/{+person}' do
119
- it { should match('/hello/Frank') .capturing person: 'Frank' }
120
- it { should match('/hello/a_b~c') .capturing person: 'a_b~c' }
121
- it { should match('/hello/a.%20') .capturing person: 'a.%20' }
122
- it { should match('/hello/a/%20') .capturing person: 'a/%20' }
123
- it { should match('/hello/:') .capturing person: ?: }
124
- it { should match('/hello//') .capturing person: ?/ }
125
- it { should match('/hello/?') .capturing person: ?? }
126
- it { should match('/hello/#') .capturing person: ?# }
127
- it { should match('/hello/[') .capturing person: ?[ }
128
- it { should match('/hello/]') .capturing person: ?] }
129
- it { should match('/hello/@') .capturing person: ?@ }
130
- it { should match('/hello/!') .capturing person: ?! }
131
- it { should match('/hello/*') .capturing person: ?* }
132
- it { should match('/hello/+') .capturing person: ?+ }
133
- it { should match('/hello/,') .capturing person: ?, }
134
- it { should match('/hello/;') .capturing person: ?; }
135
- it { should match('/hello/=') .capturing person: ?= }
136
- end
137
-
138
- pattern "/{+foo}/{bar}" do
139
- it { should match('/foo/bar') .capturing foo: 'foo', bar: 'bar' }
140
- it { should match('/foo.bar/bar.foo') .capturing foo: 'foo.bar', bar: 'bar.foo' }
141
- it { should match('/foo/bar/bar.foo') .capturing foo: 'foo/bar', bar: 'bar.foo' }
142
- it { should match('/10.1/te.st') .capturing foo: '10.1', bar: 'te.st' }
143
- it { should match('/10.1.2/te.st') .capturing foo: '10.1.2', bar: 'te.st' }
144
-
145
- it { should_not match('/foo%2Fbar') }
146
- it { should_not match('/foo%2fbar') }
147
- end
148
- end
149
-
150
- context 'operator #' do
151
- pattern '/hello/{#person}' do
152
- it { should match('/hello/#Frank') .capturing person: 'Frank' }
153
- it { should match('/hello/#a_b~c') .capturing person: 'a_b~c' }
154
- it { should match('/hello/#a.%20') .capturing person: 'a.%20' }
155
- it { should match('/hello/#a/%20') .capturing person: 'a/%20' }
156
- it { should match('/hello/#:') .capturing person: ?: }
157
- it { should match('/hello/#/') .capturing person: ?/ }
158
- it { should match('/hello/#?') .capturing person: ?? }
159
- it { should match('/hello/##') .capturing person: ?# }
160
- it { should match('/hello/#[') .capturing person: ?[ }
161
- it { should match('/hello/#]') .capturing person: ?] }
162
- it { should match('/hello/#@') .capturing person: ?@ }
163
- it { should match('/hello/#!') .capturing person: ?! }
164
- it { should match('/hello/#*') .capturing person: ?* }
165
- it { should match('/hello/#+') .capturing person: ?+ }
166
- it { should match('/hello/#,') .capturing person: ?, }
167
- it { should match('/hello/#;') .capturing person: ?; }
168
- it { should match('/hello/#=') .capturing person: ?= }
169
-
170
-
171
- it { should_not match('/hello/Frank') }
172
- it { should_not match('/hello/a_b~c') }
173
- it { should_not match('/hello/a.%20') }
174
-
175
- it { should_not match('/hello/:') }
176
- it { should_not match('/hello//') }
177
- it { should_not match('/hello/?') }
178
- it { should_not match('/hello/#') }
179
- it { should_not match('/hello/[') }
180
- it { should_not match('/hello/]') }
181
- it { should_not match('/hello/@') }
182
- it { should_not match('/hello/!') }
183
- it { should_not match('/hello/*') }
184
- it { should_not match('/hello/+') }
185
- it { should_not match('/hello/,') }
186
- it { should_not match('/hello/;') }
187
- it { should_not match('/hello/=') }
188
-
189
-
190
- example { pattern.params('/hello/#Frank').should be == {'person' => 'Frank'} }
191
- end
192
-
193
- pattern "/{+foo}/{#bar}" do
194
- it { should match('/foo/#bar') .capturing foo: 'foo', bar: 'bar' }
195
- it { should match('/foo.bar/#bar.foo') .capturing foo: 'foo.bar', bar: 'bar.foo' }
196
- it { should match('/foo/bar/#bar.foo') .capturing foo: 'foo/bar', bar: 'bar.foo' }
197
- it { should match('/10.1/#te.st') .capturing foo: '10.1', bar: 'te.st' }
198
- it { should match('/10.1.2/#te.st') .capturing foo: '10.1.2', bar: 'te.st' }
199
-
200
- it { should_not match('/foo%2F#bar') }
201
- it { should_not match('/foo%2f#bar') }
202
-
203
- example { pattern.params('/hello/#Frank').should be == {'foo' => 'hello', 'bar' => 'Frank'} }
204
- end
205
- end
206
- end
207
-
208
- context 'level 3' do
209
- context 'without operator' do
210
- pattern "{a,b,c}" do
211
- it { should match("~x,42,_").capturing a: '~x', b: '42', c: '_' }
212
- it { should_not match("~x,42") }
213
- it { should_not match("~x/42") }
214
- it { should_not match("~x#42") }
215
- it { should_not match("~x,42,_#42") }
216
-
217
- example { pattern.params('d,f,g').should be == {'a' => 'd', 'b' => 'f', 'c' => 'g'} }
218
- end
219
- end
220
-
221
- context 'operator +' do
222
- pattern "{+a,b,c}" do
223
- it { should match("~x,42,_") .capturing a: '~x', b: '42', c: '_' }
224
- it { should match("~x,42,_#42") .capturing a: '~x', b: '42', c: '_#42' }
225
- it { should match("~/x,42,_/42") .capturing a: '~/x', b: '42', c: '_/42' }
226
-
227
- it { should_not match("~x,42") }
228
- it { should_not match("~x/42") }
229
- it { should_not match("~x#42") }
230
- end
231
- end
232
-
233
- context 'operator #' do
234
- pattern "{#a,b,c}" do
235
- it { should match("#~x,42,_") .capturing a: '~x', b: '42', c: '_' }
236
- it { should match("#~x,42,_#42") .capturing a: '~x', b: '42', c: '_#42' }
237
- it { should match("#~/x,42,_#42") .capturing a: '~/x', b: '42', c: '_#42' }
238
-
239
- it { should_not match("~x,42,_") }
240
- it { should_not match("~x,42,_#42") }
241
- it { should_not match("~/x,42,_#42") }
242
-
243
- it { should_not match("~x,42") }
244
- it { should_not match("~x/42") }
245
- it { should_not match("~x#42") }
246
- end
247
- end
248
-
249
- context 'operator .' do
250
- pattern '/hello/{.person}' do
251
- it { should match('/hello/.Frank') .capturing person: 'Frank' }
252
- it { should match('/hello/.a_b~c') .capturing person: 'a_b~c' }
253
-
254
- it { should_not match('/hello/.:') }
255
- it { should_not match('/hello/./') }
256
- it { should_not match('/hello/.?') }
257
- it { should_not match('/hello/.#') }
258
- it { should_not match('/hello/.[') }
259
- it { should_not match('/hello/.]') }
260
- it { should_not match('/hello/.@') }
261
- it { should_not match('/hello/.!') }
262
- it { should_not match('/hello/.*') }
263
- it { should_not match('/hello/.+') }
264
- it { should_not match('/hello/.,') }
265
- it { should_not match('/hello/.;') }
266
- it { should_not match('/hello/.=') }
267
-
268
- it { should_not match('/hello/Frank') }
269
- it { should_not match('/hello/a_b~c') }
270
- it { should_not match('/hello/a.%20') }
271
-
272
- it { should_not match('/hello/:') }
273
- it { should_not match('/hello//') }
274
- it { should_not match('/hello/?') }
275
- it { should_not match('/hello/#') }
276
- it { should_not match('/hello/[') }
277
- it { should_not match('/hello/]') }
278
- it { should_not match('/hello/@') }
279
- it { should_not match('/hello/!') }
280
- it { should_not match('/hello/*') }
281
- it { should_not match('/hello/+') }
282
- it { should_not match('/hello/,') }
283
- it { should_not match('/hello/;') }
284
- it { should_not match('/hello/=') }
285
- end
286
-
287
- pattern "{.a,b,c}" do
288
- it { should match(".~x.42._").capturing a: '~x', b: '42', c: '_' }
289
- it { should_not match(".~x,42") }
290
- it { should_not match(".~x/42") }
291
- it { should_not match(".~x#42") }
292
- it { should_not match(".~x,42,_") }
293
- it { should_not match("~x.42._") }
294
- end
295
- end
296
-
297
- context 'operator /' do
298
- pattern '/hello{/person}' do
299
- it { should match('/hello/Frank') .capturing person: 'Frank' }
300
- it { should match('/hello/a_b~c') .capturing person: 'a_b~c' }
301
-
302
- it { should_not match('/hello//:') }
303
- it { should_not match('/hello///') }
304
- it { should_not match('/hello//?') }
305
- it { should_not match('/hello//#') }
306
- it { should_not match('/hello//[') }
307
- it { should_not match('/hello//]') }
308
- it { should_not match('/hello//@') }
309
- it { should_not match('/hello//!') }
310
- it { should_not match('/hello//*') }
311
- it { should_not match('/hello//+') }
312
- it { should_not match('/hello//,') }
313
- it { should_not match('/hello//;') }
314
- it { should_not match('/hello//=') }
315
-
316
- it { should_not match('/hello/:') }
317
- it { should_not match('/hello//') }
318
- it { should_not match('/hello/?') }
319
- it { should_not match('/hello/#') }
320
- it { should_not match('/hello/[') }
321
- it { should_not match('/hello/]') }
322
- it { should_not match('/hello/@') }
323
- it { should_not match('/hello/!') }
324
- it { should_not match('/hello/*') }
325
- it { should_not match('/hello/+') }
326
- it { should_not match('/hello/,') }
327
- it { should_not match('/hello/;') }
328
- it { should_not match('/hello/=') }
329
- end
330
-
331
- pattern "{/a,b,c}" do
332
- it { should match("/~x/42/_").capturing a: '~x', b: '42', c: '_' }
333
- it { should_not match("/~x,42") }
334
- it { should_not match("/~x.42") }
335
- it { should_not match("/~x#42") }
336
- it { should_not match("/~x,42,_") }
337
- it { should_not match("~x/42/_") }
338
- end
339
- end
340
-
341
- context 'operator ;' do
342
- pattern '/hello/{;person}' do
343
- it { should match('/hello/;person=Frank') .capturing person: 'Frank' }
344
- it { should match('/hello/;person=a_b~c') .capturing person: 'a_b~c' }
345
- it { should match('/hello/;person') .capturing person: nil }
346
-
347
- it { should_not match('/hello/;persona=Frank') }
348
- it { should_not match('/hello/;persona=a_b~c') }
349
-
350
- it { should_not match('/hello/;person=:') }
351
- it { should_not match('/hello/;person=/') }
352
- it { should_not match('/hello/;person=?') }
353
- it { should_not match('/hello/;person=#') }
354
- it { should_not match('/hello/;person=[') }
355
- it { should_not match('/hello/;person=]') }
356
- it { should_not match('/hello/;person=@') }
357
- it { should_not match('/hello/;person=!') }
358
- it { should_not match('/hello/;person=*') }
359
- it { should_not match('/hello/;person=+') }
360
- it { should_not match('/hello/;person=,') }
361
- it { should_not match('/hello/;person=;') }
362
- it { should_not match('/hello/;person==') }
363
-
364
- it { should_not match('/hello/;Frank') }
365
- it { should_not match('/hello/;a_b~c') }
366
- it { should_not match('/hello/;a.%20') }
367
-
368
- it { should_not match('/hello/:') }
369
- it { should_not match('/hello//') }
370
- it { should_not match('/hello/?') }
371
- it { should_not match('/hello/#') }
372
- it { should_not match('/hello/[') }
373
- it { should_not match('/hello/]') }
374
- it { should_not match('/hello/@') }
375
- it { should_not match('/hello/!') }
376
- it { should_not match('/hello/*') }
377
- it { should_not match('/hello/+') }
378
- it { should_not match('/hello/,') }
379
- it { should_not match('/hello/;') }
380
- it { should_not match('/hello/=') }
381
- end
382
-
383
- pattern "{;a,b,c}" do
384
- it { should match(";a=~x;b=42;c=_") .capturing a: '~x', b: '42', c: '_' }
385
- it { should match(";a=~x;b;c=_") .capturing a: '~x', b: nil, c: '_' }
386
-
387
- it { should_not match(";a=~x;c=_;b=42").capturing a: '~x', b: '42', c: '_' }
388
-
389
- it { should_not match(";a=~x;b=42") }
390
- it { should_not match("a=~x;b=42") }
391
- it { should_not match(";a=~x;b=#42;c") }
392
- it { should_not match(";a=~x,b=42,c=_") }
393
- it { should_not match("~x;b=42;c=_") }
394
- end
395
- end
396
-
397
- context 'operator ?' do
398
- pattern '/hello/{?person}' do
399
- it { should match('/hello/?person=Frank') .capturing person: 'Frank' }
400
- it { should match('/hello/?person=a_b~c') .capturing person: 'a_b~c' }
401
- it { should match('/hello/?person') .capturing person: nil }
402
-
403
- it { should_not match('/hello/?persona=Frank') }
404
- it { should_not match('/hello/?persona=a_b~c') }
405
-
406
- it { should_not match('/hello/?person=:') }
407
- it { should_not match('/hello/?person=/') }
408
- it { should_not match('/hello/?person=?') }
409
- it { should_not match('/hello/?person=#') }
410
- it { should_not match('/hello/?person=[') }
411
- it { should_not match('/hello/?person=]') }
412
- it { should_not match('/hello/?person=@') }
413
- it { should_not match('/hello/?person=!') }
414
- it { should_not match('/hello/?person=*') }
415
- it { should_not match('/hello/?person=+') }
416
- it { should_not match('/hello/?person=,') }
417
- it { should_not match('/hello/?person=;') }
418
- it { should_not match('/hello/?person==') }
419
-
420
- it { should_not match('/hello/?Frank') }
421
- it { should_not match('/hello/?a_b~c') }
422
- it { should_not match('/hello/?a.%20') }
423
-
424
- it { should_not match('/hello/:') }
425
- it { should_not match('/hello//') }
426
- it { should_not match('/hello/?') }
427
- it { should_not match('/hello/#') }
428
- it { should_not match('/hello/[') }
429
- it { should_not match('/hello/]') }
430
- it { should_not match('/hello/@') }
431
- it { should_not match('/hello/!') }
432
- it { should_not match('/hello/*') }
433
- it { should_not match('/hello/+') }
434
- it { should_not match('/hello/,') }
435
- it { should_not match('/hello/;') }
436
- it { should_not match('/hello/=') }
437
- end
438
-
439
- pattern "{?a,b,c}" do
440
- it { should match("?a=~x&b=42&c=_") .capturing a: '~x', b: '42', c: '_' }
441
- it { should match("?a=~x&b&c=_") .capturing a: '~x', b: nil, c: '_' }
442
-
443
- it { should_not match("?a=~x&c=_&b=42").capturing a: '~x', b: '42', c: '_' }
444
-
445
- it { should_not match("?a=~x&b=42") }
446
- it { should_not match("a=~x&b=42") }
447
- it { should_not match("?a=~x&b=#42&c") }
448
- it { should_not match("?a=~x,b=42,c=_") }
449
- it { should_not match("~x&b=42&c=_") }
450
- end
451
- end
452
-
453
- context 'operator &' do
454
- pattern '/hello/{&person}' do
455
- it { should match('/hello/&person=Frank') .capturing person: 'Frank' }
456
- it { should match('/hello/&person=a_b~c') .capturing person: 'a_b~c' }
457
- it { should match('/hello/&person') .capturing person: nil }
458
-
459
- it { should_not match('/hello/&persona=Frank') }
460
- it { should_not match('/hello/&persona=a_b~c') }
461
-
462
- it { should_not match('/hello/&person=:') }
463
- it { should_not match('/hello/&person=/') }
464
- it { should_not match('/hello/&person=?') }
465
- it { should_not match('/hello/&person=#') }
466
- it { should_not match('/hello/&person=[') }
467
- it { should_not match('/hello/&person=]') }
468
- it { should_not match('/hello/&person=@') }
469
- it { should_not match('/hello/&person=!') }
470
- it { should_not match('/hello/&person=*') }
471
- it { should_not match('/hello/&person=+') }
472
- it { should_not match('/hello/&person=,') }
473
- it { should_not match('/hello/&person=;') }
474
- it { should_not match('/hello/&person==') }
475
-
476
- it { should_not match('/hello/&Frank') }
477
- it { should_not match('/hello/&a_b~c') }
478
- it { should_not match('/hello/&a.%20') }
479
-
480
- it { should_not match('/hello/:') }
481
- it { should_not match('/hello//') }
482
- it { should_not match('/hello/?') }
483
- it { should_not match('/hello/#') }
484
- it { should_not match('/hello/[') }
485
- it { should_not match('/hello/]') }
486
- it { should_not match('/hello/@') }
487
- it { should_not match('/hello/!') }
488
- it { should_not match('/hello/*') }
489
- it { should_not match('/hello/+') }
490
- it { should_not match('/hello/,') }
491
- it { should_not match('/hello/;') }
492
- it { should_not match('/hello/=') }
493
- end
494
-
495
- pattern "{&a,b,c}" do
496
- it { should match("&a=~x&b=42&c=_") .capturing a: '~x', b: '42', c: '_' }
497
- it { should match("&a=~x&b&c=_") .capturing a: '~x', b: nil, c: '_' }
498
-
499
- it { should_not match("&a=~x&c=_&b=42").capturing a: '~x', b: '42', c: '_' }
500
-
501
- it { should_not match("&a=~x&b=42") }
502
- it { should_not match("a=~x&b=42") }
503
- it { should_not match("&a=~x&b=#42&c") }
504
- it { should_not match("&a=~x,b=42,c=_") }
505
- it { should_not match("~x&b=42&c=_") }
506
- end
507
- end
508
- end
509
-
510
- context 'level 4' do
511
- context 'without operator' do
512
- context 'prefix' do
513
- pattern '{a:3}/bar' do
514
- it { should match('foo/bar') .capturing a: 'foo' }
515
- it { should match('fo/bar') .capturing a: 'fo' }
516
- it { should match('f/bar') .capturing a: 'f' }
517
- it { should_not match('fooo/bar') }
518
- end
519
-
520
- pattern '{a:3}{b}' do
521
- it { should match('foobar') .capturing a: 'foo', b: 'bar' }
522
- end
523
- end
524
-
525
- context 'expand' do
526
- pattern '{a*}' do
527
- it { should match('a') .capturing a: 'a' }
528
- it { should match('a,b') .capturing a: 'a,b' }
529
- it { should match('a,b,c') .capturing a: 'a,b,c' }
530
- it { should_not match('a,b/c') }
531
- it { should_not match('a,') }
532
-
533
- example { pattern.params('a').should be == { 'a' => ['a'] }}
534
- example { pattern.params('a,b').should be == { 'a' => ['a', 'b'] }}
535
- end
536
-
537
- pattern '{a*},{b}' do
538
- it { should match('a,b') .capturing a: 'a', b: 'b' }
539
- it { should match('a,b,c') .capturing a: 'a,b', b: 'c' }
540
- it { should_not match('a,b/c') }
541
- it { should_not match('a,') }
542
-
543
- example { pattern.params('a,b').should be == { 'a' => ['a'], 'b' => 'b' }}
544
- example { pattern.params('a,b,c').should be == { 'a' => ['a', 'b'], 'b' => 'c' }}
545
- end
546
-
547
- pattern '{a*,b}' do
548
- it { should match('a,b') .capturing a: 'a', b: 'b' }
549
- it { should match('a,b,c') .capturing a: 'a,b', b: 'c' }
550
- it { should_not match('a,b/c') }
551
- it { should_not match('a,') }
552
-
553
- example { pattern.params('a,b').should be == { 'a' => ['a'], 'b' => 'b' }}
554
- example { pattern.params('a,b,c').should be == { 'a' => ['a', 'b'], 'b' => 'c' }}
555
- end
556
- end
557
- end
558
-
559
- context 'operator +' do
560
- context 'prefix' do
561
- pattern '{+a:3}/bar' do
562
- it { should match('foo/bar') .capturing a: 'foo' }
563
- it { should match('fo/bar') .capturing a: 'fo' }
564
- it { should match('f/bar') .capturing a: 'f' }
565
- it { should_not match('fooo/bar') }
566
- end
567
-
568
- pattern '{+a:3}{b}' do
569
- it { should match('foobar') .capturing a: 'foo', b: 'bar' }
570
- end
571
- end
572
-
573
- context 'expand' do
574
- pattern '{+a*}' do
575
- it { should match('a') .capturing a: 'a' }
576
- it { should match('a,b') .capturing a: 'a,b' }
577
- it { should match('a,b,c') .capturing a: 'a,b,c' }
578
- it { should match('a,b/c') .capturing a: 'a,b/c' }
579
- end
580
-
581
- pattern '{+a*},{b}' do
582
- it { should match('a,b') .capturing a: 'a', b: 'b' }
583
- it { should match('a,b,c') .capturing a: 'a,b', b: 'c' }
584
- it { should_not match('a,b/c') }
585
- it { should_not match('a,') }
586
-
587
- example { pattern.params('a,b').should be == { 'a' => ['a'], 'b' => 'b' }}
588
- example { pattern.params('a,b,c').should be == { 'a' => ['a', 'b'], 'b' => 'c' }}
589
- end
590
- end
591
- end
592
-
593
- context 'operator #' do
594
- context 'prefix' do
595
- pattern '{#a:3}/bar' do
596
- it { should match('#foo/bar') .capturing a: 'foo' }
597
- it { should match('#fo/bar') .capturing a: 'fo' }
598
- it { should match('#f/bar') .capturing a: 'f' }
599
- it { should_not match('#fooo/bar') }
600
- end
601
-
602
- pattern '{#a:3}{b}' do
603
- it { should match('#foobar') .capturing a: 'foo', b: 'bar' }
604
- end
605
- end
606
-
607
- context 'expand' do
608
- pattern '{#a*}' do
609
- it { should match('#a') .capturing a: 'a' }
610
- it { should match('#a,b') .capturing a: 'a,b' }
611
- it { should match('#a,b,c') .capturing a: 'a,b,c' }
612
- it { should match('#a,b/c') .capturing a: 'a,b/c' }
613
-
614
- example { pattern.params('#a,b').should be == { 'a' => ['a', 'b'] }}
615
- example { pattern.params('#a,b,c').should be == { 'a' => ['a', 'b', 'c'] }}
616
- end
617
-
618
- pattern '{#a*,b}' do
619
- it { should match('#a,b') .capturing a: 'a', b: 'b' }
620
- it { should match('#a,b,c') .capturing a: 'a,b', b: 'c' }
621
- it { should_not match('#a,') }
622
-
623
- example { pattern.params('#a,b').should be == { 'a' => ['a'], 'b' => 'b' }}
624
- example { pattern.params('#a,b,c').should be == { 'a' => ['a', 'b'], 'b' => 'c' }}
625
- end
626
- end
627
- end
628
-
629
- context 'operator .' do
630
- context 'prefix' do
631
- pattern '{.a:3}/bar' do
632
- it { should match('.foo/bar') .capturing a: 'foo' }
633
- it { should match('.fo/bar') .capturing a: 'fo' }
634
- it { should match('.f/bar') .capturing a: 'f' }
635
- it { should_not match('.fooo/bar') }
636
- end
637
-
638
- pattern '{.a:3}{b}' do
639
- it { should match('.foobar') .capturing a: 'foo', b: 'bar' }
640
- end
641
- end
642
-
643
- context 'expand' do
644
- pattern '{.a*}' do
645
- it { should match('.a') .capturing a: 'a' }
646
- it { should match('.a.b') .capturing a: 'a.b' }
647
- it { should match('.a.b.c') .capturing a: 'a.b.c' }
648
- it { should_not match('.a.b,c') }
649
- it { should_not match('.a,') }
650
- end
651
-
652
- pattern '{.a*,b}' do
653
- it { should match('.a.b') .capturing a: 'a', b: 'b' }
654
- it { should match('.a.b.c') .capturing a: 'a.b', b: 'c' }
655
- it { should_not match('.a.b/c') }
656
- it { should_not match('.a.') }
657
-
658
- example { pattern.params('.a.b').should be == { 'a' => ['a'], 'b' => 'b' }}
659
- example { pattern.params('.a.b.c').should be == { 'a' => ['a', 'b'], 'b' => 'c' }}
660
- end
661
- end
662
- end
663
-
664
- context 'operator /' do
665
- context 'prefix' do
666
- pattern '{/a:3}/bar' do
667
- it { should match('/foo/bar') .capturing a: 'foo' }
668
- it { should match('/fo/bar') .capturing a: 'fo' }
669
- it { should match('/f/bar') .capturing a: 'f' }
670
- it { should_not match('/fooo/bar') }
671
- end
672
-
673
- pattern '{/a:3}{b}' do
674
- it { should match('/foobar') .capturing a: 'foo', b: 'bar' }
675
- end
676
- end
677
-
678
- context 'expand' do
679
- pattern '{/a*}' do
680
- it { should match('/a') .capturing a: 'a' }
681
- it { should match('/a/b') .capturing a: 'a/b' }
682
- it { should match('/a/b/c') .capturing a: 'a/b/c' }
683
- it { should_not match('/a/b,c') }
684
- it { should_not match('/a,') }
685
- end
686
-
687
- pattern '{/a*,b}' do
688
- it { should match('/a/b') .capturing a: 'a', b: 'b' }
689
- it { should match('/a/b/c') .capturing a: 'a/b', b: 'c' }
690
- it { should_not match('/a/b,c') }
691
- it { should_not match('/a/') }
692
-
693
- example { pattern.params('/a/b').should be == { 'a' => ['a'], 'b' => 'b' }}
694
- example { pattern.params('/a/b/c').should be == { 'a' => ['a', 'b'], 'b' => 'c' }}
695
- end
696
- end
697
- end
698
-
699
- context 'operator ;' do
700
- context 'prefix' do
701
- pattern '{;a:3}/bar' do
702
- it { should match(';a=foo/bar') .capturing a: 'foo' }
703
- it { should match(';a=fo/bar') .capturing a: 'fo' }
704
- it { should match(';a=f/bar') .capturing a: 'f' }
705
- it { should_not match(';a=fooo/bar') }
706
- end
707
-
708
- pattern '{;a:3}{b}' do
709
- it { should match(';a=foobar') .capturing a: 'foo', b: 'bar' }
710
- end
711
- end
712
-
713
- context 'expand' do
714
- pattern '{;a*}' do
715
- it { should match(';a=1') .capturing a: 'a=1' }
716
- it { should match(';a=1;a=2') .capturing a: 'a=1;a=2' }
717
- it { should match(';a=1;a=2;a=3') .capturing a: 'a=1;a=2;a=3' }
718
- it { should_not match(';a=1;a=2;b=3') }
719
- it { should_not match(';a=1;a=2;a=3,') }
720
- end
721
-
722
- pattern '{;a*,b}' do
723
- it { should match(';a=1;b') .capturing a: 'a=1', b: nil }
724
- it { should match(';a=2;a=2;b=1') .capturing a: 'a=2;a=2', b: '1' }
725
- it { should_not match(';a;b;c') }
726
- it { should_not match(';a;') }
727
-
728
- example { pattern.params(';a=2;a=2;b').should be == { 'a' => ['2', '2'], 'b' => nil }}
729
- end
730
- end
731
- end
732
-
733
- context 'operator ?' do
734
- context 'prefix' do
735
- pattern '{?a:3}/bar' do
736
- it { should match('?a=foo/bar') .capturing a: 'foo' }
737
- it { should match('?a=fo/bar') .capturing a: 'fo' }
738
- it { should match('?a=f/bar') .capturing a: 'f' }
739
- it { should_not match('?a=fooo/bar') }
740
- end
741
-
742
- pattern '{?a:3}{b}' do
743
- it { should match('?a=foobar') .capturing a: 'foo', b: 'bar' }
744
- end
745
- end
746
-
747
- context 'expand' do
748
- pattern '{?a*}' do
749
- it { should match('?a=1') .capturing a: 'a=1' }
750
- it { should match('?a=1&a=2') .capturing a: 'a=1&a=2' }
751
- it { should match('?a=1&a=2&a=3') .capturing a: 'a=1&a=2&a=3' }
752
- it { should_not match('?a=1&a=2&b=3') }
753
- it { should_not match('?a=1&a=2&a=3,') }
754
- end
755
-
756
- pattern '{?a*,b}' do
757
- it { should match('?a=1&b') .capturing a: 'a=1', b: nil }
758
- it { should match('?a=2&a=2&b=1') .capturing a: 'a=2&a=2', b: '1' }
759
- it { should_not match('?a&b&c') }
760
- it { should_not match('?a&') }
761
-
762
- example { pattern.params('?a=2&a=2&b').should be == { 'a' => ['2', '2'], 'b' => nil }}
763
- end
764
- end
765
- end
766
-
767
- context 'operator &' do
768
- context 'prefix' do
769
- pattern '{&a:3}/bar' do
770
- it { should match('&a=foo/bar') .capturing a: 'foo' }
771
- it { should match('&a=fo/bar') .capturing a: 'fo' }
772
- it { should match('&a=f/bar') .capturing a: 'f' }
773
- it { should_not match('&a=fooo/bar') }
774
- end
775
-
776
- pattern '{&a:3}{b}' do
777
- it { should match('&a=foobar') .capturing a: 'foo', b: 'bar' }
778
- end
779
- end
780
-
781
- context 'expand' do
782
- pattern '{&a*}' do
783
- it { should match('&a=1') .capturing a: 'a=1' }
784
- it { should match('&a=1&a=2') .capturing a: 'a=1&a=2' }
785
- it { should match('&a=1&a=2&a=3') .capturing a: 'a=1&a=2&a=3' }
786
- it { should_not match('&a=1&a=2&b=3') }
787
- it { should_not match('&a=1&a=2&a=3,') }
788
- end
789
-
790
- pattern '{&a*,b}' do
791
- it { should match('&a=1&b') .capturing a: 'a=1', b: nil }
792
- it { should match('&a=2&a=2&b=1') .capturing a: 'a=2&a=2', b: '1' }
793
- it { should_not match('&a&b&c') }
794
- it { should_not match('&a&') }
795
-
796
- example { pattern.params('&a=2&a=2&b').should be == { 'a' => ['2', '2'], 'b' => nil }}
797
- example { pattern.params('&a=2&a=%20&b').should be == { 'a' => ['2', ' '], 'b' => nil }}
798
- end
799
- end
800
- end
801
- end
802
-
803
- context 'invalid syntax' do
804
- example 'unexpected closing bracket' do
805
- expect { Mustermann::Template.new('foo}bar') }.
806
- to raise_error(Mustermann::ParseError, 'unexpected } while parsing "foo}bar"')
807
- end
808
-
809
- example 'missing closing bracket' do
810
- expect { Mustermann::Template.new('foo{bar') }.
811
- to raise_error(Mustermann::ParseError, 'unexpected end of string while parsing "foo{bar"')
812
- end
813
- end
814
- end