addressable 2.3.7 → 2.7.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +60 -0
- data/Gemfile +22 -16
- data/README.md +31 -15
- data/Rakefile +8 -11
- data/lib/addressable.rb +4 -0
- data/lib/addressable/idna.rb +3 -1
- data/lib/addressable/idna/native.rb +11 -5
- data/lib/addressable/idna/pure.rb +29 -26
- data/lib/addressable/template.rb +135 -28
- data/lib/addressable/uri.rb +379 -202
- data/lib/addressable/version.rb +5 -3
- data/spec/addressable/idna_spec.rb +48 -2
- data/spec/addressable/net_http_compat_spec.rb +3 -1
- data/spec/addressable/rack_mount_compat_spec.rb +106 -0
- data/spec/addressable/security_spec.rb +59 -0
- data/spec/addressable/template_spec.rb +126 -15
- data/spec/addressable/uri_spec.rb +608 -29
- data/spec/spec_helper.rb +17 -1
- data/tasks/clobber.rake +2 -0
- data/tasks/gem.rake +22 -16
- data/tasks/git.rake +2 -0
- data/tasks/metrics.rake +2 -0
- data/tasks/rspec.rake +9 -29
- data/tasks/yard.rake +2 -0
- metadata +30 -57
- data/tasks/rubyforge.rake +0 -73
- data/website/index.html +0 -110
data/lib/addressable/version.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# encoding:utf-8
|
2
4
|
#--
|
3
|
-
# Copyright (C)
|
5
|
+
# Copyright (C) Bob Aman
|
4
6
|
#
|
5
7
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
8
|
# you may not use this file except in compliance with the License.
|
@@ -21,8 +23,8 @@ if !defined?(Addressable::VERSION)
|
|
21
23
|
module Addressable
|
22
24
|
module VERSION
|
23
25
|
MAJOR = 2
|
24
|
-
MINOR =
|
25
|
-
TINY =
|
26
|
+
MINOR = 7
|
27
|
+
TINY = 0
|
26
28
|
|
27
29
|
STRING = [MAJOR, MINOR, TINY].join('.')
|
28
30
|
end
|
@@ -1,5 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# coding: utf-8
|
2
|
-
# Copyright (C)
|
4
|
+
# Copyright (C) Bob Aman
|
3
5
|
#
|
4
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
7
|
# you may not use this file except in compliance with the License.
|
@@ -26,6 +28,11 @@ shared_examples_for "converting from unicode to ASCII" do
|
|
26
28
|
expect(Addressable::IDNA.to_ascii("www.google.com")).to eq("www.google.com")
|
27
29
|
end
|
28
30
|
|
31
|
+
long = 'AcinusFallumTrompetumNullunCreditumVisumEstAtCuadLongumEtCefallum.com'
|
32
|
+
it "should convert '#{long}' correctly" do
|
33
|
+
expect(Addressable::IDNA.to_ascii(long)).to eq(long)
|
34
|
+
end
|
35
|
+
|
29
36
|
it "should convert 'www.詹姆斯.com' correctly" do
|
30
37
|
expect(Addressable::IDNA.to_ascii(
|
31
38
|
"www.詹姆斯.com"
|
@@ -129,6 +136,12 @@ shared_examples_for "converting from unicode to ASCII" do
|
|
129
136
|
)).to eq("xn--4ud")
|
130
137
|
end
|
131
138
|
|
139
|
+
it "should convert '🌹🌹🌹.ws' correctly" do
|
140
|
+
expect(Addressable::IDNA.to_ascii(
|
141
|
+
"\360\237\214\271\360\237\214\271\360\237\214\271.ws"
|
142
|
+
)).to eq("xn--2h8haa.ws")
|
143
|
+
end
|
144
|
+
|
132
145
|
it "should handle two adjacent '.'s correctly" do
|
133
146
|
expect(Addressable::IDNA.to_ascii(
|
134
147
|
"example..host"
|
@@ -137,8 +150,23 @@ shared_examples_for "converting from unicode to ASCII" do
|
|
137
150
|
end
|
138
151
|
|
139
152
|
shared_examples_for "converting from ASCII to unicode" do
|
153
|
+
long = 'AcinusFallumTrompetumNullunCreditumVisumEstAtCuadLongumEtCefallum.com'
|
154
|
+
it "should convert '#{long}' correctly" do
|
155
|
+
expect(Addressable::IDNA.to_unicode(long)).to eq(long)
|
156
|
+
end
|
157
|
+
|
158
|
+
it "should return the identity conversion when punycode decode fails" do
|
159
|
+
expect(Addressable::IDNA.to_unicode("xn--zckp1cyg1.sblo.jp")).to eq(
|
160
|
+
"xn--zckp1cyg1.sblo.jp")
|
161
|
+
end
|
162
|
+
|
163
|
+
it "should return the identity conversion when the ACE prefix has no suffix" do
|
164
|
+
expect(Addressable::IDNA.to_unicode("xn--...-")).to eq("xn--...-")
|
165
|
+
end
|
166
|
+
|
140
167
|
it "should convert 'www.google.com' correctly" do
|
141
|
-
expect(Addressable::IDNA.to_unicode("www.google.com")).to eq(
|
168
|
+
expect(Addressable::IDNA.to_unicode("www.google.com")).to eq(
|
169
|
+
"www.google.com")
|
142
170
|
end
|
143
171
|
|
144
172
|
it "should convert 'www.詹姆斯.com' correctly" do
|
@@ -147,12 +175,24 @@ shared_examples_for "converting from ASCII to unicode" do
|
|
147
175
|
)).to eq("www.詹姆斯.com")
|
148
176
|
end
|
149
177
|
|
178
|
+
it "should convert '詹姆斯.com' correctly" do
|
179
|
+
expect(Addressable::IDNA.to_unicode(
|
180
|
+
"xn--8ws00zhy3a.com"
|
181
|
+
)).to eq("詹姆斯.com")
|
182
|
+
end
|
183
|
+
|
150
184
|
it "should convert 'www.iñtërnâtiônàlizætiøn.com' correctly" do
|
151
185
|
expect(Addressable::IDNA.to_unicode(
|
152
186
|
"www.xn--itrntinliztin-vdb0a5exd8ewcye.com"
|
153
187
|
)).to eq("www.iñtërnâtiônàlizætiøn.com")
|
154
188
|
end
|
155
189
|
|
190
|
+
it "should convert 'iñtërnâtiônàlizætiøn.com' correctly" do
|
191
|
+
expect(Addressable::IDNA.to_unicode(
|
192
|
+
"xn--itrntinliztin-vdb0a5exd8ewcye.com"
|
193
|
+
)).to eq("iñtërnâtiônàlizætiøn.com")
|
194
|
+
end
|
195
|
+
|
156
196
|
it "should convert " +
|
157
197
|
"'www.ほんとうにながいわけのわからないどめいんめいのらべるまだながくしないとたりない.w3.mag.keio.ac.jp' " +
|
158
198
|
"correctly" do
|
@@ -199,6 +239,12 @@ shared_examples_for "converting from ASCII to unicode" do
|
|
199
239
|
)).to eq("\341\206\265")
|
200
240
|
end
|
201
241
|
|
242
|
+
it "should convert '🌹🌹🌹.ws' correctly" do
|
243
|
+
expect(Addressable::IDNA.to_unicode(
|
244
|
+
"xn--2h8haa.ws"
|
245
|
+
)).to eq("\360\237\214\271\360\237\214\271\360\237\214\271.ws")
|
246
|
+
end
|
247
|
+
|
202
248
|
it "should handle two adjacent '.'s correctly" do
|
203
249
|
expect(Addressable::IDNA.to_unicode(
|
204
250
|
"example..host"
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# coding: utf-8
|
4
|
+
# Copyright (C) Bob Aman
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
|
18
|
+
|
19
|
+
require "spec_helper"
|
20
|
+
|
21
|
+
require "addressable/uri"
|
22
|
+
require "addressable/template"
|
23
|
+
require "rack/mount"
|
24
|
+
|
25
|
+
describe Rack::Mount do
|
26
|
+
let(:app_one) do
|
27
|
+
proc { |env| [200, {'Content-Type' => 'text/plain'}, 'Route 1'] }
|
28
|
+
end
|
29
|
+
let(:app_two) do
|
30
|
+
proc { |env| [200, {'Content-Type' => 'text/plain'}, 'Route 2'] }
|
31
|
+
end
|
32
|
+
let(:app_three) do
|
33
|
+
proc { |env| [200, {'Content-Type' => 'text/plain'}, 'Route 3'] }
|
34
|
+
end
|
35
|
+
let(:routes) do
|
36
|
+
s = Rack::Mount::RouteSet.new do |set|
|
37
|
+
set.add_route(app_one, {
|
38
|
+
:request_method => 'GET',
|
39
|
+
:path_info => Addressable::Template.new('/one/{id}/')
|
40
|
+
}, {:id => 'unidentified'}, :one)
|
41
|
+
set.add_route(app_two, {
|
42
|
+
:request_method => 'GET',
|
43
|
+
:path_info => Addressable::Template.new('/two/')
|
44
|
+
}, {:id => 'unidentified'}, :two)
|
45
|
+
set.add_route(app_three, {
|
46
|
+
:request_method => 'GET',
|
47
|
+
:path_info => Addressable::Template.new('/three/{id}/').to_regexp
|
48
|
+
}, {:id => 'unidentified'}, :three)
|
49
|
+
end
|
50
|
+
s.rehash
|
51
|
+
s
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should generate from routes with Addressable::Template" do
|
55
|
+
path, _ = routes.generate(:path_info, :one, {:id => '123'})
|
56
|
+
expect(path).to eq '/one/123/'
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should generate from routes with Addressable::Template using defaults" do
|
60
|
+
path, _ = routes.generate(:path_info, :one, {})
|
61
|
+
expect(path).to eq '/one/unidentified/'
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should recognize routes with Addressable::Template" do
|
65
|
+
request = Rack::Request.new(
|
66
|
+
'REQUEST_METHOD' => 'GET',
|
67
|
+
'PATH_INFO' => '/one/123/'
|
68
|
+
)
|
69
|
+
route, _, params = routes.recognize(request)
|
70
|
+
expect(route).not_to be_nil
|
71
|
+
expect(route.app).to eq app_one
|
72
|
+
expect(params).to eq({id: '123'})
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should generate from routes with Addressable::Template" do
|
76
|
+
path, _ = routes.generate(:path_info, :two, {:id => '654'})
|
77
|
+
expect(path).to eq '/two/'
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should generate from routes with Addressable::Template using defaults" do
|
81
|
+
path, _ = routes.generate(:path_info, :two, {})
|
82
|
+
expect(path).to eq '/two/'
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should recognize routes with Addressable::Template" do
|
86
|
+
request = Rack::Request.new(
|
87
|
+
'REQUEST_METHOD' => 'GET',
|
88
|
+
'PATH_INFO' => '/two/'
|
89
|
+
)
|
90
|
+
route, _, params = routes.recognize(request)
|
91
|
+
expect(route).not_to be_nil
|
92
|
+
expect(route.app).to eq app_two
|
93
|
+
expect(params).to eq({id: 'unidentified'})
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should recognize routes with derived Regexp" do
|
97
|
+
request = Rack::Request.new(
|
98
|
+
'REQUEST_METHOD' => 'GET',
|
99
|
+
'PATH_INFO' => '/three/789/'
|
100
|
+
)
|
101
|
+
route, _, params = routes.recognize(request)
|
102
|
+
expect(route).not_to be_nil
|
103
|
+
expect(route.app).to eq app_three
|
104
|
+
expect(params).to eq({id: '789'})
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# coding: utf-8
|
4
|
+
# Copyright (C) Bob Aman
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
|
18
|
+
|
19
|
+
require "spec_helper"
|
20
|
+
|
21
|
+
require "addressable/uri"
|
22
|
+
|
23
|
+
describe Addressable::URI, "when created with a URI known to cause crashes " +
|
24
|
+
"in certain browsers" do
|
25
|
+
it "should parse correctly" do
|
26
|
+
uri = Addressable::URI.parse('%%30%30')
|
27
|
+
expect(uri.path).to eq('%%30%30')
|
28
|
+
expect(uri.normalize.path).to eq('%2500')
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should parse correctly as a full URI" do
|
32
|
+
uri = Addressable::URI.parse('http://www.example.com/%%30%30')
|
33
|
+
expect(uri.path).to eq('/%%30%30')
|
34
|
+
expect(uri.normalize.path).to eq('/%2500')
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe Addressable::URI, "when created with a URI known to cause crashes " +
|
39
|
+
"in certain browsers" do
|
40
|
+
it "should parse correctly" do
|
41
|
+
uri = Addressable::URI.parse('لُصّبُلُلصّبُررً ॣ ॣh ॣ ॣ 冗')
|
42
|
+
expect(uri.path).to eq('لُصّبُلُلصّبُررً ॣ ॣh ॣ ॣ 冗')
|
43
|
+
expect(uri.normalize.path).to eq(
|
44
|
+
'%D9%84%D9%8F%D8%B5%D9%91%D8%A8%D9%8F%D9%84%D9%8F%D9%84%D8%B5%D9%91' +
|
45
|
+
'%D8%A8%D9%8F%D8%B1%D8%B1%D9%8B%20%E0%A5%A3%20%E0%A5%A3h%20%E0%A5' +
|
46
|
+
'%A3%20%E0%A5%A3%20%E5%86%97'
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should parse correctly as a full URI" do
|
51
|
+
uri = Addressable::URI.parse('http://www.example.com/لُصّبُلُلصّبُررً ॣ ॣh ॣ ॣ 冗')
|
52
|
+
expect(uri.path).to eq('/لُصّبُلُلصّبُررً ॣ ॣh ॣ ॣ 冗')
|
53
|
+
expect(uri.normalize.path).to eq(
|
54
|
+
'/%D9%84%D9%8F%D8%B5%D9%91%D8%A8%D9%8F%D9%84%D9%8F%D9%84%D8%B5%D9%91' +
|
55
|
+
'%D8%A8%D9%8F%D8%B1%D8%B1%D9%8B%20%E0%A5%A3%20%E0%A5%A3h%20%E0%A5' +
|
56
|
+
'%A3%20%E0%A5%A3%20%E5%86%97'
|
57
|
+
)
|
58
|
+
end
|
59
|
+
end
|
@@ -1,5 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# coding: utf-8
|
2
|
-
# Copyright (C)
|
4
|
+
# Copyright (C) Bob Aman
|
3
5
|
#
|
4
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
7
|
# you may not use this file except in compliance with the License.
|
@@ -16,6 +18,7 @@
|
|
16
18
|
|
17
19
|
require "spec_helper"
|
18
20
|
|
21
|
+
require "bigdecimal"
|
19
22
|
require "addressable/template"
|
20
23
|
|
21
24
|
shared_examples_for 'expands' do |tests|
|
@@ -75,15 +78,13 @@ describe "==" do
|
|
75
78
|
end
|
76
79
|
|
77
80
|
describe "Type conversion" do
|
78
|
-
require "bigdecimal"
|
79
|
-
|
80
81
|
subject {
|
81
82
|
{
|
82
83
|
:var => true,
|
83
84
|
:hello => 1234,
|
84
85
|
:nothing => nil,
|
85
86
|
:sym => :symbolic,
|
86
|
-
:decimal => BigDecimal
|
87
|
+
:decimal => BigDecimal('1')
|
87
88
|
}
|
88
89
|
}
|
89
90
|
|
@@ -92,7 +93,7 @@ describe "Type conversion" do
|
|
92
93
|
'{hello}' => '1234',
|
93
94
|
'{nothing}' => '',
|
94
95
|
'{sym}' => 'symbolic',
|
95
|
-
'{decimal}' => '0.1E1'
|
96
|
+
'{decimal}' => RUBY_VERSION < '2.4.0' ? '0.1E1' : '0.1e1'
|
96
97
|
}
|
97
98
|
end
|
98
99
|
|
@@ -699,6 +700,13 @@ describe "Expansion" do
|
|
699
700
|
]
|
700
701
|
}
|
701
702
|
end
|
703
|
+
context "non-string key in match data" do
|
704
|
+
subject {Addressable::Template.new("http://example.com/{one}")}
|
705
|
+
|
706
|
+
it "raises TypeError" do
|
707
|
+
expect { subject.expand(Object.new => "1") }.to raise_error TypeError
|
708
|
+
end
|
709
|
+
end
|
702
710
|
end
|
703
711
|
|
704
712
|
class ExampleTwoProcessor
|
@@ -729,6 +737,21 @@ class DumbProcessor
|
|
729
737
|
end
|
730
738
|
|
731
739
|
describe Addressable::Template do
|
740
|
+
describe 'initialize' do
|
741
|
+
context 'with a non-string' do
|
742
|
+
it 'raises a TypeError' do
|
743
|
+
expect { Addressable::Template.new(nil) }.to raise_error(TypeError)
|
744
|
+
end
|
745
|
+
end
|
746
|
+
end
|
747
|
+
|
748
|
+
describe 'freeze' do
|
749
|
+
subject { Addressable::Template.new("http://example.com/{first}/{+second}/") }
|
750
|
+
it 'freezes the template' do
|
751
|
+
expect(subject.freeze).to be_frozen
|
752
|
+
end
|
753
|
+
end
|
754
|
+
|
732
755
|
describe "Matching" do
|
733
756
|
let(:uri){
|
734
757
|
Addressable::URI.parse(
|
@@ -749,7 +772,7 @@ describe Addressable::Template do
|
|
749
772
|
}
|
750
773
|
context "first uri with ExampleTwoProcessor" do
|
751
774
|
subject {
|
752
|
-
|
775
|
+
Addressable::Template.new(
|
753
776
|
"http://example.com/search/{query}/"
|
754
777
|
).match(uri, ExampleTwoProcessor)
|
755
778
|
}
|
@@ -759,7 +782,7 @@ describe Addressable::Template do
|
|
759
782
|
|
760
783
|
context "second uri with ExampleTwoProcessor" do
|
761
784
|
subject {
|
762
|
-
|
785
|
+
Addressable::Template.new(
|
763
786
|
"http://example.com/{first}/{+second}/"
|
764
787
|
).match(uri2, ExampleTwoProcessor)
|
765
788
|
}
|
@@ -769,7 +792,7 @@ describe Addressable::Template do
|
|
769
792
|
|
770
793
|
context "second uri with DumbProcessor" do
|
771
794
|
subject {
|
772
|
-
|
795
|
+
Addressable::Template.new(
|
773
796
|
"http://example.com/{first}/{+second}/"
|
774
797
|
).match(uri2, DumbProcessor)
|
775
798
|
}
|
@@ -779,7 +802,7 @@ describe Addressable::Template do
|
|
779
802
|
|
780
803
|
context "second uri" do
|
781
804
|
subject {
|
782
|
-
|
805
|
+
Addressable::Template.new(
|
783
806
|
"http://example.com/{first}{/second*}/"
|
784
807
|
).match(uri2)
|
785
808
|
}
|
@@ -788,7 +811,7 @@ describe Addressable::Template do
|
|
788
811
|
end
|
789
812
|
context "third uri" do
|
790
813
|
subject {
|
791
|
-
|
814
|
+
Addressable::Template.new(
|
792
815
|
"http://example.com/{;hash*,first}"
|
793
816
|
).match(uri3)
|
794
817
|
}
|
@@ -801,7 +824,7 @@ describe Addressable::Template do
|
|
801
824
|
# Semantically, a separate key is more likely, but both are possible.
|
802
825
|
context "fourth uri" do
|
803
826
|
subject {
|
804
|
-
|
827
|
+
Addressable::Template.new(
|
805
828
|
"http://example.com/{?hash*,first}"
|
806
829
|
).match(uri4)
|
807
830
|
}
|
@@ -811,7 +834,7 @@ describe Addressable::Template do
|
|
811
834
|
end
|
812
835
|
context "fifth uri" do
|
813
836
|
subject {
|
814
|
-
|
837
|
+
Addressable::Template.new(
|
815
838
|
"http://example.com/{path}{?hash*,first}"
|
816
839
|
).match(uri5)
|
817
840
|
}
|
@@ -819,6 +842,22 @@ describe Addressable::Template do
|
|
819
842
|
its(:captures){ should == ["foo", nil, nil] }
|
820
843
|
end
|
821
844
|
end
|
845
|
+
|
846
|
+
describe 'match' do
|
847
|
+
subject { Addressable::Template.new('http://example.com/first/second/') }
|
848
|
+
context 'when the URI is the same as the template' do
|
849
|
+
it 'returns the match data itself with an empty mapping' do
|
850
|
+
uri = Addressable::URI.parse('http://example.com/first/second/')
|
851
|
+
match_data = subject.match(uri)
|
852
|
+
expect(match_data).to be_an Addressable::Template::MatchData
|
853
|
+
expect(match_data.uri).to eq(uri)
|
854
|
+
expect(match_data.template).to eq(subject)
|
855
|
+
expect(match_data.mapping).to be_empty
|
856
|
+
expect(match_data.inspect).to be_an String
|
857
|
+
end
|
858
|
+
end
|
859
|
+
end
|
860
|
+
|
822
861
|
describe "extract" do
|
823
862
|
let(:template) {
|
824
863
|
Addressable::Template.new(
|
@@ -902,13 +941,53 @@ describe Addressable::Template do
|
|
902
941
|
)
|
903
942
|
end
|
904
943
|
end
|
944
|
+
context "partial_expand form style query with missing param at beginning" do
|
945
|
+
subject {
|
946
|
+
Addressable::Template.new("http://example.com/{?one,two}/")
|
947
|
+
}
|
948
|
+
it "builds a new pattern" do
|
949
|
+
expect(subject.partial_expand(:two => "2").pattern).to eq(
|
950
|
+
"http://example.com/?two=2{&one}/"
|
951
|
+
)
|
952
|
+
end
|
953
|
+
end
|
954
|
+
context "issue #307 - partial_expand form query with nil params" do
|
955
|
+
subject do
|
956
|
+
Addressable::Template.new("http://example.com/{?one,two,three}/")
|
957
|
+
end
|
958
|
+
it "builds a new pattern with two=nil" do
|
959
|
+
expect(subject.partial_expand(two: nil).pattern).to eq(
|
960
|
+
"http://example.com/{?one}{&three}/"
|
961
|
+
)
|
962
|
+
end
|
963
|
+
it "builds a new pattern with one=nil and two=nil" do
|
964
|
+
expect(subject.partial_expand(one: nil, two: nil).pattern).to eq(
|
965
|
+
"http://example.com/{?three}/"
|
966
|
+
)
|
967
|
+
end
|
968
|
+
it "builds a new pattern with one=1 and two=nil" do
|
969
|
+
expect(subject.partial_expand(one: 1, two: nil).pattern).to eq(
|
970
|
+
"http://example.com/?one=1{&three}/"
|
971
|
+
)
|
972
|
+
end
|
973
|
+
it "builds a new pattern with one=nil and two=2" do
|
974
|
+
expect(subject.partial_expand(one: nil, two: 2).pattern).to eq(
|
975
|
+
"http://example.com/?two=2{&three}/"
|
976
|
+
)
|
977
|
+
end
|
978
|
+
it "builds a new pattern with one=nil" do
|
979
|
+
expect(subject.partial_expand(one: nil).pattern).to eq(
|
980
|
+
"http://example.com/{?two}{&three}/"
|
981
|
+
)
|
982
|
+
end
|
983
|
+
end
|
905
984
|
context "partial_expand with query string" do
|
906
985
|
subject {
|
907
986
|
Addressable::Template.new("http://example.com/{?two,one}/")
|
908
987
|
}
|
909
988
|
it "builds a new pattern" do
|
910
989
|
expect(subject.partial_expand(:one => "1").pattern).to eq(
|
911
|
-
"http://example.com
|
990
|
+
"http://example.com/?one=1{&two}/"
|
912
991
|
)
|
913
992
|
end
|
914
993
|
end
|
@@ -922,6 +1001,24 @@ describe Addressable::Template do
|
|
922
1001
|
)
|
923
1002
|
end
|
924
1003
|
end
|
1004
|
+
context "partial expand with unicode values" do
|
1005
|
+
subject do
|
1006
|
+
Addressable::Template.new("http://example.com/{resource}/{query}/")
|
1007
|
+
end
|
1008
|
+
it "normalizes unicode by default" do
|
1009
|
+
template = subject.partial_expand("query" => "Cafe\u0301")
|
1010
|
+
expect(template.pattern).to eq(
|
1011
|
+
"http://example.com/{resource}/Caf%C3%A9/"
|
1012
|
+
)
|
1013
|
+
end
|
1014
|
+
|
1015
|
+
it "does not normalize unicode when byte semantics requested" do
|
1016
|
+
template = subject.partial_expand({"query" => "Cafe\u0301"}, nil, false)
|
1017
|
+
expect(template.pattern).to eq(
|
1018
|
+
"http://example.com/{resource}/Cafe%CC%81/"
|
1019
|
+
)
|
1020
|
+
end
|
1021
|
+
end
|
925
1022
|
end
|
926
1023
|
describe "Partial expand with strings" do
|
927
1024
|
context "partial_expand with two simple values" do
|
@@ -950,7 +1047,7 @@ describe Addressable::Template do
|
|
950
1047
|
}
|
951
1048
|
it "builds a new pattern" do
|
952
1049
|
expect(subject.partial_expand("one" => "1").pattern).to eq(
|
953
|
-
"http://example.com
|
1050
|
+
"http://example.com/?one=1{&two}/"
|
954
1051
|
)
|
955
1052
|
end
|
956
1053
|
end
|
@@ -966,6 +1063,20 @@ describe Addressable::Template do
|
|
966
1063
|
end
|
967
1064
|
end
|
968
1065
|
describe "Expand" do
|
1066
|
+
context "expand with unicode values" do
|
1067
|
+
subject do
|
1068
|
+
Addressable::Template.new("http://example.com/search/{query}/")
|
1069
|
+
end
|
1070
|
+
it "normalizes unicode by default" do
|
1071
|
+
uri = subject.expand("query" => "Cafe\u0301").to_str
|
1072
|
+
expect(uri).to eq("http://example.com/search/Caf%C3%A9/")
|
1073
|
+
end
|
1074
|
+
|
1075
|
+
it "does not normalize unicode when byte semantics requested" do
|
1076
|
+
uri = subject.expand({ "query" => "Cafe\u0301" }, nil, false).to_str
|
1077
|
+
expect(uri).to eq("http://example.com/search/Cafe%CC%81/")
|
1078
|
+
end
|
1079
|
+
end
|
969
1080
|
context "expand with a processor" do
|
970
1081
|
subject {
|
971
1082
|
Addressable::Template.new("http://example.com/search/{query}/")
|
@@ -999,7 +1110,7 @@ describe Addressable::Template do
|
|
999
1110
|
}
|
1000
1111
|
it "builds a new pattern" do
|
1001
1112
|
expect(subject.partial_expand("one" => "1").pattern).to eq(
|
1002
|
-
"http://example.com
|
1113
|
+
"http://example.com/?one=1{&two}/"
|
1003
1114
|
)
|
1004
1115
|
end
|
1005
1116
|
end
|