addressable 2.1.0 → 2.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,6 @@
1
+ === Addressable 2.1.1
2
+ * fixed some missing type checking
3
+ * fixed issue with unicode normalization
1
4
  === Addressable 2.1.0
2
5
  * refactored URI template support out into its own class
3
6
  * removed extract method due to being useless and unreliable
data/Rakefile CHANGED
@@ -1,7 +1,3 @@
1
- lib_dir = File.expand_path(File.join(File.dirname(__FILE__), "lib"))
2
- $:.unshift(lib_dir)
3
- $:.uniq!
4
-
5
1
  require 'rubygems'
6
2
  require 'rake'
7
3
  require 'rake/testtask'
@@ -10,7 +6,7 @@ require 'rake/packagetask'
10
6
  require 'rake/gempackagetask'
11
7
  require 'spec/rake/spectask'
12
8
 
13
- require File.join(File.dirname(__FILE__), 'lib/addressable', 'version')
9
+ require File.join(File.dirname(__FILE__), 'lib', 'addressable', 'version')
14
10
 
15
11
  PKG_DISPLAY_NAME = 'Addressable'
16
12
  PKG_NAME = PKG_DISPLAY_NAME.downcase
@@ -31,6 +27,38 @@ Ruby's standard library. It more closely conforms to the relevant RFCs and
31
27
  adds support for IRIs and URI templates.
32
28
  TEXT
33
29
 
30
+ desc "generates .gemspec file"
31
+ task :gemspec do
32
+ spec = Gem::Specification.new do |p|
33
+ p.name = '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
+
34
62
  PKG_FILES = FileList[
35
63
  "lib/**/*", "spec/**/*", "vendor/**/*",
36
64
  "tasks/**/*", "website/**/*",
@@ -38,11 +66,7 @@ PKG_FILES = FileList[
38
66
  ].exclude(/database\.yml/).exclude(/[_\.]git$/)
39
67
 
40
68
  RCOV_ENABLED = (RUBY_PLATFORM != "java" && RUBY_VERSION =~ /^1\.8/)
41
- if RCOV_ENABLED
42
- task :default => "spec:verify"
43
- else
44
- task :default => "spec"
45
- end
69
+ task :default => "spec"
46
70
 
47
71
  WINDOWS = (RUBY_PLATFORM =~ /mswin|win32|mingw|bccwin|cygwin/) rescue false
48
72
  SUDO = WINDOWS ? '' : ('sudo' unless ENV['SUDOLESS'])
@@ -4855,15 +4855,15 @@ module Addressable
4855
4855
  delta = firsttime ? delta / PUNYCODE_DAMP : delta >> 1
4856
4856
  # delta >> 1 is a faster way of doing delta / 2
4857
4857
  delta += delta / numpoints
4858
+ difference = PUNYCODE_BASE - PUNYCODE_TMIN
4858
4859
 
4859
4860
  k = 0
4860
- while delta > ((PUNYCODE_BASE - PUNYCODE_TMIN) * PUNYCODE_TMAX) / 2
4861
- delta /= PUNYCODE_BASE - PUNYCODE_TMIN
4861
+ while delta > (difference * PUNYCODE_TMAX) / 2
4862
+ delta /= difference
4862
4863
  k += PUNYCODE_BASE
4863
4864
  end
4864
4865
 
4865
- k + (PUNYCODE_BASE - PUNYCODE_TMIN + 1) *
4866
- delta / (delta + PUNYCODE_SKEW)
4866
+ k + (difference + 1) * delta / (delta + PUNYCODE_SKEW)
4867
4867
  end
4868
4868
  (class <<self; private :punycode_adapt; end)
4869
4869
  end
@@ -22,9 +22,6 @@
22
22
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
23
  #++
24
24
 
25
- $:.unshift(File.expand_path(File.join(File.dirname(__FILE__), '/..')))
26
- $:.uniq!
27
-
28
25
  require "addressable/version"
29
26
  require "addressable/uri"
30
27
 
@@ -39,7 +36,7 @@ module Addressable
39
36
  Addressable::URI::CharacterClasses::UNRESERVED
40
37
  OPERATOR_EXPANSION =
41
38
  /\{-([a-zA-Z]+)\|([#{anything}]+)\|([#{anything}]+)\}/
42
- VARIABLE_EXPANSION = /\{([#{anything}]+?)(=([#{anything}]+))?\}/
39
+ VARIABLE_EXPANSION = /\{([#{anything}]+?)(?:=([#{anything}]+))?\}/
43
40
 
44
41
  ##
45
42
  # Raised if an invalid template value is supplied.
@@ -154,21 +151,23 @@ module Addressable
154
151
  #
155
152
  # @param [Addressable::URI, #to_str] uri
156
153
  # The URI to extract from.
154
+ #
157
155
  # @param [#restore, #match] processor
158
156
  # A template processor object may optionally be supplied.
159
- # The object should respond to either the <tt>restore</tt> or
160
- # <tt>match</tt> messages or both. The <tt>restore</tt> method should
161
- # take two parameters: [String] name and [String] value. The
162
- # <tt>restore</tt> method should reverse any transformations that have
163
- # been performed on the value to ensure a valid URI. The
164
- # <tt>match</tt> method should take a single parameter: [String] name.
165
- # The <tt>match</tt> method should return a <tt>String</tt> containing
166
- # a regular expression capture group for matching on that particular
167
- # variable. The default value is ".*?". The <tt>match</tt> method has
168
- # no effect on multivariate operator expansions.
157
+ #
158
+ # The object should respond to either the <tt>restore</tt> or
159
+ # <tt>match</tt> messages or both. The <tt>restore</tt> method should take
160
+ # two parameters: [String] name and [String] value. The <tt>restore</tt>
161
+ # method should reverse any transformations that have been performed on the
162
+ # value to ensure a valid URI. The <tt>match</tt> method should take a
163
+ # single parameter: [String] name. The <tt>match</tt> method should return
164
+ # a <tt>String</tt> containing a regular expression capture group for
165
+ # matching on that particular variable. The default value is ".*?". The
166
+ # <tt>match</tt> method has no effect on multivariate operator expansions.
167
+ #
169
168
  # @return [Hash, NilClass]
170
- # The <tt>Hash</tt> mapping that was extracted from the URI, or
171
- # <tt>nil</tt> if the URI didn't match the template.
169
+ # The <tt>Hash</tt> mapping that was extracted from the URI, or
170
+ # <tt>nil</tt> if the URI didn't match the template.
172
171
  #
173
172
  # @example
174
173
  # class ExampleProcessor
@@ -212,21 +211,23 @@ module Addressable
212
211
  #
213
212
  # @param [Addressable::URI, #to_str] uri
214
213
  # The URI to extract from.
214
+ #
215
215
  # @param [#restore, #match] processor
216
216
  # A template processor object may optionally be supplied.
217
- # The object should respond to either the <tt>restore</tt> or
218
- # <tt>match</tt> messages or both. The <tt>restore</tt> method should
219
- # take two parameters: [String] name and [String] value. The
220
- # <tt>restore</tt> method should reverse any transformations that have
221
- # been performed on the value to ensure a valid URI. The
222
- # <tt>match</tt> method should take a single parameter: [String] name.
223
- # The <tt>match</tt> method should return a <tt>String</tt> containing
224
- # a regular expression capture group for matching on that particular
225
- # variable. The default value is ".*?". The <tt>match</tt> method has
226
- # no effect on multivariate operator expansions.
217
+ #
218
+ # The object should respond to either the <tt>restore</tt> or
219
+ # <tt>match</tt> messages or both. The <tt>restore</tt> method should take
220
+ # two parameters: [String] name and [String] value. The <tt>restore</tt>
221
+ # method should reverse any transformations that have been performed on the
222
+ # value to ensure a valid URI. The <tt>match</tt> method should take a
223
+ # single parameter: [String] name. The <tt>match</tt> method should return
224
+ # a <tt>String</tt> containing a regular expression capture group for
225
+ # matching on that particular variable. The default value is ".*?". The
226
+ # <tt>match</tt> method has no effect on multivariate operator expansions.
227
+ #
227
228
  # @return [Hash, NilClass]
228
- # The <tt>Hash</tt> mapping that was extracted from the URI, or
229
- # <tt>nil</tt> if the URI didn't match the template.
229
+ # The <tt>Hash</tt> mapping that was extracted from the URI, or
230
+ # <tt>nil</tt> if the URI didn't match the template.
230
231
  #
231
232
  # @example
232
233
  # class ExampleProcessor
@@ -325,19 +326,19 @@ module Addressable
325
326
  #
326
327
  # @param [Hash] mapping The mapping that corresponds to the pattern.
327
328
  # @param [#validate, #transform] processor
328
- # An optional processor object may be supplied. The object should
329
- # respond to either the <tt>validate</tt> or <tt>transform</tt> messages
330
- # or both. Both the <tt>validate</tt> and <tt>transform</tt> methods
331
- # should take two parameters: <tt>name</tt> and <tt>value</tt>. The
332
- # <tt>validate</tt> method should return <tt>true</tt> or
333
- # <tt>false</tt>; <tt>true</tt> if the value of the variable is valid,
334
- # <tt>false</tt> otherwise. An <tt>InvalidTemplateValueError</tt>
335
- # exception will be raised if the value is invalid. The
336
- # <tt>transform</tt> method should return the transformed variable
337
- # value as a <tt>String</tt>. If a <tt>transform</tt> method is used,
338
- # the value will not be percent encoded automatically. Unicode
339
- # normalization will be performed both before and after sending the
340
- # value to the transform method.
329
+ # An optional processor object may be supplied.
330
+ #
331
+ # The object should respond to either the <tt>validate</tt> or
332
+ # <tt>transform</tt> messages or both. Both the <tt>validate</tt> and
333
+ # <tt>transform</tt> methods should take two parameters: <tt>name</tt> and
334
+ # <tt>value</tt>. The <tt>validate</tt> method should return <tt>true</tt>
335
+ # or <tt>false</tt>; <tt>true</tt> if the value of the variable is valid,
336
+ # <tt>false</tt> otherwise. An <tt>InvalidTemplateValueError</tt>
337
+ # exception will be raised if the value is invalid. The <tt>transform</tt>
338
+ # method should return the transformed variable value as a <tt>String</tt>.
339
+ # If a <tt>transform</tt> method is used, the value will not be percent
340
+ # encoded automatically. Unicode normalization will be performed both
341
+ # before and after sending the value to the transform method.
341
342
  #
342
343
  # @return [Addressable::Template] The partially expanded URI template.
343
344
  #
@@ -401,19 +402,19 @@ module Addressable
401
402
  #
402
403
  # @param [Hash] mapping The mapping that corresponds to the pattern.
403
404
  # @param [#validate, #transform] processor
404
- # An optional processor object may be supplied. The object should
405
- # respond to either the <tt>validate</tt> or <tt>transform</tt> messages
406
- # or both. Both the <tt>validate</tt> and <tt>transform</tt> methods
407
- # should take two parameters: <tt>name</tt> and <tt>value</tt>. The
408
- # <tt>validate</tt> method should return <tt>true</tt> or
409
- # <tt>false</tt>; <tt>true</tt> if the value of the variable is valid,
410
- # <tt>false</tt> otherwise. An <tt>InvalidTemplateValueError</tt>
411
- # exception will be raised if the value is invalid. The
412
- # <tt>transform</tt> method should return the transformed variable
413
- # value as a <tt>String</tt>. If a <tt>transform</tt> method is used,
414
- # the value will not be percent encoded automatically. Unicode
415
- # normalization will be performed both before and after sending the
416
- # value to the transform method.
405
+ # An optional processor object may be supplied.
406
+ #
407
+ # The object should respond to either the <tt>validate</tt> or
408
+ # <tt>transform</tt> messages or both. Both the <tt>validate</tt> and
409
+ # <tt>transform</tt> methods should take two parameters: <tt>name</tt> and
410
+ # <tt>value</tt>. The <tt>validate</tt> method should return <tt>true</tt>
411
+ # or <tt>false</tt>; <tt>true</tt> if the value of the variable is valid,
412
+ # <tt>false</tt> otherwise. An <tt>InvalidTemplateValueError</tt>
413
+ # exception will be raised if the value is invalid. The <tt>transform</tt>
414
+ # method should return the transformed variable value as a <tt>String</tt>.
415
+ # If a <tt>transform</tt> method is used, the value will not be percent
416
+ # encoded automatically. Unicode normalization will be performed both
417
+ # before and after sending the value to the transform method.
417
418
  #
418
419
  # @return [Addressable::URI] The expanded URI template.
419
420
  #
@@ -484,55 +485,79 @@ module Addressable
484
485
  #
485
486
  # @return [Array] The variables present in the template's pattern.
486
487
  def variables
487
- @variables ||= (begin
488
- result = []
488
+ @variables ||= ordered_variable_defaults.map { |var, val| var }.uniq
489
+ end
490
+ alias_method :keys, :variables
491
+
492
+ ##
493
+ # Returns a mapping of variables to their default values specified
494
+ # in the template. Variables without defaults are not returned.
495
+ #
496
+ # @return [Hash] Mapping of template variables to their defaults
497
+ def variable_defaults
498
+ @variable_defaults ||= Hash[*ordered_variable_defaults.reject { |k,v| v.nil? }.flatten]
499
+ end
489
500
 
501
+ private
502
+
503
+ def ordered_variable_defaults
504
+ @ordered_variable_defaults ||= begin
490
505
  expansions, expansion_regexp = parse_template_pattern(pattern)
491
- expansions.each do |expansion|
492
- if expansion =~ OPERATOR_EXPANSION
493
- _, _, variables, _ = parse_template_expansion(expansion)
494
- result.concat(variables)
495
- else
496
- result << expansion[VARIABLE_EXPANSION, 1]
506
+
507
+ expansions.inject([]) do |result, expansion|
508
+ case expansion
509
+ when OPERATOR_EXPANSION
510
+ _, _, variables, mapping = parse_template_expansion(expansion)
511
+ result.concat variables.map { |var| [var, mapping[var]] }
512
+ when VARIABLE_EXPANSION
513
+ result << [$1, $2]
497
514
  end
515
+ result
498
516
  end
499
- result.uniq
500
- end)
517
+ end
501
518
  end
502
- alias_method :keys, :variables
503
519
 
504
- private
505
520
  ##
506
521
  # Transforms a mapping so that values can be substituted into the
507
522
  # template.
508
523
  #
509
524
  # @param [Hash] mapping The mapping of variables to values.
510
525
  # @param [#validate, #transform] processor
511
- # An optional processor object may be supplied. The object should
512
- # respond to either the <tt>validate</tt> or <tt>transform</tt> messages
513
- # or both. Both the <tt>validate</tt> and <tt>transform</tt> methods
514
- # should take two parameters: <tt>name</tt> and <tt>value</tt>. The
515
- # <tt>validate</tt> method should return <tt>true</tt> or
516
- # <tt>false</tt>; <tt>true</tt> if the value of the variable is valid,
517
- # <tt>false</tt> otherwise. An <tt>InvalidTemplateValueError</tt>
518
- # exception will be raised if the value is invalid. The
519
- # <tt>transform</tt> method should return the transformed variable
520
- # value as a <tt>String</tt>. If a <tt>transform</tt> method is used,
521
- # the value will not be percent encoded automatically. Unicode
522
- # normalization will be performed both before and after sending the
523
- # value to the transform method.
526
+ # An optional processor object may be supplied.
527
+ #
528
+ # The object should respond to either the <tt>validate</tt> or
529
+ # <tt>transform</tt> messages or both. Both the <tt>validate</tt> and
530
+ # <tt>transform</tt> methods should take two parameters: <tt>name</tt> and
531
+ # <tt>value</tt>. The <tt>validate</tt> method should return <tt>true</tt>
532
+ # or <tt>false</tt>; <tt>true</tt> if the value of the variable is valid,
533
+ # <tt>false</tt> otherwise. An <tt>InvalidTemplateValueError</tt> exception
534
+ # will be raised if the value is invalid. The <tt>transform</tt> method
535
+ # should return the transformed variable value as a <tt>String</tt>. If a
536
+ # <tt>transform</tt> method is used, the value will not be percent encoded
537
+ # automatically. Unicode normalization will be performed both before and
538
+ # after sending the value to the transform method.
524
539
  #
525
540
  # @return [Hash] The transformed mapping.
526
541
  def transform_mapping(mapping, processor=nil)
527
542
  return mapping.inject({}) do |accu, pair|
528
543
  name, value = pair
544
+ value = value.to_s if Numeric === value || Symbol === value
545
+
529
546
  unless value.respond_to?(:to_ary) || value.respond_to?(:to_str)
530
547
  raise TypeError,
531
548
  "Can't convert #{value.class} into String or Array."
532
549
  end
533
550
 
534
- value =
535
- value.respond_to?(:to_ary) ? value.to_ary : value.to_str
551
+ if Symbol === name
552
+ name = name.to_s
553
+ elsif name.respond_to?(:to_str)
554
+ name = name.to_str
555
+ else
556
+ raise TypeError,
557
+ "Can't convert #{name.class} into String."
558
+ end
559
+ value = value.respond_to?(:to_ary) ? value.to_ary : value.to_str
560
+
536
561
  # Handle unicode normalization
537
562
  if value.kind_of?(Array)
538
563
  value.map! { |val| Addressable::IDNA.unicode_normalize_kc(val) }
@@ -796,8 +821,8 @@ module Addressable
796
821
  # @return [Regexp]
797
822
  # A regular expression which may be used to parse a template pattern.
798
823
  def parse_template_pattern(pattern, processor=nil)
799
- # Escape the pattern. The two gsubs restore the escaped curly braces
800
- # back to their original form. Basically, escape everything that isn't
824
+ # Escape the pattern. The two gsubs restore the escaped curly braces
825
+ # back to their original form. Basically, escape everything that isn't
801
826
  # within an expansion.
802
827
  escaped_pattern = Regexp.escape(
803
828
  pattern
@@ -819,7 +844,7 @@ module Addressable
819
844
  parse_template_expansion(expansion)
820
845
  if processor != nil && processor.respond_to?(:match)
821
846
  # We can only lookup the match values for single variable
822
- # operator expansions. Besides, ".*" is usually the only
847
+ # operator expansions. Besides, ".*" is usually the only
823
848
  # reasonable value for multivariate operators anyways.
824
849
  if ["prefix", "suffix", "list"].include?(operator)
825
850
  capture_group = "(#{processor.match(names.first)})"
@@ -22,9 +22,6 @@
22
22
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
23
  #++
24
24
 
25
- $:.unshift(File.expand_path(File.join(File.dirname(__FILE__), '/..')))
26
- $:.uniq!
27
-
28
25
  require "addressable/version"
29
26
  require "addressable/idna"
30
27
 
@@ -66,8 +63,9 @@ module Addressable
66
63
  # Returns a URI object based on the parsed string.
67
64
  #
68
65
  # @param [String, Addressable::URI, #to_str] uri
69
- # The URI string to parse. No parsing is performed if the object is
70
- # already an <tt>Addressable::URI</tt>.
66
+ # The URI string to parse.
67
+ # No parsing is performed if the object is already an
68
+ # <tt>Addressable::URI</tt>.
71
69
  #
72
70
  # @return [Addressable::URI] The parsed URI.
73
71
  def self.parse(uri)
@@ -131,16 +129,17 @@ module Addressable
131
129
  end
132
130
 
133
131
  ##
134
- # Converts an input to a URI. The input does not have to be a valid
132
+ # Converts an input to a URI. The input does not have to be a valid
135
133
  # URI — the method will use heuristics to guess what URI was intended.
136
134
  # This is not standards-compliant, merely user-friendly.
137
135
  #
138
136
  # @param [String, Addressable::URI, #to_str] uri
139
- # The URI string to parse. No parsing is performed if the object is
140
- # already an <tt>Addressable::URI</tt>.
137
+ # The URI string to parse.
138
+ # No parsing is performed if the object is already an
139
+ # <tt>Addressable::URI</tt>.
141
140
  # @param [Hash] hints
142
- # A <tt>Hash</tt> of hints to the heuristic parser. Defaults to
143
- # <tt>{:scheme => "http"}</tt>.
141
+ # A <tt>Hash</tt> of hints to the heuristic parser.
142
+ # Defaults to <tt>{:scheme => "http"}</tt>.
144
143
  #
145
144
  # @return [Addressable::URI] The parsed URI.
146
145
  def self.heuristic_parse(uri, hints={})
@@ -184,16 +183,16 @@ module Addressable
184
183
  end
185
184
 
186
185
  ##
187
- # Converts a path to a file scheme URI. If the path supplied is
188
- # relative, it will be returned as a relative URI. If the path supplied
186
+ # Converts a path to a file scheme URI. If the path supplied is
187
+ # relative, it will be returned as a relative URI. If the path supplied
189
188
  # is actually a non-file URI, it will parse the URI as if it had been
190
- # parsed with <tt>Addressable::URI.parse</tt>. Handles all of the
189
+ # parsed with <tt>Addressable::URI.parse</tt>. Handles all of the
191
190
  # various Microsoft-specific formats for specifying paths.
192
191
  #
193
192
  # @param [String, Addressable::URI, #to_str] path
194
- # Typically a <tt>String</tt> path to a file or directory, but
195
- # will return a sensible return value if an absolute URI is supplied
196
- # instead.
193
+ #
194
+ # Typically a <tt>String</tt> path to a file or directory, but will return
195
+ # a sensible return value if an absolute URI is supplied instead.
197
196
  #
198
197
  # @return [Addressable::URI]
199
198
  # The parsed file scheme URI or the original URI if some other URI
@@ -281,17 +280,17 @@ module Addressable
281
280
  # @param [String, #to_str] component The URI component to encode.
282
281
  #
283
282
  # @param [String, Regexp] character_class
284
- # The characters which are not percent encoded. If a <tt>String</tt>
285
- # is passed, the <tt>String</tt> must be formatted as a regular
286
- # expression character class. (Do not include the surrounding square
287
- # brackets.) For example, <tt>"b-zB-Z0-9"</tt> would cause everything
288
- # but the letters 'b' through 'z' and the numbers '0' through '9' to be
289
- # percent encoded. If a <tt>Regexp</tt> is passed, the value
290
- # <tt>/[^b-zB-Z0-9]/</tt> would have the same effect.
291
- # A set of useful <tt>String</tt> values may be found in the
292
- # <tt>Addressable::URI::CharacterClasses</tt> module. The default value
293
- # is the reserved plus unreserved character classes specified in
294
- # <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>.
283
+ #
284
+ # The characters which are not percent encoded. If a <tt>String</tt> is
285
+ # passed, the <tt>String</tt> must be formatted as a regular expression
286
+ # character class. (Do not include the surrounding square brackets.) For
287
+ # example, <tt>"b-zB-Z0-9"</tt> would cause everything but the letters 'b'
288
+ # through 'z' and the numbers '0' through '9' to be percent encoded. If a
289
+ # <tt>Regexp</tt> is passed, the value <tt>/[^b-zB-Z0-9]/</tt> would have
290
+ # the same effect. A set of useful <tt>String</tt> values may be found in
291
+ # the <tt>Addressable::URI::CharacterClasses</tt> module. The default
292
+ # value is the reserved plus unreserved character classes specified in <a
293
+ # href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>.
295
294
  #
296
295
  # @return [String] The encoded component.
297
296
  #
@@ -343,13 +342,14 @@ module Addressable
343
342
  # The URI or component to unencode.
344
343
  #
345
344
  # @param [Class] returning
346
- # The type of object to return. This value may only be set to
347
- # <tt>String</tt> or <tt>Addressable::URI</tt>. All other values
348
- # are invalid. Defaults to <tt>String</tt>.
345
+ # The type of object to return.
346
+ # This value may only be set to <tt>String</tt> or
347
+ # <tt>Addressable::URI</tt>. All other values are invalid. Defaults to
348
+ # <tt>String</tt>.
349
349
  #
350
350
  # @return [String, Addressable::URI]
351
- # The unencoded component or URI. The return type is determined by
352
- # the <tt>returning</tt> parameter.
351
+ # The unencoded component or URI.
352
+ # The return type is determined by the <tt>returning</tt> parameter.
353
353
  def self.unencode(uri, returning=String)
354
354
  return nil if uri.nil?
355
355
  if !uri.respond_to?(:to_str)
@@ -384,13 +384,14 @@ module Addressable
384
384
  # The URI to encode.
385
385
  #
386
386
  # @param [Class] returning
387
- # The type of object to return. This value may only be set to
388
- # <tt>String</tt> or <tt>Addressable::URI</tt>. All other values
389
- # are invalid. Defaults to <tt>String</tt>.
387
+ # The type of object to return.
388
+ # This value may only be set to <tt>String</tt> or
389
+ # <tt>Addressable::URI</tt>. All other values are invalid. Defaults to
390
+ # <tt>String</tt>.
390
391
  #
391
392
  # @return [String, Addressable::URI]
392
- # The encoded URI. The return type is determined by
393
- # the <tt>returning</tt> parameter.
393
+ # The encoded URI.
394
+ # The return type is determined by the <tt>returning</tt> parameter.
394
395
  def self.encode(uri, returning=String)
395
396
  return nil if uri.nil?
396
397
  if !uri.respond_to?(:to_str)
@@ -426,20 +427,21 @@ module Addressable
426
427
  end
427
428
 
428
429
  ##
429
- # Normalizes the encoding of a URI. Characters within a hostname are
430
+ # Normalizes the encoding of a URI. Characters within a hostname are
430
431
  # not percent encoded to allow for internationalized domain names.
431
432
  #
432
433
  # @param [String, Addressable::URI, #to_str] uri
433
434
  # The URI to encode.
434
435
  #
435
436
  # @param [Class] returning
436
- # The type of object to return. This value may only be set to
437
- # <tt>String</tt> or <tt>Addressable::URI</tt>. All other values
438
- # are invalid. Defaults to <tt>String</tt>.
437
+ # The type of object to return.
438
+ # This value may only be set to <tt>String</tt> or
439
+ # <tt>Addressable::URI</tt>. All other values are invalid. Defaults to
440
+ # <tt>String</tt>.
439
441
  #
440
442
  # @return [String, Addressable::URI]
441
- # The encoded URI. The return type is determined by
442
- # the <tt>returning</tt> parameter.
443
+ # The encoded URI.
444
+ # The return type is determined by the <tt>returning</tt> parameter.
443
445
  def self.normalized_encode(uri, returning=String)
444
446
  if !uri.respond_to?(:to_str)
445
447
  raise TypeError, "Can't convert #{uri.class} into String."
@@ -501,12 +503,12 @@ module Addressable
501
503
  # @option [String, #to_str] user The user component.
502
504
  # @option [String, #to_str] password The password component.
503
505
  # @option [String, #to_str] userinfo
504
- # The userinfo component. If this is supplied, the user and password
506
+ # The userinfo component. If this is supplied, the user and password
505
507
  # components must be omitted.
506
508
  # @option [String, #to_str] host The host component.
507
509
  # @option [String, #to_str] port The port component.
508
510
  # @option [String, #to_str] authority
509
- # The authority component. If this is supplied, the user, password,
511
+ # The authority component. If this is supplied, the user, password,
510
512
  # userinfo, host, and port components must be omitted.
511
513
  # @option [String, #to_str] path The path component.
512
514
  # @option [String, #to_str] query The query component.
@@ -581,6 +583,9 @@ module Addressable
581
583
  # Check for frozenness
582
584
  raise TypeError, "Can't modify frozen URI." if self.frozen?
583
585
 
586
+ if new_scheme && !new_scheme.respond_to?(:to_str)
587
+ raise TypeError, "Can't convert #{new_scheme.class} into String."
588
+ end
584
589
  @scheme = new_scheme ? new_scheme.to_str : nil
585
590
  @scheme = nil if @scheme.to_s.strip == ""
586
591
 
@@ -631,6 +636,9 @@ module Addressable
631
636
  # Check for frozenness
632
637
  raise TypeError, "Can't modify frozen URI." if self.frozen?
633
638
 
639
+ if new_user && !new_user.respond_to?(:to_str)
640
+ raise TypeError, "Can't convert #{new_user.class} into String."
641
+ end
634
642
  @user = new_user ? new_user.to_str : nil
635
643
 
636
644
  # You can't have a nil user with a non-nil password
@@ -689,6 +697,9 @@ module Addressable
689
697
  # Check for frozenness
690
698
  raise TypeError, "Can't modify frozen URI." if self.frozen?
691
699
 
700
+ if new_password && !new_password.respond_to?(:to_str)
701
+ raise TypeError, "Can't convert #{new_password.class} into String."
702
+ end
692
703
  @password = new_password ? new_password.to_str : nil
693
704
 
694
705
  # You can't have a nil user with a non-nil password
@@ -754,6 +765,9 @@ module Addressable
754
765
  # Check for frozenness
755
766
  raise TypeError, "Can't modify frozen URI." if self.frozen?
756
767
 
768
+ if new_userinfo && !new_userinfo.respond_to?(:to_str)
769
+ raise TypeError, "Can't convert #{new_userinfo.class} into String."
770
+ end
757
771
  new_user, new_password = if new_userinfo
758
772
  [
759
773
  new_userinfo.to_str.strip[/^(.*):/, 1],
@@ -816,6 +830,9 @@ module Addressable
816
830
  # Check for frozenness
817
831
  raise TypeError, "Can't modify frozen URI." if self.frozen?
818
832
 
833
+ if new_host && !new_host.respond_to?(:to_str)
834
+ raise TypeError, "Can't convert #{new_host.class} into String."
835
+ end
819
836
  @host = new_host ? new_host.to_str : nil
820
837
 
821
838
  # Reset dependant values
@@ -881,6 +898,9 @@ module Addressable
881
898
  raise TypeError, "Can't modify frozen URI." if self.frozen?
882
899
 
883
900
  if new_authority
901
+ if !new_authority.respond_to?(:to_str)
902
+ raise TypeError, "Can't convert #{new_authority.class} into String."
903
+ end
884
904
  new_authority = new_authority.to_str
885
905
  new_userinfo = new_authority[/^([^\[\]]*)@/, 1]
886
906
  if new_userinfo
@@ -894,10 +914,10 @@ module Addressable
894
914
  end
895
915
 
896
916
  # Password assigned first to ensure validity in case of nil
897
- self.password = new_password
898
- self.user = new_user
899
- self.host = new_host
900
- self.port = new_port
917
+ self.password = defined?(new_password) ? new_password : nil
918
+ self.user = defined?(new_user) ? new_user : nil
919
+ self.host = defined?(new_host) ? new_host : nil
920
+ self.port = defined?(new_port) ? new_port : nil
901
921
 
902
922
  # Reset dependant values
903
923
  @inferred_port = nil
@@ -909,7 +929,7 @@ module Addressable
909
929
  validate()
910
930
  end
911
931
 
912
- # Returns an array of known ip-based schemes. These schemes typically
932
+ # Returns an array of known ip-based schemes. These schemes typically
913
933
  # use a similar URI form:
914
934
  # //<user>:<password>@<host>:<port>/<url-path>
915
935
  def self.ip_based_schemes
@@ -917,7 +937,7 @@ module Addressable
917
937
  end
918
938
 
919
939
  # Returns a hash of common IP-based schemes and their default port
920
- # numbers. Adding new schemes to this hash, as necessary, will allow
940
+ # numbers. Adding new schemes to this hash, as necessary, will allow
921
941
  # for better URI normalization.
922
942
  def self.port_mapping
923
943
  @port_mapping ||= {
@@ -939,7 +959,7 @@ module Addressable
939
959
 
940
960
  ##
941
961
  # The port component for this URI.
942
- # This is the port number actually given in the URI. This does not
962
+ # This is the port number actually given in the URI. This does not
943
963
  # infer port numbers from default values.
944
964
  #
945
965
  # @return [Integer] The port component.
@@ -1054,6 +1074,9 @@ module Addressable
1054
1074
  # Check for frozenness
1055
1075
  raise TypeError, "Can't modify frozen URI." if self.frozen?
1056
1076
 
1077
+ if new_path && !new_path.respond_to?(:to_str)
1078
+ raise TypeError, "Can't convert #{new_path.class} into String."
1079
+ end
1057
1080
  @path = (new_path || "").to_str
1058
1081
  if @path != "" && @path[0..0] != "/" && host != nil
1059
1082
  @path = "/#{@path}"
@@ -1098,11 +1121,19 @@ module Addressable
1098
1121
  def normalized_query
1099
1122
  @normalized_query ||= (begin
1100
1123
  if self.query
1101
- Addressable::URI.encode_component(
1102
- Addressable::IDNA.unicode_normalize_kc(
1103
- Addressable::URI.unencode_component(self.query.strip)),
1104
- Addressable::URI::CharacterClasses::QUERY
1105
- )
1124
+ begin
1125
+ Addressable::URI.encode_component(
1126
+ Addressable::IDNA.unicode_normalize_kc(
1127
+ Addressable::URI.unencode_component(self.query.strip)),
1128
+ Addressable::URI::CharacterClasses::QUERY
1129
+ )
1130
+ rescue ArgumentError
1131
+ # Likely a malformed UTF-8 character, skip unicode normalization
1132
+ Addressable::URI.encode_component(
1133
+ Addressable::URI.unencode_component(self.query.strip),
1134
+ Addressable::URI::CharacterClasses::QUERY
1135
+ )
1136
+ end
1106
1137
  else
1107
1138
  nil
1108
1139
  end
@@ -1117,6 +1148,9 @@ module Addressable
1117
1148
  # Check for frozenness
1118
1149
  raise TypeError, "Can't modify frozen URI." if self.frozen?
1119
1150
 
1151
+ if new_query && !new_query.respond_to?(:to_str)
1152
+ raise TypeError, "Can't convert #{new_query.class} into String."
1153
+ end
1120
1154
  @query = new_query ? new_query.to_str : nil
1121
1155
 
1122
1156
  # Reset dependant values
@@ -1129,8 +1163,8 @@ module Addressable
1129
1163
  #
1130
1164
  # @option [Symbol] notation
1131
1165
  # May be one of <tt>:flat</tt>, <tt>:dot</tt>, or <tt>:subscript</tt>.
1132
- # The <tt>:dot</tt> notation is not supported for assignment.
1133
- # Default value is <tt>:subscript</tt>.
1166
+ # The <tt>:dot</tt> notation is not supported for assignment. Default
1167
+ # value is <tt>:subscript</tt>.
1134
1168
  #
1135
1169
  # @return [Hash] The query string parsed as a Hash object.
1136
1170
  #
@@ -1285,11 +1319,19 @@ module Addressable
1285
1319
  def normalized_fragment
1286
1320
  @normalized_fragment ||= (begin
1287
1321
  if self.fragment
1288
- Addressable::URI.encode_component(
1289
- Addressable::IDNA.unicode_normalize_kc(
1290
- Addressable::URI.unencode_component(self.fragment.strip)),
1291
- Addressable::URI::CharacterClasses::FRAGMENT
1292
- )
1322
+ begin
1323
+ Addressable::URI.encode_component(
1324
+ Addressable::IDNA.unicode_normalize_kc(
1325
+ Addressable::URI.unencode_component(self.fragment.strip)),
1326
+ Addressable::URI::CharacterClasses::FRAGMENT
1327
+ )
1328
+ rescue ArgumentError
1329
+ # Likely a malformed UTF-8 character, skip unicode normalization
1330
+ Addressable::URI.encode_component(
1331
+ Addressable::URI.unencode_component(self.fragment.strip),
1332
+ Addressable::URI::CharacterClasses::FRAGMENT
1333
+ )
1334
+ end
1293
1335
  else
1294
1336
  nil
1295
1337
  end
@@ -1304,6 +1346,9 @@ module Addressable
1304
1346
  # Check for frozenness
1305
1347
  raise TypeError, "Can't modify frozen URI." if self.frozen?
1306
1348
 
1349
+ if new_fragment && !new_fragment.respond_to?(:to_str)
1350
+ raise TypeError, "Can't convert #{new_fragment.class} into String."
1351
+ end
1307
1352
  @fragment = new_fragment ? new_fragment.to_str : nil
1308
1353
 
1309
1354
  # Reset dependant values
@@ -1318,8 +1363,8 @@ module Addressable
1318
1363
  # Determines if the scheme indicates an IP-based protocol.
1319
1364
  #
1320
1365
  # @return [TrueClass, FalseClass]
1321
- # <tt>true</tt> if the scheme indicates an IP-based protocol.
1322
- # <tt>false</tt> otherwise.
1366
+ # <tt>true</tt> if the scheme indicates an IP-based protocol.
1367
+ # <tt>false</tt> otherwise.
1323
1368
  def ip_based?
1324
1369
  if self.scheme
1325
1370
  return self.class.ip_based_schemes.include?(
@@ -1332,8 +1377,7 @@ module Addressable
1332
1377
  # Determines if the URI is relative.
1333
1378
  #
1334
1379
  # @return [TrueClass, FalseClass]
1335
- # <tt>true</tt> if the URI is relative.
1336
- # <tt>false</tt> otherwise.
1380
+ # <tt>true</tt> if the URI is relative. <tt>false</tt> otherwise.
1337
1381
  def relative?
1338
1382
  return self.scheme.nil?
1339
1383
  end
@@ -1342,8 +1386,7 @@ module Addressable
1342
1386
  # Determines if the URI is absolute.
1343
1387
  #
1344
1388
  # @return [TrueClass, FalseClass]
1345
- # <tt>true</tt> if the URI is absolute.
1346
- # <tt>false</tt> otherwise.
1389
+ # <tt>true</tt> if the URI is absolute. <tt>false</tt> otherwise.
1347
1390
  def absolute?
1348
1391
  return !relative?
1349
1392
  end
@@ -1463,9 +1506,9 @@ module Addressable
1463
1506
 
1464
1507
  ##
1465
1508
  # Merges a URI with a <tt>Hash</tt> of components.
1466
- # This method has different behavior from <tt>join</tt>. Any components
1509
+ # This method has different behavior from <tt>join</tt>. Any components
1467
1510
  # present in the <tt>hash</tt> parameter will override the original
1468
- # components. The path component is not treated specially.
1511
+ # components. The path component is not treated specially.
1469
1512
  #
1470
1513
  # @param [Hash, Addressable::URI, #to_hash] The components to merge with.
1471
1514
  #
@@ -1541,8 +1584,8 @@ module Addressable
1541
1584
 
1542
1585
  ##
1543
1586
  # Returns the shortest normalized relative form of this URI that uses the
1544
- # supplied URI as a base for resolution. Returns an absolute URI if
1545
- # necessary. This is effectively the opposite of <tt>route_to</tt>.
1587
+ # supplied URI as a base for resolution. Returns an absolute URI if
1588
+ # necessary. This is effectively the opposite of <tt>route_to</tt>.
1546
1589
  #
1547
1590
  # @param [String, Addressable::URI, #to_str] uri The URI to route from.
1548
1591
  #
@@ -1599,8 +1642,8 @@ module Addressable
1599
1642
 
1600
1643
  ##
1601
1644
  # Returns the shortest normalized relative form of the supplied URI that
1602
- # uses this URI as a base for resolution. Returns an absolute URI if
1603
- # necessary. This is effectively the opposite of <tt>route_from</tt>.
1645
+ # uses this URI as a base for resolution. Returns an absolute URI if
1646
+ # necessary. This is effectively the opposite of <tt>route_from</tt>.
1604
1647
  #
1605
1648
  # @param [String, Addressable::URI, #to_str] uri The URI to route to.
1606
1649
  #
@@ -1651,7 +1694,7 @@ module Addressable
1651
1694
  end
1652
1695
 
1653
1696
  ##
1654
- # Creates a URI suitable for display to users. If semantic attacks are
1697
+ # Creates a URI suitable for display to users. If semantic attacks are
1655
1698
  # likely, the application should try to detect these and warn the user.
1656
1699
  # See <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>,
1657
1700
  # section 7.6 for more information.
@@ -1664,7 +1707,7 @@ module Addressable
1664
1707
  end
1665
1708
 
1666
1709
  ##
1667
- # Returns <tt>true</tt> if the URI objects are equal. This method
1710
+ # Returns <tt>true</tt> if the URI objects are equal. This method
1668
1711
  # normalizes both URIs before doing the comparison, and allows comparison
1669
1712
  # against <tt>Strings</tt>.
1670
1713
  #
@@ -1686,7 +1729,7 @@ module Addressable
1686
1729
  end
1687
1730
 
1688
1731
  ##
1689
- # Returns <tt>true</tt> if the URI objects are equal. This method
1732
+ # Returns <tt>true</tt> if the URI objects are equal. This method
1690
1733
  # normalizes both URIs before doing the comparison.
1691
1734
  #
1692
1735
  # @param [Object] uri The URI to compare.
@@ -1699,7 +1742,7 @@ module Addressable
1699
1742
  end
1700
1743
 
1701
1744
  ##
1702
- # Returns <tt>true</tt> if the URI objects are equal. This method
1745
+ # Returns <tt>true</tt> if the URI objects are equal. This method
1703
1746
  # does NOT normalize either URI before doing the comparison.
1704
1747
  #
1705
1748
  # @param [Object] uri The URI to compare.
@@ -1746,7 +1789,7 @@ module Addressable
1746
1789
  # Unfortunately, because of the memoized implementation of many of the
1747
1790
  # URI methods, the default freeze method will cause unexpected errors.
1748
1791
  # As an alternative, we freeze the string representation of the URI
1749
- # instead. This should generally produce the desired effect.
1792
+ # instead. This should generally produce the desired effect.
1750
1793
  self.to_s.freeze
1751
1794
  return self
1752
1795
  end
@@ -1823,7 +1866,7 @@ module Addressable
1823
1866
  end
1824
1867
 
1825
1868
  ##
1826
- # URI's are glorified <tt>Strings</tt>. Allow implicit conversion.
1869
+ # URI's are glorified <tt>Strings</tt>. Allow implicit conversion.
1827
1870
  alias_method :to_str, :to_s
1828
1871
 
1829
1872
  ##
@@ -28,7 +28,7 @@ if !defined?(Addressable::VERSION)
28
28
  module VERSION #:nodoc:
29
29
  MAJOR = 2
30
30
  MINOR = 1
31
- TINY = 0
31
+ TINY = 1
32
32
 
33
33
  STRING = [MAJOR, MINOR, TINY].join('.')
34
34
  end
@@ -22,9 +22,6 @@
22
22
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
23
  #++
24
24
 
25
- $:.unshift(File.expand_path(File.dirname(__FILE__) + '/../../lib'))
26
- $:.uniq!
27
-
28
25
  require "addressable/idna"
29
26
 
30
27
  describe Addressable::IDNA, "when converting from unicode to ASCII" do
@@ -22,10 +22,6 @@
22
22
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
23
  #++
24
24
 
25
- $:.unshift(File.expand_path(File.dirname(__FILE__) + '/../../lib'))
26
- $:.uniq!
27
-
28
- require "addressable/uri"
29
25
  require "addressable/template"
30
26
 
31
27
  if !"".respond_to?("force_encoding")
@@ -1341,6 +1337,54 @@ describe Addressable::URI, "when given a simple mapping" do
1341
1337
  end
1342
1338
  end
1343
1339
 
1340
+ describe Addressable::URI, "extracting defaults from a pattern" do
1341
+ before do
1342
+ @template = Addressable::Template.new("{foo}{bar=baz}{-opt|found|cond}")
1343
+ end
1344
+
1345
+ it "should extract default value" do
1346
+ @template.variable_defaults.should == {"bar" => "baz"}
1347
+ end
1348
+ end
1349
+
1350
+ describe Addressable::URI, "when given a mapping with symbol keys" do
1351
+ before do
1352
+ @mapping = { :name => "fred" }
1353
+ end
1354
+
1355
+ it "should result in 'fred' when used to expand '{foo}'" do
1356
+ Addressable::Template.new(
1357
+ "{name}"
1358
+ ).expand(@mapping).to_s.should == "fred"
1359
+ end
1360
+ end
1361
+
1362
+ describe Addressable::URI, "when given a mapping with bogus keys" do
1363
+ before do
1364
+ @mapping = { Object.new => "fred" }
1365
+ end
1366
+
1367
+ it "should raise an error" do
1368
+ (lambda do
1369
+ Addressable::Template.new(
1370
+ "{name}"
1371
+ ).expand(@mapping)
1372
+ end).should raise_error(TypeError)
1373
+ end
1374
+ end
1375
+
1376
+ describe Addressable::URI, "when given a mapping with numeric values" do
1377
+ before do
1378
+ @mapping = { :id => 123 }
1379
+ end
1380
+
1381
+ it "should result in 'fred' when used to expand '{foo}'" do
1382
+ Addressable::Template.new(
1383
+ "{id}"
1384
+ ).expand(@mapping).to_s.should == "123"
1385
+ end
1386
+ end
1387
+
1344
1388
  describe Addressable::URI, "when given a mapping containing values " +
1345
1389
  "that are already percent-encoded" do
1346
1390
  before do
@@ -1357,18 +1401,6 @@ describe Addressable::URI, "when given a mapping containing values " +
1357
1401
  end
1358
1402
  end
1359
1403
 
1360
- describe Addressable::URI, "when given a mapping containing bogus values" do
1361
- it "should raise a TypeError" do
1362
- (lambda do
1363
- Addressable::Template.new(
1364
- "http://example.com/{bogus}/"
1365
- ).expand({
1366
- "bogus" => 42
1367
- })
1368
- end).should raise_error(TypeError)
1369
- end
1370
- end
1371
-
1372
1404
  describe Addressable::URI, "when given a pattern with bogus operators" do
1373
1405
  it "should raise an InvalidTemplateOperatorError" do
1374
1406
  (lambda do
@@ -22,9 +22,6 @@
22
22
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
23
  #++
24
24
 
25
- $:.unshift(File.expand_path(File.dirname(__FILE__) + '/../../lib'))
26
- $:.uniq!
27
-
28
25
  require "addressable/uri"
29
26
 
30
27
  if !"".respond_to?("force_encoding")
@@ -72,6 +69,86 @@ describe Addressable::URI, "when created with a non-numeric port number" do
72
69
  end
73
70
  end
74
71
 
72
+ describe Addressable::URI, "when created with a non-string scheme" do
73
+ it "should raise an error" do
74
+ (lambda do
75
+ Addressable::URI.new(:scheme => :bogus)
76
+ end).should raise_error(TypeError)
77
+ end
78
+ end
79
+
80
+ describe Addressable::URI, "when created with a non-string user" do
81
+ it "should raise an error" do
82
+ (lambda do
83
+ Addressable::URI.new(:user => :bogus)
84
+ end).should raise_error(TypeError)
85
+ end
86
+ end
87
+
88
+ describe Addressable::URI, "when created with a non-string password" do
89
+ it "should raise an error" do
90
+ (lambda do
91
+ Addressable::URI.new(:password => :bogus)
92
+ end).should raise_error(TypeError)
93
+ end
94
+ end
95
+
96
+ describe Addressable::URI, "when created with a non-string userinfo" do
97
+ it "should raise an error" do
98
+ (lambda do
99
+ Addressable::URI.new(:userinfo => :bogus)
100
+ end).should raise_error(TypeError)
101
+ end
102
+ end
103
+
104
+ describe Addressable::URI, "when created with a non-string host" do
105
+ it "should raise an error" do
106
+ (lambda do
107
+ Addressable::URI.new(:host => :bogus)
108
+ end).should raise_error(TypeError)
109
+ end
110
+ end
111
+
112
+ describe Addressable::URI, "when created with a non-string authority" do
113
+ it "should raise an error" do
114
+ (lambda do
115
+ Addressable::URI.new(:authority => :bogus)
116
+ end).should raise_error(TypeError)
117
+ end
118
+ end
119
+
120
+ describe Addressable::URI, "when created with a non-string authority" do
121
+ it "should raise an error" do
122
+ (lambda do
123
+ Addressable::URI.new(:authority => :bogus)
124
+ end).should raise_error(TypeError)
125
+ end
126
+ end
127
+
128
+ describe Addressable::URI, "when created with a non-string path" do
129
+ it "should raise an error" do
130
+ (lambda do
131
+ Addressable::URI.new(:path => :bogus)
132
+ end).should raise_error(TypeError)
133
+ end
134
+ end
135
+
136
+ describe Addressable::URI, "when created with a non-string query" do
137
+ it "should raise an error" do
138
+ (lambda do
139
+ Addressable::URI.new(:query => :bogus)
140
+ end).should raise_error(TypeError)
141
+ end
142
+ end
143
+
144
+ describe Addressable::URI, "when created with a non-string fragment" do
145
+ it "should raise an error" do
146
+ (lambda do
147
+ Addressable::URI.new(:fragment => :bogus)
148
+ end).should raise_error(TypeError)
149
+ end
150
+ end
151
+
75
152
  describe Addressable::URI, "when created with a scheme but no hierarchical " +
76
153
  "segment" do
77
154
  it "should raise an error" do
@@ -944,6 +1021,54 @@ describe Addressable::URI, "when parsed from " +
944
1021
  end
945
1022
  end
946
1023
 
1024
+ describe Addressable::URI, "when parsed from " +
1025
+ "'http://example.com/?%F6'" do
1026
+ before do
1027
+ @uri = Addressable::URI.parse("http://example.com/?%F6")
1028
+ end
1029
+
1030
+ it "should not raise an exception when normalized" do
1031
+ (lambda do
1032
+ @uri.normalize
1033
+ end).should_not raise_error(ArgumentError)
1034
+ end
1035
+
1036
+ it "should be considered to be in normal form" do
1037
+ @uri.normalize.should be_eql(@uri)
1038
+ end
1039
+
1040
+ it "should not change if encoded with the normalizing algorithm" do
1041
+ Addressable::URI.normalized_encode(@uri).to_s.should ==
1042
+ "http://example.com/?%F6"
1043
+ Addressable::URI.normalized_encode(@uri, Addressable::URI).to_s.should ===
1044
+ "http://example.com/?%F6"
1045
+ end
1046
+ end
1047
+
1048
+ describe Addressable::URI, "when parsed from " +
1049
+ "'http://example.com/#%F6'" do
1050
+ before do
1051
+ @uri = Addressable::URI.parse("http://example.com/#%F6")
1052
+ end
1053
+
1054
+ it "should not raise an exception when normalized" do
1055
+ (lambda do
1056
+ @uri.normalize
1057
+ end).should_not raise_error(ArgumentError)
1058
+ end
1059
+
1060
+ it "should be considered to be in normal form" do
1061
+ @uri.normalize.should be_eql(@uri)
1062
+ end
1063
+
1064
+ it "should not change if encoded with the normalizing algorithm" do
1065
+ Addressable::URI.normalized_encode(@uri).to_s.should ==
1066
+ "http://example.com/#%F6"
1067
+ Addressable::URI.normalized_encode(@uri, Addressable::URI).to_s.should ===
1068
+ "http://example.com/#%F6"
1069
+ end
1070
+ end
1071
+
947
1072
  describe Addressable::URI, "when parsed from " +
948
1073
  "'http://example.com/%C3%87'" do
949
1074
  before do
@@ -1,14 +1,10 @@
1
- require 'spec/rake/verify_rcov'
2
-
3
1
  namespace :spec do
4
2
  Spec::Rake::SpecTask.new(:rcov) do |t|
3
+ t.libs = %w[lib spec]
5
4
  t.spec_files = FileList['spec/**/*_spec.rb']
6
5
  t.spec_opts = ['--color', '--format', 'specdoc']
7
- if RCOV_ENABLED
8
- t.rcov = true
9
- else
10
- t.rcov = false
11
- end
6
+
7
+ t.rcov = RCOV_ENABLED
12
8
  t.rcov_opts = [
13
9
  '--exclude', 'spec',
14
10
  '--exclude', '1\\.8\\/gems',
@@ -18,27 +14,19 @@ namespace :spec do
18
14
  end
19
15
 
20
16
  Spec::Rake::SpecTask.new(:normal) do |t|
17
+ t.libs = %w[lib spec]
21
18
  t.spec_files = FileList['spec/**/*_spec.rb']
22
19
  t.spec_opts = ['--color', '--format', 'specdoc']
23
20
  t.rcov = false
24
21
  end
25
22
 
26
- if RCOV_ENABLED
27
- RCov::VerifyTask.new(:verify) do |t|
28
- t.threshold = 100.0
29
- t.index_html = 'coverage/index.html'
30
- end
31
-
32
- task :verify => :rcov
33
- end
34
-
35
23
  desc "Generate HTML Specdocs for all specs"
36
24
  Spec::Rake::SpecTask.new(:specdoc) do |t|
37
- specdoc_path = File.expand_path(
38
- File.join(File.dirname(__FILE__), '../specdoc/'))
25
+ specdoc_path = File.expand_path(File.join(File.dirname(__FILE__), '..', 'specdoc'))
39
26
  Dir.mkdir(specdoc_path) if !File.exist?(specdoc_path)
40
27
 
41
28
  output_file = File.join(specdoc_path, 'index.html')
29
+ t.libs = %w[lib spec]
42
30
  t.spec_files = FileList['spec/**/*_spec.rb']
43
31
  t.spec_opts = ["--format", "\"html:#{output_file}\"", "--diff"]
44
32
  t.fail_on_error = false
@@ -53,12 +41,7 @@ namespace :spec do
53
41
  end
54
42
  end
55
43
 
56
- if RCOV_ENABLED
57
- desc "Alias to spec:verify"
58
- task "spec" => "spec:verify"
59
- else
60
- desc "Alias to spec:normal"
61
- task "spec" => "spec:normal"
62
- end
44
+ desc "Alias to spec:normal"
45
+ task "spec" => "spec:normal"
63
46
 
64
47
  task "clobber" => ["spec:clobber_rcov"]
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: addressable
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 2.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bob Aman
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-05-19 00:00:00 -04:00
12
+ date: 2009-10-31 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -42,7 +42,11 @@ dependencies:
42
42
  - !ruby/object:Gem::Version
43
43
  version: 0.3.2
44
44
  version:
45
- description: Addressable is a replacement for the URI implementation that is part of Ruby's standard library. It more closely conforms to the relevant RFCs and adds support for IRIs and URI templates.
45
+ description: |
46
+ Addressable is a replacement for the URI implementation that is part of
47
+ Ruby's standard library. It more closely conforms to the relevant RFCs and
48
+ adds support for IRIs and URI templates.
49
+
46
50
  email: bob@sporkmonger.com
47
51
  executables: []
48
52
 
@@ -51,16 +55,13 @@ extensions: []
51
55
  extra_rdoc_files:
52
56
  - README
53
57
  files:
54
- - lib/addressable
55
58
  - lib/addressable/idna.rb
56
59
  - lib/addressable/template.rb
57
60
  - lib/addressable/uri.rb
58
61
  - lib/addressable/version.rb
59
- - spec/addressable
60
62
  - spec/addressable/idna_spec.rb
61
63
  - spec/addressable/template_spec.rb
62
64
  - spec/addressable/uri_spec.rb
63
- - spec/data
64
65
  - spec/data/rfc3986.txt
65
66
  - tasks/clobber.rake
66
67
  - tasks/gem.rake
@@ -76,6 +77,8 @@ files:
76
77
  - README
77
78
  has_rdoc: true
78
79
  homepage: http://addressable.rubyforge.org/
80
+ licenses: []
81
+
79
82
  post_install_message:
80
83
  rdoc_options:
81
84
  - --main
@@ -97,9 +100,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
97
100
  requirements: []
98
101
 
99
102
  rubyforge_project: addressable
100
- rubygems_version: 1.3.1
103
+ rubygems_version: 1.3.5
101
104
  signing_key:
102
- specification_version: 2
105
+ specification_version: 3
103
106
  summary: URI Implementation
104
107
  test_files: []
105
108