addressable 2.8.0 → 2.8.4

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.
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # encoding:utf-8
4
3
  #--
5
4
  # Copyright (C) Bob Aman
6
5
  #
@@ -38,20 +37,26 @@ module Addressable
38
37
  ##
39
38
  # Container for the character classes specified in
40
39
  # <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>.
40
+ #
41
+ # Note: Concatenated and interpolated `String`s are not affected by the
42
+ # `frozen_string_literal` directive and must be frozen explicitly.
43
+ #
44
+ # Interpolated `String`s *were* frozen this way before Ruby 3.0:
45
+ # https://bugs.ruby-lang.org/issues/17104
41
46
  module CharacterClasses
42
47
  ALPHA = "a-zA-Z"
43
48
  DIGIT = "0-9"
44
49
  GEN_DELIMS = "\\:\\/\\?\\#\\[\\]\\@"
45
50
  SUB_DELIMS = "\\!\\$\\&\\'\\(\\)\\*\\+\\,\\;\\="
46
- RESERVED = GEN_DELIMS + SUB_DELIMS
47
- UNRESERVED = ALPHA + DIGIT + "\\-\\.\\_\\~"
48
- PCHAR = UNRESERVED + SUB_DELIMS + "\\:\\@"
49
- SCHEME = ALPHA + DIGIT + "\\-\\+\\."
50
- HOST = UNRESERVED + SUB_DELIMS + "\\[\\:\\]"
51
- AUTHORITY = PCHAR + "\\[\\:\\]"
52
- PATH = PCHAR + "\\/"
53
- QUERY = PCHAR + "\\/\\?"
54
- FRAGMENT = PCHAR + "\\/\\?"
51
+ RESERVED = (GEN_DELIMS + SUB_DELIMS).freeze
52
+ UNRESERVED = (ALPHA + DIGIT + "\\-\\.\\_\\~").freeze
53
+ PCHAR = (UNRESERVED + SUB_DELIMS + "\\:\\@").freeze
54
+ SCHEME = (ALPHA + DIGIT + "\\-\\+\\.").freeze
55
+ HOST = (UNRESERVED + SUB_DELIMS + "\\[\\:\\]").freeze
56
+ AUTHORITY = (PCHAR + "\\[\\]").freeze
57
+ PATH = (PCHAR + "\\/").freeze
58
+ QUERY = (PCHAR + "\\/\\?").freeze
59
+ FRAGMENT = (PCHAR + "\\/\\?").freeze
55
60
  end
56
61
 
57
62
  module NormalizeCharacterClasses
@@ -112,7 +117,7 @@ module Addressable
112
117
  uri = uri.to_str
113
118
  rescue TypeError, NoMethodError
114
119
  raise TypeError, "Can't convert #{uri.class} into String."
115
- end if not uri.is_a? String
120
+ end unless uri.is_a?(String)
116
121
 
117
122
  # This Regexp supplied as an example in RFC 3986, and it works great.
118
123
  scan = uri.scan(URIREGEX)
@@ -133,15 +138,15 @@ module Addressable
133
138
  user = userinfo.strip[/^([^:]*):?/, 1]
134
139
  password = userinfo.strip[/:(.*)$/, 1]
135
140
  end
141
+
136
142
  host = authority.sub(
137
143
  /^([^\[\]]*)@/, EMPTY_STR
138
144
  ).sub(
139
145
  /:([^:@\[\]]*?)$/, EMPTY_STR
140
146
  )
147
+
141
148
  port = authority[/:([^:@\[\]]*?)$/, 1]
142
- end
143
- if port == EMPTY_STR
144
- port = nil
149
+ port = nil if port == EMPTY_STR
145
150
  end
146
151
 
147
152
  return new(
@@ -184,7 +189,7 @@ module Addressable
184
189
  uri = uri.to_s
185
190
  end
186
191
 
187
- if !uri.respond_to?(:to_str)
192
+ unless uri.respond_to?(:to_str)
188
193
  raise TypeError, "Can't convert #{uri.class} into String."
189
194
  end
190
195
  # Otherwise, convert to a String
@@ -276,7 +281,7 @@ module Addressable
276
281
  return nil unless path
277
282
  # If a URI object is passed, just return itself.
278
283
  return path if path.kind_of?(self)
279
- if !path.respond_to?(:to_str)
284
+ unless path.respond_to?(:to_str)
280
285
  raise TypeError, "Can't convert #{path.class} into String."
281
286
  end
282
287
  # Otherwise, convert to a String
@@ -324,13 +329,13 @@ module Addressable
324
329
  # #=> #<Addressable::URI:0xcab390 URI:http://example.com/relative/path>
325
330
  def self.join(*uris)
326
331
  uri_objects = uris.collect do |uri|
327
- if !uri.respond_to?(:to_str)
332
+ unless uri.respond_to?(:to_str)
328
333
  raise TypeError, "Can't convert #{uri.class} into String."
329
334
  end
330
335
  uri.kind_of?(self) ? uri : self.parse(uri.to_str)
331
336
  end
332
337
  result = uri_objects.shift.dup
333
- for uri in uri_objects
338
+ uri_objects.each do |uri|
334
339
  result.join!(uri)
335
340
  end
336
341
  return result
@@ -469,20 +474,14 @@ module Addressable
469
474
  "Expected Class (String or Addressable::URI), " +
470
475
  "got #{return_type.inspect}"
471
476
  end
472
- uri = uri.dup
473
- # Seriously, only use UTF-8. I'm really not kidding!
474
- uri.force_encoding("utf-8")
475
477
 
476
- unless leave_encoded.empty?
477
- leave_encoded = leave_encoded.dup.force_encoding("utf-8")
478
- end
479
-
480
- result = uri.gsub(/%[0-9a-f]{2}/iu) do |sequence|
478
+ result = uri.gsub(/%[0-9a-f]{2}/i) do |sequence|
481
479
  c = sequence[1..3].to_i(16).chr
482
- c.force_encoding("utf-8")
480
+ c.force_encoding(sequence.encoding)
483
481
  leave_encoded.include?(c) ? sequence : c
484
482
  end
485
- result.force_encoding("utf-8")
483
+
484
+ result.force_encoding(Encoding::UTF_8)
486
485
  if return_type == String
487
486
  return result
488
487
  elsif return_type == ::Addressable::URI
@@ -561,10 +560,10 @@ module Addressable
561
560
  leave_re = if leave_encoded.length > 0
562
561
  character_class = "#{character_class}%" unless character_class.include?('%')
563
562
 
564
- "|%(?!#{leave_encoded.chars.map do |char|
563
+ "|%(?!#{leave_encoded.chars.flat_map do |char|
565
564
  seq = SEQUENCE_ENCODING_TABLE[char]
566
565
  [seq.upcase, seq.downcase]
567
- end.flatten.join('|')})"
566
+ end.join('|')})"
568
567
  end
569
568
 
570
569
  character_class = if leave_re
@@ -580,7 +579,7 @@ module Addressable
580
579
  unencoded = self.unencode_component(component, String, leave_encoded)
581
580
  begin
582
581
  encoded = self.encode_component(
583
- Addressable::IDNA.unicode_normalize_kc(unencoded),
582
+ unencoded.unicode_normalize(:nfc),
584
583
  character_class,
585
584
  leave_encoded
586
585
  )
@@ -688,8 +687,7 @@ module Addressable
688
687
  components.each do |key, value|
689
688
  if value != nil
690
689
  begin
691
- components[key] =
692
- Addressable::IDNA.unicode_normalize_kc(value.to_str)
690
+ components[key] = value.to_str.unicode_normalize(:nfc)
693
691
  rescue ArgumentError
694
692
  # Likely a malformed UTF-8 character, skip unicode normalization
695
693
  components[key] = value.to_str
@@ -837,7 +835,9 @@ module Addressable
837
835
  end
838
836
  end
839
837
 
840
- self.defer_validation do
838
+ reset_ivs
839
+
840
+ defer_validation do
841
841
  # Bunch of crazy logic required because of the composite components
842
842
  # like userinfo and authority.
843
843
  self.scheme = options[:scheme] if options[:scheme]
@@ -852,7 +852,8 @@ module Addressable
852
852
  self.query_values = options[:query_values] if options[:query_values]
853
853
  self.fragment = options[:fragment] if options[:fragment]
854
854
  end
855
- self.to_s
855
+
856
+ to_s # force path validation
856
857
  end
857
858
 
858
859
  ##
@@ -879,9 +880,7 @@ module Addressable
879
880
  # The scheme component for this URI.
880
881
  #
881
882
  # @return [String] The scheme component.
882
- def scheme
883
- return defined?(@scheme) ? @scheme : nil
884
- end
883
+ attr_reader :scheme
885
884
 
886
885
  ##
887
886
  # The scheme component for this URI, normalized.
@@ -889,8 +888,8 @@ module Addressable
889
888
  # @return [String] The scheme component, normalized.
890
889
  def normalized_scheme
891
890
  return nil unless self.scheme
892
- @normalized_scheme ||= begin
893
- if self.scheme =~ /^\s*ssh\+svn\s*$/i
891
+ if @normalized_scheme == NONE
892
+ @normalized_scheme = if self.scheme =~ /^\s*ssh\+svn\s*$/i
894
893
  "svn+ssh".dup
895
894
  else
896
895
  Addressable::URI.normalize_component(
@@ -900,7 +899,7 @@ module Addressable
900
899
  end
901
900
  end
902
901
  # All normalized values should be UTF-8
903
- @normalized_scheme.force_encoding(Encoding::UTF_8) if @normalized_scheme
902
+ force_utf8_encoding_if_needed(@normalized_scheme)
904
903
  @normalized_scheme
905
904
  end
906
905
 
@@ -921,7 +920,7 @@ module Addressable
921
920
  @scheme = nil if @scheme.to_s.strip.empty?
922
921
 
923
922
  # Reset dependent values
924
- remove_instance_variable(:@normalized_scheme) if defined?(@normalized_scheme)
923
+ @normalized_scheme = NONE
925
924
  remove_composite_values
926
925
 
927
926
  # Ensure we haven't created an invalid URI
@@ -932,9 +931,7 @@ module Addressable
932
931
  # The user component for this URI.
933
932
  #
934
933
  # @return [String] The user component.
935
- def user
936
- return defined?(@user) ? @user : nil
937
- end
934
+ attr_reader :user
938
935
 
939
936
  ##
940
937
  # The user component for this URI, normalized.
@@ -942,8 +939,8 @@ module Addressable
942
939
  # @return [String] The user component, normalized.
943
940
  def normalized_user
944
941
  return nil unless self.user
945
- return @normalized_user if defined?(@normalized_user)
946
- @normalized_user ||= begin
942
+ return @normalized_user unless @normalized_user == NONE
943
+ @normalized_user = begin
947
944
  if normalized_scheme =~ /https?/ && self.user.strip.empty? &&
948
945
  (!self.password || self.password.strip.empty?)
949
946
  nil
@@ -955,7 +952,7 @@ module Addressable
955
952
  end
956
953
  end
957
954
  # All normalized values should be UTF-8
958
- @normalized_user.force_encoding(Encoding::UTF_8) if @normalized_user
955
+ force_utf8_encoding_if_needed(@normalized_user)
959
956
  @normalized_user
960
957
  end
961
958
 
@@ -971,14 +968,14 @@ module Addressable
971
968
 
972
969
  # You can't have a nil user with a non-nil password
973
970
  if password != nil
974
- @user = EMPTY_STR if @user.nil?
971
+ @user = EMPTY_STR unless user
975
972
  end
976
973
 
977
974
  # Reset dependent values
978
- remove_instance_variable(:@userinfo) if defined?(@userinfo)
979
- remove_instance_variable(:@normalized_userinfo) if defined?(@normalized_userinfo)
980
- remove_instance_variable(:@authority) if defined?(@authority)
981
- remove_instance_variable(:@normalized_user) if defined?(@normalized_user)
975
+ @userinfo = nil
976
+ @normalized_userinfo = NONE
977
+ @authority = nil
978
+ @normalized_user = NONE
982
979
  remove_composite_values
983
980
 
984
981
  # Ensure we haven't created an invalid URI
@@ -989,9 +986,7 @@ module Addressable
989
986
  # The password component for this URI.
990
987
  #
991
988
  # @return [String] The password component.
992
- def password
993
- return defined?(@password) ? @password : nil
994
- end
989
+ attr_reader :password
995
990
 
996
991
  ##
997
992
  # The password component for this URI, normalized.
@@ -999,8 +994,8 @@ module Addressable
999
994
  # @return [String] The password component, normalized.
1000
995
  def normalized_password
1001
996
  return nil unless self.password
1002
- return @normalized_password if defined?(@normalized_password)
1003
- @normalized_password ||= begin
997
+ return @normalized_password unless @normalized_password == NONE
998
+ @normalized_password = begin
1004
999
  if self.normalized_scheme =~ /https?/ && self.password.strip.empty? &&
1005
1000
  (!self.user || self.user.strip.empty?)
1006
1001
  nil
@@ -1012,9 +1007,7 @@ module Addressable
1012
1007
  end
1013
1008
  end
1014
1009
  # All normalized values should be UTF-8
1015
- if @normalized_password
1016
- @normalized_password.force_encoding(Encoding::UTF_8)
1017
- end
1010
+ force_utf8_encoding_if_needed(@normalized_password)
1018
1011
  @normalized_password
1019
1012
  end
1020
1013
 
@@ -1029,17 +1022,15 @@ module Addressable
1029
1022
  @password = new_password ? new_password.to_str : nil
1030
1023
 
1031
1024
  # You can't have a nil user with a non-nil password
1032
- @password ||= nil
1033
- @user ||= nil
1034
1025
  if @password != nil
1035
- @user = EMPTY_STR if @user.nil?
1026
+ self.user = EMPTY_STR if user.nil?
1036
1027
  end
1037
1028
 
1038
1029
  # Reset dependent values
1039
- remove_instance_variable(:@userinfo) if defined?(@userinfo)
1040
- remove_instance_variable(:@normalized_userinfo) if defined?(@normalized_userinfo)
1041
- remove_instance_variable(:@authority) if defined?(@authority)
1042
- remove_instance_variable(:@normalized_password) if defined?(@normalized_password)
1030
+ @userinfo = nil
1031
+ @normalized_userinfo = NONE
1032
+ @authority = nil
1033
+ @normalized_password = NONE
1043
1034
  remove_composite_values
1044
1035
 
1045
1036
  # Ensure we haven't created an invalid URI
@@ -1069,8 +1060,8 @@ module Addressable
1069
1060
  # @return [String] The userinfo component, normalized.
1070
1061
  def normalized_userinfo
1071
1062
  return nil unless self.userinfo
1072
- return @normalized_userinfo if defined?(@normalized_userinfo)
1073
- @normalized_userinfo ||= begin
1063
+ return @normalized_userinfo unless @normalized_userinfo == NONE
1064
+ @normalized_userinfo = begin
1074
1065
  current_user = self.normalized_user
1075
1066
  current_password = self.normalized_password
1076
1067
  if !current_user && !current_password
@@ -1082,9 +1073,7 @@ module Addressable
1082
1073
  end
1083
1074
  end
1084
1075
  # All normalized values should be UTF-8
1085
- if @normalized_userinfo
1086
- @normalized_userinfo.force_encoding(Encoding::UTF_8)
1087
- end
1076
+ force_utf8_encoding_if_needed(@normalized_userinfo)
1088
1077
  @normalized_userinfo
1089
1078
  end
1090
1079
 
@@ -1110,7 +1099,7 @@ module Addressable
1110
1099
  self.user = new_user
1111
1100
 
1112
1101
  # Reset dependent values
1113
- remove_instance_variable(:@authority) if defined?(@authority)
1102
+ @authority = nil
1114
1103
  remove_composite_values
1115
1104
 
1116
1105
  # Ensure we haven't created an invalid URI
@@ -1121,9 +1110,7 @@ module Addressable
1121
1110
  # The host component for this URI.
1122
1111
  #
1123
1112
  # @return [String] The host component.
1124
- def host
1125
- return defined?(@host) ? @host : nil
1126
- end
1113
+ attr_reader :host
1127
1114
 
1128
1115
  ##
1129
1116
  # The host component for this URI, normalized.
@@ -1151,9 +1138,7 @@ module Addressable
1151
1138
  end
1152
1139
  end
1153
1140
  # All normalized values should be UTF-8
1154
- if @normalized_host && !@normalized_host.empty?
1155
- @normalized_host.force_encoding(Encoding::UTF_8)
1156
- end
1141
+ force_utf8_encoding_if_needed(@normalized_host)
1157
1142
  @normalized_host
1158
1143
  end
1159
1144
 
@@ -1168,8 +1153,8 @@ module Addressable
1168
1153
  @host = new_host ? new_host.to_str : nil
1169
1154
 
1170
1155
  # Reset dependent values
1171
- remove_instance_variable(:@authority) if defined?(@authority)
1172
- remove_instance_variable(:@normalized_host) if defined?(@normalized_host)
1156
+ @authority = nil
1157
+ @normalized_host = nil
1173
1158
  remove_composite_values
1174
1159
 
1175
1160
  # Ensure we haven't created an invalid URI
@@ -1271,9 +1256,7 @@ module Addressable
1271
1256
  authority
1272
1257
  end
1273
1258
  # All normalized values should be UTF-8
1274
- if @normalized_authority
1275
- @normalized_authority.force_encoding(Encoding::UTF_8)
1276
- end
1259
+ force_utf8_encoding_if_needed(@normalized_authority)
1277
1260
  @normalized_authority
1278
1261
  end
1279
1262
 
@@ -1302,14 +1285,14 @@ module Addressable
1302
1285
  end
1303
1286
 
1304
1287
  # Password assigned first to ensure validity in case of nil
1305
- self.password = defined?(new_password) ? new_password : nil
1306
- self.user = defined?(new_user) ? new_user : nil
1307
- self.host = defined?(new_host) ? new_host : nil
1308
- self.port = defined?(new_port) ? new_port : nil
1288
+ self.password = new_password
1289
+ self.user = new_user
1290
+ self.host = new_host
1291
+ self.port = new_port
1309
1292
 
1310
1293
  # Reset dependent values
1311
- remove_instance_variable(:@userinfo) if defined?(@userinfo)
1312
- remove_instance_variable(:@normalized_userinfo) if defined?(@normalized_userinfo)
1294
+ @userinfo = nil
1295
+ @normalized_userinfo = NONE
1313
1296
  remove_composite_values
1314
1297
 
1315
1298
  # Ensure we haven't created an invalid URI
@@ -1357,16 +1340,16 @@ module Addressable
1357
1340
  new_port = new_origin[/:([^:@\[\]\/]*?)$/, 1]
1358
1341
  end
1359
1342
 
1360
- self.scheme = defined?(new_scheme) ? new_scheme : nil
1361
- self.host = defined?(new_host) ? new_host : nil
1362
- self.port = defined?(new_port) ? new_port : nil
1343
+ self.scheme = new_scheme
1344
+ self.host = new_host
1345
+ self.port = new_port
1363
1346
  self.userinfo = nil
1364
1347
 
1365
1348
  # Reset dependent values
1366
- remove_instance_variable(:@userinfo) if defined?(@userinfo)
1367
- remove_instance_variable(:@normalized_userinfo) if defined?(@normalized_userinfo)
1368
- remove_instance_variable(:@authority) if defined?(@authority)
1369
- remove_instance_variable(:@normalized_authority) if defined?(@normalized_authority)
1349
+ @userinfo = nil
1350
+ @normalized_userinfo = NONE
1351
+ @authority = nil
1352
+ @normalized_authority = nil
1370
1353
  remove_composite_values
1371
1354
 
1372
1355
  # Ensure we haven't created an invalid URI
@@ -1393,9 +1376,7 @@ module Addressable
1393
1376
  # infer port numbers from default values.
1394
1377
  #
1395
1378
  # @return [Integer] The port component.
1396
- def port
1397
- return defined?(@port) ? @port : nil
1398
- end
1379
+ attr_reader :port
1399
1380
 
1400
1381
  ##
1401
1382
  # The port component for this URI, normalized.
@@ -1403,8 +1384,8 @@ module Addressable
1403
1384
  # @return [Integer] The port component, normalized.
1404
1385
  def normalized_port
1405
1386
  return nil unless self.port
1406
- return @normalized_port if defined?(@normalized_port)
1407
- @normalized_port ||= begin
1387
+ return @normalized_port unless @normalized_port == NONE
1388
+ @normalized_port = begin
1408
1389
  if URI.port_mapping[self.normalized_scheme] == self.port
1409
1390
  nil
1410
1391
  else
@@ -1435,8 +1416,8 @@ module Addressable
1435
1416
  @port = nil if @port == 0
1436
1417
 
1437
1418
  # Reset dependent values
1438
- remove_instance_variable(:@authority) if defined?(@authority)
1439
- remove_instance_variable(:@normalized_port) if defined?(@normalized_port)
1419
+ @authority = nil
1420
+ @normalized_port = NONE
1440
1421
  remove_composite_values
1441
1422
 
1442
1423
  # Ensure we haven't created an invalid URI
@@ -1507,7 +1488,7 @@ module Addressable
1507
1488
  site_string
1508
1489
  end
1509
1490
  # All normalized values should be UTF-8
1510
- @normalized_site.force_encoding(Encoding::UTF_8) if @normalized_site
1491
+ force_utf8_encoding_if_needed(@normalized_site)
1511
1492
  @normalized_site
1512
1493
  end
1513
1494
 
@@ -1537,9 +1518,7 @@ module Addressable
1537
1518
  # The path component for this URI.
1538
1519
  #
1539
1520
  # @return [String] The path component.
1540
- def path
1541
- return defined?(@path) ? @path : EMPTY_STR
1542
- end
1521
+ attr_reader :path
1543
1522
 
1544
1523
  NORMPATH = /^(?!\/)[^\/:]*:.*$/
1545
1524
  ##
@@ -1570,7 +1549,7 @@ module Addressable
1570
1549
  result
1571
1550
  end
1572
1551
  # All normalized values should be UTF-8
1573
- @normalized_path.force_encoding(Encoding::UTF_8) if @normalized_path
1552
+ force_utf8_encoding_if_needed(@normalized_path)
1574
1553
  @normalized_path
1575
1554
  end
1576
1555
 
@@ -1588,7 +1567,7 @@ module Addressable
1588
1567
  end
1589
1568
 
1590
1569
  # Reset dependent values
1591
- remove_instance_variable(:@normalized_path) if defined?(@normalized_path)
1570
+ @normalized_path = nil
1592
1571
  remove_composite_values
1593
1572
 
1594
1573
  # Ensure we haven't created an invalid URI
@@ -1618,9 +1597,7 @@ module Addressable
1618
1597
  # The query component for this URI.
1619
1598
  #
1620
1599
  # @return [String] The query component.
1621
- def query
1622
- return defined?(@query) ? @query : nil
1623
- end
1600
+ attr_reader :query
1624
1601
 
1625
1602
  ##
1626
1603
  # The query component for this URI, normalized.
@@ -1628,8 +1605,8 @@ module Addressable
1628
1605
  # @return [String] The query component, normalized.
1629
1606
  def normalized_query(*flags)
1630
1607
  return nil unless self.query
1631
- return @normalized_query if defined?(@normalized_query)
1632
- @normalized_query ||= begin
1608
+ return @normalized_query unless @normalized_query == NONE
1609
+ @normalized_query = begin
1633
1610
  modified_query_class = Addressable::URI::CharacterClasses::QUERY.dup
1634
1611
  # Make sure possible key-value pair delimiters are escaped.
1635
1612
  modified_query_class.sub!("\\&", "").sub!("\\;", "")
@@ -1646,7 +1623,7 @@ module Addressable
1646
1623
  component == "" ? nil : component
1647
1624
  end
1648
1625
  # All normalized values should be UTF-8
1649
- @normalized_query.force_encoding(Encoding::UTF_8) if @normalized_query
1626
+ force_utf8_encoding_if_needed(@normalized_query)
1650
1627
  @normalized_query
1651
1628
  end
1652
1629
 
@@ -1661,7 +1638,7 @@ module Addressable
1661
1638
  @query = new_query ? new_query.to_str : nil
1662
1639
 
1663
1640
  # Reset dependent values
1664
- remove_instance_variable(:@normalized_query) if defined?(@normalized_query)
1641
+ @normalized_query = NONE
1665
1642
  remove_composite_values
1666
1643
  end
1667
1644
 
@@ -1823,9 +1800,7 @@ module Addressable
1823
1800
  # The fragment component for this URI.
1824
1801
  #
1825
1802
  # @return [String] The fragment component.
1826
- def fragment
1827
- return defined?(@fragment) ? @fragment : nil
1828
- end
1803
+ attr_reader :fragment
1829
1804
 
1830
1805
  ##
1831
1806
  # The fragment component for this URI, normalized.
@@ -1833,8 +1808,8 @@ module Addressable
1833
1808
  # @return [String] The fragment component, normalized.
1834
1809
  def normalized_fragment
1835
1810
  return nil unless self.fragment
1836
- return @normalized_fragment if defined?(@normalized_fragment)
1837
- @normalized_fragment ||= begin
1811
+ return @normalized_fragment unless @normalized_fragment == NONE
1812
+ @normalized_fragment = begin
1838
1813
  component = Addressable::URI.normalize_component(
1839
1814
  self.fragment,
1840
1815
  Addressable::URI::NormalizeCharacterClasses::FRAGMENT
@@ -1842,9 +1817,7 @@ module Addressable
1842
1817
  component == "" ? nil : component
1843
1818
  end
1844
1819
  # All normalized values should be UTF-8
1845
- if @normalized_fragment
1846
- @normalized_fragment.force_encoding(Encoding::UTF_8)
1847
- end
1820
+ force_utf8_encoding_if_needed(@normalized_fragment)
1848
1821
  @normalized_fragment
1849
1822
  end
1850
1823
 
@@ -1859,7 +1832,7 @@ module Addressable
1859
1832
  @fragment = new_fragment ? new_fragment.to_str : nil
1860
1833
 
1861
1834
  # Reset dependent values
1862
- remove_instance_variable(:@normalized_fragment) if defined?(@normalized_fragment)
1835
+ @normalized_fragment = NONE
1863
1836
  remove_composite_values
1864
1837
 
1865
1838
  # Ensure we haven't created an invalid URI
@@ -2025,7 +1998,7 @@ module Addressable
2025
1998
  #
2026
1999
  # @see Hash#merge
2027
2000
  def merge(hash)
2028
- if !hash.respond_to?(:to_hash)
2001
+ unless hash.respond_to?(:to_hash)
2029
2002
  raise TypeError, "Can't convert #{hash.class} into Hash."
2030
2003
  end
2031
2004
  hash = hash.to_hash
@@ -2419,7 +2392,8 @@ module Addressable
2419
2392
  yield
2420
2393
  @validation_deferred = false
2421
2394
  validate
2422
- return nil
2395
+ ensure
2396
+ @validation_deferred = false
2423
2397
  end
2424
2398
 
2425
2399
  protected
@@ -2440,30 +2414,35 @@ module Addressable
2440
2414
  def self.normalize_path(path)
2441
2415
  # Section 5.2.4 of RFC 3986
2442
2416
 
2443
- return nil if path.nil?
2417
+ return if path.nil?
2444
2418
  normalized_path = path.dup
2445
- begin
2446
- mod = nil
2419
+ loop do
2447
2420
  mod ||= normalized_path.gsub!(RULE_2A, SLASH)
2448
2421
 
2449
2422
  pair = normalized_path.match(RULE_2B_2C)
2450
- parent, current = pair[1], pair[2] if pair
2423
+ if pair
2424
+ parent = pair[1]
2425
+ current = pair[2]
2426
+ else
2427
+ parent = nil
2428
+ current = nil
2429
+ end
2430
+
2431
+ regexp = "/#{Regexp.escape(parent.to_s)}/\\.\\./|"
2432
+ regexp += "(/#{Regexp.escape(current.to_s)}/\\.\\.$)"
2433
+
2451
2434
  if pair && ((parent != SELF_REF && parent != PARENT) ||
2452
2435
  (current != SELF_REF && current != PARENT))
2453
- mod ||= normalized_path.gsub!(
2454
- Regexp.new(
2455
- "/#{Regexp.escape(parent.to_s)}/\\.\\./|" +
2456
- "(/#{Regexp.escape(current.to_s)}/\\.\\.$)"
2457
- ), SLASH
2458
- )
2436
+ mod ||= normalized_path.gsub!(Regexp.new(regexp), SLASH)
2459
2437
  end
2460
2438
 
2461
2439
  mod ||= normalized_path.gsub!(RULE_2D, EMPTY_STR)
2462
2440
  # Non-standard, removes prefixed dotted segments from path.
2463
2441
  mod ||= normalized_path.gsub!(RULE_PREFIXED_PARENT, SLASH)
2464
- end until mod.nil?
2442
+ break if mod.nil?
2443
+ end
2465
2444
 
2466
- return normalized_path
2445
+ normalized_path
2467
2446
  end
2468
2447
 
2469
2448
  ##
@@ -2513,11 +2492,7 @@ module Addressable
2513
2492
  # @return [Addressable::URI] <code>self</code>.
2514
2493
  def replace_self(uri)
2515
2494
  # Reset dependent values
2516
- instance_variables.each do |var|
2517
- if instance_variable_defined?(var) && var != :@validation_deferred
2518
- remove_instance_variable(var)
2519
- end
2520
- end
2495
+ reset_ivs
2521
2496
 
2522
2497
  @scheme = uri.scheme
2523
2498
  @user = uri.user
@@ -2549,8 +2524,53 @@ module Addressable
2549
2524
  #
2550
2525
  # @api private
2551
2526
  def remove_composite_values
2552
- remove_instance_variable(:@uri_string) if defined?(@uri_string)
2553
- remove_instance_variable(:@hash) if defined?(@hash)
2527
+ @uri_string = nil
2528
+ @hash = nil
2529
+ end
2530
+
2531
+ ##
2532
+ # Converts the string to be UTF-8 if it is not already UTF-8
2533
+ #
2534
+ # @api private
2535
+ def force_utf8_encoding_if_needed(str)
2536
+ if str && str.encoding != Encoding::UTF_8
2537
+ str.force_encoding(Encoding::UTF_8)
2538
+ end
2554
2539
  end
2540
+
2541
+ private
2542
+
2543
+ ##
2544
+ # Resets instance variables
2545
+ #
2546
+ # @api private
2547
+ def reset_ivs
2548
+ @scheme = nil
2549
+ @user = nil
2550
+ @normalized_scheme = NONE
2551
+ @normalized_user = NONE
2552
+ @uri_string = nil
2553
+ @hash = nil
2554
+ @userinfo = nil
2555
+ @normalized_userinfo = NONE
2556
+ @authority = nil
2557
+ @password = nil
2558
+ @normalized_authority = nil
2559
+ @port = nil
2560
+ @normalized_password = NONE
2561
+ @host = nil
2562
+ @normalized_host = nil
2563
+ @normalized_port = NONE
2564
+ @path = EMPTY_STR
2565
+ @normalized_path = nil
2566
+ @normalized_query = NONE
2567
+ @fragment = nil
2568
+ @normalized_fragment = NONE
2569
+ @query = nil
2570
+ end
2571
+
2572
+ NONE = Object.new.freeze
2573
+
2574
+ private_constant :NONE
2555
2575
  end
2556
2576
  end