addressable 2.8.1 → 2.8.7

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.
@@ -50,10 +50,11 @@ module Addressable
50
50
  SUB_DELIMS = "\\!\\$\\&\\'\\(\\)\\*\\+\\,\\;\\="
51
51
  RESERVED = (GEN_DELIMS + SUB_DELIMS).freeze
52
52
  UNRESERVED = (ALPHA + DIGIT + "\\-\\.\\_\\~").freeze
53
+ RESERVED_AND_UNRESERVED = RESERVED + UNRESERVED
53
54
  PCHAR = (UNRESERVED + SUB_DELIMS + "\\:\\@").freeze
54
55
  SCHEME = (ALPHA + DIGIT + "\\-\\+\\.").freeze
55
56
  HOST = (UNRESERVED + SUB_DELIMS + "\\[\\:\\]").freeze
56
- AUTHORITY = (PCHAR + "\\[\\:\\]").freeze
57
+ AUTHORITY = (PCHAR + "\\[\\]").freeze
57
58
  PATH = (PCHAR + "\\/").freeze
58
59
  QUERY = (PCHAR + "\\/\\?").freeze
59
60
  FRAGMENT = (PCHAR + "\\/\\?").freeze
@@ -68,6 +69,18 @@ module Addressable
68
69
  QUERY = %r{[^a-zA-Z0-9\-\.\_\~\!\$\'\(\)\*\+\,\=\:\@\/\?%]|%(?!2B|2b)}
69
70
  end
70
71
 
72
+ module CharacterClassesRegexps
73
+ AUTHORITY = /[^#{CharacterClasses::AUTHORITY}]/
74
+ FRAGMENT = /[^#{CharacterClasses::FRAGMENT}]/
75
+ HOST = /[^#{CharacterClasses::HOST}]/
76
+ PATH = /[^#{CharacterClasses::PATH}]/
77
+ QUERY = /[^#{CharacterClasses::QUERY}]/
78
+ RESERVED = /[^#{CharacterClasses::RESERVED}]/
79
+ RESERVED_AND_UNRESERVED = /[^#{CharacterClasses::RESERVED_AND_UNRESERVED}]/
80
+ SCHEME = /[^#{CharacterClasses::SCHEME}]/
81
+ UNRESERVED = /[^#{CharacterClasses::UNRESERVED}]/
82
+ end
83
+
71
84
  SLASH = '/'
72
85
  EMPTY_STR = ''
73
86
 
@@ -117,7 +130,7 @@ module Addressable
117
130
  uri = uri.to_str
118
131
  rescue TypeError, NoMethodError
119
132
  raise TypeError, "Can't convert #{uri.class} into String."
120
- end if not uri.is_a? String
133
+ end unless uri.is_a?(String)
121
134
 
122
135
  # This Regexp supplied as an example in RFC 3986, and it works great.
123
136
  scan = uri.scan(URIREGEX)
@@ -138,15 +151,15 @@ module Addressable
138
151
  user = userinfo.strip[/^([^:]*):?/, 1]
139
152
  password = userinfo.strip[/:(.*)$/, 1]
140
153
  end
154
+
141
155
  host = authority.sub(
142
156
  /^([^\[\]]*)@/, EMPTY_STR
143
157
  ).sub(
144
158
  /:([^:@\[\]]*?)$/, EMPTY_STR
145
159
  )
160
+
146
161
  port = authority[/:([^:@\[\]]*?)$/, 1]
147
- end
148
- if port == EMPTY_STR
149
- port = nil
162
+ port = nil if port == EMPTY_STR
150
163
  end
151
164
 
152
165
  return new(
@@ -189,7 +202,7 @@ module Addressable
189
202
  uri = uri.to_s
190
203
  end
191
204
 
192
- if !uri.respond_to?(:to_str)
205
+ unless uri.respond_to?(:to_str)
193
206
  raise TypeError, "Can't convert #{uri.class} into String."
194
207
  end
195
208
  # Otherwise, convert to a String
@@ -281,7 +294,7 @@ module Addressable
281
294
  return nil unless path
282
295
  # If a URI object is passed, just return itself.
283
296
  return path if path.kind_of?(self)
284
- if !path.respond_to?(:to_str)
297
+ unless path.respond_to?(:to_str)
285
298
  raise TypeError, "Can't convert #{path.class} into String."
286
299
  end
287
300
  # Otherwise, convert to a String
@@ -329,13 +342,13 @@ module Addressable
329
342
  # #=> #<Addressable::URI:0xcab390 URI:http://example.com/relative/path>
330
343
  def self.join(*uris)
331
344
  uri_objects = uris.collect do |uri|
332
- if !uri.respond_to?(:to_str)
345
+ unless uri.respond_to?(:to_str)
333
346
  raise TypeError, "Can't convert #{uri.class} into String."
334
347
  end
335
348
  uri.kind_of?(self) ? uri : self.parse(uri.to_str)
336
349
  end
337
350
  result = uri_objects.shift.dup
338
- for uri in uri_objects
351
+ uri_objects.each do |uri|
339
352
  result.join!(uri)
340
353
  end
341
354
  return result
@@ -344,17 +357,13 @@ module Addressable
344
357
  ##
345
358
  # Tables used to optimize encoding operations in `self.encode_component`
346
359
  # and `self.normalize_component`
347
- SEQUENCE_ENCODING_TABLE = Hash.new do |hash, sequence|
348
- hash[sequence] = sequence.unpack("C*").map do |c|
349
- format("%02x", c)
350
- end.join
351
- end
360
+ SEQUENCE_ENCODING_TABLE = (0..255).map do |byte|
361
+ format("%02x", byte).freeze
362
+ end.freeze
352
363
 
353
- SEQUENCE_UPCASED_PERCENT_ENCODING_TABLE = Hash.new do |hash, sequence|
354
- hash[sequence] = sequence.unpack("C*").map do |c|
355
- format("%%%02X", c)
356
- end.join
357
- end
364
+ SEQUENCE_UPCASED_PERCENT_ENCODING_TABLE = (0..255).map do |byte|
365
+ format("%%%02X", byte).freeze
366
+ end.freeze
358
367
 
359
368
  ##
360
369
  # Percent encodes a URI component.
@@ -391,9 +400,7 @@ module Addressable
391
400
  # "simple/example", Addressable::URI::CharacterClasses::UNRESERVED
392
401
  # )
393
402
  # => "simple%2Fexample"
394
- def self.encode_component(component, character_class=
395
- CharacterClasses::RESERVED + CharacterClasses::UNRESERVED,
396
- upcase_encoded='')
403
+ def self.encode_component(component, character_class=CharacterClassesRegexps::RESERVED_AND_UNRESERVED, upcase_encoded='')
397
404
  return nil if component.nil?
398
405
 
399
406
  begin
@@ -421,16 +428,17 @@ module Addressable
421
428
  component = component.dup
422
429
  component.force_encoding(Encoding::ASCII_8BIT)
423
430
  # Avoiding gsub! because there are edge cases with frozen strings
424
- component = component.gsub(character_class) do |sequence|
425
- SEQUENCE_UPCASED_PERCENT_ENCODING_TABLE[sequence]
431
+ component = component.gsub(character_class) do |char|
432
+ SEQUENCE_UPCASED_PERCENT_ENCODING_TABLE[char.ord]
426
433
  end
427
434
  if upcase_encoded.length > 0
428
- upcase_encoded_chars = upcase_encoded.chars.map do |char|
429
- SEQUENCE_ENCODING_TABLE[char]
435
+ upcase_encoded_chars = upcase_encoded.bytes.map do |byte|
436
+ SEQUENCE_ENCODING_TABLE[byte]
430
437
  end
431
438
  component = component.gsub(/%(#{upcase_encoded_chars.join('|')})/,
432
439
  &:upcase)
433
440
  end
441
+
434
442
  return component
435
443
  end
436
444
 
@@ -481,7 +489,7 @@ module Addressable
481
489
  leave_encoded.include?(c) ? sequence : c
482
490
  end
483
491
 
484
- result.force_encoding("utf-8")
492
+ result.force_encoding(Encoding::UTF_8)
485
493
  if return_type == String
486
494
  return result
487
495
  elsif return_type == ::Addressable::URI
@@ -542,7 +550,7 @@ module Addressable
542
550
  # )
543
551
  # => "one two%2Fthree&four"
544
552
  def self.normalize_component(component, character_class=
545
- CharacterClasses::RESERVED + CharacterClasses::UNRESERVED,
553
+ CharacterClassesRegexps::RESERVED_AND_UNRESERVED,
546
554
  leave_encoded='')
547
555
  return nil if component.nil?
548
556
 
@@ -560,10 +568,9 @@ module Addressable
560
568
  leave_re = if leave_encoded.length > 0
561
569
  character_class = "#{character_class}%" unless character_class.include?('%')
562
570
 
563
- "|%(?!#{leave_encoded.chars.flat_map do |char|
564
- seq = SEQUENCE_ENCODING_TABLE[char]
565
- [seq.upcase, seq.downcase]
566
- end.join('|')})"
571
+ bytes = leave_encoded.bytes
572
+ leave_encoded_pattern = bytes.map { |b| SEQUENCE_ENCODING_TABLE[b] }.join('|')
573
+ "|%(?!#{leave_encoded_pattern}|#{leave_encoded_pattern.upcase})"
567
574
  end
568
575
 
569
576
  character_class = if leave_re
@@ -579,7 +586,7 @@ module Addressable
579
586
  unencoded = self.unencode_component(component, String, leave_encoded)
580
587
  begin
581
588
  encoded = self.encode_component(
582
- Addressable::IDNA.unicode_normalize_kc(unencoded),
589
+ unencoded.unicode_normalize(:nfc),
583
590
  character_class,
584
591
  leave_encoded
585
592
  )
@@ -623,15 +630,15 @@ module Addressable
623
630
  uri_object = uri.kind_of?(self) ? uri : self.parse(uri)
624
631
  encoded_uri = Addressable::URI.new(
625
632
  :scheme => self.encode_component(uri_object.scheme,
626
- Addressable::URI::CharacterClasses::SCHEME),
633
+ Addressable::URI::CharacterClassesRegexps::SCHEME),
627
634
  :authority => self.encode_component(uri_object.authority,
628
- Addressable::URI::CharacterClasses::AUTHORITY),
635
+ Addressable::URI::CharacterClassesRegexps::AUTHORITY),
629
636
  :path => self.encode_component(uri_object.path,
630
- Addressable::URI::CharacterClasses::PATH),
637
+ Addressable::URI::CharacterClassesRegexps::PATH),
631
638
  :query => self.encode_component(uri_object.query,
632
- Addressable::URI::CharacterClasses::QUERY),
639
+ Addressable::URI::CharacterClassesRegexps::QUERY),
633
640
  :fragment => self.encode_component(uri_object.fragment,
634
- Addressable::URI::CharacterClasses::FRAGMENT)
641
+ Addressable::URI::CharacterClassesRegexps::FRAGMENT)
635
642
  )
636
643
  if return_type == String
637
644
  return encoded_uri.to_s
@@ -687,8 +694,7 @@ module Addressable
687
694
  components.each do |key, value|
688
695
  if value != nil
689
696
  begin
690
- components[key] =
691
- Addressable::IDNA.unicode_normalize_kc(value.to_str)
697
+ components[key] = value.to_str.unicode_normalize(:nfc)
692
698
  rescue ArgumentError
693
699
  # Likely a malformed UTF-8 character, skip unicode normalization
694
700
  components[key] = value.to_str
@@ -697,19 +703,19 @@ module Addressable
697
703
  end
698
704
  encoded_uri = Addressable::URI.new(
699
705
  :scheme => self.encode_component(components[:scheme],
700
- Addressable::URI::CharacterClasses::SCHEME),
706
+ Addressable::URI::CharacterClassesRegexps::SCHEME),
701
707
  :user => self.encode_component(components[:user],
702
- Addressable::URI::CharacterClasses::UNRESERVED),
708
+ Addressable::URI::CharacterClassesRegexps::UNRESERVED),
703
709
  :password => self.encode_component(components[:password],
704
- Addressable::URI::CharacterClasses::UNRESERVED),
710
+ Addressable::URI::CharacterClassesRegexps::UNRESERVED),
705
711
  :host => components[:host],
706
712
  :port => components[:port],
707
713
  :path => self.encode_component(components[:path],
708
- Addressable::URI::CharacterClasses::PATH),
714
+ Addressable::URI::CharacterClassesRegexps::PATH),
709
715
  :query => self.encode_component(components[:query],
710
- Addressable::URI::CharacterClasses::QUERY),
716
+ Addressable::URI::CharacterClassesRegexps::QUERY),
711
717
  :fragment => self.encode_component(components[:fragment],
712
- Addressable::URI::CharacterClasses::FRAGMENT)
718
+ Addressable::URI::CharacterClassesRegexps::FRAGMENT)
713
719
  )
714
720
  if return_type == String
715
721
  return encoded_uri.to_s
@@ -760,11 +766,11 @@ module Addressable
760
766
  [
761
767
  self.encode_component(
762
768
  key.gsub(/(\r\n|\n|\r)/, "\r\n"),
763
- CharacterClasses::UNRESERVED
769
+ CharacterClassesRegexps::UNRESERVED
764
770
  ).gsub("%20", "+"),
765
771
  self.encode_component(
766
772
  value.gsub(/(\r\n|\n|\r)/, "\r\n"),
767
- CharacterClasses::UNRESERVED
773
+ CharacterClassesRegexps::UNRESERVED
768
774
  ).gsub("%20", "+")
769
775
  ]
770
776
  end
@@ -836,7 +842,9 @@ module Addressable
836
842
  end
837
843
  end
838
844
 
839
- self.defer_validation do
845
+ reset_ivs
846
+
847
+ defer_validation do
840
848
  # Bunch of crazy logic required because of the composite components
841
849
  # like userinfo and authority.
842
850
  self.scheme = options[:scheme] if options[:scheme]
@@ -851,7 +859,8 @@ module Addressable
851
859
  self.query_values = options[:query_values] if options[:query_values]
852
860
  self.fragment = options[:fragment] if options[:fragment]
853
861
  end
854
- self.to_s
862
+
863
+ to_s # force path validation
855
864
  end
856
865
 
857
866
  ##
@@ -878,9 +887,7 @@ module Addressable
878
887
  # The scheme component for this URI.
879
888
  #
880
889
  # @return [String] The scheme component.
881
- def scheme
882
- return defined?(@scheme) ? @scheme : nil
883
- end
890
+ attr_reader :scheme
884
891
 
885
892
  ##
886
893
  # The scheme component for this URI, normalized.
@@ -888,8 +895,8 @@ module Addressable
888
895
  # @return [String] The scheme component, normalized.
889
896
  def normalized_scheme
890
897
  return nil unless self.scheme
891
- @normalized_scheme ||= begin
892
- if self.scheme =~ /^\s*ssh\+svn\s*$/i
898
+ if @normalized_scheme == NONE
899
+ @normalized_scheme = if self.scheme =~ /^\s*ssh\+svn\s*$/i
893
900
  "svn+ssh".dup
894
901
  else
895
902
  Addressable::URI.normalize_component(
@@ -920,7 +927,7 @@ module Addressable
920
927
  @scheme = nil if @scheme.to_s.strip.empty?
921
928
 
922
929
  # Reset dependent values
923
- remove_instance_variable(:@normalized_scheme) if defined?(@normalized_scheme)
930
+ @normalized_scheme = NONE
924
931
  remove_composite_values
925
932
 
926
933
  # Ensure we haven't created an invalid URI
@@ -931,9 +938,7 @@ module Addressable
931
938
  # The user component for this URI.
932
939
  #
933
940
  # @return [String] The user component.
934
- def user
935
- return defined?(@user) ? @user : nil
936
- end
941
+ attr_reader :user
937
942
 
938
943
  ##
939
944
  # The user component for this URI, normalized.
@@ -941,8 +946,8 @@ module Addressable
941
946
  # @return [String] The user component, normalized.
942
947
  def normalized_user
943
948
  return nil unless self.user
944
- return @normalized_user if defined?(@normalized_user)
945
- @normalized_user ||= begin
949
+ return @normalized_user unless @normalized_user == NONE
950
+ @normalized_user = begin
946
951
  if normalized_scheme =~ /https?/ && self.user.strip.empty? &&
947
952
  (!self.password || self.password.strip.empty?)
948
953
  nil
@@ -970,14 +975,14 @@ module Addressable
970
975
 
971
976
  # You can't have a nil user with a non-nil password
972
977
  if password != nil
973
- @user = EMPTY_STR if @user.nil?
978
+ @user = EMPTY_STR unless user
974
979
  end
975
980
 
976
981
  # Reset dependent values
977
- remove_instance_variable(:@userinfo) if defined?(@userinfo)
978
- remove_instance_variable(:@normalized_userinfo) if defined?(@normalized_userinfo)
979
- remove_instance_variable(:@authority) if defined?(@authority)
980
- remove_instance_variable(:@normalized_user) if defined?(@normalized_user)
982
+ @userinfo = nil
983
+ @normalized_userinfo = NONE
984
+ @authority = nil
985
+ @normalized_user = NONE
981
986
  remove_composite_values
982
987
 
983
988
  # Ensure we haven't created an invalid URI
@@ -988,9 +993,7 @@ module Addressable
988
993
  # The password component for this URI.
989
994
  #
990
995
  # @return [String] The password component.
991
- def password
992
- return defined?(@password) ? @password : nil
993
- end
996
+ attr_reader :password
994
997
 
995
998
  ##
996
999
  # The password component for this URI, normalized.
@@ -998,8 +1001,8 @@ module Addressable
998
1001
  # @return [String] The password component, normalized.
999
1002
  def normalized_password
1000
1003
  return nil unless self.password
1001
- return @normalized_password if defined?(@normalized_password)
1002
- @normalized_password ||= begin
1004
+ return @normalized_password unless @normalized_password == NONE
1005
+ @normalized_password = begin
1003
1006
  if self.normalized_scheme =~ /https?/ && self.password.strip.empty? &&
1004
1007
  (!self.user || self.user.strip.empty?)
1005
1008
  nil
@@ -1026,17 +1029,15 @@ module Addressable
1026
1029
  @password = new_password ? new_password.to_str : nil
1027
1030
 
1028
1031
  # You can't have a nil user with a non-nil password
1029
- @password ||= nil
1030
- @user ||= nil
1031
1032
  if @password != nil
1032
- @user = EMPTY_STR if @user.nil?
1033
+ self.user = EMPTY_STR if user.nil?
1033
1034
  end
1034
1035
 
1035
1036
  # Reset dependent values
1036
- remove_instance_variable(:@userinfo) if defined?(@userinfo)
1037
- remove_instance_variable(:@normalized_userinfo) if defined?(@normalized_userinfo)
1038
- remove_instance_variable(:@authority) if defined?(@authority)
1039
- remove_instance_variable(:@normalized_password) if defined?(@normalized_password)
1037
+ @userinfo = nil
1038
+ @normalized_userinfo = NONE
1039
+ @authority = nil
1040
+ @normalized_password = NONE
1040
1041
  remove_composite_values
1041
1042
 
1042
1043
  # Ensure we haven't created an invalid URI
@@ -1066,8 +1067,8 @@ module Addressable
1066
1067
  # @return [String] The userinfo component, normalized.
1067
1068
  def normalized_userinfo
1068
1069
  return nil unless self.userinfo
1069
- return @normalized_userinfo if defined?(@normalized_userinfo)
1070
- @normalized_userinfo ||= begin
1070
+ return @normalized_userinfo unless @normalized_userinfo == NONE
1071
+ @normalized_userinfo = begin
1071
1072
  current_user = self.normalized_user
1072
1073
  current_password = self.normalized_password
1073
1074
  if !current_user && !current_password
@@ -1105,7 +1106,7 @@ module Addressable
1105
1106
  self.user = new_user
1106
1107
 
1107
1108
  # Reset dependent values
1108
- remove_instance_variable(:@authority) if defined?(@authority)
1109
+ @authority = nil
1109
1110
  remove_composite_values
1110
1111
 
1111
1112
  # Ensure we haven't created an invalid URI
@@ -1116,9 +1117,7 @@ module Addressable
1116
1117
  # The host component for this URI.
1117
1118
  #
1118
1119
  # @return [String] The host component.
1119
- def host
1120
- return defined?(@host) ? @host : nil
1121
- end
1120
+ attr_reader :host
1122
1121
 
1123
1122
  ##
1124
1123
  # The host component for this URI, normalized.
@@ -1161,8 +1160,8 @@ module Addressable
1161
1160
  @host = new_host ? new_host.to_str : nil
1162
1161
 
1163
1162
  # Reset dependent values
1164
- remove_instance_variable(:@authority) if defined?(@authority)
1165
- remove_instance_variable(:@normalized_host) if defined?(@normalized_host)
1163
+ @authority = nil
1164
+ @normalized_host = nil
1166
1165
  remove_composite_values
1167
1166
 
1168
1167
  # Ensure we haven't created an invalid URI
@@ -1293,14 +1292,14 @@ module Addressable
1293
1292
  end
1294
1293
 
1295
1294
  # Password assigned first to ensure validity in case of nil
1296
- self.password = defined?(new_password) ? new_password : nil
1297
- self.user = defined?(new_user) ? new_user : nil
1298
- self.host = defined?(new_host) ? new_host : nil
1299
- self.port = defined?(new_port) ? new_port : nil
1295
+ self.password = new_password
1296
+ self.user = new_user
1297
+ self.host = new_host
1298
+ self.port = new_port
1300
1299
 
1301
1300
  # Reset dependent values
1302
- remove_instance_variable(:@userinfo) if defined?(@userinfo)
1303
- remove_instance_variable(:@normalized_userinfo) if defined?(@normalized_userinfo)
1301
+ @userinfo = nil
1302
+ @normalized_userinfo = NONE
1304
1303
  remove_composite_values
1305
1304
 
1306
1305
  # Ensure we haven't created an invalid URI
@@ -1348,16 +1347,16 @@ module Addressable
1348
1347
  new_port = new_origin[/:([^:@\[\]\/]*?)$/, 1]
1349
1348
  end
1350
1349
 
1351
- self.scheme = defined?(new_scheme) ? new_scheme : nil
1352
- self.host = defined?(new_host) ? new_host : nil
1353
- self.port = defined?(new_port) ? new_port : nil
1350
+ self.scheme = new_scheme
1351
+ self.host = new_host
1352
+ self.port = new_port
1354
1353
  self.userinfo = nil
1355
1354
 
1356
1355
  # Reset dependent values
1357
- remove_instance_variable(:@userinfo) if defined?(@userinfo)
1358
- remove_instance_variable(:@normalized_userinfo) if defined?(@normalized_userinfo)
1359
- remove_instance_variable(:@authority) if defined?(@authority)
1360
- remove_instance_variable(:@normalized_authority) if defined?(@normalized_authority)
1356
+ @userinfo = nil
1357
+ @normalized_userinfo = NONE
1358
+ @authority = nil
1359
+ @normalized_authority = nil
1361
1360
  remove_composite_values
1362
1361
 
1363
1362
  # Ensure we haven't created an invalid URI
@@ -1384,9 +1383,7 @@ module Addressable
1384
1383
  # infer port numbers from default values.
1385
1384
  #
1386
1385
  # @return [Integer] The port component.
1387
- def port
1388
- return defined?(@port) ? @port : nil
1389
- end
1386
+ attr_reader :port
1390
1387
 
1391
1388
  ##
1392
1389
  # The port component for this URI, normalized.
@@ -1394,8 +1391,8 @@ module Addressable
1394
1391
  # @return [Integer] The port component, normalized.
1395
1392
  def normalized_port
1396
1393
  return nil unless self.port
1397
- return @normalized_port if defined?(@normalized_port)
1398
- @normalized_port ||= begin
1394
+ return @normalized_port unless @normalized_port == NONE
1395
+ @normalized_port = begin
1399
1396
  if URI.port_mapping[self.normalized_scheme] == self.port
1400
1397
  nil
1401
1398
  else
@@ -1426,8 +1423,8 @@ module Addressable
1426
1423
  @port = nil if @port == 0
1427
1424
 
1428
1425
  # Reset dependent values
1429
- remove_instance_variable(:@authority) if defined?(@authority)
1430
- remove_instance_variable(:@normalized_port) if defined?(@normalized_port)
1426
+ @authority = nil
1427
+ @normalized_port = NONE
1431
1428
  remove_composite_values
1432
1429
 
1433
1430
  # Ensure we haven't created an invalid URI
@@ -1528,9 +1525,7 @@ module Addressable
1528
1525
  # The path component for this URI.
1529
1526
  #
1530
1527
  # @return [String] The path component.
1531
- def path
1532
- return defined?(@path) ? @path : EMPTY_STR
1533
- end
1528
+ attr_reader :path
1534
1529
 
1535
1530
  NORMPATH = /^(?!\/)[^\/:]*:.*$/
1536
1531
  ##
@@ -1544,7 +1539,7 @@ module Addressable
1544
1539
  # Relative paths with colons in the first segment are ambiguous.
1545
1540
  path = path.sub(":", "%2F")
1546
1541
  end
1547
- # String#split(delimeter, -1) uses the more strict splitting behavior
1542
+ # String#split(delimiter, -1) uses the more strict splitting behavior
1548
1543
  # found by default in Python.
1549
1544
  result = path.strip.split(SLASH, -1).map do |segment|
1550
1545
  Addressable::URI.normalize_component(
@@ -1579,7 +1574,7 @@ module Addressable
1579
1574
  end
1580
1575
 
1581
1576
  # Reset dependent values
1582
- remove_instance_variable(:@normalized_path) if defined?(@normalized_path)
1577
+ @normalized_path = nil
1583
1578
  remove_composite_values
1584
1579
 
1585
1580
  # Ensure we haven't created an invalid URI
@@ -1609,9 +1604,7 @@ module Addressable
1609
1604
  # The query component for this URI.
1610
1605
  #
1611
1606
  # @return [String] The query component.
1612
- def query
1613
- return defined?(@query) ? @query : nil
1614
- end
1607
+ attr_reader :query
1615
1608
 
1616
1609
  ##
1617
1610
  # The query component for this URI, normalized.
@@ -1619,8 +1612,8 @@ module Addressable
1619
1612
  # @return [String] The query component, normalized.
1620
1613
  def normalized_query(*flags)
1621
1614
  return nil unless self.query
1622
- return @normalized_query if defined?(@normalized_query)
1623
- @normalized_query ||= begin
1615
+ return @normalized_query unless @normalized_query == NONE
1616
+ @normalized_query = begin
1624
1617
  modified_query_class = Addressable::URI::CharacterClasses::QUERY.dup
1625
1618
  # Make sure possible key-value pair delimiters are escaped.
1626
1619
  modified_query_class.sub!("\\&", "").sub!("\\;", "")
@@ -1652,7 +1645,7 @@ module Addressable
1652
1645
  @query = new_query ? new_query.to_str : nil
1653
1646
 
1654
1647
  # Reset dependent values
1655
- remove_instance_variable(:@normalized_query) if defined?(@normalized_query)
1648
+ @normalized_query = NONE
1656
1649
  remove_composite_values
1657
1650
  end
1658
1651
 
@@ -1752,20 +1745,20 @@ module Addressable
1752
1745
  buffer = "".dup
1753
1746
  new_query_values.each do |key, value|
1754
1747
  encoded_key = URI.encode_component(
1755
- key, CharacterClasses::UNRESERVED
1748
+ key, CharacterClassesRegexps::UNRESERVED
1756
1749
  )
1757
1750
  if value == nil
1758
1751
  buffer << "#{encoded_key}&"
1759
1752
  elsif value.kind_of?(Array)
1760
1753
  value.each do |sub_value|
1761
1754
  encoded_value = URI.encode_component(
1762
- sub_value, CharacterClasses::UNRESERVED
1755
+ sub_value, CharacterClassesRegexps::UNRESERVED
1763
1756
  )
1764
1757
  buffer << "#{encoded_key}=#{encoded_value}&"
1765
1758
  end
1766
1759
  else
1767
1760
  encoded_value = URI.encode_component(
1768
- value, CharacterClasses::UNRESERVED
1761
+ value, CharacterClassesRegexps::UNRESERVED
1769
1762
  )
1770
1763
  buffer << "#{encoded_key}=#{encoded_value}&"
1771
1764
  end
@@ -1814,9 +1807,7 @@ module Addressable
1814
1807
  # The fragment component for this URI.
1815
1808
  #
1816
1809
  # @return [String] The fragment component.
1817
- def fragment
1818
- return defined?(@fragment) ? @fragment : nil
1819
- end
1810
+ attr_reader :fragment
1820
1811
 
1821
1812
  ##
1822
1813
  # The fragment component for this URI, normalized.
@@ -1824,8 +1815,8 @@ module Addressable
1824
1815
  # @return [String] The fragment component, normalized.
1825
1816
  def normalized_fragment
1826
1817
  return nil unless self.fragment
1827
- return @normalized_fragment if defined?(@normalized_fragment)
1828
- @normalized_fragment ||= begin
1818
+ return @normalized_fragment unless @normalized_fragment == NONE
1819
+ @normalized_fragment = begin
1829
1820
  component = Addressable::URI.normalize_component(
1830
1821
  self.fragment,
1831
1822
  Addressable::URI::NormalizeCharacterClasses::FRAGMENT
@@ -1848,7 +1839,7 @@ module Addressable
1848
1839
  @fragment = new_fragment ? new_fragment.to_str : nil
1849
1840
 
1850
1841
  # Reset dependent values
1851
- remove_instance_variable(:@normalized_fragment) if defined?(@normalized_fragment)
1842
+ @normalized_fragment = NONE
1852
1843
  remove_composite_values
1853
1844
 
1854
1845
  # Ensure we haven't created an invalid URI
@@ -2014,7 +2005,7 @@ module Addressable
2014
2005
  #
2015
2006
  # @see Hash#merge
2016
2007
  def merge(hash)
2017
- if !hash.respond_to?(:to_hash)
2008
+ unless hash.respond_to?(:to_hash)
2018
2009
  raise TypeError, "Can't convert #{hash.class} into Hash."
2019
2010
  end
2020
2011
  hash = hash.to_hash
@@ -2408,7 +2399,27 @@ module Addressable
2408
2399
  yield
2409
2400
  @validation_deferred = false
2410
2401
  validate
2411
- return nil
2402
+ ensure
2403
+ @validation_deferred = false
2404
+ end
2405
+
2406
+ def encode_with(coder)
2407
+ instance_variables.each do |ivar|
2408
+ value = instance_variable_get(ivar)
2409
+ if value != NONE
2410
+ key = ivar.to_s.slice(1..-1)
2411
+ coder[key] = value
2412
+ end
2413
+ end
2414
+ nil
2415
+ end
2416
+
2417
+ def init_with(coder)
2418
+ reset_ivs
2419
+ coder.map.each do |key, value|
2420
+ instance_variable_set("@#{key}", value)
2421
+ end
2422
+ nil
2412
2423
  end
2413
2424
 
2414
2425
  protected
@@ -2507,11 +2518,7 @@ module Addressable
2507
2518
  # @return [Addressable::URI] <code>self</code>.
2508
2519
  def replace_self(uri)
2509
2520
  # Reset dependent values
2510
- instance_variables.each do |var|
2511
- if instance_variable_defined?(var) && var != :@validation_deferred
2512
- remove_instance_variable(var)
2513
- end
2514
- end
2521
+ reset_ivs
2515
2522
 
2516
2523
  @scheme = uri.scheme
2517
2524
  @user = uri.user
@@ -2543,8 +2550,8 @@ module Addressable
2543
2550
  #
2544
2551
  # @api private
2545
2552
  def remove_composite_values
2546
- remove_instance_variable(:@uri_string) if defined?(@uri_string)
2547
- remove_instance_variable(:@hash) if defined?(@hash)
2553
+ @uri_string = nil
2554
+ @hash = nil
2548
2555
  end
2549
2556
 
2550
2557
  ##
@@ -2556,5 +2563,40 @@ module Addressable
2556
2563
  str.force_encoding(Encoding::UTF_8)
2557
2564
  end
2558
2565
  end
2566
+
2567
+ private
2568
+
2569
+ ##
2570
+ # Resets instance variables
2571
+ #
2572
+ # @api private
2573
+ def reset_ivs
2574
+ @scheme = nil
2575
+ @user = nil
2576
+ @normalized_scheme = NONE
2577
+ @normalized_user = NONE
2578
+ @uri_string = nil
2579
+ @hash = nil
2580
+ @userinfo = nil
2581
+ @normalized_userinfo = NONE
2582
+ @authority = nil
2583
+ @password = nil
2584
+ @normalized_authority = nil
2585
+ @port = nil
2586
+ @normalized_password = NONE
2587
+ @host = nil
2588
+ @normalized_host = nil
2589
+ @normalized_port = NONE
2590
+ @path = EMPTY_STR
2591
+ @normalized_path = nil
2592
+ @normalized_query = NONE
2593
+ @fragment = nil
2594
+ @normalized_fragment = NONE
2595
+ @query = nil
2596
+ end
2597
+
2598
+ NONE = Module.new.freeze
2599
+
2600
+ private_constant :NONE
2559
2601
  end
2560
2602
  end