addressable 2.1.1 → 2.1.2

Sign up to get free protection for your applications and to get access to all the features.
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