honkster-addressable 2.1.2 → 2.2.3

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,86 +1,109 @@
1
+ === Addressable 2.2.5
2
+ - 'parsing' a pre-parsed URI object is now a dup operation
3
+
4
+ === Addressable 2.2.4
5
+ - added origin support from draft-ietf-websec-origin-00
6
+ - resolved issue with attempting to navigate below root
7
+ - fixed bug with string splitting in query strings
8
+
9
+ === Addressable 2.2.3
10
+ - added :flat_array notation for query strings
11
+
12
+ === Addressable 2.2.2
13
+ - fixed issue with percent escaping of '+' character in query strings
14
+
15
+ === Addressable 2.2.1
16
+ - added support for application/x-www-form-urlencoded.
17
+
18
+ === Addressable 2.2.0
19
+ - added site methods
20
+ - improved documentation
21
+
1
22
  === 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
23
+ - added HTTP request URI methods
24
+ - better handling of Windows file paths
25
+ - validation_deferred boolean replaced with defer_validation block
26
+ - normalization of percent-encoded paths should now be correct
27
+ - fixed issue with constructing URIs with relative paths
28
+ - fixed warnings
6
29
 
7
30
  === Addressable 2.1.1
8
- * more type checking changes
9
- * fixed issue with unicode normalization
10
- * added method to find template defaults
11
- * symbolic keys are now allowed in template mappings
12
- * numeric values and symbolic values are now allowed in template mappings
31
+ - more type checking changes
32
+ - fixed issue with unicode normalization
33
+ - added method to find template defaults
34
+ - symbolic keys are now allowed in template mappings
35
+ - numeric values and symbolic values are now allowed in template mappings
13
36
 
14
37
  === Addressable 2.1.0
15
- * refactored URI template support out into its own class
16
- * removed extract method due to being useless and unreliable
17
- * removed Addressable::URI.expand_template
18
- * removed Addressable::URI#extract_mapping
19
- * added partial template expansion
20
- * fixed minor bugs in the parse and heuristic_parse methods
21
- * fixed incompatibility with Ruby 1.9.1
22
- * fixed bottleneck in Addressable::URI#hash and Addressable::URI#to_s
23
- * fixed unicode normalization exception
24
- * updated query_values methods to better handle subscript notation
25
- * worked around issue with freezing URIs
26
- * improved specs
38
+ - refactored URI template support out into its own class
39
+ - removed extract method due to being useless and unreliable
40
+ - removed Addressable::URI.expand_template
41
+ - removed Addressable::URI#extract_mapping
42
+ - added partial template expansion
43
+ - fixed minor bugs in the parse and heuristic_parse methods
44
+ - fixed incompatibility with Ruby 1.9.1
45
+ - fixed bottleneck in Addressable::URI#hash and Addressable::URI#to_s
46
+ - fixed unicode normalization exception
47
+ - updated query_values methods to better handle subscript notation
48
+ - worked around issue with freezing URIs
49
+ - improved specs
27
50
 
28
51
  === Addressable 2.0.2
29
- * fixed issue with URI template expansion
30
- * fixed issue with percent escaping characters 0-15
52
+ - fixed issue with URI template expansion
53
+ - fixed issue with percent escaping characters 0-15
31
54
 
32
55
  === Addressable 2.0.1
33
- * fixed issue with query string assignment
34
- * fixed issue with improperly encoded components
56
+ - fixed issue with query string assignment
57
+ - fixed issue with improperly encoded components
35
58
 
36
59
  === Addressable 2.0.0
37
- * the initialize method now takes an options hash as its only parameter
38
- * added query_values method to URI class
39
- * completely replaced IDNA implementation with pure Ruby
40
- * renamed Addressable::ADDRESSABLE_VERSION to Addressable::VERSION
41
- * completely reworked the Rakefile
42
- * changed the behavior of the port method significantly
43
- * Addressable::URI.encode_segment, Addressable::URI.unencode_segment renamed
44
- * documentation is now in YARD format
45
- * more rigorous type checking
46
- * to_str method implemented, implicit conversion to Strings now allowed
47
- * Addressable::URI#omit method added, Addressable::URI#merge method replaced
48
- * updated URI Template code to match v 03 of the draft spec
49
- * added a bunch of new specifications
60
+ - the initialize method now takes an options hash as its only parameter
61
+ - added query_values method to URI class
62
+ - completely replaced IDNA implementation with pure Ruby
63
+ - renamed Addressable::ADDRESSABLE_VERSION to Addressable::VERSION
64
+ - completely reworked the Rakefile
65
+ - changed the behavior of the port method significantly
66
+ - Addressable::URI.encode_segment, Addressable::URI.unencode_segment renamed
67
+ - documentation is now in YARD format
68
+ - more rigorous type checking
69
+ - to_str method implemented, implicit conversion to Strings now allowed
70
+ - Addressable::URI#omit method added, Addressable::URI#merge method replaced
71
+ - updated URI Template code to match v 03 of the draft spec
72
+ - added a bunch of new specifications
50
73
 
51
74
  === Addressable 1.0.4
52
- * switched to using RSpec's pending system for specs that rely on IDN
53
- * fixed issue with creating URIs with paths that are not prefixed with '/'
75
+ - switched to using RSpec's pending system for specs that rely on IDN
76
+ - fixed issue with creating URIs with paths that are not prefixed with '/'
54
77
 
55
78
  === Addressable 1.0.3
56
- * implemented a hash method
79
+ - implemented a hash method
57
80
 
58
81
  === Addressable 1.0.2
59
- * fixed minor bug with the extract_mapping method
82
+ - fixed minor bug with the extract_mapping method
60
83
 
61
84
  === Addressable 1.0.1
62
- * fixed minor bug with the extract_mapping method
85
+ - fixed minor bug with the extract_mapping method
63
86
 
64
87
  === Addressable 1.0.0
65
- * heuristic parse method added
66
- * parsing is slightly more strict
67
- * replaced to_h with to_hash
68
- * fixed routing methods
69
- * improved specifications
70
- * improved heckle rake task
71
- * no surviving heckle mutations
88
+ - heuristic parse method added
89
+ - parsing is slightly more strict
90
+ - replaced to_h with to_hash
91
+ - fixed routing methods
92
+ - improved specifications
93
+ - improved heckle rake task
94
+ - no surviving heckle mutations
72
95
 
73
96
  === Addressable 0.1.2
74
- * improved normalization
75
- * fixed bug in joining algorithm
76
- * updated specifications
97
+ - improved normalization
98
+ - fixed bug in joining algorithm
99
+ - updated specifications
77
100
 
78
101
  === Addressable 0.1.1
79
- * updated documentation
80
- * added URI Template variable extraction
102
+ - updated documentation
103
+ - added URI Template variable extraction
81
104
 
82
105
  === Addressable 0.1.0
83
- * initial release
84
- * implementation based on RFC 3986, 3987
85
- * support for IRIs via libidn
86
- * support for the URI Template draft spec
106
+ - initial release
107
+ - implementation based on RFC 3986, 3987
108
+ - support for IRIs via libidn
109
+ - support for the URI Template draft spec
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Addressable, Copyright (c) 2006-2008 Bob Aman
1
+ Addressable, Copyright (c) 2006-2010 Bob Aman
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README CHANGED
@@ -1,10 +1,20 @@
1
+ == About
2
+
3
+ Homepage:: Addressable[http://addressable.rubyforge.org/]
4
+ Authors:: Bob Aman (mailto:bob@sporkmonger.com)
5
+ Copyright:: Copyright 2010 Bob Aman
6
+ License:: MIT
7
+
1
8
  Addressable is a replacement for the URI implementation that is part of
2
9
  Ruby's standard library. It more closely conforms to the relevant RFCs and
3
10
  adds support for IRIs and URI templates. Additionally, it provides extensive
4
11
  support for URI templates.
5
12
 
6
- Example usage:
7
-
13
+ == Classes
14
+ - {Addressable::URI}
15
+ - {Addressable::Template}
16
+
17
+ == Example usage
8
18
  require "addressable/uri"
9
19
 
10
20
  uri = Addressable::URI.parse("http://example.com/path/to/resource/")
data/Rakefile CHANGED
@@ -27,38 +27,6 @@ Ruby's standard library. It more closely conforms to the relevant RFCs and
27
27
  adds support for IRIs and URI templates.
28
28
  TEXT
29
29
 
30
- desc "generates .gemspec file"
31
- task :gemspec do
32
- spec = Gem::Specification.new do |p|
33
- p.name = ENV["GEM_PREFIX"] ? "#{ENV["GEM_PREFIX"]}-addressable" : 'addressable'
34
- p.version = PKG_VERSION
35
-
36
- p.summary = PKG_SUMMARY
37
- p.description = PKG_DESCRIPTION
38
-
39
- p.author = 'Bob Aman'
40
- p.email = 'bob@sporkmonger.com'
41
- p.homepage = 'http://github.com/mislav/addressable'
42
- p.rubyforge_project = nil
43
-
44
- p.files = FileList['Rakefile', '{bin,lib,tasks,spec}/**/*', 'README*', 'LICENSE*', 'CHANGELOG*'] & `git ls-files`.split
45
-
46
- p.executables = Dir['bin/*'].map { |f| File.basename(f) }
47
-
48
- p.has_rdoc = true
49
- end
50
-
51
- spec_string = spec.to_ruby
52
-
53
- begin
54
- Thread.new { eval("$SAFE = 3\n#{spec_string}", binding) }.join
55
- rescue
56
- abort "unsafe gemspec: #{$!}"
57
- else
58
- File.open("#{spec.name}.gemspec", 'w') { |file| file.write spec_string }
59
- end
60
- end
61
-
62
30
  PKG_FILES = FileList[
63
31
  "lib/**/*", "spec/**/*", "vendor/**/*",
64
32
  "tasks/**/*", "website/**/*",
@@ -1,6 +1,6 @@
1
1
  # encoding:utf-8
2
2
  #--
3
- # Addressable, Copyright (c) 2006-2008 Bob Aman
3
+ # Addressable, Copyright (c) 2006-2010 Bob Aman
4
4
  #
5
5
  # Permission is hereby granted, free of charge, to any person obtaining
6
6
  # a copy of this software and associated documentation files (the
@@ -1,6 +1,6 @@
1
1
  # encoding:utf-8
2
2
  #--
3
- # Addressable, Copyright (c) 2006-2008 Bob Aman
3
+ # Addressable, Copyright (c) 2006-2010 Bob Aman
4
4
  #
5
5
  # Permission is hereby granted, free of charge, to any person obtaining
6
6
  # a copy of this software and associated documentation files (the
@@ -59,15 +59,15 @@ module Addressable
59
59
  #
60
60
  # @param [String, Addressable::URI, #to_str] uri
61
61
  # The URI string to parse.
62
- # No parsing is performed if the object is already an
63
- # <tt>Addressable::URI</tt>.
62
+ # No parsing is performed if the object is already an
63
+ # <code>Addressable::URI</code>.
64
64
  #
65
65
  # @return [Addressable::URI] The parsed URI.
66
66
  def self.parse(uri)
67
67
  # If we were given nil, return nil.
68
68
  return nil unless uri
69
69
  # If a URI object is passed, just return itself.
70
- return uri if uri.kind_of?(self)
70
+ return uri.dup if uri.kind_of?(self)
71
71
 
72
72
  # If a URI object of the Ruby standard library variety is passed,
73
73
  # convert it to a string, then parse the string.
@@ -130,18 +130,18 @@ module Addressable
130
130
  #
131
131
  # @param [String, Addressable::URI, #to_str] uri
132
132
  # The URI string to parse.
133
- # No parsing is performed if the object is already an
134
- # <tt>Addressable::URI</tt>.
133
+ # No parsing is performed if the object is already an
134
+ # <code>Addressable::URI</code>.
135
135
  # @param [Hash] hints
136
- # A <tt>Hash</tt> of hints to the heuristic parser.
137
- # Defaults to <tt>{:scheme => "http"}</tt>.
136
+ # A <code>Hash</code> of hints to the heuristic parser.
137
+ # Defaults to <code>{:scheme => "http"}</code>.
138
138
  #
139
139
  # @return [Addressable::URI] The parsed URI.
140
140
  def self.heuristic_parse(uri, hints={})
141
141
  # If we were given nil, return nil.
142
142
  return nil unless uri
143
143
  # If a URI object is passed, just return itself.
144
- return uri if uri.kind_of?(self)
144
+ return uri.dup if uri.kind_of?(self)
145
145
  if !uri.respond_to?(:to_str)
146
146
  raise TypeError, "Can't convert #{uri.class} into String."
147
147
  end
@@ -167,11 +167,13 @@ module Addressable
167
167
  if parsed.path.include?(".")
168
168
  new_host = parsed.path[/^([^\/]+\.[^\/]*)/, 1]
169
169
  if new_host
170
- new_path = parsed.path.gsub(
171
- Regexp.new("^" + Regexp.escape(new_host)), "")
172
- parsed.host = new_host
173
- parsed.path = new_path
174
- 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
175
177
  end
176
178
  end
177
179
  return parsed
@@ -181,13 +183,13 @@ module Addressable
181
183
  # Converts a path to a file scheme URI. If the path supplied is
182
184
  # relative, it will be returned as a relative URI. If the path supplied
183
185
  # is actually a non-file URI, it will parse the URI as if it had been
184
- # parsed with <tt>Addressable::URI.parse</tt>. Handles all of the
186
+ # parsed with <code>Addressable::URI.parse</code>. Handles all of the
185
187
  # various Microsoft-specific formats for specifying paths.
186
188
  #
187
189
  # @param [String, Addressable::URI, #to_str] path
188
- #
189
- # Typically a <tt>String</tt> path to a file or directory, but will return
190
- # a sensible return value if an absolute URI is supplied instead.
190
+ # Typically a <code>String</code> path to a file or directory, but
191
+ # will return a sensible return value if an absolute URI is supplied
192
+ # instead.
191
193
  #
192
194
  # @return [Addressable::URI]
193
195
  # The parsed file scheme URI or the original URI if some other URI
@@ -277,17 +279,17 @@ module Addressable
277
279
  # @param [String, #to_str] component The URI component to encode.
278
280
  #
279
281
  # @param [String, Regexp] character_class
280
- #
281
- # The characters which are not percent encoded. If a <tt>String</tt> is
282
- # passed, the <tt>String</tt> must be formatted as a regular expression
283
- # character class. (Do not include the surrounding square brackets.) For
284
- # example, <tt>"b-zB-Z0-9"</tt> would cause everything but the letters 'b'
285
- # through 'z' and the numbers '0' through '9' to be percent encoded. If a
286
- # <tt>Regexp</tt> is passed, the value <tt>/[^b-zB-Z0-9]/</tt> would have
287
- # the same effect. A set of useful <tt>String</tt> values may be found in
288
- # the <tt>Addressable::URI::CharacterClasses</tt> module. The default
289
- # value is the reserved plus unreserved character classes specified in <a
290
- # href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>.
282
+ # The characters which are not percent encoded. If a <code>String</code>
283
+ # is passed, the <code>String</code> must be formatted as a regular
284
+ # expression character class. (Do not include the surrounding square
285
+ # brackets.) For example, <code>"b-zB-Z0-9"</code> would cause
286
+ # everything but the letters 'b' through 'z' and the numbers '0' through
287
+ # '9' to be percent encoded. If a <code>Regexp</code> is passed, the
288
+ # value <code>/[^b-zB-Z0-9]/</code> would have the same effect. A set of
289
+ # useful <code>String</code> values may be found in the
290
+ # <code>Addressable::URI::CharacterClasses</code> module. The default
291
+ # value is the reserved plus unreserved character classes specified in
292
+ # <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>.
291
293
  #
292
294
  # @return [String] The encoded component.
293
295
  #
@@ -332,21 +334,21 @@ module Addressable
332
334
  ##
333
335
  # Unencodes any percent encoded characters within a URI component.
334
336
  # This method may be used for unencoding either components or full URIs,
335
- # however, it is recommended to use the <tt>unencode_component</tt> alias
336
- # when unencoding components.
337
+ # however, it is recommended to use the <code>unencode_component</code>
338
+ # alias when unencoding components.
337
339
  #
338
340
  # @param [String, Addressable::URI, #to_str] uri
339
341
  # The URI or component to unencode.
340
342
  #
341
343
  # @param [Class] returning
342
344
  # The type of object to return.
343
- # This value may only be set to <tt>String</tt> or
344
- # <tt>Addressable::URI</tt>. All other values are invalid. Defaults to
345
- # <tt>String</tt>.
345
+ # This value may only be set to <code>String</code> or
346
+ # <code>Addressable::URI</code>. All other values are invalid. Defaults
347
+ # to <code>String</code>.
346
348
  #
347
349
  # @return [String, Addressable::URI]
348
350
  # The unencoded component or URI.
349
- # The return type is determined by the <tt>returning</tt> parameter.
351
+ # The return type is determined by the <code>returning</code> parameter.
350
352
  def self.unencode(uri, returning=String)
351
353
  return nil if uri.nil?
352
354
  if !uri.respond_to?(:to_str)
@@ -381,17 +383,17 @@ module Addressable
381
383
  # @param [String, #to_str] component The URI component to encode.
382
384
  #
383
385
  # @param [String, Regexp] character_class
384
- #
385
- # The characters which are not percent encoded. If a <tt>String</tt> is
386
- # passed, the <tt>String</tt> must be formatted as a regular expression
387
- # character class. (Do not include the surrounding square brackets.) For
388
- # example, <tt>"b-zB-Z0-9"</tt> would cause everything but the letters 'b'
389
- # through 'z' and the numbers '0' through '9' to be percent encoded. If a
390
- # <tt>Regexp</tt> is passed, the value <tt>/[^b-zB-Z0-9]/</tt> would have
391
- # the same effect. A set of useful <tt>String</tt> values may be found in
392
- # the <tt>Addressable::URI::CharacterClasses</tt> module. The default
393
- # value is the reserved plus unreserved character classes specified in <a
394
- # href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>.
386
+ # The characters which are not percent encoded. If a <code>String</code>
387
+ # is passed, the <code>String</code> must be formatted as a regular
388
+ # expression character class. (Do not include the surrounding square
389
+ # brackets.) For example, <code>"b-zB-Z0-9"</code> would cause
390
+ # everything but the letters 'b' through 'z' and the numbers '0' through
391
+ # '9' to be percent encoded. If a <code>Regexp</code> is passed, the
392
+ # value <code>/[^b-zB-Z0-9]/</code> would have the same effect. A set of
393
+ # useful <code>String</code> values may be found in the
394
+ # <code>Addressable::URI::CharacterClasses</code> module. The default
395
+ # value is the reserved plus unreserved character classes specified in
396
+ # <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>.
395
397
  #
396
398
  # @return [String] The normalized component.
397
399
  #
@@ -447,13 +449,13 @@ module Addressable
447
449
  #
448
450
  # @param [Class] returning
449
451
  # The type of object to return.
450
- # This value may only be set to <tt>String</tt> or
451
- # <tt>Addressable::URI</tt>. All other values are invalid. Defaults to
452
- # <tt>String</tt>.
452
+ # This value may only be set to <code>String</code> or
453
+ # <code>Addressable::URI</code>. All other values are invalid. Defaults
454
+ # to <code>String</code>.
453
455
  #
454
456
  # @return [String, Addressable::URI]
455
457
  # The encoded URI.
456
- # The return type is determined by the <tt>returning</tt> parameter.
458
+ # The return type is determined by the <code>returning</code> parameter.
457
459
  def self.encode(uri, returning=String)
458
460
  return nil if uri.nil?
459
461
  if !uri.respond_to?(:to_str)
@@ -497,13 +499,13 @@ module Addressable
497
499
  #
498
500
  # @param [Class] returning
499
501
  # The type of object to return.
500
- # This value may only be set to <tt>String</tt> or
501
- # <tt>Addressable::URI</tt>. All other values are invalid. Defaults to
502
- # <tt>String</tt>.
502
+ # This value may only be set to <code>String</code> or
503
+ # <code>Addressable::URI</code>. All other values are invalid. Defaults
504
+ # to <code>String</code>.
503
505
  #
504
506
  # @return [String, Addressable::URI]
505
507
  # The encoded URI.
506
- # The return type is determined by the <tt>returning</tt> parameter.
508
+ # The return type is determined by the <code>returning</code> parameter.
507
509
  def self.normalized_encode(uri, returning=String)
508
510
  if !uri.respond_to?(:to_str)
509
511
  raise TypeError, "Can't convert #{uri.class} into String."
@@ -558,6 +560,81 @@ module Addressable
558
560
  end
559
561
  end
560
562
 
563
+ ##
564
+ # Encodes a set of key/value pairs according to the rules for the
565
+ # <code>application/x-www-form-urlencoded</code> MIME type.
566
+ #
567
+ # @param [#to_hash, #to_ary] form_values
568
+ # The form values to encode.
569
+ #
570
+ # @param [TrueClass, FalseClass] sort
571
+ # Sort the key/value pairs prior to encoding.
572
+ # Defaults to <code>false</code>.
573
+ #
574
+ # @return [String]
575
+ # The encoded value.
576
+ def self.form_encode(form_values, sort=false)
577
+ if form_values.respond_to?(:to_hash)
578
+ form_values = form_values.to_hash.to_a
579
+ elsif form_values.respond_to?(:to_ary)
580
+ form_values = form_values.to_ary
581
+ else
582
+ raise TypeError, "Can't convert #{form_values.class} into Array."
583
+ end
584
+ form_values = form_values.map do |(key, value)|
585
+ [key.to_s, value.to_s]
586
+ end
587
+ if sort
588
+ # Useful for OAuth and optimizing caching systems
589
+ form_values = form_values.sort
590
+ end
591
+ escaped_form_values = form_values.map do |(key, value)|
592
+ # Line breaks are CRLF pairs
593
+ [
594
+ self.encode_component(
595
+ key.gsub(/(\r\n|\n|\r)/, "\r\n"),
596
+ CharacterClasses::UNRESERVED
597
+ ).gsub("%20", "+"),
598
+ self.encode_component(
599
+ value.gsub(/(\r\n|\n|\r)/, "\r\n"),
600
+ CharacterClasses::UNRESERVED
601
+ ).gsub("%20", "+")
602
+ ]
603
+ end
604
+ return (escaped_form_values.map do |(key, value)|
605
+ "#{key}=#{value}"
606
+ end).join("&")
607
+ end
608
+
609
+ ##
610
+ # Decodes a <code>String</code> according to the rules for the
611
+ # <code>application/x-www-form-urlencoded</code> MIME type.
612
+ #
613
+ # @param [String, #to_str] encoded_value
614
+ # The form values to decode.
615
+ #
616
+ # @return [Array]
617
+ # The decoded values.
618
+ # This is not a <code>Hash</code> because of the possibility for
619
+ # duplicate keys.
620
+ def self.form_unencode(encoded_value)
621
+ if !encoded_value.respond_to?(:to_str)
622
+ raise TypeError, "Can't convert #{encoded_value.class} into String."
623
+ end
624
+ encoded_value = encoded_value.to_str
625
+ split_values = encoded_value.split("&").map do |pair|
626
+ pair.split("=", 2)
627
+ end
628
+ return split_values.map do |(key, value)|
629
+ [
630
+ key ? self.unencode_component(
631
+ key.gsub("+", "%20")).gsub(/(\r\n|\n|\r)/, "\n") : nil,
632
+ value ? (self.unencode_component(
633
+ value.gsub("+", "%20")).gsub(/(\r\n|\n|\r)/, "\n")) : nil
634
+ ]
635
+ end
636
+ end
637
+
561
638
  ##
562
639
  # Creates a new uri object from component parts.
563
640
  #
@@ -647,13 +724,19 @@ module Addressable
647
724
 
648
725
  if new_scheme && !new_scheme.respond_to?(:to_str)
649
726
  raise TypeError, "Can't convert #{new_scheme.class} into String."
727
+ elsif new_scheme
728
+ new_scheme = new_scheme.to_str
729
+ end
730
+ if new_scheme && new_scheme !~ /[a-z][a-z0-9\.\+\-]*/i
731
+ raise InvalidURIError, "Invalid scheme format."
650
732
  end
651
- @scheme = new_scheme ? new_scheme.to_str : nil
733
+ @scheme = new_scheme
652
734
  @scheme = nil if @scheme.to_s.strip == ""
653
735
 
654
736
  # Reset dependant values
655
737
  @normalized_scheme = nil
656
738
  @uri_string = nil
739
+ @hash = nil
657
740
 
658
741
  # Ensure we haven't created an invalid URI
659
742
  validate()
@@ -714,6 +797,7 @@ module Addressable
714
797
  @authority = nil
715
798
  @normalized_user = nil
716
799
  @uri_string = nil
800
+ @hash = nil
717
801
 
718
802
  # Ensure we haven't created an invalid URI
719
803
  validate()
@@ -775,6 +859,7 @@ module Addressable
775
859
  @authority = nil
776
860
  @normalized_password = nil
777
861
  @uri_string = nil
862
+ @hash = nil
778
863
 
779
864
  # Ensure we haven't created an invalid URI
780
865
  validate()
@@ -844,6 +929,7 @@ module Addressable
844
929
  # Reset dependant values
845
930
  @authority = nil
846
931
  @uri_string = nil
932
+ @hash = nil
847
933
 
848
934
  # Ensure we haven't created an invalid URI
849
935
  validate()
@@ -899,6 +985,7 @@ module Addressable
899
985
  @authority = nil
900
986
  @normalized_host = nil
901
987
  @uri_string = nil
988
+ @hash = nil
902
989
 
903
990
  # Ensure we haven't created an invalid URI
904
991
  validate()
@@ -984,14 +1071,35 @@ module Addressable
984
1071
  @userinfo = nil
985
1072
  @normalized_userinfo = nil
986
1073
  @uri_string = nil
1074
+ @hash = nil
987
1075
 
988
1076
  # Ensure we haven't created an invalid URI
989
1077
  validate()
990
1078
  end
991
1079
 
1080
+ ##
1081
+ # The origin for this URI, serialized to ASCII, as per
1082
+ # draft-ietf-websec-origin-00, section 5.2.
1083
+ #
1084
+ # @return [String] The serialized origin.
1085
+ def origin
1086
+ return (if self.scheme && self.authority
1087
+ if self.normalized_port
1088
+ (
1089
+ "#{self.normalized_scheme}://#{self.normalized_host}" +
1090
+ ":#{self.normalized_port}"
1091
+ )
1092
+ else
1093
+ "#{self.normalized_scheme}://#{self.normalized_host}"
1094
+ end
1095
+ else
1096
+ "null"
1097
+ end)
1098
+ end
1099
+
992
1100
  # Returns an array of known ip-based schemes. These schemes typically
993
1101
  # use a similar URI form:
994
- # //<user>:<password>@<host>:<port>/<url-path>
1102
+ # <code>//<user>:<password>@<host>:<port>/<url-path></code>
995
1103
  def self.ip_based_schemes
996
1104
  return self.port_mapping.keys
997
1105
  end
@@ -1065,6 +1173,7 @@ module Addressable
1065
1173
  @inferred_port = nil
1066
1174
  @normalized_port = nil
1067
1175
  @uri_string = nil
1176
+ @hash = nil
1068
1177
 
1069
1178
  # Ensure we haven't created an invalid URI
1070
1179
  validate()
@@ -1090,6 +1199,76 @@ module Addressable
1090
1199
  end)
1091
1200
  end
1092
1201
 
1202
+ ##
1203
+ # The combination of components that represent a site.
1204
+ # Combines the scheme, user, password, host, and port components.
1205
+ # Primarily useful for HTTP and HTTPS.
1206
+ #
1207
+ # For example, <code>"http://example.com/path?query"</code> would have a
1208
+ # <code>site</code> value of <code>"http://example.com"</code>.
1209
+ #
1210
+ # @return [String] The components that identify a site.
1211
+ def site
1212
+ @site ||= (begin
1213
+ if self.scheme || self.authority
1214
+ site_string = ""
1215
+ site_string << "#{self.scheme}:" if self.scheme != nil
1216
+ site_string << "//#{self.authority}" if self.authority != nil
1217
+ site_string
1218
+ else
1219
+ nil
1220
+ end
1221
+ end)
1222
+ end
1223
+
1224
+ ##
1225
+ # The normalized combination of components that represent a site.
1226
+ # Combines the scheme, user, password, host, and port components.
1227
+ # Primarily useful for HTTP and HTTPS.
1228
+ #
1229
+ # For example, <code>"http://example.com/path?query"</code> would have a
1230
+ # <code>site</code> value of <code>"http://example.com"</code>.
1231
+ #
1232
+ # @return [String] The normalized components that identify a site.
1233
+ def normalized_site
1234
+ @site ||= (begin
1235
+ if self.normalized_scheme || self.normalized_authority
1236
+ site_string = ""
1237
+ if self.normalized_scheme != nil
1238
+ site_string << "#{self.normalized_scheme}:"
1239
+ end
1240
+ if self.normalized_authority != nil
1241
+ site_string << "//#{self.normalized_authority}"
1242
+ end
1243
+ site_string
1244
+ else
1245
+ nil
1246
+ end
1247
+ end)
1248
+ end
1249
+
1250
+ ##
1251
+ # Sets the site value for this URI.
1252
+ #
1253
+ # @param [String, #to_str] new_site The new site value.
1254
+ def site=(new_site)
1255
+ if new_site
1256
+ if !new_site.respond_to?(:to_str)
1257
+ raise TypeError, "Can't convert #{new_site.class} into String."
1258
+ end
1259
+ new_site = new_site.to_str
1260
+ # These two regular expressions derived from the primary parsing
1261
+ # expression
1262
+ self.scheme = new_site[/^(?:([^:\/?#]+):)?(?:\/\/(?:[^\/?#]*))?$/, 1]
1263
+ self.authority = new_site[
1264
+ /^(?:(?:[^:\/?#]+):)?(?:\/\/([^\/?#]*))?$/, 1
1265
+ ]
1266
+ else
1267
+ self.scheme = nil
1268
+ self.authority = nil
1269
+ end
1270
+ end
1271
+
1093
1272
  ##
1094
1273
  # The path component for this URI.
1095
1274
  #
@@ -1105,8 +1284,13 @@ module Addressable
1105
1284
  # @return [String] The path component, normalized.
1106
1285
  def normalized_path
1107
1286
  @normalized_path ||= (begin
1287
+ if self.scheme == nil && self.path != nil && self.path != "" &&
1288
+ self.path =~ /^(?!\/)[^\/:]*:.*$/
1289
+ # Relative paths with colons in the first segment are ambiguous.
1290
+ self.path.sub!(":", "%2F")
1291
+ end
1108
1292
  # String#split(delimeter, -1) uses the more strict splitting behavior
1109
- # found in Python.
1293
+ # found by default in Python.
1110
1294
  result = (self.path.strip.split("/", -1).map do |segment|
1111
1295
  Addressable::URI.normalize_component(
1112
1296
  segment,
@@ -1141,6 +1325,7 @@ module Addressable
1141
1325
  # Reset dependant values
1142
1326
  @normalized_path = nil
1143
1327
  @uri_string = nil
1328
+ @hash = nil
1144
1329
  end
1145
1330
 
1146
1331
  ##
@@ -1203,17 +1388,18 @@ module Addressable
1203
1388
  # Reset dependant values
1204
1389
  @normalized_query = nil
1205
1390
  @uri_string = nil
1391
+ @hash = nil
1206
1392
  end
1207
1393
 
1208
1394
  ##
1209
1395
  # Converts the query component to a Hash value.
1210
1396
  #
1211
1397
  # @option [Symbol] notation
1212
- # May be one of <tt>:flat</tt>, <tt>:dot</tt>, or <tt>:subscript</tt>.
1213
- # The <tt>:dot</tt> notation is not supported for assignment. Default
1214
- # value is <tt>:subscript</tt>.
1398
+ # May be one of <code>:flat</code>, <code>:dot</code>, or
1399
+ # <code>:subscript</code>. The <code>:dot</code> notation is not
1400
+ # supported for assignment. Default value is <code>:subscript</code>.
1215
1401
  #
1216
- # @return [Hash] The query string parsed as a Hash object.
1402
+ # @return [Hash, Array] The query string parsed as a Hash or Array object.
1217
1403
  #
1218
1404
  # @example
1219
1405
  # Addressable::URI.parse("?one=1&two=2&three=3").query_values
@@ -1236,12 +1422,16 @@ module Addressable
1236
1422
  # "?one[two][three][]=four&one[two][three][]=five"
1237
1423
  # ).query_values
1238
1424
  # #=> {"one" => {"two" => {"three" => ["four", "five"]}}}
1425
+ # Addressable::URI.parse(
1426
+ # "?one=two&one=three").query_values(:notation => :flat_array)
1427
+ # #=> [['one', 'two'], ['one', 'three']]
1239
1428
  def query_values(options={})
1240
1429
  defaults = {:notation => :subscript}
1241
1430
  options = defaults.merge(options)
1242
- if ![:flat, :dot, :subscript].include?(options[:notation])
1431
+ if ![:flat, :dot, :subscript, :flat_array].include?(options[:notation])
1243
1432
  raise ArgumentError,
1244
- "Invalid notation. Must be one of: [:flat, :dot, :subscript]."
1433
+ "Invalid notation. Must be one of: " +
1434
+ "[:flat, :dot, :subscript, :flat_array]."
1245
1435
  end
1246
1436
  dehash = lambda do |hash|
1247
1437
  hash.each do |(key, value)|
@@ -1258,19 +1448,22 @@ module Addressable
1258
1448
  end
1259
1449
  end
1260
1450
  return nil if self.query == nil
1451
+ empty_accumulator = :flat_array == options[:notation] ? [] : {}
1261
1452
  return ((self.query.split("&").map do |pair|
1262
- pair.split("=")
1263
- end).inject({}) do |accumulator, (key, value)|
1453
+ pair.split("=", 2) if pair && pair != ""
1454
+ end).compact.inject(empty_accumulator.dup) do |accumulator, (key, value)|
1264
1455
  value = true if value.nil?
1265
1456
  key = self.class.unencode_component(key)
1266
1457
  if value != true
1267
- value = self.class.unencode_component(value).gsub(/\+/, " ")
1458
+ value = self.class.unencode_component(value.gsub(/\+/, " "))
1268
1459
  end
1269
1460
  if options[:notation] == :flat
1270
1461
  if accumulator[key]
1271
1462
  raise ArgumentError, "Key was repeated: #{key.inspect}"
1272
1463
  end
1273
1464
  accumulator[key] = value
1465
+ elsif options[:notation] == :flat_array
1466
+ accumulator << [key, value]
1274
1467
  else
1275
1468
  if options[:notation] == :dot
1276
1469
  array_value = false
@@ -1293,8 +1486,12 @@ module Addressable
1293
1486
  end
1294
1487
  end
1295
1488
  accumulator
1296
- end).inject({}) do |accumulator, (key, value)|
1297
- accumulator[key] = value.kind_of?(Hash) ? dehash.call(value) : value
1489
+ end).inject(empty_accumulator.dup) do |accumulator, (key, value)|
1490
+ if options[:notation] == :flat_array
1491
+ accumulator << [key, value]
1492
+ else
1493
+ accumulator[key] = value.kind_of?(Hash) ? dehash.call(value) : value
1494
+ end
1298
1495
  accumulator
1299
1496
  end
1300
1497
  end
@@ -1302,15 +1499,32 @@ module Addressable
1302
1499
  ##
1303
1500
  # Sets the query component for this URI from a Hash object.
1304
1501
  # This method produces a query string using the :subscript notation.
1502
+ # An empty Hash will result in a nil query.
1305
1503
  #
1306
- # @param [Hash, #to_hash] new_query_values The new query values.
1504
+ # @param [Hash, #to_hash, Array] new_query_values The new query values.
1307
1505
  def query_values=(new_query_values)
1308
1506
  # Check for frozenness
1309
1507
  raise TypeError, "Can't modify frozen URI." if self.frozen?
1310
- if !new_query_values.respond_to?(:to_hash)
1311
- raise TypeError, "Can't convert #{new_query_values.class} into Hash."
1508
+ if new_query_values == nil
1509
+ self.query = nil
1510
+ return nil
1511
+ end
1512
+
1513
+ if !new_query_values.is_a?(Array)
1514
+ if !new_query_values.respond_to?(:to_hash)
1515
+ raise TypeError,
1516
+ "Can't convert #{new_query_values.class} into Hash."
1517
+ end
1518
+ new_query_values = new_query_values.to_hash
1519
+ new_query_values = new_query_values.map do |key, value|
1520
+ key = key.to_s if key.kind_of?(Symbol)
1521
+ [key, value]
1522
+ end
1523
+ # Useful default for OAuth and caching.
1524
+ # Only to be used for non-Array inputs. Arrays should preserve order.
1525
+ new_query_values.sort!
1312
1526
  end
1313
- new_query_values = new_query_values.to_hash
1527
+ # new_query_values have form [['key1', 'value1'], ['key2', 'value2']]
1314
1528
 
1315
1529
  # Algorithm shamelessly stolen from Julien Genestoux, slightly modified
1316
1530
  buffer = ""
@@ -1344,11 +1558,7 @@ module Addressable
1344
1558
  end
1345
1559
  end
1346
1560
  end
1347
- @query = buffer.chop
1348
-
1349
- # Reset dependant values
1350
- @normalized_query = nil
1351
- @uri_string = nil
1561
+ self.query = buffer.chop
1352
1562
  end
1353
1563
 
1354
1564
  ##
@@ -1386,6 +1596,7 @@ module Addressable
1386
1596
 
1387
1597
  # Reset dependant values
1388
1598
  @uri_string = nil
1599
+ @hash = nil
1389
1600
  end
1390
1601
 
1391
1602
  ##
@@ -1429,6 +1640,7 @@ module Addressable
1429
1640
  # Reset dependant values
1430
1641
  @normalized_fragment = nil
1431
1642
  @uri_string = nil
1643
+ @hash = nil
1432
1644
 
1433
1645
  # Ensure we haven't created an invalid URI
1434
1646
  validate()
@@ -1438,8 +1650,8 @@ module Addressable
1438
1650
  # Determines if the scheme indicates an IP-based protocol.
1439
1651
  #
1440
1652
  # @return [TrueClass, FalseClass]
1441
- # <tt>true</tt> if the scheme indicates an IP-based protocol.
1442
- # <tt>false</tt> otherwise.
1653
+ # <code>true</code> if the scheme indicates an IP-based protocol.
1654
+ # <code>false</code> otherwise.
1443
1655
  def ip_based?
1444
1656
  if self.scheme
1445
1657
  return self.class.ip_based_schemes.include?(
@@ -1452,7 +1664,8 @@ module Addressable
1452
1664
  # Determines if the URI is relative.
1453
1665
  #
1454
1666
  # @return [TrueClass, FalseClass]
1455
- # <tt>true</tt> if the URI is relative. <tt>false</tt> otherwise.
1667
+ # <code>true</code> if the URI is relative. <code>false</code>
1668
+ # otherwise.
1456
1669
  def relative?
1457
1670
  return self.scheme.nil?
1458
1671
  end
@@ -1461,7 +1674,8 @@ module Addressable
1461
1674
  # Determines if the URI is absolute.
1462
1675
  #
1463
1676
  # @return [TrueClass, FalseClass]
1464
- # <tt>true</tt> if the URI is absolute. <tt>false</tt> otherwise.
1677
+ # <code>true</code> if the URI is absolute. <code>false</code>
1678
+ # otherwise.
1465
1679
  def absolute?
1466
1680
  return !relative?
1467
1681
  end
@@ -1568,7 +1782,7 @@ module Addressable
1568
1782
  alias_method :+, :join
1569
1783
 
1570
1784
  ##
1571
- # Destructive form of <tt>join</tt>.
1785
+ # Destructive form of <code>join</code>.
1572
1786
  #
1573
1787
  # @param [String, Addressable::URI, #to_str] The URI to join with.
1574
1788
  #
@@ -1580,10 +1794,10 @@ module Addressable
1580
1794
  end
1581
1795
 
1582
1796
  ##
1583
- # Merges a URI with a <tt>Hash</tt> of components.
1584
- # This method has different behavior from <tt>join</tt>. Any components
1585
- # present in the <tt>hash</tt> parameter will override the original
1586
- # components. The path component is not treated specially.
1797
+ # Merges a URI with a <code>Hash</code> of components.
1798
+ # This method has different behavior from <code>join</code>. Any
1799
+ # components present in the <code>hash</code> parameter will override the
1800
+ # original components. The path component is not treated specially.
1587
1801
  #
1588
1802
  # @param [Hash, Addressable::URI, #to_hash] The components to merge with.
1589
1803
  #
@@ -1648,7 +1862,7 @@ module Addressable
1648
1862
  end
1649
1863
 
1650
1864
  ##
1651
- # Destructive form of <tt>merge</tt>.
1865
+ # Destructive form of <code>merge</code>.
1652
1866
  #
1653
1867
  # @param [Hash, Addressable::URI, #to_hash] The components to merge with.
1654
1868
  #
@@ -1662,7 +1876,7 @@ module Addressable
1662
1876
  ##
1663
1877
  # Returns the shortest normalized relative form of this URI that uses the
1664
1878
  # supplied URI as a base for resolution. Returns an absolute URI if
1665
- # necessary. This is effectively the opposite of <tt>route_to</tt>.
1879
+ # necessary. This is effectively the opposite of <code>route_to</code>.
1666
1880
  #
1667
1881
  # @param [String, Addressable::URI, #to_str] uri The URI to route from.
1668
1882
  #
@@ -1720,7 +1934,7 @@ module Addressable
1720
1934
  ##
1721
1935
  # Returns the shortest normalized relative form of the supplied URI that
1722
1936
  # uses this URI as a base for resolution. Returns an absolute URI if
1723
- # necessary. This is effectively the opposite of <tt>route_from</tt>.
1937
+ # necessary. This is effectively the opposite of <code>route_from</code>.
1724
1938
  #
1725
1939
  # @param [String, Addressable::URI, #to_str] uri The URI to route to.
1726
1940
  #
@@ -1784,14 +1998,15 @@ module Addressable
1784
1998
  end
1785
1999
 
1786
2000
  ##
1787
- # Returns <tt>true</tt> if the URI objects are equal. This method
2001
+ # Returns <code>true</code> if the URI objects are equal. This method
1788
2002
  # normalizes both URIs before doing the comparison, and allows comparison
1789
- # against <tt>Strings</tt>.
2003
+ # against <code>Strings</code>.
1790
2004
  #
1791
2005
  # @param [Object] uri The URI to compare.
1792
2006
  #
1793
2007
  # @return [TrueClass, FalseClass]
1794
- # <tt>true</tt> if the URIs are equivalent, <tt>false</tt> otherwise.
2008
+ # <code>true</code> if the URIs are equivalent, <code>false</code>
2009
+ # otherwise.
1795
2010
  def ===(uri)
1796
2011
  if uri.respond_to?(:normalize)
1797
2012
  uri_string = uri.normalize.to_s
@@ -1806,26 +2021,28 @@ module Addressable
1806
2021
  end
1807
2022
 
1808
2023
  ##
1809
- # Returns <tt>true</tt> if the URI objects are equal. This method
2024
+ # Returns <code>true</code> if the URI objects are equal. This method
1810
2025
  # normalizes both URIs before doing the comparison.
1811
2026
  #
1812
2027
  # @param [Object] uri The URI to compare.
1813
2028
  #
1814
2029
  # @return [TrueClass, FalseClass]
1815
- # <tt>true</tt> if the URIs are equivalent, <tt>false</tt> otherwise.
2030
+ # <code>true</code> if the URIs are equivalent, <code>false</code>
2031
+ # otherwise.
1816
2032
  def ==(uri)
1817
2033
  return false unless uri.kind_of?(self.class)
1818
2034
  return self.normalize.to_s == uri.normalize.to_s
1819
2035
  end
1820
2036
 
1821
2037
  ##
1822
- # Returns <tt>true</tt> if the URI objects are equal. This method
2038
+ # Returns <code>true</code> if the URI objects are equal. This method
1823
2039
  # does NOT normalize either URI before doing the comparison.
1824
2040
  #
1825
2041
  # @param [Object] uri The URI to compare.
1826
2042
  #
1827
2043
  # @return [TrueClass, FalseClass]
1828
- # <tt>true</tt> if the URIs are equivalent, <tt>false</tt> otherwise.
2044
+ # <code>true</code> if the URIs are equivalent, <code>false</code>
2045
+ # otherwise.
1829
2046
  def eql?(uri)
1830
2047
  return false unless uri.kind_of?(self.class)
1831
2048
  return self.to_s == uri.to_s
@@ -1875,7 +2092,7 @@ module Addressable
1875
2092
  # Determines if the URI is frozen.
1876
2093
  #
1877
2094
  # @return [TrueClass, FalseClass]
1878
- # True if the URI is frozen, false otherwise.
2095
+ # <code>true</code> if the URI is frozen, <code>false</code> otherwise.
1879
2096
  def frozen?
1880
2097
  self.to_s.frozen?
1881
2098
  end
@@ -1924,9 +2141,9 @@ module Addressable
1924
2141
  end
1925
2142
 
1926
2143
  ##
1927
- # Converts the URI to a <tt>String</tt>.
2144
+ # Converts the URI to a <code>String</code>.
1928
2145
  #
1929
- # @return [String] The URI's <tt>String</tt> representation.
2146
+ # @return [String] The URI's <code>String</code> representation.
1930
2147
  def to_s
1931
2148
  @uri_string ||= (begin
1932
2149
  uri_string = ""
@@ -1943,13 +2160,13 @@ module Addressable
1943
2160
  end
1944
2161
 
1945
2162
  ##
1946
- # URI's are glorified <tt>Strings</tt>. Allow implicit conversion.
2163
+ # URI's are glorified <code>Strings</code>. Allow implicit conversion.
1947
2164
  alias_method :to_str, :to_s
1948
2165
 
1949
2166
  ##
1950
2167
  # Returns a Hash of the URI components.
1951
2168
  #
1952
- # @return [Hash] The URI as a <tt>Hash</tt> of components.
2169
+ # @return [Hash] The URI as a <code>Hash</code> of components.
1953
2170
  def to_hash
1954
2171
  return {
1955
2172
  :scheme => self.scheme,
@@ -1964,9 +2181,9 @@ module Addressable
1964
2181
  end
1965
2182
 
1966
2183
  ##
1967
- # Returns a <tt>String</tt> representation of the URI object's state.
2184
+ # Returns a <code>String</code> representation of the URI object's state.
1968
2185
  #
1969
- # @return [String] The URI object's state, as a <tt>String</tt>.
2186
+ # @return [String] The URI object's state, as a <code>String</code>.
1970
2187
  def inspect
1971
2188
  sprintf("#<%s:%#0x URI:%s>", self.class.to_s, self.object_id, self.to_s)
1972
2189
  end
@@ -2015,6 +2232,9 @@ module Addressable
2015
2232
  end
2016
2233
  normalized_path.gsub!(/^\.\.?\/?/, "")
2017
2234
  normalized_path.gsub!(/^\/\.\.?\//, "/")
2235
+
2236
+ # Non-standard
2237
+ normalized_path.gsub!(/^(\/\.\.?)+\/?$/, "/")
2018
2238
  end until previous_state == normalized_path
2019
2239
  return normalized_path
2020
2240
  end
@@ -2036,6 +2256,11 @@ module Addressable
2036
2256
  raise InvalidURIError, "Hostname not supplied: '#{self.to_s}'"
2037
2257
  end
2038
2258
  end
2259
+ if self.path != nil && self.path != "" && self.path[0..0] != "/" &&
2260
+ self.authority != nil
2261
+ raise InvalidURIError,
2262
+ "Cannot have a relative path with an authority set: '#{self.to_s}'"
2263
+ end
2039
2264
  return nil
2040
2265
  end
2041
2266
 
@@ -2043,9 +2268,9 @@ module Addressable
2043
2268
  # Replaces the internal state of self with the specified URI's state.
2044
2269
  # Used in destructive operations to avoid massive code repetition.
2045
2270
  #
2046
- # @param [Addressable::URI] uri The URI to replace <tt>self</tt> with.
2271
+ # @param [Addressable::URI] uri The URI to replace <code>self</code> with.
2047
2272
  #
2048
- # @return [Addressable::URI] <tt>self</tt>.
2273
+ # @return [Addressable::URI] <code>self</code>.
2049
2274
  def replace_self(uri)
2050
2275
  # Reset dependant values
2051
2276
  instance_variables.each do |var|