addressable 2.1.1 → 2.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CHANGELOG CHANGED
@@ -1,6 +1,18 @@
1
+ === Addressable 2.1.2
2
+ * added HTTP request URI methods
3
+ * better handling of Windows file paths
4
+ * validation_deferred boolean replaced with defer_validation block
5
+ * normalization of percent-encoded paths should now be correct
6
+ * fixed issue with constructing URIs with relative paths
7
+ * fixed warnings
8
+
1
9
  === Addressable 2.1.1
2
- * fixed some missing type checking
10
+ * more type checking changes
3
11
  * fixed issue with unicode normalization
12
+ * added method to find template defaults
13
+ * symbolic keys are now allowed in template mappings
14
+ * numeric values and symbolic values are now allowed in template mappings
15
+
4
16
  === Addressable 2.1.0
5
17
  * refactored URI template support out into its own class
6
18
  * removed extract method due to being useless and unreliable
@@ -495,13 +495,13 @@ module Addressable
495
495
  #
496
496
  # @return [Hash] Mapping of template variables to their defaults
497
497
  def variable_defaults
498
- @variable_defaults ||= Hash[*ordered_variable_defaults.reject { |k,v| v.nil? }.flatten]
498
+ @variable_defaults ||=
499
+ Hash[*ordered_variable_defaults.reject { |k, v| v.nil? }.flatten]
499
500
  end
500
501
 
501
502
  private
502
-
503
503
  def ordered_variable_defaults
504
- @ordered_variable_defaults ||= begin
504
+ @ordered_variable_defaults ||= (begin
505
505
  expansions, expansion_regexp = parse_template_pattern(pattern)
506
506
 
507
507
  expansions.inject([]) do |result, expansion|
@@ -514,7 +514,7 @@ module Addressable
514
514
  end
515
515
  result
516
516
  end
517
- end
517
+ end)
518
518
  end
519
519
 
520
520
  ##
@@ -800,9 +800,9 @@ module Addressable
800
800
  # @return [Array]
801
801
  # A tuple of the operator, argument, variables, and mapping.
802
802
  def parse_template_expansion(capture, mapping={})
803
- operator, argument, variables = capture[1...-1].split("|")
803
+ operator, argument, variables = capture[1...-1].split("|", -1)
804
804
  operator.gsub!(/^\-/, "")
805
- variables = variables.split(",")
805
+ variables = variables.split(",", -1)
806
806
  mapping = (variables.inject({}) do |accu, var|
807
807
  varname, _, vardefault = var.scan(/^(.+?)(=(.*))?$/)[0]
808
808
  accu[varname] = vardefault
@@ -36,11 +36,6 @@ module Addressable
36
36
  class InvalidURIError < StandardError
37
37
  end
38
38
 
39
- ##
40
- # Raised if an invalid method option is supplied.
41
- class InvalidOptionError < StandardError
42
- end
43
-
44
39
  ##
45
40
  # Container for the character classes specified in
46
41
  # <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>.
@@ -172,11 +167,13 @@ module Addressable
172
167
  if parsed.path.include?(".")
173
168
  new_host = parsed.path[/^([^\/]+\.[^\/]*)/, 1]
174
169
  if new_host
175
- new_path = parsed.path.gsub(
176
- Regexp.new("^" + Regexp.escape(new_host)), "")
177
- parsed.host = new_host
178
- parsed.path = new_path
179
- parsed.scheme = hints[:scheme] unless parsed.scheme
170
+ parsed.defer_validation do
171
+ new_path = parsed.path.gsub(
172
+ Regexp.new("^" + Regexp.escape(new_host)), "")
173
+ parsed.host = new_host
174
+ parsed.path = new_path
175
+ parsed.scheme = hints[:scheme] unless parsed.scheme
176
+ end
180
177
  end
181
178
  end
182
179
  return parsed
@@ -223,12 +220,14 @@ module Addressable
223
220
  path = path.to_str.strip
224
221
 
225
222
  path.gsub!(/^file:\/?\/?/, "") if path =~ /^file:\/?\/?/
226
- path = "/" + path if path =~ /^([a-zA-Z])(\||:)/
223
+ path = "/" + path if path =~ /^([a-zA-Z])[\|:]/
227
224
  uri = self.parse(path)
228
225
 
229
226
  if uri.scheme == nil
230
227
  # Adjust windows-style uris
231
- uri.path.gsub!(/^\/?([a-zA-Z])\|(\\|\/)/, "/\\1:/")
228
+ uri.path.gsub!(/^\/?([a-zA-Z])[\|:][\\\/]/) do
229
+ "/#{$1.downcase}:/"
230
+ end
232
231
  uri.path.gsub!(/\\/, "/")
233
232
  if File.exists?(uri.path) &&
234
233
  File.stat(uri.path).directory?
@@ -377,6 +376,71 @@ module Addressable
377
376
  alias_method :unescape_component, :unencode
378
377
  end
379
378
 
379
+
380
+ ##
381
+ # Normalizes the encoding of a URI component.
382
+ #
383
+ # @param [String, #to_str] component The URI component to encode.
384
+ #
385
+ # @param [String, Regexp] character_class
386
+ #
387
+ # The characters which are not percent encoded. If a <tt>String</tt> is
388
+ # passed, the <tt>String</tt> must be formatted as a regular expression
389
+ # character class. (Do not include the surrounding square brackets.) For
390
+ # example, <tt>"b-zB-Z0-9"</tt> would cause everything but the letters 'b'
391
+ # through 'z' and the numbers '0' through '9' to be percent encoded. If a
392
+ # <tt>Regexp</tt> is passed, the value <tt>/[^b-zB-Z0-9]/</tt> would have
393
+ # the same effect. A set of useful <tt>String</tt> values may be found in
394
+ # the <tt>Addressable::URI::CharacterClasses</tt> module. The default
395
+ # value is the reserved plus unreserved character classes specified in <a
396
+ # href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>.
397
+ #
398
+ # @return [String] The normalized component.
399
+ #
400
+ # @example
401
+ # Addressable::URI.normalize_component("simpl%65/%65xampl%65", "b-zB-Z")
402
+ # => "simple%2Fex%61mple"
403
+ # Addressable::URI.normalize_component(
404
+ # "simpl%65/%65xampl%65", /[^b-zB-Z]/
405
+ # )
406
+ # => "simple%2Fex%61mple"
407
+ # Addressable::URI.normalize_component(
408
+ # "simpl%65/%65xampl%65",
409
+ # Addressable::URI::CharacterClasses::UNRESERVED
410
+ # )
411
+ # => "simple%2Fexample"
412
+ def self.normalize_component(component, character_class=
413
+ CharacterClasses::RESERVED + CharacterClasses::UNRESERVED)
414
+ return nil if component.nil?
415
+ if !component.respond_to?(:to_str)
416
+ raise TypeError, "Can't convert #{component.class} into String."
417
+ end
418
+ component = component.to_str
419
+ if ![String, Regexp].include?(character_class.class)
420
+ raise TypeError,
421
+ "Expected String or Regexp, got #{character_class.inspect}"
422
+ end
423
+ if character_class.kind_of?(String)
424
+ character_class = /[^#{character_class}]/
425
+ end
426
+ if component.respond_to?(:force_encoding)
427
+ # We can't perform regexps on invalid UTF sequences, but
428
+ # here we need to, so switch to ASCII.
429
+ component = component.dup
430
+ component.force_encoding(Encoding::ASCII_8BIT)
431
+ end
432
+ unencoded = self.unencode_component(component)
433
+ begin
434
+ encoded = self.encode_component(
435
+ Addressable::IDNA.unicode_normalize_kc(unencoded),
436
+ character_class
437
+ )
438
+ rescue ArgumentError
439
+ encoded = self.encode_component(unencoded)
440
+ end
441
+ return encoded
442
+ end
443
+
380
444
  ##
381
445
  # Percent encodes any special characters in the URI.
382
446
  #
@@ -530,18 +594,20 @@ module Addressable
530
594
  end
531
595
  end
532
596
 
533
- self.validation_deferred = true
534
- self.scheme = options[:scheme] if options[:scheme]
535
- self.user = options[:user] if options[:user]
536
- self.password = options[:password] if options[:password]
537
- self.userinfo = options[:userinfo] if options[:userinfo]
538
- self.host = options[:host] if options[:host]
539
- self.port = options[:port] if options[:port]
540
- self.authority = options[:authority] if options[:authority]
541
- self.path = options[:path] if options[:path]
542
- self.query = options[:query] if options[:query]
543
- self.fragment = options[:fragment] if options[:fragment]
544
- self.validation_deferred = false
597
+ self.defer_validation do
598
+ # Bunch of crazy logic required because of the composite components
599
+ # like userinfo and authority.
600
+ self.scheme = options[:scheme] if options[:scheme]
601
+ self.user = options[:user] if options[:user]
602
+ self.password = options[:password] if options[:password]
603
+ self.userinfo = options[:userinfo] if options[:userinfo]
604
+ self.host = options[:host] if options[:host]
605
+ self.port = options[:port] if options[:port]
606
+ self.authority = options[:authority] if options[:authority]
607
+ self.path = options[:path] if options[:path]
608
+ self.query = options[:query] if options[:query]
609
+ self.fragment = options[:fragment] if options[:fragment]
610
+ end
545
611
  end
546
612
 
547
613
  ##
@@ -549,7 +615,7 @@ module Addressable
549
615
  #
550
616
  # @return [String] The scheme component.
551
617
  def scheme
552
- return @scheme
618
+ return @scheme ||= nil
553
619
  end
554
620
 
555
621
  ##
@@ -562,10 +628,8 @@ module Addressable
562
628
  if self.scheme =~ /^\s*ssh\+svn\s*$/i
563
629
  "svn+ssh"
564
630
  else
565
- Addressable::URI.encode_component(
566
- Addressable::IDNA.unicode_normalize_kc(
567
- Addressable::URI.unencode_component(
568
- self.scheme.strip.downcase)),
631
+ Addressable::URI.normalize_component(
632
+ self.scheme.strip.downcase,
569
633
  Addressable::URI::CharacterClasses::SCHEME
570
634
  )
571
635
  end
@@ -602,7 +666,7 @@ module Addressable
602
666
  #
603
667
  # @return [String] The user component.
604
668
  def user
605
- return @user
669
+ return @user ||= nil
606
670
  end
607
671
 
608
672
  ##
@@ -616,9 +680,8 @@ module Addressable
616
680
  (!self.password || self.password.strip == "")
617
681
  nil
618
682
  else
619
- Addressable::URI.encode_component(
620
- Addressable::IDNA.unicode_normalize_kc(
621
- Addressable::URI.unencode_component(self.user.strip)),
683
+ Addressable::URI.normalize_component(
684
+ self.user.strip,
622
685
  Addressable::URI::CharacterClasses::UNRESERVED
623
686
  )
624
687
  end
@@ -663,7 +726,7 @@ module Addressable
663
726
  #
664
727
  # @return [String] The password component.
665
728
  def password
666
- return @password
729
+ return @password ||= nil
667
730
  end
668
731
 
669
732
  ##
@@ -677,9 +740,8 @@ module Addressable
677
740
  (!self.user || self.user.strip == "")
678
741
  nil
679
742
  else
680
- Addressable::URI.encode_component(
681
- Addressable::IDNA.unicode_normalize_kc(
682
- Addressable::URI.unencode_component(self.password.strip)),
743
+ Addressable::URI.normalize_component(
744
+ self.password.strip,
683
745
  Addressable::URI::CharacterClasses::UNRESERVED
684
746
  )
685
747
  end
@@ -794,7 +856,7 @@ module Addressable
794
856
  #
795
857
  # @return [String] The host component.
796
858
  def host
797
- return @host
859
+ return @host ||= nil
798
860
  end
799
861
 
800
862
  ##
@@ -1035,7 +1097,8 @@ module Addressable
1035
1097
  #
1036
1098
  # @return [String] The path component.
1037
1099
  def path
1038
- return (@path || "")
1100
+ @path ||= ""
1101
+ return @path
1039
1102
  end
1040
1103
 
1041
1104
  ##
@@ -1044,19 +1107,19 @@ module Addressable
1044
1107
  # @return [String] The path component, normalized.
1045
1108
  def normalized_path
1046
1109
  @normalized_path ||= (begin
1047
- begin
1048
- result = Addressable::URI.encode_component(
1049
- Addressable::IDNA.unicode_normalize_kc(
1050
- Addressable::URI.unencode_component(self.path.strip)),
1051
- Addressable::URI::CharacterClasses::PATH
1052
- )
1053
- rescue ArgumentError
1054
- # Likely a malformed UTF-8 character, skip unicode normalization
1055
- result = Addressable::URI.encode_component(
1056
- Addressable::URI.unencode_component(self.path.strip),
1057
- Addressable::URI::CharacterClasses::PATH
1058
- )
1110
+ if self.scheme == nil && self.path != nil && self.path != "" &&
1111
+ self.path =~ /^(?!\/)[^\/:]*:.*$/
1112
+ # Relative paths with colons in the first segment are ambiguous.
1113
+ self.path.sub!(":", "%2F")
1059
1114
  end
1115
+ # String#split(delimeter, -1) uses the more strict splitting behavior
1116
+ # found by default in Python.
1117
+ result = (self.path.strip.split("/", -1).map do |segment|
1118
+ Addressable::URI.normalize_component(
1119
+ segment,
1120
+ Addressable::URI::CharacterClasses::PCHAR
1121
+ )
1122
+ end).join("/")
1060
1123
  result = self.class.normalize_path(result)
1061
1124
  if result == "" &&
1062
1125
  ["http", "https", "ftp", "tftp"].include?(self.normalized_scheme)
@@ -1111,7 +1174,7 @@ module Addressable
1111
1174
  #
1112
1175
  # @return [String] The query component.
1113
1176
  def query
1114
- return @query
1177
+ return @query ||= nil
1115
1178
  end
1116
1179
 
1117
1180
  ##
@@ -1121,19 +1184,10 @@ module Addressable
1121
1184
  def normalized_query
1122
1185
  @normalized_query ||= (begin
1123
1186
  if self.query
1124
- begin
1125
- Addressable::URI.encode_component(
1126
- Addressable::IDNA.unicode_normalize_kc(
1127
- Addressable::URI.unencode_component(self.query.strip)),
1128
- Addressable::URI::CharacterClasses::QUERY
1129
- )
1130
- rescue ArgumentError
1131
- # Likely a malformed UTF-8 character, skip unicode normalization
1132
- Addressable::URI.encode_component(
1133
- Addressable::URI.unencode_component(self.query.strip),
1134
- Addressable::URI::CharacterClasses::QUERY
1135
- )
1136
- end
1187
+ Addressable::URI.normalize_component(
1188
+ self.query.strip,
1189
+ Addressable::URI::CharacterClasses::QUERY
1190
+ )
1137
1191
  else
1138
1192
  nil
1139
1193
  end
@@ -1304,12 +1358,49 @@ module Addressable
1304
1358
  @uri_string = nil
1305
1359
  end
1306
1360
 
1361
+ ##
1362
+ # The HTTP request URI for this URI. This is the path and the
1363
+ # query string.
1364
+ #
1365
+ # @return [String] The request URI required for an HTTP request.
1366
+ def request_uri
1367
+ return nil if self.absolute? && self.scheme !~ /^https?$/
1368
+ return (
1369
+ (self.path != "" ? self.path : "/") +
1370
+ (self.query ? "?#{self.query}" : "")
1371
+ )
1372
+ end
1373
+
1374
+ ##
1375
+ # Sets the HTTP request URI for this URI.
1376
+ #
1377
+ # @param [String, #to_str] new_request_uri The new HTTP request URI.
1378
+ def request_uri=(new_request_uri)
1379
+ if !new_request_uri.respond_to?(:to_str)
1380
+ raise TypeError, "Can't convert #{new_request_uri.class} into String."
1381
+ end
1382
+ if self.absolute? && self.scheme !~ /^https?$/
1383
+ raise InvalidURIError,
1384
+ "Cannot set an HTTP request URI for a non-HTTP URI."
1385
+ end
1386
+ new_request_uri = new_request_uri.to_str
1387
+ path_component = new_request_uri[/^([^\?]*)\?(?:.*)$/, 1]
1388
+ query_component = new_request_uri[/^(?:[^\?]*)\?(.*)$/, 1]
1389
+ path_component = path_component.to_s
1390
+ path_component = (path_component != "" ? path_component : "/")
1391
+ self.path = path_component
1392
+ self.query = query_component
1393
+
1394
+ # Reset dependant values
1395
+ @uri_string = nil
1396
+ end
1397
+
1307
1398
  ##
1308
1399
  # The fragment component for this URI.
1309
1400
  #
1310
1401
  # @return [String] The fragment component.
1311
1402
  def fragment
1312
- return @fragment
1403
+ return @fragment ||= nil
1313
1404
  end
1314
1405
 
1315
1406
  ##
@@ -1319,19 +1410,10 @@ module Addressable
1319
1410
  def normalized_fragment
1320
1411
  @normalized_fragment ||= (begin
1321
1412
  if self.fragment
1322
- begin
1323
- Addressable::URI.encode_component(
1324
- Addressable::IDNA.unicode_normalize_kc(
1325
- Addressable::URI.unencode_component(self.fragment.strip)),
1326
- Addressable::URI::CharacterClasses::FRAGMENT
1327
- )
1328
- rescue ArgumentError
1329
- # Likely a malformed UTF-8 character, skip unicode normalization
1330
- Addressable::URI.encode_component(
1331
- Addressable::URI.unencode_component(self.fragment.strip),
1332
- Addressable::URI::CharacterClasses::FRAGMENT
1333
- )
1334
- end
1413
+ Addressable::URI.normalize_component(
1414
+ self.fragment.strip,
1415
+ Addressable::URI::CharacterClasses::FRAGMENT
1416
+ )
1335
1417
  else
1336
1418
  nil
1337
1419
  end
@@ -1536,36 +1618,38 @@ module Addressable
1536
1618
  end
1537
1619
 
1538
1620
  uri = Addressable::URI.new
1539
- uri.validation_deferred = true
1540
- uri.scheme =
1541
- hash.has_key?(:scheme) ? hash[:scheme] : self.scheme
1542
- if hash.has_key?(:authority)
1543
- uri.authority =
1544
- hash.has_key?(:authority) ? hash[:authority] : self.authority
1621
+ uri.defer_validation do
1622
+ # Bunch of crazy logic required because of the composite components
1623
+ # like userinfo and authority.
1624
+ uri.scheme =
1625
+ hash.has_key?(:scheme) ? hash[:scheme] : self.scheme
1626
+ if hash.has_key?(:authority)
1627
+ uri.authority =
1628
+ hash.has_key?(:authority) ? hash[:authority] : self.authority
1629
+ end
1630
+ if hash.has_key?(:userinfo)
1631
+ uri.userinfo =
1632
+ hash.has_key?(:userinfo) ? hash[:userinfo] : self.userinfo
1633
+ end
1634
+ if !hash.has_key?(:userinfo) && !hash.has_key?(:authority)
1635
+ uri.user =
1636
+ hash.has_key?(:user) ? hash[:user] : self.user
1637
+ uri.password =
1638
+ hash.has_key?(:password) ? hash[:password] : self.password
1639
+ end
1640
+ if !hash.has_key?(:authority)
1641
+ uri.host =
1642
+ hash.has_key?(:host) ? hash[:host] : self.host
1643
+ uri.port =
1644
+ hash.has_key?(:port) ? hash[:port] : self.port
1645
+ end
1646
+ uri.path =
1647
+ hash.has_key?(:path) ? hash[:path] : self.path
1648
+ uri.query =
1649
+ hash.has_key?(:query) ? hash[:query] : self.query
1650
+ uri.fragment =
1651
+ hash.has_key?(:fragment) ? hash[:fragment] : self.fragment
1545
1652
  end
1546
- if hash.has_key?(:userinfo)
1547
- uri.userinfo =
1548
- hash.has_key?(:userinfo) ? hash[:userinfo] : self.userinfo
1549
- end
1550
- if !hash.has_key?(:userinfo) && !hash.has_key?(:authority)
1551
- uri.user =
1552
- hash.has_key?(:user) ? hash[:user] : self.user
1553
- uri.password =
1554
- hash.has_key?(:password) ? hash[:password] : self.password
1555
- end
1556
- if !hash.has_key?(:authority)
1557
- uri.host =
1558
- hash.has_key?(:host) ? hash[:host] : self.host
1559
- uri.port =
1560
- hash.has_key?(:port) ? hash[:port] : self.port
1561
- end
1562
- uri.path =
1563
- hash.has_key?(:path) ? hash[:path] : self.path
1564
- uri.query =
1565
- hash.has_key?(:query) ? hash[:query] : self.query
1566
- uri.fragment =
1567
- hash.has_key?(:fragment) ? hash[:fragment] : self.fragment
1568
- uri.validation_deferred = false
1569
1653
 
1570
1654
  return uri
1571
1655
  end
@@ -1825,12 +1909,12 @@ module Addressable
1825
1909
  "Invalid component names: #{invalid_components.inspect}."
1826
1910
  end
1827
1911
  duplicated_uri = self.dup
1828
- duplicated_uri.validation_deferred = true
1829
- components.each do |component|
1830
- duplicated_uri.send((component.to_s + "=").to_sym, nil)
1912
+ duplicated_uri.defer_validation do
1913
+ components.each do |component|
1914
+ duplicated_uri.send((component.to_s + "=").to_sym, nil)
1915
+ end
1916
+ duplicated_uri.user = duplicated_uri.normalized_user
1831
1917
  end
1832
- duplicated_uri.user = duplicated_uri.normalized_user
1833
- duplicated_uri.validation_deferred = false
1834
1918
  duplicated_uri
1835
1919
  end
1836
1920
 
@@ -1895,27 +1979,20 @@ module Addressable
1895
1979
  end
1896
1980
 
1897
1981
  ##
1898
- # If URI validation needs to be disabled, this can be set to true.
1899
- #
1900
- # @return [TrueClass, FalseClass]
1901
- # <tt>true</tt> if validation has been deferred,
1902
- # <tt>false</tt> otherwise.
1903
- def validation_deferred
1904
- !!@validation_deferred
1905
- end
1906
-
1907
- ##
1908
- # If URI validation needs to be disabled, this can be set to true.
1982
+ # This method allows you to make several changes to a URI simultaneously,
1983
+ # which separately would cause validation errors, but in conjunction,
1984
+ # are valid. The URI will be revalidated as soon as the entire block has
1985
+ # been executed.
1909
1986
  #
1910
- # @param [TrueClass, FalseClass] new_validation_deferred
1911
- # <tt>true</tt> if validation will be deferred,
1912
- # <tt>false</tt> otherwise.
1913
- def validation_deferred=(new_validation_deferred)
1914
- # Check for frozenness
1915
- raise TypeError, "Can't modify frozen URI." if self.frozen?
1916
-
1917
- @validation_deferred = new_validation_deferred
1918
- validate unless @validation_deferred
1987
+ # @param [Proc] block
1988
+ # A set of operations to perform on a given URI.
1989
+ def defer_validation(&block)
1990
+ raise LocalJumpError, "No block given." unless block
1991
+ @validation_deferred = true
1992
+ block.call()
1993
+ @validation_deferred = false
1994
+ validate
1995
+ return nil
1919
1996
  end
1920
1997
 
1921
1998
  private
@@ -1952,7 +2029,7 @@ module Addressable
1952
2029
  ##
1953
2030
  # Ensures that the URI is valid.
1954
2031
  def validate
1955
- return if self.validation_deferred
2032
+ return if !!@validation_deferred
1956
2033
  if self.scheme != nil &&
1957
2034
  (self.host == nil || self.host == "") &&
1958
2035
  (self.path == nil || self.path == "")
@@ -1966,6 +2043,11 @@ module Addressable
1966
2043
  raise InvalidURIError, "Hostname not supplied: '#{self.to_s}'"
1967
2044
  end
1968
2045
  end
2046
+ if self.path != nil && self.path != "" && self.path[0..0] != "/" &&
2047
+ self.authority != nil
2048
+ raise InvalidURIError,
2049
+ "Cannot have a relative path with an authority set: '#{self.to_s}'"
2050
+ end
1969
2051
  return nil
1970
2052
  end
1971
2053
 
@@ -28,7 +28,7 @@ if !defined?(Addressable::VERSION)
28
28
  module VERSION #:nodoc:
29
29
  MAJOR = 2
30
30
  MINOR = 1
31
- TINY = 1
31
+ TINY = 2
32
32
 
33
33
  STRING = [MAJOR, MINOR, TINY].join('.')
34
34
  end
@@ -1475,6 +1475,15 @@ describe Addressable::Template, "with a partially expanded template" do
1475
1475
  @initial_template.expand({"one" => "1", "two" => "2"}).should ==
1476
1476
  @partial_template.expand({"two" => "2"})
1477
1477
  end
1478
+
1479
+ it "should raise an error if the template is expanded with bogus values" do
1480
+ (lambda do
1481
+ @initial_template.expand({"one" => Object.new, "two" => Object.new})
1482
+ end).should raise_error(TypeError)
1483
+ (lambda do
1484
+ @partial_template.expand({"two" => Object.new})
1485
+ end).should raise_error(TypeError)
1486
+ end
1478
1487
  end
1479
1488
 
1480
1489
  describe Addressable::Template, "with a partially expanded template" do
@@ -323,6 +323,10 @@ describe Addressable::URI, "when parsed from ''" do
323
323
  @uri.path.should == ""
324
324
  end
325
325
 
326
+ it "should have a request URI of '/'" do
327
+ @uri.request_uri.should == "/"
328
+ end
329
+
326
330
  it "should be considered relative" do
327
331
  @uri.should be_relative
328
332
  end
@@ -355,6 +359,10 @@ describe Addressable::URI, "when parsed from " +
355
359
  @uri.path.should == "/rfc/rfc1808.txt"
356
360
  end
357
361
 
362
+ it "should not have a request URI" do
363
+ @uri.request_uri.should == nil
364
+ end
365
+
358
366
  it "should be considered to be in normal form" do
359
367
  @uri.normalize.should be_eql(@uri)
360
368
  end
@@ -383,6 +391,10 @@ describe Addressable::URI, "when parsed from " +
383
391
  @uri.path.should == "/rfc/rfc2396.txt"
384
392
  end
385
393
 
394
+ it "should have a request URI of '/rfc/rfc2396.txt'" do
395
+ @uri.request_uri.should == "/rfc/rfc2396.txt"
396
+ end
397
+
386
398
  it "should be considered to be in normal form" do
387
399
  @uri.normalize.should be_eql(@uri)
388
400
  end
@@ -421,6 +433,16 @@ describe Addressable::URI, "when parsed from " +
421
433
  @uri.path.should == "/c=GB"
422
434
  end
423
435
 
436
+ it "should not have a request URI" do
437
+ @uri.request_uri.should == nil
438
+ end
439
+
440
+ it "should not allow request URI assignment" do
441
+ (lambda do
442
+ @uri.request_uri = "/"
443
+ end).should raise_error(Addressable::URI::InvalidURIError)
444
+ end
445
+
424
446
  it "should have a query of 'objectClass?one'" do
425
447
  @uri.query.should == "objectClass?one"
426
448
  end
@@ -465,6 +487,10 @@ describe Addressable::URI, "when parsed from " +
465
487
  @uri.path.should == "John.Doe@example.com"
466
488
  end
467
489
 
490
+ it "should not have a request URI" do
491
+ @uri.request_uri.should == nil
492
+ end
493
+
468
494
  it "should be considered to be in normal form" do
469
495
  @uri.normalize.should be_eql(@uri)
470
496
  end
@@ -489,6 +515,10 @@ describe Addressable::URI, "when parsed from " +
489
515
  @uri.path.should == "comp.infosystems.www.servers.unix"
490
516
  end
491
517
 
518
+ it "should not have a request URI" do
519
+ @uri.request_uri.should == nil
520
+ end
521
+
492
522
  it "should be considered to be in normal form" do
493
523
  @uri.normalize.should be_eql(@uri)
494
524
  end
@@ -513,6 +543,10 @@ describe Addressable::URI, "when parsed from " +
513
543
  @uri.path.should == "+1-816-555-1212"
514
544
  end
515
545
 
546
+ it "should not have a request URI" do
547
+ @uri.request_uri.should == nil
548
+ end
549
+
516
550
  it "should be considered to be in normal form" do
517
551
  @uri.normalize.should be_eql(@uri)
518
552
  end
@@ -545,6 +579,10 @@ describe Addressable::URI, "when parsed from " +
545
579
  @uri.path.should == "/"
546
580
  end
547
581
 
582
+ it "should not have a request URI" do
583
+ @uri.request_uri.should == nil
584
+ end
585
+
548
586
  it "should be considered to be in normal form" do
549
587
  @uri.normalize.should be_eql(@uri)
550
588
  end
@@ -571,6 +609,10 @@ describe Addressable::URI, "when parsed from " +
571
609
  @uri.path.should == "oasis:names:specification:docbook:dtd:xml:4.1.2"
572
610
  end
573
611
 
612
+ it "should not have a request URI" do
613
+ @uri.request_uri.should == nil
614
+ end
615
+
574
616
  it "should be considered to be in normal form" do
575
617
  @uri.normalize.should be_eql(@uri)
576
618
  end
@@ -639,6 +681,10 @@ describe Addressable::URI, "when parsed from " +
639
681
  @uri.query_values.should == nil
640
682
  end
641
683
 
684
+ it "should have a request URI of '/'" do
685
+ @uri.request_uri.should == "/"
686
+ end
687
+
642
688
  it "should have no fragment" do
643
689
  @uri.fragment.should == nil
644
690
  end
@@ -826,6 +872,51 @@ describe Addressable::URI, "when parsed from " +
826
872
  end
827
873
  end
828
874
 
875
+ # Section 5.1.2 of RFC 2616
876
+ describe Addressable::URI, "when parsed from " +
877
+ "'http://www.w3.org/pub/WWW/TheProject.html'" do
878
+ before do
879
+ @uri = Addressable::URI.parse("http://www.w3.org/pub/WWW/TheProject.html")
880
+ end
881
+
882
+ it "should have the correct request URI" do
883
+ @uri.request_uri.should == "/pub/WWW/TheProject.html"
884
+ end
885
+
886
+ it "should have the correct request URI after assignment" do
887
+ @uri.request_uri = "/some/where/else.html?query?string"
888
+ @uri.request_uri.should == "/some/where/else.html?query?string"
889
+ @uri.path.should == "/some/where/else.html"
890
+ @uri.query.should == "query?string"
891
+ end
892
+
893
+ it "should have the correct request URI after assignment" do
894
+ @uri.request_uri = "?x=y"
895
+ @uri.request_uri.should == "/?x=y"
896
+ @uri.path.should == "/"
897
+ @uri.query.should == "x=y"
898
+ end
899
+
900
+ it "should raise an error if the request URI is set to something bogus" do
901
+ (lambda do
902
+ @uri.request_uri = 42
903
+ end).should raise_error(TypeError)
904
+ end
905
+
906
+ it "should correctly convert to a hash" do
907
+ @uri.to_hash.should == {
908
+ :scheme => "http",
909
+ :user => nil,
910
+ :password => nil,
911
+ :host => "www.w3.org",
912
+ :port => nil,
913
+ :path => "/pub/WWW/TheProject.html",
914
+ :query => nil,
915
+ :fragment => nil
916
+ }
917
+ end
918
+ end
919
+
829
920
  describe Addressable::URI, "when parsed from " +
830
921
  "'http://example.com/'" do
831
922
  before do
@@ -871,6 +962,10 @@ describe Addressable::URI, "when parsed from " +
871
962
  @uri.to_s.should == "http://example.com/"
872
963
  end
873
964
 
965
+ it "should have a request URI of '/'" do
966
+ @uri.request_uri.should == "/"
967
+ end
968
+
874
969
  it "should correctly convert to a hash" do
875
970
  @uri.to_hash.should == {
876
971
  :scheme => "http",
@@ -1021,6 +1116,34 @@ describe Addressable::URI, "when parsed from " +
1021
1116
  end
1022
1117
  end
1023
1118
 
1119
+ describe Addressable::URI, "when parsed from " +
1120
+ "'http://example.com/path%2Fsegment/'" do
1121
+ before do
1122
+ @uri = Addressable::URI.parse("http://example.com/path%2Fsegment/")
1123
+ end
1124
+
1125
+ it "should be considered to be in normal form" do
1126
+ @uri.normalize.should be_eql(@uri)
1127
+ end
1128
+
1129
+ it "should be equal to 'http://example.com/path%2Fsegment/'" do
1130
+ @uri.normalize.should be_eql(
1131
+ Addressable::URI.parse("http://example.com/path%2Fsegment/")
1132
+ )
1133
+ end
1134
+
1135
+ it "should not be equal to 'http://example.com/path/segment/'" do
1136
+ @uri.should_not ==
1137
+ Addressable::URI.parse("http://example.com/path/segment/")
1138
+ end
1139
+
1140
+ it "should not be equal to 'http://example.com/path/segment/'" do
1141
+ @uri.normalize.should_not be_eql(
1142
+ Addressable::URI.parse("http://example.com/path/segment/")
1143
+ )
1144
+ end
1145
+ end
1146
+
1024
1147
  describe Addressable::URI, "when parsed from " +
1025
1148
  "'http://example.com/?%F6'" do
1026
1149
  before do
@@ -2985,7 +3108,8 @@ describe Addressable::URI, "with a base uri of 'http://a/b/c/d;p?q'" do
2985
3108
  # Section 5.4.1 of RFC 3986
2986
3109
  it "when joined with '#s' should resolve to http://a/b/c/d;p?q#s" do
2987
3110
  (@uri + "#s").to_s.should == "http://a/b/c/d;p?q#s"
2988
- Addressable::URI.join(@uri.to_s, "#s").to_s.should == "http://a/b/c/d;p?q#s"
3111
+ Addressable::URI.join(@uri.to_s, "#s").to_s.should ==
3112
+ "http://a/b/c/d;p?q#s"
2989
3113
  end
2990
3114
 
2991
3115
  # Section 5.4.1 of RFC 3986
@@ -3082,7 +3206,8 @@ describe Addressable::URI, "with a base uri of 'http://a/b/c/d;p?q'" do
3082
3206
 
3083
3207
  it "when joined with '../.././../g' should resolve to http://a/g" do
3084
3208
  (@uri + "../.././../g").to_s.should == "http://a/g"
3085
- Addressable::URI.join(@uri.to_s, "../.././../g").to_s.should == "http://a/g"
3209
+ Addressable::URI.join(@uri.to_s, "../.././../g").to_s.should ==
3210
+ "http://a/g"
3086
3211
  end
3087
3212
 
3088
3213
  # Section 5.4.2 of RFC 3986
@@ -3248,25 +3373,25 @@ describe Addressable::URI, "when converting a bogus path" do
3248
3373
  end
3249
3374
  end
3250
3375
 
3251
- describe Addressable::URI, "when given the root directory" do
3376
+ describe Addressable::URI, "when given a UNIX root directory" do
3252
3377
  before do
3253
- if RUBY_PLATFORM =~ /mswin/
3254
- @path = "C:\\"
3255
- else
3256
- @path = "/"
3257
- end
3378
+ @path = "/"
3258
3379
  end
3259
3380
 
3260
- if RUBY_PLATFORM =~ /mswin/
3261
- it "should convert to \'file:///c:/\'" do
3262
- @uri = Addressable::URI.convert_path(@path)
3263
- @uri.to_str.should == "file:///c:/"
3264
- end
3265
- else
3266
- it "should convert to \'file:///\'" do
3267
- @uri = Addressable::URI.convert_path(@path)
3268
- @uri.to_str.should == "file:///"
3269
- end
3381
+ it "should convert to \'file:///\'" do
3382
+ @uri = Addressable::URI.convert_path(@path)
3383
+ @uri.to_str.should == "file:///"
3384
+ end
3385
+ end
3386
+
3387
+ describe Addressable::URI, "when given a Windows root directory" do
3388
+ before do
3389
+ @path = "C:\\"
3390
+ end
3391
+
3392
+ it "should convert to \'file:///c:/\'" do
3393
+ @uri = Addressable::URI.convert_path(@path)
3394
+ @uri.to_str.should == "file:///c:/"
3270
3395
  end
3271
3396
  end
3272
3397
 
@@ -3390,6 +3515,71 @@ describe Addressable::URI, "when parsing a non-String object" do
3390
3515
  end
3391
3516
  end
3392
3517
 
3518
+ describe Addressable::URI, "when normalizing a non-String object" do
3519
+ it "should correctly parse anything with a 'to_str' method" do
3520
+ Addressable::URI.normalize_component(SuperString.new(42))
3521
+ end
3522
+
3523
+ it "should raise a TypeError for objects than cannot be converted" do
3524
+ (lambda do
3525
+ Addressable::URI.normalize_component(42)
3526
+ end).should raise_error(TypeError, "Can't convert Fixnum into String.")
3527
+ end
3528
+
3529
+ it "should raise a TypeError for objects than cannot be converted" do
3530
+ (lambda do
3531
+ Addressable::URI.normalize_component("component", 42)
3532
+ end).should raise_error(TypeError)
3533
+ end
3534
+ end
3535
+
3536
+ describe Addressable::URI, "when normalizing a path with an encoded slash" do
3537
+ it "should result in correct percent encoded sequence" do
3538
+ Addressable::URI.parse("/path%2Fsegment/").normalize.path.should ==
3539
+ "/path%2Fsegment/"
3540
+ end
3541
+ end
3542
+
3543
+ describe Addressable::URI, "when normalizing a partially encoded string" do
3544
+ it "should result in correct percent encoded sequence" do
3545
+ Addressable::URI.normalize_component(
3546
+ "partially % encoded%21"
3547
+ ).should == "partially%20%25%20encoded!"
3548
+ end
3549
+
3550
+ it "should result in correct percent encoded sequence" do
3551
+ Addressable::URI.normalize_component(
3552
+ "partially %25 encoded!"
3553
+ ).should == "partially%20%25%20encoded!"
3554
+ end
3555
+ end
3556
+
3557
+ describe Addressable::URI, "when normalizing a unicode sequence" do
3558
+ it "should result in correct percent encoded sequence" do
3559
+ Addressable::URI.normalize_component(
3560
+ "/C%CC%A7"
3561
+ ).should == "/%C3%87"
3562
+ end
3563
+
3564
+ it "should result in correct percent encoded sequence" do
3565
+ Addressable::URI.normalize_component(
3566
+ "/%C3%87"
3567
+ ).should == "/%C3%87"
3568
+ end
3569
+ end
3570
+
3571
+ describe Addressable::URI, "when normalizing a multibyte string" do
3572
+ it "should result in correct percent encoded sequence" do
3573
+ Addressable::URI.normalize_component("günther").should ==
3574
+ "g%C3%BCnther"
3575
+ end
3576
+
3577
+ it "should result in correct percent encoded sequence" do
3578
+ Addressable::URI.normalize_component("g%C3%BCnther").should ==
3579
+ "g%C3%BCnther"
3580
+ end
3581
+ end
3582
+
3393
3583
  describe Addressable::URI, "when encoding a multibyte string" do
3394
3584
  it "should result in correct percent encoded sequence" do
3395
3585
  Addressable::URI.encode_component("günther").should == "g%C3%BCnther"
@@ -3675,3 +3865,50 @@ describe Addressable::URI, "when assigning query values" do
3675
3865
  @uri.query.should == "a=a&b[c]&b[d]=d"
3676
3866
  end
3677
3867
  end
3868
+
3869
+ describe Addressable::URI, "when assigning path values" do
3870
+ before do
3871
+ @uri = Addressable::URI.new
3872
+ end
3873
+
3874
+ it "should correctly assign paths containing colons" do
3875
+ @uri.path = "acct:bob@sporkmonger.com"
3876
+ Addressable::URI.parse(@uri.normalize.to_str).path.should == @uri.path
3877
+ @uri.normalize.to_str.should == "acct%2Fbob@sporkmonger.com"
3878
+ end
3879
+
3880
+ it "should correctly assign paths containing colons" do
3881
+ @uri.path = "/acct:bob@sporkmonger.com"
3882
+ @uri.authority = "example.com"
3883
+ @uri.normalize.to_str.should == "//example.com/acct:bob@sporkmonger.com"
3884
+ end
3885
+
3886
+ it "should correctly assign paths containing colons" do
3887
+ @uri.path = "acct:bob@sporkmonger.com"
3888
+ @uri.scheme = "something"
3889
+ @uri.normalize.to_str.should == "something:acct:bob@sporkmonger.com"
3890
+ end
3891
+
3892
+ it "should not allow relative paths to be assigned on absolute URIs" do
3893
+ (lambda do
3894
+ @uri.scheme = "http"
3895
+ @uri.host = "example.com"
3896
+ @uri.path = "acct:bob@sporkmonger.com"
3897
+ end).should raise_error(Addressable::URI::InvalidURIError)
3898
+ end
3899
+
3900
+ it "should not allow relative paths to be assigned on absolute URIs" do
3901
+ (lambda do
3902
+ @uri.path = "acct:bob@sporkmonger.com"
3903
+ @uri.scheme = "http"
3904
+ @uri.host = "example.com"
3905
+ end).should raise_error(Addressable::URI::InvalidURIError)
3906
+ end
3907
+
3908
+ it "should not allow relative paths to be assigned on absolute URIs" do
3909
+ (lambda do
3910
+ @uri.path = "uuid:0b3ecf60-3f93-11df-a9c3-001f5bfffe12"
3911
+ @uri.scheme = "urn"
3912
+ end).should_not raise_error(Addressable::URI::InvalidURIError)
3913
+ end
3914
+ end
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.1.1
4
+ version: 2.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bob Aman
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-10-31 00:00:00 -07:00
12
+ date: 2010-04-23 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency