addressable 2.3.3 → 2.3.4
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of addressable might be problematic. Click here for more details.
- data/CHANGELOG.md +6 -0
- data/README.md +63 -52
- data/lib/addressable/idna/pure.rb +15 -4
- data/lib/addressable/template.rb +68 -0
- data/lib/addressable/uri.rb +9 -4
- data/lib/addressable/version.rb +1 -1
- data/spec/addressable/idna_spec.rb +5 -0
- data/spec/addressable/template_spec.rb +74 -0
- data/spec/addressable/uri_spec.rb +536 -1
- metadata +2 -2
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
# Addressable 2.3.4
|
2
|
+
- fixed issue with encoding altering its inputs
|
3
|
+
- query string normalization now leaves ';' characters alone
|
4
|
+
- FakeFS is detected before attempting to load unicode tables
|
5
|
+
- additional testing to ensure frozen objects don't cause problems
|
6
|
+
|
1
7
|
# Addressable 2.3.3
|
2
8
|
- fixed issue with converting common primitives during template expansion
|
3
9
|
- fixed port encoding issue
|
data/README.md
CHANGED
@@ -20,68 +20,79 @@ RFC 6570 (level 4), providing support for IRIs and URI templates.
|
|
20
20
|
|
21
21
|
- {Addressable::URI}
|
22
22
|
- {Addressable::Template}
|
23
|
-
- {Addressable::UriTemplate}
|
24
23
|
|
25
24
|
# Example usage
|
26
25
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
26
|
+
```ruby
|
27
|
+
require "addressable/uri"
|
28
|
+
|
29
|
+
uri = Addressable::URI.parse("http://example.com/path/to/resource/")
|
30
|
+
uri.scheme
|
31
|
+
#=> "http"
|
32
|
+
uri.host
|
33
|
+
#=> "example.com"
|
34
|
+
uri.path
|
35
|
+
#=> "/path/to/resource/"
|
36
|
+
|
37
|
+
uri = Addressable::URI.parse("http://www.詹姆斯.com/")
|
38
|
+
uri.normalize
|
39
|
+
#=> #<Addressable::URI:0xc9a4c8 URI:http://www.xn--8ws00zhy3a.com/>
|
40
|
+
```
|
41
|
+
|
42
|
+
|
43
|
+
# URI Templates
|
44
|
+
|
45
|
+
For more details, see [RFC 6570](https://www.rfc-editor.org/rfc/rfc6570.txt).
|
46
|
+
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
|
50
|
+
require "addressable/template"
|
51
|
+
|
52
|
+
template = Addressable::Template.new("http://example.com/{?query*}/")
|
53
|
+
template.expand({
|
54
|
+
"query" => {
|
55
|
+
'foo' => 'bar',
|
56
|
+
'color' => 'red'
|
57
|
+
}
|
58
|
+
})
|
59
|
+
#=> #<Addressable::URI:0xc9d95c URI:http://example.com/?foo=bar&color=red>
|
60
|
+
|
61
|
+
template = Addressable::Template.new("http://example.com/{?one,two,three}/")
|
62
|
+
template.partial_expand({"one" => "1", "three" => 3}).pattern
|
63
|
+
#=> "http://example.com/?one=1{&two}&three=3"
|
64
|
+
|
65
|
+
template = Addressable::Template.new(
|
66
|
+
"http://{host}{/segments}/{?one,two,bogus}{#fragment}"
|
67
|
+
)
|
68
|
+
uri = Addressable::URI.parse(
|
69
|
+
"http://example.com/a/b/c/?one=1&two=2#foo"
|
70
|
+
)
|
71
|
+
template.extract(uri)
|
72
|
+
#=>
|
73
|
+
# {
|
74
|
+
# "host" => "example.com",
|
75
|
+
# "segments" => ["a", "b", "c"],
|
76
|
+
# "one" => "1",
|
77
|
+
# "two" => "2",
|
78
|
+
# "fragment" => "foo"
|
79
|
+
# }
|
80
|
+
```
|
74
81
|
|
75
82
|
# Install
|
76
83
|
|
77
|
-
|
84
|
+
```console
|
85
|
+
$ sudo gem install addressable
|
86
|
+
```
|
78
87
|
|
79
88
|
You may optionally turn on native IDN support by installing libidn and the
|
80
89
|
idn gem:
|
81
90
|
|
82
|
-
|
83
|
-
|
84
|
-
|
91
|
+
```console
|
92
|
+
$ sudo apt-get install idn # Debian/Ubuntu
|
93
|
+
$ sudo brew install libidn # OS X
|
94
|
+
$ sudo gem install idn
|
95
|
+
```
|
85
96
|
|
86
97
|
**NOTE:** Native IDN support appears to be broken in Ruby 1.9.x. The IDN gem
|
87
98
|
hasn't been updated in years.
|
@@ -106,6 +106,7 @@ module Addressable
|
|
106
106
|
|
107
107
|
# Unicode normalization form KC.
|
108
108
|
def self.unicode_normalize_kc(input)
|
109
|
+
input = input.to_s unless input.is_a?(String)
|
109
110
|
unpacked = input.unpack("U*")
|
110
111
|
unpacked =
|
111
112
|
unicode_compose(unicode_sort_canonical(unicode_decompose(unpacked)))
|
@@ -317,10 +318,20 @@ module Addressable
|
|
317
318
|
UNICODE_DATA_LOWERCASE = 5
|
318
319
|
UNICODE_DATA_TITLECASE = 6
|
319
320
|
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
321
|
+
begin
|
322
|
+
if defined?(FakeFS)
|
323
|
+
fakefs_state = FakeFS.activated?
|
324
|
+
FakeFS.deactivate!
|
325
|
+
end
|
326
|
+
# This is a sparse Unicode table. Codepoints without entries are
|
327
|
+
# assumed to have the value: [0, 0, nil, nil, nil, nil, nil]
|
328
|
+
UNICODE_DATA = File.open(UNICODE_TABLE, "rb") do |file|
|
329
|
+
Marshal.load(file.read)
|
330
|
+
end
|
331
|
+
ensure
|
332
|
+
if defined?(FakeFS)
|
333
|
+
FakeFS.activate! if fakefs_state
|
334
|
+
end
|
324
335
|
end
|
325
336
|
|
326
337
|
COMPOSITION_TABLE = {}
|
data/lib/addressable/template.rb
CHANGED
@@ -132,6 +132,7 @@ module Addressable
|
|
132
132
|
self.template.variables
|
133
133
|
end
|
134
134
|
alias_method :keys, :variables
|
135
|
+
alias_method :names, :variables
|
135
136
|
|
136
137
|
##
|
137
138
|
# @return [Array]
|
@@ -146,6 +147,64 @@ module Addressable
|
|
146
147
|
end
|
147
148
|
alias_method :captures, :values
|
148
149
|
|
150
|
+
##
|
151
|
+
# Accesses captured values by name or by index.
|
152
|
+
#
|
153
|
+
# @param [String, Symbol, Fixnum] key
|
154
|
+
# Capture index or name. Note that when accessing by with index
|
155
|
+
# of 0, the full URI will be returned. The intention is to mimic
|
156
|
+
# the ::MatchData#[] behavior.
|
157
|
+
#
|
158
|
+
# @param [#to_int, nil] len
|
159
|
+
# If provided, an array of values will be returend with the given
|
160
|
+
# parameter used as length.
|
161
|
+
#
|
162
|
+
# @return [Array, String, nil]
|
163
|
+
# The captured value corresponding to the index or name. If the
|
164
|
+
# value was not provided or the key is unknown, nil will be
|
165
|
+
# returned.
|
166
|
+
#
|
167
|
+
# If the second parameter is provided, an array of that length will
|
168
|
+
# be returned instead.
|
169
|
+
def [](key, len = nil)
|
170
|
+
if len
|
171
|
+
to_a[key, len]
|
172
|
+
elsif String === key or Symbol === key
|
173
|
+
mapping[key.to_s]
|
174
|
+
else
|
175
|
+
to_a[key]
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
##
|
180
|
+
# @return [Array]
|
181
|
+
# Array with the matched URI as first element followed by the captured
|
182
|
+
# values.
|
183
|
+
def to_a
|
184
|
+
[to_s, *values]
|
185
|
+
end
|
186
|
+
|
187
|
+
##
|
188
|
+
# @return [String]
|
189
|
+
# The matched URI as String.
|
190
|
+
def to_s
|
191
|
+
uri.to_s
|
192
|
+
end
|
193
|
+
alias_method :string, :to_s
|
194
|
+
|
195
|
+
# Returns multiple captured values at once.
|
196
|
+
#
|
197
|
+
# @param [String, Symbol, Fixnum] *indexes
|
198
|
+
# Indices of the captures to be returned
|
199
|
+
#
|
200
|
+
# @return [Array]
|
201
|
+
# Values corresponding to given indices.
|
202
|
+
#
|
203
|
+
# @see Addressable::Template::MatchData#[]
|
204
|
+
def values_at(*indexes)
|
205
|
+
indexes.map { |i| self[i] }
|
206
|
+
end
|
207
|
+
|
149
208
|
##
|
150
209
|
# Returns a <tt>String</tt> representation of the MatchData's state.
|
151
210
|
#
|
@@ -154,6 +213,15 @@ module Addressable
|
|
154
213
|
sprintf("#<%s:%#0x RESULT:%s>",
|
155
214
|
self.class.to_s, self.object_id, self.mapping.inspect)
|
156
215
|
end
|
216
|
+
|
217
|
+
##
|
218
|
+
# Dummy method for code expecting a ::MatchData instance
|
219
|
+
#
|
220
|
+
# @return [String] An empty string.
|
221
|
+
def pre_match
|
222
|
+
""
|
223
|
+
end
|
224
|
+
alias_method :post_match, :pre_match
|
157
225
|
end
|
158
226
|
|
159
227
|
##
|
data/lib/addressable/uri.rb
CHANGED
@@ -363,11 +363,12 @@ module Addressable
|
|
363
363
|
component = component.dup
|
364
364
|
component.force_encoding(Encoding::ASCII_8BIT)
|
365
365
|
end
|
366
|
-
|
366
|
+
# Avoiding gsub! because there are edge cases with frozen strings
|
367
|
+
component = component.gsub(character_class) do |sequence|
|
367
368
|
(sequence.unpack('C*').map { |c| "%" + ("%02x" % c).upcase }).join
|
368
369
|
end
|
369
370
|
if upcase_encoded.length > 0
|
370
|
-
component.gsub
|
371
|
+
component = component.gsub(/%(#{upcase_encoded.chars.map do |char|
|
371
372
|
char.unpack('C*').map { |c| '%02x' % c }.join
|
372
373
|
end.join('|')})/i) { |s| s.upcase }
|
373
374
|
end
|
@@ -1430,10 +1431,14 @@ module Addressable
|
|
1430
1431
|
# @return [String] The query component, normalized.
|
1431
1432
|
def normalized_query
|
1432
1433
|
self.query && @normalized_query ||= (begin
|
1434
|
+
modified_query_class = Addressable::URI::CharacterClasses::QUERY
|
1435
|
+
# Make sure possible key-value pair delimiters are escaped.
|
1436
|
+
modified_query_class = modified_query_class.sub("\\&", "")
|
1437
|
+
modified_query_class = modified_query_class.sub("\\;", "")
|
1433
1438
|
(self.query.split("&", -1).map do |pair|
|
1434
1439
|
Addressable::URI.normalize_component(
|
1435
1440
|
pair,
|
1436
|
-
|
1441
|
+
modified_query_class,
|
1437
1442
|
'+'
|
1438
1443
|
)
|
1439
1444
|
end).join("&")
|
@@ -1907,7 +1912,7 @@ module Addressable
|
|
1907
1912
|
end
|
1908
1913
|
else
|
1909
1914
|
if uri.path != SLASH
|
1910
|
-
components[:path].gsub
|
1915
|
+
components[:path] = components[:path].gsub(
|
1911
1916
|
Regexp.new("^" + Regexp.escape(uri.path)), EMPTY_STR)
|
1912
1917
|
end
|
1913
1918
|
end
|
data/lib/addressable/version.rb
CHANGED
@@ -186,6 +186,11 @@ shared_examples_for "converting from ASCII to unicode" do
|
|
186
186
|
"xn--4ud"
|
187
187
|
).should == "\341\206\265"
|
188
188
|
end
|
189
|
+
|
190
|
+
it "should normalize 'string' correctly" do
|
191
|
+
Addressable::IDNA.unicode_normalize_kc(:'string').should == "string"
|
192
|
+
Addressable::IDNA.unicode_normalize_kc("string").should == "string"
|
193
|
+
end
|
189
194
|
end
|
190
195
|
|
191
196
|
describe Addressable::IDNA, "when using the pure-Ruby implementation" do
|
@@ -1020,3 +1020,77 @@ describe Addressable::Template do
|
|
1020
1020
|
end
|
1021
1021
|
end
|
1022
1022
|
end
|
1023
|
+
|
1024
|
+
describe Addressable::Template::MatchData do
|
1025
|
+
let(:template) { Addressable::Template.new('{foo}/{bar}') }
|
1026
|
+
subject(:its) { template.match('ab/cd') }
|
1027
|
+
its(:uri) { should == Addressable::URI.parse('ab/cd') }
|
1028
|
+
its(:template) { should == template }
|
1029
|
+
its(:mapping) { should == { 'foo' => 'ab', 'bar' => 'cd' } }
|
1030
|
+
its(:variables) { should == ['foo', 'bar'] }
|
1031
|
+
its(:keys) { should == its.variables }
|
1032
|
+
its(:names) { should == its.variables }
|
1033
|
+
its(:values) { should == ['ab', 'cd'] }
|
1034
|
+
its(:captures) { should == its.values }
|
1035
|
+
its(:to_a) { should == ['ab/cd', 'ab', 'cd'] }
|
1036
|
+
its(:to_s) { should == 'ab/cd' }
|
1037
|
+
its(:string) { should == its.to_s }
|
1038
|
+
its(:pre_match) { should == "" }
|
1039
|
+
its(:post_match) { should == "" }
|
1040
|
+
|
1041
|
+
describe 'values_at' do
|
1042
|
+
it 'returns an array with the values' do
|
1043
|
+
its.values_at(0, 2).should == ['ab/cd', 'cd']
|
1044
|
+
end
|
1045
|
+
it 'allows mixing integer an string keys' do
|
1046
|
+
its.values_at('foo', 1).should == ['ab', 'ab']
|
1047
|
+
end
|
1048
|
+
it 'accepts unknown keys' do
|
1049
|
+
its.values_at('baz', 'foo').should == [nil, 'ab']
|
1050
|
+
end
|
1051
|
+
end
|
1052
|
+
|
1053
|
+
describe '[]' do
|
1054
|
+
context 'string key' do
|
1055
|
+
it 'returns the corresponding capture' do
|
1056
|
+
its['foo'].should == 'ab'
|
1057
|
+
its['bar'].should == 'cd'
|
1058
|
+
end
|
1059
|
+
it 'returns nil for unknown keys' do
|
1060
|
+
its['baz'].should be_nil
|
1061
|
+
end
|
1062
|
+
end
|
1063
|
+
context 'symbol key' do
|
1064
|
+
it 'returns the corresponding capture' do
|
1065
|
+
its[:foo].should == 'ab'
|
1066
|
+
its[:bar].should == 'cd'
|
1067
|
+
end
|
1068
|
+
it 'returns nil for unknown keys' do
|
1069
|
+
its[:baz].should be_nil
|
1070
|
+
end
|
1071
|
+
end
|
1072
|
+
context 'integer key' do
|
1073
|
+
it 'returns the full URI for index 0' do
|
1074
|
+
its[0].should == 'ab/cd'
|
1075
|
+
end
|
1076
|
+
it 'returns the corresponding capture' do
|
1077
|
+
its[1].should == 'ab'
|
1078
|
+
its[2].should == 'cd'
|
1079
|
+
end
|
1080
|
+
it 'returns nil for unknown keys' do
|
1081
|
+
its[3].should be_nil
|
1082
|
+
end
|
1083
|
+
end
|
1084
|
+
context 'other key' do
|
1085
|
+
it 'raises an exception' do
|
1086
|
+
expect { its[Object.new] }.to raise_error(TypeError)
|
1087
|
+
end
|
1088
|
+
end
|
1089
|
+
context 'with length' do
|
1090
|
+
it 'returns an array starting at index with given length' do
|
1091
|
+
its[0, 2].should == ['ab/cd', 'ab']
|
1092
|
+
its[2, 1].should == ['cd']
|
1093
|
+
end
|
1094
|
+
end
|
1095
|
+
end
|
1096
|
+
end
|
@@ -218,6 +218,373 @@ describe Addressable::URI, "when created from nil components" do
|
|
218
218
|
end
|
219
219
|
end
|
220
220
|
|
221
|
+
describe Addressable::URI, "when initialized from individual components" do
|
222
|
+
before do
|
223
|
+
@uri = Addressable::URI.new(
|
224
|
+
:scheme => "http",
|
225
|
+
:user => "user",
|
226
|
+
:password => "password",
|
227
|
+
:host => "example.com",
|
228
|
+
:port => 8080,
|
229
|
+
:path => "/path",
|
230
|
+
:query => "query=value",
|
231
|
+
:fragment => "fragment"
|
232
|
+
)
|
233
|
+
end
|
234
|
+
|
235
|
+
it "returns 'http' for #scheme" do
|
236
|
+
@uri.scheme.should == "http"
|
237
|
+
end
|
238
|
+
|
239
|
+
it "returns 'http' for #normalized_scheme" do
|
240
|
+
@uri.normalized_scheme.should == "http"
|
241
|
+
end
|
242
|
+
|
243
|
+
it "returns 'user' for #user" do
|
244
|
+
@uri.user.should == "user"
|
245
|
+
end
|
246
|
+
|
247
|
+
it "returns 'user' for #normalized_user" do
|
248
|
+
@uri.normalized_user.should == "user"
|
249
|
+
end
|
250
|
+
|
251
|
+
it "returns 'password' for #password" do
|
252
|
+
@uri.password.should == "password"
|
253
|
+
end
|
254
|
+
|
255
|
+
it "returns 'password' for #normalized_password" do
|
256
|
+
@uri.normalized_password.should == "password"
|
257
|
+
end
|
258
|
+
|
259
|
+
it "returns 'user:password' for #userinfo" do
|
260
|
+
@uri.userinfo.should == "user:password"
|
261
|
+
end
|
262
|
+
|
263
|
+
it "returns 'user:password' for #normalized_userinfo" do
|
264
|
+
@uri.normalized_userinfo.should == "user:password"
|
265
|
+
end
|
266
|
+
|
267
|
+
it "returns 'example.com' for #host" do
|
268
|
+
@uri.host.should == "example.com"
|
269
|
+
end
|
270
|
+
|
271
|
+
it "returns 'example.com' for #normalized_host" do
|
272
|
+
@uri.normalized_host.should == "example.com"
|
273
|
+
end
|
274
|
+
|
275
|
+
it "returns 'user:password@example.com:8080' for #authority" do
|
276
|
+
@uri.authority.should == "user:password@example.com:8080"
|
277
|
+
end
|
278
|
+
|
279
|
+
it "returns 'user:password@example.com:8080' for #normalized_authority" do
|
280
|
+
@uri.normalized_authority.should == "user:password@example.com:8080"
|
281
|
+
end
|
282
|
+
|
283
|
+
it "returns 8080 for #port" do
|
284
|
+
@uri.port.should == 8080
|
285
|
+
end
|
286
|
+
|
287
|
+
it "returns 8080 for #normalized_port" do
|
288
|
+
@uri.normalized_port.should == 8080
|
289
|
+
end
|
290
|
+
|
291
|
+
it "returns 80 for #default_port" do
|
292
|
+
@uri.default_port.should == 80
|
293
|
+
end
|
294
|
+
|
295
|
+
it "returns 'http://user:password@example.com:8080' for #site" do
|
296
|
+
@uri.site.should == "http://user:password@example.com:8080"
|
297
|
+
end
|
298
|
+
|
299
|
+
it "returns 'http://user:password@example.com:8080' for #normalized_site" do
|
300
|
+
@uri.normalized_site.should == "http://user:password@example.com:8080"
|
301
|
+
end
|
302
|
+
|
303
|
+
it "returns '/path' for #path" do
|
304
|
+
@uri.path.should == "/path"
|
305
|
+
end
|
306
|
+
|
307
|
+
it "returns '/path' for #normalized_path" do
|
308
|
+
@uri.normalized_path.should == "/path"
|
309
|
+
end
|
310
|
+
|
311
|
+
it "returns 'query=value' for #query" do
|
312
|
+
@uri.query.should == "query=value"
|
313
|
+
end
|
314
|
+
|
315
|
+
it "returns 'query=value' for #normalized_query" do
|
316
|
+
@uri.normalized_query.should == "query=value"
|
317
|
+
end
|
318
|
+
|
319
|
+
it "returns 'fragment' for #fragment" do
|
320
|
+
@uri.fragment.should == "fragment"
|
321
|
+
end
|
322
|
+
|
323
|
+
it "returns 'fragment' for #normalized_fragment" do
|
324
|
+
@uri.normalized_fragment.should == "fragment"
|
325
|
+
end
|
326
|
+
|
327
|
+
it "returns #hash" do
|
328
|
+
@uri.hash.should_not be nil
|
329
|
+
end
|
330
|
+
|
331
|
+
it "returns #to_s" do
|
332
|
+
@uri.to_s.should ==
|
333
|
+
"http://user:password@example.com:8080/path?query=value#fragment"
|
334
|
+
end
|
335
|
+
|
336
|
+
it "should not be frozen" do
|
337
|
+
@uri.should_not be_frozen
|
338
|
+
end
|
339
|
+
|
340
|
+
|
341
|
+
it "should allow destructive operations" do
|
342
|
+
expect { @uri.normalize! }.not_to raise_error
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
describe Addressable::URI, "when initialized from " +
|
347
|
+
"frozen individual components" do
|
348
|
+
before do
|
349
|
+
@uri = Addressable::URI.new(
|
350
|
+
:scheme => "http".freeze,
|
351
|
+
:user => "user".freeze,
|
352
|
+
:password => "password".freeze,
|
353
|
+
:host => "example.com".freeze,
|
354
|
+
:port => "8080".freeze,
|
355
|
+
:path => "/path".freeze,
|
356
|
+
:query => "query=value".freeze,
|
357
|
+
:fragment => "fragment".freeze
|
358
|
+
)
|
359
|
+
end
|
360
|
+
|
361
|
+
it "returns 'http' for #scheme" do
|
362
|
+
@uri.scheme.should == "http"
|
363
|
+
end
|
364
|
+
|
365
|
+
it "returns 'http' for #normalized_scheme" do
|
366
|
+
@uri.normalized_scheme.should == "http"
|
367
|
+
end
|
368
|
+
|
369
|
+
it "returns 'user' for #user" do
|
370
|
+
@uri.user.should == "user"
|
371
|
+
end
|
372
|
+
|
373
|
+
it "returns 'user' for #normalized_user" do
|
374
|
+
@uri.normalized_user.should == "user"
|
375
|
+
end
|
376
|
+
|
377
|
+
it "returns 'password' for #password" do
|
378
|
+
@uri.password.should == "password"
|
379
|
+
end
|
380
|
+
|
381
|
+
it "returns 'password' for #normalized_password" do
|
382
|
+
@uri.normalized_password.should == "password"
|
383
|
+
end
|
384
|
+
|
385
|
+
it "returns 'user:password' for #userinfo" do
|
386
|
+
@uri.userinfo.should == "user:password"
|
387
|
+
end
|
388
|
+
|
389
|
+
it "returns 'user:password' for #normalized_userinfo" do
|
390
|
+
@uri.normalized_userinfo.should == "user:password"
|
391
|
+
end
|
392
|
+
|
393
|
+
it "returns 'example.com' for #host" do
|
394
|
+
@uri.host.should == "example.com"
|
395
|
+
end
|
396
|
+
|
397
|
+
it "returns 'example.com' for #normalized_host" do
|
398
|
+
@uri.normalized_host.should == "example.com"
|
399
|
+
end
|
400
|
+
|
401
|
+
it "returns 'user:password@example.com:8080' for #authority" do
|
402
|
+
@uri.authority.should == "user:password@example.com:8080"
|
403
|
+
end
|
404
|
+
|
405
|
+
it "returns 'user:password@example.com:8080' for #normalized_authority" do
|
406
|
+
@uri.normalized_authority.should == "user:password@example.com:8080"
|
407
|
+
end
|
408
|
+
|
409
|
+
it "returns 8080 for #port" do
|
410
|
+
@uri.port.should == 8080
|
411
|
+
end
|
412
|
+
|
413
|
+
it "returns 8080 for #normalized_port" do
|
414
|
+
@uri.normalized_port.should == 8080
|
415
|
+
end
|
416
|
+
|
417
|
+
it "returns 80 for #default_port" do
|
418
|
+
@uri.default_port.should == 80
|
419
|
+
end
|
420
|
+
|
421
|
+
it "returns 'http://user:password@example.com:8080' for #site" do
|
422
|
+
@uri.site.should == "http://user:password@example.com:8080"
|
423
|
+
end
|
424
|
+
|
425
|
+
it "returns 'http://user:password@example.com:8080' for #normalized_site" do
|
426
|
+
@uri.normalized_site.should == "http://user:password@example.com:8080"
|
427
|
+
end
|
428
|
+
|
429
|
+
it "returns '/path' for #path" do
|
430
|
+
@uri.path.should == "/path"
|
431
|
+
end
|
432
|
+
|
433
|
+
it "returns '/path' for #normalized_path" do
|
434
|
+
@uri.normalized_path.should == "/path"
|
435
|
+
end
|
436
|
+
|
437
|
+
it "returns 'query=value' for #query" do
|
438
|
+
@uri.query.should == "query=value"
|
439
|
+
end
|
440
|
+
|
441
|
+
it "returns 'query=value' for #normalized_query" do
|
442
|
+
@uri.normalized_query.should == "query=value"
|
443
|
+
end
|
444
|
+
|
445
|
+
it "returns 'fragment' for #fragment" do
|
446
|
+
@uri.fragment.should == "fragment"
|
447
|
+
end
|
448
|
+
|
449
|
+
it "returns 'fragment' for #normalized_fragment" do
|
450
|
+
@uri.normalized_fragment.should == "fragment"
|
451
|
+
end
|
452
|
+
|
453
|
+
it "returns #hash" do
|
454
|
+
@uri.hash.should_not be nil
|
455
|
+
end
|
456
|
+
|
457
|
+
it "returns #to_s" do
|
458
|
+
@uri.to_s.should ==
|
459
|
+
"http://user:password@example.com:8080/path?query=value#fragment"
|
460
|
+
end
|
461
|
+
|
462
|
+
it "should not be frozen" do
|
463
|
+
@uri.should_not be_frozen
|
464
|
+
end
|
465
|
+
|
466
|
+
it "should allow destructive operations" do
|
467
|
+
expect { @uri.normalize! }.not_to raise_error
|
468
|
+
end
|
469
|
+
end
|
470
|
+
|
471
|
+
describe Addressable::URI, "when parsed from a frozen string" do
|
472
|
+
before do
|
473
|
+
@uri = Addressable::URI.parse(
|
474
|
+
"http://user:password@example.com:8080/path?query=value#fragment".freeze
|
475
|
+
)
|
476
|
+
end
|
477
|
+
|
478
|
+
it "returns 'http' for #scheme" do
|
479
|
+
@uri.scheme.should == "http"
|
480
|
+
end
|
481
|
+
|
482
|
+
it "returns 'http' for #normalized_scheme" do
|
483
|
+
@uri.normalized_scheme.should == "http"
|
484
|
+
end
|
485
|
+
|
486
|
+
it "returns 'user' for #user" do
|
487
|
+
@uri.user.should == "user"
|
488
|
+
end
|
489
|
+
|
490
|
+
it "returns 'user' for #normalized_user" do
|
491
|
+
@uri.normalized_user.should == "user"
|
492
|
+
end
|
493
|
+
|
494
|
+
it "returns 'password' for #password" do
|
495
|
+
@uri.password.should == "password"
|
496
|
+
end
|
497
|
+
|
498
|
+
it "returns 'password' for #normalized_password" do
|
499
|
+
@uri.normalized_password.should == "password"
|
500
|
+
end
|
501
|
+
|
502
|
+
it "returns 'user:password' for #userinfo" do
|
503
|
+
@uri.userinfo.should == "user:password"
|
504
|
+
end
|
505
|
+
|
506
|
+
it "returns 'user:password' for #normalized_userinfo" do
|
507
|
+
@uri.normalized_userinfo.should == "user:password"
|
508
|
+
end
|
509
|
+
|
510
|
+
it "returns 'example.com' for #host" do
|
511
|
+
@uri.host.should == "example.com"
|
512
|
+
end
|
513
|
+
|
514
|
+
it "returns 'example.com' for #normalized_host" do
|
515
|
+
@uri.normalized_host.should == "example.com"
|
516
|
+
end
|
517
|
+
|
518
|
+
it "returns 'user:password@example.com:8080' for #authority" do
|
519
|
+
@uri.authority.should == "user:password@example.com:8080"
|
520
|
+
end
|
521
|
+
|
522
|
+
it "returns 'user:password@example.com:8080' for #normalized_authority" do
|
523
|
+
@uri.normalized_authority.should == "user:password@example.com:8080"
|
524
|
+
end
|
525
|
+
|
526
|
+
it "returns 8080 for #port" do
|
527
|
+
@uri.port.should == 8080
|
528
|
+
end
|
529
|
+
|
530
|
+
it "returns 8080 for #normalized_port" do
|
531
|
+
@uri.normalized_port.should == 8080
|
532
|
+
end
|
533
|
+
|
534
|
+
it "returns 80 for #default_port" do
|
535
|
+
@uri.default_port.should == 80
|
536
|
+
end
|
537
|
+
|
538
|
+
it "returns 'http://user:password@example.com:8080' for #site" do
|
539
|
+
@uri.site.should == "http://user:password@example.com:8080"
|
540
|
+
end
|
541
|
+
|
542
|
+
it "returns 'http://user:password@example.com:8080' for #normalized_site" do
|
543
|
+
@uri.normalized_site.should == "http://user:password@example.com:8080"
|
544
|
+
end
|
545
|
+
|
546
|
+
it "returns '/path' for #path" do
|
547
|
+
@uri.path.should == "/path"
|
548
|
+
end
|
549
|
+
|
550
|
+
it "returns '/path' for #normalized_path" do
|
551
|
+
@uri.normalized_path.should == "/path"
|
552
|
+
end
|
553
|
+
|
554
|
+
it "returns 'query=value' for #query" do
|
555
|
+
@uri.query.should == "query=value"
|
556
|
+
end
|
557
|
+
|
558
|
+
it "returns 'query=value' for #normalized_query" do
|
559
|
+
@uri.normalized_query.should == "query=value"
|
560
|
+
end
|
561
|
+
|
562
|
+
it "returns 'fragment' for #fragment" do
|
563
|
+
@uri.fragment.should == "fragment"
|
564
|
+
end
|
565
|
+
|
566
|
+
it "returns 'fragment' for #normalized_fragment" do
|
567
|
+
@uri.normalized_fragment.should == "fragment"
|
568
|
+
end
|
569
|
+
|
570
|
+
it "returns #hash" do
|
571
|
+
@uri.hash.should_not be nil
|
572
|
+
end
|
573
|
+
|
574
|
+
it "returns #to_s" do
|
575
|
+
@uri.to_s.should ==
|
576
|
+
"http://user:password@example.com:8080/path?query=value#fragment"
|
577
|
+
end
|
578
|
+
|
579
|
+
it "should not be frozen" do
|
580
|
+
@uri.should_not be_frozen
|
581
|
+
end
|
582
|
+
|
583
|
+
it "should allow destructive operations" do
|
584
|
+
expect { @uri.normalize! }.not_to raise_error
|
585
|
+
end
|
586
|
+
end
|
587
|
+
|
221
588
|
describe Addressable::URI, "when frozen" do
|
222
589
|
before do
|
223
590
|
@uri = Addressable::URI.new.freeze
|
@@ -232,7 +599,7 @@ describe Addressable::URI, "when frozen" do
|
|
232
599
|
end
|
233
600
|
|
234
601
|
it "returns nil for #user" do
|
235
|
-
@uri.user
|
602
|
+
@uri.user.should == nil
|
236
603
|
end
|
237
604
|
|
238
605
|
it "returns nil for #normalized_user" do
|
@@ -322,6 +689,153 @@ describe Addressable::URI, "when frozen" do
|
|
322
689
|
it "returns #to_s" do
|
323
690
|
@uri.to_s.should == ''
|
324
691
|
end
|
692
|
+
|
693
|
+
it "should be frozen" do
|
694
|
+
@uri.should be_frozen
|
695
|
+
end
|
696
|
+
|
697
|
+
it "should not be frozen after duping" do
|
698
|
+
@uri.dup.should_not be_frozen
|
699
|
+
end
|
700
|
+
|
701
|
+
it "should not allow destructive operations" do
|
702
|
+
expect { @uri.normalize! }.to raise_error { |error|
|
703
|
+
error.message.should match(/can't modify frozen/)
|
704
|
+
error.should satisfy { |e| RuntimeError === e || TypeError === e }
|
705
|
+
}
|
706
|
+
end
|
707
|
+
end
|
708
|
+
|
709
|
+
describe Addressable::URI, "when frozen" do
|
710
|
+
before do
|
711
|
+
@uri = Addressable::URI.parse(
|
712
|
+
"HTTP://example.com.:%38%30/%70a%74%68?a=%31#1%323"
|
713
|
+
).freeze
|
714
|
+
end
|
715
|
+
|
716
|
+
it "returns 'HTTP' for #scheme" do
|
717
|
+
@uri.scheme.should == "HTTP"
|
718
|
+
end
|
719
|
+
|
720
|
+
it "returns 'http' for #normalized_scheme" do
|
721
|
+
@uri.normalized_scheme.should == "http"
|
722
|
+
@uri.normalize.scheme.should == "http"
|
723
|
+
end
|
724
|
+
|
725
|
+
it "returns nil for #user" do
|
726
|
+
@uri.user.should == nil
|
727
|
+
end
|
728
|
+
|
729
|
+
it "returns nil for #normalized_user" do
|
730
|
+
@uri.normalized_user.should == nil
|
731
|
+
end
|
732
|
+
|
733
|
+
it "returns nil for #password" do
|
734
|
+
@uri.password.should == nil
|
735
|
+
end
|
736
|
+
|
737
|
+
it "returns nil for #normalized_password" do
|
738
|
+
@uri.normalized_password.should == nil
|
739
|
+
end
|
740
|
+
|
741
|
+
it "returns nil for #userinfo" do
|
742
|
+
@uri.userinfo.should == nil
|
743
|
+
end
|
744
|
+
|
745
|
+
it "returns nil for #normalized_userinfo" do
|
746
|
+
@uri.normalized_userinfo.should == nil
|
747
|
+
end
|
748
|
+
|
749
|
+
it "returns 'example.com.' for #host" do
|
750
|
+
@uri.host.should == "example.com."
|
751
|
+
end
|
752
|
+
|
753
|
+
it "returns nil for #normalized_host" do
|
754
|
+
@uri.normalized_host.should == "example.com"
|
755
|
+
@uri.normalize.host.should == "example.com"
|
756
|
+
end
|
757
|
+
|
758
|
+
it "returns 'example.com.:80' for #authority" do
|
759
|
+
@uri.authority.should == "example.com.:80"
|
760
|
+
end
|
761
|
+
|
762
|
+
it "returns 'example.com:80' for #normalized_authority" do
|
763
|
+
@uri.normalized_authority.should == "example.com"
|
764
|
+
@uri.normalize.authority.should == "example.com"
|
765
|
+
end
|
766
|
+
|
767
|
+
it "returns 80 for #port" do
|
768
|
+
@uri.port.should == 80
|
769
|
+
end
|
770
|
+
|
771
|
+
it "returns nil for #normalized_port" do
|
772
|
+
@uri.normalized_port.should == nil
|
773
|
+
@uri.normalize.port.should == nil
|
774
|
+
end
|
775
|
+
|
776
|
+
it "returns 80 for #default_port" do
|
777
|
+
@uri.default_port.should == 80
|
778
|
+
end
|
779
|
+
|
780
|
+
it "returns 'HTTP://example.com.:80' for #site" do
|
781
|
+
@uri.site.should == "HTTP://example.com.:80"
|
782
|
+
end
|
783
|
+
|
784
|
+
it "returns 'http://example.com' for #normalized_site" do
|
785
|
+
@uri.normalized_site.should == "http://example.com"
|
786
|
+
@uri.normalize.site.should == "http://example.com"
|
787
|
+
end
|
788
|
+
|
789
|
+
it "returns '/%70a%74%68' for #path" do
|
790
|
+
@uri.path.should == "/%70a%74%68"
|
791
|
+
end
|
792
|
+
|
793
|
+
it "returns '/path' for #normalized_path" do
|
794
|
+
@uri.normalized_path.should == "/path"
|
795
|
+
@uri.normalize.path.should == "/path"
|
796
|
+
end
|
797
|
+
|
798
|
+
it "returns 'a=%31' for #query" do
|
799
|
+
@uri.query.should == "a=%31"
|
800
|
+
end
|
801
|
+
|
802
|
+
it "returns 'a=1' for #normalized_query" do
|
803
|
+
@uri.normalized_query.should == "a=1"
|
804
|
+
@uri.normalize.query.should == "a=1"
|
805
|
+
end
|
806
|
+
|
807
|
+
it "returns '1%323' for #fragment" do
|
808
|
+
@uri.fragment.should == "1%323"
|
809
|
+
end
|
810
|
+
|
811
|
+
it "returns '123' for #normalized_fragment" do
|
812
|
+
@uri.normalized_fragment.should == "123"
|
813
|
+
@uri.normalize.fragment.should == "123"
|
814
|
+
end
|
815
|
+
|
816
|
+
it "returns #hash" do
|
817
|
+
@uri.hash.should_not be nil
|
818
|
+
end
|
819
|
+
|
820
|
+
it "returns #to_s" do
|
821
|
+
@uri.to_s.should == 'HTTP://example.com.:80/%70a%74%68?a=%31#1%323'
|
822
|
+
@uri.normalize.to_s.should == 'http://example.com/path?a=1#123'
|
823
|
+
end
|
824
|
+
|
825
|
+
it "should be frozen" do
|
826
|
+
@uri.should be_frozen
|
827
|
+
end
|
828
|
+
|
829
|
+
it "should not be frozen after duping" do
|
830
|
+
@uri.dup.should_not be_frozen
|
831
|
+
end
|
832
|
+
|
833
|
+
it "should not allow destructive operations" do
|
834
|
+
expect { @uri.normalize! }.to raise_error { |error|
|
835
|
+
error.message.should match(/can't modify frozen/)
|
836
|
+
error.should satisfy { |e| RuntimeError === e || TypeError === e }
|
837
|
+
}
|
838
|
+
end
|
325
839
|
end
|
326
840
|
|
327
841
|
describe Addressable::URI, "when created from string components" do
|
@@ -3102,6 +3616,27 @@ describe Addressable::URI, "when parsed from " +
|
|
3102
3616
|
end
|
3103
3617
|
end
|
3104
3618
|
|
3619
|
+
describe Addressable::URI, "when parsed from " +
|
3620
|
+
"'http://example.com/?q='one;two'&x=1'" do
|
3621
|
+
before do
|
3622
|
+
@uri = Addressable::URI.parse("http://example.com/?q='one;two'&x=1")
|
3623
|
+
end
|
3624
|
+
|
3625
|
+
it "should have a query of 'q='one;two'&x=1'" do
|
3626
|
+
@uri.query.should == "q='one;two'&x=1"
|
3627
|
+
end
|
3628
|
+
|
3629
|
+
it "should have query_values of {\"q\" => \"'one;two'\", \"x\" => \"1\"}" do
|
3630
|
+
@uri.query_values.should == {"q" => "'one;two'", "x" => "1"}
|
3631
|
+
end
|
3632
|
+
|
3633
|
+
it "should escape the ';' character when normalizing to avoid ambiguity " +
|
3634
|
+
"with the W3C HTML 4.01 specification" do
|
3635
|
+
# HTML 4.01 Section B.2.2
|
3636
|
+
@uri.normalize.query.should == "q='one%3Btwo'&x=1"
|
3637
|
+
end
|
3638
|
+
end
|
3639
|
+
|
3105
3640
|
describe Addressable::URI, "when parsed from " +
|
3106
3641
|
"'http://example.com/?&&x=b'" do
|
3107
3642
|
before do
|
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.3.
|
4
|
+
version: 2.3.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-04-15 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|