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