addressable 2.6.0 → 2.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -48,12 +48,21 @@ module Addressable
48
48
  PCHAR = UNRESERVED + SUB_DELIMS + "\\:\\@"
49
49
  SCHEME = ALPHA + DIGIT + "\\-\\+\\."
50
50
  HOST = UNRESERVED + SUB_DELIMS + "\\[\\:\\]"
51
- AUTHORITY = PCHAR
51
+ AUTHORITY = PCHAR + "\\[\\:\\]"
52
52
  PATH = PCHAR + "\\/"
53
53
  QUERY = PCHAR + "\\/\\?"
54
54
  FRAGMENT = PCHAR + "\\/\\?"
55
55
  end
56
56
 
57
+ module NormalizeCharacterClasses
58
+ HOST = /[^#{CharacterClasses::HOST}]/
59
+ UNRESERVED = /[^#{CharacterClasses::UNRESERVED}]/
60
+ PCHAR = /[^#{CharacterClasses::PCHAR}]/
61
+ SCHEME = /[^#{CharacterClasses::SCHEME}]/
62
+ FRAGMENT = /[^#{CharacterClasses::FRAGMENT}]/
63
+ QUERY = %r{[^a-zA-Z0-9\-\.\_\~\!\$\'\(\)\*\+\,\=\:\@\/\?%]|%(?!2B|2b)}
64
+ end
65
+
57
66
  SLASH = '/'
58
67
  EMPTY_STR = ''
59
68
 
@@ -73,7 +82,7 @@ module Addressable
73
82
  "wais" => 210,
74
83
  "ldap" => 389,
75
84
  "prospero" => 1525
76
- }
85
+ }.freeze
77
86
 
78
87
  ##
79
88
  # Returns a URI object based on the parsed string.
@@ -207,7 +216,7 @@ module Addressable
207
216
  fragments = match.captures
208
217
  authority = fragments[3]
209
218
  if authority && authority.length > 0
210
- new_authority = authority.gsub(/\\/, '/').gsub(/ /, '%20')
219
+ new_authority = authority.tr("\\", "/").gsub(" ", "%20")
211
220
  # NOTE: We want offset 4, not 3!
212
221
  offset = match.offset(4)
213
222
  uri = uri.dup
@@ -218,8 +227,9 @@ module Addressable
218
227
  parsed = self.parse(hints[:scheme] + "://" + uri)
219
228
  end
220
229
  if parsed.path.include?(".")
221
- new_host = parsed.path[/^([^\/]+\.[^\/]*)/, 1]
222
- if new_host
230
+ if parsed.path[/\b@\b/]
231
+ parsed.scheme = "mailto" unless parsed.scheme
232
+ elsif new_host = parsed.path[/^([^\/]+\.[^\/]*)/, 1]
223
233
  parsed.defer_validation do
224
234
  new_path = parsed.path.sub(
225
235
  Regexp.new("^" + Regexp.escape(new_host)), EMPTY_STR)
@@ -281,15 +291,15 @@ module Addressable
281
291
  uri.path.sub!(/^\/?([a-zA-Z])[\|:][\\\/]/) do
282
292
  "/#{$1.downcase}:/"
283
293
  end
284
- uri.path.gsub!(/\\/, SLASH)
294
+ uri.path.tr!("\\", SLASH)
285
295
  if File.exist?(uri.path) &&
286
296
  File.stat(uri.path).directory?
287
- uri.path.sub!(/\/$/, EMPTY_STR)
297
+ uri.path.chomp!(SLASH)
288
298
  uri.path = uri.path + '/'
289
299
  end
290
300
 
291
301
  # If the path is absolute, set the scheme and host.
292
- if uri.path =~ /^\//
302
+ if uri.path.start_with?(SLASH)
293
303
  uri.scheme = "file"
294
304
  uri.host = EMPTY_STR
295
305
  end
@@ -326,6 +336,21 @@ module Addressable
326
336
  return result
327
337
  end
328
338
 
339
+ ##
340
+ # Tables used to optimize encoding operations in `self.encode_component`
341
+ # and `self.normalize_component`
342
+ SEQUENCE_ENCODING_TABLE = Hash.new do |hash, sequence|
343
+ hash[sequence] = sequence.unpack("C*").map do |c|
344
+ format("%02x", c)
345
+ end.join
346
+ end
347
+
348
+ SEQUENCE_UPCASED_PERCENT_ENCODING_TABLE = Hash.new do |hash, sequence|
349
+ hash[sequence] = sequence.unpack("C*").map do |c|
350
+ format("%%%02X", c)
351
+ end.join
352
+ end
353
+
329
354
  ##
330
355
  # Percent encodes a URI component.
331
356
  #
@@ -392,18 +417,20 @@ module Addressable
392
417
  component.force_encoding(Encoding::ASCII_8BIT)
393
418
  # Avoiding gsub! because there are edge cases with frozen strings
394
419
  component = component.gsub(character_class) do |sequence|
395
- (sequence.unpack('C*').map { |c| "%" + ("%02x" % c).upcase }).join
420
+ SEQUENCE_UPCASED_PERCENT_ENCODING_TABLE[sequence]
396
421
  end
397
422
  if upcase_encoded.length > 0
398
- component = component.gsub(/%(#{upcase_encoded.chars.map do |char|
399
- char.unpack('C*').map { |c| '%02x' % c }.join
400
- end.join('|')})/i) { |s| s.upcase }
423
+ upcase_encoded_chars = upcase_encoded.chars.map do |char|
424
+ SEQUENCE_ENCODING_TABLE[char]
425
+ end
426
+ component = component.gsub(/%(#{upcase_encoded_chars.join('|')})/,
427
+ &:upcase)
401
428
  end
402
429
  return component
403
430
  end
404
431
 
405
432
  class << self
406
- alias_method :encode_component, :encode_component
433
+ alias_method :escape_component, :encode_component
407
434
  end
408
435
 
409
436
  ##
@@ -445,7 +472,11 @@ module Addressable
445
472
  uri = uri.dup
446
473
  # Seriously, only use UTF-8. I'm really not kidding!
447
474
  uri.force_encoding("utf-8")
448
- leave_encoded = leave_encoded.dup.force_encoding("utf-8")
475
+
476
+ unless leave_encoded.empty?
477
+ leave_encoded = leave_encoded.dup.force_encoding("utf-8")
478
+ end
479
+
449
480
  result = uri.gsub(/%[0-9a-f]{2}/iu) do |sequence|
450
481
  c = sequence[1..3].to_i(16).chr
451
482
  c.force_encoding("utf-8")
@@ -531,12 +562,16 @@ module Addressable
531
562
  character_class = "#{character_class}%" unless character_class.include?('%')
532
563
 
533
564
  "|%(?!#{leave_encoded.chars.map do |char|
534
- seq = char.unpack('C*').map { |c| '%02x' % c }.join
565
+ seq = SEQUENCE_ENCODING_TABLE[char]
535
566
  [seq.upcase, seq.downcase]
536
567
  end.flatten.join('|')})"
537
568
  end
538
569
 
539
- character_class = /[^#{character_class}]#{leave_re}/
570
+ character_class = if leave_re
571
+ /[^#{character_class}]#{leave_re}/
572
+ else
573
+ /[^#{character_class}]/
574
+ end
540
575
  end
541
576
  # We can't perform regexps on invalid UTF sequences, but
542
577
  # here we need to, so switch to ASCII.
@@ -860,7 +895,7 @@ module Addressable
860
895
  else
861
896
  Addressable::URI.normalize_component(
862
897
  self.scheme.strip.downcase,
863
- Addressable::URI::CharacterClasses::SCHEME
898
+ Addressable::URI::NormalizeCharacterClasses::SCHEME
864
899
  )
865
900
  end
866
901
  end
@@ -880,7 +915,7 @@ module Addressable
880
915
  new_scheme = new_scheme.to_str
881
916
  end
882
917
  if new_scheme && new_scheme !~ /\A[a-z][a-z0-9\.\+\-]*\z/i
883
- raise InvalidURIError, "Invalid scheme format: #{new_scheme}"
918
+ raise InvalidURIError, "Invalid scheme format: '#{new_scheme}'"
884
919
  end
885
920
  @scheme = new_scheme
886
921
  @scheme = nil if @scheme.to_s.strip.empty?
@@ -915,7 +950,7 @@ module Addressable
915
950
  else
916
951
  Addressable::URI.normalize_component(
917
952
  self.user.strip,
918
- Addressable::URI::CharacterClasses::UNRESERVED
953
+ Addressable::URI::NormalizeCharacterClasses::UNRESERVED
919
954
  )
920
955
  end
921
956
  end
@@ -972,7 +1007,7 @@ module Addressable
972
1007
  else
973
1008
  Addressable::URI.normalize_component(
974
1009
  self.password.strip,
975
- Addressable::URI::CharacterClasses::UNRESERVED
1010
+ Addressable::URI::NormalizeCharacterClasses::UNRESERVED
976
1011
  )
977
1012
  end
978
1013
  end
@@ -1096,6 +1131,7 @@ module Addressable
1096
1131
  # @return [String] The host component, normalized.
1097
1132
  def normalized_host
1098
1133
  return nil unless self.host
1134
+
1099
1135
  @normalized_host ||= begin
1100
1136
  if !self.host.strip.empty?
1101
1137
  result = ::Addressable::IDNA.to_ascii(
@@ -1107,14 +1143,17 @@ module Addressable
1107
1143
  end
1108
1144
  result = Addressable::URI.normalize_component(
1109
1145
  result,
1110
- CharacterClasses::HOST)
1146
+ NormalizeCharacterClasses::HOST
1147
+ )
1111
1148
  result
1112
1149
  else
1113
1150
  EMPTY_STR.dup
1114
1151
  end
1115
1152
  end
1116
1153
  # All normalized values should be UTF-8
1117
- @normalized_host.force_encoding(Encoding::UTF_8) if @normalized_host
1154
+ if @normalized_host && !@normalized_host.empty?
1155
+ @normalized_host.force_encoding(Encoding::UTF_8)
1156
+ end
1118
1157
  @normalized_host
1119
1158
  end
1120
1159
 
@@ -1172,7 +1211,7 @@ module Addressable
1172
1211
  # Returns the top-level domain for this host.
1173
1212
  #
1174
1213
  # @example
1175
- # Addressable::URI.parse("www.example.co.uk").tld # => "co.uk"
1214
+ # Addressable::URI.parse("http://www.example.co.uk").tld # => "co.uk"
1176
1215
  def tld
1177
1216
  PublicSuffix.parse(self.host, ignore_private: true).tld
1178
1217
  end
@@ -1182,7 +1221,7 @@ module Addressable
1182
1221
  #
1183
1222
  # @param [String, #to_str] new_tld The new top-level domain.
1184
1223
  def tld=(new_tld)
1185
- replaced_tld = domain.sub(/#{tld}\z/, new_tld)
1224
+ replaced_tld = host.sub(/#{tld}\z/, new_tld)
1186
1225
  self.host = PublicSuffix::Domain.new(replaced_tld).to_s
1187
1226
  end
1188
1227
 
@@ -1190,7 +1229,7 @@ module Addressable
1190
1229
  # Returns the public suffix domain for this host.
1191
1230
  #
1192
1231
  # @example
1193
- # Addressable::URI.parse("www.example.co.uk").domain # => "example.co.uk"
1232
+ # Addressable::URI.parse("http://www.example.co.uk").domain # => "example.co.uk"
1194
1233
  def domain
1195
1234
  PublicSuffix.domain(self.host, ignore_private: true)
1196
1235
  end
@@ -1519,7 +1558,7 @@ module Addressable
1519
1558
  result = path.strip.split(SLASH, -1).map do |segment|
1520
1559
  Addressable::URI.normalize_component(
1521
1560
  segment,
1522
- Addressable::URI::CharacterClasses::PCHAR
1561
+ Addressable::URI::NormalizeCharacterClasses::PCHAR
1523
1562
  )
1524
1563
  end.join(SLASH)
1525
1564
 
@@ -1594,10 +1633,15 @@ module Addressable
1594
1633
  modified_query_class = Addressable::URI::CharacterClasses::QUERY.dup
1595
1634
  # Make sure possible key-value pair delimiters are escaped.
1596
1635
  modified_query_class.sub!("\\&", "").sub!("\\;", "")
1597
- pairs = (self.query || "").split("&", -1)
1636
+ pairs = (query || "").split("&", -1)
1637
+ pairs.delete_if(&:empty?).uniq! if flags.include?(:compacted)
1598
1638
  pairs.sort! if flags.include?(:sorted)
1599
1639
  component = pairs.map do |pair|
1600
- Addressable::URI.normalize_component(pair, modified_query_class, "+")
1640
+ Addressable::URI.normalize_component(
1641
+ pair,
1642
+ Addressable::URI::NormalizeCharacterClasses::QUERY,
1643
+ "+"
1644
+ )
1601
1645
  end.join("&")
1602
1646
  component == "" ? nil : component
1603
1647
  end
@@ -1656,11 +1700,13 @@ module Addressable
1656
1700
  # so it's best to make all changes in-place.
1657
1701
  pair[0] = URI.unencode_component(pair[0])
1658
1702
  if pair[1].respond_to?(:to_str)
1703
+ value = pair[1].to_str
1659
1704
  # I loathe the fact that I have to do this. Stupid HTML 4.01.
1660
1705
  # Treating '+' as a space was just an unbelievably bad idea.
1661
1706
  # There was nothing wrong with '%20'!
1662
1707
  # If it ain't broke, don't fix it!
1663
- pair[1] = URI.unencode_component(pair[1].to_str.gsub(/\+/, " "))
1708
+ value = value.tr("+", " ") if ["http", "https", nil].include?(scheme)
1709
+ pair[1] = URI.unencode_component(value)
1664
1710
  end
1665
1711
  if return_type == Hash
1666
1712
  accu[pair[0]] = pair[1]
@@ -1791,7 +1837,7 @@ module Addressable
1791
1837
  @normalized_fragment ||= begin
1792
1838
  component = Addressable::URI.normalize_component(
1793
1839
  self.fragment,
1794
- Addressable::URI::CharacterClasses::FRAGMENT
1840
+ Addressable::URI::NormalizeCharacterClasses::FRAGMENT
1795
1841
  )
1796
1842
  component == "" ? nil : component
1797
1843
  end
@@ -1917,7 +1963,7 @@ module Addressable
1917
1963
  # Section 5.2.3 of RFC 3986
1918
1964
  #
1919
1965
  # Removes the right-most path segment from the base path.
1920
- if base_path =~ /\//
1966
+ if base_path.include?(SLASH)
1921
1967
  base_path.sub!(/\/[^\/]+$/, SLASH)
1922
1968
  else
1923
1969
  base_path = EMPTY_STR
@@ -2367,10 +2413,10 @@ module Addressable
2367
2413
  #
2368
2414
  # @param [Proc] block
2369
2415
  # A set of operations to perform on a given URI.
2370
- def defer_validation(&block)
2371
- raise LocalJumpError, "No block given." unless block
2416
+ def defer_validation
2417
+ raise LocalJumpError, "No block given." unless block_given?
2372
2418
  @validation_deferred = true
2373
- block.call()
2419
+ yield
2374
2420
  @validation_deferred = false
2375
2421
  validate
2376
2422
  return nil
@@ -23,7 +23,7 @@ if !defined?(Addressable::VERSION)
23
23
  module Addressable
24
24
  module VERSION
25
25
  MAJOR = 2
26
- MINOR = 6
26
+ MINOR = 8
27
27
  TINY = 0
28
28
 
29
29
  STRING = [MAJOR, MINOR, TINY].join('.')
@@ -294,7 +294,9 @@ begin
294
294
  it_should_behave_like "converting from unicode to ASCII"
295
295
  it_should_behave_like "converting from ASCII to unicode"
296
296
  end
297
- rescue LoadError
297
+ rescue LoadError => error
298
+ raise error if ENV["CI"] && TestHelper.native_supported?
299
+
298
300
  # Cannot test the native implementation without libidn support.
299
301
  warn('Could not load native IDN implementation.')
300
302
  end
@@ -19,6 +19,7 @@
19
19
  require "spec_helper"
20
20
 
21
21
  require "bigdecimal"
22
+ require "timeout"
22
23
  require "addressable/template"
23
24
 
24
25
  shared_examples_for 'expands' do |tests|
@@ -1340,6 +1341,14 @@ describe Addressable::Template do
1340
1341
  expect(subject).not_to match("foo_bar*")
1341
1342
  expect(subject).not_to match("foo_bar:20")
1342
1343
  end
1344
+
1345
+ it 'should parse in a reasonable time' do
1346
+ expect do
1347
+ Timeout.timeout(0.1) do
1348
+ expect(subject).not_to match("0"*25 + "!")
1349
+ end
1350
+ end.not_to raise_error
1351
+ end
1343
1352
  end
1344
1353
  context "VARIABLE_LIST" do
1345
1354
  subject { Addressable::Template::VARIABLE_LIST }
@@ -65,116 +65,116 @@ end
65
65
 
66
66
  describe Addressable::URI, "when created with a non-numeric port number" do
67
67
  it "should raise an error" do
68
- expect(lambda do
68
+ expect do
69
69
  Addressable::URI.new(:port => "bogus")
70
- end).to raise_error(Addressable::URI::InvalidURIError)
70
+ end.to raise_error(Addressable::URI::InvalidURIError)
71
71
  end
72
72
  end
73
73
 
74
74
  describe Addressable::URI, "when created with a invalid encoded port number" do
75
75
  it "should raise an error" do
76
- expect(lambda do
76
+ expect do
77
77
  Addressable::URI.new(:port => "%eb")
78
- end).to raise_error(Addressable::URI::InvalidURIError)
78
+ end.to raise_error(Addressable::URI::InvalidURIError)
79
79
  end
80
80
  end
81
81
 
82
82
  describe Addressable::URI, "when created with a non-string scheme" do
83
83
  it "should raise an error" do
84
- expect(lambda do
84
+ expect do
85
85
  Addressable::URI.new(:scheme => :bogus)
86
- end).to raise_error(TypeError)
86
+ end.to raise_error(TypeError)
87
87
  end
88
88
  end
89
89
 
90
90
  describe Addressable::URI, "when created with a non-string user" do
91
91
  it "should raise an error" do
92
- expect(lambda do
92
+ expect do
93
93
  Addressable::URI.new(:user => :bogus)
94
- end).to raise_error(TypeError)
94
+ end.to raise_error(TypeError)
95
95
  end
96
96
  end
97
97
 
98
98
  describe Addressable::URI, "when created with a non-string password" do
99
99
  it "should raise an error" do
100
- expect(lambda do
100
+ expect do
101
101
  Addressable::URI.new(:password => :bogus)
102
- end).to raise_error(TypeError)
102
+ end.to raise_error(TypeError)
103
103
  end
104
104
  end
105
105
 
106
106
  describe Addressable::URI, "when created with a non-string userinfo" do
107
107
  it "should raise an error" do
108
- expect(lambda do
108
+ expect do
109
109
  Addressable::URI.new(:userinfo => :bogus)
110
- end).to raise_error(TypeError)
110
+ end.to raise_error(TypeError)
111
111
  end
112
112
  end
113
113
 
114
114
  describe Addressable::URI, "when created with a non-string host" do
115
115
  it "should raise an error" do
116
- expect(lambda do
116
+ expect do
117
117
  Addressable::URI.new(:host => :bogus)
118
- end).to raise_error(TypeError)
118
+ end.to raise_error(TypeError)
119
119
  end
120
120
  end
121
121
 
122
122
  describe Addressable::URI, "when created with a non-string authority" do
123
123
  it "should raise an error" do
124
- expect(lambda do
124
+ expect do
125
125
  Addressable::URI.new(:authority => :bogus)
126
- end).to raise_error(TypeError)
126
+ end.to raise_error(TypeError)
127
127
  end
128
128
  end
129
129
 
130
130
  describe Addressable::URI, "when created with a non-string path" do
131
131
  it "should raise an error" do
132
- expect(lambda do
132
+ expect do
133
133
  Addressable::URI.new(:path => :bogus)
134
- end).to raise_error(TypeError)
134
+ end.to raise_error(TypeError)
135
135
  end
136
136
  end
137
137
 
138
138
  describe Addressable::URI, "when created with a non-string query" do
139
139
  it "should raise an error" do
140
- expect(lambda do
140
+ expect do
141
141
  Addressable::URI.new(:query => :bogus)
142
- end).to raise_error(TypeError)
142
+ end.to raise_error(TypeError)
143
143
  end
144
144
  end
145
145
 
146
146
  describe Addressable::URI, "when created with a non-string fragment" do
147
147
  it "should raise an error" do
148
- expect(lambda do
148
+ expect do
149
149
  Addressable::URI.new(:fragment => :bogus)
150
- end).to raise_error(TypeError)
150
+ end.to raise_error(TypeError)
151
151
  end
152
152
  end
153
153
 
154
154
  describe Addressable::URI, "when created with a scheme but no hierarchical " +
155
155
  "segment" do
156
156
  it "should raise an error" do
157
- expect(lambda do
157
+ expect do
158
158
  Addressable::URI.parse("http:")
159
- end).to raise_error(Addressable::URI::InvalidURIError)
159
+ end.to raise_error(Addressable::URI::InvalidURIError)
160
160
  end
161
161
  end
162
162
 
163
163
  describe Addressable::URI, "quote handling" do
164
164
  describe 'in host name' do
165
165
  it "should raise an error for single quote" do
166
- expect(lambda do
166
+ expect do
167
167
  Addressable::URI.parse("http://local\"host/")
168
- end).to raise_error(Addressable::URI::InvalidURIError)
168
+ end.to raise_error(Addressable::URI::InvalidURIError)
169
169
  end
170
170
  end
171
171
  end
172
172
 
173
173
  describe Addressable::URI, "newline normalization" do
174
174
  it "should not accept newlines in scheme" do
175
- expect(lambda do
175
+ expect do
176
176
  Addressable::URI.parse("ht%0atp://localhost/")
177
- end).to raise_error(Addressable::URI::InvalidURIError)
177
+ end.to raise_error(Addressable::URI::InvalidURIError)
178
178
  end
179
179
 
180
180
  it "should not unescape newline in path" do
@@ -199,47 +199,47 @@ describe Addressable::URI, "newline normalization" do
199
199
 
200
200
  it "should not accept newline in hostname" do
201
201
  uri = Addressable::URI.parse("http://localhost/")
202
- expect(lambda do
202
+ expect do
203
203
  uri.host = "local\nhost"
204
- end).to raise_error(Addressable::URI::InvalidURIError)
204
+ end.to raise_error(Addressable::URI::InvalidURIError)
205
205
  end
206
206
  end
207
207
 
208
208
  describe Addressable::URI, "when created with ambiguous path" do
209
209
  it "should raise an error" do
210
- expect(lambda do
210
+ expect do
211
211
  Addressable::URI.parse("::http")
212
- end).to raise_error(Addressable::URI::InvalidURIError)
212
+ end.to raise_error(Addressable::URI::InvalidURIError)
213
213
  end
214
214
  end
215
215
 
216
216
  describe Addressable::URI, "when created with an invalid host" do
217
217
  it "should raise an error" do
218
- expect(lambda do
218
+ expect do
219
219
  Addressable::URI.new(:host => "<invalid>")
220
- end).to raise_error(Addressable::URI::InvalidURIError)
220
+ end.to raise_error(Addressable::URI::InvalidURIError)
221
221
  end
222
222
  end
223
223
 
224
224
  describe Addressable::URI, "when created with a host consisting of " +
225
225
  "sub-delims characters" do
226
226
  it "should not raise an error" do
227
- expect(lambda do
227
+ expect do
228
228
  Addressable::URI.new(
229
229
  :host => Addressable::URI::CharacterClasses::SUB_DELIMS.gsub(/\\/, '')
230
230
  )
231
- end).not_to raise_error
231
+ end.not_to raise_error
232
232
  end
233
233
  end
234
234
 
235
235
  describe Addressable::URI, "when created with a host consisting of " +
236
236
  "unreserved characters" do
237
237
  it "should not raise an error" do
238
- expect(lambda do
238
+ expect do
239
239
  Addressable::URI.new(
240
240
  :host => Addressable::URI::CharacterClasses::UNRESERVED.gsub(/\\/, '')
241
241
  )
242
- end).not_to raise_error
242
+ end.not_to raise_error
243
243
  end
244
244
  end
245
245
 
@@ -269,83 +269,83 @@ describe Addressable::URI, "when created from nil components" do
269
269
  end
270
270
 
271
271
  it "should raise an error if the scheme is set to whitespace" do
272
- expect(lambda do
272
+ expect do
273
273
  @uri.scheme = "\t \n"
274
- end).to raise_error(Addressable::URI::InvalidURIError)
274
+ end.to raise_error(Addressable::URI::InvalidURIError, /'\t \n'/)
275
275
  end
276
276
 
277
277
  it "should raise an error if the scheme is set to all digits" do
278
- expect(lambda do
278
+ expect do
279
279
  @uri.scheme = "123"
280
- end).to raise_error(Addressable::URI::InvalidURIError)
280
+ end.to raise_error(Addressable::URI::InvalidURIError, /'123'/)
281
281
  end
282
282
 
283
283
  it "should raise an error if the scheme begins with a digit" do
284
- expect(lambda do
284
+ expect do
285
285
  @uri.scheme = "1scheme"
286
- end).to raise_error(Addressable::URI::InvalidURIError)
286
+ end.to raise_error(Addressable::URI::InvalidURIError, /'1scheme'/)
287
287
  end
288
288
 
289
289
  it "should raise an error if the scheme begins with a plus" do
290
- expect(lambda do
290
+ expect do
291
291
  @uri.scheme = "+scheme"
292
- end).to raise_error(Addressable::URI::InvalidURIError)
292
+ end.to raise_error(Addressable::URI::InvalidURIError, /'\+scheme'/)
293
293
  end
294
294
 
295
295
  it "should raise an error if the scheme begins with a dot" do
296
- expect(lambda do
296
+ expect do
297
297
  @uri.scheme = ".scheme"
298
- end).to raise_error(Addressable::URI::InvalidURIError)
298
+ end.to raise_error(Addressable::URI::InvalidURIError, /'\.scheme'/)
299
299
  end
300
300
 
301
301
  it "should raise an error if the scheme begins with a dash" do
302
- expect(lambda do
302
+ expect do
303
303
  @uri.scheme = "-scheme"
304
- end).to raise_error(Addressable::URI::InvalidURIError)
304
+ end.to raise_error(Addressable::URI::InvalidURIError, /'-scheme'/)
305
305
  end
306
306
 
307
307
  it "should raise an error if the scheme contains an illegal character" do
308
- expect(lambda do
308
+ expect do
309
309
  @uri.scheme = "scheme!"
310
- end).to raise_error(Addressable::URI::InvalidURIError)
310
+ end.to raise_error(Addressable::URI::InvalidURIError, /'scheme!'/)
311
311
  end
312
312
 
313
313
  it "should raise an error if the scheme contains whitespace" do
314
- expect(lambda do
314
+ expect do
315
315
  @uri.scheme = "sch eme"
316
- end).to raise_error(Addressable::URI::InvalidURIError)
316
+ end.to raise_error(Addressable::URI::InvalidURIError, /'sch eme'/)
317
317
  end
318
318
 
319
319
  it "should raise an error if the scheme contains a newline" do
320
- expect(lambda do
320
+ expect do
321
321
  @uri.scheme = "sch\neme"
322
- end).to raise_error(Addressable::URI::InvalidURIError)
322
+ end.to raise_error(Addressable::URI::InvalidURIError)
323
323
  end
324
324
 
325
325
  it "should raise an error if set into an invalid state" do
326
- expect(lambda do
326
+ expect do
327
327
  @uri.user = "user"
328
- end).to raise_error(Addressable::URI::InvalidURIError)
328
+ end.to raise_error(Addressable::URI::InvalidURIError)
329
329
  end
330
330
 
331
331
  it "should raise an error if set into an invalid state" do
332
- expect(lambda do
332
+ expect do
333
333
  @uri.password = "pass"
334
- end).to raise_error(Addressable::URI::InvalidURIError)
334
+ end.to raise_error(Addressable::URI::InvalidURIError)
335
335
  end
336
336
 
337
337
  it "should raise an error if set into an invalid state" do
338
- expect(lambda do
338
+ expect do
339
339
  @uri.scheme = "http"
340
340
  @uri.fragment = "fragment"
341
- end).to raise_error(Addressable::URI::InvalidURIError)
341
+ end.to raise_error(Addressable::URI::InvalidURIError)
342
342
  end
343
343
 
344
344
  it "should raise an error if set into an invalid state" do
345
- expect(lambda do
345
+ expect do
346
346
  @uri.fragment = "fragment"
347
347
  @uri.scheme = "http"
348
- end).to raise_error(Addressable::URI::InvalidURIError)
348
+ end.to raise_error(Addressable::URI::InvalidURIError)
349
349
  end
350
350
  end
351
351
 
@@ -1015,31 +1015,31 @@ describe Addressable::URI, "when created from string components" do
1015
1015
  end
1016
1016
 
1017
1017
  it "should raise an error if invalid components omitted" do
1018
- expect(lambda do
1018
+ expect do
1019
1019
  @uri.omit(:bogus)
1020
- end).to raise_error(ArgumentError)
1021
- expect(lambda do
1020
+ end.to raise_error(ArgumentError)
1021
+ expect do
1022
1022
  @uri.omit(:scheme, :bogus, :path)
1023
- end).to raise_error(ArgumentError)
1023
+ end.to raise_error(ArgumentError)
1024
1024
  end
1025
1025
  end
1026
1026
 
1027
1027
  describe Addressable::URI, "when created with a nil host but " +
1028
1028
  "non-nil authority components" do
1029
1029
  it "should raise an error" do
1030
- expect(lambda do
1030
+ expect do
1031
1031
  Addressable::URI.new(:user => "user", :password => "pass", :port => 80)
1032
- end).to raise_error(Addressable::URI::InvalidURIError)
1032
+ end.to raise_error(Addressable::URI::InvalidURIError)
1033
1033
  end
1034
1034
  end
1035
1035
 
1036
1036
  describe Addressable::URI, "when created with both an authority and a user" do
1037
1037
  it "should raise an error" do
1038
- expect(lambda do
1038
+ expect do
1039
1039
  Addressable::URI.new(
1040
1040
  :user => "user", :authority => "user@example.com:80"
1041
1041
  )
1042
- end).to raise_error(ArgumentError)
1042
+ end.to raise_error(ArgumentError)
1043
1043
  end
1044
1044
  end
1045
1045
 
@@ -1077,33 +1077,33 @@ end
1077
1077
 
1078
1078
  describe Addressable::URI, "when created with a host with a backslash" do
1079
1079
  it "should raise an error" do
1080
- expect(lambda do
1080
+ expect do
1081
1081
  Addressable::URI.new(:authority => "example\\example")
1082
- end).to raise_error(Addressable::URI::InvalidURIError)
1082
+ end.to raise_error(Addressable::URI::InvalidURIError)
1083
1083
  end
1084
1084
  end
1085
1085
 
1086
1086
  describe Addressable::URI, "when created with a host with a slash" do
1087
1087
  it "should raise an error" do
1088
- expect(lambda do
1088
+ expect do
1089
1089
  Addressable::URI.new(:authority => "example/example")
1090
- end).to raise_error(Addressable::URI::InvalidURIError)
1090
+ end.to raise_error(Addressable::URI::InvalidURIError)
1091
1091
  end
1092
1092
  end
1093
1093
 
1094
1094
  describe Addressable::URI, "when created with a host with a space" do
1095
1095
  it "should raise an error" do
1096
- expect(lambda do
1096
+ expect do
1097
1097
  Addressable::URI.new(:authority => "example example")
1098
- end).to raise_error(Addressable::URI::InvalidURIError)
1098
+ end.to raise_error(Addressable::URI::InvalidURIError)
1099
1099
  end
1100
1100
  end
1101
1101
 
1102
1102
  describe Addressable::URI, "when created with both a userinfo and a user" do
1103
1103
  it "should raise an error" do
1104
- expect(lambda do
1104
+ expect do
1105
1105
  Addressable::URI.new(:user => "user", :userinfo => "user:pass")
1106
- end).to raise_error(ArgumentError)
1106
+ end.to raise_error(ArgumentError)
1107
1107
  end
1108
1108
  end
1109
1109
 
@@ -1195,18 +1195,18 @@ describe Addressable::URI, "when parsed from something that looks " +
1195
1195
  "like a URI object" do
1196
1196
  it "should parse without error" do
1197
1197
  uri = Addressable::URI.parse(Fake::URI::HTTP.new("http://example.com/"))
1198
- expect(lambda do
1198
+ expect do
1199
1199
  Addressable::URI.parse(uri)
1200
- end).not_to raise_error
1200
+ end.not_to raise_error
1201
1201
  end
1202
1202
  end
1203
1203
 
1204
1204
  describe Addressable::URI, "when parsed from a standard library URI object" do
1205
1205
  it "should parse without error" do
1206
1206
  uri = Addressable::URI.parse(URI.parse("http://example.com/"))
1207
- expect(lambda do
1207
+ expect do
1208
1208
  Addressable::URI.parse(uri)
1209
- end).not_to raise_error
1209
+ end.not_to raise_error
1210
1210
  end
1211
1211
  end
1212
1212
 
@@ -1366,9 +1366,9 @@ describe Addressable::URI, "when parsed from " +
1366
1366
  end
1367
1367
 
1368
1368
  it "should not allow request URI assignment" do
1369
- expect(lambda do
1369
+ expect do
1370
1370
  @uri.request_uri = "/"
1371
- end).to raise_error(Addressable::URI::InvalidURIError)
1371
+ end.to raise_error(Addressable::URI::InvalidURIError)
1372
1372
  end
1373
1373
 
1374
1374
  it "should have a query of 'objectClass?one'" do
@@ -1390,9 +1390,9 @@ describe Addressable::URI, "when parsed from " +
1390
1390
  end
1391
1391
 
1392
1392
  it "should raise an error if omission would create an invalid URI" do
1393
- expect(lambda do
1393
+ expect do
1394
1394
  @uri.omit(:authority, :path)
1395
- end).to raise_error(Addressable::URI::InvalidURIError)
1395
+ end.to raise_error(Addressable::URI::InvalidURIError)
1396
1396
  end
1397
1397
 
1398
1398
  it "should have an origin of 'ldap://[2001:db8::7]'" do
@@ -1778,9 +1778,9 @@ describe Addressable::URI, "when parsed from " +
1778
1778
 
1779
1779
  it "should not be roughly equal to the string " +
1780
1780
  "'http://example.com:bogus/'" do
1781
- expect(lambda do
1781
+ expect do
1782
1782
  expect(@uri === "http://example.com:bogus/").to eq(false)
1783
- end).not_to raise_error
1783
+ end.not_to raise_error
1784
1784
  end
1785
1785
 
1786
1786
  it "should result in itself when joined with itself" do
@@ -1810,21 +1810,21 @@ describe Addressable::URI, "when parsed from " +
1810
1810
  end
1811
1811
 
1812
1812
  it "should not allow origin assignment without scheme" do
1813
- expect(lambda do
1813
+ expect do
1814
1814
  @uri.origin = "example.com"
1815
- end).to raise_error(Addressable::URI::InvalidURIError)
1815
+ end.to raise_error(Addressable::URI::InvalidURIError)
1816
1816
  end
1817
1817
 
1818
1818
  it "should not allow origin assignment without host" do
1819
- expect(lambda do
1819
+ expect do
1820
1820
  @uri.origin = "http://"
1821
- end).to raise_error(Addressable::URI::InvalidURIError)
1821
+ end.to raise_error(Addressable::URI::InvalidURIError)
1822
1822
  end
1823
1823
 
1824
1824
  it "should not allow origin assignment with bogus type" do
1825
- expect(lambda do
1825
+ expect do
1826
1826
  @uri.origin = :bogus
1827
- end).to raise_error(TypeError)
1827
+ end.to raise_error(TypeError)
1828
1828
  end
1829
1829
 
1830
1830
  # Section 6.2.3 of RFC 3986
@@ -1880,9 +1880,9 @@ describe Addressable::URI, "when parsed from " +
1880
1880
  end
1881
1881
 
1882
1882
  it "when joined with a bogus object a TypeError should be raised" do
1883
- expect(lambda do
1883
+ expect do
1884
1884
  @uri.join(42)
1885
- end).to raise_error(TypeError)
1885
+ end.to raise_error(TypeError)
1886
1886
  end
1887
1887
 
1888
1888
  it "should have the correct username after assignment" do
@@ -2015,15 +2015,15 @@ describe Addressable::URI, "when parsed from " +
2015
2015
  end
2016
2016
 
2017
2017
  it "should raise an error if the site value is set to something bogus" do
2018
- expect(lambda do
2018
+ expect do
2019
2019
  @uri.site = 42
2020
- end).to raise_error(TypeError)
2020
+ end.to raise_error(TypeError)
2021
2021
  end
2022
2022
 
2023
2023
  it "should raise an error if the request URI is set to something bogus" do
2024
- expect(lambda do
2024
+ expect do
2025
2025
  @uri.request_uri = 42
2026
- end).to raise_error(TypeError)
2026
+ end.to raise_error(TypeError)
2027
2027
  end
2028
2028
 
2029
2029
  it "should correctly convert to a hash" do
@@ -2072,9 +2072,9 @@ describe Addressable::URI, "when parsing IPv6 addresses" do
2072
2072
 
2073
2073
  it "should raise an error for " +
2074
2074
  "'http://[<invalid>]/'" do
2075
- expect(lambda do
2075
+ expect do
2076
2076
  Addressable::URI.parse("http://[<invalid>]/")
2077
- end).to raise_error(Addressable::URI::InvalidURIError)
2077
+ end.to raise_error(Addressable::URI::InvalidURIError)
2078
2078
  end
2079
2079
  end
2080
2080
 
@@ -2100,9 +2100,9 @@ describe Addressable::URI, "when assigning IPv6 address" do
2100
2100
  it "should not allow to set bare IPv6 address as host" do
2101
2101
  uri = Addressable::URI.parse("http://[::1]/")
2102
2102
  skip "not checked"
2103
- expect(lambda do
2103
+ expect do
2104
2104
  uri.host = '3ffe:1900:4545:3:200:f8ff:fe21:67cf'
2105
- end).to raise_error(Addressable::URI::InvalidURIError)
2105
+ end.to raise_error(Addressable::URI::InvalidURIError)
2106
2106
  end
2107
2107
  end
2108
2108
 
@@ -2134,9 +2134,9 @@ describe Addressable::URI, "when parsing IPvFuture addresses" do
2134
2134
 
2135
2135
  it "should raise an error for " +
2136
2136
  "'http://[v0.<invalid>]/'" do
2137
- expect(lambda do
2137
+ expect do
2138
2138
  Addressable::URI.parse("http://[v0.<invalid>]/")
2139
- end).to raise_error(Addressable::URI::InvalidURIError)
2139
+ end.to raise_error(Addressable::URI::InvalidURIError)
2140
2140
  end
2141
2141
  end
2142
2142
 
@@ -2480,9 +2480,9 @@ describe Addressable::URI, "when parsed from " +
2480
2480
  end
2481
2481
 
2482
2482
  it "should not raise an exception when normalized" do
2483
- expect(lambda do
2483
+ expect do
2484
2484
  @uri.normalize
2485
- end).not_to raise_error
2485
+ end.not_to raise_error
2486
2486
  end
2487
2487
 
2488
2488
  it "should be considered to be in normal form" do
@@ -2534,9 +2534,9 @@ describe Addressable::URI, "when parsed from " +
2534
2534
  end
2535
2535
 
2536
2536
  it "should not raise an exception when normalized" do
2537
- expect(lambda do
2537
+ expect do
2538
2538
  @uri.normalize
2539
- end).not_to raise_error
2539
+ end.not_to raise_error
2540
2540
  end
2541
2541
 
2542
2542
  it "should be considered to be in normal form" do
@@ -2559,9 +2559,9 @@ describe Addressable::URI, "when parsed from " +
2559
2559
  end
2560
2560
 
2561
2561
  it "should not raise an exception when normalized" do
2562
- expect(lambda do
2562
+ expect do
2563
2563
  @uri.normalize
2564
- end).not_to raise_error
2564
+ end.not_to raise_error
2565
2565
  end
2566
2566
 
2567
2567
  it "should be considered to be in normal form" do
@@ -2597,9 +2597,9 @@ describe Addressable::URI, "when parsed from " +
2597
2597
  end
2598
2598
 
2599
2599
  it "should raise an error if encoding with an unexpected return type" do
2600
- expect(lambda do
2600
+ expect do
2601
2601
  Addressable::URI.normalized_encode(@uri, Integer)
2602
- end).to raise_error(TypeError)
2602
+ end.to raise_error(TypeError)
2603
2603
  end
2604
2604
 
2605
2605
  it "if percent encoded should be 'http://example.com/C%25CC%25A7'" do
@@ -2615,9 +2615,9 @@ describe Addressable::URI, "when parsed from " +
2615
2615
  end
2616
2616
 
2617
2617
  it "should raise an error if encoding with an unexpected return type" do
2618
- expect(lambda do
2618
+ expect do
2619
2619
  Addressable::URI.encode(@uri, Integer)
2620
- end).to raise_error(TypeError)
2620
+ end.to raise_error(TypeError)
2621
2621
  end
2622
2622
 
2623
2623
  it "should be identical to its duplicate" do
@@ -2752,9 +2752,9 @@ describe Addressable::URI, "when parsed from " +
2752
2752
 
2753
2753
  it "should not be roughly equal to the string " +
2754
2754
  "'http://example.com:bogus/'" do
2755
- expect(lambda do
2755
+ expect do
2756
2756
  expect(@uri === "http://example.com:bogus/").to eq(false)
2757
- end).not_to raise_error
2757
+ end.not_to raise_error
2758
2758
  end
2759
2759
 
2760
2760
  it "should result in itself when joined with itself" do
@@ -3100,9 +3100,9 @@ describe Addressable::URI, "when parsed from " +
3100
3100
  end
3101
3101
 
3102
3102
  it "should become invalid when normalized" do
3103
- expect(lambda do
3103
+ expect do
3104
3104
  @uri.normalize
3105
- end).to raise_error(Addressable::URI::InvalidURIError, /authority/)
3105
+ end.to raise_error(Addressable::URI::InvalidURIError, /authority/)
3106
3106
  end
3107
3107
 
3108
3108
  it "should have a path of '/..//example.com'" do
@@ -3340,12 +3340,12 @@ describe Addressable::URI, "when parsed from " +
3340
3340
  end
3341
3341
 
3342
3342
  it "should raise an error if routing is attempted" do
3343
- expect(lambda do
3343
+ expect do
3344
3344
  @uri.route_to("http://example.com/")
3345
- end).to raise_error(ArgumentError, /relative\/path\/to\/resource/)
3346
- expect(lambda do
3345
+ end.to raise_error(ArgumentError, /relative\/path\/to\/resource/)
3346
+ expect do
3347
3347
  @uri.route_from("http://example.com/")
3348
- end).to raise_error(ArgumentError, /relative\/path\/to\/resource/)
3348
+ end.to raise_error(ArgumentError, /relative\/path\/to\/resource/)
3349
3349
  end
3350
3350
 
3351
3351
  it "when joined with 'another/relative/path' should be " +
@@ -3942,9 +3942,9 @@ describe Addressable::URI, "when parsed from " +
3942
3942
  end
3943
3943
 
3944
3944
  it "should raise an error if assigning a bogus object to the hostname" do
3945
- expect(lambda do
3945
+ expect do
3946
3946
  @uri.hostname = Object.new
3947
- end).to raise_error
3947
+ end.to raise_error(TypeError)
3948
3948
  end
3949
3949
 
3950
3950
  it "should have the correct port after assignment" do
@@ -4023,9 +4023,9 @@ describe Addressable::URI, "when parsed from " +
4023
4023
  end
4024
4024
 
4025
4025
  it "should raise an error if query values are set to a bogus type" do
4026
- expect(lambda do
4026
+ expect do
4027
4027
  @uri.query_values = "bogus"
4028
- end).to raise_error(TypeError)
4028
+ end.to raise_error(TypeError)
4029
4029
  end
4030
4030
 
4031
4031
  it "should have the correct fragment after assignment" do
@@ -4097,39 +4097,39 @@ describe Addressable::URI, "when parsed from " +
4097
4097
  end
4098
4098
 
4099
4099
  it "should fail to merge with bogus values" do
4100
- expect(lambda do
4100
+ expect do
4101
4101
  @uri.merge(:port => "bogus")
4102
- end).to raise_error(Addressable::URI::InvalidURIError)
4102
+ end.to raise_error(Addressable::URI::InvalidURIError)
4103
4103
  end
4104
4104
 
4105
4105
  it "should fail to merge with bogus values" do
4106
- expect(lambda do
4106
+ expect do
4107
4107
  @uri.merge(:authority => "bar@baz:bogus")
4108
- end).to raise_error(Addressable::URI::InvalidURIError)
4108
+ end.to raise_error(Addressable::URI::InvalidURIError)
4109
4109
  end
4110
4110
 
4111
4111
  it "should fail to merge with bogus parameters" do
4112
- expect(lambda do
4112
+ expect do
4113
4113
  @uri.merge(42)
4114
- end).to raise_error(TypeError)
4114
+ end.to raise_error(TypeError)
4115
4115
  end
4116
4116
 
4117
4117
  it "should fail to merge with bogus parameters" do
4118
- expect(lambda do
4118
+ expect do
4119
4119
  @uri.merge("http://example.com/")
4120
- end).to raise_error(TypeError)
4120
+ end.to raise_error(TypeError)
4121
4121
  end
4122
4122
 
4123
4123
  it "should fail to merge with both authority and subcomponents" do
4124
- expect(lambda do
4124
+ expect do
4125
4125
  @uri.merge(:authority => "foo:bar@baz:42", :port => "42")
4126
- end).to raise_error(ArgumentError)
4126
+ end.to raise_error(ArgumentError)
4127
4127
  end
4128
4128
 
4129
4129
  it "should fail to merge with both userinfo and subcomponents" do
4130
- expect(lambda do
4130
+ expect do
4131
4131
  @uri.merge(:userinfo => "foo:bar", :user => "foo")
4132
- end).to raise_error(ArgumentError)
4132
+ end.to raise_error(ArgumentError)
4133
4133
  end
4134
4134
 
4135
4135
  it "should be identical to its duplicate" do
@@ -4262,6 +4262,36 @@ describe Addressable::URI, "when parsed from " +
4262
4262
  end
4263
4263
  end
4264
4264
 
4265
+ describe Addressable::URI, "when parsed from 'https://example.com/?q=a+b'" do
4266
+ before do
4267
+ @uri = Addressable::URI.parse("https://example.com/?q=a+b")
4268
+ end
4269
+
4270
+ it "should have query_values of {'q' => 'a b'}" do
4271
+ expect(@uri.query_values).to eq("q" => "a b")
4272
+ end
4273
+ end
4274
+
4275
+ describe Addressable::URI, "when parsed from 'example.com?q=a+b'" do
4276
+ before do
4277
+ @uri = Addressable::URI.parse("example.com?q=a+b")
4278
+ end
4279
+
4280
+ it "should have query_values of {'q' => 'a b'}" do
4281
+ expect(@uri.query_values).to eq("q" => "a b")
4282
+ end
4283
+ end
4284
+
4285
+ describe Addressable::URI, "when parsed from 'mailto:?q=a+b'" do
4286
+ before do
4287
+ @uri = Addressable::URI.parse("mailto:?q=a+b")
4288
+ end
4289
+
4290
+ it "should have query_values of {'q' => 'a+b'}" do
4291
+ expect(@uri.query_values).to eq("q" => "a+b")
4292
+ end
4293
+ end
4294
+
4265
4295
  describe Addressable::URI, "when parsed from " +
4266
4296
  "'http://example.com/?q=a%2bb'" do
4267
4297
  before do
@@ -4303,6 +4333,46 @@ describe Addressable::URI, "when parsed from " +
4303
4333
  end
4304
4334
  end
4305
4335
 
4336
+ describe Addressable::URI, "when parsed from 'http://example/?b=1&a=2&c=3'" do
4337
+ before do
4338
+ @uri = Addressable::URI.parse("http://example/?b=1&a=2&c=3")
4339
+ end
4340
+
4341
+ it "should have a sorted normalized query of 'a=2&b=1&c=3'" do
4342
+ expect(@uri.normalized_query(:sorted)).to eq("a=2&b=1&c=3")
4343
+ end
4344
+ end
4345
+
4346
+ describe Addressable::URI, "when parsed from 'http://example/?&a&&c&'" do
4347
+ before do
4348
+ @uri = Addressable::URI.parse("http://example/?&a&&c&")
4349
+ end
4350
+
4351
+ it "should have a compacted normalized query of 'a&c'" do
4352
+ expect(@uri.normalized_query(:compacted)).to eq("a&c")
4353
+ end
4354
+ end
4355
+
4356
+ describe Addressable::URI, "when parsed from 'http://example.com/?a=1&a=1'" do
4357
+ before do
4358
+ @uri = Addressable::URI.parse("http://example.com/?a=1&a=1")
4359
+ end
4360
+
4361
+ it "should have a compacted normalized query of 'a=1'" do
4362
+ expect(@uri.normalized_query(:compacted)).to eq("a=1")
4363
+ end
4364
+ end
4365
+
4366
+ describe Addressable::URI, "when parsed from 'http://example.com/?a=1&a=2'" do
4367
+ before do
4368
+ @uri = Addressable::URI.parse("http://example.com/?a=1&a=2")
4369
+ end
4370
+
4371
+ it "should have a compacted normalized query of 'a=1&a=2'" do
4372
+ expect(@uri.normalized_query(:compacted)).to eq("a=1&a=2")
4373
+ end
4374
+ end
4375
+
4306
4376
  describe Addressable::URI, "when parsed from " +
4307
4377
  "'http://example.com/sound%2bvision'" do
4308
4378
  before do
@@ -4414,10 +4484,10 @@ describe Addressable::URI, "when parsed from " +
4414
4484
  end
4415
4485
 
4416
4486
  it "should raise an error after nil assignment of authority segment" do
4417
- expect(lambda do
4487
+ expect do
4418
4488
  # This would create an invalid URI
4419
4489
  @uri.authority = nil
4420
- end).to raise_error
4490
+ end.to raise_error(Addressable::URI::InvalidURIError)
4421
4491
  end
4422
4492
  end
4423
4493
 
@@ -4646,12 +4716,12 @@ describe Addressable::URI, "when parsed from " +
4646
4716
  end
4647
4717
 
4648
4718
  it "should raise an error if routing is attempted" do
4649
- expect(lambda do
4719
+ expect do
4650
4720
  @uri.route_to("http://example.com/")
4651
- end).to raise_error(ArgumentError, /\/\/example.com\//)
4652
- expect(lambda do
4721
+ end.to raise_error(ArgumentError, /\/\/example.com\//)
4722
+ expect do
4653
4723
  @uri.route_from("http://example.com/")
4654
- end).to raise_error(ArgumentError, /\/\/example.com\//)
4724
+ end.to raise_error(ArgumentError, /\/\/example.com\//)
4655
4725
  end
4656
4726
 
4657
4727
  it "should have a 'null' origin" do
@@ -4745,9 +4815,9 @@ end
4745
4815
  describe Addressable::URI, "when parsed from " +
4746
4816
  "'http://under_score.example.com/'" do
4747
4817
  it "should not cause an error" do
4748
- expect(lambda do
4818
+ expect do
4749
4819
  Addressable::URI.parse("http://under_score.example.com/")
4750
- end).not_to raise_error
4820
+ end.not_to raise_error
4751
4821
  end
4752
4822
  end
4753
4823
 
@@ -4819,9 +4889,9 @@ describe Addressable::URI, "when parsed from '?one=1&two=2&three=3'" do
4819
4889
  end
4820
4890
 
4821
4891
  it "should raise an error for invalid return type values" do
4822
- expect(lambda do
4823
- @uri.query_values(Fixnum)
4824
- end).to raise_error(ArgumentError)
4892
+ expect do
4893
+ @uri.query_values(Integer)
4894
+ end.to raise_error(ArgumentError)
4825
4895
  end
4826
4896
 
4827
4897
  it "should have the correct array query values" do
@@ -5422,9 +5492,9 @@ describe Addressable::URI, "with a base uri of 'http://a/b/c/d;p?q'" do
5422
5492
  end
5423
5493
 
5424
5494
  it "when joined with a bogus object a TypeError should be raised" do
5425
- expect(lambda do
5495
+ expect do
5426
5496
  Addressable::URI.join(@uri, 42)
5427
- end).to raise_error(TypeError)
5497
+ end.to raise_error(TypeError)
5428
5498
  end
5429
5499
  end
5430
5500
 
@@ -5451,9 +5521,9 @@ end
5451
5521
 
5452
5522
  describe Addressable::URI, "when converting a bogus path" do
5453
5523
  it "should raise a TypeError" do
5454
- expect(lambda do
5524
+ expect do
5455
5525
  Addressable::URI.convert_path(42)
5456
- end).to raise_error(TypeError)
5526
+ end.to raise_error(TypeError)
5457
5527
  end
5458
5528
  end
5459
5529
 
@@ -5515,18 +5585,18 @@ describe Addressable::URI, "when given the tld " do
5515
5585
  end
5516
5586
 
5517
5587
  context "which " do
5518
- let (:uri) { Addressable::URI.parse("http://comrade.net/path/to/source/") }
5588
+ let (:uri) { Addressable::URI.parse("http://www.comrade.net/path/to/source/") }
5519
5589
 
5520
5590
  it "contains a subdomain" do
5521
5591
  uri.tld = "co.uk"
5522
5592
 
5523
- expect(uri.to_s).to eq("http://comrade.co.uk/path/to/source/")
5593
+ expect(uri.to_s).to eq("http://www.comrade.co.uk/path/to/source/")
5524
5594
  end
5525
5595
 
5526
5596
  it "is part of the domain" do
5527
5597
  uri.tld = "com"
5528
5598
 
5529
- expect(uri.to_s).to eq("http://comrade.com/path/to/source/")
5599
+ expect(uri.to_s).to eq("http://www.comrade.com/path/to/source/")
5530
5600
  end
5531
5601
  end
5532
5602
  end
@@ -5648,9 +5718,9 @@ describe Addressable::URI, "when parsing a non-String object" do
5648
5718
  end
5649
5719
 
5650
5720
  it "should raise a TypeError for objects than cannot be converted" do
5651
- expect(lambda do
5721
+ expect do
5652
5722
  Addressable::URI.parse(42)
5653
- end).to raise_error(TypeError)
5723
+ end.to raise_error(TypeError)
5654
5724
  end
5655
5725
 
5656
5726
  it "should correctly parse heuristically anything with a 'to_str' method" do
@@ -5658,9 +5728,9 @@ describe Addressable::URI, "when parsing a non-String object" do
5658
5728
  end
5659
5729
 
5660
5730
  it "should raise a TypeError for objects than cannot be converted" do
5661
- expect(lambda do
5731
+ expect do
5662
5732
  Addressable::URI.heuristic_parse(42)
5663
- end).to raise_error(TypeError)
5733
+ end.to raise_error(TypeError)
5664
5734
  end
5665
5735
  end
5666
5736
 
@@ -5704,9 +5774,9 @@ end
5704
5774
 
5705
5775
  describe Addressable::URI, "when form encoding a non-Array object" do
5706
5776
  it "should raise a TypeError for objects than cannot be converted" do
5707
- expect(lambda do
5777
+ expect do
5708
5778
  Addressable::URI.form_encode(42)
5709
- end).to raise_error(TypeError)
5779
+ end.to raise_error(TypeError)
5710
5780
  end
5711
5781
  end
5712
5782
 
@@ -5772,9 +5842,9 @@ describe Addressable::URI, "when form unencoding a non-String object" do
5772
5842
  end
5773
5843
 
5774
5844
  it "should raise a TypeError for objects than cannot be converted" do
5775
- expect(lambda do
5845
+ expect do
5776
5846
  Addressable::URI.form_unencode(42)
5777
- end).to raise_error(TypeError)
5847
+ end.to raise_error(TypeError)
5778
5848
  end
5779
5849
  end
5780
5850
 
@@ -5784,15 +5854,15 @@ describe Addressable::URI, "when normalizing a non-String object" do
5784
5854
  end
5785
5855
 
5786
5856
  it "should raise a TypeError for objects than cannot be converted" do
5787
- expect(lambda do
5857
+ expect do
5788
5858
  Addressable::URI.normalize_component(42)
5789
- end).to raise_error(TypeError)
5859
+ end.to raise_error(TypeError)
5790
5860
  end
5791
5861
 
5792
5862
  it "should raise a TypeError for objects than cannot be converted" do
5793
- expect(lambda do
5863
+ expect do
5794
5864
  Addressable::URI.normalize_component("component", 42)
5795
- end).to raise_error(TypeError)
5865
+ end.to raise_error(TypeError)
5796
5866
  end
5797
5867
  end
5798
5868
 
@@ -5864,6 +5934,18 @@ describe Addressable::URI, "when normalizing a string but leaving some character
5864
5934
  end
5865
5935
  end
5866
5936
 
5937
+ describe Addressable::URI, "when encoding IP literals" do
5938
+ it "should work for IPv4" do
5939
+ input = "http://127.0.0.1/"
5940
+ expect(Addressable::URI.encode(input)).to eq(input)
5941
+ end
5942
+
5943
+ it "should work for IPv6" do
5944
+ input = "http://[fe80::200:f8ff:fe21:67cf]/"
5945
+ expect(Addressable::URI.encode(input)).to eq(input)
5946
+ end
5947
+ end
5948
+
5867
5949
  describe Addressable::URI, "when encoding a string with existing encodings to upcase" do
5868
5950
  it "should result in correct percent encoded sequence" do
5869
5951
  expect(Addressable::URI.encode_component("JK%4c", "0-9A-IKM-Za-z%", "L")).to eq("%4AK%4C")
@@ -5936,41 +6018,41 @@ end
5936
6018
 
5937
6019
  describe Addressable::URI, "when unencoding a bogus object" do
5938
6020
  it "should raise a TypeError" do
5939
- expect(lambda do
6021
+ expect do
5940
6022
  Addressable::URI.unencode_component(42)
5941
- end).to raise_error(TypeError)
6023
+ end.to raise_error(TypeError)
5942
6024
  end
5943
6025
 
5944
6026
  it "should raise a TypeError" do
5945
- expect(lambda do
6027
+ expect do
5946
6028
  Addressable::URI.unencode("/path?g%C3%BCnther", Integer)
5947
- end).to raise_error(TypeError)
6029
+ end.to raise_error(TypeError)
5948
6030
  end
5949
6031
  end
5950
6032
 
5951
6033
  describe Addressable::URI, "when encoding a bogus object" do
5952
6034
  it "should raise a TypeError" do
5953
- expect(lambda do
6035
+ expect do
5954
6036
  Addressable::URI.encode(Object.new)
5955
- end).to raise_error(TypeError)
6037
+ end.to raise_error(TypeError)
5956
6038
  end
5957
6039
 
5958
6040
  it "should raise a TypeError" do
5959
- expect(lambda do
6041
+ expect do
5960
6042
  Addressable::URI.normalized_encode(Object.new)
5961
- end).to raise_error(TypeError)
6043
+ end.to raise_error(TypeError)
5962
6044
  end
5963
6045
 
5964
6046
  it "should raise a TypeError" do
5965
- expect(lambda do
6047
+ expect do
5966
6048
  Addressable::URI.encode_component("günther", Object.new)
5967
- end).to raise_error(TypeError)
6049
+ end.to raise_error(TypeError)
5968
6050
  end
5969
6051
 
5970
6052
  it "should raise a TypeError" do
5971
- expect(lambda do
6053
+ expect do
5972
6054
  Addressable::URI.encode_component(Object.new)
5973
- end).to raise_error(TypeError)
6055
+ end.to raise_error(TypeError)
5974
6056
  end
5975
6057
  end
5976
6058
 
@@ -5986,9 +6068,9 @@ describe Addressable::URI, "when given the input " +
5986
6068
  end
5987
6069
 
5988
6070
  it "should not raise error when frozen" do
5989
- expect(lambda do
6071
+ expect do
5990
6072
  Addressable::URI.heuristic_parse(@input).freeze.to_s
5991
- end).not_to raise_error
6073
+ end.not_to raise_error
5992
6074
  end
5993
6075
  end
5994
6076
 
@@ -6352,6 +6434,44 @@ describe Addressable::URI, "when given the input " +
6352
6434
  end
6353
6435
  end
6354
6436
 
6437
+ describe Addressable::URI, "when given the input: 'user@domain.com'" do
6438
+ before do
6439
+ @input = "user@domain.com"
6440
+ end
6441
+
6442
+ context "for heuristic parse" do
6443
+ it "should remain 'mailto:user@domain.com'" do
6444
+ uri = Addressable::URI.heuristic_parse("mailto:#{@input}")
6445
+ expect(uri.to_s).to eq("mailto:user@domain.com")
6446
+ end
6447
+
6448
+ it "should have a scheme of 'mailto'" do
6449
+ uri = Addressable::URI.heuristic_parse(@input)
6450
+ expect(uri.to_s).to eq("mailto:user@domain.com")
6451
+ expect(uri.scheme).to eq("mailto")
6452
+ end
6453
+
6454
+ it "should remain 'acct:user@domain.com'" do
6455
+ uri = Addressable::URI.heuristic_parse("acct:#{@input}")
6456
+ expect(uri.to_s).to eq("acct:user@domain.com")
6457
+ end
6458
+
6459
+ context "HTTP" do
6460
+ before do
6461
+ @uri = Addressable::URI.heuristic_parse("http://#{@input}/")
6462
+ end
6463
+
6464
+ it "should remain 'http://user@domain.com/'" do
6465
+ expect(@uri.to_s).to eq("http://user@domain.com/")
6466
+ end
6467
+
6468
+ it "should have the username 'user' for HTTP basic authentication" do
6469
+ expect(@uri.user).to eq("user")
6470
+ end
6471
+ end
6472
+ end
6473
+ end
6474
+
6355
6475
  describe Addressable::URI, "when assigning query values" do
6356
6476
  before do
6357
6477
  @uri = Addressable::URI.new
@@ -6363,54 +6483,54 @@ describe Addressable::URI, "when assigning query values" do
6363
6483
  end
6364
6484
 
6365
6485
  it "should raise an error attempting to assign {'a' => {'b' => ['c']}}" do
6366
- expect(lambda do
6486
+ expect do
6367
6487
  @uri.query_values = { 'a' => {'b' => ['c'] } }
6368
- end).to raise_error(TypeError)
6488
+ end.to raise_error(TypeError)
6369
6489
  end
6370
6490
 
6371
6491
  it "should raise an error attempting to assign " +
6372
6492
  "{:b => '2', :a => {:c => '1'}}" do
6373
- expect(lambda do
6493
+ expect do
6374
6494
  @uri.query_values = {:b => '2', :a => {:c => '1'}}
6375
- end).to raise_error(TypeError)
6495
+ end.to raise_error(TypeError)
6376
6496
  end
6377
6497
 
6378
6498
  it "should raise an error attempting to assign " +
6379
6499
  "{:a => 'a', :b => [{:c => 'c', :d => 'd'}, " +
6380
6500
  "{:e => 'e', :f => 'f'}]}" do
6381
- expect(lambda do
6501
+ expect do
6382
6502
  @uri.query_values = {
6383
6503
  :a => "a", :b => [{:c => "c", :d => "d"}, {:e => "e", :f => "f"}]
6384
6504
  }
6385
- end).to raise_error(TypeError)
6505
+ end.to raise_error(TypeError)
6386
6506
  end
6387
6507
 
6388
6508
  it "should raise an error attempting to assign " +
6389
6509
  "{:a => 'a', :b => [{:c => true, :d => 'd'}, " +
6390
6510
  "{:e => 'e', :f => 'f'}]}" do
6391
- expect(lambda do
6511
+ expect do
6392
6512
  @uri.query_values = {
6393
6513
  :a => 'a', :b => [{:c => true, :d => 'd'}, {:e => 'e', :f => 'f'}]
6394
6514
  }
6395
- end).to raise_error(TypeError)
6515
+ end.to raise_error(TypeError)
6396
6516
  end
6397
6517
 
6398
6518
  it "should raise an error attempting to assign " +
6399
6519
  "{:a => 'a', :b => {:c => true, :d => 'd'}}" do
6400
- expect(lambda do
6520
+ expect do
6401
6521
  @uri.query_values = {
6402
6522
  :a => 'a', :b => {:c => true, :d => 'd'}
6403
6523
  }
6404
- end).to raise_error(TypeError)
6524
+ end.to raise_error(TypeError)
6405
6525
  end
6406
6526
 
6407
6527
  it "should raise an error attempting to assign " +
6408
6528
  "{:a => 'a', :b => {:c => true, :d => 'd'}}" do
6409
- expect(lambda do
6529
+ expect do
6410
6530
  @uri.query_values = {
6411
6531
  :a => 'a', :b => {:c => true, :d => 'd'}
6412
6532
  }
6413
- end).to raise_error(TypeError)
6533
+ end.to raise_error(TypeError)
6414
6534
  end
6415
6535
 
6416
6536
  it "should correctly assign {:a => 1, :b => 1.5}" do
@@ -6421,13 +6541,13 @@ describe Addressable::URI, "when assigning query values" do
6421
6541
  it "should raise an error attempting to assign " +
6422
6542
  "{:z => 1, :f => [2, {999.1 => [3,'4']}, ['h', 'i']], " +
6423
6543
  ":a => {:b => ['c', 'd'], :e => true, :y => 0.5}}" do
6424
- expect(lambda do
6544
+ expect do
6425
6545
  @uri.query_values = {
6426
6546
  :z => 1,
6427
6547
  :f => [ 2, {999.1 => [3,'4']}, ['h', 'i'] ],
6428
6548
  :a => { :b => ['c', 'd'], :e => true, :y => 0.5 }
6429
6549
  }
6430
- end).to raise_error(TypeError)
6550
+ end.to raise_error(TypeError)
6431
6551
  end
6432
6552
 
6433
6553
  it "should correctly assign {}" do
@@ -6477,7 +6597,7 @@ describe Addressable::URI, "when assigning path values" do
6477
6597
  @uri.path = "acct:bob@sporkmonger.com"
6478
6598
  expect(@uri.path).to eq("acct:bob@sporkmonger.com")
6479
6599
  expect(@uri.normalize.to_str).to eq("acct%2Fbob@sporkmonger.com")
6480
- expect(lambda { @uri.to_s }).to raise_error(
6600
+ expect { @uri.to_s }.to raise_error(
6481
6601
  Addressable::URI::InvalidURIError
6482
6602
  )
6483
6603
  end
@@ -6495,26 +6615,26 @@ describe Addressable::URI, "when assigning path values" do
6495
6615
  end
6496
6616
 
6497
6617
  it "should not allow relative paths to be assigned on absolute URIs" do
6498
- expect(lambda do
6618
+ expect do
6499
6619
  @uri.scheme = "http"
6500
6620
  @uri.host = "example.com"
6501
6621
  @uri.path = "acct:bob@sporkmonger.com"
6502
- end).to raise_error(Addressable::URI::InvalidURIError)
6622
+ end.to raise_error(Addressable::URI::InvalidURIError)
6503
6623
  end
6504
6624
 
6505
6625
  it "should not allow relative paths to be assigned on absolute URIs" do
6506
- expect(lambda do
6626
+ expect do
6507
6627
  @uri.path = "acct:bob@sporkmonger.com"
6508
6628
  @uri.scheme = "http"
6509
6629
  @uri.host = "example.com"
6510
- end).to raise_error(Addressable::URI::InvalidURIError)
6630
+ end.to raise_error(Addressable::URI::InvalidURIError)
6511
6631
  end
6512
6632
 
6513
6633
  it "should not allow relative paths to be assigned on absolute URIs" do
6514
- expect(lambda do
6634
+ expect do
6515
6635
  @uri.path = "uuid:0b3ecf60-3f93-11df-a9c3-001f5bfffe12"
6516
6636
  @uri.scheme = "urn"
6517
- end).not_to raise_error
6637
+ end.not_to raise_error
6518
6638
  end
6519
6639
  end
6520
6640