addressable 2.4.0 → 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,1386 +0,0 @@
1
- # coding: utf-8
2
- # Copyright (C) 2006-2015 Bob Aman
3
- #
4
- # Licensed under the Apache License, Version 2.0 (the "License");
5
- # you may not use this file except in compliance with the License.
6
- # You may obtain a copy of the License at
7
- #
8
- # http://www.apache.org/licenses/LICENSE-2.0
9
- #
10
- # Unless required by applicable law or agreed to in writing, software
11
- # distributed under the License is distributed on an "AS IS" BASIS,
12
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- # See the License for the specific language governing permissions and
14
- # limitations under the License.
15
-
16
-
17
- require "spec_helper"
18
-
19
- require "bigdecimal"
20
- require "addressable/template"
21
-
22
- shared_examples_for 'expands' do |tests|
23
- tests.each do |template, expansion|
24
- exp = expansion.is_a?(Array) ? expansion.first : expansion
25
- it "#{template} to #{exp}" do
26
- tmpl = Addressable::Template.new(template).expand(subject)
27
- if expansion.is_a?(Array)
28
- expect(expansion.any?{|i| i == tmpl.to_str}).to be true
29
- else
30
- expect(tmpl.to_str).to eq(expansion)
31
- end
32
- end
33
- end
34
- end
35
-
36
- describe "eql?" do
37
- let(:template) { Addressable::Template.new('https://www.example.com/{foo}') }
38
- it 'is equal when the pattern matches' do
39
- other_template = Addressable::Template.new('https://www.example.com/{foo}')
40
- expect(template).to be_eql(other_template)
41
- expect(other_template).to be_eql(template)
42
- end
43
- it 'is not equal when the pattern differs' do
44
- other_template = Addressable::Template.new('https://www.example.com/{bar}')
45
- expect(template).to_not be_eql(other_template)
46
- expect(other_template).to_not be_eql(template)
47
- end
48
- it 'is not equal to non-templates' do
49
- uri = 'https://www.example.com/foo/bar'
50
- addressable_template = Addressable::Template.new uri
51
- addressable_uri = Addressable::URI.parse uri
52
- expect(addressable_template).to_not be_eql(addressable_uri)
53
- expect(addressable_uri).to_not be_eql(addressable_template)
54
- end
55
- end
56
-
57
- describe "==" do
58
- let(:template) { Addressable::Template.new('https://www.example.com/{foo}') }
59
- it 'is equal when the pattern matches' do
60
- other_template = Addressable::Template.new('https://www.example.com/{foo}')
61
- expect(template).to eq other_template
62
- expect(other_template).to eq template
63
- end
64
- it 'is not equal when the pattern differs' do
65
- other_template = Addressable::Template.new('https://www.example.com/{bar}')
66
- expect(template).not_to eq other_template
67
- expect(other_template).not_to eq template
68
- end
69
- it 'is not equal to non-templates' do
70
- uri = 'https://www.example.com/foo/bar'
71
- addressable_template = Addressable::Template.new uri
72
- addressable_uri = Addressable::URI.parse uri
73
- expect(addressable_template).not_to eq addressable_uri
74
- expect(addressable_uri).not_to eq addressable_template
75
- end
76
- end
77
-
78
- describe "Type conversion" do
79
- subject {
80
- {
81
- :var => true,
82
- :hello => 1234,
83
- :nothing => nil,
84
- :sym => :symbolic,
85
- :decimal => BigDecimal.new('1')
86
- }
87
- }
88
-
89
- it_behaves_like 'expands', {
90
- '{var}' => 'true',
91
- '{hello}' => '1234',
92
- '{nothing}' => '',
93
- '{sym}' => 'symbolic',
94
- '{decimal}' => '0.1E1'
95
- }
96
- end
97
-
98
- describe "Level 1:" do
99
- subject {
100
- {:var => "value", :hello => "Hello World!"}
101
- }
102
- it_behaves_like 'expands', {
103
- '{var}' => 'value',
104
- '{hello}' => 'Hello%20World%21'
105
- }
106
- end
107
-
108
- describe "Level 2" do
109
- subject {
110
- {
111
- :var => "value",
112
- :hello => "Hello World!",
113
- :path => "/foo/bar"
114
- }
115
- }
116
- context "Operator +:" do
117
- it_behaves_like 'expands', {
118
- '{+var}' => 'value',
119
- '{+hello}' => 'Hello%20World!',
120
- '{+path}/here' => '/foo/bar/here',
121
- 'here?ref={+path}' => 'here?ref=/foo/bar'
122
- }
123
- end
124
- context "Operator #:" do
125
- it_behaves_like 'expands', {
126
- 'X{#var}' => 'X#value',
127
- 'X{#hello}' => 'X#Hello%20World!'
128
- }
129
- end
130
- end
131
-
132
- describe "Level 3" do
133
- subject {
134
- {
135
- :var => "value",
136
- :hello => "Hello World!",
137
- :empty => "",
138
- :path => "/foo/bar",
139
- :x => "1024",
140
- :y => "768"
141
- }
142
- }
143
- context "Operator nil (multiple vars):" do
144
- it_behaves_like 'expands', {
145
- 'map?{x,y}' => 'map?1024,768',
146
- '{x,hello,y}' => '1024,Hello%20World%21,768'
147
- }
148
- end
149
- context "Operator + (multiple vars):" do
150
- it_behaves_like 'expands', {
151
- '{+x,hello,y}' => '1024,Hello%20World!,768',
152
- '{+path,x}/here' => '/foo/bar,1024/here'
153
- }
154
- end
155
- context "Operator # (multiple vars):" do
156
- it_behaves_like 'expands', {
157
- '{#x,hello,y}' => '#1024,Hello%20World!,768',
158
- '{#path,x}/here' => '#/foo/bar,1024/here'
159
- }
160
- end
161
- context "Operator ." do
162
- it_behaves_like 'expands', {
163
- 'X{.var}' => 'X.value',
164
- 'X{.x,y}' => 'X.1024.768'
165
- }
166
- end
167
- context "Operator /" do
168
- it_behaves_like 'expands', {
169
- '{/var}' => '/value',
170
- '{/var,x}/here' => '/value/1024/here'
171
- }
172
- end
173
- context "Operator ;" do
174
- it_behaves_like 'expands', {
175
- '{;x,y}' => ';x=1024;y=768',
176
- '{;x,y,empty}' => ';x=1024;y=768;empty'
177
- }
178
- end
179
- context "Operator ?" do
180
- it_behaves_like 'expands', {
181
- '{?x,y}' => '?x=1024&y=768',
182
- '{?x,y,empty}' => '?x=1024&y=768&empty='
183
- }
184
- end
185
- context "Operator &" do
186
- it_behaves_like 'expands', {
187
- '?fixed=yes{&x}' => '?fixed=yes&x=1024',
188
- '{&x,y,empty}' => '&x=1024&y=768&empty='
189
- }
190
- end
191
- end
192
-
193
- describe "Level 4" do
194
- subject {
195
- {
196
- :var => "value",
197
- :hello => "Hello World!",
198
- :path => "/foo/bar",
199
- :semi => ";",
200
- :list => %w(red green blue),
201
- :keys => {"semi" => ';', "dot" => '.', "comma" => ','}
202
- }
203
- }
204
- context "Expansion with value modifiers" do
205
- it_behaves_like 'expands', {
206
- '{var:3}' => 'val',
207
- '{var:30}' => 'value',
208
- '{list}' => 'red,green,blue',
209
- '{list*}' => 'red,green,blue',
210
- '{keys}' => [
211
- 'semi,%3B,dot,.,comma,%2C',
212
- 'dot,.,semi,%3B,comma,%2C',
213
- 'comma,%2C,semi,%3B,dot,.',
214
- 'semi,%3B,comma,%2C,dot,.',
215
- 'dot,.,comma,%2C,semi,%3B',
216
- 'comma,%2C,dot,.,semi,%3B'
217
- ],
218
- '{keys*}' => [
219
- 'semi=%3B,dot=.,comma=%2C',
220
- 'dot=.,semi=%3B,comma=%2C',
221
- 'comma=%2C,semi=%3B,dot=.',
222
- 'semi=%3B,comma=%2C,dot=.',
223
- 'dot=.,comma=%2C,semi=%3B',
224
- 'comma=%2C,dot=.,semi=%3B'
225
- ]
226
- }
227
- end
228
- context "Operator + with value modifiers" do
229
- it_behaves_like 'expands', {
230
- '{+path:6}/here' => '/foo/b/here',
231
- '{+list}' => 'red,green,blue',
232
- '{+list*}' => 'red,green,blue',
233
- '{+keys}' => [
234
- 'semi,;,dot,.,comma,,',
235
- 'dot,.,semi,;,comma,,',
236
- 'comma,,,semi,;,dot,.',
237
- 'semi,;,comma,,,dot,.',
238
- 'dot,.,comma,,,semi,;',
239
- 'comma,,,dot,.,semi,;'
240
- ],
241
- '{+keys*}' => [
242
- 'semi=;,dot=.,comma=,',
243
- 'dot=.,semi=;,comma=,',
244
- 'comma=,,semi=;,dot=.',
245
- 'semi=;,comma=,,dot=.',
246
- 'dot=.,comma=,,semi=;',
247
- 'comma=,,dot=.,semi=;'
248
- ]
249
- }
250
- end
251
- context "Operator # with value modifiers" do
252
- it_behaves_like 'expands', {
253
- '{#path:6}/here' => '#/foo/b/here',
254
- '{#list}' => '#red,green,blue',
255
- '{#list*}' => '#red,green,blue',
256
- '{#keys}' => [
257
- '#semi,;,dot,.,comma,,',
258
- '#dot,.,semi,;,comma,,',
259
- '#comma,,,semi,;,dot,.',
260
- '#semi,;,comma,,,dot,.',
261
- '#dot,.,comma,,,semi,;',
262
- '#comma,,,dot,.,semi,;'
263
- ],
264
- '{#keys*}' => [
265
- '#semi=;,dot=.,comma=,',
266
- '#dot=.,semi=;,comma=,',
267
- '#comma=,,semi=;,dot=.',
268
- '#semi=;,comma=,,dot=.',
269
- '#dot=.,comma=,,semi=;',
270
- '#comma=,,dot=.,semi=;'
271
- ]
272
- }
273
- end
274
- context "Operator . with value modifiers" do
275
- it_behaves_like 'expands', {
276
- 'X{.var:3}' => 'X.val',
277
- 'X{.list}' => 'X.red,green,blue',
278
- 'X{.list*}' => 'X.red.green.blue',
279
- 'X{.keys}' => [
280
- 'X.semi,%3B,dot,.,comma,%2C',
281
- 'X.dot,.,semi,%3B,comma,%2C',
282
- 'X.comma,%2C,semi,%3B,dot,.',
283
- 'X.semi,%3B,comma,%2C,dot,.',
284
- 'X.dot,.,comma,%2C,semi,%3B',
285
- 'X.comma,%2C,dot,.,semi,%3B'
286
- ],
287
- 'X{.keys*}' => [
288
- 'X.semi=%3B.dot=..comma=%2C',
289
- 'X.dot=..semi=%3B.comma=%2C',
290
- 'X.comma=%2C.semi=%3B.dot=.',
291
- 'X.semi=%3B.comma=%2C.dot=.',
292
- 'X.dot=..comma=%2C.semi=%3B',
293
- 'X.comma=%2C.dot=..semi=%3B'
294
- ]
295
- }
296
- end
297
- context "Operator / with value modifiers" do
298
- it_behaves_like 'expands', {
299
- '{/var:1,var}' => '/v/value',
300
- '{/list}' => '/red,green,blue',
301
- '{/list*}' => '/red/green/blue',
302
- '{/list*,path:4}' => '/red/green/blue/%2Ffoo',
303
- '{/keys}' => [
304
- '/semi,%3B,dot,.,comma,%2C',
305
- '/dot,.,semi,%3B,comma,%2C',
306
- '/comma,%2C,semi,%3B,dot,.',
307
- '/semi,%3B,comma,%2C,dot,.',
308
- '/dot,.,comma,%2C,semi,%3B',
309
- '/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
- context "Operator ; with value modifiers" do
322
- it_behaves_like 'expands', {
323
- '{;hello:5}' => ';hello=Hello',
324
- '{;list}' => ';list=red,green,blue',
325
- '{;list*}' => ';list=red;list=green;list=blue',
326
- '{;keys}' => [
327
- ';keys=semi,%3B,dot,.,comma,%2C',
328
- ';keys=dot,.,semi,%3B,comma,%2C',
329
- ';keys=comma,%2C,semi,%3B,dot,.',
330
- ';keys=semi,%3B,comma,%2C,dot,.',
331
- ';keys=dot,.,comma,%2C,semi,%3B',
332
- ';keys=comma,%2C,dot,.,semi,%3B'
333
- ],
334
- '{;keys*}' => [
335
- ';semi=%3B;dot=.;comma=%2C',
336
- ';dot=.;semi=%3B;comma=%2C',
337
- ';comma=%2C;semi=%3B;dot=.',
338
- ';semi=%3B;comma=%2C;dot=.',
339
- ';dot=.;comma=%2C;semi=%3B',
340
- ';comma=%2C;dot=.;semi=%3B'
341
- ]
342
- }
343
- end
344
- context "Operator ? with value modifiers" do
345
- it_behaves_like 'expands', {
346
- '{?var:3}' => '?var=val',
347
- '{?list}' => '?list=red,green,blue',
348
- '{?list*}' => '?list=red&list=green&list=blue',
349
- '{?keys}' => [
350
- '?keys=semi,%3B,dot,.,comma,%2C',
351
- '?keys=dot,.,semi,%3B,comma,%2C',
352
- '?keys=comma,%2C,semi,%3B,dot,.',
353
- '?keys=semi,%3B,comma,%2C,dot,.',
354
- '?keys=dot,.,comma,%2C,semi,%3B',
355
- '?keys=comma,%2C,dot,.,semi,%3B'
356
- ],
357
- '{?keys*}' => [
358
- '?semi=%3B&dot=.&comma=%2C',
359
- '?dot=.&semi=%3B&comma=%2C',
360
- '?comma=%2C&semi=%3B&dot=.',
361
- '?semi=%3B&comma=%2C&dot=.',
362
- '?dot=.&comma=%2C&semi=%3B',
363
- '?comma=%2C&dot=.&semi=%3B'
364
- ]
365
- }
366
- end
367
- context "Operator & with value modifiers" do
368
- it_behaves_like 'expands', {
369
- '{&var:3}' => '&var=val',
370
- '{&list}' => '&list=red,green,blue',
371
- '{&list*}' => '&list=red&list=green&list=blue',
372
- '{&keys}' => [
373
- '&keys=semi,%3B,dot,.,comma,%2C',
374
- '&keys=dot,.,semi,%3B,comma,%2C',
375
- '&keys=comma,%2C,semi,%3B,dot,.',
376
- '&keys=semi,%3B,comma,%2C,dot,.',
377
- '&keys=dot,.,comma,%2C,semi,%3B',
378
- '&keys=comma,%2C,dot,.,semi,%3B'
379
- ],
380
- '{&keys*}' => [
381
- '&semi=%3B&dot=.&comma=%2C',
382
- '&dot=.&semi=%3B&comma=%2C',
383
- '&comma=%2C&semi=%3B&dot=.',
384
- '&semi=%3B&comma=%2C&dot=.',
385
- '&dot=.&comma=%2C&semi=%3B',
386
- '&comma=%2C&dot=.&semi=%3B'
387
- ]
388
- }
389
- end
390
- end
391
- describe "Modifiers" do
392
- subject {
393
- {
394
- :var => "value",
395
- :semi => ";",
396
- :year => %w(1965 2000 2012),
397
- :dom => %w(example com)
398
- }
399
- }
400
- context "length" do
401
- it_behaves_like 'expands', {
402
- '{var:3}' => 'val',
403
- '{var:30}' => 'value',
404
- '{var}' => 'value',
405
- '{semi}' => '%3B',
406
- '{semi:2}' => '%3B'
407
- }
408
- end
409
- context "explode" do
410
- it_behaves_like 'expands', {
411
- 'find{?year*}' => 'find?year=1965&year=2000&year=2012',
412
- 'www{.dom*}' => 'www.example.com',
413
- }
414
- end
415
- end
416
- describe "Expansion" do
417
- subject {
418
- {
419
- :count => ["one", "two", "three"],
420
- :dom => ["example", "com"],
421
- :dub => "me/too",
422
- :hello => "Hello World!",
423
- :half => "50%",
424
- :var => "value",
425
- :who => "fred",
426
- :base => "http://example.com/home/",
427
- :path => "/foo/bar",
428
- :list => ["red", "green", "blue"],
429
- :keys => {"semi" => ";","dot" => ".","comma" => ","},
430
- :v => "6",
431
- :x => "1024",
432
- :y => "768",
433
- :empty => "",
434
- :empty_keys => {},
435
- :undef => nil
436
- }
437
- }
438
- context "concatenation" do
439
- it_behaves_like 'expands', {
440
- '{count}' => 'one,two,three',
441
- '{count*}' => 'one,two,three',
442
- '{/count}' => '/one,two,three',
443
- '{/count*}' => '/one/two/three',
444
- '{;count}' => ';count=one,two,three',
445
- '{;count*}' => ';count=one;count=two;count=three',
446
- '{?count}' => '?count=one,two,three',
447
- '{?count*}' => '?count=one&count=two&count=three',
448
- '{&count*}' => '&count=one&count=two&count=three'
449
- }
450
- end
451
- context "simple expansion" do
452
- it_behaves_like 'expands', {
453
- '{var}' => 'value',
454
- '{hello}' => 'Hello%20World%21',
455
- '{half}' => '50%25',
456
- 'O{empty}X' => 'OX',
457
- 'O{undef}X' => 'OX',
458
- '{x,y}' => '1024,768',
459
- '{x,hello,y}' => '1024,Hello%20World%21,768',
460
- '?{x,empty}' => '?1024,',
461
- '?{x,undef}' => '?1024',
462
- '?{undef,y}' => '?768',
463
- '{var:3}' => 'val',
464
- '{var:30}' => 'value',
465
- '{list}' => 'red,green,blue',
466
- '{list*}' => 'red,green,blue',
467
- '{keys}' => [
468
- 'semi,%3B,dot,.,comma,%2C',
469
- 'dot,.,semi,%3B,comma,%2C',
470
- 'comma,%2C,semi,%3B,dot,.',
471
- 'semi,%3B,comma,%2C,dot,.',
472
- 'dot,.,comma,%2C,semi,%3B',
473
- 'comma,%2C,dot,.,semi,%3B'
474
- ],
475
- '{keys*}' => [
476
- 'semi=%3B,dot=.,comma=%2C',
477
- 'dot=.,semi=%3B,comma=%2C',
478
- 'comma=%2C,semi=%3B,dot=.',
479
- 'semi=%3B,comma=%2C,dot=.',
480
- 'dot=.,comma=%2C,semi=%3B',
481
- 'comma=%2C,dot=.,semi=%3B'
482
- ]
483
- }
484
- end
485
- context "reserved expansion (+)" do
486
- it_behaves_like 'expands', {
487
- '{+var}' => 'value',
488
- '{+hello}' => 'Hello%20World!',
489
- '{+half}' => '50%25',
490
- '{base}index' => 'http%3A%2F%2Fexample.com%2Fhome%2Findex',
491
- '{+base}index' => 'http://example.com/home/index',
492
- 'O{+empty}X' => 'OX',
493
- 'O{+undef}X' => 'OX',
494
- '{+path}/here' => '/foo/bar/here',
495
- 'here?ref={+path}' => 'here?ref=/foo/bar',
496
- 'up{+path}{var}/here' => 'up/foo/barvalue/here',
497
- '{+x,hello,y}' => '1024,Hello%20World!,768',
498
- '{+path,x}/here' => '/foo/bar,1024/here',
499
- '{+path:6}/here' => '/foo/b/here',
500
- '{+list}' => 'red,green,blue',
501
- '{+list*}' => 'red,green,blue',
502
- '{+keys}' => [
503
- 'semi,;,dot,.,comma,,',
504
- 'dot,.,semi,;,comma,,',
505
- 'comma,,,semi,;,dot,.',
506
- 'semi,;,comma,,,dot,.',
507
- 'dot,.,comma,,,semi,;',
508
- 'comma,,,dot,.,semi,;'
509
- ],
510
- '{+keys*}' => [
511
- 'semi=;,dot=.,comma=,',
512
- 'dot=.,semi=;,comma=,',
513
- 'comma=,,semi=;,dot=.',
514
- 'semi=;,comma=,,dot=.',
515
- 'dot=.,comma=,,semi=;',
516
- 'comma=,,dot=.,semi=;'
517
- ]
518
- }
519
- end
520
- context "fragment expansion (#)" do
521
- it_behaves_like 'expands', {
522
- '{#var}' => '#value',
523
- '{#hello}' => '#Hello%20World!',
524
- '{#half}' => '#50%25',
525
- 'foo{#empty}' => 'foo#',
526
- 'foo{#undef}' => 'foo',
527
- '{#x,hello,y}' => '#1024,Hello%20World!,768',
528
- '{#path,x}/here' => '#/foo/bar,1024/here',
529
- '{#path:6}/here' => '#/foo/b/here',
530
- '{#list}' => '#red,green,blue',
531
- '{#list*}' => '#red,green,blue',
532
- '{#keys}' => [
533
- '#semi,;,dot,.,comma,,',
534
- '#dot,.,semi,;,comma,,',
535
- '#comma,,,semi,;,dot,.',
536
- '#semi,;,comma,,,dot,.',
537
- '#dot,.,comma,,,semi,;',
538
- '#comma,,,dot,.,semi,;'
539
- ],
540
- '{#keys*}' => [
541
- '#semi=;,dot=.,comma=,',
542
- '#dot=.,semi=;,comma=,',
543
- '#comma=,,semi=;,dot=.',
544
- '#semi=;,comma=,,dot=.',
545
- '#dot=.,comma=,,semi=;',
546
- '#comma=,,dot=.,semi=;'
547
- ]
548
- }
549
- end
550
- context "label expansion (.)" do
551
- it_behaves_like 'expands', {
552
- '{.who}' => '.fred',
553
- '{.who,who}' => '.fred.fred',
554
- '{.half,who}' => '.50%25.fred',
555
- 'www{.dom*}' => 'www.example.com',
556
- 'X{.var}' => 'X.value',
557
- 'X{.empty}' => 'X.',
558
- 'X{.undef}' => 'X',
559
- 'X{.var:3}' => 'X.val',
560
- 'X{.list}' => 'X.red,green,blue',
561
- 'X{.list*}' => 'X.red.green.blue',
562
- 'X{.keys}' => [
563
- 'X.semi,%3B,dot,.,comma,%2C',
564
- 'X.dot,.,semi,%3B,comma,%2C',
565
- 'X.comma,%2C,semi,%3B,dot,.',
566
- 'X.semi,%3B,comma,%2C,dot,.',
567
- 'X.dot,.,comma,%2C,semi,%3B',
568
- 'X.comma,%2C,dot,.,semi,%3B'
569
- ],
570
- 'X{.keys*}' => [
571
- 'X.semi=%3B.dot=..comma=%2C',
572
- 'X.dot=..semi=%3B.comma=%2C',
573
- 'X.comma=%2C.semi=%3B.dot=.',
574
- 'X.semi=%3B.comma=%2C.dot=.',
575
- 'X.dot=..comma=%2C.semi=%3B',
576
- 'X.comma=%2C.dot=..semi=%3B'
577
- ],
578
- 'X{.empty_keys}' => 'X',
579
- 'X{.empty_keys*}' => 'X'
580
- }
581
- end
582
- context "path expansion (/)" do
583
- it_behaves_like 'expands', {
584
- '{/who}' => '/fred',
585
- '{/who,who}' => '/fred/fred',
586
- '{/half,who}' => '/50%25/fred',
587
- '{/who,dub}' => '/fred/me%2Ftoo',
588
- '{/var}' => '/value',
589
- '{/var,empty}' => '/value/',
590
- '{/var,undef}' => '/value',
591
- '{/var,x}/here' => '/value/1024/here',
592
- '{/var:1,var}' => '/v/value',
593
- '{/list}' => '/red,green,blue',
594
- '{/list*}' => '/red/green/blue',
595
- '{/list*,path:4}' => '/red/green/blue/%2Ffoo',
596
- '{/keys}' => [
597
- '/semi,%3B,dot,.,comma,%2C',
598
- '/dot,.,semi,%3B,comma,%2C',
599
- '/comma,%2C,semi,%3B,dot,.',
600
- '/semi,%3B,comma,%2C,dot,.',
601
- '/dot,.,comma,%2C,semi,%3B',
602
- '/comma,%2C,dot,.,semi,%3B'
603
- ],
604
- '{/keys*}' => [
605
- '/semi=%3B/dot=./comma=%2C',
606
- '/dot=./semi=%3B/comma=%2C',
607
- '/comma=%2C/semi=%3B/dot=.',
608
- '/semi=%3B/comma=%2C/dot=.',
609
- '/dot=./comma=%2C/semi=%3B',
610
- '/comma=%2C/dot=./semi=%3B'
611
- ]
612
- }
613
- end
614
- context "path-style expansion (;)" do
615
- it_behaves_like 'expands', {
616
- '{;who}' => ';who=fred',
617
- '{;half}' => ';half=50%25',
618
- '{;empty}' => ';empty',
619
- '{;v,empty,who}' => ';v=6;empty;who=fred',
620
- '{;v,bar,who}' => ';v=6;who=fred',
621
- '{;x,y}' => ';x=1024;y=768',
622
- '{;x,y,empty}' => ';x=1024;y=768;empty',
623
- '{;x,y,undef}' => ';x=1024;y=768',
624
- '{;hello:5}' => ';hello=Hello',
625
- '{;list}' => ';list=red,green,blue',
626
- '{;list*}' => ';list=red;list=green;list=blue',
627
- '{;keys}' => [
628
- ';keys=semi,%3B,dot,.,comma,%2C',
629
- ';keys=dot,.,semi,%3B,comma,%2C',
630
- ';keys=comma,%2C,semi,%3B,dot,.',
631
- ';keys=semi,%3B,comma,%2C,dot,.',
632
- ';keys=dot,.,comma,%2C,semi,%3B',
633
- ';keys=comma,%2C,dot,.,semi,%3B'
634
- ],
635
- '{;keys*}' => [
636
- ';semi=%3B;dot=.;comma=%2C',
637
- ';dot=.;semi=%3B;comma=%2C',
638
- ';comma=%2C;semi=%3B;dot=.',
639
- ';semi=%3B;comma=%2C;dot=.',
640
- ';dot=.;comma=%2C;semi=%3B',
641
- ';comma=%2C;dot=.;semi=%3B'
642
- ]
643
- }
644
- end
645
- context "form query expansion (?)" do
646
- it_behaves_like 'expands', {
647
- '{?who}' => '?who=fred',
648
- '{?half}' => '?half=50%25',
649
- '{?x,y}' => '?x=1024&y=768',
650
- '{?x,y,empty}' => '?x=1024&y=768&empty=',
651
- '{?x,y,undef}' => '?x=1024&y=768',
652
- '{?var:3}' => '?var=val',
653
- '{?list}' => '?list=red,green,blue',
654
- '{?list*}' => '?list=red&list=green&list=blue',
655
- '{?keys}' => [
656
- '?keys=semi,%3B,dot,.,comma,%2C',
657
- '?keys=dot,.,semi,%3B,comma,%2C',
658
- '?keys=comma,%2C,semi,%3B,dot,.',
659
- '?keys=semi,%3B,comma,%2C,dot,.',
660
- '?keys=dot,.,comma,%2C,semi,%3B',
661
- '?keys=comma,%2C,dot,.,semi,%3B'
662
- ],
663
- '{?keys*}' => [
664
- '?semi=%3B&dot=.&comma=%2C',
665
- '?dot=.&semi=%3B&comma=%2C',
666
- '?comma=%2C&semi=%3B&dot=.',
667
- '?semi=%3B&comma=%2C&dot=.',
668
- '?dot=.&comma=%2C&semi=%3B',
669
- '?comma=%2C&dot=.&semi=%3B'
670
- ]
671
- }
672
- end
673
- context "form query expansion (&)" do
674
- it_behaves_like 'expands', {
675
- '{&who}' => '&who=fred',
676
- '{&half}' => '&half=50%25',
677
- '?fixed=yes{&x}' => '?fixed=yes&x=1024',
678
- '{&x,y,empty}' => '&x=1024&y=768&empty=',
679
- '{&x,y,undef}' => '&x=1024&y=768',
680
- '{&var:3}' => '&var=val',
681
- '{&list}' => '&list=red,green,blue',
682
- '{&list*}' => '&list=red&list=green&list=blue',
683
- '{&keys}' => [
684
- '&keys=semi,%3B,dot,.,comma,%2C',
685
- '&keys=dot,.,semi,%3B,comma,%2C',
686
- '&keys=comma,%2C,semi,%3B,dot,.',
687
- '&keys=semi,%3B,comma,%2C,dot,.',
688
- '&keys=dot,.,comma,%2C,semi,%3B',
689
- '&keys=comma,%2C,dot,.,semi,%3B'
690
- ],
691
- '{&keys*}' => [
692
- '&semi=%3B&dot=.&comma=%2C',
693
- '&dot=.&semi=%3B&comma=%2C',
694
- '&comma=%2C&semi=%3B&dot=.',
695
- '&semi=%3B&comma=%2C&dot=.',
696
- '&dot=.&comma=%2C&semi=%3B',
697
- '&comma=%2C&dot=.&semi=%3B'
698
- ]
699
- }
700
- end
701
- context "non-string key in match data" do
702
- subject {Addressable::Template.new("http://example.com/{one}")}
703
-
704
- it "raises TypeError" do
705
- expect { subject.expand(Object.new => "1") }.to raise_error TypeError
706
- end
707
- end
708
- end
709
-
710
- class ExampleTwoProcessor
711
- def self.restore(name, value)
712
- return value.gsub(/-/, " ") if name == "query"
713
- return value
714
- end
715
-
716
- def self.match(name)
717
- return ".*?" if name == "first"
718
- return ".*"
719
- end
720
- def self.validate(name, value)
721
- return !!(value =~ /^[\w ]+$/) if name == "query"
722
- return true
723
- end
724
-
725
- def self.transform(name, value)
726
- return value.gsub(/ /, "+") if name == "query"
727
- return value
728
- end
729
- end
730
-
731
- class DumbProcessor
732
- def self.match(name)
733
- return ".*?" if name == "first"
734
- end
735
- end
736
-
737
- describe Addressable::Template do
738
- describe 'initialize' do
739
- context 'with a non-string' do
740
- it 'raises a TypeError' do
741
- expect { Addressable::Template.new(nil) }.to raise_error(TypeError)
742
- end
743
- end
744
- end
745
-
746
- describe 'freeze' do
747
- subject { Addressable::Template.new("http://example.com/{first}/{+second}/") }
748
- it 'freezes the template' do
749
- expect(subject.freeze).to be_frozen
750
- end
751
- end
752
-
753
- describe "Matching" do
754
- let(:uri){
755
- Addressable::URI.parse(
756
- "http://example.com/search/an-example-search-query/"
757
- )
758
- }
759
- let(:uri2){
760
- Addressable::URI.parse("http://example.com/a/b/c/")
761
- }
762
- let(:uri3){
763
- Addressable::URI.parse("http://example.com/;a=1;b=2;c=3;first=foo")
764
- }
765
- let(:uri4){
766
- Addressable::URI.parse("http://example.com/?a=1&b=2&c=3&first=foo")
767
- }
768
- let(:uri5){
769
- "http://example.com/foo"
770
- }
771
- context "first uri with ExampleTwoProcessor" do
772
- subject {
773
- Addressable::Template.new(
774
- "http://example.com/search/{query}/"
775
- ).match(uri, ExampleTwoProcessor)
776
- }
777
- its(:variables){ should == ["query"] }
778
- its(:captures){ should == ["an example search query"] }
779
- end
780
-
781
- context "second uri with ExampleTwoProcessor" do
782
- subject {
783
- Addressable::Template.new(
784
- "http://example.com/{first}/{+second}/"
785
- ).match(uri2, ExampleTwoProcessor)
786
- }
787
- its(:variables){ should == ["first", "second"] }
788
- its(:captures){ should == ["a", "b/c"] }
789
- end
790
-
791
- context "second uri with DumbProcessor" do
792
- subject {
793
- Addressable::Template.new(
794
- "http://example.com/{first}/{+second}/"
795
- ).match(uri2, DumbProcessor)
796
- }
797
- its(:variables){ should == ["first", "second"] }
798
- its(:captures){ should == ["a", "b/c"] }
799
- end
800
-
801
- context "second uri" do
802
- subject {
803
- Addressable::Template.new(
804
- "http://example.com/{first}{/second*}/"
805
- ).match(uri2)
806
- }
807
- its(:variables){ should == ["first", "second"] }
808
- its(:captures){ should == ["a", ["b","c"]] }
809
- end
810
- context "third uri" do
811
- subject {
812
- Addressable::Template.new(
813
- "http://example.com/{;hash*,first}"
814
- ).match(uri3)
815
- }
816
- its(:variables){ should == ["hash", "first"] }
817
- its(:captures){ should == [
818
- {"a" => "1", "b" => "2", "c" => "3", "first" => "foo"}, nil] }
819
- end
820
- # Note that this expansion is impossible to revert deterministically - the
821
- # * operator means first could have been a key of hash or a separate key.
822
- # Semantically, a separate key is more likely, but both are possible.
823
- context "fourth uri" do
824
- subject {
825
- Addressable::Template.new(
826
- "http://example.com/{?hash*,first}"
827
- ).match(uri4)
828
- }
829
- its(:variables){ should == ["hash", "first"] }
830
- its(:captures){ should == [
831
- {"a" => "1", "b" => "2", "c" => "3", "first"=> "foo"}, nil] }
832
- end
833
- context "fifth uri" do
834
- subject {
835
- Addressable::Template.new(
836
- "http://example.com/{path}{?hash*,first}"
837
- ).match(uri5)
838
- }
839
- its(:variables){ should == ["path", "hash", "first"] }
840
- its(:captures){ should == ["foo", nil, nil] }
841
- end
842
- end
843
-
844
- describe 'match' do
845
- subject { Addressable::Template.new('http://example.com/first/second/') }
846
- context 'when the URI is the same as the template' do
847
- it 'returns the match data itself with an empty mapping' do
848
- uri = Addressable::URI.parse('http://example.com/first/second/')
849
- match_data = subject.match(uri)
850
- expect(match_data).to be_an Addressable::Template::MatchData
851
- expect(match_data.uri).to eq(uri)
852
- expect(match_data.template).to eq(subject)
853
- expect(match_data.mapping).to be_empty
854
- end
855
- end
856
- end
857
-
858
- describe "extract" do
859
- let(:template) {
860
- Addressable::Template.new(
861
- "http://{host}{/segments*}/{?one,two,bogus}{#fragment}"
862
- )
863
- }
864
- let(:uri){ "http://example.com/a/b/c/?one=1&two=2#foo" }
865
- let(:uri2){ "http://example.com/a/b/c/#foo" }
866
- it "should be able to extract with queries" do
867
- expect(template.extract(uri)).to eq({
868
- "host" => "example.com",
869
- "segments" => %w(a b c),
870
- "one" => "1",
871
- "bogus" => nil,
872
- "two" => "2",
873
- "fragment" => "foo"
874
- })
875
- end
876
- it "should be able to extract without queries" do
877
- expect(template.extract(uri2)).to eq({
878
- "host" => "example.com",
879
- "segments" => %w(a b c),
880
- "one" => nil,
881
- "bogus" => nil,
882
- "two" => nil,
883
- "fragment" => "foo"
884
- })
885
- end
886
-
887
- context "issue #137" do
888
- subject { Addressable::Template.new('/path{?page,per_page}') }
889
-
890
- it "can match empty" do
891
- data = subject.extract("/path")
892
- expect(data["page"]).to eq(nil)
893
- expect(data["per_page"]).to eq(nil)
894
- expect(data.keys.sort).to eq(['page', 'per_page'])
895
- end
896
-
897
- it "can match first var" do
898
- data = subject.extract("/path?page=1")
899
- expect(data["page"]).to eq("1")
900
- expect(data["per_page"]).to eq(nil)
901
- expect(data.keys.sort).to eq(['page', 'per_page'])
902
- end
903
-
904
- it "can match second var" do
905
- data = subject.extract("/path?per_page=1")
906
- expect(data["page"]).to eq(nil)
907
- expect(data["per_page"]).to eq("1")
908
- expect(data.keys.sort).to eq(['page', 'per_page'])
909
- end
910
-
911
- it "can match both vars" do
912
- data = subject.extract("/path?page=2&per_page=1")
913
- expect(data["page"]).to eq("2")
914
- expect(data["per_page"]).to eq("1")
915
- expect(data.keys.sort).to eq(['page', 'per_page'])
916
- end
917
- end
918
- end
919
-
920
- describe "Partial expand with symbols" do
921
- context "partial_expand with two simple values" do
922
- subject {
923
- Addressable::Template.new("http://example.com/{one}/{two}/")
924
- }
925
- it "builds a new pattern" do
926
- expect(subject.partial_expand(:one => "1").pattern).to eq(
927
- "http://example.com/1/{two}/"
928
- )
929
- end
930
- end
931
- context "partial_expand query with missing param in middle" do
932
- subject {
933
- Addressable::Template.new("http://example.com/{?one,two,three}/")
934
- }
935
- it "builds a new pattern" do
936
- expect(subject.partial_expand(:one => "1", :three => "3").pattern).to eq(
937
- "http://example.com/?one=1{&two}&three=3/"
938
- )
939
- end
940
- end
941
- context "partial_expand form style query with missing param at beginning" do
942
- subject {
943
- Addressable::Template.new("http://example.com/{?one,two}/")
944
- }
945
- it "builds a new pattern" do
946
- expect(subject.partial_expand(:two => "2").pattern).to eq(
947
- "http://example.com/?two=2{&one}/"
948
- )
949
- end
950
- end
951
- context "partial_expand with query string" do
952
- subject {
953
- Addressable::Template.new("http://example.com/{?two,one}/")
954
- }
955
- it "builds a new pattern" do
956
- expect(subject.partial_expand(:one => "1").pattern).to eq(
957
- "http://example.com/?one=1{&two}/"
958
- )
959
- end
960
- end
961
- context "partial_expand with path operator" do
962
- subject {
963
- Addressable::Template.new("http://example.com{/one,two}/")
964
- }
965
- it "builds a new pattern" do
966
- expect(subject.partial_expand(:one => "1").pattern).to eq(
967
- "http://example.com/1{/two}/"
968
- )
969
- end
970
- end
971
- end
972
- describe "Partial expand with strings" do
973
- context "partial_expand with two simple values" do
974
- subject {
975
- Addressable::Template.new("http://example.com/{one}/{two}/")
976
- }
977
- it "builds a new pattern" do
978
- expect(subject.partial_expand("one" => "1").pattern).to eq(
979
- "http://example.com/1/{two}/"
980
- )
981
- end
982
- end
983
- context "partial_expand query with missing param in middle" do
984
- subject {
985
- Addressable::Template.new("http://example.com/{?one,two,three}/")
986
- }
987
- it "builds a new pattern" do
988
- expect(subject.partial_expand("one" => "1", "three" => "3").pattern).to eq(
989
- "http://example.com/?one=1{&two}&three=3/"
990
- )
991
- end
992
- end
993
- context "partial_expand with query string" do
994
- subject {
995
- Addressable::Template.new("http://example.com/{?two,one}/")
996
- }
997
- it "builds a new pattern" do
998
- expect(subject.partial_expand("one" => "1").pattern).to eq(
999
- "http://example.com/?one=1{&two}/"
1000
- )
1001
- end
1002
- end
1003
- context "partial_expand with path operator" do
1004
- subject {
1005
- Addressable::Template.new("http://example.com{/one,two}/")
1006
- }
1007
- it "builds a new pattern" do
1008
- expect(subject.partial_expand("one" => "1").pattern).to eq(
1009
- "http://example.com/1{/two}/"
1010
- )
1011
- end
1012
- end
1013
- end
1014
- describe "Expand" do
1015
- context "expand with a processor" do
1016
- subject {
1017
- Addressable::Template.new("http://example.com/search/{query}/")
1018
- }
1019
- it "processes spaces" do
1020
- expect(subject.expand({"query" => "an example search query"},
1021
- ExampleTwoProcessor).to_str).to eq(
1022
- "http://example.com/search/an+example+search+query/"
1023
- )
1024
- end
1025
- it "validates" do
1026
- expect{
1027
- subject.expand({"query" => "Bogus!"},
1028
- ExampleTwoProcessor).to_str
1029
- }.to raise_error(Addressable::Template::InvalidTemplateValueError)
1030
- end
1031
- end
1032
- context "partial_expand query with missing param in middle" do
1033
- subject {
1034
- Addressable::Template.new("http://example.com/{?one,two,three}/")
1035
- }
1036
- it "builds a new pattern" do
1037
- expect(subject.partial_expand("one" => "1", "three" => "3").pattern).to eq(
1038
- "http://example.com/?one=1{&two}&three=3/"
1039
- )
1040
- end
1041
- end
1042
- context "partial_expand with query string" do
1043
- subject {
1044
- Addressable::Template.new("http://example.com/{?two,one}/")
1045
- }
1046
- it "builds a new pattern" do
1047
- expect(subject.partial_expand("one" => "1").pattern).to eq(
1048
- "http://example.com/?one=1{&two}/"
1049
- )
1050
- end
1051
- end
1052
- context "partial_expand with path operator" do
1053
- subject {
1054
- Addressable::Template.new("http://example.com{/one,two}/")
1055
- }
1056
- it "builds a new pattern" do
1057
- expect(subject.partial_expand("one" => "1").pattern).to eq(
1058
- "http://example.com/1{/two}/"
1059
- )
1060
- end
1061
- end
1062
- end
1063
- context "Matching with operators" do
1064
- describe "Level 1:" do
1065
- subject { Addressable::Template.new("foo{foo}/{bar}baz") }
1066
- it "can match" do
1067
- data = subject.match("foofoo/bananabaz")
1068
- expect(data.mapping["foo"]).to eq("foo")
1069
- expect(data.mapping["bar"]).to eq("banana")
1070
- end
1071
- it "can fail" do
1072
- expect(subject.match("bar/foo")).to be_nil
1073
- expect(subject.match("foobaz")).to be_nil
1074
- end
1075
- it "can match empty" do
1076
- data = subject.match("foo/baz")
1077
- expect(data.mapping["foo"]).to eq(nil)
1078
- expect(data.mapping["bar"]).to eq(nil)
1079
- end
1080
- it "lists vars" do
1081
- expect(subject.variables).to eq(["foo", "bar"])
1082
- end
1083
- end
1084
-
1085
- describe "Level 2:" do
1086
- subject { Addressable::Template.new("foo{+foo}{#bar}baz") }
1087
- it "can match" do
1088
- data = subject.match("foo/test/banana#bazbaz")
1089
- expect(data.mapping["foo"]).to eq("/test/banana")
1090
- expect(data.mapping["bar"]).to eq("baz")
1091
- end
1092
- it "can match empty level 2 #" do
1093
- data = subject.match("foo/test/bananabaz")
1094
- expect(data.mapping["foo"]).to eq("/test/banana")
1095
- expect(data.mapping["bar"]).to eq(nil)
1096
- data = subject.match("foo/test/banana#baz")
1097
- expect(data.mapping["foo"]).to eq("/test/banana")
1098
- expect(data.mapping["bar"]).to eq("")
1099
- end
1100
- it "can match empty level 2 +" do
1101
- data = subject.match("foobaz")
1102
- expect(data.mapping["foo"]).to eq(nil)
1103
- expect(data.mapping["bar"]).to eq(nil)
1104
- data = subject.match("foo#barbaz")
1105
- expect(data.mapping["foo"]).to eq(nil)
1106
- expect(data.mapping["bar"]).to eq("bar")
1107
- end
1108
- it "lists vars" do
1109
- expect(subject.variables).to eq(["foo", "bar"])
1110
- end
1111
- end
1112
-
1113
- describe "Level 3:" do
1114
- context "no operator" do
1115
- subject { Addressable::Template.new("foo{foo,bar}baz") }
1116
- it "can match" do
1117
- data = subject.match("foofoo,barbaz")
1118
- expect(data.mapping["foo"]).to eq("foo")
1119
- expect(data.mapping["bar"]).to eq("bar")
1120
- end
1121
- it "lists vars" do
1122
- expect(subject.variables).to eq(["foo", "bar"])
1123
- end
1124
- end
1125
- context "+ operator" do
1126
- subject { Addressable::Template.new("foo{+foo,bar}baz") }
1127
- it "can match" do
1128
- data = subject.match("foofoo/bar,barbaz")
1129
- expect(data.mapping["bar"]).to eq("foo/bar,bar")
1130
- expect(data.mapping["foo"]).to eq("")
1131
- end
1132
- it "lists vars" do
1133
- expect(subject.variables).to eq(["foo", "bar"])
1134
- end
1135
- end
1136
- context ". operator" do
1137
- subject { Addressable::Template.new("foo{.foo,bar}baz") }
1138
- it "can match" do
1139
- data = subject.match("foo.foo.barbaz")
1140
- expect(data.mapping["foo"]).to eq("foo")
1141
- expect(data.mapping["bar"]).to eq("bar")
1142
- end
1143
- it "lists vars" do
1144
- expect(subject.variables).to eq(["foo", "bar"])
1145
- end
1146
- end
1147
- context "/ operator" do
1148
- subject { Addressable::Template.new("foo{/foo,bar}baz") }
1149
- it "can match" do
1150
- data = subject.match("foo/foo/barbaz")
1151
- expect(data.mapping["foo"]).to eq("foo")
1152
- expect(data.mapping["bar"]).to eq("bar")
1153
- end
1154
- it "lists vars" do
1155
- expect(subject.variables).to eq(["foo", "bar"])
1156
- end
1157
- end
1158
- context "; operator" do
1159
- subject { Addressable::Template.new("foo{;foo,bar,baz}baz") }
1160
- it "can match" do
1161
- data = subject.match("foo;foo=bar%20baz;bar=foo;bazbaz")
1162
- expect(data.mapping["foo"]).to eq("bar baz")
1163
- expect(data.mapping["bar"]).to eq("foo")
1164
- expect(data.mapping["baz"]).to eq("")
1165
- end
1166
- it "lists vars" do
1167
- expect(subject.variables).to eq(%w(foo bar baz))
1168
- end
1169
- end
1170
- context "? operator" do
1171
- context "test" do
1172
- subject { Addressable::Template.new("foo{?foo,bar}baz") }
1173
- it "can match" do
1174
- data = subject.match("foo?foo=bar%20baz&bar=foobaz")
1175
- expect(data.mapping["foo"]).to eq("bar baz")
1176
- expect(data.mapping["bar"]).to eq("foo")
1177
- end
1178
- it "lists vars" do
1179
- expect(subject.variables).to eq(%w(foo bar))
1180
- end
1181
- end
1182
-
1183
- context "issue #137" do
1184
- subject { Addressable::Template.new('/path{?page,per_page}') }
1185
-
1186
- it "can match empty" do
1187
- data = subject.match("/path")
1188
- expect(data.mapping["page"]).to eq(nil)
1189
- expect(data.mapping["per_page"]).to eq(nil)
1190
- expect(data.mapping.keys.sort).to eq(['page', 'per_page'])
1191
- end
1192
-
1193
- it "can match first var" do
1194
- data = subject.match("/path?page=1")
1195
- expect(data.mapping["page"]).to eq("1")
1196
- expect(data.mapping["per_page"]).to eq(nil)
1197
- expect(data.mapping.keys.sort).to eq(['page', 'per_page'])
1198
- end
1199
-
1200
- it "can match second var" do
1201
- data = subject.match("/path?per_page=1")
1202
- expect(data.mapping["page"]).to eq(nil)
1203
- expect(data.mapping["per_page"]).to eq("1")
1204
- expect(data.mapping.keys.sort).to eq(['page', 'per_page'])
1205
- end
1206
-
1207
- it "can match both vars" do
1208
- data = subject.match("/path?page=2&per_page=1")
1209
- expect(data.mapping["page"]).to eq("2")
1210
- expect(data.mapping["per_page"]).to eq("1")
1211
- expect(data.mapping.keys.sort).to eq(['page', 'per_page'])
1212
- end
1213
- end
1214
-
1215
- context "issue #71" do
1216
- subject { Addressable::Template.new("http://cyberscore.dev/api/users{?username}") }
1217
- it "can match" do
1218
- data = subject.match("http://cyberscore.dev/api/users?username=foobaz")
1219
- expect(data.mapping["username"]).to eq("foobaz")
1220
- end
1221
- it "lists vars" do
1222
- expect(subject.variables).to eq(%w(username))
1223
- expect(subject.keys).to eq(%w(username))
1224
- end
1225
- end
1226
- end
1227
- context "& operator" do
1228
- subject { Addressable::Template.new("foo{&foo,bar}baz") }
1229
- it "can match" do
1230
- data = subject.match("foo&foo=bar%20baz&bar=foobaz")
1231
- expect(data.mapping["foo"]).to eq("bar baz")
1232
- expect(data.mapping["bar"]).to eq("foo")
1233
- end
1234
- it "lists vars" do
1235
- expect(subject.variables).to eq(%w(foo bar))
1236
- end
1237
- end
1238
- end
1239
- end
1240
-
1241
- context "support regexes:" do
1242
- context "EXPRESSION" do
1243
- subject { Addressable::Template::EXPRESSION }
1244
- it "should be able to match an expression" do
1245
- expect(subject).to match("{foo}")
1246
- expect(subject).to match("{foo,9}")
1247
- expect(subject).to match("{foo.bar,baz}")
1248
- expect(subject).to match("{+foo.bar,baz}")
1249
- expect(subject).to match("{foo,foo%20bar}")
1250
- expect(subject).to match("{#foo:20,baz*}")
1251
- expect(subject).to match("stuff{#foo:20,baz*}things")
1252
- end
1253
- it "should fail on non vars" do
1254
- expect(subject).not_to match("!{foo")
1255
- expect(subject).not_to match("{foo.bar.}")
1256
- expect(subject).not_to match("!{}")
1257
- end
1258
- end
1259
- context "VARNAME" do
1260
- subject { Addressable::Template::VARNAME }
1261
- it "should be able to match a variable" do
1262
- expect(subject).to match("foo")
1263
- expect(subject).to match("9")
1264
- expect(subject).to match("foo.bar")
1265
- expect(subject).to match("foo_bar")
1266
- expect(subject).to match("foo_bar.baz")
1267
- expect(subject).to match("foo%20bar")
1268
- expect(subject).to match("foo%20bar.baz")
1269
- end
1270
- it "should fail on non vars" do
1271
- expect(subject).not_to match("!foo")
1272
- expect(subject).not_to match("foo.bar.")
1273
- expect(subject).not_to match("foo%2%00bar")
1274
- expect(subject).not_to match("foo_ba%r")
1275
- expect(subject).not_to match("foo_bar*")
1276
- expect(subject).not_to match("foo_bar:20")
1277
- end
1278
- end
1279
- context "VARIABLE_LIST" do
1280
- subject { Addressable::Template::VARIABLE_LIST }
1281
- it "should be able to match a variable list" do
1282
- expect(subject).to match("foo,bar")
1283
- expect(subject).to match("foo")
1284
- expect(subject).to match("foo,bar*,baz")
1285
- expect(subject).to match("foo.bar,bar_baz*,baz:12")
1286
- end
1287
- it "should fail on non vars" do
1288
- expect(subject).not_to match(",foo,bar*,baz")
1289
- expect(subject).not_to match("foo,*bar,baz")
1290
- expect(subject).not_to match("foo,,bar*,baz")
1291
- end
1292
- end
1293
- context "VARSPEC" do
1294
- subject { Addressable::Template::VARSPEC }
1295
- it "should be able to match a variable with modifier" do
1296
- expect(subject).to match("9:8")
1297
- expect(subject).to match("foo.bar*")
1298
- expect(subject).to match("foo_bar:12")
1299
- expect(subject).to match("foo_bar.baz*")
1300
- expect(subject).to match("foo%20bar:12")
1301
- expect(subject).to match("foo%20bar.baz*")
1302
- end
1303
- it "should fail on non vars" do
1304
- expect(subject).not_to match("!foo")
1305
- expect(subject).not_to match("*foo")
1306
- expect(subject).not_to match("fo*o")
1307
- expect(subject).not_to match("fo:o")
1308
- expect(subject).not_to match("foo:")
1309
- end
1310
- end
1311
- end
1312
- end
1313
-
1314
- describe Addressable::Template::MatchData do
1315
- let(:template) { Addressable::Template.new('{foo}/{bar}') }
1316
- subject(:its) { template.match('ab/cd') }
1317
- its(:uri) { should == Addressable::URI.parse('ab/cd') }
1318
- its(:template) { should == template }
1319
- its(:mapping) { should == { 'foo' => 'ab', 'bar' => 'cd' } }
1320
- its(:variables) { should == ['foo', 'bar'] }
1321
- its(:keys) { should == ['foo', 'bar'] }
1322
- its(:names) { should == ['foo', 'bar'] }
1323
- its(:values) { should == ['ab', 'cd'] }
1324
- its(:captures) { should == ['ab', 'cd'] }
1325
- its(:to_a) { should == ['ab/cd', 'ab', 'cd'] }
1326
- its(:to_s) { should == 'ab/cd' }
1327
- its(:string) { should == its.to_s }
1328
- its(:pre_match) { should == "" }
1329
- its(:post_match) { should == "" }
1330
-
1331
- describe 'values_at' do
1332
- it 'returns an array with the values' do
1333
- expect(its.values_at(0, 2)).to eq(['ab/cd', 'cd'])
1334
- end
1335
- it 'allows mixing integer an string keys' do
1336
- expect(its.values_at('foo', 1)).to eq(['ab', 'ab'])
1337
- end
1338
- it 'accepts unknown keys' do
1339
- expect(its.values_at('baz', 'foo')).to eq([nil, 'ab'])
1340
- end
1341
- end
1342
-
1343
- describe '[]' do
1344
- context 'string key' do
1345
- it 'returns the corresponding capture' do
1346
- expect(its['foo']).to eq('ab')
1347
- expect(its['bar']).to eq('cd')
1348
- end
1349
- it 'returns nil for unknown keys' do
1350
- expect(its['baz']).to be_nil
1351
- end
1352
- end
1353
- context 'symbol key' do
1354
- it 'returns the corresponding capture' do
1355
- expect(its[:foo]).to eq('ab')
1356
- expect(its[:bar]).to eq('cd')
1357
- end
1358
- it 'returns nil for unknown keys' do
1359
- expect(its[:baz]).to be_nil
1360
- end
1361
- end
1362
- context 'integer key' do
1363
- it 'returns the full URI for index 0' do
1364
- expect(its[0]).to eq('ab/cd')
1365
- end
1366
- it 'returns the corresponding capture' do
1367
- expect(its[1]).to eq('ab')
1368
- expect(its[2]).to eq('cd')
1369
- end
1370
- it 'returns nil for unknown keys' do
1371
- expect(its[3]).to be_nil
1372
- end
1373
- end
1374
- context 'other key' do
1375
- it 'raises an exception' do
1376
- expect { its[Object.new] }.to raise_error(TypeError)
1377
- end
1378
- end
1379
- context 'with length' do
1380
- it 'returns an array starting at index with given length' do
1381
- expect(its[0, 2]).to eq(['ab/cd', 'ab'])
1382
- expect(its[2, 1]).to eq(['cd'])
1383
- end
1384
- end
1385
- end
1386
- end