addressable 2.3.2 → 2.9.0

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.
@@ -1,1001 +0,0 @@
1
- require "addressable/template"
2
-
3
- shared_examples_for 'expands' do |tests|
4
- tests.each do |template, expansion|
5
- exp = expansion.is_a?(Array) ? expansion.first : expansion
6
- it "#{template} to #{exp}" do
7
- tmpl = Addressable::Template.new(template).expand(subject)
8
- if expansion.is_a?(Array)
9
- expansion.any?{|i| i == tmpl.to_str}.should be_true
10
- else
11
- tmpl.to_str.should == expansion
12
- end
13
- end
14
- end
15
- end
16
-
17
- describe "Level 1:" do
18
- subject{
19
- {:var => "value", :hello => "Hello World!"}
20
- }
21
- it_behaves_like 'expands', {
22
- '{var}' => 'value',
23
- '{hello}' => 'Hello%20World%21'
24
- }
25
- end
26
-
27
- describe "Level 2" do
28
- subject{
29
- {
30
- :var => "value",
31
- :hello => "Hello World!",
32
- :path => "/foo/bar"
33
- }
34
- }
35
- context "Operator +:" do
36
- it_behaves_like 'expands', {
37
- '{+var}' => 'value',
38
- '{+hello}' => 'Hello%20World!',
39
- '{+path}/here' => '/foo/bar/here',
40
- 'here?ref={+path}' => 'here?ref=/foo/bar'
41
- }
42
- end
43
- context "Operator #:" do
44
- it_behaves_like 'expands', {
45
- 'X{#var}' => 'X#value',
46
- 'X{#hello}' => 'X#Hello%20World!'
47
- }
48
- end
49
- end
50
-
51
- describe "Level 3" do
52
- subject{
53
- {
54
- :var => "value",
55
- :hello => "Hello World!",
56
- :empty => "",
57
- :path => "/foo/bar",
58
- :x => "1024",
59
- :y => "768"
60
- }
61
- }
62
- context "Operator nil (multiple vars):" do
63
- it_behaves_like 'expands', {
64
- 'map?{x,y}' => 'map?1024,768',
65
- '{x,hello,y}' => '1024,Hello%20World%21,768'
66
- }
67
- end
68
- context "Operator + (multiple vars):" do
69
- it_behaves_like 'expands', {
70
- '{+x,hello,y}' => '1024,Hello%20World!,768',
71
- '{+path,x}/here' => '/foo/bar,1024/here'
72
- }
73
- end
74
- context "Operator # (multiple vars):" do
75
- it_behaves_like 'expands', {
76
- '{#x,hello,y}' => '#1024,Hello%20World!,768',
77
- '{#path,x}/here' => '#/foo/bar,1024/here'
78
- }
79
- end
80
- context "Operator ." do
81
- it_behaves_like 'expands', {
82
- 'X{.var}' => 'X.value',
83
- 'X{.x,y}' => 'X.1024.768'
84
- }
85
- end
86
- context "Operator /" do
87
- it_behaves_like 'expands', {
88
- '{/var}' => '/value',
89
- '{/var,x}/here' => '/value/1024/here'
90
- }
91
- end
92
- context "Operator ;" do
93
- it_behaves_like 'expands', {
94
- '{;x,y}' => ';x=1024;y=768',
95
- '{;x,y,empty}' => ';x=1024;y=768;empty'
96
- }
97
- end
98
- context "Operator ?" do
99
- it_behaves_like 'expands', {
100
- '{?x,y}' => '?x=1024&y=768',
101
- '{?x,y,empty}' => '?x=1024&y=768&empty='
102
- }
103
- end
104
- context "Operator &" do
105
- it_behaves_like 'expands', {
106
- '?fixed=yes{&x}' => '?fixed=yes&x=1024',
107
- '{&x,y,empty}' => '&x=1024&y=768&empty='
108
- }
109
- end
110
- end
111
-
112
- describe "Level 4" do
113
- subject{
114
- {
115
- :var => "value",
116
- :hello => "Hello World!",
117
- :path => "/foo/bar",
118
- :semi => ";",
119
- :list => %w(red green blue),
120
- :keys => {"semi" => ';', "dot" => '.', "comma" => ','}
121
- }
122
- }
123
- context "Expansion with value modifiers" do
124
- it_behaves_like 'expands', {
125
- '{var:3}' => 'val',
126
- '{var:30}' => 'value',
127
- '{list}' => 'red,green,blue',
128
- '{list*}' => 'red,green,blue',
129
- '{keys}' => [
130
- 'semi,%3B,dot,.,comma,%2C',
131
- 'dot,.,semi,%3B,comma,%2C',
132
- 'comma,%2C,semi,%3B,dot,.',
133
- 'semi,%3B,comma,%2C,dot,.',
134
- 'dot,.,comma,%2C,semi,%3B',
135
- 'comma,%2C,dot,.,semi,%3B'
136
- ],
137
- '{keys*}' => [
138
- 'semi=%3B,dot=.,comma=%2C',
139
- 'dot=.,semi=%3B,comma=%2C',
140
- 'comma=%2C,semi=%3B,dot=.',
141
- 'semi=%3B,comma=%2C,dot=.',
142
- 'dot=.,comma=%2C,semi=%3B',
143
- 'comma=%2C,dot=.,semi=%3B'
144
- ]
145
- }
146
- end
147
- context "Operator + with value modifiers" do
148
- it_behaves_like 'expands', {
149
- '{+path:6}/here' => '/foo/b/here',
150
- '{+list}' => 'red,green,blue',
151
- '{+list*}' => 'red,green,blue',
152
- '{+keys}' => [
153
- 'semi,;,dot,.,comma,,',
154
- 'dot,.,semi,;,comma,,',
155
- 'comma,,,semi,;,dot,.',
156
- 'semi,;,comma,,,dot,.',
157
- 'dot,.,comma,,,semi,;',
158
- 'comma,,,dot,.,semi,;'
159
- ],
160
- '{+keys*}' => [
161
- 'semi=;,dot=.,comma=,',
162
- 'dot=.,semi=;,comma=,',
163
- 'comma=,,semi=;,dot=.',
164
- 'semi=;,comma=,,dot=.',
165
- 'dot=.,comma=,,semi=;',
166
- 'comma=,,dot=.,semi=;'
167
- ]
168
- }
169
- end
170
- context "Operator # with value modifiers" do
171
- it_behaves_like 'expands', {
172
- '{#path:6}/here' => '#/foo/b/here',
173
- '{#list}' => '#red,green,blue',
174
- '{#list*}' => '#red,green,blue',
175
- '{#keys}' => [
176
- '#semi,;,dot,.,comma,,',
177
- '#dot,.,semi,;,comma,,',
178
- '#comma,,,semi,;,dot,.',
179
- '#semi,;,comma,,,dot,.',
180
- '#dot,.,comma,,,semi,;',
181
- '#comma,,,dot,.,semi,;'
182
- ],
183
- '{#keys*}' => [
184
- '#semi=;,dot=.,comma=,',
185
- '#dot=.,semi=;,comma=,',
186
- '#comma=,,semi=;,dot=.',
187
- '#semi=;,comma=,,dot=.',
188
- '#dot=.,comma=,,semi=;',
189
- '#comma=,,dot=.,semi=;'
190
- ]
191
- }
192
- end
193
- context "Operator . with value modifiers" do
194
- it_behaves_like 'expands', {
195
- 'X{.var:3}' => 'X.val',
196
- 'X{.list}' => 'X.red,green,blue',
197
- 'X{.list*}' => 'X.red.green.blue',
198
- 'X{.keys}' => [
199
- 'X.semi,%3B,dot,.,comma,%2C',
200
- 'X.dot,.,semi,%3B,comma,%2C',
201
- 'X.comma,%2C,semi,%3B,dot,.',
202
- 'X.semi,%3B,comma,%2C,dot,.',
203
- 'X.dot,.,comma,%2C,semi,%3B',
204
- 'X.comma,%2C,dot,.,semi,%3B'
205
- ],
206
- 'X{.keys*}' => [
207
- 'X.semi=%3B.dot=..comma=%2C',
208
- 'X.dot=..semi=%3B.comma=%2C',
209
- 'X.comma=%2C.semi=%3B.dot=.',
210
- 'X.semi=%3B.comma=%2C.dot=.',
211
- 'X.dot=..comma=%2C.semi=%3B',
212
- 'X.comma=%2C.dot=..semi=%3B'
213
- ]
214
- }
215
- end
216
- context "Operator / with value modifiers" do
217
- it_behaves_like 'expands', {
218
- '{/var:1,var}' => '/v/value',
219
- '{/list}' => '/red,green,blue',
220
- '{/list*}' => '/red/green/blue',
221
- '{/list*,path:4}' => '/red/green/blue/%2Ffoo',
222
- '{/keys}' => [
223
- '/semi,%3B,dot,.,comma,%2C',
224
- '/dot,.,semi,%3B,comma,%2C',
225
- '/comma,%2C,semi,%3B,dot,.',
226
- '/semi,%3B,comma,%2C,dot,.',
227
- '/dot,.,comma,%2C,semi,%3B',
228
- '/comma,%2C,dot,.,semi,%3B'
229
- ],
230
- '{/keys*}' => [
231
- '/semi=%3B/dot=./comma=%2C',
232
- '/dot=./semi=%3B/comma=%2C',
233
- '/comma=%2C/semi=%3B/dot=.',
234
- '/semi=%3B/comma=%2C/dot=.',
235
- '/dot=./comma=%2C/semi=%3B',
236
- '/comma=%2C/dot=./semi=%3B'
237
- ]
238
- }
239
- end
240
- context "Operator ; with value modifiers" do
241
- it_behaves_like 'expands', {
242
- '{;hello:5}' => ';hello=Hello',
243
- '{;list}' => ';list=red,green,blue',
244
- '{;list*}' => ';list=red;list=green;list=blue',
245
- '{;keys}' => [
246
- ';keys=semi,%3B,dot,.,comma,%2C',
247
- ';keys=dot,.,semi,%3B,comma,%2C',
248
- ';keys=comma,%2C,semi,%3B,dot,.',
249
- ';keys=semi,%3B,comma,%2C,dot,.',
250
- ';keys=dot,.,comma,%2C,semi,%3B',
251
- ';keys=comma,%2C,dot,.,semi,%3B'
252
- ],
253
- '{;keys*}' => [
254
- ';semi=%3B;dot=.;comma=%2C',
255
- ';dot=.;semi=%3B;comma=%2C',
256
- ';comma=%2C;semi=%3B;dot=.',
257
- ';semi=%3B;comma=%2C;dot=.',
258
- ';dot=.;comma=%2C;semi=%3B',
259
- ';comma=%2C;dot=.;semi=%3B'
260
- ]
261
- }
262
- end
263
- context "Operator ? with value modifiers" do
264
- it_behaves_like 'expands', {
265
- '{?var:3}' => '?var=val',
266
- '{?list}' => '?list=red,green,blue',
267
- '{?list*}' => '?list=red&list=green&list=blue',
268
- '{?keys}' => [
269
- '?keys=semi,%3B,dot,.,comma,%2C',
270
- '?keys=dot,.,semi,%3B,comma,%2C',
271
- '?keys=comma,%2C,semi,%3B,dot,.',
272
- '?keys=semi,%3B,comma,%2C,dot,.',
273
- '?keys=dot,.,comma,%2C,semi,%3B',
274
- '?keys=comma,%2C,dot,.,semi,%3B'
275
- ],
276
- '{?keys*}' => [
277
- '?semi=%3B&dot=.&comma=%2C',
278
- '?dot=.&semi=%3B&comma=%2C',
279
- '?comma=%2C&semi=%3B&dot=.',
280
- '?semi=%3B&comma=%2C&dot=.',
281
- '?dot=.&comma=%2C&semi=%3B',
282
- '?comma=%2C&dot=.&semi=%3B'
283
- ]
284
- }
285
- end
286
- context "Operator & with value modifiers" do
287
- it_behaves_like 'expands', {
288
- '{&var:3}' => '&var=val',
289
- '{&list}' => '&list=red,green,blue',
290
- '{&list*}' => '&list=red&list=green&list=blue',
291
- '{&keys}' => [
292
- '&keys=semi,%3B,dot,.,comma,%2C',
293
- '&keys=dot,.,semi,%3B,comma,%2C',
294
- '&keys=comma,%2C,semi,%3B,dot,.',
295
- '&keys=semi,%3B,comma,%2C,dot,.',
296
- '&keys=dot,.,comma,%2C,semi,%3B',
297
- '&keys=comma,%2C,dot,.,semi,%3B'
298
- ],
299
- '{&keys*}' => [
300
- '&semi=%3B&dot=.&comma=%2C',
301
- '&dot=.&semi=%3B&comma=%2C',
302
- '&comma=%2C&semi=%3B&dot=.',
303
- '&semi=%3B&comma=%2C&dot=.',
304
- '&dot=.&comma=%2C&semi=%3B',
305
- '&comma=%2C&dot=.&semi=%3B'
306
- ]
307
- }
308
- end
309
- end
310
- describe "Modifiers" do
311
- subject{
312
- {
313
- :var => "value",
314
- :semi => ";",
315
- :year => %w(1965 2000 2012),
316
- :dom => %w(example com)
317
- }
318
- }
319
- context "length" do
320
- it_behaves_like 'expands', {
321
- '{var:3}' => 'val',
322
- '{var:30}' => 'value',
323
- '{var}' => 'value',
324
- '{semi}' => '%3B',
325
- '{semi:2}' => '%3B'
326
- }
327
- end
328
- context "explode" do
329
- it_behaves_like 'expands', {
330
- 'find{?year*}' => 'find?year=1965&year=2000&year=2012',
331
- 'www{.dom*}' => 'www.example.com',
332
- }
333
- end
334
- end
335
- describe "Expansion" do
336
- subject{
337
- {
338
- :count => ["one", "two", "three"],
339
- :dom => ["example", "com"],
340
- :dub => "me/too",
341
- :hello => "Hello World!",
342
- :half => "50%",
343
- :var => "value",
344
- :who => "fred",
345
- :base => "http://example.com/home/",
346
- :path => "/foo/bar",
347
- :list => ["red", "green", "blue"],
348
- :keys => {"semi" => ";","dot" => ".","comma" => ","},
349
- :v => "6",
350
- :x => "1024",
351
- :y => "768",
352
- :empty => "",
353
- :empty_keys => {},
354
- :undef => nil
355
- }
356
- }
357
- context "concatenation" do
358
- it_behaves_like 'expands', {
359
- '{count}' => 'one,two,three',
360
- '{count*}' => 'one,two,three',
361
- '{/count}' => '/one,two,three',
362
- '{/count*}' => '/one/two/three',
363
- '{;count}' => ';count=one,two,three',
364
- '{;count*}' => ';count=one;count=two;count=three',
365
- '{?count}' => '?count=one,two,three',
366
- '{?count*}' => '?count=one&count=two&count=three',
367
- '{&count*}' => '&count=one&count=two&count=three'
368
- }
369
- end
370
- context "simple expansion" do
371
- it_behaves_like 'expands', {
372
- '{var}' => 'value',
373
- '{hello}' => 'Hello%20World%21',
374
- '{half}' => '50%25',
375
- 'O{empty}X' => 'OX',
376
- 'O{undef}X' => 'OX',
377
- '{x,y}' => '1024,768',
378
- '{x,hello,y}' => '1024,Hello%20World%21,768',
379
- '?{x,empty}' => '?1024,',
380
- '?{x,undef}' => '?1024',
381
- '?{undef,y}' => '?768',
382
- '{var:3}' => 'val',
383
- '{var:30}' => 'value',
384
- '{list}' => 'red,green,blue',
385
- '{list*}' => 'red,green,blue',
386
- '{keys}' => [
387
- 'semi,%3B,dot,.,comma,%2C',
388
- 'dot,.,semi,%3B,comma,%2C',
389
- 'comma,%2C,semi,%3B,dot,.',
390
- 'semi,%3B,comma,%2C,dot,.',
391
- 'dot,.,comma,%2C,semi,%3B',
392
- 'comma,%2C,dot,.,semi,%3B'
393
- ],
394
- '{keys*}' => [
395
- 'semi=%3B,dot=.,comma=%2C',
396
- 'dot=.,semi=%3B,comma=%2C',
397
- 'comma=%2C,semi=%3B,dot=.',
398
- 'semi=%3B,comma=%2C,dot=.',
399
- 'dot=.,comma=%2C,semi=%3B',
400
- 'comma=%2C,dot=.,semi=%3B'
401
- ]
402
- }
403
- end
404
- context "reserved expansion (+)" do
405
- it_behaves_like 'expands', {
406
- '{+var}' => 'value',
407
- '{+hello}' => 'Hello%20World!',
408
- '{+half}' => '50%25',
409
- '{base}index' => 'http%3A%2F%2Fexample.com%2Fhome%2Findex',
410
- '{+base}index' => 'http://example.com/home/index',
411
- 'O{+empty}X' => 'OX',
412
- 'O{+undef}X' => 'OX',
413
- '{+path}/here' => '/foo/bar/here',
414
- 'here?ref={+path}' => 'here?ref=/foo/bar',
415
- 'up{+path}{var}/here' => 'up/foo/barvalue/here',
416
- '{+x,hello,y}' => '1024,Hello%20World!,768',
417
- '{+path,x}/here' => '/foo/bar,1024/here',
418
- '{+path:6}/here' => '/foo/b/here',
419
- '{+list}' => 'red,green,blue',
420
- '{+list*}' => 'red,green,blue',
421
- '{+keys}' => [
422
- 'semi,;,dot,.,comma,,',
423
- 'dot,.,semi,;,comma,,',
424
- 'comma,,,semi,;,dot,.',
425
- 'semi,;,comma,,,dot,.',
426
- 'dot,.,comma,,,semi,;',
427
- 'comma,,,dot,.,semi,;'
428
- ],
429
- '{+keys*}' => [
430
- 'semi=;,dot=.,comma=,',
431
- 'dot=.,semi=;,comma=,',
432
- 'comma=,,semi=;,dot=.',
433
- 'semi=;,comma=,,dot=.',
434
- 'dot=.,comma=,,semi=;',
435
- 'comma=,,dot=.,semi=;'
436
- ]
437
- }
438
- end
439
- context "fragment expansion (#)" do
440
- it_behaves_like 'expands', {
441
- '{#var}' => '#value',
442
- '{#hello}' => '#Hello%20World!',
443
- '{#half}' => '#50%25',
444
- 'foo{#empty}' => 'foo#',
445
- 'foo{#undef}' => 'foo',
446
- '{#x,hello,y}' => '#1024,Hello%20World!,768',
447
- '{#path,x}/here' => '#/foo/bar,1024/here',
448
- '{#path:6}/here' => '#/foo/b/here',
449
- '{#list}' => '#red,green,blue',
450
- '{#list*}' => '#red,green,blue',
451
- '{#keys}' => [
452
- '#semi,;,dot,.,comma,,',
453
- '#dot,.,semi,;,comma,,',
454
- '#comma,,,semi,;,dot,.',
455
- '#semi,;,comma,,,dot,.',
456
- '#dot,.,comma,,,semi,;',
457
- '#comma,,,dot,.,semi,;'
458
- ],
459
- '{#keys*}' => [
460
- '#semi=;,dot=.,comma=,',
461
- '#dot=.,semi=;,comma=,',
462
- '#comma=,,semi=;,dot=.',
463
- '#semi=;,comma=,,dot=.',
464
- '#dot=.,comma=,,semi=;',
465
- '#comma=,,dot=.,semi=;'
466
- ]
467
- }
468
- end
469
- context "label expansion (.)" do
470
- it_behaves_like 'expands', {
471
- '{.who}' => '.fred',
472
- '{.who,who}' => '.fred.fred',
473
- '{.half,who}' => '.50%25.fred',
474
- 'www{.dom*}' => 'www.example.com',
475
- 'X{.var}' => 'X.value',
476
- 'X{.empty}' => 'X.',
477
- 'X{.undef}' => 'X',
478
- 'X{.var:3}' => 'X.val',
479
- 'X{.list}' => 'X.red,green,blue',
480
- 'X{.list*}' => 'X.red.green.blue',
481
- 'X{.keys}' => [
482
- 'X.semi,%3B,dot,.,comma,%2C',
483
- 'X.dot,.,semi,%3B,comma,%2C',
484
- 'X.comma,%2C,semi,%3B,dot,.',
485
- 'X.semi,%3B,comma,%2C,dot,.',
486
- 'X.dot,.,comma,%2C,semi,%3B',
487
- 'X.comma,%2C,dot,.,semi,%3B'
488
- ],
489
- 'X{.keys*}' => [
490
- 'X.semi=%3B.dot=..comma=%2C',
491
- 'X.dot=..semi=%3B.comma=%2C',
492
- 'X.comma=%2C.semi=%3B.dot=.',
493
- 'X.semi=%3B.comma=%2C.dot=.',
494
- 'X.dot=..comma=%2C.semi=%3B',
495
- 'X.comma=%2C.dot=..semi=%3B'
496
- ],
497
- 'X{.empty_keys}' => 'X',
498
- 'X{.empty_keys*}' => 'X'
499
- }
500
- end
501
- context "path expansion (/)" do
502
- it_behaves_like 'expands', {
503
- '{/who}' => '/fred',
504
- '{/who,who}' => '/fred/fred',
505
- '{/half,who}' => '/50%25/fred',
506
- '{/who,dub}' => '/fred/me%2Ftoo',
507
- '{/var}' => '/value',
508
- '{/var,empty}' => '/value/',
509
- '{/var,undef}' => '/value',
510
- '{/var,x}/here' => '/value/1024/here',
511
- '{/var:1,var}' => '/v/value',
512
- '{/list}' => '/red,green,blue',
513
- '{/list*}' => '/red/green/blue',
514
- '{/list*,path:4}' => '/red/green/blue/%2Ffoo',
515
- '{/keys}' => [
516
- '/semi,%3B,dot,.,comma,%2C',
517
- '/dot,.,semi,%3B,comma,%2C',
518
- '/comma,%2C,semi,%3B,dot,.',
519
- '/semi,%3B,comma,%2C,dot,.',
520
- '/dot,.,comma,%2C,semi,%3B',
521
- '/comma,%2C,dot,.,semi,%3B'
522
- ],
523
- '{/keys*}' => [
524
- '/semi=%3B/dot=./comma=%2C',
525
- '/dot=./semi=%3B/comma=%2C',
526
- '/comma=%2C/semi=%3B/dot=.',
527
- '/semi=%3B/comma=%2C/dot=.',
528
- '/dot=./comma=%2C/semi=%3B',
529
- '/comma=%2C/dot=./semi=%3B'
530
- ]
531
- }
532
- end
533
- context "path-style expansion (;)" do
534
- it_behaves_like 'expands', {
535
- '{;who}' => ';who=fred',
536
- '{;half}' => ';half=50%25',
537
- '{;empty}' => ';empty',
538
- '{;v,empty,who}' => ';v=6;empty;who=fred',
539
- '{;v,bar,who}' => ';v=6;who=fred',
540
- '{;x,y}' => ';x=1024;y=768',
541
- '{;x,y,empty}' => ';x=1024;y=768;empty',
542
- '{;x,y,undef}' => ';x=1024;y=768',
543
- '{;hello:5}' => ';hello=Hello',
544
- '{;list}' => ';list=red,green,blue',
545
- '{;list*}' => ';list=red;list=green;list=blue',
546
- '{;keys}' => [
547
- ';keys=semi,%3B,dot,.,comma,%2C',
548
- ';keys=dot,.,semi,%3B,comma,%2C',
549
- ';keys=comma,%2C,semi,%3B,dot,.',
550
- ';keys=semi,%3B,comma,%2C,dot,.',
551
- ';keys=dot,.,comma,%2C,semi,%3B',
552
- ';keys=comma,%2C,dot,.,semi,%3B'
553
- ],
554
- '{;keys*}' => [
555
- ';semi=%3B;dot=.;comma=%2C',
556
- ';dot=.;semi=%3B;comma=%2C',
557
- ';comma=%2C;semi=%3B;dot=.',
558
- ';semi=%3B;comma=%2C;dot=.',
559
- ';dot=.;comma=%2C;semi=%3B',
560
- ';comma=%2C;dot=.;semi=%3B'
561
- ]
562
- }
563
- end
564
- context "form query expansion (?)" do
565
- it_behaves_like 'expands', {
566
- '{?who}' => '?who=fred',
567
- '{?half}' => '?half=50%25',
568
- '{?x,y}' => '?x=1024&y=768',
569
- '{?x,y,empty}' => '?x=1024&y=768&empty=',
570
- '{?x,y,undef}' => '?x=1024&y=768',
571
- '{?var:3}' => '?var=val',
572
- '{?list}' => '?list=red,green,blue',
573
- '{?list*}' => '?list=red&list=green&list=blue',
574
- '{?keys}' => [
575
- '?keys=semi,%3B,dot,.,comma,%2C',
576
- '?keys=dot,.,semi,%3B,comma,%2C',
577
- '?keys=comma,%2C,semi,%3B,dot,.',
578
- '?keys=semi,%3B,comma,%2C,dot,.',
579
- '?keys=dot,.,comma,%2C,semi,%3B',
580
- '?keys=comma,%2C,dot,.,semi,%3B'
581
- ],
582
- '{?keys*}' => [
583
- '?semi=%3B&dot=.&comma=%2C',
584
- '?dot=.&semi=%3B&comma=%2C',
585
- '?comma=%2C&semi=%3B&dot=.',
586
- '?semi=%3B&comma=%2C&dot=.',
587
- '?dot=.&comma=%2C&semi=%3B',
588
- '?comma=%2C&dot=.&semi=%3B'
589
- ]
590
- }
591
- end
592
- context "form query expansion (&)" do
593
- it_behaves_like 'expands', {
594
- '{&who}' => '&who=fred',
595
- '{&half}' => '&half=50%25',
596
- '?fixed=yes{&x}' => '?fixed=yes&x=1024',
597
- '{&x,y,empty}' => '&x=1024&y=768&empty=',
598
- '{&x,y,undef}' => '&x=1024&y=768',
599
- '{&var:3}' => '&var=val',
600
- '{&list}' => '&list=red,green,blue',
601
- '{&list*}' => '&list=red&list=green&list=blue',
602
- '{&keys}' => [
603
- '&keys=semi,%3B,dot,.,comma,%2C',
604
- '&keys=dot,.,semi,%3B,comma,%2C',
605
- '&keys=comma,%2C,semi,%3B,dot,.',
606
- '&keys=semi,%3B,comma,%2C,dot,.',
607
- '&keys=dot,.,comma,%2C,semi,%3B',
608
- '&keys=comma,%2C,dot,.,semi,%3B'
609
- ],
610
- '{&keys*}' => [
611
- '&semi=%3B&dot=.&comma=%2C',
612
- '&dot=.&semi=%3B&comma=%2C',
613
- '&comma=%2C&semi=%3B&dot=.',
614
- '&semi=%3B&comma=%2C&dot=.',
615
- '&dot=.&comma=%2C&semi=%3B',
616
- '&comma=%2C&dot=.&semi=%3B'
617
- ]
618
- }
619
- end
620
- end
621
-
622
- class ExampleTwoProcessor
623
- def self.restore(name, value)
624
- return value.gsub(/-/, " ") if name == "query"
625
- return value
626
- end
627
-
628
- def self.match(name)
629
- return ".*?" if name == "first"
630
- return ".*"
631
- end
632
- def self.validate(name, value)
633
- return !!(value =~ /^[\w ]+$/) if name == "query"
634
- return true
635
- end
636
-
637
- def self.transform(name, value)
638
- return value.gsub(/ /, "+") if name == "query"
639
- return value
640
- end
641
- end
642
-
643
-
644
- describe Addressable::Template do
645
- describe "Matching" do
646
- let(:uri){
647
- Addressable::URI.parse(
648
- "http://example.com/search/an-example-search-query/"
649
- )
650
- }
651
- let(:uri2){
652
- Addressable::URI.parse("http://example.com/a/b/c/")
653
- }
654
- let(:uri3){
655
- Addressable::URI.parse("http://example.com/;a=1;b=2;c=3;first=foo")
656
- }
657
- let(:uri4){
658
- Addressable::URI.parse("http://example.com/?a=1&b=2&c=3&first=foo")
659
- }
660
- context "first uri with ExampleTwoProcessor" do
661
- subject{
662
- match = Addressable::Template.new(
663
- "http://example.com/search/{query}/"
664
- ).match(uri, ExampleTwoProcessor)
665
- }
666
- its(:variables){ should == ["query"]}
667
- its(:captures){ should == ["an example search query"]}
668
- end
669
-
670
- context "second uri with ExampleTwoProcessor" do
671
- subject{
672
- match = Addressable::Template.new(
673
- "http://example.com/{first}/{+second}/"
674
- ).match(uri2, ExampleTwoProcessor)
675
- }
676
- its(:variables){ should == ["first", "second"]}
677
- its(:captures){ should == ["a", "b/c"] }
678
- end
679
- context "second uri" do
680
- subject{
681
- match = Addressable::Template.new(
682
- "http://example.com/{first}{/second*}/"
683
- ).match(uri2)
684
- }
685
- its(:variables){ should == ["first", "second"]}
686
- its(:captures){ should == ["a", ["b","c"]] }
687
- end
688
- context "third uri" do
689
- subject{
690
- match = Addressable::Template.new(
691
- "http://example.com/{;hash*,first}"
692
- ).match(uri3)
693
- }
694
- its(:variables){ should == ["hash", "first"]}
695
- its(:captures){ should == [
696
- {"a" => "1", "b" => "2", "c" => "3", "first" => "foo"}, nil] }
697
- end
698
- context "fourth uri" do
699
- subject{
700
- match = Addressable::Template.new(
701
- "http://example.com/{?hash*,first}"
702
- ).match(uri4)
703
- }
704
- its(:variables){ should == ["hash", "first"]}
705
- its(:captures){ should == [
706
- {"a" => "1", "b" => "2", "c" => "3", "first"=> "foo"}, nil] }
707
- end
708
- end
709
- describe "extract" do
710
- let(:template) {
711
- Addressable::Template.new(
712
- "http://{host}{/segments*}/{?one,two,bogus}{#fragment}"
713
- )
714
- }
715
- let(:uri){ "http://example.com/a/b/c/?one=1&two=2#foo" }
716
- it "should be able to extract" do
717
- template.extract(uri).should == {
718
- "host" => "example.com",
719
- "segments" => %w(a b c),
720
- "one" => "1",
721
- "bogus" => nil,
722
- "two" => "2",
723
- "fragment" => "foo"
724
- }
725
- end
726
- end
727
- describe "Partial expand" do
728
- context "partial_expand with two simple values" do
729
- subject{
730
- Addressable::Template.new("http://example.com/{one}/{two}/")
731
- }
732
- it "builds a new pattern" do
733
- subject.partial_expand("one" => "1").pattern.should ==
734
- "http://example.com/1/{two}/"
735
- end
736
- end
737
- context "partial_expand query with missing param in middle" do
738
- subject{
739
- Addressable::Template.new("http://example.com/{?one,two,three}/")
740
- }
741
- it "builds a new pattern" do
742
- subject.partial_expand("one" => "1", "three" => "3").pattern.should ==
743
- "http://example.com/?one=1{&two}&three=3/"
744
- end
745
- end
746
- context "partial_expand with query string" do
747
- subject{
748
- Addressable::Template.new("http://example.com/{?two,one}/")
749
- }
750
- it "builds a new pattern" do
751
- subject.partial_expand("one" => "1").pattern.should ==
752
- "http://example.com/{?two}&one=1/"
753
- end
754
- end
755
- context "partial_expand with path operator" do
756
- subject{
757
- Addressable::Template.new("http://example.com{/one,two}/")
758
- }
759
- it "builds a new pattern" do
760
- subject.partial_expand("one" => "1").pattern.should ==
761
- "http://example.com/1{/two}/"
762
- end
763
- end
764
- end
765
- describe "Expand" do
766
- context "expand with a processor" do
767
- subject{
768
- Addressable::Template.new("http://example.com/search/{query}/")
769
- }
770
- it "processes spaces" do
771
- subject.expand({"query" => "an example search query"},
772
- ExampleTwoProcessor).to_str.should ==
773
- "http://example.com/search/an+example+search+query/"
774
- end
775
- it "validates" do
776
- lambda{
777
- subject.expand({"query" => "Bogus!"},
778
- ExampleTwoProcessor).to_str
779
- }.should raise_error(Addressable::Template::InvalidTemplateValueError)
780
- end
781
- end
782
- context "partial_expand query with missing param in middle" do
783
- subject{
784
- Addressable::Template.new("http://example.com/{?one,two,three}/")
785
- }
786
- it "builds a new pattern" do
787
- subject.partial_expand("one" => "1", "three" => "3").pattern.should ==
788
- "http://example.com/?one=1{&two}&three=3/"
789
- end
790
- end
791
- context "partial_expand with query string" do
792
- subject{
793
- Addressable::Template.new("http://example.com/{?two,one}/")
794
- }
795
- it "builds a new pattern" do
796
- subject.partial_expand("one" => "1").pattern.should ==
797
- "http://example.com/{?two}&one=1/"
798
- end
799
- end
800
- context "partial_expand with path operator" do
801
- subject{
802
- Addressable::Template.new("http://example.com{/one,two}/")
803
- }
804
- it "builds a new pattern" do
805
- subject.partial_expand("one" => "1").pattern.should ==
806
- "http://example.com/1{/two}/"
807
- end
808
- end
809
- end
810
- context "Matching with operators" do
811
- describe "Level 1:" do
812
- subject { Addressable::Template.new("foo{foo}/{bar}baz") }
813
- it "can match" do
814
- data = subject.match("foofoo/bananabaz")
815
- data.mapping["foo"].should == "foo"
816
- data.mapping["bar"].should == "banana"
817
- end
818
- it "lists vars" do
819
- subject.variables.should == ["foo", "bar"]
820
- end
821
- end
822
-
823
- describe "Level 2:" do
824
- subject { Addressable::Template.new("foo{+foo}{#bar}baz") }
825
- it "can match" do
826
- data = subject.match("foo/test/banana#bazbaz")
827
- data.mapping["foo"].should == "/test/banana"
828
- data.mapping["bar"].should == "baz"
829
- end
830
- it "lists vars" do
831
- subject.variables.should == ["foo", "bar"]
832
- end
833
- end
834
-
835
- describe "Level 3:" do
836
- context "no operator" do
837
- subject { Addressable::Template.new("foo{foo,bar}baz") }
838
- it "can match" do
839
- data = subject.match("foofoo,barbaz")
840
- data.mapping["foo"].should == "foo"
841
- data.mapping["bar"].should == "bar"
842
- end
843
- it "lists vars" do
844
- subject.variables.should == ["foo", "bar"]
845
- end
846
- end
847
- context "+ operator" do
848
- subject { Addressable::Template.new("foo{+foo,bar}baz") }
849
- it "can match" do
850
- data = subject.match("foofoo/bar,barbaz")
851
- data.mapping["bar"].should == "foo/bar,bar"
852
- data.mapping["foo"].should == ""
853
- end
854
- it "lists vars" do
855
- subject.variables.should == ["foo", "bar"]
856
- end
857
- end
858
- context ". operator" do
859
- subject { Addressable::Template.new("foo{.foo,bar}baz") }
860
- it "can match" do
861
- data = subject.match("foo.foo.barbaz")
862
- data.mapping["foo"].should == "foo"
863
- data.mapping["bar"].should == "bar"
864
- end
865
- it "lists vars" do
866
- subject.variables.should == ["foo", "bar"]
867
- end
868
- end
869
- context "/ operator" do
870
- subject { Addressable::Template.new("foo{/foo,bar}baz") }
871
- it "can match" do
872
- data = subject.match("foo/foo/barbaz")
873
- data.mapping["foo"].should == "foo"
874
- data.mapping["bar"].should == "bar"
875
- end
876
- it "lists vars" do
877
- subject.variables.should == ["foo", "bar"]
878
- end
879
- end
880
- context "; operator" do
881
- subject { Addressable::Template.new("foo{;foo,bar,baz}baz") }
882
- it "can match" do
883
- data = subject.match("foo;foo=bar%20baz;bar=foo;bazbaz")
884
- data.mapping["foo"].should == "bar baz"
885
- data.mapping["bar"].should == "foo"
886
- data.mapping["baz"].should == ""
887
- end
888
- it "lists vars" do
889
- subject.variables.should == %w(foo bar baz)
890
- end
891
- end
892
- context "? operator" do
893
- context "test" do
894
- subject { Addressable::Template.new("foo{?foo,bar}baz") }
895
- it "can match" do
896
- data = subject.match("foo?foo=bar%20baz&bar=foobaz")
897
- data.mapping["foo"].should == "bar baz"
898
- data.mapping["bar"].should == "foo"
899
- end
900
- it "lists vars" do
901
- subject.variables.should == %w(foo bar)
902
- end
903
- end
904
- context "issue #71" do
905
- subject { Addressable::Template.new("http://cyberscore.dev/api/users{?username}") }
906
- it "can match" do
907
- data = subject.match("http://cyberscore.dev/api/users?username=foobaz")
908
- data.mapping["username"].should == "foobaz"
909
- end
910
- it "lists vars" do
911
- subject.variables.should == %w(username)
912
- subject.keys.should == %w(username)
913
- end
914
- end
915
- end
916
- context "& operator" do
917
- subject { Addressable::Template.new("foo{&foo,bar}baz") }
918
- it "can match" do
919
- data = subject.match("foo&foo=bar%20baz&bar=foobaz")
920
- data.mapping["foo"].should == "bar baz"
921
- data.mapping["bar"].should == "foo"
922
- end
923
- it "lists vars" do
924
- subject.variables.should == %w(foo bar)
925
- end
926
- end
927
- end
928
- end
929
-
930
- context "support regexes:" do
931
- context "EXPRESSION" do
932
- subject { Addressable::Template::EXPRESSION }
933
- it "should be able to match an expression" do
934
- subject.should match("{foo}")
935
- subject.should match("{foo,9}")
936
- subject.should match("{foo.bar,baz}")
937
- subject.should match("{+foo.bar,baz}")
938
- subject.should match("{foo,foo%20bar}")
939
- subject.should match("{#foo:20,baz*}")
940
- subject.should match("stuff{#foo:20,baz*}things")
941
- end
942
- it "should fail on non vars" do
943
- subject.should_not match("!{foo")
944
- subject.should_not match("{foo.bar.}")
945
- subject.should_not match("!{}")
946
- end
947
- end
948
- context "VARNAME" do
949
- subject { Addressable::Template::VARNAME }
950
- it "should be able to match a variable" do
951
- subject.should match("foo")
952
- subject.should match("9")
953
- subject.should match("foo.bar")
954
- subject.should match("foo_bar")
955
- subject.should match("foo_bar.baz")
956
- subject.should match("foo%20bar")
957
- subject.should match("foo%20bar.baz")
958
- end
959
- it "should fail on non vars" do
960
- subject.should_not match("!foo")
961
- subject.should_not match("foo.bar.")
962
- subject.should_not match("foo%2%00bar")
963
- subject.should_not match("foo_ba%r")
964
- subject.should_not match("foo_bar*")
965
- subject.should_not match("foo_bar:20")
966
- end
967
- end
968
- context "VARIABLE_LIST" do
969
- subject { Addressable::Template::VARIABLE_LIST }
970
- it "should be able to match a variable list" do
971
- subject.should match("foo,bar")
972
- subject.should match("foo")
973
- subject.should match("foo,bar*,baz")
974
- subject.should match("foo.bar,bar_baz*,baz:12")
975
- end
976
- it "should fail on non vars" do
977
- subject.should_not match(",foo,bar*,baz")
978
- subject.should_not match("foo,*bar,baz")
979
- subject.should_not match("foo,,bar*,baz")
980
- end
981
- end
982
- context "VARSPEC" do
983
- subject { Addressable::Template::VARSPEC }
984
- it "should be able to match a variable with modifier" do
985
- subject.should match("9:8")
986
- subject.should match("foo.bar*")
987
- subject.should match("foo_bar:12")
988
- subject.should match("foo_bar.baz*")
989
- subject.should match("foo%20bar:12")
990
- subject.should match("foo%20bar.baz*")
991
- end
992
- it "should fail on non vars" do
993
- subject.should_not match("!foo")
994
- subject.should_not match("*foo")
995
- subject.should_not match("fo*o")
996
- subject.should_not match("fo:o")
997
- subject.should_not match("foo:")
998
- end
999
- end
1000
- end
1001
- end