addressable 2.8.1 → 2.8.7

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.
@@ -23,7 +23,7 @@ if !defined?(Addressable::VERSION)
23
23
  module VERSION
24
24
  MAJOR = 2
25
25
  MINOR = 8
26
- TINY = 1
26
+ TINY = 7
27
27
 
28
28
  STRING = [MAJOR, MINOR, TINY].join('.')
29
29
  end
@@ -38,6 +38,12 @@ shared_examples_for "converting from unicode to ASCII" do
38
38
  )).to eq("www.xn--8ws00zhy3a.com")
39
39
  end
40
40
 
41
+ it "also accepts unicode strings encoded as ascii-8bit" do
42
+ expect(Addressable::IDNA.to_ascii(
43
+ "www.詹姆斯.com".b
44
+ )).to eq("www.xn--8ws00zhy3a.com")
45
+ end
46
+
41
47
  it "should convert 'www.Iñtërnâtiônàlizætiøn.com' correctly" do
42
48
  "www.Iñtërnâtiônàlizætiøn.com"
43
49
  expect(Addressable::IDNA.to_ascii(
@@ -249,11 +255,6 @@ shared_examples_for "converting from ASCII to unicode" do
249
255
  "example..host"
250
256
  )).to eq("example..host")
251
257
  end
252
-
253
- it "should normalize 'string' correctly" do
254
- expect(Addressable::IDNA.unicode_normalize_kc(:'string')).to eq("string")
255
- expect(Addressable::IDNA.unicode_normalize_kc("string")).to eq("string")
256
- end
257
258
  end
258
259
 
259
260
  describe Addressable::IDNA, "when using the pure-Ruby implementation" do
@@ -26,11 +26,7 @@ shared_examples_for 'expands' do |tests|
26
26
  exp = expansion.is_a?(Array) ? expansion.first : expansion
27
27
  it "#{template} to #{exp}" do
28
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
29
+ expect(tmpl.to_str).to eq(expansion)
34
30
  end
35
31
  end
36
32
  end
@@ -209,7 +205,7 @@ describe "Level 4" do
209
205
  :path => "/foo/bar",
210
206
  :semi => ";",
211
207
  :list => %w(red green blue),
212
- :keys => {"semi" => ';', "dot" => '.', "comma" => ','}
208
+ :keys => {"semi" => ';', "dot" => '.', :comma => ','}
213
209
  }
214
210
  }
215
211
  context "Expansion with value modifiers" do
@@ -218,22 +214,8 @@ describe "Level 4" do
218
214
  '{var:30}' => 'value',
219
215
  '{list}' => 'red,green,blue',
220
216
  '{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
- ]
217
+ '{keys}' => 'semi,%3B,dot,.,comma,%2C',
218
+ '{keys*}' => 'semi=%3B,dot=.,comma=%2C',
237
219
  }
238
220
  end
239
221
  context "Operator + with value modifiers" do
@@ -241,22 +223,8 @@ describe "Level 4" do
241
223
  '{+path:6}/here' => '/foo/b/here',
242
224
  '{+list}' => 'red,green,blue',
243
225
  '{+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
- ]
226
+ '{+keys}' => 'semi,;,dot,.,comma,,',
227
+ '{+keys*}' => 'semi=;,dot=.,comma=,',
260
228
  }
261
229
  end
262
230
  context "Operator # with value modifiers" do
@@ -264,22 +232,8 @@ describe "Level 4" do
264
232
  '{#path:6}/here' => '#/foo/b/here',
265
233
  '{#list}' => '#red,green,blue',
266
234
  '{#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
- ]
235
+ '{#keys}' => '#semi,;,dot,.,comma,,',
236
+ '{#keys*}' => '#semi=;,dot=.,comma=,',
283
237
  }
284
238
  end
285
239
  context "Operator . with value modifiers" do
@@ -287,22 +241,8 @@ describe "Level 4" do
287
241
  'X{.var:3}' => 'X.val',
288
242
  'X{.list}' => 'X.red,green,blue',
289
243
  '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
- ]
244
+ 'X{.keys}' => 'X.semi,%3B,dot,.,comma,%2C',
245
+ 'X{.keys*}' => 'X.semi=%3B.dot=..comma=%2C',
306
246
  }
307
247
  end
308
248
  context "Operator / with value modifiers" do
@@ -311,22 +251,8 @@ describe "Level 4" do
311
251
  '{/list}' => '/red,green,blue',
312
252
  '{/list*}' => '/red/green/blue',
313
253
  '{/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
- ]
254
+ '{/keys}' => '/semi,%3B,dot,.,comma,%2C',
255
+ '{/keys*}' => '/semi=%3B/dot=./comma=%2C',
330
256
  }
331
257
  end
332
258
  context "Operator ; with value modifiers" do
@@ -334,22 +260,8 @@ describe "Level 4" do
334
260
  '{;hello:5}' => ';hello=Hello',
335
261
  '{;list}' => ';list=red,green,blue',
336
262
  '{;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
- ]
263
+ '{;keys}' => ';keys=semi,%3B,dot,.,comma,%2C',
264
+ '{;keys*}' => ';semi=%3B;dot=.;comma=%2C',
353
265
  }
354
266
  end
355
267
  context "Operator ? with value modifiers" do
@@ -357,22 +269,8 @@ describe "Level 4" do
357
269
  '{?var:3}' => '?var=val',
358
270
  '{?list}' => '?list=red,green,blue',
359
271
  '{?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
- ]
272
+ '{?keys}' => '?keys=semi,%3B,dot,.,comma,%2C',
273
+ '{?keys*}' => '?semi=%3B&dot=.&comma=%2C',
376
274
  }
377
275
  end
378
276
  context "Operator & with value modifiers" do
@@ -380,22 +278,8 @@ describe "Level 4" do
380
278
  '{&var:3}' => '&var=val',
381
279
  '{&list}' => '&list=red,green,blue',
382
280
  '{&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
- ]
281
+ '{&keys}' => '&keys=semi,%3B,dot,.,comma,%2C',
282
+ '{&keys*}' => '&semi=%3B&dot=.&comma=%2C',
399
283
  }
400
284
  end
401
285
  end
@@ -404,7 +288,7 @@ describe "Modifiers" do
404
288
  {
405
289
  :var => "value",
406
290
  :semi => ";",
407
- :year => %w(1965 2000 2012),
291
+ :year => [1965, 2000, 2012],
408
292
  :dom => %w(example com)
409
293
  }
410
294
  }
@@ -437,7 +321,7 @@ describe "Expansion" do
437
321
  :base => "http://example.com/home/",
438
322
  :path => "/foo/bar",
439
323
  :list => ["red", "green", "blue"],
440
- :keys => {"semi" => ";","dot" => ".","comma" => ","},
324
+ :keys => {"semi" => ";","dot" => ".",:comma => ","},
441
325
  :v => "6",
442
326
  :x => "1024",
443
327
  :y => "768",
@@ -475,22 +359,8 @@ describe "Expansion" do
475
359
  '{var:30}' => 'value',
476
360
  '{list}' => 'red,green,blue',
477
361
  '{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
- ]
362
+ '{keys}' => 'semi,%3B,dot,.,comma,%2C',
363
+ '{keys*}' => 'semi=%3B,dot=.,comma=%2C',
494
364
  }
495
365
  end
496
366
  context "reserved expansion (+)" do
@@ -510,22 +380,8 @@ describe "Expansion" do
510
380
  '{+path:6}/here' => '/foo/b/here',
511
381
  '{+list}' => 'red,green,blue',
512
382
  '{+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
- ]
383
+ '{+keys}' => 'semi,;,dot,.,comma,,',
384
+ '{+keys*}' => 'semi=;,dot=.,comma=,',
529
385
  }
530
386
  end
531
387
  context "fragment expansion (#)" do
@@ -540,22 +396,8 @@ describe "Expansion" do
540
396
  '{#path:6}/here' => '#/foo/b/here',
541
397
  '{#list}' => '#red,green,blue',
542
398
  '{#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
- ]
399
+ '{#keys}' => '#semi,;,dot,.,comma,,',
400
+ '{#keys*}' => '#semi=;,dot=.,comma=,',
559
401
  }
560
402
  end
561
403
  context "label expansion (.)" do
@@ -570,22 +412,8 @@ describe "Expansion" do
570
412
  'X{.var:3}' => 'X.val',
571
413
  'X{.list}' => 'X.red,green,blue',
572
414
  '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
- ],
415
+ 'X{.keys}' => 'X.semi,%3B,dot,.,comma,%2C',
416
+ 'X{.keys*}' => 'X.semi=%3B.dot=..comma=%2C',
589
417
  'X{.empty_keys}' => 'X',
590
418
  'X{.empty_keys*}' => 'X'
591
419
  }
@@ -604,22 +432,8 @@ describe "Expansion" do
604
432
  '{/list}' => '/red,green,blue',
605
433
  '{/list*}' => '/red/green/blue',
606
434
  '{/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
- ]
435
+ '{/keys}' => '/semi,%3B,dot,.,comma,%2C',
436
+ '{/keys*}' => '/semi=%3B/dot=./comma=%2C',
623
437
  }
624
438
  end
625
439
  context "path-style expansion (;)" do
@@ -635,22 +449,8 @@ describe "Expansion" do
635
449
  '{;hello:5}' => ';hello=Hello',
636
450
  '{;list}' => ';list=red,green,blue',
637
451
  '{;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
- ]
452
+ '{;keys}' => ';keys=semi,%3B,dot,.,comma,%2C',
453
+ '{;keys*}' => ';semi=%3B;dot=.;comma=%2C',
654
454
  }
655
455
  end
656
456
  context "form query expansion (?)" do
@@ -663,22 +463,8 @@ describe "Expansion" do
663
463
  '{?var:3}' => '?var=val',
664
464
  '{?list}' => '?list=red,green,blue',
665
465
  '{?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
- ]
466
+ '{?keys}' => '?keys=semi,%3B,dot,.,comma,%2C',
467
+ '{?keys*}' => '?semi=%3B&dot=.&comma=%2C',
682
468
  }
683
469
  end
684
470
  context "form query expansion (&)" do
@@ -691,22 +477,8 @@ describe "Expansion" do
691
477
  '{&var:3}' => '&var=val',
692
478
  '{&list}' => '&list=red,green,blue',
693
479
  '{&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
- ]
480
+ '{&keys}' => '&keys=semi,%3B,dot,.,comma,%2C',
481
+ '{&keys*}' => '&semi=%3B&dot=.&comma=%2C',
710
482
  }
711
483
  end
712
484
  context "non-string key in match data" do
@@ -1021,6 +793,19 @@ describe Addressable::Template do
1021
793
  )
1022
794
  end
1023
795
 
796
+ it "normalizes as unicode even with wrong encoding specified" do
797
+ template = subject.partial_expand("query" => "Cafe\u0301".b)
798
+ expect(template.pattern).to eq(
799
+ "http://example.com/{resource}/Caf%C3%A9/"
800
+ )
801
+ end
802
+
803
+ it "raises on invalid unicode input" do
804
+ expect {
805
+ subject.partial_expand("query" => "M\xE9thode".b)
806
+ }.to raise_error(ArgumentError, "invalid byte sequence in UTF-8")
807
+ end
808
+
1024
809
  it "does not normalize unicode when byte semantics requested" do
1025
810
  template = subject.partial_expand({"query" => "Cafe\u0301"}, nil, false)
1026
811
  expect(template.pattern).to eq(
@@ -1081,6 +866,17 @@ describe Addressable::Template do
1081
866
  expect(uri).to eq("http://example.com/search/Caf%C3%A9/")
1082
867
  end
1083
868
 
869
+ it "normalizes as unicode even with wrong encoding specified" do
870
+ uri = subject.expand("query" => "Cafe\u0301".b).to_str
871
+ expect(uri).to eq("http://example.com/search/Caf%C3%A9/")
872
+ end
873
+
874
+ it "raises on invalid unicode input" do
875
+ expect {
876
+ subject.expand("query" => "M\xE9thode".b).to_str
877
+ }.to raise_error(ArgumentError, "invalid byte sequence in UTF-8")
878
+ end
879
+
1084
880
  it "does not normalize unicode when byte semantics requested" do
1085
881
  uri = subject.expand({ "query" => "Cafe\u0301" }, nil, false).to_str
1086
882
  expect(uri).to eq("http://example.com/search/Cafe%CC%81/")
@@ -20,6 +20,7 @@ require "spec_helper"
20
20
  require "addressable/uri"
21
21
  require "uri"
22
22
  require "ipaddr"
23
+ require "yaml"
23
24
 
24
25
  if !"".respond_to?("force_encoding")
25
26
  class String
@@ -3021,6 +3022,20 @@ describe Addressable::URI, "when parsed from " +
3021
3022
  end
3022
3023
  end
3023
3024
 
3025
+ describe Addressable::URI, "when parsed with empty port" do
3026
+ subject(:uri) do
3027
+ Addressable::URI.parse("//example.com:")
3028
+ end
3029
+
3030
+ it "should not infer a port" do
3031
+ expect(uri.port).to be(nil)
3032
+ end
3033
+
3034
+ it "should have a site value of '//example.com'" do
3035
+ expect(uri.site).to eq("//example.com")
3036
+ end
3037
+ end
3038
+
3024
3039
  describe Addressable::URI, "when parsed from " +
3025
3040
  "'http://example.com/%2E/'" do
3026
3041
  before do
@@ -5939,6 +5954,26 @@ describe Addressable::URI, "when normalizing a path with an encoded slash" do
5939
5954
  end
5940
5955
  end
5941
5956
 
5957
+ describe Addressable::URI, "when normalizing a path with special unicode" do
5958
+ it "does not stop at or ignore null bytes" do
5959
+ expect(Addressable::URI.parse("/path%00segment/").normalize.path).to eq(
5960
+ "/path%00segment/"
5961
+ )
5962
+ end
5963
+
5964
+ it "does apply NFC unicode normalization" do
5965
+ expect(Addressable::URI.parse("/%E2%84%A6").normalize.path).to eq(
5966
+ "/%CE%A9"
5967
+ )
5968
+ end
5969
+
5970
+ it "does not apply NFKC unicode normalization" do
5971
+ expect(Addressable::URI.parse("/%C2%AF%C2%A0").normalize.path).to eq(
5972
+ "/%C2%AF%C2%A0"
5973
+ )
5974
+ end
5975
+ end
5976
+
5942
5977
  describe Addressable::URI, "when normalizing a partially encoded string" do
5943
5978
  it "should result in correct percent encoded sequence" do
5944
5979
  expect(Addressable::URI.normalize_component(
@@ -6734,6 +6769,37 @@ describe Addressable::URI, "when initializing a subclass of Addressable::URI" do
6734
6769
  end
6735
6770
  end
6736
6771
 
6772
+ describe Addressable::URI, "support serialization roundtrip" do
6773
+ before do
6774
+ @uri = Addressable::URI.new(
6775
+ :scheme => "http",
6776
+ :user => "user",
6777
+ :password => "password",
6778
+ :host => "example.com",
6779
+ :port => 80,
6780
+ :path => "/path",
6781
+ :query => "query=value",
6782
+ :fragment => "fragment"
6783
+ )
6784
+ end
6785
+
6786
+ it "is in a working state after being serialized with Marshal" do
6787
+ @uri = Addressable::URI.parse("http://example.com")
6788
+ cloned_uri = Marshal.load(Marshal.dump(@uri))
6789
+ expect(cloned_uri.normalized_scheme).to be == @uri.normalized_scheme
6790
+ end
6791
+
6792
+ it "is in a working state after being serialized with YAML" do
6793
+ @uri = Addressable::URI.parse("http://example.com")
6794
+ cloned_uri = if YAML.respond_to?(:unsafe_load)
6795
+ YAML.unsafe_load(YAML.dump(@uri))
6796
+ else
6797
+ YAML.load(YAML.dump(@uri))
6798
+ end
6799
+ expect(cloned_uri.normalized_scheme).to be == @uri.normalized_scheme
6800
+ end
6801
+ end
6802
+
6737
6803
  describe Addressable::URI, "when initialized in a non-main `Ractor`" do
6738
6804
  it "should have the same value as if used in the main `Ractor`" do
6739
6805
  pending("Ruby 3.0+ for `Ractor` support") unless defined?(Ractor)
@@ -6743,3 +6809,32 @@ describe Addressable::URI, "when initialized in a non-main `Ractor`" do
6743
6809
  ).to eq(main)
6744
6810
  end
6745
6811
  end
6812
+
6813
+ describe Addressable::URI, "when deferring validation" do
6814
+ subject(:deferred) { uri.instance_variable_get(:@validation_deferred) }
6815
+
6816
+ let(:uri) { Addressable::URI.parse("http://example.com") }
6817
+
6818
+ it "defers validation within the block" do
6819
+ uri.defer_validation do
6820
+ expect(deferred).to be true
6821
+ end
6822
+ end
6823
+
6824
+ it "always resets deferral afterward" do
6825
+ expect { uri.defer_validation { raise "boom" } }.to raise_error("boom")
6826
+ expect(deferred).to be false
6827
+ end
6828
+
6829
+ it "returns nil" do
6830
+ res = uri.defer_validation {}
6831
+ expect(res).to be nil
6832
+ end
6833
+ end
6834
+
6835
+ describe Addressable::URI, "YAML safe loading" do
6836
+ it "doesn't serialize anonymous objects" do
6837
+ url = Addressable::URI.parse("http://example.com/")
6838
+ expect(YAML.dump(url)).to_not include("!ruby/object {}")
6839
+ end
6840
+ end
data/tasks/gem.rake CHANGED
@@ -21,7 +21,7 @@ namespace :gem do
21
21
 
22
22
  s.required_ruby_version = ">= 2.2"
23
23
 
24
- s.add_runtime_dependency "public_suffix", ">= 2.0.2", "< 6.0"
24
+ s.add_runtime_dependency "public_suffix", ">= 2.0.2", "< 7.0"
25
25
  s.add_development_dependency "bundler", ">= 1.0", "< 3.0"
26
26
 
27
27
  s.require_path = "lib"
@@ -31,7 +31,7 @@ namespace :gem do
31
31
  s.homepage = "https://github.com/sporkmonger/addressable"
32
32
  s.license = "Apache-2.0"
33
33
  s.metadata = {
34
- "changelog_uri" => "https://github.com/sporkmonger/addressable/blob/main/CHANGELOG.md"
34
+ "changelog_uri" => "https://github.com/sporkmonger/addressable/blob/main/CHANGELOG.md#v#{PKG_VERSION}"
35
35
  }
36
36
  end
37
37
 
@@ -56,7 +56,7 @@ namespace :gem do
56
56
 
57
57
  desc "Install the gem"
58
58
  task :install => ["clobber", "gem:package"] do
59
- sh "#{SUDO} gem install --local pkg/#{GEM_SPEC.full_name}"
59
+ sh "gem install --local ./pkg/#{GEM_SPEC.full_name}.gem"
60
60
  end
61
61
 
62
62
  desc "Uninstall the gem"
@@ -65,7 +65,7 @@ namespace :gem do
65
65
  if installed_list &&
66
66
  (installed_list.collect { |s| s.version.to_s}.include?(PKG_VERSION))
67
67
  sh(
68
- "#{SUDO} gem uninstall --version '#{PKG_VERSION}' " +
68
+ "gem uninstall --version '#{PKG_VERSION}' " +
69
69
  "--ignore-dependencies --executables #{PKG_NAME}"
70
70
  )
71
71
  end