mustermann 0.0.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.
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.test_queue_stats +0 -0
- data/.travis.yml +6 -0
- data/Gemfile +2 -0
- data/LICENSE +22 -0
- data/README.md +644 -0
- data/Rakefile +3 -0
- data/bench/capturing.rb +24 -0
- data/bench/simple_vs_sinatra.rb +23 -0
- data/bench/template_vs_addressable.rb +23 -0
- data/lib/mustermann.rb +40 -0
- data/lib/mustermann/ast.rb +403 -0
- data/lib/mustermann/error.rb +14 -0
- data/lib/mustermann/extension.rb +52 -0
- data/lib/mustermann/identity.rb +19 -0
- data/lib/mustermann/pattern.rb +142 -0
- data/lib/mustermann/rails.rb +26 -0
- data/lib/mustermann/regexp_based.rb +30 -0
- data/lib/mustermann/shell.rb +22 -0
- data/lib/mustermann/simple.rb +35 -0
- data/lib/mustermann/simple_match.rb +30 -0
- data/lib/mustermann/sinatra.rb +32 -0
- data/lib/mustermann/template.rb +140 -0
- data/lib/mustermann/version.rb +3 -0
- data/mustermann.gemspec +28 -0
- data/spec/ast_spec.rb +8 -0
- data/spec/extension_spec.rb +153 -0
- data/spec/identity_spec.rb +82 -0
- data/spec/mustermann_spec.rb +0 -0
- data/spec/pattern_spec.rb +16 -0
- data/spec/rails_spec.rb +453 -0
- data/spec/regexp_based_spec.rb +8 -0
- data/spec/shell_spec.rb +108 -0
- data/spec/simple_match_spec.rb +10 -0
- data/spec/simple_spec.rb +236 -0
- data/spec/sinatra_spec.rb +554 -0
- data/spec/support.rb +78 -0
- data/spec/template_spec.rb +814 -0
- metadata +227 -0
data/spec/support.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
ENV['RACK_ENV'] = 'test'
|
2
|
+
|
3
|
+
require 'simplecov'
|
4
|
+
require 'coveralls'
|
5
|
+
|
6
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
7
|
+
SimpleCov::Formatter::HTMLFormatter,
|
8
|
+
Coveralls::SimpleCov::Formatter
|
9
|
+
]
|
10
|
+
|
11
|
+
SimpleCov.start do
|
12
|
+
project_name 'mustermann'
|
13
|
+
minimum_coverage 100
|
14
|
+
|
15
|
+
add_filter "/spec/"
|
16
|
+
add_group 'Library', 'lib'
|
17
|
+
end
|
18
|
+
|
19
|
+
RSpec::Matchers.define :match do |expected|
|
20
|
+
match do |actual|
|
21
|
+
@captures ||= false
|
22
|
+
match = actual.match(expected)
|
23
|
+
match &&= @captures.all? { |k, v| match[k] == v } if @captures
|
24
|
+
match
|
25
|
+
end
|
26
|
+
|
27
|
+
chain :capturing do |captures|
|
28
|
+
@captures = captures
|
29
|
+
end
|
30
|
+
|
31
|
+
failure_message_for_should do |actual|
|
32
|
+
require 'pp'
|
33
|
+
match = actual.match(expected)
|
34
|
+
if match
|
35
|
+
key, value = @captures.detect { |k, v| match[k] != v }
|
36
|
+
"expected %p to capture %p as %p when matching %p, but got %p\n\nRegular Expression:\n%p" % [
|
37
|
+
actual.to_s, key, value, expected, match[key], actual.regexp
|
38
|
+
]
|
39
|
+
else
|
40
|
+
"expected %p to match %p" % [ actual, expected ]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
failure_message_for_should_not do |actual|
|
45
|
+
"expected %p not to match %p" % [
|
46
|
+
actual.to_s, expected
|
47
|
+
]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
module Support
|
52
|
+
module Pattern
|
53
|
+
def pattern(pattern, options = nil, &block)
|
54
|
+
description = "pattern %p" % pattern
|
55
|
+
|
56
|
+
if options
|
57
|
+
description << " with options %p" % options
|
58
|
+
instance = described_class.new(pattern, options)
|
59
|
+
else
|
60
|
+
instance = described_class.new(pattern)
|
61
|
+
end
|
62
|
+
|
63
|
+
context description do
|
64
|
+
subject(:pattern) { instance }
|
65
|
+
its(:to_s) { should be == pattern }
|
66
|
+
its(:inspect) { should be == "#<#{described_class}:#{pattern.inspect}>" }
|
67
|
+
its(:names) { should be_an(Array) }
|
68
|
+
|
69
|
+
example 'string should be immune to external change' do
|
70
|
+
subject.to_s.replace "NOT THE PATTERN"
|
71
|
+
subject.to_s.should be == pattern
|
72
|
+
end
|
73
|
+
|
74
|
+
instance_eval(&block)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,814 @@
|
|
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
|