addressable 2.3.3 → 2.8.9

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