addressable 2.3.3 → 2.3.4

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.

@@ -1,3 +1,9 @@
1
+ # Addressable 2.3.4
2
+ - fixed issue with encoding altering its inputs
3
+ - query string normalization now leaves ';' characters alone
4
+ - FakeFS is detected before attempting to load unicode tables
5
+ - additional testing to ensure frozen objects don't cause problems
6
+
1
7
  # Addressable 2.3.3
2
8
  - fixed issue with converting common primitives during template expansion
3
9
  - fixed port encoding issue
data/README.md CHANGED
@@ -20,68 +20,79 @@ RFC 6570 (level 4), providing support for IRIs and URI templates.
20
20
 
21
21
  - {Addressable::URI}
22
22
  - {Addressable::Template}
23
- - {Addressable::UriTemplate}
24
23
 
25
24
  # Example usage
26
25
 
27
- require "addressable/uri"
28
-
29
- uri = Addressable::URI.parse("http://example.com/path/to/resource/")
30
- uri.scheme
31
- #=> "http"
32
- uri.host
33
- #=> "example.com"
34
- uri.path
35
- #=> "/path/to/resource/"
36
-
37
- uri = Addressable::URI.parse("http://www.詹姆斯.com/")
38
- uri.normalize
39
- #=> #<Addressable::URI:0xc9a4c8 URI:http://www.xn--8ws00zhy3a.com/>
40
-
41
- require "addressable/template"
42
-
43
- template = Addressable::Template.new("http://example.com/{-list|+|query}/")
44
- template.expand({
45
- "query" => "an example query".split(" ")
46
- })
47
- #=> #<Addressable::URI:0xc9d95c URI:http://example.com/an+example+query/>
48
-
49
- template = Addressable::Template.new(
50
- "http://example.com/{-join|&|one,two,three}/"
51
- )
52
- template.partial_expand({"one" => "1", "three" => 3}).pattern
53
- #=> "http://example.com/?one=1{-prefix|&two=|two}&three=3"
54
-
55
- template = Addressable::Template.new(
56
- "http://{host}/{-suffix|/|segments}?{-join|&|one,two,bogus}\#{fragment}"
57
- )
58
- template2 = Addressable::UriTemplate.new(
59
- "http://{host}{/segments}/{?one,two,bogus}{#fragment}"
60
- )
61
- uri = Addressable::URI.parse(
62
- "http://example.com/a/b/c/?one=1&two=2#foo"
63
- )
64
- template.extract(uri)
65
- template2.extract(uri)
66
- #=>
67
- # {
68
- # "host" => "example.com",
69
- # "segments" => ["a", "b", "c"],
70
- # "one" => "1",
71
- # "two" => "2",
72
- # "fragment" => "foo"
73
- # }
26
+ ```ruby
27
+ require "addressable/uri"
28
+
29
+ uri = Addressable::URI.parse("http://example.com/path/to/resource/")
30
+ uri.scheme
31
+ #=> "http"
32
+ uri.host
33
+ #=> "example.com"
34
+ uri.path
35
+ #=> "/path/to/resource/"
36
+
37
+ uri = Addressable::URI.parse("http://www.詹姆斯.com/")
38
+ uri.normalize
39
+ #=> #<Addressable::URI:0xc9a4c8 URI:http://www.xn--8ws00zhy3a.com/>
40
+ ```
41
+
42
+
43
+ # URI Templates
44
+
45
+ For more details, see [RFC 6570](https://www.rfc-editor.org/rfc/rfc6570.txt).
46
+
47
+
48
+ ```ruby
49
+
50
+ require "addressable/template"
51
+
52
+ template = Addressable::Template.new("http://example.com/{?query*}/")
53
+ template.expand({
54
+ "query" => {
55
+ 'foo' => 'bar',
56
+ 'color' => 'red'
57
+ }
58
+ })
59
+ #=> #<Addressable::URI:0xc9d95c URI:http://example.com/?foo=bar&color=red>
60
+
61
+ template = Addressable::Template.new("http://example.com/{?one,two,three}/")
62
+ template.partial_expand({"one" => "1", "three" => 3}).pattern
63
+ #=> "http://example.com/?one=1{&two}&three=3"
64
+
65
+ template = Addressable::Template.new(
66
+ "http://{host}{/segments}/{?one,two,bogus}{#fragment}"
67
+ )
68
+ uri = Addressable::URI.parse(
69
+ "http://example.com/a/b/c/?one=1&two=2#foo"
70
+ )
71
+ template.extract(uri)
72
+ #=>
73
+ # {
74
+ # "host" => "example.com",
75
+ # "segments" => ["a", "b", "c"],
76
+ # "one" => "1",
77
+ # "two" => "2",
78
+ # "fragment" => "foo"
79
+ # }
80
+ ```
74
81
 
75
82
  # Install
76
83
 
77
- $ sudo gem install addressable
84
+ ```console
85
+ $ sudo gem install addressable
86
+ ```
78
87
 
79
88
  You may optionally turn on native IDN support by installing libidn and the
80
89
  idn gem:
81
90
 
82
- $ sudo apt-get install idn # Debian/Ubuntu
83
- $ sudo brew install libidn # OS X
84
- $ sudo gem install idn
91
+ ```console
92
+ $ sudo apt-get install idn # Debian/Ubuntu
93
+ $ sudo brew install libidn # OS X
94
+ $ sudo gem install idn
95
+ ```
85
96
 
86
97
  **NOTE:** Native IDN support appears to be broken in Ruby 1.9.x. The IDN gem
87
98
  hasn't been updated in years.
@@ -106,6 +106,7 @@ module Addressable
106
106
 
107
107
  # Unicode normalization form KC.
108
108
  def self.unicode_normalize_kc(input)
109
+ input = input.to_s unless input.is_a?(String)
109
110
  unpacked = input.unpack("U*")
110
111
  unpacked =
111
112
  unicode_compose(unicode_sort_canonical(unicode_decompose(unpacked)))
@@ -317,10 +318,20 @@ module Addressable
317
318
  UNICODE_DATA_LOWERCASE = 5
318
319
  UNICODE_DATA_TITLECASE = 6
319
320
 
320
- # This is a sparse Unicode table. Codepoints without entries are
321
- # assumed to have the value: [0, 0, nil, nil, nil, nil, nil]
322
- UNICODE_DATA = File.open(UNICODE_TABLE, "rb") do |file|
323
- Marshal.load(file.read)
321
+ begin
322
+ if defined?(FakeFS)
323
+ fakefs_state = FakeFS.activated?
324
+ FakeFS.deactivate!
325
+ end
326
+ # This is a sparse Unicode table. Codepoints without entries are
327
+ # assumed to have the value: [0, 0, nil, nil, nil, nil, nil]
328
+ UNICODE_DATA = File.open(UNICODE_TABLE, "rb") do |file|
329
+ Marshal.load(file.read)
330
+ end
331
+ ensure
332
+ if defined?(FakeFS)
333
+ FakeFS.activate! if fakefs_state
334
+ end
324
335
  end
325
336
 
326
337
  COMPOSITION_TABLE = {}
@@ -132,6 +132,7 @@ module Addressable
132
132
  self.template.variables
133
133
  end
134
134
  alias_method :keys, :variables
135
+ alias_method :names, :variables
135
136
 
136
137
  ##
137
138
  # @return [Array]
@@ -146,6 +147,64 @@ module Addressable
146
147
  end
147
148
  alias_method :captures, :values
148
149
 
150
+ ##
151
+ # Accesses captured values by name or by index.
152
+ #
153
+ # @param [String, Symbol, Fixnum] key
154
+ # Capture index or name. Note that when accessing by with index
155
+ # of 0, the full URI will be returned. The intention is to mimic
156
+ # the ::MatchData#[] behavior.
157
+ #
158
+ # @param [#to_int, nil] len
159
+ # If provided, an array of values will be returend with the given
160
+ # parameter used as length.
161
+ #
162
+ # @return [Array, String, nil]
163
+ # The captured value corresponding to the index or name. If the
164
+ # value was not provided or the key is unknown, nil will be
165
+ # returned.
166
+ #
167
+ # If the second parameter is provided, an array of that length will
168
+ # be returned instead.
169
+ def [](key, len = nil)
170
+ if len
171
+ to_a[key, len]
172
+ elsif String === key or Symbol === key
173
+ mapping[key.to_s]
174
+ else
175
+ to_a[key]
176
+ end
177
+ end
178
+
179
+ ##
180
+ # @return [Array]
181
+ # Array with the matched URI as first element followed by the captured
182
+ # values.
183
+ def to_a
184
+ [to_s, *values]
185
+ end
186
+
187
+ ##
188
+ # @return [String]
189
+ # The matched URI as String.
190
+ def to_s
191
+ uri.to_s
192
+ end
193
+ alias_method :string, :to_s
194
+
195
+ # Returns multiple captured values at once.
196
+ #
197
+ # @param [String, Symbol, Fixnum] *indexes
198
+ # Indices of the captures to be returned
199
+ #
200
+ # @return [Array]
201
+ # Values corresponding to given indices.
202
+ #
203
+ # @see Addressable::Template::MatchData#[]
204
+ def values_at(*indexes)
205
+ indexes.map { |i| self[i] }
206
+ end
207
+
149
208
  ##
150
209
  # Returns a <tt>String</tt> representation of the MatchData's state.
151
210
  #
@@ -154,6 +213,15 @@ module Addressable
154
213
  sprintf("#<%s:%#0x RESULT:%s>",
155
214
  self.class.to_s, self.object_id, self.mapping.inspect)
156
215
  end
216
+
217
+ ##
218
+ # Dummy method for code expecting a ::MatchData instance
219
+ #
220
+ # @return [String] An empty string.
221
+ def pre_match
222
+ ""
223
+ end
224
+ alias_method :post_match, :pre_match
157
225
  end
158
226
 
159
227
  ##
@@ -363,11 +363,12 @@ module Addressable
363
363
  component = component.dup
364
364
  component.force_encoding(Encoding::ASCII_8BIT)
365
365
  end
366
- component.gsub!(character_class) do |sequence|
366
+ # Avoiding gsub! because there are edge cases with frozen strings
367
+ component = component.gsub(character_class) do |sequence|
367
368
  (sequence.unpack('C*').map { |c| "%" + ("%02x" % c).upcase }).join
368
369
  end
369
370
  if upcase_encoded.length > 0
370
- component.gsub!(/%(#{upcase_encoded.chars.map do |char|
371
+ component = component.gsub(/%(#{upcase_encoded.chars.map do |char|
371
372
  char.unpack('C*').map { |c| '%02x' % c }.join
372
373
  end.join('|')})/i) { |s| s.upcase }
373
374
  end
@@ -1430,10 +1431,14 @@ module Addressable
1430
1431
  # @return [String] The query component, normalized.
1431
1432
  def normalized_query
1432
1433
  self.query && @normalized_query ||= (begin
1434
+ modified_query_class = Addressable::URI::CharacterClasses::QUERY
1435
+ # Make sure possible key-value pair delimiters are escaped.
1436
+ modified_query_class = modified_query_class.sub("\\&", "")
1437
+ modified_query_class = modified_query_class.sub("\\;", "")
1433
1438
  (self.query.split("&", -1).map do |pair|
1434
1439
  Addressable::URI.normalize_component(
1435
1440
  pair,
1436
- Addressable::URI::CharacterClasses::QUERY.sub("\\&", ""),
1441
+ modified_query_class,
1437
1442
  '+'
1438
1443
  )
1439
1444
  end).join("&")
@@ -1907,7 +1912,7 @@ module Addressable
1907
1912
  end
1908
1913
  else
1909
1914
  if uri.path != SLASH
1910
- components[:path].gsub!(
1915
+ components[:path] = components[:path].gsub(
1911
1916
  Regexp.new("^" + Regexp.escape(uri.path)), EMPTY_STR)
1912
1917
  end
1913
1918
  end
@@ -22,7 +22,7 @@ if !defined?(Addressable::VERSION)
22
22
  module VERSION
23
23
  MAJOR = 2
24
24
  MINOR = 3
25
- TINY = 3
25
+ TINY = 4
26
26
 
27
27
  STRING = [MAJOR, MINOR, TINY].join('.')
28
28
  end
@@ -186,6 +186,11 @@ shared_examples_for "converting from ASCII to unicode" do
186
186
  "xn--4ud"
187
187
  ).should == "\341\206\265"
188
188
  end
189
+
190
+ it "should normalize 'string' correctly" do
191
+ Addressable::IDNA.unicode_normalize_kc(:'string').should == "string"
192
+ Addressable::IDNA.unicode_normalize_kc("string").should == "string"
193
+ end
189
194
  end
190
195
 
191
196
  describe Addressable::IDNA, "when using the pure-Ruby implementation" do
@@ -1020,3 +1020,77 @@ describe Addressable::Template do
1020
1020
  end
1021
1021
  end
1022
1022
  end
1023
+
1024
+ describe Addressable::Template::MatchData do
1025
+ let(:template) { Addressable::Template.new('{foo}/{bar}') }
1026
+ subject(:its) { template.match('ab/cd') }
1027
+ its(:uri) { should == Addressable::URI.parse('ab/cd') }
1028
+ its(:template) { should == template }
1029
+ its(:mapping) { should == { 'foo' => 'ab', 'bar' => 'cd' } }
1030
+ its(:variables) { should == ['foo', 'bar'] }
1031
+ its(:keys) { should == its.variables }
1032
+ its(:names) { should == its.variables }
1033
+ its(:values) { should == ['ab', 'cd'] }
1034
+ its(:captures) { should == its.values }
1035
+ its(:to_a) { should == ['ab/cd', 'ab', 'cd'] }
1036
+ its(:to_s) { should == 'ab/cd' }
1037
+ its(:string) { should == its.to_s }
1038
+ its(:pre_match) { should == "" }
1039
+ its(:post_match) { should == "" }
1040
+
1041
+ describe 'values_at' do
1042
+ it 'returns an array with the values' do
1043
+ its.values_at(0, 2).should == ['ab/cd', 'cd']
1044
+ end
1045
+ it 'allows mixing integer an string keys' do
1046
+ its.values_at('foo', 1).should == ['ab', 'ab']
1047
+ end
1048
+ it 'accepts unknown keys' do
1049
+ its.values_at('baz', 'foo').should == [nil, 'ab']
1050
+ end
1051
+ end
1052
+
1053
+ describe '[]' do
1054
+ context 'string key' do
1055
+ it 'returns the corresponding capture' do
1056
+ its['foo'].should == 'ab'
1057
+ its['bar'].should == 'cd'
1058
+ end
1059
+ it 'returns nil for unknown keys' do
1060
+ its['baz'].should be_nil
1061
+ end
1062
+ end
1063
+ context 'symbol key' do
1064
+ it 'returns the corresponding capture' do
1065
+ its[:foo].should == 'ab'
1066
+ its[:bar].should == 'cd'
1067
+ end
1068
+ it 'returns nil for unknown keys' do
1069
+ its[:baz].should be_nil
1070
+ end
1071
+ end
1072
+ context 'integer key' do
1073
+ it 'returns the full URI for index 0' do
1074
+ its[0].should == 'ab/cd'
1075
+ end
1076
+ it 'returns the corresponding capture' do
1077
+ its[1].should == 'ab'
1078
+ its[2].should == 'cd'
1079
+ end
1080
+ it 'returns nil for unknown keys' do
1081
+ its[3].should be_nil
1082
+ end
1083
+ end
1084
+ context 'other key' do
1085
+ it 'raises an exception' do
1086
+ expect { its[Object.new] }.to raise_error(TypeError)
1087
+ end
1088
+ end
1089
+ context 'with length' do
1090
+ it 'returns an array starting at index with given length' do
1091
+ its[0, 2].should == ['ab/cd', 'ab']
1092
+ its[2, 1].should == ['cd']
1093
+ end
1094
+ end
1095
+ end
1096
+ end
@@ -218,6 +218,373 @@ describe Addressable::URI, "when created from nil components" do
218
218
  end
219
219
  end
220
220
 
221
+ describe Addressable::URI, "when initialized from individual components" do
222
+ before do
223
+ @uri = Addressable::URI.new(
224
+ :scheme => "http",
225
+ :user => "user",
226
+ :password => "password",
227
+ :host => "example.com",
228
+ :port => 8080,
229
+ :path => "/path",
230
+ :query => "query=value",
231
+ :fragment => "fragment"
232
+ )
233
+ end
234
+
235
+ it "returns 'http' for #scheme" do
236
+ @uri.scheme.should == "http"
237
+ end
238
+
239
+ it "returns 'http' for #normalized_scheme" do
240
+ @uri.normalized_scheme.should == "http"
241
+ end
242
+
243
+ it "returns 'user' for #user" do
244
+ @uri.user.should == "user"
245
+ end
246
+
247
+ it "returns 'user' for #normalized_user" do
248
+ @uri.normalized_user.should == "user"
249
+ end
250
+
251
+ it "returns 'password' for #password" do
252
+ @uri.password.should == "password"
253
+ end
254
+
255
+ it "returns 'password' for #normalized_password" do
256
+ @uri.normalized_password.should == "password"
257
+ end
258
+
259
+ it "returns 'user:password' for #userinfo" do
260
+ @uri.userinfo.should == "user:password"
261
+ end
262
+
263
+ it "returns 'user:password' for #normalized_userinfo" do
264
+ @uri.normalized_userinfo.should == "user:password"
265
+ end
266
+
267
+ it "returns 'example.com' for #host" do
268
+ @uri.host.should == "example.com"
269
+ end
270
+
271
+ it "returns 'example.com' for #normalized_host" do
272
+ @uri.normalized_host.should == "example.com"
273
+ end
274
+
275
+ it "returns 'user:password@example.com:8080' for #authority" do
276
+ @uri.authority.should == "user:password@example.com:8080"
277
+ end
278
+
279
+ it "returns 'user:password@example.com:8080' for #normalized_authority" do
280
+ @uri.normalized_authority.should == "user:password@example.com:8080"
281
+ end
282
+
283
+ it "returns 8080 for #port" do
284
+ @uri.port.should == 8080
285
+ end
286
+
287
+ it "returns 8080 for #normalized_port" do
288
+ @uri.normalized_port.should == 8080
289
+ end
290
+
291
+ it "returns 80 for #default_port" do
292
+ @uri.default_port.should == 80
293
+ end
294
+
295
+ it "returns 'http://user:password@example.com:8080' for #site" do
296
+ @uri.site.should == "http://user:password@example.com:8080"
297
+ end
298
+
299
+ it "returns 'http://user:password@example.com:8080' for #normalized_site" do
300
+ @uri.normalized_site.should == "http://user:password@example.com:8080"
301
+ end
302
+
303
+ it "returns '/path' for #path" do
304
+ @uri.path.should == "/path"
305
+ end
306
+
307
+ it "returns '/path' for #normalized_path" do
308
+ @uri.normalized_path.should == "/path"
309
+ end
310
+
311
+ it "returns 'query=value' for #query" do
312
+ @uri.query.should == "query=value"
313
+ end
314
+
315
+ it "returns 'query=value' for #normalized_query" do
316
+ @uri.normalized_query.should == "query=value"
317
+ end
318
+
319
+ it "returns 'fragment' for #fragment" do
320
+ @uri.fragment.should == "fragment"
321
+ end
322
+
323
+ it "returns 'fragment' for #normalized_fragment" do
324
+ @uri.normalized_fragment.should == "fragment"
325
+ end
326
+
327
+ it "returns #hash" do
328
+ @uri.hash.should_not be nil
329
+ end
330
+
331
+ it "returns #to_s" do
332
+ @uri.to_s.should ==
333
+ "http://user:password@example.com:8080/path?query=value#fragment"
334
+ end
335
+
336
+ it "should not be frozen" do
337
+ @uri.should_not be_frozen
338
+ end
339
+
340
+
341
+ it "should allow destructive operations" do
342
+ expect { @uri.normalize! }.not_to raise_error
343
+ end
344
+ end
345
+
346
+ describe Addressable::URI, "when initialized from " +
347
+ "frozen individual components" do
348
+ before do
349
+ @uri = Addressable::URI.new(
350
+ :scheme => "http".freeze,
351
+ :user => "user".freeze,
352
+ :password => "password".freeze,
353
+ :host => "example.com".freeze,
354
+ :port => "8080".freeze,
355
+ :path => "/path".freeze,
356
+ :query => "query=value".freeze,
357
+ :fragment => "fragment".freeze
358
+ )
359
+ end
360
+
361
+ it "returns 'http' for #scheme" do
362
+ @uri.scheme.should == "http"
363
+ end
364
+
365
+ it "returns 'http' for #normalized_scheme" do
366
+ @uri.normalized_scheme.should == "http"
367
+ end
368
+
369
+ it "returns 'user' for #user" do
370
+ @uri.user.should == "user"
371
+ end
372
+
373
+ it "returns 'user' for #normalized_user" do
374
+ @uri.normalized_user.should == "user"
375
+ end
376
+
377
+ it "returns 'password' for #password" do
378
+ @uri.password.should == "password"
379
+ end
380
+
381
+ it "returns 'password' for #normalized_password" do
382
+ @uri.normalized_password.should == "password"
383
+ end
384
+
385
+ it "returns 'user:password' for #userinfo" do
386
+ @uri.userinfo.should == "user:password"
387
+ end
388
+
389
+ it "returns 'user:password' for #normalized_userinfo" do
390
+ @uri.normalized_userinfo.should == "user:password"
391
+ end
392
+
393
+ it "returns 'example.com' for #host" do
394
+ @uri.host.should == "example.com"
395
+ end
396
+
397
+ it "returns 'example.com' for #normalized_host" do
398
+ @uri.normalized_host.should == "example.com"
399
+ end
400
+
401
+ it "returns 'user:password@example.com:8080' for #authority" do
402
+ @uri.authority.should == "user:password@example.com:8080"
403
+ end
404
+
405
+ it "returns 'user:password@example.com:8080' for #normalized_authority" do
406
+ @uri.normalized_authority.should == "user:password@example.com:8080"
407
+ end
408
+
409
+ it "returns 8080 for #port" do
410
+ @uri.port.should == 8080
411
+ end
412
+
413
+ it "returns 8080 for #normalized_port" do
414
+ @uri.normalized_port.should == 8080
415
+ end
416
+
417
+ it "returns 80 for #default_port" do
418
+ @uri.default_port.should == 80
419
+ end
420
+
421
+ it "returns 'http://user:password@example.com:8080' for #site" do
422
+ @uri.site.should == "http://user:password@example.com:8080"
423
+ end
424
+
425
+ it "returns 'http://user:password@example.com:8080' for #normalized_site" do
426
+ @uri.normalized_site.should == "http://user:password@example.com:8080"
427
+ end
428
+
429
+ it "returns '/path' for #path" do
430
+ @uri.path.should == "/path"
431
+ end
432
+
433
+ it "returns '/path' for #normalized_path" do
434
+ @uri.normalized_path.should == "/path"
435
+ end
436
+
437
+ it "returns 'query=value' for #query" do
438
+ @uri.query.should == "query=value"
439
+ end
440
+
441
+ it "returns 'query=value' for #normalized_query" do
442
+ @uri.normalized_query.should == "query=value"
443
+ end
444
+
445
+ it "returns 'fragment' for #fragment" do
446
+ @uri.fragment.should == "fragment"
447
+ end
448
+
449
+ it "returns 'fragment' for #normalized_fragment" do
450
+ @uri.normalized_fragment.should == "fragment"
451
+ end
452
+
453
+ it "returns #hash" do
454
+ @uri.hash.should_not be nil
455
+ end
456
+
457
+ it "returns #to_s" do
458
+ @uri.to_s.should ==
459
+ "http://user:password@example.com:8080/path?query=value#fragment"
460
+ end
461
+
462
+ it "should not be frozen" do
463
+ @uri.should_not be_frozen
464
+ end
465
+
466
+ it "should allow destructive operations" do
467
+ expect { @uri.normalize! }.not_to raise_error
468
+ end
469
+ end
470
+
471
+ describe Addressable::URI, "when parsed from a frozen string" do
472
+ before do
473
+ @uri = Addressable::URI.parse(
474
+ "http://user:password@example.com:8080/path?query=value#fragment".freeze
475
+ )
476
+ end
477
+
478
+ it "returns 'http' for #scheme" do
479
+ @uri.scheme.should == "http"
480
+ end
481
+
482
+ it "returns 'http' for #normalized_scheme" do
483
+ @uri.normalized_scheme.should == "http"
484
+ end
485
+
486
+ it "returns 'user' for #user" do
487
+ @uri.user.should == "user"
488
+ end
489
+
490
+ it "returns 'user' for #normalized_user" do
491
+ @uri.normalized_user.should == "user"
492
+ end
493
+
494
+ it "returns 'password' for #password" do
495
+ @uri.password.should == "password"
496
+ end
497
+
498
+ it "returns 'password' for #normalized_password" do
499
+ @uri.normalized_password.should == "password"
500
+ end
501
+
502
+ it "returns 'user:password' for #userinfo" do
503
+ @uri.userinfo.should == "user:password"
504
+ end
505
+
506
+ it "returns 'user:password' for #normalized_userinfo" do
507
+ @uri.normalized_userinfo.should == "user:password"
508
+ end
509
+
510
+ it "returns 'example.com' for #host" do
511
+ @uri.host.should == "example.com"
512
+ end
513
+
514
+ it "returns 'example.com' for #normalized_host" do
515
+ @uri.normalized_host.should == "example.com"
516
+ end
517
+
518
+ it "returns 'user:password@example.com:8080' for #authority" do
519
+ @uri.authority.should == "user:password@example.com:8080"
520
+ end
521
+
522
+ it "returns 'user:password@example.com:8080' for #normalized_authority" do
523
+ @uri.normalized_authority.should == "user:password@example.com:8080"
524
+ end
525
+
526
+ it "returns 8080 for #port" do
527
+ @uri.port.should == 8080
528
+ end
529
+
530
+ it "returns 8080 for #normalized_port" do
531
+ @uri.normalized_port.should == 8080
532
+ end
533
+
534
+ it "returns 80 for #default_port" do
535
+ @uri.default_port.should == 80
536
+ end
537
+
538
+ it "returns 'http://user:password@example.com:8080' for #site" do
539
+ @uri.site.should == "http://user:password@example.com:8080"
540
+ end
541
+
542
+ it "returns 'http://user:password@example.com:8080' for #normalized_site" do
543
+ @uri.normalized_site.should == "http://user:password@example.com:8080"
544
+ end
545
+
546
+ it "returns '/path' for #path" do
547
+ @uri.path.should == "/path"
548
+ end
549
+
550
+ it "returns '/path' for #normalized_path" do
551
+ @uri.normalized_path.should == "/path"
552
+ end
553
+
554
+ it "returns 'query=value' for #query" do
555
+ @uri.query.should == "query=value"
556
+ end
557
+
558
+ it "returns 'query=value' for #normalized_query" do
559
+ @uri.normalized_query.should == "query=value"
560
+ end
561
+
562
+ it "returns 'fragment' for #fragment" do
563
+ @uri.fragment.should == "fragment"
564
+ end
565
+
566
+ it "returns 'fragment' for #normalized_fragment" do
567
+ @uri.normalized_fragment.should == "fragment"
568
+ end
569
+
570
+ it "returns #hash" do
571
+ @uri.hash.should_not be nil
572
+ end
573
+
574
+ it "returns #to_s" do
575
+ @uri.to_s.should ==
576
+ "http://user:password@example.com:8080/path?query=value#fragment"
577
+ end
578
+
579
+ it "should not be frozen" do
580
+ @uri.should_not be_frozen
581
+ end
582
+
583
+ it "should allow destructive operations" do
584
+ expect { @uri.normalize! }.not_to raise_error
585
+ end
586
+ end
587
+
221
588
  describe Addressable::URI, "when frozen" do
222
589
  before do
223
590
  @uri = Addressable::URI.new.freeze
@@ -232,7 +599,7 @@ describe Addressable::URI, "when frozen" do
232
599
  end
233
600
 
234
601
  it "returns nil for #user" do
235
- @uri.user .should == nil
602
+ @uri.user.should == nil
236
603
  end
237
604
 
238
605
  it "returns nil for #normalized_user" do
@@ -322,6 +689,153 @@ describe Addressable::URI, "when frozen" do
322
689
  it "returns #to_s" do
323
690
  @uri.to_s.should == ''
324
691
  end
692
+
693
+ it "should be frozen" do
694
+ @uri.should be_frozen
695
+ end
696
+
697
+ it "should not be frozen after duping" do
698
+ @uri.dup.should_not be_frozen
699
+ end
700
+
701
+ it "should not allow destructive operations" do
702
+ expect { @uri.normalize! }.to raise_error { |error|
703
+ error.message.should match(/can't modify frozen/)
704
+ error.should satisfy { |e| RuntimeError === e || TypeError === e }
705
+ }
706
+ end
707
+ end
708
+
709
+ describe Addressable::URI, "when frozen" do
710
+ before do
711
+ @uri = Addressable::URI.parse(
712
+ "HTTP://example.com.:%38%30/%70a%74%68?a=%31#1%323"
713
+ ).freeze
714
+ end
715
+
716
+ it "returns 'HTTP' for #scheme" do
717
+ @uri.scheme.should == "HTTP"
718
+ end
719
+
720
+ it "returns 'http' for #normalized_scheme" do
721
+ @uri.normalized_scheme.should == "http"
722
+ @uri.normalize.scheme.should == "http"
723
+ end
724
+
725
+ it "returns nil for #user" do
726
+ @uri.user.should == nil
727
+ end
728
+
729
+ it "returns nil for #normalized_user" do
730
+ @uri.normalized_user.should == nil
731
+ end
732
+
733
+ it "returns nil for #password" do
734
+ @uri.password.should == nil
735
+ end
736
+
737
+ it "returns nil for #normalized_password" do
738
+ @uri.normalized_password.should == nil
739
+ end
740
+
741
+ it "returns nil for #userinfo" do
742
+ @uri.userinfo.should == nil
743
+ end
744
+
745
+ it "returns nil for #normalized_userinfo" do
746
+ @uri.normalized_userinfo.should == nil
747
+ end
748
+
749
+ it "returns 'example.com.' for #host" do
750
+ @uri.host.should == "example.com."
751
+ end
752
+
753
+ it "returns nil for #normalized_host" do
754
+ @uri.normalized_host.should == "example.com"
755
+ @uri.normalize.host.should == "example.com"
756
+ end
757
+
758
+ it "returns 'example.com.:80' for #authority" do
759
+ @uri.authority.should == "example.com.:80"
760
+ end
761
+
762
+ it "returns 'example.com:80' for #normalized_authority" do
763
+ @uri.normalized_authority.should == "example.com"
764
+ @uri.normalize.authority.should == "example.com"
765
+ end
766
+
767
+ it "returns 80 for #port" do
768
+ @uri.port.should == 80
769
+ end
770
+
771
+ it "returns nil for #normalized_port" do
772
+ @uri.normalized_port.should == nil
773
+ @uri.normalize.port.should == nil
774
+ end
775
+
776
+ it "returns 80 for #default_port" do
777
+ @uri.default_port.should == 80
778
+ end
779
+
780
+ it "returns 'HTTP://example.com.:80' for #site" do
781
+ @uri.site.should == "HTTP://example.com.:80"
782
+ end
783
+
784
+ it "returns 'http://example.com' for #normalized_site" do
785
+ @uri.normalized_site.should == "http://example.com"
786
+ @uri.normalize.site.should == "http://example.com"
787
+ end
788
+
789
+ it "returns '/%70a%74%68' for #path" do
790
+ @uri.path.should == "/%70a%74%68"
791
+ end
792
+
793
+ it "returns '/path' for #normalized_path" do
794
+ @uri.normalized_path.should == "/path"
795
+ @uri.normalize.path.should == "/path"
796
+ end
797
+
798
+ it "returns 'a=%31' for #query" do
799
+ @uri.query.should == "a=%31"
800
+ end
801
+
802
+ it "returns 'a=1' for #normalized_query" do
803
+ @uri.normalized_query.should == "a=1"
804
+ @uri.normalize.query.should == "a=1"
805
+ end
806
+
807
+ it "returns '1%323' for #fragment" do
808
+ @uri.fragment.should == "1%323"
809
+ end
810
+
811
+ it "returns '123' for #normalized_fragment" do
812
+ @uri.normalized_fragment.should == "123"
813
+ @uri.normalize.fragment.should == "123"
814
+ end
815
+
816
+ it "returns #hash" do
817
+ @uri.hash.should_not be nil
818
+ end
819
+
820
+ it "returns #to_s" do
821
+ @uri.to_s.should == 'HTTP://example.com.:80/%70a%74%68?a=%31#1%323'
822
+ @uri.normalize.to_s.should == 'http://example.com/path?a=1#123'
823
+ end
824
+
825
+ it "should be frozen" do
826
+ @uri.should be_frozen
827
+ end
828
+
829
+ it "should not be frozen after duping" do
830
+ @uri.dup.should_not be_frozen
831
+ end
832
+
833
+ it "should not allow destructive operations" do
834
+ expect { @uri.normalize! }.to raise_error { |error|
835
+ error.message.should match(/can't modify frozen/)
836
+ error.should satisfy { |e| RuntimeError === e || TypeError === e }
837
+ }
838
+ end
325
839
  end
326
840
 
327
841
  describe Addressable::URI, "when created from string components" do
@@ -3102,6 +3616,27 @@ describe Addressable::URI, "when parsed from " +
3102
3616
  end
3103
3617
  end
3104
3618
 
3619
+ describe Addressable::URI, "when parsed from " +
3620
+ "'http://example.com/?q='one;two'&x=1'" do
3621
+ before do
3622
+ @uri = Addressable::URI.parse("http://example.com/?q='one;two'&x=1")
3623
+ end
3624
+
3625
+ it "should have a query of 'q='one;two'&x=1'" do
3626
+ @uri.query.should == "q='one;two'&x=1"
3627
+ end
3628
+
3629
+ it "should have query_values of {\"q\" => \"'one;two'\", \"x\" => \"1\"}" do
3630
+ @uri.query_values.should == {"q" => "'one;two'", "x" => "1"}
3631
+ end
3632
+
3633
+ it "should escape the ';' character when normalizing to avoid ambiguity " +
3634
+ "with the W3C HTML 4.01 specification" do
3635
+ # HTML 4.01 Section B.2.2
3636
+ @uri.normalize.query.should == "q='one%3Btwo'&x=1"
3637
+ end
3638
+ end
3639
+
3105
3640
  describe Addressable::URI, "when parsed from " +
3106
3641
  "'http://example.com/?&&x=b'" do
3107
3642
  before do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: addressable
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.3
4
+ version: 2.3.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-02-19 00:00:00.000000000 Z
12
+ date: 2013-04-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake