addressable 2.3.5 → 2.3.6

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of addressable might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7469c2a80add393372ae8c44de978834410a65fc
4
- data.tar.gz: ff31775eb9800b5aa84260a06c7fb6b6c93c855e
3
+ metadata.gz: c062f20a75939191f680842716b9ce79816e8952
4
+ data.tar.gz: 4ff3027264ee6f61fe887f1035c4fa7c472f7c90
5
5
  SHA512:
6
- metadata.gz: d0542072bdbf9520eed193aa4b8fddb95bd8869662ec23566529bb6ecf9688ccaba3dd4b77bdcea889862d7947a71b9bf4770dbc6eb872cc84b976f781bfd5f2
7
- data.tar.gz: 39ca65c92ecdc6d4891c794e56876e7a3923182c1de78691c9e0b794eea0d93ffe100766706825a5abefd911ac3f392687992eb04de9bbfd44d33b428fb2d6d4
6
+ metadata.gz: 26da95b6a6dd459054e700fa3ff906fbc5512dcc0ad2b3cb47e0b5a1a05d2722767605b8f62f044534425ffa4485a53e8132a816792136b37e80c3ff0c20bfbf
7
+ data.tar.gz: 9a0d4766e4faeb57353a6d14524e31610e77b84dd9dda33d51ba472db803197cc2989f3c6dc08623ebbc8e95850e331d8a065b9483483a8e78223c3887381283
@@ -1,3 +1,12 @@
1
+ # Addressable 2.3.6
2
+ - normalization drops empty query string
3
+ - better handling in template extract for missing values
4
+ - template modifier for `'?'` now treated as optional
5
+ - fixed issue where character class parameters were modified
6
+ - templates can now be tested for equality
7
+ - added `:sorted` option to normalization of query strings
8
+ - fixed issue with normalization of hosts given in `'example.com.'` form
9
+
1
10
  # Addressable 2.3.5
2
11
  - added Addressable::URI#empty? method
3
12
  - Addressable::URI#hostname methods now strip square brackets from IPv6 hosts
@@ -149,11 +158,11 @@
149
158
  - improved normalization
150
159
  - fixed bug in joining algorithm
151
160
  - updated specifications
152
-
161
+
153
162
  # Addressable 0.1.1
154
163
  - updated documentation
155
164
  - added URI Template variable extraction
156
-
165
+
157
166
  # Addressable 0.1.0
158
167
  - initial release
159
168
  - implementation based on RFC 3986, 3987
data/Gemfile CHANGED
@@ -16,4 +16,13 @@ end
16
16
  gem 'idn', :platform => :mri_18
17
17
  gem 'idn-ruby', :platform => :mri_19
18
18
 
19
+ platforms :mri_18 do
20
+ gem 'mime-types', '~> 1.25'
21
+ end
22
+
23
+ platforms :rbx do
24
+ gem 'rubysl', '~> 2.0'
25
+ gem 'rubinius-coverage'
26
+ end
27
+
19
28
  gemspec
data/README.md CHANGED
@@ -98,8 +98,5 @@ idn gem:
98
98
  ```console
99
99
  $ sudo apt-get install idn # Debian/Ubuntu
100
100
  $ sudo brew install libidn # OS X
101
- $ sudo gem install idn
101
+ $ sudo gem install idn-ruby
102
102
  ```
103
-
104
- **NOTE:** Native IDN support appears to be broken in Ruby 1.9.x. The IDN gem
105
- hasn't been updated in years.
@@ -250,6 +250,26 @@ module Addressable
250
250
  self.class.to_s, self.object_id, self.pattern)
251
251
  end
252
252
 
253
+ ##
254
+ # Returns <code>true</code> if the Template objects are equal. This method
255
+ # does NOT normalize either Template before doing the comparison.
256
+ #
257
+ # @param [Object] template The Template to compare.
258
+ #
259
+ # @return [TrueClass, FalseClass]
260
+ # <code>true</code> if the Templates are equivalent, <code>false</code>
261
+ # otherwise.
262
+ def ==(template)
263
+ return false unless template.kind_of?(Template)
264
+ return self.pattern == template.pattern
265
+ end
266
+
267
+ ##
268
+ # Addressable::Template makes no distinction between `==` and `eql?`.
269
+ #
270
+ # @see #==
271
+ alias_method :eql?, :==
272
+
253
273
  ##
254
274
  # Extracts a mapping from the URI using a URI Template pattern.
255
275
  #
@@ -397,6 +417,7 @@ module Addressable
397
417
  _, operator, varlist = *expansion.match(EXPRESSION)
398
418
  varlist.split(',').each do |varspec|
399
419
  _, name, modifier = *varspec.match(VARSPEC)
420
+ mapping[name] ||= nil
400
421
  case operator
401
422
  when nil, '+', '#', '/', '.'
402
423
  unparsed_value = unparsed_values[index]
@@ -405,12 +426,14 @@ module Addressable
405
426
  value = value.split(JOINERS[operator]) if value && modifier == '*'
406
427
  when ';', '?', '&'
407
428
  if modifier == '*'
408
- value = unparsed_values[index].split(JOINERS[operator])
409
- value = value.inject({}) do |acc, v|
410
- key, val = v.split('=')
411
- val = "" if val.nil?
412
- acc[key] = val
413
- acc
429
+ if unparsed_values[index]
430
+ value = unparsed_values[index].split(JOINERS[operator])
431
+ value = value.inject({}) do |acc, v|
432
+ key, val = v.split('=')
433
+ val = "" if val.nil?
434
+ acc[key] = val
435
+ acc
436
+ end
414
437
  end
415
438
  else
416
439
  if (unparsed_values[index])
@@ -435,10 +458,9 @@ module Addressable
435
458
  value = Addressable::URI.unencode_component(value)
436
459
  end
437
460
  end
438
- if mapping[name] == nil || mapping[name] == value
461
+ if !mapping.has_key?(name) || mapping[name].nil?
462
+ # Doesn't exist, set to value (even if value is nil)
439
463
  mapping[name] = value
440
- else
441
- return nil
442
464
  end
443
465
  index = index + 1
444
466
  end
@@ -872,10 +894,12 @@ module Addressable
872
894
  _, operator, varlist = *expansion.match(EXPRESSION)
873
895
  leader = Regexp.escape(LEADERS.fetch(operator, ''))
874
896
  joiner = Regexp.escape(JOINERS.fetch(operator, ','))
875
- leader + varlist.split(',').map do |varspec|
897
+ combined = varlist.split(',').map do |varspec|
876
898
  _, name, modifier = *varspec.match(VARSPEC)
877
- if processor != nil && processor.respond_to?(:match)
878
- "(#{ processor.match(name) })"
899
+
900
+ result = processor && processor.respond_to?(:match) ? processor.match(name) : nil
901
+ if result
902
+ "(#{ result })"
879
903
  else
880
904
  group = case operator
881
905
  when '+'
@@ -902,6 +926,7 @@ module Addressable
902
926
  end
903
927
  end
904
928
  end.join("#{joiner}?")
929
+ "(?:|#{leader}#{combined})"
905
930
  end
906
931
 
907
932
  # Ensure that the regular expression matches the whole URI.
@@ -162,6 +162,15 @@ module Addressable
162
162
  return nil unless uri
163
163
  # If a URI object is passed, just return itself.
164
164
  return uri.dup if uri.kind_of?(self)
165
+
166
+ # If a URI object of the Ruby standard library variety is passed,
167
+ # convert it to a string, then parse the string.
168
+ # We do the check this way because we don't want to accidentally
169
+ # cause a missing constant exception to be thrown.
170
+ if uri.class.name =~ /^URI\b/
171
+ uri = uri.to_s
172
+ end
173
+
165
174
  if !uri.respond_to?(:to_str)
166
175
  raise TypeError, "Can't convert #{uri.class} into String."
167
176
  end
@@ -415,8 +424,13 @@ module Addressable
415
424
  "Expected Class (String or Addressable::URI), " +
416
425
  "got #{return_type.inspect}"
417
426
  end
418
- result = uri.gsub(/%[0-9a-f]{2}/i) do |sequence|
427
+ uri = uri.dup
428
+ # Seriously, only use UTF-8. I'm really not kidding!
429
+ uri.force_encoding("utf-8") if uri.respond_to?(:force_encoding)
430
+ leave_encoded.force_encoding("utf-8") if leave_encoded.respond_to?(:force_encoding)
431
+ result = uri.gsub(/%[0-9a-f]{2}/iu) do |sequence|
419
432
  c = sequence[1..3].to_i(16).chr
433
+ c.force_encoding("utf-8") if c.respond_to?(:force_encoding)
420
434
  leave_encoded.include?(c) ? sequence : c
421
435
  end
422
436
  result.force_encoding("utf-8") if result.respond_to?(:force_encoding)
@@ -496,7 +510,7 @@ module Addressable
496
510
  end
497
511
  if character_class.kind_of?(String)
498
512
  leave_re = if leave_encoded.length > 0
499
- character_class << '%'
513
+ character_class = "#{character_class}%" unless character_class.include?('%')
500
514
 
501
515
  "|%(?!#{leave_encoded.chars.map do |char|
502
516
  seq = char.unpack('C*').map { |c| '%02x' % c }.join
@@ -522,6 +536,9 @@ module Addressable
522
536
  rescue ArgumentError
523
537
  encoded = self.encode_component(unencoded)
524
538
  end
539
+ if encoded.respond_to?(:force_encoding)
540
+ encoded.force_encoding(Encoding::UTF_8)
541
+ end
525
542
  return encoded
526
543
  end
527
544
 
@@ -1049,8 +1066,8 @@ module Addressable
1049
1066
  result = ::Addressable::IDNA.to_ascii(
1050
1067
  URI.unencode_component(self.host.strip.downcase)
1051
1068
  )
1052
- if result[-1..-1] == "."
1053
- # Trailing dots are unnecessary
1069
+ if result =~ /[^\.]\.$/
1070
+ # Single trailing dots are unnecessary.
1054
1071
  result = result[0...-1]
1055
1072
  end
1056
1073
  result
@@ -1449,20 +1466,16 @@ module Addressable
1449
1466
  # The query component for this URI, normalized.
1450
1467
  #
1451
1468
  # @return [String] The query component, normalized.
1452
- def normalized_query
1453
- self.query && @normalized_query ||= (begin
1454
- modified_query_class = Addressable::URI::CharacterClasses::QUERY
1455
- # Make sure possible key-value pair delimiters are escaped.
1456
- modified_query_class = modified_query_class.sub("\\&", "")
1457
- modified_query_class = modified_query_class.sub("\\;", "")
1458
- (self.query.split("&", -1).map do |pair|
1459
- Addressable::URI.normalize_component(
1460
- pair,
1461
- modified_query_class,
1462
- '+'
1463
- )
1464
- end).join("&")
1465
- end)
1469
+ def normalized_query(*flags)
1470
+ modified_query_class = Addressable::URI::CharacterClasses::QUERY.dup
1471
+ # Make sure possible key-value pair delimiters are escaped.
1472
+ modified_query_class.sub!("\\&", "").sub!("\\;", "")
1473
+ pairs = (self.query || "").split("&", -1)
1474
+ pairs.sort! if flags.include?(:sorted)
1475
+ component = (pairs.map do |pair|
1476
+ Addressable::URI.normalize_component(pair, modified_query_class, "+")
1477
+ end).join("&")
1478
+ component == "" ? nil : component
1466
1479
  end
1467
1480
 
1468
1481
  ##
@@ -1643,10 +1656,11 @@ module Addressable
1643
1656
  # @return [String] The fragment component, normalized.
1644
1657
  def normalized_fragment
1645
1658
  self.fragment && @normalized_fragment ||= (begin
1646
- Addressable::URI.normalize_component(
1647
- self.fragment.strip,
1659
+ component = Addressable::URI.normalize_component(
1660
+ self.fragment,
1648
1661
  Addressable::URI::CharacterClasses::FRAGMENT
1649
1662
  )
1663
+ component == "" ? nil : component
1650
1664
  end)
1651
1665
  end
1652
1666
 
@@ -22,7 +22,7 @@ if !defined?(Addressable::VERSION)
22
22
  module VERSION
23
23
  MAJOR = 2
24
24
  MINOR = 3
25
- TINY = 5
25
+ TINY = 6
26
26
 
27
27
  STRING = [MAJOR, MINOR, TINY].join('.')
28
28
  end
@@ -32,20 +32,72 @@ shared_examples_for 'expands' do |tests|
32
32
  end
33
33
  end
34
34
 
35
+ describe "eql?" do
36
+ let(:template) { Addressable::Template.new('https://www.example.com/{foo}') }
37
+ it 'is equal when the pattern matches' do
38
+ other_template = Addressable::Template.new('https://www.example.com/{foo}')
39
+ expect(template).to be_eql(other_template)
40
+ expect(other_template).to be_eql(template)
41
+ end
42
+ it 'is not equal when the pattern differs' do
43
+ other_template = Addressable::Template.new('https://www.example.com/{bar}')
44
+ expect(template).to_not be_eql(other_template)
45
+ expect(other_template).to_not be_eql(template)
46
+ end
47
+ it 'is not equal to non-templates' do
48
+ uri = 'https://www.example.com/foo/bar'
49
+ addressable_template = Addressable::Template.new uri
50
+ addressable_uri = Addressable::URI.parse uri
51
+ expect(addressable_template).to_not be_eql(addressable_uri)
52
+ expect(addressable_uri).to_not be_eql(addressable_template)
53
+ end
54
+ end
55
+
56
+ describe "==" do
57
+ let(:template) { Addressable::Template.new('https://www.example.com/{foo}') }
58
+ it 'is equal when the pattern matches' do
59
+ other_template = Addressable::Template.new('https://www.example.com/{foo}')
60
+ expect(template).should == other_template
61
+ expect(other_template).should == template
62
+ end
63
+ it 'is not equal when the pattern differs' do
64
+ other_template = Addressable::Template.new('https://www.example.com/{bar}')
65
+ expect(template).should_not == other_template
66
+ expect(other_template).should_not == template
67
+ end
68
+ it 'is not equal to non-templates' do
69
+ uri = 'https://www.example.com/foo/bar'
70
+ addressable_template = Addressable::Template.new uri
71
+ addressable_uri = Addressable::URI.parse uri
72
+ expect(addressable_template).should_not == addressable_uri
73
+ expect(addressable_uri).should_not == addressable_template
74
+ end
75
+ end
76
+
35
77
  describe "Type conversion" do
36
- subject{
37
- {:var => true, :hello => 1234, :nothing => nil, :sym => :symbolic}
78
+ require "bigdecimal"
79
+
80
+ subject {
81
+ {
82
+ :var => true,
83
+ :hello => 1234,
84
+ :nothing => nil,
85
+ :sym => :symbolic,
86
+ :decimal => BigDecimal.new(1)
87
+ }
38
88
  }
89
+
39
90
  it_behaves_like 'expands', {
40
91
  '{var}' => 'true',
41
92
  '{hello}' => '1234',
42
93
  '{nothing}' => '',
43
- '{sym}' => 'symbolic'
94
+ '{sym}' => 'symbolic',
95
+ '{decimal}' => '0.1E1'
44
96
  }
45
97
  end
46
98
 
47
99
  describe "Level 1:" do
48
- subject{
100
+ subject {
49
101
  {:var => "value", :hello => "Hello World!"}
50
102
  }
51
103
  it_behaves_like 'expands', {
@@ -55,7 +107,7 @@ describe "Level 1:" do
55
107
  end
56
108
 
57
109
  describe "Level 2" do
58
- subject{
110
+ subject {
59
111
  {
60
112
  :var => "value",
61
113
  :hello => "Hello World!",
@@ -79,7 +131,7 @@ describe "Level 2" do
79
131
  end
80
132
 
81
133
  describe "Level 3" do
82
- subject{
134
+ subject {
83
135
  {
84
136
  :var => "value",
85
137
  :hello => "Hello World!",
@@ -140,7 +192,7 @@ describe "Level 3" do
140
192
  end
141
193
 
142
194
  describe "Level 4" do
143
- subject{
195
+ subject {
144
196
  {
145
197
  :var => "value",
146
198
  :hello => "Hello World!",
@@ -338,7 +390,7 @@ describe "Level 4" do
338
390
  end
339
391
  end
340
392
  describe "Modifiers" do
341
- subject{
393
+ subject {
342
394
  {
343
395
  :var => "value",
344
396
  :semi => ";",
@@ -363,7 +415,7 @@ describe "Modifiers" do
363
415
  end
364
416
  end
365
417
  describe "Expansion" do
366
- subject{
418
+ subject {
367
419
  {
368
420
  :count => ["one", "two", "three"],
369
421
  :dom => ["example", "com"],
@@ -670,6 +722,11 @@ class ExampleTwoProcessor
670
722
  end
671
723
  end
672
724
 
725
+ class DumbProcessor
726
+ def self.match(name)
727
+ return ".*?" if name == "first"
728
+ end
729
+ end
673
730
 
674
731
  describe Addressable::Template do
675
732
  describe "Matching" do
@@ -687,54 +744,80 @@ describe Addressable::Template do
687
744
  let(:uri4){
688
745
  Addressable::URI.parse("http://example.com/?a=1&b=2&c=3&first=foo")
689
746
  }
747
+ let(:uri5){
748
+ "http://example.com/foo"
749
+ }
690
750
  context "first uri with ExampleTwoProcessor" do
691
- subject{
751
+ subject {
692
752
  match = Addressable::Template.new(
693
753
  "http://example.com/search/{query}/"
694
754
  ).match(uri, ExampleTwoProcessor)
695
755
  }
696
- its(:variables){ should == ["query"]}
697
- its(:captures){ should == ["an example search query"]}
756
+ its(:variables){ should == ["query"] }
757
+ its(:captures){ should == ["an example search query"] }
698
758
  end
699
759
 
700
760
  context "second uri with ExampleTwoProcessor" do
701
- subject{
761
+ subject {
702
762
  match = Addressable::Template.new(
703
763
  "http://example.com/{first}/{+second}/"
704
764
  ).match(uri2, ExampleTwoProcessor)
705
765
  }
706
- its(:variables){ should == ["first", "second"]}
766
+ its(:variables){ should == ["first", "second"] }
767
+ its(:captures){ should == ["a", "b/c"] }
768
+ end
769
+
770
+ context "second uri with DumbProcessor" do
771
+ subject {
772
+ match = Addressable::Template.new(
773
+ "http://example.com/{first}/{+second}/"
774
+ ).match(uri2, DumbProcessor)
775
+ }
776
+ its(:variables){ should == ["first", "second"] }
707
777
  its(:captures){ should == ["a", "b/c"] }
708
778
  end
779
+
709
780
  context "second uri" do
710
- subject{
781
+ subject {
711
782
  match = Addressable::Template.new(
712
783
  "http://example.com/{first}{/second*}/"
713
784
  ).match(uri2)
714
785
  }
715
- its(:variables){ should == ["first", "second"]}
786
+ its(:variables){ should == ["first", "second"] }
716
787
  its(:captures){ should == ["a", ["b","c"]] }
717
788
  end
718
789
  context "third uri" do
719
- subject{
790
+ subject {
720
791
  match = Addressable::Template.new(
721
792
  "http://example.com/{;hash*,first}"
722
793
  ).match(uri3)
723
794
  }
724
- its(:variables){ should == ["hash", "first"]}
795
+ its(:variables){ should == ["hash", "first"] }
725
796
  its(:captures){ should == [
726
797
  {"a" => "1", "b" => "2", "c" => "3", "first" => "foo"}, nil] }
727
798
  end
799
+ # Note that this expansion is impossible to revert deterministically - the
800
+ # * operator means first could have been a key of hash or a separate key.
801
+ # Semantically, a separate key is more likely, but both are possible.
728
802
  context "fourth uri" do
729
- subject{
803
+ subject {
730
804
  match = Addressable::Template.new(
731
805
  "http://example.com/{?hash*,first}"
732
806
  ).match(uri4)
733
807
  }
734
- its(:variables){ should == ["hash", "first"]}
808
+ its(:variables){ should == ["hash", "first"] }
735
809
  its(:captures){ should == [
736
810
  {"a" => "1", "b" => "2", "c" => "3", "first"=> "foo"}, nil] }
737
811
  end
812
+ context "fifth uri" do
813
+ subject {
814
+ match = Addressable::Template.new(
815
+ "http://example.com/{path}{?hash*,first}"
816
+ ).match(uri5)
817
+ }
818
+ its(:variables){ should == ["path", "hash", "first"] }
819
+ its(:captures){ should == ["foo", nil, nil] }
820
+ end
738
821
  end
739
822
  describe "extract" do
740
823
  let(:template) {
@@ -743,7 +826,8 @@ describe Addressable::Template do
743
826
  )
744
827
  }
745
828
  let(:uri){ "http://example.com/a/b/c/?one=1&two=2#foo" }
746
- it "should be able to extract" do
829
+ let(:uri2){ "http://example.com/a/b/c/#foo" }
830
+ it "should be able to extract with queries" do
747
831
  template.extract(uri).should == {
748
832
  "host" => "example.com",
749
833
  "segments" => %w(a b c),
@@ -753,10 +837,53 @@ describe Addressable::Template do
753
837
  "fragment" => "foo"
754
838
  }
755
839
  end
840
+ it "should be able to extract without queries" do
841
+ template.extract(uri2).should == {
842
+ "host" => "example.com",
843
+ "segments" => %w(a b c),
844
+ "one" => nil,
845
+ "bogus" => nil,
846
+ "two" => nil,
847
+ "fragment" => "foo"
848
+ }
849
+ end
850
+
851
+ context "issue #137" do
852
+ subject { Addressable::Template.new('/path{?page,per_page}') }
853
+
854
+ it "can match empty" do
855
+ data = subject.extract("/path")
856
+ data["page"].should == nil
857
+ data["per_page"].should == nil
858
+ data.keys.sort.should == ['page', 'per_page']
859
+ end
860
+
861
+ it "can match first var" do
862
+ data = subject.extract("/path?page=1")
863
+ data["page"].should == "1"
864
+ data["per_page"].should == nil
865
+ data.keys.sort.should == ['page', 'per_page']
866
+ end
867
+
868
+ it "can match second var" do
869
+ data = subject.extract("/path?per_page=1")
870
+ data["page"].should == nil
871
+ data["per_page"].should == "1"
872
+ data.keys.sort.should == ['page', 'per_page']
873
+ end
874
+
875
+ it "can match both vars" do
876
+ data = subject.extract("/path?page=2&per_page=1")
877
+ data["page"].should == "2"
878
+ data["per_page"].should == "1"
879
+ data.keys.sort.should == ['page', 'per_page']
880
+ end
881
+ end
756
882
  end
883
+
757
884
  describe "Partial expand with symbols" do
758
885
  context "partial_expand with two simple values" do
759
- subject{
886
+ subject {
760
887
  Addressable::Template.new("http://example.com/{one}/{two}/")
761
888
  }
762
889
  it "builds a new pattern" do
@@ -765,7 +892,7 @@ describe Addressable::Template do
765
892
  end
766
893
  end
767
894
  context "partial_expand query with missing param in middle" do
768
- subject{
895
+ subject {
769
896
  Addressable::Template.new("http://example.com/{?one,two,three}/")
770
897
  }
771
898
  it "builds a new pattern" do
@@ -774,7 +901,7 @@ describe Addressable::Template do
774
901
  end
775
902
  end
776
903
  context "partial_expand with query string" do
777
- subject{
904
+ subject {
778
905
  Addressable::Template.new("http://example.com/{?two,one}/")
779
906
  }
780
907
  it "builds a new pattern" do
@@ -783,7 +910,7 @@ describe Addressable::Template do
783
910
  end
784
911
  end
785
912
  context "partial_expand with path operator" do
786
- subject{
913
+ subject {
787
914
  Addressable::Template.new("http://example.com{/one,two}/")
788
915
  }
789
916
  it "builds a new pattern" do
@@ -794,7 +921,7 @@ describe Addressable::Template do
794
921
  end
795
922
  describe "Partial expand with strings" do
796
923
  context "partial_expand with two simple values" do
797
- subject{
924
+ subject {
798
925
  Addressable::Template.new("http://example.com/{one}/{two}/")
799
926
  }
800
927
  it "builds a new pattern" do
@@ -803,7 +930,7 @@ describe Addressable::Template do
803
930
  end
804
931
  end
805
932
  context "partial_expand query with missing param in middle" do
806
- subject{
933
+ subject {
807
934
  Addressable::Template.new("http://example.com/{?one,two,three}/")
808
935
  }
809
936
  it "builds a new pattern" do
@@ -812,7 +939,7 @@ describe Addressable::Template do
812
939
  end
813
940
  end
814
941
  context "partial_expand with query string" do
815
- subject{
942
+ subject {
816
943
  Addressable::Template.new("http://example.com/{?two,one}/")
817
944
  }
818
945
  it "builds a new pattern" do
@@ -821,7 +948,7 @@ describe Addressable::Template do
821
948
  end
822
949
  end
823
950
  context "partial_expand with path operator" do
824
- subject{
951
+ subject {
825
952
  Addressable::Template.new("http://example.com{/one,two}/")
826
953
  }
827
954
  it "builds a new pattern" do
@@ -832,7 +959,7 @@ describe Addressable::Template do
832
959
  end
833
960
  describe "Expand" do
834
961
  context "expand with a processor" do
835
- subject{
962
+ subject {
836
963
  Addressable::Template.new("http://example.com/search/{query}/")
837
964
  }
838
965
  it "processes spaces" do
@@ -848,7 +975,7 @@ describe Addressable::Template do
848
975
  end
849
976
  end
850
977
  context "partial_expand query with missing param in middle" do
851
- subject{
978
+ subject {
852
979
  Addressable::Template.new("http://example.com/{?one,two,three}/")
853
980
  }
854
981
  it "builds a new pattern" do
@@ -857,7 +984,7 @@ describe Addressable::Template do
857
984
  end
858
985
  end
859
986
  context "partial_expand with query string" do
860
- subject{
987
+ subject {
861
988
  Addressable::Template.new("http://example.com/{?two,one}/")
862
989
  }
863
990
  it "builds a new pattern" do
@@ -866,7 +993,7 @@ describe Addressable::Template do
866
993
  end
867
994
  end
868
995
  context "partial_expand with path operator" do
869
- subject{
996
+ subject {
870
997
  Addressable::Template.new("http://example.com{/one,two}/")
871
998
  }
872
999
  it "builds a new pattern" do
@@ -889,8 +1016,8 @@ describe Addressable::Template do
889
1016
  end
890
1017
  it "can match empty" do
891
1018
  data = subject.match("foo/baz")
892
- data.mapping["foo"].should == ""
893
- data.mapping["bar"].should == ""
1019
+ data.mapping["foo"].should == nil
1020
+ data.mapping["bar"].should == nil
894
1021
  end
895
1022
  it "lists vars" do
896
1023
  subject.variables.should == ["foo", "bar"]
@@ -904,6 +1031,22 @@ describe Addressable::Template do
904
1031
  data.mapping["foo"].should == "/test/banana"
905
1032
  data.mapping["bar"].should == "baz"
906
1033
  end
1034
+ it "can match empty level 2 #" do
1035
+ data = subject.match("foo/test/bananabaz")
1036
+ data.mapping["foo"].should == "/test/banana"
1037
+ data.mapping["bar"].should == nil
1038
+ data = subject.match("foo/test/banana#baz")
1039
+ data.mapping["foo"].should == "/test/banana"
1040
+ data.mapping["bar"].should == ""
1041
+ end
1042
+ it "can match empty level 2 +" do
1043
+ data = subject.match("foobaz")
1044
+ data.mapping["foo"].should == nil
1045
+ data.mapping["bar"].should == nil
1046
+ data = subject.match("foo#barbaz")
1047
+ data.mapping["foo"].should == nil
1048
+ data.mapping["bar"].should == "bar"
1049
+ end
907
1050
  it "lists vars" do
908
1051
  subject.variables.should == ["foo", "bar"]
909
1052
  end
@@ -978,6 +1121,39 @@ describe Addressable::Template do
978
1121
  subject.variables.should == %w(foo bar)
979
1122
  end
980
1123
  end
1124
+
1125
+ context "issue #137" do
1126
+ subject { Addressable::Template.new('/path{?page,per_page}') }
1127
+
1128
+ it "can match empty" do
1129
+ data = subject.match("/path")
1130
+ data.mapping["page"].should == nil
1131
+ data.mapping["per_page"].should == nil
1132
+ data.mapping.keys.sort.should == ['page', 'per_page']
1133
+ end
1134
+
1135
+ it "can match first var" do
1136
+ data = subject.match("/path?page=1")
1137
+ data.mapping["page"].should == "1"
1138
+ data.mapping["per_page"].should == nil
1139
+ data.mapping.keys.sort.should == ['page', 'per_page']
1140
+ end
1141
+
1142
+ it "can match second var" do
1143
+ data = subject.match("/path?per_page=1")
1144
+ data.mapping["page"].should == nil
1145
+ data.mapping["per_page"].should == "1"
1146
+ data.mapping.keys.sort.should == ['page', 'per_page']
1147
+ end
1148
+
1149
+ it "can match both vars" do
1150
+ data = subject.match("/path?page=2&per_page=1")
1151
+ data.mapping["page"].should == "2"
1152
+ data.mapping["per_page"].should == "1"
1153
+ data.mapping.keys.sort.should == ['page', 'per_page']
1154
+ end
1155
+ end
1156
+
981
1157
  context "issue #71" do
982
1158
  subject { Addressable::Template.new("http://cyberscore.dev/api/users{?username}") }
983
1159
  it "can match" do
@@ -1084,10 +1260,10 @@ describe Addressable::Template::MatchData do
1084
1260
  its(:template) { should == template }
1085
1261
  its(:mapping) { should == { 'foo' => 'ab', 'bar' => 'cd' } }
1086
1262
  its(:variables) { should == ['foo', 'bar'] }
1087
- its(:keys) { should == its.variables }
1088
- its(:names) { should == its.variables }
1263
+ its(:keys) { should == ['foo', 'bar'] }
1264
+ its(:names) { should == ['foo', 'bar'] }
1089
1265
  its(:values) { should == ['ab', 'cd'] }
1090
- its(:captures) { should == its.values }
1266
+ its(:captures) { should == ['ab', 'cd'] }
1091
1267
  its(:to_a) { should == ['ab/cd', 'ab', 'cd'] }
1092
1268
  its(:to_s) { should == 'ab/cd' }
1093
1269
  its(:string) { should == its.to_s }
@@ -17,6 +17,7 @@
17
17
  require "spec_helper"
18
18
 
19
19
  require "addressable/uri"
20
+ require "uri"
20
21
 
21
22
  if !"".respond_to?("force_encoding")
22
23
  class String
@@ -931,6 +932,17 @@ describe Addressable::URI, "when created with an authority and no port" do
931
932
  end
932
933
  end
933
934
 
935
+ describe Addressable::URI, "when created with a host with trailing dots" do
936
+ before do
937
+ @uri = Addressable::URI.new(:authority => "example...")
938
+ end
939
+
940
+ it "should have a stable normalized form" do
941
+ @uri.normalize.normalize.normalize.host.should ==
942
+ @uri.normalize.host
943
+ end
944
+ end
945
+
934
946
  describe Addressable::URI, "when created with both a userinfo and a user" do
935
947
  it "should raise an error" do
936
948
  (lambda do
@@ -2019,6 +2031,38 @@ describe Addressable::URI, "when parsed from " +
2019
2031
  end
2020
2032
  end
2021
2033
 
2034
+ describe Addressable::URI, "when parsed from " +
2035
+ "'http://example.com?#'" do
2036
+ before do
2037
+ @uri = Addressable::URI.parse("http://example.com?#")
2038
+ end
2039
+
2040
+ it "should correctly convert to a hash" do
2041
+ @uri.to_hash.should == {
2042
+ :scheme => "http",
2043
+ :user => nil,
2044
+ :password => nil,
2045
+ :host => "example.com",
2046
+ :port => nil,
2047
+ :path => "",
2048
+ :query => "",
2049
+ :fragment => ""
2050
+ }
2051
+ end
2052
+
2053
+ it "should have a request URI of '/?'" do
2054
+ @uri.request_uri.should == "/?"
2055
+ end
2056
+
2057
+ it "should normalize to 'http://example.com/'" do
2058
+ @uri.normalize.to_s.should == "http://example.com/"
2059
+ end
2060
+
2061
+ it "should have an origin of 'http://example.com'" do
2062
+ @uri.origin.should == "http://example.com"
2063
+ end
2064
+ end
2065
+
2022
2066
  describe Addressable::URI, "when parsed from " +
2023
2067
  "'http://@example.com/'" do
2024
2068
  before do
@@ -2136,7 +2180,7 @@ describe Addressable::URI, "when parsed from " +
2136
2180
  it "should not raise an exception when normalized" do
2137
2181
  (lambda do
2138
2182
  @uri.normalize
2139
- end).should_not raise_error(ArgumentError)
2183
+ end).should_not raise_error
2140
2184
  end
2141
2185
 
2142
2186
  it "should be considered to be in normal form" do
@@ -2188,7 +2232,7 @@ describe Addressable::URI, "when parsed from " +
2188
2232
  it "should not raise an exception when normalized" do
2189
2233
  (lambda do
2190
2234
  @uri.normalize
2191
- end).should_not raise_error(ArgumentError)
2235
+ end).should_not raise_error
2192
2236
  end
2193
2237
 
2194
2238
  it "should be considered to be in normal form" do
@@ -2212,7 +2256,7 @@ describe Addressable::URI, "when parsed from " +
2212
2256
  it "should not raise an exception when normalized" do
2213
2257
  (lambda do
2214
2258
  @uri.normalize
2215
- end).should_not raise_error(ArgumentError)
2259
+ end).should_not raise_error
2216
2260
  end
2217
2261
 
2218
2262
  it "should be considered to be in normal form" do
@@ -2589,7 +2633,7 @@ describe Addressable::URI, "when parsed from " +
2589
2633
  end
2590
2634
 
2591
2635
  it "should normalize to 'http://example.com/'" do
2592
- @uri.normalize.should === "http://example.com/"
2636
+ @uri.normalize.to_s.should == "http://example.com/"
2593
2637
  end
2594
2638
 
2595
2639
  it "should have an origin of 'http://example.com'" do
@@ -2597,6 +2641,31 @@ describe Addressable::URI, "when parsed from " +
2597
2641
  end
2598
2642
  end
2599
2643
 
2644
+ describe Addressable::URI, "when parsed from " +
2645
+ "'http://example.com/%2E/'" do
2646
+ before do
2647
+ @uri = Addressable::URI.parse("http://example.com/%2E/")
2648
+ end
2649
+
2650
+ it "should be considered to be in normal form" do
2651
+ pending(
2652
+ 'path segment normalization should happen before ' +
2653
+ 'percent escaping normalization'
2654
+ ) do
2655
+ @uri.normalize.should be_eql(@uri)
2656
+ end
2657
+ end
2658
+
2659
+ it "should normalize to 'http://example.com/%2E/'" do
2660
+ pending(
2661
+ 'path segment normalization should happen before ' +
2662
+ 'percent escaping normalization'
2663
+ ) do
2664
+ @uri.normalize.should == "http://example.com/%2E/"
2665
+ end
2666
+ end
2667
+ end
2668
+
2600
2669
  describe Addressable::URI, "when parsed from " +
2601
2670
  "'http://example.com/..'" do
2602
2671
  before do
@@ -2612,7 +2681,7 @@ describe Addressable::URI, "when parsed from " +
2612
2681
  end
2613
2682
 
2614
2683
  it "should normalize to 'http://example.com/'" do
2615
- @uri.normalize.should === "http://example.com/"
2684
+ @uri.normalize.to_s.should == "http://example.com/"
2616
2685
  end
2617
2686
  end
2618
2687
 
@@ -2631,7 +2700,7 @@ describe Addressable::URI, "when parsed from " +
2631
2700
  end
2632
2701
 
2633
2702
  it "should normalize to 'http://example.com/'" do
2634
- @uri.normalize.should === "http://example.com/"
2703
+ @uri.normalize.to_s.should == "http://example.com/"
2635
2704
  end
2636
2705
  end
2637
2706
 
@@ -2650,7 +2719,7 @@ describe Addressable::URI, "when parsed from " +
2650
2719
  end
2651
2720
 
2652
2721
  it "should normalize to 'http://example.com/'" do
2653
- @uri.normalize.should === "http://example.com/"
2722
+ @uri.normalize.to_s.should == "http://example.com/"
2654
2723
  end
2655
2724
  end
2656
2725
 
@@ -2669,7 +2738,7 @@ describe Addressable::URI, "when parsed from " +
2669
2738
  end
2670
2739
 
2671
2740
  it "should normalize to 'http://example.com/'" do
2672
- @uri.normalize.should === "http://example.com/"
2741
+ @uri.normalize.to_s.should == "http://example.com/"
2673
2742
  end
2674
2743
  end
2675
2744
 
@@ -2688,7 +2757,7 @@ describe Addressable::URI, "when parsed from " +
2688
2757
  end
2689
2758
 
2690
2759
  it "should normalize to 'http://example.com/'" do
2691
- @uri.normalize.should === "http://example.com/"
2760
+ @uri.normalize.to_s.should == "http://example.com/"
2692
2761
  end
2693
2762
  end
2694
2763
 
@@ -2707,7 +2776,7 @@ describe Addressable::URI, "when parsed from " +
2707
2776
  end
2708
2777
 
2709
2778
  it "should normalize to 'http://example.com/'" do
2710
- @uri.normalize.should === "http://example.com/"
2779
+ @uri.normalize.to_s.should == "http://example.com/"
2711
2780
  end
2712
2781
  end
2713
2782
 
@@ -2722,7 +2791,7 @@ describe Addressable::URI, "when parsed from '/a/b/c/./../../g'" do
2722
2791
 
2723
2792
  # Section 5.2.4 of RFC 3986
2724
2793
  it "should normalize to '/a/g'" do
2725
- @uri.normalize.should === "/a/g"
2794
+ @uri.normalize.to_s.should == "/a/g"
2726
2795
  end
2727
2796
  end
2728
2797
 
@@ -2737,7 +2806,7 @@ describe Addressable::URI, "when parsed from 'mid/content=5/../6'" do
2737
2806
 
2738
2807
  # Section 5.2.4 of RFC 3986
2739
2808
  it "should normalize to 'mid/6'" do
2740
- @uri.normalize.should === "mid/6"
2809
+ @uri.normalize.to_s.should == "mid/6"
2741
2810
  end
2742
2811
  end
2743
2812
 
@@ -2752,7 +2821,7 @@ describe Addressable::URI, "when parsed from " +
2752
2821
  end
2753
2822
 
2754
2823
  it "should normalize to 'http://www.example.com//'" do
2755
- @uri.normalize.should === "http://www.example.com//"
2824
+ @uri.normalize.to_s.should == "http://www.example.com//"
2756
2825
  end
2757
2826
  end
2758
2827
 
@@ -4346,6 +4415,10 @@ describe Addressable::URI, "when parsed from '?'" do
4346
4415
  @uri = Addressable::URI.parse("?")
4347
4416
  end
4348
4417
 
4418
+ it "should normalize to ''" do
4419
+ @uri.normalize.to_s.should == ""
4420
+ end
4421
+
4349
4422
  it "should have the correct return type" do
4350
4423
  @uri.query_values.should == {}
4351
4424
  @uri.query_values(Hash).should == {}
@@ -4490,6 +4563,11 @@ describe Addressable::URI, "when parsed from " +
4490
4563
  {'one' => ['two', 'three', 'four']}
4491
4564
  end
4492
4565
  end
4566
+
4567
+ it "should handle assignment with keys of mixed type" do
4568
+ @uri.query_values = @uri.query_values(Hash).merge({:one => 'three'})
4569
+ @uri.query_values(Hash).should == {'one' => 'three'}
4570
+ end
4493
4571
  end
4494
4572
 
4495
4573
  describe Addressable::URI, "when parsed from " +
@@ -5335,6 +5413,16 @@ describe Addressable::URI, "when normalizing a string but leaving some character
5335
5413
  Addressable::URI.normalize_component("%58X%59Y%5AZ", "0-9a-zXY", "Y").should ==
5336
5414
  "XX%59Y%5A%5A"
5337
5415
  end
5416
+
5417
+ it "should not modify the character class" do
5418
+ character_class = "0-9a-zXY"
5419
+
5420
+ character_class_copy = character_class.dup
5421
+
5422
+ Addressable::URI.normalize_component("%58X%59Y%5AZ", character_class, "Y")
5423
+
5424
+ character_class.should == character_class_copy
5425
+ end
5338
5426
  end
5339
5427
 
5340
5428
  describe Addressable::URI, "when encoding a string with existing encodings to upcase" do
@@ -5379,6 +5467,10 @@ describe Addressable::URI, "when unencoding a multibyte string" do
5379
5467
  Addressable::URI.unencode_component("g%C3%BCnther").should == "günther"
5380
5468
  end
5381
5469
 
5470
+ it "should consistently use UTF-8 internally" do
5471
+ Addressable::URI.unencode_component("ski=%BA%DAɫ").should == "ski=\xBA\xDAɫ"
5472
+ end
5473
+
5382
5474
  it "should result in correct percent encoded sequence as a URI" do
5383
5475
  Addressable::URI.unencode(
5384
5476
  "/path?g%C3%BCnther", ::Addressable::URI
@@ -5642,6 +5734,18 @@ describe Addressable::URI, "when given the input " +
5642
5734
  end
5643
5735
  end
5644
5736
 
5737
+ describe Addressable::URI, "when given the input " +
5738
+ "::URI.parse('http://example.com')" do
5739
+ before do
5740
+ @input = ::URI.parse('http://example.com')
5741
+ end
5742
+
5743
+ it "should heuristically parse to 'http://example.com'" do
5744
+ @uri = Addressable::URI.heuristic_parse(@input)
5745
+ @uri.to_s.should == "http://example.com"
5746
+ end
5747
+ end
5748
+
5645
5749
  describe Addressable::URI, "when assigning query values" do
5646
5750
  before do
5647
5751
  @uri = Addressable::URI.new
@@ -5753,7 +5857,7 @@ describe Addressable::URI, "when assigning query values" do
5753
5857
  describe 'when a hash with mixed types is assigned to query_values' do
5754
5858
  it 'should not raise an error' do
5755
5859
  pending 'Issue #94' do
5756
- expect { subject.query_values = { "page" => "1", :page => 2 } }.to_not raise_error ArgumentError
5860
+ expect { subject.query_values = { "page" => "1", :page => 2 } }.to_not raise_error
5757
5861
  end
5758
5862
  end
5759
5863
  end
@@ -5805,7 +5909,7 @@ describe Addressable::URI, "when assigning path values" do
5805
5909
  (lambda do
5806
5910
  @uri.path = "uuid:0b3ecf60-3f93-11df-a9c3-001f5bfffe12"
5807
5911
  @uri.scheme = "urn"
5808
- end).should_not raise_error(Addressable::URI::InvalidURIError)
5912
+ end).should_not raise_error
5809
5913
  end
5810
5914
  end
5811
5915
 
@@ -1,2 +1,6 @@
1
- require 'coveralls'
2
- Coveralls.wear!
1
+ begin
2
+ require 'coveralls'
3
+ Coveralls.wear!
4
+ rescue LoadError
5
+ warn "warning: coveralls gem not found; skipping Coveralls"
6
+ end
@@ -24,22 +24,6 @@ namespace :gem do
24
24
  end
25
25
  end
26
26
 
27
- namespace :doc do
28
- desc "Publish RDoc to RubyForge"
29
- task :release => ["doc"] do
30
- require "rake/contrib/sshpublisher"
31
- require "yaml"
32
-
33
- config = YAML.load(
34
- File.read(File.expand_path('~/.rubyforge/user-config.yml'))
35
- )
36
- host = "#{config['username']}@rubyforge.org"
37
- remote_dir = RUBY_FORGE_PATH + "/api"
38
- local_dir = "doc"
39
- Rake::SshDirPublisher.new(host, remote_dir, local_dir).upload
40
- end
41
- end
42
-
43
27
  namespace :spec do
44
28
  desc "Publish specdoc to RubyForge"
45
29
  task :release => ["spec:specdoc"] do
@@ -78,11 +78,11 @@
78
78
  </a>
79
79
  </li>
80
80
  <li>
81
- <a href="http://github.com/sporkmonger/addressable/tree/">
81
+ <a href="http://github.com/sporkmonger/addressable">
82
82
  GitHub Page
83
83
  </a>
84
84
  </li>
85
- <li><a href="/api/">API</a></li>
85
+ <li><a href="http://rubydoc.info/gems/addressable">API</a></li>
86
86
  <li><a href="/specdoc/">Specifications</a></li>
87
87
  <li><a href="/coverage/">Code Coverage</a></li>
88
88
  </ul>
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: addressable
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.5
4
+ version: 2.3.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bob Aman
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-06-27 00:00:00.000000000 Z
11
+ date: 2014-03-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake