addressable 2.2.3 → 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 +7 -0
- data/CHANGELOG.md +235 -0
- data/Gemfile +32 -0
- data/LICENSE.txt +202 -0
- data/README.md +121 -0
- data/Rakefile +9 -17
- data/data/unicode.data +0 -0
- data/lib/addressable.rb +4 -0
- data/lib/addressable/idna.rb +26 -4870
- data/lib/addressable/idna/native.rb +61 -0
- data/lib/addressable/idna/pure.rb +676 -0
- data/lib/addressable/template.rb +581 -585
- data/lib/addressable/uri.rb +870 -609
- data/lib/addressable/version.rb +16 -20
- data/spec/addressable/idna_spec.rb +170 -64
- data/spec/addressable/net_http_compat_spec.rb +30 -0
- data/spec/addressable/rack_mount_compat_spec.rb +106 -0
- data/spec/addressable/security_spec.rb +59 -0
- data/spec/addressable/template_spec.rb +1346 -2047
- data/spec/addressable/uri_spec.rb +3472 -1198
- data/spec/spec_helper.rb +24 -0
- data/tasks/clobber.rake +2 -0
- data/tasks/gem.rake +28 -19
- data/tasks/git.rake +9 -2
- data/tasks/metrics.rake +2 -0
- data/tasks/rspec.rake +23 -0
- data/tasks/yard.rake +7 -4
- metadata +78 -117
- data/CHANGELOG +0 -101
- data/LICENSE +0 -20
- data/README +0 -60
- data/tasks/rdoc.rake +0 -26
- data/tasks/rubyforge.rake +0 -89
- data/tasks/spec.rake +0 -47
- data/website/index.html +0 -110
@@ -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,2152 +1,1451 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# coding: utf-8
|
4
|
+
# Copyright (C) Bob Aman
|
4
5
|
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
# without limitation the rights to use, copy, modify, merge, publish,
|
9
|
-
# distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
-
# permit persons to whom the Software is furnished to do so, subject to
|
11
|
-
# the following conditions:
|
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
|
12
9
|
#
|
13
|
-
#
|
14
|
-
# included in all copies or substantial portions of the Software.
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
15
11
|
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
-
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
23
|
-
#++
|
24
|
-
|
25
|
-
require "addressable/template"
|
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.
|
26
17
|
|
27
|
-
if !"".respond_to?("force_encoding")
|
28
|
-
class String
|
29
|
-
def force_encoding(encoding)
|
30
|
-
@encoding = encoding
|
31
|
-
end
|
32
18
|
|
33
|
-
|
34
|
-
@encoding ||= Encoding::ASCII_8BIT
|
35
|
-
end
|
36
|
-
end
|
19
|
+
require "spec_helper"
|
37
20
|
|
38
|
-
|
39
|
-
|
40
|
-
@name = name
|
41
|
-
end
|
21
|
+
require "bigdecimal"
|
22
|
+
require "addressable/template"
|
42
23
|
|
43
|
-
|
44
|
-
|
24
|
+
shared_examples_for 'expands' do |tests|
|
25
|
+
tests.each do |template, expansion|
|
26
|
+
exp = expansion.is_a?(Array) ? expansion.first : expansion
|
27
|
+
it "#{template} to #{exp}" do
|
28
|
+
tmpl = Addressable::Template.new(template).expand(subject)
|
29
|
+
if expansion.is_a?(Array)
|
30
|
+
expect(expansion.any?{|i| i == tmpl.to_str}).to be true
|
31
|
+
else
|
32
|
+
expect(tmpl.to_str).to eq(expansion)
|
33
|
+
end
|
45
34
|
end
|
46
|
-
|
47
|
-
UTF_8 = Encoding.new("UTF-8")
|
48
|
-
ASCII_8BIT = Encoding.new("US-ASCII")
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
class ExampleProcessor
|
53
|
-
def self.validate(name, value)
|
54
|
-
return !!(value =~ /^[\w ]+$/) if name == "query"
|
55
|
-
return true
|
56
|
-
end
|
57
|
-
|
58
|
-
def self.transform(name, value)
|
59
|
-
return value.gsub(/ /, "+") if name == "query"
|
60
|
-
return value
|
61
|
-
end
|
62
|
-
|
63
|
-
def self.restore(name, value)
|
64
|
-
return value.gsub(/\+/, " ") if name == "query"
|
65
|
-
return value.tr("A-Za-z", "N-ZA-Mn-za-m") if name == "rot13"
|
66
|
-
return value
|
67
|
-
end
|
68
|
-
|
69
|
-
def self.match(name)
|
70
|
-
return ".*?" if name == "first"
|
71
|
-
return ".*"
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
class SlashlessProcessor
|
76
|
-
def self.match(name)
|
77
|
-
return "[^/\\n]*"
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
class NoOpProcessor
|
82
|
-
def self.transform(name, value)
|
83
|
-
value
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
describe Addressable::Template do
|
88
|
-
it "should raise a TypeError for invalid patterns" do
|
89
|
-
(lambda do
|
90
|
-
Addressable::Template.new(42)
|
91
|
-
end).should raise_error(TypeError, "Can't convert Fixnum into String.")
|
92
35
|
end
|
93
36
|
end
|
94
37
|
|
95
|
-
describe
|
96
|
-
|
97
|
-
|
38
|
+
describe "eql?" do
|
39
|
+
let(:template) { Addressable::Template.new('https://www.example.com/{foo}') }
|
40
|
+
it 'is equal when the pattern matches' do
|
41
|
+
other_template = Addressable::Template.new('https://www.example.com/{foo}')
|
42
|
+
expect(template).to be_eql(other_template)
|
43
|
+
expect(other_template).to be_eql(template)
|
98
44
|
end
|
99
|
-
|
100
|
-
|
101
|
-
|
45
|
+
it 'is not equal when the pattern differs' do
|
46
|
+
other_template = Addressable::Template.new('https://www.example.com/{bar}')
|
47
|
+
expect(template).to_not be_eql(other_template)
|
48
|
+
expect(other_template).to_not be_eql(template)
|
102
49
|
end
|
103
|
-
|
104
|
-
|
105
|
-
|
50
|
+
it 'is not equal to non-templates' do
|
51
|
+
uri = 'https://www.example.com/foo/bar'
|
52
|
+
addressable_template = Addressable::Template.new uri
|
53
|
+
addressable_uri = Addressable::URI.parse uri
|
54
|
+
expect(addressable_template).to_not be_eql(addressable_uri)
|
55
|
+
expect(addressable_uri).to_not be_eql(addressable_template)
|
106
56
|
end
|
107
57
|
end
|
108
58
|
|
109
|
-
describe
|
110
|
-
|
111
|
-
|
59
|
+
describe "==" do
|
60
|
+
let(:template) { Addressable::Template.new('https://www.example.com/{foo}') }
|
61
|
+
it 'is equal when the pattern matches' do
|
62
|
+
other_template = Addressable::Template.new('https://www.example.com/{foo}')
|
63
|
+
expect(template).to eq other_template
|
64
|
+
expect(other_template).to eq template
|
112
65
|
end
|
113
|
-
|
114
|
-
|
115
|
-
|
66
|
+
it 'is not equal when the pattern differs' do
|
67
|
+
other_template = Addressable::Template.new('https://www.example.com/{bar}')
|
68
|
+
expect(template).not_to eq other_template
|
69
|
+
expect(other_template).not_to eq template
|
116
70
|
end
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
Addressable::
|
121
|
-
|
122
|
-
|
71
|
+
it 'is not equal to non-templates' do
|
72
|
+
uri = 'https://www.example.com/foo/bar'
|
73
|
+
addressable_template = Addressable::Template.new uri
|
74
|
+
addressable_uri = Addressable::URI.parse uri
|
75
|
+
expect(addressable_template).not_to eq addressable_uri
|
76
|
+
expect(addressable_uri).not_to eq addressable_template
|
123
77
|
end
|
124
78
|
end
|
125
79
|
|
126
|
-
describe
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
80
|
+
describe "Type conversion" do
|
81
|
+
subject {
|
82
|
+
{
|
83
|
+
:var => true,
|
84
|
+
:hello => 1234,
|
85
|
+
:nothing => nil,
|
86
|
+
:sym => :symbolic,
|
87
|
+
:decimal => BigDecimal('1')
|
88
|
+
}
|
89
|
+
}
|
90
|
+
|
91
|
+
it_behaves_like 'expands', {
|
92
|
+
'{var}' => 'true',
|
93
|
+
'{hello}' => '1234',
|
94
|
+
'{nothing}' => '',
|
95
|
+
'{sym}' => 'symbolic',
|
96
|
+
'{decimal}' => RUBY_VERSION < '2.4.0' ? '0.1E1' : '0.1e1'
|
97
|
+
}
|
98
|
+
end
|
99
|
+
|
100
|
+
describe "Level 1:" do
|
101
|
+
subject {
|
102
|
+
{:var => "value", :hello => "Hello World!"}
|
103
|
+
}
|
104
|
+
it_behaves_like 'expands', {
|
105
|
+
'{var}' => 'value',
|
106
|
+
'{hello}' => 'Hello%20World%21'
|
107
|
+
}
|
108
|
+
end
|
109
|
+
|
110
|
+
describe "Level 2" do
|
111
|
+
subject {
|
112
|
+
{
|
113
|
+
:var => "value",
|
114
|
+
:hello => "Hello World!",
|
115
|
+
:path => "/foo/bar"
|
116
|
+
}
|
117
|
+
}
|
118
|
+
context "Operator +:" do
|
119
|
+
it_behaves_like 'expands', {
|
120
|
+
'{+var}' => 'value',
|
121
|
+
'{+hello}' => 'Hello%20World!',
|
122
|
+
'{+path}/here' => '/foo/bar/here',
|
123
|
+
'here?ref={+path}' => 'here?ref=/foo/bar'
|
124
|
+
}
|
137
125
|
end
|
138
|
-
|
139
|
-
|
140
|
-
|
126
|
+
context "Operator #:" do
|
127
|
+
it_behaves_like 'expands', {
|
128
|
+
'X{#var}' => 'X#value',
|
129
|
+
'X{#hello}' => 'X#Hello%20World!'
|
130
|
+
}
|
141
131
|
end
|
142
132
|
end
|
143
133
|
|
144
|
-
describe
|
145
|
-
|
146
|
-
|
147
|
-
|
134
|
+
describe "Level 3" do
|
135
|
+
subject {
|
136
|
+
{
|
137
|
+
:var => "value",
|
138
|
+
:hello => "Hello World!",
|
139
|
+
:empty => "",
|
140
|
+
:path => "/foo/bar",
|
141
|
+
:x => "1024",
|
142
|
+
:y => "768"
|
143
|
+
}
|
144
|
+
}
|
145
|
+
context "Operator nil (multiple vars):" do
|
146
|
+
it_behaves_like 'expands', {
|
147
|
+
'map?{x,y}' => 'map?1024,768',
|
148
|
+
'{x,hello,y}' => '1024,Hello%20World%21,768'
|
149
|
+
}
|
148
150
|
end
|
149
|
-
|
150
|
-
|
151
|
-
|
151
|
+
context "Operator + (multiple vars):" do
|
152
|
+
it_behaves_like 'expands', {
|
153
|
+
'{+x,hello,y}' => '1024,Hello%20World!,768',
|
154
|
+
'{+path,x}/here' => '/foo/bar,1024/here'
|
155
|
+
}
|
152
156
|
end
|
153
|
-
|
154
|
-
|
155
|
-
|
157
|
+
context "Operator # (multiple vars):" do
|
158
|
+
it_behaves_like 'expands', {
|
159
|
+
'{#x,hello,y}' => '#1024,Hello%20World!,768',
|
160
|
+
'{#path,x}/here' => '#/foo/bar,1024/here'
|
161
|
+
}
|
156
162
|
end
|
157
|
-
|
158
|
-
|
159
|
-
|
163
|
+
context "Operator ." do
|
164
|
+
it_behaves_like 'expands', {
|
165
|
+
'X{.var}' => 'X.value',
|
166
|
+
'X{.x,y}' => 'X.1024.768'
|
167
|
+
}
|
160
168
|
end
|
161
|
-
|
162
|
-
|
163
|
-
|
169
|
+
context "Operator /" do
|
170
|
+
it_behaves_like 'expands', {
|
171
|
+
'{/var}' => '/value',
|
172
|
+
'{/var,x}/here' => '/value/1024/here'
|
173
|
+
}
|
164
174
|
end
|
165
|
-
|
166
|
-
|
167
|
-
|
175
|
+
context "Operator ;" do
|
176
|
+
it_behaves_like 'expands', {
|
177
|
+
'{;x,y}' => ';x=1024;y=768',
|
178
|
+
'{;x,y,empty}' => ';x=1024;y=768;empty'
|
179
|
+
}
|
168
180
|
end
|
169
|
-
|
170
|
-
|
171
|
-
|
181
|
+
context "Operator ?" do
|
182
|
+
it_behaves_like 'expands', {
|
183
|
+
'{?x,y}' => '?x=1024&y=768',
|
184
|
+
'{?x,y,empty}' => '?x=1024&y=768&empty='
|
185
|
+
}
|
172
186
|
end
|
173
|
-
|
174
|
-
|
175
|
-
|
187
|
+
context "Operator &" do
|
188
|
+
it_behaves_like 'expands', {
|
189
|
+
'?fixed=yes{&x}' => '?fixed=yes&x=1024',
|
190
|
+
'{&x,y,empty}' => '&x=1024&y=768&empty='
|
191
|
+
}
|
176
192
|
end
|
177
193
|
end
|
178
194
|
|
179
|
-
describe
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
195
|
+
describe "Level 4" do
|
196
|
+
subject {
|
197
|
+
{
|
198
|
+
:var => "value",
|
199
|
+
:hello => "Hello World!",
|
200
|
+
:path => "/foo/bar",
|
201
|
+
:semi => ";",
|
202
|
+
:list => %w(red green blue),
|
203
|
+
:keys => {"semi" => ';', "dot" => '.', "comma" => ','}
|
204
|
+
}
|
205
|
+
}
|
206
|
+
context "Expansion with value modifiers" do
|
207
|
+
it_behaves_like 'expands', {
|
208
|
+
'{var:3}' => 'val',
|
209
|
+
'{var:30}' => 'value',
|
210
|
+
'{list}' => 'red,green,blue',
|
211
|
+
'{list*}' => 'red,green,blue',
|
212
|
+
'{keys}' => [
|
213
|
+
'semi,%3B,dot,.,comma,%2C',
|
214
|
+
'dot,.,semi,%3B,comma,%2C',
|
215
|
+
'comma,%2C,semi,%3B,dot,.',
|
216
|
+
'semi,%3B,comma,%2C,dot,.',
|
217
|
+
'dot,.,comma,%2C,semi,%3B',
|
218
|
+
'comma,%2C,dot,.,semi,%3B'
|
219
|
+
],
|
220
|
+
'{keys*}' => [
|
221
|
+
'semi=%3B,dot=.,comma=%2C',
|
222
|
+
'dot=.,semi=%3B,comma=%2C',
|
223
|
+
'comma=%2C,semi=%3B,dot=.',
|
224
|
+
'semi=%3B,comma=%2C,dot=.',
|
225
|
+
'dot=.,comma=%2C,semi=%3B',
|
226
|
+
'comma=%2C,dot=.,semi=%3B'
|
227
|
+
]
|
228
|
+
}
|
187
229
|
end
|
188
|
-
|
189
|
-
|
190
|
-
|
230
|
+
context "Operator + with value modifiers" do
|
231
|
+
it_behaves_like 'expands', {
|
232
|
+
'{+path:6}/here' => '/foo/b/here',
|
233
|
+
'{+list}' => 'red,green,blue',
|
234
|
+
'{+list*}' => 'red,green,blue',
|
235
|
+
'{+keys}' => [
|
236
|
+
'semi,;,dot,.,comma,,',
|
237
|
+
'dot,.,semi,;,comma,,',
|
238
|
+
'comma,,,semi,;,dot,.',
|
239
|
+
'semi,;,comma,,,dot,.',
|
240
|
+
'dot,.,comma,,,semi,;',
|
241
|
+
'comma,,,dot,.,semi,;'
|
242
|
+
],
|
243
|
+
'{+keys*}' => [
|
244
|
+
'semi=;,dot=.,comma=,',
|
245
|
+
'dot=.,semi=;,comma=,',
|
246
|
+
'comma=,,semi=;,dot=.',
|
247
|
+
'semi=;,comma=,,dot=.',
|
248
|
+
'dot=.,comma=,,semi=;',
|
249
|
+
'comma=,,dot=.,semi=;'
|
250
|
+
]
|
251
|
+
}
|
191
252
|
end
|
192
|
-
|
193
|
-
|
194
|
-
|
253
|
+
context "Operator # with value modifiers" do
|
254
|
+
it_behaves_like 'expands', {
|
255
|
+
'{#path:6}/here' => '#/foo/b/here',
|
256
|
+
'{#list}' => '#red,green,blue',
|
257
|
+
'{#list*}' => '#red,green,blue',
|
258
|
+
'{#keys}' => [
|
259
|
+
'#semi,;,dot,.,comma,,',
|
260
|
+
'#dot,.,semi,;,comma,,',
|
261
|
+
'#comma,,,semi,;,dot,.',
|
262
|
+
'#semi,;,comma,,,dot,.',
|
263
|
+
'#dot,.,comma,,,semi,;',
|
264
|
+
'#comma,,,dot,.,semi,;'
|
265
|
+
],
|
266
|
+
'{#keys*}' => [
|
267
|
+
'#semi=;,dot=.,comma=,',
|
268
|
+
'#dot=.,semi=;,comma=,',
|
269
|
+
'#comma=,,semi=;,dot=.',
|
270
|
+
'#semi=;,comma=,,dot=.',
|
271
|
+
'#dot=.,comma=,,semi=;',
|
272
|
+
'#comma=,,dot=.,semi=;'
|
273
|
+
]
|
274
|
+
}
|
195
275
|
end
|
196
|
-
|
197
|
-
|
198
|
-
|
276
|
+
context "Operator . with value modifiers" do
|
277
|
+
it_behaves_like 'expands', {
|
278
|
+
'X{.var:3}' => 'X.val',
|
279
|
+
'X{.list}' => 'X.red,green,blue',
|
280
|
+
'X{.list*}' => 'X.red.green.blue',
|
281
|
+
'X{.keys}' => [
|
282
|
+
'X.semi,%3B,dot,.,comma,%2C',
|
283
|
+
'X.dot,.,semi,%3B,comma,%2C',
|
284
|
+
'X.comma,%2C,semi,%3B,dot,.',
|
285
|
+
'X.semi,%3B,comma,%2C,dot,.',
|
286
|
+
'X.dot,.,comma,%2C,semi,%3B',
|
287
|
+
'X.comma,%2C,dot,.,semi,%3B'
|
288
|
+
],
|
289
|
+
'X{.keys*}' => [
|
290
|
+
'X.semi=%3B.dot=..comma=%2C',
|
291
|
+
'X.dot=..semi=%3B.comma=%2C',
|
292
|
+
'X.comma=%2C.semi=%3B.dot=.',
|
293
|
+
'X.semi=%3B.comma=%2C.dot=.',
|
294
|
+
'X.dot=..comma=%2C.semi=%3B',
|
295
|
+
'X.comma=%2C.dot=..semi=%3B'
|
296
|
+
]
|
297
|
+
}
|
199
298
|
end
|
200
|
-
|
201
|
-
|
202
|
-
|
299
|
+
context "Operator / with value modifiers" do
|
300
|
+
it_behaves_like 'expands', {
|
301
|
+
'{/var:1,var}' => '/v/value',
|
302
|
+
'{/list}' => '/red,green,blue',
|
303
|
+
'{/list*}' => '/red/green/blue',
|
304
|
+
'{/list*,path:4}' => '/red/green/blue/%2Ffoo',
|
305
|
+
'{/keys}' => [
|
306
|
+
'/semi,%3B,dot,.,comma,%2C',
|
307
|
+
'/dot,.,semi,%3B,comma,%2C',
|
308
|
+
'/comma,%2C,semi,%3B,dot,.',
|
309
|
+
'/semi,%3B,comma,%2C,dot,.',
|
310
|
+
'/dot,.,comma,%2C,semi,%3B',
|
311
|
+
'/comma,%2C,dot,.,semi,%3B'
|
312
|
+
],
|
313
|
+
'{/keys*}' => [
|
314
|
+
'/semi=%3B/dot=./comma=%2C',
|
315
|
+
'/dot=./semi=%3B/comma=%2C',
|
316
|
+
'/comma=%2C/semi=%3B/dot=.',
|
317
|
+
'/semi=%3B/comma=%2C/dot=.',
|
318
|
+
'/dot=./comma=%2C/semi=%3B',
|
319
|
+
'/comma=%2C/dot=./semi=%3B'
|
320
|
+
]
|
321
|
+
}
|
203
322
|
end
|
204
|
-
|
205
|
-
|
206
|
-
|
323
|
+
context "Operator ; with value modifiers" do
|
324
|
+
it_behaves_like 'expands', {
|
325
|
+
'{;hello:5}' => ';hello=Hello',
|
326
|
+
'{;list}' => ';list=red,green,blue',
|
327
|
+
'{;list*}' => ';list=red;list=green;list=blue',
|
328
|
+
'{;keys}' => [
|
329
|
+
';keys=semi,%3B,dot,.,comma,%2C',
|
330
|
+
';keys=dot,.,semi,%3B,comma,%2C',
|
331
|
+
';keys=comma,%2C,semi,%3B,dot,.',
|
332
|
+
';keys=semi,%3B,comma,%2C,dot,.',
|
333
|
+
';keys=dot,.,comma,%2C,semi,%3B',
|
334
|
+
';keys=comma,%2C,dot,.,semi,%3B'
|
335
|
+
],
|
336
|
+
'{;keys*}' => [
|
337
|
+
';semi=%3B;dot=.;comma=%2C',
|
338
|
+
';dot=.;semi=%3B;comma=%2C',
|
339
|
+
';comma=%2C;semi=%3B;dot=.',
|
340
|
+
';semi=%3B;comma=%2C;dot=.',
|
341
|
+
';dot=.;comma=%2C;semi=%3B',
|
342
|
+
';comma=%2C;dot=.;semi=%3B'
|
343
|
+
]
|
344
|
+
}
|
207
345
|
end
|
208
|
-
|
209
|
-
|
210
|
-
|
346
|
+
context "Operator ? with value modifiers" do
|
347
|
+
it_behaves_like 'expands', {
|
348
|
+
'{?var:3}' => '?var=val',
|
349
|
+
'{?list}' => '?list=red,green,blue',
|
350
|
+
'{?list*}' => '?list=red&list=green&list=blue',
|
351
|
+
'{?keys}' => [
|
352
|
+
'?keys=semi,%3B,dot,.,comma,%2C',
|
353
|
+
'?keys=dot,.,semi,%3B,comma,%2C',
|
354
|
+
'?keys=comma,%2C,semi,%3B,dot,.',
|
355
|
+
'?keys=semi,%3B,comma,%2C,dot,.',
|
356
|
+
'?keys=dot,.,comma,%2C,semi,%3B',
|
357
|
+
'?keys=comma,%2C,dot,.,semi,%3B'
|
358
|
+
],
|
359
|
+
'{?keys*}' => [
|
360
|
+
'?semi=%3B&dot=.&comma=%2C',
|
361
|
+
'?dot=.&semi=%3B&comma=%2C',
|
362
|
+
'?comma=%2C&semi=%3B&dot=.',
|
363
|
+
'?semi=%3B&comma=%2C&dot=.',
|
364
|
+
'?dot=.&comma=%2C&semi=%3B',
|
365
|
+
'?comma=%2C&dot=.&semi=%3B'
|
366
|
+
]
|
367
|
+
}
|
211
368
|
end
|
212
|
-
|
213
|
-
|
214
|
-
|
369
|
+
context "Operator & with value modifiers" do
|
370
|
+
it_behaves_like 'expands', {
|
371
|
+
'{&var:3}' => '&var=val',
|
372
|
+
'{&list}' => '&list=red,green,blue',
|
373
|
+
'{&list*}' => '&list=red&list=green&list=blue',
|
374
|
+
'{&keys}' => [
|
375
|
+
'&keys=semi,%3B,dot,.,comma,%2C',
|
376
|
+
'&keys=dot,.,semi,%3B,comma,%2C',
|
377
|
+
'&keys=comma,%2C,semi,%3B,dot,.',
|
378
|
+
'&keys=semi,%3B,comma,%2C,dot,.',
|
379
|
+
'&keys=dot,.,comma,%2C,semi,%3B',
|
380
|
+
'&keys=comma,%2C,dot,.,semi,%3B'
|
381
|
+
],
|
382
|
+
'{&keys*}' => [
|
383
|
+
'&semi=%3B&dot=.&comma=%2C',
|
384
|
+
'&dot=.&semi=%3B&comma=%2C',
|
385
|
+
'&comma=%2C&semi=%3B&dot=.',
|
386
|
+
'&semi=%3B&comma=%2C&dot=.',
|
387
|
+
'&dot=.&comma=%2C&semi=%3B',
|
388
|
+
'&comma=%2C&dot=.&semi=%3B'
|
389
|
+
]
|
390
|
+
}
|
215
391
|
end
|
216
392
|
end
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
end
|
235
|
-
|
236
|
-
it "should not match '/1/1'" do
|
237
|
-
@template.match("/1/1").should == nil
|
238
|
-
end
|
239
|
-
|
240
|
-
it "should not match '/11/'" do
|
241
|
-
@template.match("/11/").should == nil
|
242
|
-
end
|
243
|
-
|
244
|
-
it "should not match '/1/2/'" do
|
245
|
-
@template.match("/1/2/").should == nil
|
246
|
-
end
|
247
|
-
|
248
|
-
it "should not match '/2/1/'" do
|
249
|
-
@template.match("/2/1/").should == nil
|
250
|
-
end
|
251
|
-
|
252
|
-
it "should not match '/1/'" do
|
253
|
-
@template.match("/1/").should == nil
|
254
|
-
end
|
255
|
-
|
256
|
-
it "should not match '/1/1/1/'" do
|
257
|
-
@template.match("/1/1/1/").should == nil
|
393
|
+
describe "Modifiers" do
|
394
|
+
subject {
|
395
|
+
{
|
396
|
+
:var => "value",
|
397
|
+
:semi => ";",
|
398
|
+
:year => %w(1965 2000 2012),
|
399
|
+
:dom => %w(example com)
|
400
|
+
}
|
401
|
+
}
|
402
|
+
context "length" do
|
403
|
+
it_behaves_like 'expands', {
|
404
|
+
'{var:3}' => 'val',
|
405
|
+
'{var:30}' => 'value',
|
406
|
+
'{var}' => 'value',
|
407
|
+
'{semi}' => '%3B',
|
408
|
+
'{semi:2}' => '%3B'
|
409
|
+
}
|
258
410
|
end
|
259
|
-
|
260
|
-
|
261
|
-
|
411
|
+
context "explode" do
|
412
|
+
it_behaves_like 'expands', {
|
413
|
+
'find{?year*}' => 'find?year=1965&year=2000&year=2012',
|
414
|
+
'www{.dom*}' => 'www.example.com',
|
415
|
+
}
|
262
416
|
end
|
263
417
|
end
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
"/
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
418
|
+
describe "Expansion" do
|
419
|
+
subject {
|
420
|
+
{
|
421
|
+
:count => ["one", "two", "three"],
|
422
|
+
:dom => ["example", "com"],
|
423
|
+
:dub => "me/too",
|
424
|
+
:hello => "Hello World!",
|
425
|
+
:half => "50%",
|
426
|
+
:var => "value",
|
427
|
+
:who => "fred",
|
428
|
+
:base => "http://example.com/home/",
|
429
|
+
:path => "/foo/bar",
|
430
|
+
:list => ["red", "green", "blue"],
|
431
|
+
:keys => {"semi" => ";","dot" => ".","comma" => ","},
|
432
|
+
:v => "6",
|
433
|
+
:x => "1024",
|
434
|
+
:y => "768",
|
435
|
+
:empty => "",
|
436
|
+
:empty_keys => {},
|
437
|
+
:undef => nil
|
438
|
+
}
|
439
|
+
}
|
440
|
+
context "concatenation" do
|
441
|
+
it_behaves_like 'expands', {
|
442
|
+
'{count}' => 'one,two,three',
|
443
|
+
'{count*}' => 'one,two,three',
|
444
|
+
'{/count}' => '/one,two,three',
|
445
|
+
'{/count*}' => '/one/two/three',
|
446
|
+
'{;count}' => ';count=one,two,three',
|
447
|
+
'{;count*}' => ';count=one;count=two;count=three',
|
448
|
+
'{?count}' => '?count=one,two,three',
|
449
|
+
'{?count*}' => '?count=one&count=two&count=three',
|
450
|
+
'{&count*}' => '&count=one&count=two&count=three'
|
290
451
|
}
|
291
452
|
end
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
453
|
+
context "simple expansion" do
|
454
|
+
it_behaves_like 'expands', {
|
455
|
+
'{var}' => 'value',
|
456
|
+
'{hello}' => 'Hello%20World%21',
|
457
|
+
'{half}' => '50%25',
|
458
|
+
'O{empty}X' => 'OX',
|
459
|
+
'O{undef}X' => 'OX',
|
460
|
+
'{x,y}' => '1024,768',
|
461
|
+
'{x,hello,y}' => '1024,Hello%20World%21,768',
|
462
|
+
'?{x,empty}' => '?1024,',
|
463
|
+
'?{x,undef}' => '?1024',
|
464
|
+
'?{undef,y}' => '?768',
|
465
|
+
'{var:3}' => 'val',
|
466
|
+
'{var:30}' => 'value',
|
467
|
+
'{list}' => 'red,green,blue',
|
468
|
+
'{list*}' => 'red,green,blue',
|
469
|
+
'{keys}' => [
|
470
|
+
'semi,%3B,dot,.,comma,%2C',
|
471
|
+
'dot,.,semi,%3B,comma,%2C',
|
472
|
+
'comma,%2C,semi,%3B,dot,.',
|
473
|
+
'semi,%3B,comma,%2C,dot,.',
|
474
|
+
'dot,.,comma,%2C,semi,%3B',
|
475
|
+
'comma,%2C,dot,.,semi,%3B'
|
476
|
+
],
|
477
|
+
'{keys*}' => [
|
478
|
+
'semi=%3B,dot=.,comma=%2C',
|
479
|
+
'dot=.,semi=%3B,comma=%2C',
|
480
|
+
'comma=%2C,semi=%3B,dot=.',
|
481
|
+
'semi=%3B,comma=%2C,dot=.',
|
482
|
+
'dot=.,comma=%2C,semi=%3B',
|
483
|
+
'comma=%2C,dot=.,semi=%3B'
|
484
|
+
]
|
485
|
+
}
|
303
486
|
end
|
304
|
-
|
305
|
-
|
306
|
-
|
487
|
+
context "reserved expansion (+)" do
|
488
|
+
it_behaves_like 'expands', {
|
489
|
+
'{+var}' => 'value',
|
490
|
+
'{+hello}' => 'Hello%20World!',
|
491
|
+
'{+half}' => '50%25',
|
492
|
+
'{base}index' => 'http%3A%2F%2Fexample.com%2Fhome%2Findex',
|
493
|
+
'{+base}index' => 'http://example.com/home/index',
|
494
|
+
'O{+empty}X' => 'OX',
|
495
|
+
'O{+undef}X' => 'OX',
|
496
|
+
'{+path}/here' => '/foo/bar/here',
|
497
|
+
'here?ref={+path}' => 'here?ref=/foo/bar',
|
498
|
+
'up{+path}{var}/here' => 'up/foo/barvalue/here',
|
499
|
+
'{+x,hello,y}' => '1024,Hello%20World!,768',
|
500
|
+
'{+path,x}/here' => '/foo/bar,1024/here',
|
501
|
+
'{+path:6}/here' => '/foo/b/here',
|
502
|
+
'{+list}' => 'red,green,blue',
|
503
|
+
'{+list*}' => 'red,green,blue',
|
504
|
+
'{+keys}' => [
|
505
|
+
'semi,;,dot,.,comma,,',
|
506
|
+
'dot,.,semi,;,comma,,',
|
507
|
+
'comma,,,semi,;,dot,.',
|
508
|
+
'semi,;,comma,,,dot,.',
|
509
|
+
'dot,.,comma,,,semi,;',
|
510
|
+
'comma,,,dot,.,semi,;'
|
511
|
+
],
|
512
|
+
'{+keys*}' => [
|
513
|
+
'semi=;,dot=.,comma=,',
|
514
|
+
'dot=.,semi=;,comma=,',
|
515
|
+
'comma=,,semi=;,dot=.',
|
516
|
+
'semi=;,comma=,,dot=.',
|
517
|
+
'dot=.,comma=,,semi=;',
|
518
|
+
'comma=,,dot=.,semi=;'
|
519
|
+
]
|
520
|
+
}
|
307
521
|
end
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
522
|
+
context "fragment expansion (#)" do
|
523
|
+
it_behaves_like 'expands', {
|
524
|
+
'{#var}' => '#value',
|
525
|
+
'{#hello}' => '#Hello%20World!',
|
526
|
+
'{#half}' => '#50%25',
|
527
|
+
'foo{#empty}' => 'foo#',
|
528
|
+
'foo{#undef}' => 'foo',
|
529
|
+
'{#x,hello,y}' => '#1024,Hello%20World!,768',
|
530
|
+
'{#path,x}/here' => '#/foo/bar,1024/here',
|
531
|
+
'{#path:6}/here' => '#/foo/b/here',
|
532
|
+
'{#list}' => '#red,green,blue',
|
533
|
+
'{#list*}' => '#red,green,blue',
|
534
|
+
'{#keys}' => [
|
535
|
+
'#semi,;,dot,.,comma,,',
|
536
|
+
'#dot,.,semi,;,comma,,',
|
537
|
+
'#comma,,,semi,;,dot,.',
|
538
|
+
'#semi,;,comma,,,dot,.',
|
539
|
+
'#dot,.,comma,,,semi,;',
|
540
|
+
'#comma,,,dot,.,semi,;'
|
541
|
+
],
|
542
|
+
'{#keys*}' => [
|
543
|
+
'#semi=;,dot=.,comma=,',
|
544
|
+
'#dot=.,semi=;,comma=,',
|
545
|
+
'#comma=,,semi=;,dot=.',
|
546
|
+
'#semi=;,comma=,,dot=.',
|
547
|
+
'#dot=.,comma=,,semi=;',
|
548
|
+
'#comma=,,dot=.,semi=;'
|
549
|
+
]
|
550
|
+
}
|
314
551
|
end
|
315
|
-
|
316
|
-
|
317
|
-
|
552
|
+
context "label expansion (.)" do
|
553
|
+
it_behaves_like 'expands', {
|
554
|
+
'{.who}' => '.fred',
|
555
|
+
'{.who,who}' => '.fred.fred',
|
556
|
+
'{.half,who}' => '.50%25.fred',
|
557
|
+
'www{.dom*}' => 'www.example.com',
|
558
|
+
'X{.var}' => 'X.value',
|
559
|
+
'X{.empty}' => 'X.',
|
560
|
+
'X{.undef}' => 'X',
|
561
|
+
'X{.var:3}' => 'X.val',
|
562
|
+
'X{.list}' => 'X.red,green,blue',
|
563
|
+
'X{.list*}' => 'X.red.green.blue',
|
564
|
+
'X{.keys}' => [
|
565
|
+
'X.semi,%3B,dot,.,comma,%2C',
|
566
|
+
'X.dot,.,semi,%3B,comma,%2C',
|
567
|
+
'X.comma,%2C,semi,%3B,dot,.',
|
568
|
+
'X.semi,%3B,comma,%2C,dot,.',
|
569
|
+
'X.dot,.,comma,%2C,semi,%3B',
|
570
|
+
'X.comma,%2C,dot,.,semi,%3B'
|
571
|
+
],
|
572
|
+
'X{.keys*}' => [
|
573
|
+
'X.semi=%3B.dot=..comma=%2C',
|
574
|
+
'X.dot=..semi=%3B.comma=%2C',
|
575
|
+
'X.comma=%2C.semi=%3B.dot=.',
|
576
|
+
'X.semi=%3B.comma=%2C.dot=.',
|
577
|
+
'X.dot=..comma=%2C.semi=%3B',
|
578
|
+
'X.comma=%2C.dot=..semi=%3B'
|
579
|
+
],
|
580
|
+
'X{.empty_keys}' => 'X',
|
581
|
+
'X{.empty_keys*}' => 'X'
|
582
|
+
}
|
318
583
|
end
|
319
|
-
|
320
|
-
|
321
|
-
|
584
|
+
context "path expansion (/)" do
|
585
|
+
it_behaves_like 'expands', {
|
586
|
+
'{/who}' => '/fred',
|
587
|
+
'{/who,who}' => '/fred/fred',
|
588
|
+
'{/half,who}' => '/50%25/fred',
|
589
|
+
'{/who,dub}' => '/fred/me%2Ftoo',
|
590
|
+
'{/var}' => '/value',
|
591
|
+
'{/var,empty}' => '/value/',
|
592
|
+
'{/var,undef}' => '/value',
|
593
|
+
'{/var,x}/here' => '/value/1024/here',
|
594
|
+
'{/var:1,var}' => '/v/value',
|
595
|
+
'{/list}' => '/red,green,blue',
|
596
|
+
'{/list*}' => '/red/green/blue',
|
597
|
+
'{/list*,path:4}' => '/red/green/blue/%2Ffoo',
|
598
|
+
'{/keys}' => [
|
599
|
+
'/semi,%3B,dot,.,comma,%2C',
|
600
|
+
'/dot,.,semi,%3B,comma,%2C',
|
601
|
+
'/comma,%2C,semi,%3B,dot,.',
|
602
|
+
'/semi,%3B,comma,%2C,dot,.',
|
603
|
+
'/dot,.,comma,%2C,semi,%3B',
|
604
|
+
'/comma,%2C,dot,.,semi,%3B'
|
605
|
+
],
|
606
|
+
'{/keys*}' => [
|
607
|
+
'/semi=%3B/dot=./comma=%2C',
|
608
|
+
'/dot=./semi=%3B/comma=%2C',
|
609
|
+
'/comma=%2C/semi=%3B/dot=.',
|
610
|
+
'/semi=%3B/comma=%2C/dot=.',
|
611
|
+
'/dot=./comma=%2C/semi=%3B',
|
612
|
+
'/comma=%2C/dot=./semi=%3B'
|
613
|
+
]
|
614
|
+
}
|
322
615
|
end
|
323
|
-
|
324
|
-
|
325
|
-
|
616
|
+
context "path-style expansion (;)" do
|
617
|
+
it_behaves_like 'expands', {
|
618
|
+
'{;who}' => ';who=fred',
|
619
|
+
'{;half}' => ';half=50%25',
|
620
|
+
'{;empty}' => ';empty',
|
621
|
+
'{;v,empty,who}' => ';v=6;empty;who=fred',
|
622
|
+
'{;v,bar,who}' => ';v=6;who=fred',
|
623
|
+
'{;x,y}' => ';x=1024;y=768',
|
624
|
+
'{;x,y,empty}' => ';x=1024;y=768;empty',
|
625
|
+
'{;x,y,undef}' => ';x=1024;y=768',
|
626
|
+
'{;hello:5}' => ';hello=Hello',
|
627
|
+
'{;list}' => ';list=red,green,blue',
|
628
|
+
'{;list*}' => ';list=red;list=green;list=blue',
|
629
|
+
'{;keys}' => [
|
630
|
+
';keys=semi,%3B,dot,.,comma,%2C',
|
631
|
+
';keys=dot,.,semi,%3B,comma,%2C',
|
632
|
+
';keys=comma,%2C,semi,%3B,dot,.',
|
633
|
+
';keys=semi,%3B,comma,%2C,dot,.',
|
634
|
+
';keys=dot,.,comma,%2C,semi,%3B',
|
635
|
+
';keys=comma,%2C,dot,.,semi,%3B'
|
636
|
+
],
|
637
|
+
'{;keys*}' => [
|
638
|
+
';semi=%3B;dot=.;comma=%2C',
|
639
|
+
';dot=.;semi=%3B;comma=%2C',
|
640
|
+
';comma=%2C;semi=%3B;dot=.',
|
641
|
+
';semi=%3B;comma=%2C;dot=.',
|
642
|
+
';dot=.;comma=%2C;semi=%3B',
|
643
|
+
';comma=%2C;dot=.;semi=%3B'
|
644
|
+
]
|
645
|
+
}
|
326
646
|
end
|
327
|
-
|
328
|
-
|
329
|
-
|
647
|
+
context "form query expansion (?)" do
|
648
|
+
it_behaves_like 'expands', {
|
649
|
+
'{?who}' => '?who=fred',
|
650
|
+
'{?half}' => '?half=50%25',
|
651
|
+
'{?x,y}' => '?x=1024&y=768',
|
652
|
+
'{?x,y,empty}' => '?x=1024&y=768&empty=',
|
653
|
+
'{?x,y,undef}' => '?x=1024&y=768',
|
654
|
+
'{?var:3}' => '?var=val',
|
655
|
+
'{?list}' => '?list=red,green,blue',
|
656
|
+
'{?list*}' => '?list=red&list=green&list=blue',
|
657
|
+
'{?keys}' => [
|
658
|
+
'?keys=semi,%3B,dot,.,comma,%2C',
|
659
|
+
'?keys=dot,.,semi,%3B,comma,%2C',
|
660
|
+
'?keys=comma,%2C,semi,%3B,dot,.',
|
661
|
+
'?keys=semi,%3B,comma,%2C,dot,.',
|
662
|
+
'?keys=dot,.,comma,%2C,semi,%3B',
|
663
|
+
'?keys=comma,%2C,dot,.,semi,%3B'
|
664
|
+
],
|
665
|
+
'{?keys*}' => [
|
666
|
+
'?semi=%3B&dot=.&comma=%2C',
|
667
|
+
'?dot=.&semi=%3B&comma=%2C',
|
668
|
+
'?comma=%2C&semi=%3B&dot=.',
|
669
|
+
'?semi=%3B&comma=%2C&dot=.',
|
670
|
+
'?dot=.&comma=%2C&semi=%3B',
|
671
|
+
'?comma=%2C&dot=.&semi=%3B'
|
672
|
+
]
|
673
|
+
}
|
330
674
|
end
|
331
|
-
|
332
|
-
|
333
|
-
|
675
|
+
context "form query expansion (&)" do
|
676
|
+
it_behaves_like 'expands', {
|
677
|
+
'{&who}' => '&who=fred',
|
678
|
+
'{&half}' => '&half=50%25',
|
679
|
+
'?fixed=yes{&x}' => '?fixed=yes&x=1024',
|
680
|
+
'{&x,y,empty}' => '&x=1024&y=768&empty=',
|
681
|
+
'{&x,y,undef}' => '&x=1024&y=768',
|
682
|
+
'{&var:3}' => '&var=val',
|
683
|
+
'{&list}' => '&list=red,green,blue',
|
684
|
+
'{&list*}' => '&list=red&list=green&list=blue',
|
685
|
+
'{&keys}' => [
|
686
|
+
'&keys=semi,%3B,dot,.,comma,%2C',
|
687
|
+
'&keys=dot,.,semi,%3B,comma,%2C',
|
688
|
+
'&keys=comma,%2C,semi,%3B,dot,.',
|
689
|
+
'&keys=semi,%3B,comma,%2C,dot,.',
|
690
|
+
'&keys=dot,.,comma,%2C,semi,%3B',
|
691
|
+
'&keys=comma,%2C,dot,.,semi,%3B'
|
692
|
+
],
|
693
|
+
'{&keys*}' => [
|
694
|
+
'&semi=%3B&dot=.&comma=%2C',
|
695
|
+
'&dot=.&semi=%3B&comma=%2C',
|
696
|
+
'&comma=%2C&semi=%3B&dot=.',
|
697
|
+
'&semi=%3B&comma=%2C&dot=.',
|
698
|
+
'&dot=.&comma=%2C&semi=%3B',
|
699
|
+
'&comma=%2C&dot=.&semi=%3B'
|
700
|
+
]
|
701
|
+
}
|
334
702
|
end
|
703
|
+
context "non-string key in match data" do
|
704
|
+
subject {Addressable::Template.new("http://example.com/{one}")}
|
335
705
|
|
336
|
-
|
337
|
-
|
706
|
+
it "raises TypeError" do
|
707
|
+
expect { subject.expand(Object.new => "1") }.to raise_error TypeError
|
708
|
+
end
|
338
709
|
end
|
339
710
|
end
|
340
711
|
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
"http://www.example.com/?{-join|&|query,number}"
|
346
|
-
)
|
347
|
-
end
|
348
|
-
|
349
|
-
it "when inspected, should have the correct class name" do
|
350
|
-
@template.inspect.should include("Addressable::Template")
|
351
|
-
end
|
352
|
-
|
353
|
-
it "when inspected, should have the correct object id" do
|
354
|
-
@template.inspect.should include("%#0x" % @template.object_id)
|
355
|
-
end
|
356
|
-
|
357
|
-
it "should have the variables ['query', 'number']" do
|
358
|
-
@template.variables.should == ["query", "number"]
|
359
|
-
end
|
360
|
-
|
361
|
-
it "should not match the pattern 'http://www.example.com/'" do
|
362
|
-
@template.match("http://www.example.com/").should == nil
|
712
|
+
class ExampleTwoProcessor
|
713
|
+
def self.restore(name, value)
|
714
|
+
return value.gsub(/-/, " ") if name == "query"
|
715
|
+
return value
|
363
716
|
end
|
364
717
|
|
365
|
-
|
366
|
-
|
718
|
+
def self.match(name)
|
719
|
+
return ".*?" if name == "first"
|
720
|
+
return ".*"
|
367
721
|
end
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
match = @template.match(
|
372
|
-
"http://www.example.com/?query=mycelium"
|
373
|
-
)
|
374
|
-
match.variables.should == ["query", "number"]
|
375
|
-
match.values.should == ["mycelium", nil]
|
376
|
-
match.mapping.should == {"query" => "mycelium"}
|
377
|
-
match.inspect.should =~ /MatchData/
|
722
|
+
def self.validate(name, value)
|
723
|
+
return !!(value =~ /^[\w ]+$/) if name == "query"
|
724
|
+
return true
|
378
725
|
end
|
379
726
|
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
"http://www.example.com/?query=mycelium&number=100"
|
384
|
-
).mapping.should == {"query" => "mycelium", "number" => "100"}
|
727
|
+
def self.transform(name, value)
|
728
|
+
return value.gsub(/ /, "+") if name == "query"
|
729
|
+
return value
|
385
730
|
end
|
386
731
|
end
|
387
732
|
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
end
|
392
|
-
|
393
|
-
it "should not match the pattern '/{number}/' " +
|
394
|
-
"with the SlashlessProcessor" do
|
395
|
-
Addressable::Template.new(
|
396
|
-
"/{number}/"
|
397
|
-
).extract(@uri, SlashlessProcessor).should == nil
|
398
|
-
end
|
399
|
-
|
400
|
-
it "should have the correct mapping when extracting values " +
|
401
|
-
"using the pattern '/{number}/' without a processor" do
|
402
|
-
Addressable::Template.new("/{number}/").extract(@uri).should == {
|
403
|
-
"number" => "one/two"
|
404
|
-
}
|
405
|
-
end
|
406
|
-
|
407
|
-
it "should have the correct mapping when extracting values " +
|
408
|
-
"using the pattern '/{first}/{second}/' with the SlashlessProcessor" do
|
409
|
-
Addressable::Template.new(
|
410
|
-
"/{first}/{second}/"
|
411
|
-
).extract(@uri, SlashlessProcessor).should == {
|
412
|
-
"first" => "one",
|
413
|
-
"second" => "two"
|
414
|
-
}
|
733
|
+
class DumbProcessor
|
734
|
+
def self.match(name)
|
735
|
+
return ".*?" if name == "first"
|
415
736
|
end
|
416
737
|
end
|
417
738
|
|
418
|
-
describe Addressable::
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
it "should have the correct mapping when extracting values using " +
|
426
|
-
"the pattern 'http://example.com/search/{query}/' with the " +
|
427
|
-
"ExampleProcessor" do
|
428
|
-
Addressable::Template.new(
|
429
|
-
"http://example.com/search/{query}/"
|
430
|
-
).extract(@uri, ExampleProcessor).should == {
|
431
|
-
"query" => "an example search query"
|
432
|
-
}
|
433
|
-
end
|
434
|
-
|
435
|
-
it "should have the correct mapping when extracting values " +
|
436
|
-
"using the pattern " +
|
437
|
-
"'http://example.com/search/{-list|+|query}/'" do
|
438
|
-
Addressable::Template.new(
|
439
|
-
"http://example.com/search/{-list|+|query}/"
|
440
|
-
).extract(@uri).should == {
|
441
|
-
"query" => ["an", "example", "search", "query"]
|
442
|
-
}
|
443
|
-
end
|
444
|
-
|
445
|
-
it "should return nil when extracting values using " +
|
446
|
-
"a non-matching pattern" do
|
447
|
-
Addressable::Template.new(
|
448
|
-
"http://bogus.com/{thingy}/"
|
449
|
-
).extract(@uri).should == nil
|
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
|
450
746
|
end
|
451
|
-
end
|
452
747
|
|
453
|
-
describe
|
454
|
-
"
|
455
|
-
|
456
|
-
|
457
|
-
|
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
|
458
753
|
end
|
459
754
|
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
).extract(@uri, ExampleProcessor).should == {
|
466
|
-
"first" => "a",
|
467
|
-
"second" => "b/c"
|
755
|
+
describe "Matching" do
|
756
|
+
let(:uri){
|
757
|
+
Addressable::URI.parse(
|
758
|
+
"http://example.com/search/an-example-search-query/"
|
759
|
+
)
|
468
760
|
}
|
469
|
-
|
470
|
-
|
471
|
-
it "should have the correct mapping when extracting values " +
|
472
|
-
"using the pattern " +
|
473
|
-
"'http://example.com/{first}/{-list|/|second}/'" do
|
474
|
-
Addressable::Template.new(
|
475
|
-
"http://example.com/{first}/{-list|/|second}/"
|
476
|
-
).extract(@uri).should == {
|
477
|
-
"first" => "a",
|
478
|
-
"second" => ["b", "c"]
|
761
|
+
let(:uri2){
|
762
|
+
Addressable::URI.parse("http://example.com/a/b/c/")
|
479
763
|
}
|
480
|
-
|
481
|
-
|
482
|
-
it "should have the correct mapping when extracting values " +
|
483
|
-
"using the pattern " +
|
484
|
-
"'http://example.com/{first}/{-list|/|rot13}/' " +
|
485
|
-
"with the ExampleProcessor" do
|
486
|
-
Addressable::Template.new(
|
487
|
-
"http://example.com/{first}/{-list|/|rot13}/"
|
488
|
-
).extract(@uri, ExampleProcessor).should == {
|
489
|
-
"first" => "a",
|
490
|
-
"rot13" => ["o", "p"]
|
764
|
+
let(:uri3){
|
765
|
+
Addressable::URI.parse("http://example.com/;a=1;b=2;c=3;first=foo")
|
491
766
|
}
|
492
|
-
|
493
|
-
|
494
|
-
it "should have the correct mapping when extracting values " +
|
495
|
-
"using the pattern " +
|
496
|
-
"'http://example.com/{-list|/|rot13}/' " +
|
497
|
-
"with the ExampleProcessor" do
|
498
|
-
Addressable::Template.new(
|
499
|
-
"http://example.com/{-list|/|rot13}/"
|
500
|
-
).extract(@uri, ExampleProcessor).should == {
|
501
|
-
"rot13" => ["n", "o", "p"]
|
767
|
+
let(:uri4){
|
768
|
+
Addressable::URI.parse("http://example.com/?a=1&b=2&c=3&first=foo")
|
502
769
|
}
|
503
|
-
|
504
|
-
|
505
|
-
it "should not map to anything when extracting values " +
|
506
|
-
"using the pattern " +
|
507
|
-
"'http://example.com/{-list|/|rot13}/'" do
|
508
|
-
Addressable::Template.new(
|
509
|
-
"http://example.com/{-join|/|a,b,c}/"
|
510
|
-
).extract(@uri).should == nil
|
511
|
-
end
|
512
|
-
end
|
513
|
-
|
514
|
-
describe Addressable::URI, "when parsed from " +
|
515
|
-
"'http://example.com/?a=one&b=two&c=three'" do
|
516
|
-
before do
|
517
|
-
@uri = Addressable::URI.parse("http://example.com/?a=one&b=two&c=three")
|
518
|
-
end
|
519
|
-
|
520
|
-
it "should have the correct mapping when extracting values " +
|
521
|
-
"using the pattern " +
|
522
|
-
"'http://example.com/?{-join|&|a,b,c}'" do
|
523
|
-
Addressable::Template.new(
|
524
|
-
"http://example.com/?{-join|&|a,b,c}"
|
525
|
-
).extract(@uri).should == {
|
526
|
-
"a" => "one",
|
527
|
-
"b" => "two",
|
528
|
-
"c" => "three"
|
770
|
+
let(:uri5){
|
771
|
+
"http://example.com/foo"
|
529
772
|
}
|
530
|
-
|
531
|
-
|
773
|
+
context "first uri with ExampleTwoProcessor" do
|
774
|
+
subject {
|
775
|
+
Addressable::Template.new(
|
776
|
+
"http://example.com/search/{query}/"
|
777
|
+
).match(uri, ExampleTwoProcessor)
|
778
|
+
}
|
779
|
+
its(:variables){ should == ["query"] }
|
780
|
+
its(:captures){ should == ["an example search query"] }
|
781
|
+
end
|
532
782
|
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
783
|
+
context "second uri with ExampleTwoProcessor" do
|
784
|
+
subject {
|
785
|
+
Addressable::Template.new(
|
786
|
+
"http://example.com/{first}/{+second}/"
|
787
|
+
).match(uri2, ExampleTwoProcessor)
|
788
|
+
}
|
789
|
+
its(:variables){ should == ["first", "second"] }
|
790
|
+
its(:captures){ should == ["a", "b/c"] }
|
791
|
+
end
|
538
792
|
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
"
|
546
|
-
|
547
|
-
|
548
|
-
end
|
793
|
+
context "second uri with DumbProcessor" do
|
794
|
+
subject {
|
795
|
+
Addressable::Template.new(
|
796
|
+
"http://example.com/{first}/{+second}/"
|
797
|
+
).match(uri2, DumbProcessor)
|
798
|
+
}
|
799
|
+
its(:variables){ should == ["first", "second"] }
|
800
|
+
its(:captures){ should == ["a", "b/c"] }
|
801
|
+
end
|
549
802
|
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
803
|
+
context "second uri" do
|
804
|
+
subject {
|
805
|
+
Addressable::Template.new(
|
806
|
+
"http://example.com/{first}{/second*}/"
|
807
|
+
).match(uri2)
|
808
|
+
}
|
809
|
+
its(:variables){ should == ["first", "second"] }
|
810
|
+
its(:captures){ should == ["a", ["b","c"]] }
|
811
|
+
end
|
812
|
+
context "third uri" do
|
813
|
+
subject {
|
814
|
+
Addressable::Template.new(
|
815
|
+
"http://example.com/{;hash*,first}"
|
816
|
+
).match(uri3)
|
817
|
+
}
|
818
|
+
its(:variables){ should == ["hash", "first"] }
|
819
|
+
its(:captures){ should == [
|
820
|
+
{"a" => "1", "b" => "2", "c" => "3", "first" => "foo"}, nil] }
|
821
|
+
end
|
822
|
+
# Note that this expansion is impossible to revert deterministically - the
|
823
|
+
# * operator means first could have been a key of hash or a separate key.
|
824
|
+
# Semantically, a separate key is more likely, but both are possible.
|
825
|
+
context "fourth uri" do
|
826
|
+
subject {
|
827
|
+
Addressable::Template.new(
|
828
|
+
"http://example.com/{?hash*,first}"
|
829
|
+
).match(uri4)
|
830
|
+
}
|
831
|
+
its(:variables){ should == ["hash", "first"] }
|
832
|
+
its(:captures){ should == [
|
833
|
+
{"a" => "1", "b" => "2", "c" => "3", "first"=> "foo"}, nil] }
|
834
|
+
end
|
835
|
+
context "fifth uri" do
|
836
|
+
subject {
|
837
|
+
Addressable::Template.new(
|
838
|
+
"http://example.com/{path}{?hash*,first}"
|
839
|
+
).match(uri5)
|
840
|
+
}
|
841
|
+
its(:variables){ should == ["path", "hash", "first"] }
|
842
|
+
its(:captures){ should == ["foo", nil, nil] }
|
843
|
+
end
|
554
844
|
end
|
555
845
|
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
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
|
563
859
|
end
|
564
860
|
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
"parts" => ["", "", "something", "", ""]
|
861
|
+
describe "extract" do
|
862
|
+
let(:template) {
|
863
|
+
Addressable::Template.new(
|
864
|
+
"http://{host}{/segments*}/{?one,two,bogus}{#fragment}"
|
865
|
+
)
|
571
866
|
}
|
572
|
-
|
867
|
+
let(:uri){ "http://example.com/a/b/c/?one=1&two=2#foo" }
|
868
|
+
let(:uri2){ "http://example.com/a/b/c/#foo" }
|
869
|
+
it "should be able to extract with queries" do
|
870
|
+
expect(template.extract(uri)).to eq({
|
871
|
+
"host" => "example.com",
|
872
|
+
"segments" => %w(a b c),
|
873
|
+
"one" => "1",
|
874
|
+
"bogus" => nil,
|
875
|
+
"two" => "2",
|
876
|
+
"fragment" => "foo"
|
877
|
+
})
|
878
|
+
end
|
879
|
+
it "should be able to extract without queries" do
|
880
|
+
expect(template.extract(uri2)).to eq({
|
881
|
+
"host" => "example.com",
|
882
|
+
"segments" => %w(a b c),
|
883
|
+
"one" => nil,
|
884
|
+
"bogus" => nil,
|
885
|
+
"two" => nil,
|
886
|
+
"fragment" => "foo"
|
887
|
+
})
|
888
|
+
end
|
573
889
|
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
"
|
578
|
-
|
579
|
-
|
580
|
-
|
890
|
+
context "issue #137" do
|
891
|
+
subject { Addressable::Template.new('/path{?page,per_page}') }
|
892
|
+
|
893
|
+
it "can match empty" do
|
894
|
+
data = subject.extract("/path")
|
895
|
+
expect(data["page"]).to eq(nil)
|
896
|
+
expect(data["per_page"]).to eq(nil)
|
897
|
+
expect(data.keys.sort).to eq(['page', 'per_page'])
|
898
|
+
end
|
899
|
+
|
900
|
+
it "can match first var" do
|
901
|
+
data = subject.extract("/path?page=1")
|
902
|
+
expect(data["page"]).to eq("1")
|
903
|
+
expect(data["per_page"]).to eq(nil)
|
904
|
+
expect(data.keys.sort).to eq(['page', 'per_page'])
|
905
|
+
end
|
906
|
+
|
907
|
+
it "can match second var" do
|
908
|
+
data = subject.extract("/path?per_page=1")
|
909
|
+
expect(data["page"]).to eq(nil)
|
910
|
+
expect(data["per_page"]).to eq("1")
|
911
|
+
expect(data.keys.sort).to eq(['page', 'per_page'])
|
912
|
+
end
|
913
|
+
|
914
|
+
it "can match both vars" do
|
915
|
+
data = subject.extract("/path?page=2&per_page=1")
|
916
|
+
expect(data["page"]).to eq("2")
|
917
|
+
expect(data["per_page"]).to eq("1")
|
918
|
+
expect(data.keys.sort).to eq(['page', 'per_page'])
|
919
|
+
end
|
920
|
+
end
|
581
921
|
end
|
582
|
-
end
|
583
922
|
|
584
|
-
describe
|
585
|
-
"
|
586
|
-
|
587
|
-
|
923
|
+
describe "Partial expand with symbols" do
|
924
|
+
context "partial_expand with two simple values" do
|
925
|
+
subject {
|
926
|
+
Addressable::Template.new("http://example.com/{one}/{two}/")
|
927
|
+
}
|
928
|
+
it "builds a new pattern" do
|
929
|
+
expect(subject.partial_expand(:one => "1").pattern).to eq(
|
930
|
+
"http://example.com/1/{two}/"
|
931
|
+
)
|
932
|
+
end
|
933
|
+
end
|
934
|
+
context "partial_expand query with missing param in middle" do
|
935
|
+
subject {
|
936
|
+
Addressable::Template.new("http://example.com/{?one,two,three}/")
|
937
|
+
}
|
938
|
+
it "builds a new pattern" do
|
939
|
+
expect(subject.partial_expand(:one => "1", :three => "3").pattern).to eq(
|
940
|
+
"http://example.com/?one=1{&two}&three=3/"
|
941
|
+
)
|
942
|
+
end
|
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
|
984
|
+
context "partial_expand with query string" do
|
985
|
+
subject {
|
986
|
+
Addressable::Template.new("http://example.com/{?two,one}/")
|
987
|
+
}
|
988
|
+
it "builds a new pattern" do
|
989
|
+
expect(subject.partial_expand(:one => "1").pattern).to eq(
|
990
|
+
"http://example.com/?one=1{&two}/"
|
991
|
+
)
|
992
|
+
end
|
993
|
+
end
|
994
|
+
context "partial_expand with path operator" do
|
995
|
+
subject {
|
996
|
+
Addressable::Template.new("http://example.com{/one,two}/")
|
997
|
+
}
|
998
|
+
it "builds a new pattern" do
|
999
|
+
expect(subject.partial_expand(:one => "1").pattern).to eq(
|
1000
|
+
"http://example.com/1{/two}/"
|
1001
|
+
)
|
1002
|
+
end
|
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
|
588
1022
|
end
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
"
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
1023
|
+
describe "Partial expand with strings" do
|
1024
|
+
context "partial_expand with two simple values" do
|
1025
|
+
subject {
|
1026
|
+
Addressable::Template.new("http://example.com/{one}/{two}/")
|
1027
|
+
}
|
1028
|
+
it "builds a new pattern" do
|
1029
|
+
expect(subject.partial_expand("one" => "1").pattern).to eq(
|
1030
|
+
"http://example.com/1/{two}/"
|
1031
|
+
)
|
1032
|
+
end
|
1033
|
+
end
|
1034
|
+
context "partial_expand query with missing param in middle" do
|
1035
|
+
subject {
|
1036
|
+
Addressable::Template.new("http://example.com/{?one,two,three}/")
|
1037
|
+
}
|
1038
|
+
it "builds a new pattern" do
|
1039
|
+
expect(subject.partial_expand("one" => "1", "three" => "3").pattern).to eq(
|
1040
|
+
"http://example.com/?one=1{&two}&three=3/"
|
1041
|
+
)
|
1042
|
+
end
|
1043
|
+
end
|
1044
|
+
context "partial_expand with query string" do
|
1045
|
+
subject {
|
1046
|
+
Addressable::Template.new("http://example.com/{?two,one}/")
|
1047
|
+
}
|
1048
|
+
it "builds a new pattern" do
|
1049
|
+
expect(subject.partial_expand("one" => "1").pattern).to eq(
|
1050
|
+
"http://example.com/?one=1{&two}/"
|
1051
|
+
)
|
1052
|
+
end
|
1053
|
+
end
|
1054
|
+
context "partial_expand with path operator" do
|
1055
|
+
subject {
|
1056
|
+
Addressable::Template.new("http://example.com{/one,two}/")
|
1057
|
+
}
|
1058
|
+
it "builds a new pattern" do
|
1059
|
+
expect(subject.partial_expand("one" => "1").pattern).to eq(
|
1060
|
+
"http://example.com/1{/two}/"
|
1061
|
+
)
|
1062
|
+
end
|
1063
|
+
end
|
599
1064
|
end
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
"
|
606
|
-
|
607
|
-
|
608
|
-
|
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
|
1080
|
+
context "expand with a processor" do
|
1081
|
+
subject {
|
1082
|
+
Addressable::Template.new("http://example.com/search/{query}/")
|
1083
|
+
}
|
1084
|
+
it "processes spaces" do
|
1085
|
+
expect(subject.expand({"query" => "an example search query"},
|
1086
|
+
ExampleTwoProcessor).to_str).to eq(
|
1087
|
+
"http://example.com/search/an+example+search+query/"
|
1088
|
+
)
|
1089
|
+
end
|
1090
|
+
it "validates" do
|
1091
|
+
expect{
|
1092
|
+
subject.expand({"query" => "Bogus!"},
|
1093
|
+
ExampleTwoProcessor).to_str
|
1094
|
+
}.to raise_error(Addressable::Template::InvalidTemplateValueError)
|
1095
|
+
end
|
1096
|
+
end
|
1097
|
+
context "partial_expand query with missing param in middle" do
|
1098
|
+
subject {
|
1099
|
+
Addressable::Template.new("http://example.com/{?one,two,three}/")
|
1100
|
+
}
|
1101
|
+
it "builds a new pattern" do
|
1102
|
+
expect(subject.partial_expand("one" => "1", "three" => "3").pattern).to eq(
|
1103
|
+
"http://example.com/?one=1{&two}&three=3/"
|
1104
|
+
)
|
1105
|
+
end
|
1106
|
+
end
|
1107
|
+
context "partial_expand with query string" do
|
1108
|
+
subject {
|
1109
|
+
Addressable::Template.new("http://example.com/{?two,one}/")
|
1110
|
+
}
|
1111
|
+
it "builds a new pattern" do
|
1112
|
+
expect(subject.partial_expand("one" => "1").pattern).to eq(
|
1113
|
+
"http://example.com/?one=1{&two}/"
|
1114
|
+
)
|
1115
|
+
end
|
1116
|
+
end
|
1117
|
+
context "partial_expand with path operator" do
|
1118
|
+
subject {
|
1119
|
+
Addressable::Template.new("http://example.com{/one,two}/")
|
1120
|
+
}
|
1121
|
+
it "builds a new pattern" do
|
1122
|
+
expect(subject.partial_expand("one" => "1").pattern).to eq(
|
1123
|
+
"http://example.com/1{/two}/"
|
1124
|
+
)
|
1125
|
+
end
|
1126
|
+
end
|
609
1127
|
end
|
1128
|
+
context "Matching with operators" do
|
1129
|
+
describe "Level 1:" do
|
1130
|
+
subject { Addressable::Template.new("foo{foo}/{bar}baz") }
|
1131
|
+
it "can match" do
|
1132
|
+
data = subject.match("foofoo/bananabaz")
|
1133
|
+
expect(data.mapping["foo"]).to eq("foo")
|
1134
|
+
expect(data.mapping["bar"]).to eq("banana")
|
1135
|
+
end
|
1136
|
+
it "can fail" do
|
1137
|
+
expect(subject.match("bar/foo")).to be_nil
|
1138
|
+
expect(subject.match("foobaz")).to be_nil
|
1139
|
+
end
|
1140
|
+
it "can match empty" do
|
1141
|
+
data = subject.match("foo/baz")
|
1142
|
+
expect(data.mapping["foo"]).to eq(nil)
|
1143
|
+
expect(data.mapping["bar"]).to eq(nil)
|
1144
|
+
end
|
1145
|
+
it "lists vars" do
|
1146
|
+
expect(subject.variables).to eq(["foo", "bar"])
|
1147
|
+
end
|
1148
|
+
end
|
610
1149
|
|
611
|
-
|
612
|
-
|
613
|
-
"
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
1150
|
+
describe "Level 2:" do
|
1151
|
+
subject { Addressable::Template.new("foo{+foo}{#bar}baz") }
|
1152
|
+
it "can match" do
|
1153
|
+
data = subject.match("foo/test/banana#bazbaz")
|
1154
|
+
expect(data.mapping["foo"]).to eq("/test/banana")
|
1155
|
+
expect(data.mapping["bar"]).to eq("baz")
|
1156
|
+
end
|
1157
|
+
it "can match empty level 2 #" do
|
1158
|
+
data = subject.match("foo/test/bananabaz")
|
1159
|
+
expect(data.mapping["foo"]).to eq("/test/banana")
|
1160
|
+
expect(data.mapping["bar"]).to eq(nil)
|
1161
|
+
data = subject.match("foo/test/banana#baz")
|
1162
|
+
expect(data.mapping["foo"]).to eq("/test/banana")
|
1163
|
+
expect(data.mapping["bar"]).to eq("")
|
1164
|
+
end
|
1165
|
+
it "can match empty level 2 +" do
|
1166
|
+
data = subject.match("foobaz")
|
1167
|
+
expect(data.mapping["foo"]).to eq(nil)
|
1168
|
+
expect(data.mapping["bar"]).to eq(nil)
|
1169
|
+
data = subject.match("foo#barbaz")
|
1170
|
+
expect(data.mapping["foo"]).to eq(nil)
|
1171
|
+
expect(data.mapping["bar"]).to eq("bar")
|
1172
|
+
end
|
1173
|
+
it "lists vars" do
|
1174
|
+
expect(subject.variables).to eq(["foo", "bar"])
|
1175
|
+
end
|
1176
|
+
end
|
618
1177
|
|
619
|
-
|
620
|
-
"
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
1178
|
+
describe "Level 3:" do
|
1179
|
+
context "no operator" do
|
1180
|
+
subject { Addressable::Template.new("foo{foo,bar}baz") }
|
1181
|
+
it "can match" do
|
1182
|
+
data = subject.match("foofoo,barbaz")
|
1183
|
+
expect(data.mapping["foo"]).to eq("foo")
|
1184
|
+
expect(data.mapping["bar"]).to eq("bar")
|
1185
|
+
end
|
1186
|
+
it "lists vars" do
|
1187
|
+
expect(subject.variables).to eq(["foo", "bar"])
|
1188
|
+
end
|
1189
|
+
end
|
1190
|
+
context "+ operator" do
|
1191
|
+
subject { Addressable::Template.new("foo{+foo,bar}baz") }
|
1192
|
+
it "can match" do
|
1193
|
+
data = subject.match("foofoo/bar,barbaz")
|
1194
|
+
expect(data.mapping["bar"]).to eq("foo/bar,bar")
|
1195
|
+
expect(data.mapping["foo"]).to eq("")
|
1196
|
+
end
|
1197
|
+
it "lists vars" do
|
1198
|
+
expect(subject.variables).to eq(["foo", "bar"])
|
1199
|
+
end
|
1200
|
+
end
|
1201
|
+
context ". operator" do
|
1202
|
+
subject { Addressable::Template.new("foo{.foo,bar}baz") }
|
1203
|
+
it "can match" do
|
1204
|
+
data = subject.match("foo.foo.barbaz")
|
1205
|
+
expect(data.mapping["foo"]).to eq("foo")
|
1206
|
+
expect(data.mapping["bar"]).to eq("bar")
|
1207
|
+
end
|
1208
|
+
it "lists vars" do
|
1209
|
+
expect(subject.variables).to eq(["foo", "bar"])
|
1210
|
+
end
|
1211
|
+
end
|
1212
|
+
context "/ operator" do
|
1213
|
+
subject { Addressable::Template.new("foo{/foo,bar}baz") }
|
1214
|
+
it "can match" do
|
1215
|
+
data = subject.match("foo/foo/barbaz")
|
1216
|
+
expect(data.mapping["foo"]).to eq("foo")
|
1217
|
+
expect(data.mapping["bar"]).to eq("bar")
|
1218
|
+
end
|
1219
|
+
it "lists vars" do
|
1220
|
+
expect(subject.variables).to eq(["foo", "bar"])
|
1221
|
+
end
|
1222
|
+
end
|
1223
|
+
context "; operator" do
|
1224
|
+
subject { Addressable::Template.new("foo{;foo,bar,baz}baz") }
|
1225
|
+
it "can match" do
|
1226
|
+
data = subject.match("foo;foo=bar%20baz;bar=foo;bazbaz")
|
1227
|
+
expect(data.mapping["foo"]).to eq("bar baz")
|
1228
|
+
expect(data.mapping["bar"]).to eq("foo")
|
1229
|
+
expect(data.mapping["baz"]).to eq("")
|
1230
|
+
end
|
1231
|
+
it "lists vars" do
|
1232
|
+
expect(subject.variables).to eq(%w(foo bar baz))
|
1233
|
+
end
|
1234
|
+
end
|
1235
|
+
context "? operator" do
|
1236
|
+
context "test" do
|
1237
|
+
subject { Addressable::Template.new("foo{?foo,bar}baz") }
|
1238
|
+
it "can match" do
|
1239
|
+
data = subject.match("foo?foo=bar%20baz&bar=foobaz")
|
1240
|
+
expect(data.mapping["foo"]).to eq("bar baz")
|
1241
|
+
expect(data.mapping["bar"]).to eq("foo")
|
1242
|
+
end
|
1243
|
+
it "lists vars" do
|
1244
|
+
expect(subject.variables).to eq(%w(foo bar))
|
1245
|
+
end
|
1246
|
+
end
|
1247
|
+
|
1248
|
+
context "issue #137" do
|
1249
|
+
subject { Addressable::Template.new('/path{?page,per_page}') }
|
1250
|
+
|
1251
|
+
it "can match empty" do
|
1252
|
+
data = subject.match("/path")
|
1253
|
+
expect(data.mapping["page"]).to eq(nil)
|
1254
|
+
expect(data.mapping["per_page"]).to eq(nil)
|
1255
|
+
expect(data.mapping.keys.sort).to eq(['page', 'per_page'])
|
1256
|
+
end
|
1257
|
+
|
1258
|
+
it "can match first var" do
|
1259
|
+
data = subject.match("/path?page=1")
|
1260
|
+
expect(data.mapping["page"]).to eq("1")
|
1261
|
+
expect(data.mapping["per_page"]).to eq(nil)
|
1262
|
+
expect(data.mapping.keys.sort).to eq(['page', 'per_page'])
|
1263
|
+
end
|
1264
|
+
|
1265
|
+
it "can match second var" do
|
1266
|
+
data = subject.match("/path?per_page=1")
|
1267
|
+
expect(data.mapping["page"]).to eq(nil)
|
1268
|
+
expect(data.mapping["per_page"]).to eq("1")
|
1269
|
+
expect(data.mapping.keys.sort).to eq(['page', 'per_page'])
|
1270
|
+
end
|
1271
|
+
|
1272
|
+
it "can match both vars" do
|
1273
|
+
data = subject.match("/path?page=2&per_page=1")
|
1274
|
+
expect(data.mapping["page"]).to eq("2")
|
1275
|
+
expect(data.mapping["per_page"]).to eq("1")
|
1276
|
+
expect(data.mapping.keys.sort).to eq(['page', 'per_page'])
|
1277
|
+
end
|
1278
|
+
end
|
1279
|
+
|
1280
|
+
context "issue #71" do
|
1281
|
+
subject { Addressable::Template.new("http://cyberscore.dev/api/users{?username}") }
|
1282
|
+
it "can match" do
|
1283
|
+
data = subject.match("http://cyberscore.dev/api/users?username=foobaz")
|
1284
|
+
expect(data.mapping["username"]).to eq("foobaz")
|
1285
|
+
end
|
1286
|
+
it "lists vars" do
|
1287
|
+
expect(subject.variables).to eq(%w(username))
|
1288
|
+
expect(subject.keys).to eq(%w(username))
|
1289
|
+
end
|
1290
|
+
end
|
1291
|
+
end
|
1292
|
+
context "& operator" do
|
1293
|
+
subject { Addressable::Template.new("foo{&foo,bar}baz") }
|
1294
|
+
it "can match" do
|
1295
|
+
data = subject.match("foo&foo=bar%20baz&bar=foobaz")
|
1296
|
+
expect(data.mapping["foo"]).to eq("bar baz")
|
1297
|
+
expect(data.mapping["bar"]).to eq("foo")
|
1298
|
+
end
|
1299
|
+
it "lists vars" do
|
1300
|
+
expect(subject.variables).to eq(%w(foo bar))
|
1301
|
+
end
|
1302
|
+
end
|
1303
|
+
end
|
628
1304
|
end
|
629
1305
|
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
1306
|
+
context "support regexes:" do
|
1307
|
+
context "EXPRESSION" do
|
1308
|
+
subject { Addressable::Template::EXPRESSION }
|
1309
|
+
it "should be able to match an expression" do
|
1310
|
+
expect(subject).to match("{foo}")
|
1311
|
+
expect(subject).to match("{foo,9}")
|
1312
|
+
expect(subject).to match("{foo.bar,baz}")
|
1313
|
+
expect(subject).to match("{+foo.bar,baz}")
|
1314
|
+
expect(subject).to match("{foo,foo%20bar}")
|
1315
|
+
expect(subject).to match("{#foo:20,baz*}")
|
1316
|
+
expect(subject).to match("stuff{#foo:20,baz*}things")
|
1317
|
+
end
|
1318
|
+
it "should fail on non vars" do
|
1319
|
+
expect(subject).not_to match("!{foo")
|
1320
|
+
expect(subject).not_to match("{foo.bar.}")
|
1321
|
+
expect(subject).not_to match("!{}")
|
1322
|
+
end
|
1323
|
+
end
|
1324
|
+
context "VARNAME" do
|
1325
|
+
subject { Addressable::Template::VARNAME }
|
1326
|
+
it "should be able to match a variable" do
|
1327
|
+
expect(subject).to match("foo")
|
1328
|
+
expect(subject).to match("9")
|
1329
|
+
expect(subject).to match("foo.bar")
|
1330
|
+
expect(subject).to match("foo_bar")
|
1331
|
+
expect(subject).to match("foo_bar.baz")
|
1332
|
+
expect(subject).to match("foo%20bar")
|
1333
|
+
expect(subject).to match("foo%20bar.baz")
|
1334
|
+
end
|
1335
|
+
it "should fail on non vars" do
|
1336
|
+
expect(subject).not_to match("!foo")
|
1337
|
+
expect(subject).not_to match("foo.bar.")
|
1338
|
+
expect(subject).not_to match("foo%2%00bar")
|
1339
|
+
expect(subject).not_to match("foo_ba%r")
|
1340
|
+
expect(subject).not_to match("foo_bar*")
|
1341
|
+
expect(subject).not_to match("foo_bar:20")
|
1342
|
+
end
|
1343
|
+
end
|
1344
|
+
context "VARIABLE_LIST" do
|
1345
|
+
subject { Addressable::Template::VARIABLE_LIST }
|
1346
|
+
it "should be able to match a variable list" do
|
1347
|
+
expect(subject).to match("foo,bar")
|
1348
|
+
expect(subject).to match("foo")
|
1349
|
+
expect(subject).to match("foo,bar*,baz")
|
1350
|
+
expect(subject).to match("foo.bar,bar_baz*,baz:12")
|
1351
|
+
end
|
1352
|
+
it "should fail on non vars" do
|
1353
|
+
expect(subject).not_to match(",foo,bar*,baz")
|
1354
|
+
expect(subject).not_to match("foo,*bar,baz")
|
1355
|
+
expect(subject).not_to match("foo,,bar*,baz")
|
1356
|
+
end
|
1357
|
+
end
|
1358
|
+
context "VARSPEC" do
|
1359
|
+
subject { Addressable::Template::VARSPEC }
|
1360
|
+
it "should be able to match a variable with modifier" do
|
1361
|
+
expect(subject).to match("9:8")
|
1362
|
+
expect(subject).to match("foo.bar*")
|
1363
|
+
expect(subject).to match("foo_bar:12")
|
1364
|
+
expect(subject).to match("foo_bar.baz*")
|
1365
|
+
expect(subject).to match("foo%20bar:12")
|
1366
|
+
expect(subject).to match("foo%20bar.baz*")
|
1367
|
+
end
|
1368
|
+
it "should fail on non vars" do
|
1369
|
+
expect(subject).not_to match("!foo")
|
1370
|
+
expect(subject).not_to match("*foo")
|
1371
|
+
expect(subject).not_to match("fo*o")
|
1372
|
+
expect(subject).not_to match("fo:o")
|
1373
|
+
expect(subject).not_to match("foo:")
|
1374
|
+
end
|
1375
|
+
end
|
636
1376
|
end
|
1377
|
+
end
|
637
1378
|
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
1379
|
+
describe Addressable::Template::MatchData do
|
1380
|
+
let(:template) { Addressable::Template.new('{foo}/{bar}') }
|
1381
|
+
subject(:its) { template.match('ab/cd') }
|
1382
|
+
its(:uri) { should == Addressable::URI.parse('ab/cd') }
|
1383
|
+
its(:template) { should == template }
|
1384
|
+
its(:mapping) { should == { 'foo' => 'ab', 'bar' => 'cd' } }
|
1385
|
+
its(:variables) { should == ['foo', 'bar'] }
|
1386
|
+
its(:keys) { should == ['foo', 'bar'] }
|
1387
|
+
its(:names) { should == ['foo', 'bar'] }
|
1388
|
+
its(:values) { should == ['ab', 'cd'] }
|
1389
|
+
its(:captures) { should == ['ab', 'cd'] }
|
1390
|
+
its(:to_a) { should == ['ab/cd', 'ab', 'cd'] }
|
1391
|
+
its(:to_s) { should == 'ab/cd' }
|
1392
|
+
its(:string) { should == its.to_s }
|
1393
|
+
its(:pre_match) { should == "" }
|
1394
|
+
its(:post_match) { should == "" }
|
1395
|
+
|
1396
|
+
describe 'values_at' do
|
1397
|
+
it 'returns an array with the values' do
|
1398
|
+
expect(its.values_at(0, 2)).to eq(['ab/cd', 'cd'])
|
1399
|
+
end
|
1400
|
+
it 'allows mixing integer an string keys' do
|
1401
|
+
expect(its.values_at('foo', 1)).to eq(['ab', 'ab'])
|
1402
|
+
end
|
1403
|
+
it 'accepts unknown keys' do
|
1404
|
+
expect(its.values_at('baz', 'foo')).to eq([nil, 'ab'])
|
1405
|
+
end
|
646
1406
|
end
|
647
1407
|
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
end
|
691
|
-
|
692
|
-
it "should have the correct mapping when extracting values " +
|
693
|
-
"using the pattern " +
|
694
|
-
"'http://example.com/{first}/spacer/{-suffix|/|stuff}'" do
|
695
|
-
Addressable::Template.new(
|
696
|
-
"http://example.com/{first}/spacer/{-suffix|/|stuff}"
|
697
|
-
).extract(@uri).should == {
|
698
|
-
"first" => "one",
|
699
|
-
"stuff" => "two"
|
700
|
-
}
|
701
|
-
end
|
702
|
-
|
703
|
-
it "should not match anything when extracting values " +
|
704
|
-
"using the incorrect suffix pattern " +
|
705
|
-
"'http://example.com/{-suffix|/|stuff}/'" do
|
706
|
-
Addressable::Template.new(
|
707
|
-
"http://example.com/{-suffix|/|stuff}/"
|
708
|
-
).extract(@uri).should == nil
|
709
|
-
end
|
710
|
-
|
711
|
-
it "should have the correct mapping when extracting values " +
|
712
|
-
"using the pattern " +
|
713
|
-
"'http://example.com/{-suffix|/|rot13}' with the ExampleProcessor" do
|
714
|
-
Addressable::Template.new(
|
715
|
-
"http://example.com/{-suffix|/|rot13}"
|
716
|
-
).extract(@uri, ExampleProcessor).should == {
|
717
|
-
"rot13" => ["bar", "fcnpre", "gjb"]
|
718
|
-
}
|
719
|
-
end
|
720
|
-
|
721
|
-
it "should have the correct mapping when extracting values " +
|
722
|
-
"using the pattern " +
|
723
|
-
"'http://example.com{-suffix|/|rot13}' with the ExampleProcessor" do
|
724
|
-
Addressable::Template.new(
|
725
|
-
"http://example.com{-suffix|/|rot13}"
|
726
|
-
).extract(@uri, ExampleProcessor).should == {
|
727
|
-
"rot13" => ["", "bar", "fcnpre", "gjb"]
|
728
|
-
}
|
729
|
-
end
|
730
|
-
|
731
|
-
it "should not match anything when extracting values " +
|
732
|
-
"using the incorrect suffix pattern " +
|
733
|
-
"'http://example.com/{-suffix|/|rot13}/' with the ExampleProcessor" do
|
734
|
-
Addressable::Template.new(
|
735
|
-
"http://example.com/{-suffix|/|rot13}/"
|
736
|
-
).extract(@uri, ExampleProcessor).should == nil
|
737
|
-
end
|
738
|
-
end
|
739
|
-
|
740
|
-
describe Addressable::URI, "when parsed from " +
|
741
|
-
"'http://example.com/?email=bob@sporkmonger.com'" do
|
742
|
-
before do
|
743
|
-
@uri = Addressable::URI.parse(
|
744
|
-
"http://example.com/?email=bob@sporkmonger.com"
|
745
|
-
)
|
746
|
-
end
|
747
|
-
|
748
|
-
it "should not match anything when extracting values " +
|
749
|
-
"using the incorrect opt pattern " +
|
750
|
-
"'http://example.com/?email={-opt|bogus@bogus.com|test}'" do
|
751
|
-
Addressable::Template.new(
|
752
|
-
"http://example.com/?email={-opt|bogus@bogus.com|test}"
|
753
|
-
).extract(@uri).should == nil
|
754
|
-
end
|
755
|
-
|
756
|
-
it "should not match anything when extracting values " +
|
757
|
-
"using the incorrect neg pattern " +
|
758
|
-
"'http://example.com/?email={-neg|bogus@bogus.com|test}'" do
|
759
|
-
Addressable::Template.new(
|
760
|
-
"http://example.com/?email={-neg|bogus@bogus.com|test}"
|
761
|
-
).extract(@uri).should == nil
|
762
|
-
end
|
763
|
-
|
764
|
-
it "should indicate a match when extracting values " +
|
765
|
-
"using the opt pattern " +
|
766
|
-
"'http://example.com/?email={-opt|bob@sporkmonger.com|test}'" do
|
767
|
-
Addressable::Template.new(
|
768
|
-
"http://example.com/?email={-opt|bob@sporkmonger.com|test}"
|
769
|
-
).extract(@uri).should == {}
|
770
|
-
end
|
771
|
-
|
772
|
-
it "should indicate a match when extracting values " +
|
773
|
-
"using the neg pattern " +
|
774
|
-
"'http://example.com/?email={-neg|bob@sporkmonger.com|test}'" do
|
775
|
-
Addressable::Template.new(
|
776
|
-
"http://example.com/?email={-neg|bob@sporkmonger.com|test}"
|
777
|
-
).extract(@uri).should == {}
|
778
|
-
end
|
779
|
-
end
|
780
|
-
|
781
|
-
describe Addressable::URI, "when parsed from " +
|
782
|
-
"'http://example.com/?email='" do
|
783
|
-
before do
|
784
|
-
@uri = Addressable::URI.parse(
|
785
|
-
"http://example.com/?email="
|
786
|
-
)
|
787
|
-
end
|
788
|
-
|
789
|
-
it "should indicate a match when extracting values " +
|
790
|
-
"using the opt pattern " +
|
791
|
-
"'http://example.com/?email={-opt|bob@sporkmonger.com|test}'" do
|
792
|
-
Addressable::Template.new(
|
793
|
-
"http://example.com/?email={-opt|bob@sporkmonger.com|test}"
|
794
|
-
).extract(@uri).should == {}
|
795
|
-
end
|
796
|
-
|
797
|
-
it "should indicate a match when extracting values " +
|
798
|
-
"using the neg pattern " +
|
799
|
-
"'http://example.com/?email={-neg|bob@sporkmonger.com|test}'" do
|
800
|
-
Addressable::Template.new(
|
801
|
-
"http://example.com/?email={-neg|bob@sporkmonger.com|test}"
|
802
|
-
).extract(@uri).should == {}
|
803
|
-
end
|
804
|
-
end
|
805
|
-
|
806
|
-
describe Addressable::URI, "when parsed from " +
|
807
|
-
"'http://example.com/a/b/c/?one=1&two=2#foo'" do
|
808
|
-
before do
|
809
|
-
@uri = Addressable::URI.parse(
|
810
|
-
"http://example.com/a/b/c/?one=1&two=2#foo"
|
811
|
-
)
|
812
|
-
end
|
813
|
-
|
814
|
-
it "should have the correct mapping when extracting values " +
|
815
|
-
"using the pattern " +
|
816
|
-
"'http://{host}/{-suffix|/|segments}?{-join|&|one,two}\#{fragment}'" do
|
817
|
-
Addressable::Template.new(
|
818
|
-
"http://{host}/{-suffix|/|segments}?{-join|&|one,two}\#{fragment}"
|
819
|
-
).extract(@uri).should == {
|
820
|
-
"host" => "example.com",
|
821
|
-
"segments" => ["a", "b", "c"],
|
822
|
-
"one" => "1",
|
823
|
-
"two" => "2",
|
824
|
-
"fragment" => "foo"
|
825
|
-
}
|
826
|
-
end
|
827
|
-
|
828
|
-
it "should not match when extracting values " +
|
829
|
-
"using the pattern " +
|
830
|
-
"'http://{host}/{-suffix|/|segments}?{-join|&|one}\#{fragment}'" do
|
831
|
-
Addressable::Template.new(
|
832
|
-
"http://{host}/{-suffix|/|segments}?{-join|&|one}\#{fragment}"
|
833
|
-
).extract(@uri).should == nil
|
834
|
-
end
|
835
|
-
|
836
|
-
it "should not match when extracting values " +
|
837
|
-
"using the pattern " +
|
838
|
-
"'http://{host}/{-suffix|/|segments}?{-join|&|bogus}\#{fragment}'" do
|
839
|
-
Addressable::Template.new(
|
840
|
-
"http://{host}/{-suffix|/|segments}?{-join|&|bogus}\#{fragment}"
|
841
|
-
).extract(@uri).should == nil
|
842
|
-
end
|
843
|
-
|
844
|
-
it "should not match when extracting values " +
|
845
|
-
"using the pattern " +
|
846
|
-
"'http://{host}/{-suffix|/|segments}?" +
|
847
|
-
"{-join|&|one,bogus}\#{fragment}'" do
|
848
|
-
Addressable::Template.new(
|
849
|
-
"http://{host}/{-suffix|/|segments}?{-join|&|one,bogus}\#{fragment}"
|
850
|
-
).extract(@uri).should == nil
|
851
|
-
end
|
852
|
-
|
853
|
-
it "should not match when extracting values " +
|
854
|
-
"using the pattern " +
|
855
|
-
"'http://{host}/{-suffix|/|segments}?" +
|
856
|
-
"{-join|&|one,two,bogus}\#{fragment}'" do
|
857
|
-
Addressable::Template.new(
|
858
|
-
"http://{host}/{-suffix|/|segments}?{-join|&|one,two,bogus}\#{fragment}"
|
859
|
-
).extract(@uri).should == {
|
860
|
-
"host" => "example.com",
|
861
|
-
"segments" => ["a", "b", "c"],
|
862
|
-
"one" => "1",
|
863
|
-
"two" => "2",
|
864
|
-
"fragment" => "foo"
|
865
|
-
}
|
866
|
-
end
|
867
|
-
end
|
868
|
-
|
869
|
-
describe Addressable::URI, "when given a pattern with bogus operators" do
|
870
|
-
before do
|
871
|
-
@uri = Addressable::URI.parse("http://example.com/a/b/c/")
|
872
|
-
end
|
873
|
-
|
874
|
-
it "should raise an InvalidTemplateOperatorError" do
|
875
|
-
(lambda do
|
876
|
-
Addressable::Template.new(
|
877
|
-
"http://example.com/{-bogus|/|a,b,c}/"
|
878
|
-
).extract(@uri)
|
879
|
-
end).should raise_error(
|
880
|
-
Addressable::Template::InvalidTemplateOperatorError
|
881
|
-
)
|
882
|
-
end
|
883
|
-
|
884
|
-
it "should raise an InvalidTemplateOperatorError" do
|
885
|
-
(lambda do
|
886
|
-
Addressable::Template.new(
|
887
|
-
"http://example.com{-prefix|/|a,b,c}/"
|
888
|
-
).extract(@uri)
|
889
|
-
end).should raise_error(
|
890
|
-
Addressable::Template::InvalidTemplateOperatorError
|
891
|
-
)
|
892
|
-
end
|
893
|
-
|
894
|
-
it "should raise an InvalidTemplateOperatorError" do
|
895
|
-
(lambda do
|
896
|
-
Addressable::Template.new(
|
897
|
-
"http://example.com/{-suffix|/|a,b,c}"
|
898
|
-
).extract(@uri)
|
899
|
-
end).should raise_error(
|
900
|
-
Addressable::Template::InvalidTemplateOperatorError
|
901
|
-
)
|
902
|
-
end
|
903
|
-
|
904
|
-
it "should raise an InvalidTemplateOperatorError" do
|
905
|
-
(lambda do
|
906
|
-
Addressable::Template.new(
|
907
|
-
"http://example.com/{-list|/|a,b,c}/"
|
908
|
-
).extract(@uri)
|
909
|
-
end).should raise_error(
|
910
|
-
Addressable::Template::InvalidTemplateOperatorError
|
911
|
-
)
|
912
|
-
end
|
913
|
-
end
|
914
|
-
|
915
|
-
describe Addressable::URI, "when given a mapping that contains an Array" do
|
916
|
-
before do
|
917
|
-
@mapping = {"query" => "an example search query".split(" ")}
|
918
|
-
end
|
919
|
-
|
920
|
-
it "should result in 'http://example.com/search/an+example+search+query/'" +
|
921
|
-
" when used to expand 'http://example.com/search/{-list|+|query}/'" do
|
922
|
-
Addressable::Template.new(
|
923
|
-
"http://example.com/search/{-list|+|query}/"
|
924
|
-
).expand(@mapping).to_str.should ==
|
925
|
-
"http://example.com/search/an+example+search+query/"
|
926
|
-
end
|
927
|
-
|
928
|
-
it "should result in 'http://example.com/search/an+example+search+query/'" +
|
929
|
-
" when used to expand 'http://example.com/search/{-list|+|query}/'" +
|
930
|
-
" with a NoOpProcessor" do
|
931
|
-
Addressable::Template.new(
|
932
|
-
"http://example.com/search/{-list|+|query}/"
|
933
|
-
).expand(@mapping, NoOpProcessor).to_str.should ==
|
934
|
-
"http://example.com/search/an+example+search+query/"
|
935
|
-
end
|
936
|
-
end
|
937
|
-
|
938
|
-
describe Addressable::URI, "when given an empty mapping" do
|
939
|
-
before do
|
940
|
-
@mapping = {}
|
941
|
-
end
|
942
|
-
|
943
|
-
it "should result in 'http://example.com/search/'" +
|
944
|
-
" when used to expand 'http://example.com/search/{-list|+|query}'" do
|
945
|
-
Addressable::Template.new(
|
946
|
-
"http://example.com/search/{-list|+|query}"
|
947
|
-
).expand(@mapping).to_str.should == "http://example.com/search/"
|
948
|
-
end
|
949
|
-
|
950
|
-
it "should result in 'http://example.com'" +
|
951
|
-
" when used to expand 'http://example.com{-prefix|/|foo}'" do
|
952
|
-
Addressable::Template.new(
|
953
|
-
"http://example.com{-prefix|/|foo}"
|
954
|
-
).expand(@mapping).to_str.should == "http://example.com"
|
955
|
-
end
|
956
|
-
|
957
|
-
it "should result in 'http://example.com'" +
|
958
|
-
" when used to expand 'http://example.com{-suffix|/|foo}'" do
|
959
|
-
Addressable::Template.new(
|
960
|
-
"http://example.com{-suffix|/|foo}"
|
961
|
-
).expand(@mapping).to_str.should == "http://example.com"
|
962
|
-
end
|
963
|
-
end
|
964
|
-
|
965
|
-
describe Addressable::URI, "when given the template pattern " +
|
966
|
-
"'http://example.com/search/{query}/' " +
|
967
|
-
"to be processed with the ExampleProcessor" do
|
968
|
-
before do
|
969
|
-
@pattern = "http://example.com/search/{query}/"
|
970
|
-
end
|
971
|
-
|
972
|
-
it "should expand to " +
|
973
|
-
"'http://example.com/search/an+example+search+query/' " +
|
974
|
-
"with a mapping of {\"query\" => \"an example search query\"} " do
|
975
|
-
Addressable::Template.new(
|
976
|
-
"http://example.com/search/{query}/"
|
977
|
-
).expand({
|
978
|
-
"query" => "an example search query"
|
979
|
-
}, ExampleProcessor).to_s.should ==
|
980
|
-
"http://example.com/search/an+example+search+query/"
|
981
|
-
end
|
982
|
-
|
983
|
-
it "should raise an error " +
|
984
|
-
"with a mapping of {\"query\" => \"invalid!\"}" do
|
985
|
-
(lambda do
|
986
|
-
Addressable::Template.new(
|
987
|
-
"http://example.com/search/{query}/"
|
988
|
-
).expand({"query" => "invalid!"}, ExampleProcessor).to_s
|
989
|
-
end).should raise_error(Addressable::Template::InvalidTemplateValueError)
|
990
|
-
end
|
991
|
-
end
|
992
|
-
|
993
|
-
# Section 3.3.1 of the URI Template draft v 01
|
994
|
-
describe Addressable::URI, "when given the mapping supplied in " +
|
995
|
-
"Section 3.3.1 of the URI Template draft v 01" do
|
996
|
-
before do
|
997
|
-
@mapping = {
|
998
|
-
"a" => "fred",
|
999
|
-
"b" => "barney",
|
1000
|
-
"c" => "cheeseburger",
|
1001
|
-
"d" => "one two three",
|
1002
|
-
"e" => "20% tricky",
|
1003
|
-
"f" => "",
|
1004
|
-
"20" => "this-is-spinal-tap",
|
1005
|
-
"scheme" => "https",
|
1006
|
-
"p" => "quote=to+be+or+not+to+be",
|
1007
|
-
"q" => "hullo#world"
|
1008
|
-
}
|
1009
|
-
end
|
1010
|
-
|
1011
|
-
it "should result in 'http://example.org/page1#fred' " +
|
1012
|
-
"when used to expand 'http://example.org/page1\#{a}'" do
|
1013
|
-
Addressable::Template.new(
|
1014
|
-
"http://example.org/page1\#{a}"
|
1015
|
-
).expand(@mapping).to_s.should == "http://example.org/page1#fred"
|
1016
|
-
end
|
1017
|
-
|
1018
|
-
it "should result in 'http://example.org/fred/barney/' " +
|
1019
|
-
"when used to expand 'http://example.org/{a}/{b}/'" do
|
1020
|
-
Addressable::Template.new(
|
1021
|
-
"http://example.org/{a}/{b}/"
|
1022
|
-
).expand(@mapping).to_s.should == "http://example.org/fred/barney/"
|
1023
|
-
end
|
1024
|
-
|
1025
|
-
it "should result in 'http://example.org/fredbarney/' " +
|
1026
|
-
"when used to expand 'http://example.org/{a}{b}/'" do
|
1027
|
-
Addressable::Template.new(
|
1028
|
-
"http://example.org/{a}{b}/"
|
1029
|
-
).expand(@mapping).to_s.should == "http://example.org/fredbarney/"
|
1030
|
-
end
|
1031
|
-
|
1032
|
-
it "should result in " +
|
1033
|
-
"'http://example.com/order/cheeseburger/cheeseburger/cheeseburger/' " +
|
1034
|
-
"when used to expand 'http://example.com/order/{c}/{c}/{c}/'" do
|
1035
|
-
Addressable::Template.new(
|
1036
|
-
"http://example.com/order/{c}/{c}/{c}/"
|
1037
|
-
).expand(@mapping).to_s.should ==
|
1038
|
-
"http://example.com/order/cheeseburger/cheeseburger/cheeseburger/"
|
1039
|
-
end
|
1040
|
-
|
1041
|
-
it "should result in 'http://example.org/one%20two%20three' " +
|
1042
|
-
"when used to expand 'http://example.org/{d}'" do
|
1043
|
-
Addressable::Template.new(
|
1044
|
-
"http://example.org/{d}"
|
1045
|
-
).expand(@mapping).to_s.should ==
|
1046
|
-
"http://example.org/one%20two%20three"
|
1047
|
-
end
|
1048
|
-
|
1049
|
-
it "should result in 'http://example.org/20%25%20tricky' " +
|
1050
|
-
"when used to expand 'http://example.org/{e}'" do
|
1051
|
-
Addressable::Template.new(
|
1052
|
-
"http://example.org/{e}"
|
1053
|
-
).expand(@mapping).to_s.should ==
|
1054
|
-
"http://example.org/20%25%20tricky"
|
1055
|
-
end
|
1056
|
-
|
1057
|
-
it "should result in 'http://example.com//' " +
|
1058
|
-
"when used to expand 'http://example.com/{f}/'" do
|
1059
|
-
Addressable::Template.new(
|
1060
|
-
"http://example.com/{f}/"
|
1061
|
-
).expand(@mapping).to_s.should ==
|
1062
|
-
"http://example.com//"
|
1063
|
-
end
|
1064
|
-
|
1065
|
-
it "should result in " +
|
1066
|
-
"'https://this-is-spinal-tap.example.org?date=&option=fred' " +
|
1067
|
-
"when used to expand " +
|
1068
|
-
"'{scheme}://{20}.example.org?date={wilma}&option={a}'" do
|
1069
|
-
Addressable::Template.new(
|
1070
|
-
"{scheme}://{20}.example.org?date={wilma}&option={a}"
|
1071
|
-
).expand(@mapping).to_s.should ==
|
1072
|
-
"https://this-is-spinal-tap.example.org?date=&option=fred"
|
1073
|
-
end
|
1074
|
-
|
1075
|
-
# The v 01 draft conflicts with the v 03 draft here.
|
1076
|
-
# The Addressable implementation uses v 03.
|
1077
|
-
it "should result in " +
|
1078
|
-
"'http://example.org?quote%3Dto%2Bbe%2Bor%2Bnot%2Bto%2Bbe' " +
|
1079
|
-
"when used to expand 'http://example.org?{p}'" do
|
1080
|
-
Addressable::Template.new(
|
1081
|
-
"http://example.org?{p}"
|
1082
|
-
).expand(@mapping).to_s.should ==
|
1083
|
-
"http://example.org?quote%3Dto%2Bbe%2Bor%2Bnot%2Bto%2Bbe"
|
1084
|
-
end
|
1085
|
-
|
1086
|
-
# The v 01 draft conflicts with the v 03 draft here.
|
1087
|
-
# The Addressable implementation uses v 03.
|
1088
|
-
it "should result in 'http://example.com/hullo%23world' " +
|
1089
|
-
"when used to expand 'http://example.com/{q}'" do
|
1090
|
-
Addressable::Template.new(
|
1091
|
-
"http://example.com/{q}"
|
1092
|
-
).expand(@mapping).to_s.should == "http://example.com/hullo%23world"
|
1093
|
-
end
|
1094
|
-
end
|
1095
|
-
|
1096
|
-
# Section 4.5 of the URI Template draft v 03
|
1097
|
-
describe Addressable::URI, "when given the mapping supplied in " +
|
1098
|
-
"Section 4.5 of the URI Template draft v 03" do
|
1099
|
-
before do
|
1100
|
-
@mapping = {
|
1101
|
-
"foo" => "ϓ",
|
1102
|
-
"bar" => "fred",
|
1103
|
-
"baz" => "10,20,30",
|
1104
|
-
"qux" => ["10","20","30"],
|
1105
|
-
"corge" => [],
|
1106
|
-
"grault" => "",
|
1107
|
-
"garply" => "a/b/c",
|
1108
|
-
"waldo" => "ben & jerrys",
|
1109
|
-
"fred" => ["fred", "", "wilma"],
|
1110
|
-
"plugh" => ["ẛ", "ṡ"],
|
1111
|
-
"1-a_b.c" => "200"
|
1112
|
-
}
|
1113
|
-
end
|
1114
|
-
|
1115
|
-
it "should result in 'http://example.org/?q=fred' " +
|
1116
|
-
"when used to expand 'http://example.org/?q={bar}'" do
|
1117
|
-
Addressable::Template.new(
|
1118
|
-
"http://example.org/?q={bar}"
|
1119
|
-
).expand(@mapping).to_s.should == "http://example.org/?q=fred"
|
1120
|
-
end
|
1121
|
-
|
1122
|
-
it "should result in '/' " +
|
1123
|
-
"when used to expand '/{xyzzy}'" do
|
1124
|
-
Addressable::Template.new(
|
1125
|
-
"/{xyzzy}"
|
1126
|
-
).expand(@mapping).to_s.should == "/"
|
1127
|
-
end
|
1128
|
-
|
1129
|
-
it "should result in " +
|
1130
|
-
"'http://example.org/?foo=%CE%8E&bar=fred&baz=10%2C20%2C30' " +
|
1131
|
-
"when used to expand " +
|
1132
|
-
"'http://example.org/?{-join|&|foo,bar,xyzzy,baz}'" do
|
1133
|
-
Addressable::Template.new(
|
1134
|
-
"http://example.org/?{-join|&|foo,bar,xyzzy,baz}"
|
1135
|
-
).expand(@mapping).to_s.should ==
|
1136
|
-
"http://example.org/?foo=%CE%8E&bar=fred&baz=10%2C20%2C30"
|
1137
|
-
end
|
1138
|
-
|
1139
|
-
it "should result in 'http://example.org/?d=10,20,30' " +
|
1140
|
-
"when used to expand 'http://example.org/?d={-list|,|qux}'" do
|
1141
|
-
Addressable::Template.new(
|
1142
|
-
"http://example.org/?d={-list|,|qux}"
|
1143
|
-
).expand(
|
1144
|
-
@mapping
|
1145
|
-
).to_s.should == "http://example.org/?d=10,20,30"
|
1146
|
-
end
|
1147
|
-
|
1148
|
-
it "should result in 'http://example.org/?d=10&d=20&d=30' " +
|
1149
|
-
"when used to expand 'http://example.org/?d={-list|&d=|qux}'" do
|
1150
|
-
Addressable::Template.new(
|
1151
|
-
"http://example.org/?d={-list|&d=|qux}"
|
1152
|
-
).expand(
|
1153
|
-
@mapping
|
1154
|
-
).to_s.should == "http://example.org/?d=10&d=20&d=30"
|
1155
|
-
end
|
1156
|
-
|
1157
|
-
it "should result in 'http://example.org/fredfred/a%2Fb%2Fc' " +
|
1158
|
-
"when used to expand 'http://example.org/{bar}{bar}/{garply}'" do
|
1159
|
-
Addressable::Template.new(
|
1160
|
-
"http://example.org/{bar}{bar}/{garply}"
|
1161
|
-
).expand(
|
1162
|
-
@mapping
|
1163
|
-
).to_s.should == "http://example.org/fredfred/a%2Fb%2Fc"
|
1164
|
-
end
|
1165
|
-
|
1166
|
-
it "should result in 'http://example.org/fred/fred//wilma' " +
|
1167
|
-
"when used to expand 'http://example.org/{bar}{-prefix|/|fred}'" do
|
1168
|
-
Addressable::Template.new(
|
1169
|
-
"http://example.org/{bar}{-prefix|/|fred}"
|
1170
|
-
).expand(
|
1171
|
-
@mapping
|
1172
|
-
).to_s.should == "http://example.org/fred/fred//wilma"
|
1173
|
-
end
|
1174
|
-
|
1175
|
-
it "should result in ':%E1%B9%A1:%E1%B9%A1:' " +
|
1176
|
-
"when used to expand '{-neg|:|corge}{-suffix|:|plugh}'" do
|
1177
|
-
Addressable::Template.new(
|
1178
|
-
"{-neg|:|corge}{-suffix|:|plugh}"
|
1179
|
-
).expand(
|
1180
|
-
@mapping
|
1181
|
-
).to_s.should == ":%E1%B9%A1:%E1%B9%A1:"
|
1182
|
-
end
|
1183
|
-
|
1184
|
-
it "should result in '../ben%20%26%20jerrys/' " +
|
1185
|
-
"when used to expand '../{waldo}/'" do
|
1186
|
-
Addressable::Template.new(
|
1187
|
-
"../{waldo}/"
|
1188
|
-
).expand(
|
1189
|
-
@mapping
|
1190
|
-
).to_s.should == "../ben%20%26%20jerrys/"
|
1191
|
-
end
|
1192
|
-
|
1193
|
-
it "should result in 'telnet:192.0.2.16:80' " +
|
1194
|
-
"when used to expand 'telnet:192.0.2.16{-opt|:80|grault}'" do
|
1195
|
-
Addressable::Template.new(
|
1196
|
-
"telnet:192.0.2.16{-opt|:80|grault}"
|
1197
|
-
).expand(
|
1198
|
-
@mapping
|
1199
|
-
).to_s.should == "telnet:192.0.2.16:80"
|
1200
|
-
end
|
1201
|
-
|
1202
|
-
it "should result in ':200:' " +
|
1203
|
-
"when used to expand ':{1-a_b.c}:'" do
|
1204
|
-
Addressable::Template.new(
|
1205
|
-
":{1-a_b.c}:"
|
1206
|
-
).expand(
|
1207
|
-
@mapping
|
1208
|
-
).to_s.should == ":200:"
|
1209
|
-
end
|
1210
|
-
end
|
1211
|
-
|
1212
|
-
describe Addressable::URI, "when given a mapping that contains a " +
|
1213
|
-
"template-var within a value" do
|
1214
|
-
before do
|
1215
|
-
@mapping = {
|
1216
|
-
"a" => "{b}",
|
1217
|
-
"b" => "barney",
|
1218
|
-
}
|
1219
|
-
end
|
1220
|
-
|
1221
|
-
it "should result in 'http://example.com/%7Bb%7D/barney/' " +
|
1222
|
-
"when used to expand 'http://example.com/{a}/{b}/'" do
|
1223
|
-
Addressable::Template.new(
|
1224
|
-
"http://example.com/{a}/{b}/"
|
1225
|
-
).expand(
|
1226
|
-
@mapping
|
1227
|
-
).to_s.should == "http://example.com/%7Bb%7D/barney/"
|
1228
|
-
end
|
1229
|
-
|
1230
|
-
it "should result in 'http://example.com//%7Bb%7D/' " +
|
1231
|
-
"when used to expand 'http://example.com/{-opt|foo|foo}/{a}/'" do
|
1232
|
-
Addressable::Template.new(
|
1233
|
-
"http://example.com/{-opt|foo|foo}/{a}/"
|
1234
|
-
).expand(
|
1235
|
-
@mapping
|
1236
|
-
).to_s.should == "http://example.com//%7Bb%7D/"
|
1237
|
-
end
|
1238
|
-
|
1239
|
-
it "should result in 'http://example.com//%7Bb%7D/' " +
|
1240
|
-
"when used to expand 'http://example.com/{-neg|foo|b}/{a}/'" do
|
1241
|
-
Addressable::Template.new(
|
1242
|
-
"http://example.com/{-neg|foo|b}/{a}/"
|
1243
|
-
).expand(
|
1244
|
-
@mapping
|
1245
|
-
).to_s.should == "http://example.com//%7Bb%7D/"
|
1246
|
-
end
|
1247
|
-
|
1248
|
-
it "should result in 'http://example.com//barney/%7Bb%7D/' " +
|
1249
|
-
"when used to expand 'http://example.com/{-prefix|/|b}/{a}/'" do
|
1250
|
-
Addressable::Template.new(
|
1251
|
-
"http://example.com/{-prefix|/|b}/{a}/"
|
1252
|
-
).expand(
|
1253
|
-
@mapping
|
1254
|
-
).to_s.should == "http://example.com//barney/%7Bb%7D/"
|
1255
|
-
end
|
1256
|
-
|
1257
|
-
it "should result in 'http://example.com/barney//%7Bb%7D/' " +
|
1258
|
-
"when used to expand 'http://example.com/{-suffix|/|b}/{a}/'" do
|
1259
|
-
Addressable::Template.new(
|
1260
|
-
"http://example.com/{-suffix|/|b}/{a}/"
|
1261
|
-
).expand(
|
1262
|
-
@mapping
|
1263
|
-
).to_s.should == "http://example.com/barney//%7Bb%7D/"
|
1264
|
-
end
|
1265
|
-
|
1266
|
-
it "should result in 'http://example.com/%7Bb%7D/?b=barney&c=42' " +
|
1267
|
-
"when used to expand 'http://example.com/{a}/?{-join|&|b,c=42}'" do
|
1268
|
-
Addressable::Template.new(
|
1269
|
-
"http://example.com/{a}/?{-join|&|b,c=42}"
|
1270
|
-
).expand(
|
1271
|
-
@mapping
|
1272
|
-
).to_s.should == "http://example.com/%7Bb%7D/?b=barney&c=42"
|
1273
|
-
end
|
1274
|
-
|
1275
|
-
it "should result in 'http://example.com/42/?b=barney' " +
|
1276
|
-
"when used to expand 'http://example.com/{c=42}/?{-join|&|b}'" do
|
1277
|
-
Addressable::Template.new(
|
1278
|
-
"http://example.com/{c=42}/?{-join|&|b}"
|
1279
|
-
).expand(@mapping).to_s.should == "http://example.com/42/?b=barney"
|
1280
|
-
end
|
1281
|
-
end
|
1282
|
-
|
1283
|
-
describe Addressable::URI, "when given a single variable mapping" do
|
1284
|
-
before do
|
1285
|
-
@mapping = {
|
1286
|
-
"foo" => "fred"
|
1287
|
-
}
|
1288
|
-
end
|
1289
|
-
|
1290
|
-
it "should result in 'fred' when used to expand '{foo}'" do
|
1291
|
-
Addressable::Template.new(
|
1292
|
-
"{foo}"
|
1293
|
-
).expand(@mapping).to_s.should == "fred"
|
1294
|
-
end
|
1295
|
-
|
1296
|
-
it "should result in 'wilma' when used to expand '{bar=wilma}'" do
|
1297
|
-
Addressable::Template.new(
|
1298
|
-
"{bar=wilma}"
|
1299
|
-
).expand(@mapping).to_s.should == "wilma"
|
1300
|
-
end
|
1301
|
-
|
1302
|
-
it "should result in '' when used to expand '{baz}'" do
|
1303
|
-
Addressable::Template.new(
|
1304
|
-
"{baz}"
|
1305
|
-
).expand(@mapping).to_s.should == ""
|
1306
|
-
end
|
1307
|
-
end
|
1308
|
-
|
1309
|
-
describe Addressable::URI, "when given a simple mapping" do
|
1310
|
-
before do
|
1311
|
-
@mapping = {
|
1312
|
-
"foo" => "fred",
|
1313
|
-
"bar" => "barney",
|
1314
|
-
"baz" => ""
|
1315
|
-
}
|
1316
|
-
end
|
1317
|
-
|
1318
|
-
it "should result in 'foo=fred&bar=barney&baz=' when used to expand " +
|
1319
|
-
"'{-join|&|foo,bar,baz,qux}'" do
|
1320
|
-
Addressable::Template.new(
|
1321
|
-
"{-join|&|foo,bar,baz,qux}"
|
1322
|
-
).expand(@mapping).to_s.should == "foo=fred&bar=barney&baz="
|
1323
|
-
end
|
1324
|
-
|
1325
|
-
it "should result in 'bar=barney' when used to expand " +
|
1326
|
-
"'{-join|&|bar}'" do
|
1327
|
-
Addressable::Template.new(
|
1328
|
-
"{-join|&|bar}"
|
1329
|
-
).expand(@mapping).to_s.should == "bar=barney"
|
1330
|
-
end
|
1331
|
-
|
1332
|
-
it "should result in '' when used to expand " +
|
1333
|
-
"'{-join|&|qux}'" do
|
1334
|
-
Addressable::Template.new(
|
1335
|
-
"{-join|&|qux}"
|
1336
|
-
).expand(@mapping).to_s.should == ""
|
1337
|
-
end
|
1338
|
-
end
|
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
|
-
|
1388
|
-
describe Addressable::URI, "when given a mapping containing values " +
|
1389
|
-
"that are already percent-encoded" do
|
1390
|
-
before do
|
1391
|
-
@mapping = {
|
1392
|
-
"a" => "%7Bb%7D"
|
1393
|
-
}
|
1394
|
-
end
|
1395
|
-
|
1396
|
-
it "should result in 'http://example.com/%257Bb%257D/' " +
|
1397
|
-
"when used to expand 'http://example.com/{a}/'" do
|
1398
|
-
Addressable::Template.new(
|
1399
|
-
"http://example.com/{a}/"
|
1400
|
-
).expand(@mapping).to_s.should == "http://example.com/%257Bb%257D/"
|
1401
|
-
end
|
1402
|
-
end
|
1403
|
-
|
1404
|
-
describe Addressable::URI, "when given a pattern with bogus operators" do
|
1405
|
-
it "should raise an InvalidTemplateOperatorError" do
|
1406
|
-
(lambda do
|
1407
|
-
Addressable::Template.new(
|
1408
|
-
"http://example.com/{-bogus|/|a,b,c}/"
|
1409
|
-
).expand({
|
1410
|
-
"a" => "a", "b" => "b", "c" => "c"
|
1411
|
-
})
|
1412
|
-
end).should raise_error(
|
1413
|
-
Addressable::Template::InvalidTemplateOperatorError
|
1414
|
-
)
|
1415
|
-
end
|
1416
|
-
|
1417
|
-
it "should raise an InvalidTemplateOperatorError" do
|
1418
|
-
(lambda do
|
1419
|
-
Addressable::Template.new(
|
1420
|
-
"http://example.com/{-prefix|/|a,b,c}/"
|
1421
|
-
).expand({
|
1422
|
-
"a" => "a", "b" => "b", "c" => "c"
|
1423
|
-
})
|
1424
|
-
end).should raise_error(
|
1425
|
-
Addressable::Template::InvalidTemplateOperatorError
|
1426
|
-
)
|
1427
|
-
end
|
1428
|
-
|
1429
|
-
it "should raise an InvalidTemplateOperatorError" do
|
1430
|
-
(lambda do
|
1431
|
-
Addressable::Template.new(
|
1432
|
-
"http://example.com/{-suffix|/|a,b,c}/"
|
1433
|
-
).expand({
|
1434
|
-
"a" => "a", "b" => "b", "c" => "c"
|
1435
|
-
})
|
1436
|
-
end).should raise_error(
|
1437
|
-
Addressable::Template::InvalidTemplateOperatorError
|
1438
|
-
)
|
1439
|
-
end
|
1440
|
-
|
1441
|
-
it "should raise an InvalidTemplateOperatorError" do
|
1442
|
-
(lambda do
|
1443
|
-
Addressable::Template.new(
|
1444
|
-
"http://example.com/{-join|/|a,b,c}/"
|
1445
|
-
).expand({
|
1446
|
-
"a" => ["a"], "b" => ["b"], "c" => "c"
|
1447
|
-
})
|
1448
|
-
end).should raise_error(
|
1449
|
-
Addressable::Template::InvalidTemplateOperatorError
|
1450
|
-
)
|
1451
|
-
end
|
1452
|
-
|
1453
|
-
it "should raise an InvalidTemplateOperatorError" do
|
1454
|
-
(lambda do
|
1455
|
-
Addressable::Template.new(
|
1456
|
-
"http://example.com/{-list|/|a,b,c}/"
|
1457
|
-
).expand({
|
1458
|
-
"a" => ["a"], "b" => ["b"], "c" => "c"
|
1459
|
-
})
|
1460
|
-
end).should raise_error(
|
1461
|
-
Addressable::Template::InvalidTemplateOperatorError
|
1462
|
-
)
|
1463
|
-
end
|
1464
|
-
end
|
1465
|
-
|
1466
|
-
describe Addressable::Template, "with a partially expanded template" do
|
1467
|
-
before do
|
1468
|
-
@initial_template = Addressable::Template.new(
|
1469
|
-
"http://example.com/{one}/{two}/"
|
1470
|
-
)
|
1471
|
-
@partial_template = @initial_template.partial_expand({"one" => "1"})
|
1472
|
-
end
|
1473
|
-
|
1474
|
-
it "should produce the same result when fully expanded" do
|
1475
|
-
@initial_template.expand({"one" => "1", "two" => "2"}).should ==
|
1476
|
-
@partial_template.expand({"two" => "2"})
|
1477
|
-
end
|
1478
|
-
|
1479
|
-
it "should raise an error if the template is expanded with bogus values" do
|
1480
|
-
(lambda do
|
1481
|
-
@initial_template.expand({"one" => Object.new, "two" => Object.new})
|
1482
|
-
end).should raise_error(TypeError)
|
1483
|
-
(lambda do
|
1484
|
-
@partial_template.expand({"two" => Object.new})
|
1485
|
-
end).should raise_error(TypeError)
|
1486
|
-
end
|
1487
|
-
end
|
1488
|
-
|
1489
|
-
describe Addressable::Template, "with a partially expanded template" do
|
1490
|
-
before do
|
1491
|
-
@initial_template = Addressable::Template.new(
|
1492
|
-
"http://example.com/{one}/{two}/"
|
1493
|
-
)
|
1494
|
-
@partial_template = @initial_template.partial_expand({"two" => "2"})
|
1495
|
-
end
|
1496
|
-
|
1497
|
-
it "should produce the same result when fully expanded" do
|
1498
|
-
@initial_template.expand({"one" => "1", "two" => "2"}).should ==
|
1499
|
-
@partial_template.expand({"one" => "1"})
|
1500
|
-
end
|
1501
|
-
end
|
1502
|
-
|
1503
|
-
describe Addressable::Template, "with a partially expanded template" do
|
1504
|
-
before do
|
1505
|
-
@initial_template = Addressable::Template.new(
|
1506
|
-
"http://example.com/{one}/{two}/"
|
1507
|
-
)
|
1508
|
-
@partial_template = @initial_template.partial_expand({"two" => "2"})
|
1509
|
-
end
|
1510
|
-
|
1511
|
-
it "should produce the same result when fully expanded" do
|
1512
|
-
@initial_template.expand({"one" => "1", "two" => "2"}).should ==
|
1513
|
-
@partial_template.expand({"one" => "1"})
|
1514
|
-
end
|
1515
|
-
end
|
1516
|
-
|
1517
|
-
describe Addressable::Template, "with a partially expanded template" do
|
1518
|
-
before do
|
1519
|
-
@initial_template = Addressable::Template.new(
|
1520
|
-
"http://example.com/{one=1}/{two=2}/"
|
1521
|
-
)
|
1522
|
-
@partial_template = @initial_template.partial_expand({"one" => "3"})
|
1523
|
-
end
|
1524
|
-
|
1525
|
-
it "should produce the same result when fully expanded" do
|
1526
|
-
@initial_template.expand({"one" => "3", "two" => "4"}).should ==
|
1527
|
-
@partial_template.expand({"two" => "4"})
|
1528
|
-
end
|
1529
|
-
|
1530
|
-
it "should produce the correct result when fully expanded" do
|
1531
|
-
@partial_template.expand({}).should === "http://example.com/3/2/"
|
1532
|
-
end
|
1533
|
-
end
|
1534
|
-
|
1535
|
-
describe Addressable::Template, "with a partially expanded template" do
|
1536
|
-
before do
|
1537
|
-
@initial_template = Addressable::Template.new(
|
1538
|
-
"http://example.com/{one=1}/{two=2}/"
|
1539
|
-
)
|
1540
|
-
@partial_template = @initial_template.partial_expand({"two" => "4"})
|
1541
|
-
end
|
1542
|
-
|
1543
|
-
it "should produce the same result when fully expanded" do
|
1544
|
-
@initial_template.expand({"one" => "3", "two" => "4"}).should ==
|
1545
|
-
@partial_template.expand({"one" => "3"})
|
1546
|
-
end
|
1547
|
-
|
1548
|
-
it "should produce the correct result when fully expanded" do
|
1549
|
-
@partial_template.expand({}).should === "http://example.com/1/4/"
|
1550
|
-
end
|
1551
|
-
end
|
1552
|
-
|
1553
|
-
describe Addressable::Template, "with a partially expanded template" do
|
1554
|
-
before do
|
1555
|
-
@initial_template = Addressable::Template.new(
|
1556
|
-
"http://example.com/{-opt|found|one,two,three}"
|
1557
|
-
)
|
1558
|
-
@partial_template = @initial_template.partial_expand({})
|
1559
|
-
end
|
1560
|
-
|
1561
|
-
it "should produce the same result when fully expanded" do
|
1562
|
-
@initial_template.expand({"one" => "1"}).to_str.should ==
|
1563
|
-
@partial_template.expand({"two" => "2"}).to_str
|
1564
|
-
end
|
1565
|
-
|
1566
|
-
it "should produce the correct result when fully expanded" do
|
1567
|
-
@partial_template.expand({}).to_str.should == "http://example.com/"
|
1568
|
-
end
|
1569
|
-
|
1570
|
-
it "should produce the correct result when fully expanded" do
|
1571
|
-
@partial_template.expand({"one" => "1"}).to_str.should ==
|
1572
|
-
"http://example.com/found"
|
1573
|
-
end
|
1574
|
-
|
1575
|
-
it "should produce the correct result when fully expanded" do
|
1576
|
-
@partial_template.expand({"two" => "2"}).to_str.should ==
|
1577
|
-
"http://example.com/found"
|
1578
|
-
end
|
1579
|
-
|
1580
|
-
it "should produce the correct result when fully expanded" do
|
1581
|
-
@partial_template.expand({"three" => "3"}).to_str.should ==
|
1582
|
-
"http://example.com/found"
|
1583
|
-
end
|
1584
|
-
|
1585
|
-
it "should produce the correct result when fully expanded" do
|
1586
|
-
@partial_template.expand({"four" => "4"}).to_str.should ==
|
1587
|
-
"http://example.com/"
|
1588
|
-
end
|
1589
|
-
|
1590
|
-
it "should produce the correct result when fully expanded" do
|
1591
|
-
@partial_template.expand({"one" => "1", "two" => "2"}).to_str.should ==
|
1592
|
-
"http://example.com/found"
|
1593
|
-
end
|
1594
|
-
end
|
1595
|
-
|
1596
|
-
describe Addressable::Template, "with a partially expanded template" do
|
1597
|
-
before do
|
1598
|
-
@initial_template = Addressable::Template.new(
|
1599
|
-
"http://example.com/{-opt|found|one,two,three}"
|
1600
|
-
)
|
1601
|
-
@partial_template = @initial_template.partial_expand({"one" => "1"})
|
1602
|
-
end
|
1603
|
-
|
1604
|
-
it "should produce the same result when fully expanded" do
|
1605
|
-
@initial_template.expand({"one" => "1"}).to_str.should ==
|
1606
|
-
@partial_template.expand({"two" => "2"}).to_str
|
1607
|
-
end
|
1608
|
-
|
1609
|
-
it "should produce the correct result when fully expanded" do
|
1610
|
-
@partial_template.expand({}).to_str.should == "http://example.com/found"
|
1611
|
-
end
|
1612
|
-
|
1613
|
-
it "should produce the correct pattern" do
|
1614
|
-
@partial_template.pattern.should == "http://example.com/found"
|
1615
|
-
end
|
1616
|
-
end
|
1617
|
-
|
1618
|
-
describe Addressable::Template, "with a partially expanded template" do
|
1619
|
-
before do
|
1620
|
-
@initial_template = Addressable::Template.new(
|
1621
|
-
"http://example.com/{-neg|notfound|one,two,three}"
|
1622
|
-
)
|
1623
|
-
@partial_template = @initial_template.partial_expand({})
|
1624
|
-
end
|
1625
|
-
|
1626
|
-
it "should produce the same result when fully expanded" do
|
1627
|
-
@initial_template.expand({"one" => "1"}).to_str.should ==
|
1628
|
-
@partial_template.expand({"two" => "2"}).to_str
|
1629
|
-
end
|
1630
|
-
|
1631
|
-
it "should produce the correct result when fully expanded" do
|
1632
|
-
@partial_template.expand({}).to_str.should == "http://example.com/notfound"
|
1633
|
-
end
|
1634
|
-
|
1635
|
-
it "should produce the correct result when fully expanded" do
|
1636
|
-
@partial_template.expand({"one" => "1"}).to_str.should ==
|
1637
|
-
"http://example.com/"
|
1638
|
-
end
|
1639
|
-
|
1640
|
-
it "should produce the correct result when fully expanded" do
|
1641
|
-
@partial_template.expand({"two" => "2"}).to_str.should ==
|
1642
|
-
"http://example.com/"
|
1643
|
-
end
|
1644
|
-
|
1645
|
-
it "should produce the correct result when fully expanded" do
|
1646
|
-
@partial_template.expand({"three" => "3"}).to_str.should ==
|
1647
|
-
"http://example.com/"
|
1648
|
-
end
|
1649
|
-
|
1650
|
-
it "should produce the correct result when fully expanded" do
|
1651
|
-
@partial_template.expand({"four" => "4"}).to_str.should ==
|
1652
|
-
"http://example.com/notfound"
|
1653
|
-
end
|
1654
|
-
|
1655
|
-
it "should produce the correct result when fully expanded" do
|
1656
|
-
@partial_template.expand({"one" => "1", "two" => "2"}).to_str.should ==
|
1657
|
-
"http://example.com/"
|
1658
|
-
end
|
1659
|
-
end
|
1660
|
-
|
1661
|
-
describe Addressable::Template, "with a partially expanded template" do
|
1662
|
-
before do
|
1663
|
-
@initial_template = Addressable::Template.new(
|
1664
|
-
"http://example.com/{-neg|notfound|one,two,three}"
|
1665
|
-
)
|
1666
|
-
@partial_template = @initial_template.partial_expand({"one" => "1"})
|
1667
|
-
end
|
1668
|
-
|
1669
|
-
it "should produce the same result when fully expanded" do
|
1670
|
-
@initial_template.expand({"one" => "1"}).to_str.should ==
|
1671
|
-
@partial_template.expand({"two" => "2"}).to_str
|
1672
|
-
end
|
1673
|
-
|
1674
|
-
it "should produce the correct result when fully expanded" do
|
1675
|
-
@partial_template.expand({}).to_str.should == "http://example.com/"
|
1676
|
-
end
|
1677
|
-
|
1678
|
-
it "should produce the correct pattern" do
|
1679
|
-
@partial_template.pattern.should == "http://example.com/"
|
1680
|
-
end
|
1681
|
-
end
|
1682
|
-
|
1683
|
-
describe Addressable::Template, "with a partially expanded template" do
|
1684
|
-
before do
|
1685
|
-
@initial_template = Addressable::Template.new(
|
1686
|
-
"http://example.com/?{-prefix|x=|one}"
|
1687
|
-
)
|
1688
|
-
@partial_template = @initial_template.partial_expand({})
|
1689
|
-
end
|
1690
|
-
|
1691
|
-
it "should produce the same result when fully expanded" do
|
1692
|
-
@initial_template.expand({"one" => "1"}).to_str.should ==
|
1693
|
-
@partial_template.expand({"one" => "1"}).to_str
|
1694
|
-
end
|
1695
|
-
|
1696
|
-
it "should produce the correct result when fully expanded" do
|
1697
|
-
@partial_template.expand({}).to_str.should == "http://example.com/?"
|
1698
|
-
end
|
1699
|
-
|
1700
|
-
it "should produce the correct result when fully expanded" do
|
1701
|
-
@partial_template.expand({"one" => "1"}).to_str.should ==
|
1702
|
-
"http://example.com/?x=1"
|
1703
|
-
end
|
1704
|
-
|
1705
|
-
it "should produce the correct result when fully expanded" do
|
1706
|
-
@partial_template.expand({"two" => "2"}).to_str.should ==
|
1707
|
-
"http://example.com/?"
|
1708
|
-
end
|
1709
|
-
|
1710
|
-
it "should produce the correct result when fully expanded" do
|
1711
|
-
@partial_template.expand({"one" => "1", "two" => "2"}).to_str.should ==
|
1712
|
-
"http://example.com/?x=1"
|
1713
|
-
end
|
1714
|
-
end
|
1715
|
-
|
1716
|
-
describe Addressable::Template, "with a partially expanded template" do
|
1717
|
-
before do
|
1718
|
-
@initial_template = Addressable::Template.new(
|
1719
|
-
"http://example.com/?{-prefix|x=|one}"
|
1720
|
-
)
|
1721
|
-
@partial_template = @initial_template.partial_expand({"one" => "1"})
|
1722
|
-
end
|
1723
|
-
|
1724
|
-
it "should produce the same result when fully expanded" do
|
1725
|
-
@initial_template.expand({"one" => "1"}).to_str.should ==
|
1726
|
-
@partial_template.expand({}).to_str
|
1727
|
-
end
|
1728
|
-
|
1729
|
-
it "should produce the correct result when fully expanded" do
|
1730
|
-
@partial_template.expand({}).to_str.should == "http://example.com/?x=1"
|
1731
|
-
end
|
1732
|
-
|
1733
|
-
it "should produce the correct pattern" do
|
1734
|
-
@partial_template.pattern.should == "http://example.com/?x=1"
|
1735
|
-
end
|
1736
|
-
end
|
1737
|
-
|
1738
|
-
describe Addressable::Template, "with a partially expanded template" do
|
1739
|
-
before do
|
1740
|
-
@initial_template = Addressable::Template.new(
|
1741
|
-
"http://example.com/?{-suffix|=x|one}"
|
1742
|
-
)
|
1743
|
-
@partial_template = @initial_template.partial_expand({})
|
1744
|
-
end
|
1745
|
-
|
1746
|
-
it "should produce the same result when fully expanded" do
|
1747
|
-
@initial_template.expand({"one" => "1"}).to_str.should ==
|
1748
|
-
@partial_template.expand({"one" => "1"}).to_str
|
1749
|
-
end
|
1750
|
-
|
1751
|
-
it "should produce the correct result when fully expanded" do
|
1752
|
-
@partial_template.expand({}).to_str.should == "http://example.com/?"
|
1753
|
-
end
|
1754
|
-
|
1755
|
-
it "should produce the correct result when fully expanded" do
|
1756
|
-
@partial_template.expand({"one" => "1"}).to_str.should ==
|
1757
|
-
"http://example.com/?1=x"
|
1758
|
-
end
|
1759
|
-
|
1760
|
-
it "should produce the correct result when fully expanded" do
|
1761
|
-
@partial_template.expand({"two" => "2"}).to_str.should ==
|
1762
|
-
"http://example.com/?"
|
1763
|
-
end
|
1764
|
-
|
1765
|
-
it "should produce the correct result when fully expanded" do
|
1766
|
-
@partial_template.expand({"one" => "1", "two" => "2"}).to_str.should ==
|
1767
|
-
"http://example.com/?1=x"
|
1768
|
-
end
|
1769
|
-
end
|
1770
|
-
|
1771
|
-
describe Addressable::Template, "with a partially expanded template" do
|
1772
|
-
before do
|
1773
|
-
@initial_template = Addressable::Template.new(
|
1774
|
-
"http://example.com/?{-suffix|=x|one}"
|
1775
|
-
)
|
1776
|
-
@partial_template = @initial_template.partial_expand({"one" => "1"})
|
1777
|
-
end
|
1778
|
-
|
1779
|
-
it "should produce the same result when fully expanded" do
|
1780
|
-
@initial_template.expand({"one" => "1"}).to_str.should ==
|
1781
|
-
@partial_template.expand({}).to_str
|
1782
|
-
end
|
1783
|
-
|
1784
|
-
it "should produce the correct result when fully expanded" do
|
1785
|
-
@partial_template.expand({}).to_str.should == "http://example.com/?1=x"
|
1786
|
-
end
|
1787
|
-
|
1788
|
-
it "should produce the correct pattern" do
|
1789
|
-
@partial_template.pattern.should == "http://example.com/?1=x"
|
1790
|
-
end
|
1791
|
-
end
|
1792
|
-
|
1793
|
-
describe Addressable::Template, "with a partially expanded template" do
|
1794
|
-
before do
|
1795
|
-
@initial_template = Addressable::Template.new(
|
1796
|
-
"http://example.com/?{-join|&|one}"
|
1797
|
-
)
|
1798
|
-
@partial_template = @initial_template.partial_expand({})
|
1799
|
-
end
|
1800
|
-
|
1801
|
-
it "should produce the same result when fully expanded" do
|
1802
|
-
@initial_template.expand({"one" => "1"}).to_str.should ==
|
1803
|
-
@partial_template.expand({"one" => "1"}).to_str
|
1804
|
-
end
|
1805
|
-
|
1806
|
-
it "should produce the correct result when fully expanded" do
|
1807
|
-
@partial_template.expand({}).to_str.should == "http://example.com/?"
|
1808
|
-
end
|
1809
|
-
|
1810
|
-
it "should produce the correct result when fully expanded" do
|
1811
|
-
@partial_template.pattern.should == @initial_template.pattern
|
1812
|
-
end
|
1813
|
-
end
|
1814
|
-
|
1815
|
-
describe Addressable::Template, "with a partially expanded template" do
|
1816
|
-
before do
|
1817
|
-
@initial_template = Addressable::Template.new(
|
1818
|
-
"http://example.com/?{-join|&|one,two}"
|
1819
|
-
)
|
1820
|
-
@partial_template = @initial_template.partial_expand({"one" => "1"})
|
1821
|
-
end
|
1822
|
-
|
1823
|
-
it "should produce the same result when fully expanded" do
|
1824
|
-
@initial_template.expand({"one" => "1", "two" => "2"}).to_str.should ==
|
1825
|
-
@partial_template.expand({"two" => "2"}).to_str
|
1826
|
-
end
|
1827
|
-
|
1828
|
-
it "should produce the correct result when fully expanded" do
|
1829
|
-
@partial_template.expand({}).to_str.should == "http://example.com/?one=1"
|
1830
|
-
end
|
1831
|
-
end
|
1832
|
-
|
1833
|
-
describe Addressable::Template, "with a partially expanded template" do
|
1834
|
-
before do
|
1835
|
-
@initial_template = Addressable::Template.new(
|
1836
|
-
"http://example.com/?{-join|&|one,two}"
|
1837
|
-
)
|
1838
|
-
@partial_template = @initial_template.partial_expand({"two" => "2"})
|
1839
|
-
end
|
1840
|
-
|
1841
|
-
it "should produce the same result when fully expanded" do
|
1842
|
-
@initial_template.expand({"one" => "1", "two" => "2"}).to_str.should ==
|
1843
|
-
@partial_template.expand({"one" => "1"}).to_str
|
1844
|
-
end
|
1845
|
-
|
1846
|
-
it "should produce the correct result when fully expanded" do
|
1847
|
-
@partial_template.expand({}).to_str.should == "http://example.com/?two=2"
|
1848
|
-
end
|
1849
|
-
end
|
1850
|
-
|
1851
|
-
describe Addressable::Template, "with a partially expanded template" do
|
1852
|
-
before do
|
1853
|
-
@initial_template = Addressable::Template.new(
|
1854
|
-
"http://example.com/?{-join|&|one,two,three}"
|
1855
|
-
)
|
1856
|
-
@partial_template = @initial_template.partial_expand({"one" => "1"})
|
1857
|
-
end
|
1858
|
-
|
1859
|
-
it "should produce the same result when fully expanded" do
|
1860
|
-
@initial_template.expand({
|
1861
|
-
"one" => "1", "two" => "2", "three" => "3"
|
1862
|
-
}).to_str.should ==
|
1863
|
-
@partial_template.expand({"two" => "2", "three" => "3"}).to_str
|
1864
|
-
end
|
1865
|
-
|
1866
|
-
it "should produce the correct result when fully expanded" do
|
1867
|
-
@partial_template.expand({}).to_str.should == "http://example.com/?one=1"
|
1868
|
-
end
|
1869
|
-
|
1870
|
-
it "should produce the correct result when fully expanded" do
|
1871
|
-
@partial_template.expand({"two" => "2"}).to_str.should ==
|
1872
|
-
"http://example.com/?one=1&two=2"
|
1873
|
-
end
|
1874
|
-
|
1875
|
-
it "should produce the correct result when fully expanded" do
|
1876
|
-
@partial_template.expand({"three" => "3"}).to_str.should ==
|
1877
|
-
"http://example.com/?one=1&three=3"
|
1878
|
-
end
|
1879
|
-
end
|
1880
|
-
|
1881
|
-
describe Addressable::Template, "with a partially expanded template" do
|
1882
|
-
before do
|
1883
|
-
@initial_template = Addressable::Template.new(
|
1884
|
-
"http://example.com/?{-join|&|one,two,three}"
|
1885
|
-
)
|
1886
|
-
@partial_template = @initial_template.partial_expand({"two" => "2"})
|
1887
|
-
end
|
1888
|
-
|
1889
|
-
it "should produce the same result when fully expanded" do
|
1890
|
-
@initial_template.expand({
|
1891
|
-
"one" => "1", "two" => "2", "three" => "3"
|
1892
|
-
}).to_str.should ==
|
1893
|
-
@partial_template.expand({"one" => "1", "three" => "3"}).to_str
|
1894
|
-
end
|
1895
|
-
|
1896
|
-
it "should produce the correct result when fully expanded" do
|
1897
|
-
@partial_template.expand({}).to_str.should == "http://example.com/?two=2"
|
1898
|
-
end
|
1899
|
-
|
1900
|
-
it "should produce the correct result when fully expanded" do
|
1901
|
-
@partial_template.expand({"one" => "1"}).to_str.should ==
|
1902
|
-
"http://example.com/?one=1&two=2"
|
1903
|
-
end
|
1904
|
-
|
1905
|
-
it "should produce the correct result when fully expanded" do
|
1906
|
-
@partial_template.expand({"three" => "3"}).to_str.should ==
|
1907
|
-
"http://example.com/?two=2&three=3"
|
1908
|
-
end
|
1909
|
-
end
|
1910
|
-
|
1911
|
-
describe Addressable::Template, "with a partially expanded template" do
|
1912
|
-
before do
|
1913
|
-
@initial_template = Addressable::Template.new(
|
1914
|
-
"http://example.com/?{-join|&|one,two,three}"
|
1915
|
-
)
|
1916
|
-
@partial_template = @initial_template.partial_expand({"three" => "3"})
|
1917
|
-
end
|
1918
|
-
|
1919
|
-
it "should produce the same result when fully expanded" do
|
1920
|
-
@initial_template.expand({
|
1921
|
-
"one" => "1", "two" => "2", "three" => "3"
|
1922
|
-
}).to_str.should ==
|
1923
|
-
@partial_template.expand({"one" => "1", "two" => "2"}).to_str
|
1924
|
-
end
|
1925
|
-
|
1926
|
-
it "should produce the correct result when fully expanded" do
|
1927
|
-
@partial_template.expand({}).to_str.should == "http://example.com/?three=3"
|
1928
|
-
end
|
1929
|
-
|
1930
|
-
it "should produce the correct result when fully expanded" do
|
1931
|
-
@partial_template.expand({"one" => "1"}).to_str.should ==
|
1932
|
-
"http://example.com/?one=1&three=3"
|
1933
|
-
end
|
1934
|
-
|
1935
|
-
it "should produce the correct result when fully expanded" do
|
1936
|
-
@partial_template.expand({"two" => "2"}).to_str.should ==
|
1937
|
-
"http://example.com/?two=2&three=3"
|
1938
|
-
end
|
1939
|
-
end
|
1940
|
-
|
1941
|
-
describe Addressable::Template, "with a partially expanded template" do
|
1942
|
-
before do
|
1943
|
-
@initial_template = Addressable::Template.new(
|
1944
|
-
"http://example.com/?{-join|&|one,two,three}"
|
1945
|
-
)
|
1946
|
-
@partial_template = @initial_template.partial_expand({
|
1947
|
-
"one" => "1", "two" => "2"
|
1948
|
-
})
|
1949
|
-
end
|
1950
|
-
|
1951
|
-
it "should produce the same result when fully expanded" do
|
1952
|
-
@initial_template.expand({
|
1953
|
-
"one" => "1", "two" => "2", "three" => "3"
|
1954
|
-
}).to_str.should ==
|
1955
|
-
@partial_template.expand({"three" => "3"}).to_str
|
1956
|
-
end
|
1957
|
-
|
1958
|
-
it "should produce the correct result when fully expanded" do
|
1959
|
-
@partial_template.expand({}).to_str.should ==
|
1960
|
-
"http://example.com/?one=1&two=2"
|
1961
|
-
end
|
1962
|
-
|
1963
|
-
it "should produce the correct result when fully expanded" do
|
1964
|
-
@partial_template.expand({"three" => "3"}).to_str.should ==
|
1965
|
-
"http://example.com/?one=1&two=2&three=3"
|
1966
|
-
end
|
1967
|
-
end
|
1968
|
-
|
1969
|
-
describe Addressable::Template, "with a partially expanded template" do
|
1970
|
-
before do
|
1971
|
-
@initial_template = Addressable::Template.new(
|
1972
|
-
"http://example.com/?{-join|&|one,two,three}"
|
1973
|
-
)
|
1974
|
-
@partial_template = @initial_template.partial_expand({
|
1975
|
-
"one" => "1", "three" => "3"
|
1976
|
-
})
|
1977
|
-
end
|
1978
|
-
|
1979
|
-
it "should produce the same result when fully expanded" do
|
1980
|
-
@initial_template.expand({
|
1981
|
-
"one" => "1", "two" => "2", "three" => "3"
|
1982
|
-
}).to_str.should ==
|
1983
|
-
@partial_template.expand({"two" => "2"}).to_str
|
1984
|
-
end
|
1985
|
-
|
1986
|
-
it "should produce the correct result when fully expanded" do
|
1987
|
-
@partial_template.expand({}).to_str.should ==
|
1988
|
-
"http://example.com/?one=1&three=3"
|
1989
|
-
end
|
1990
|
-
|
1991
|
-
it "should produce the correct result when fully expanded" do
|
1992
|
-
@partial_template.expand({"two" => "2"}).to_str.should ==
|
1993
|
-
"http://example.com/?one=1&two=2&three=3"
|
1994
|
-
end
|
1995
|
-
end
|
1996
|
-
|
1997
|
-
describe Addressable::Template, "with a partially expanded template" do
|
1998
|
-
before do
|
1999
|
-
@initial_template = Addressable::Template.new(
|
2000
|
-
"http://example.com/?{-join|&|one,two,three}"
|
2001
|
-
)
|
2002
|
-
@partial_template = @initial_template.partial_expand({
|
2003
|
-
"two" => "2", "three" => "3"
|
2004
|
-
})
|
2005
|
-
end
|
2006
|
-
|
2007
|
-
it "should produce the same result when fully expanded" do
|
2008
|
-
@initial_template.expand({
|
2009
|
-
"one" => "1", "two" => "2", "three" => "3"
|
2010
|
-
}).to_str.should ==
|
2011
|
-
@partial_template.expand({"one" => "1"}).to_str
|
2012
|
-
end
|
2013
|
-
|
2014
|
-
it "should produce the correct result when fully expanded" do
|
2015
|
-
@partial_template.expand({}).to_str.should ==
|
2016
|
-
"http://example.com/?two=2&three=3"
|
2017
|
-
end
|
2018
|
-
|
2019
|
-
it "should produce the correct result when fully expanded" do
|
2020
|
-
@partial_template.expand({"one" => "1"}).to_str.should ==
|
2021
|
-
"http://example.com/?one=1&two=2&three=3"
|
2022
|
-
end
|
2023
|
-
end
|
2024
|
-
|
2025
|
-
describe Addressable::Template, "with a partially expanded template" do
|
2026
|
-
before do
|
2027
|
-
@initial_template = Addressable::Template.new(
|
2028
|
-
"http://example.com/?{-join|&|one,two,three}"
|
2029
|
-
)
|
2030
|
-
end
|
2031
|
-
|
2032
|
-
it "should raise an error when partially expanding a bogus operator" do
|
2033
|
-
(lambda do
|
2034
|
-
@initial_template.partial_expand({"one" => ["1"]})
|
2035
|
-
end).should raise_error(
|
2036
|
-
Addressable::Template::InvalidTemplateOperatorError
|
2037
|
-
)
|
2038
|
-
(lambda do
|
2039
|
-
@initial_template.partial_expand({"two" => "2", "three" => ["3"]})
|
2040
|
-
end).should raise_error(
|
2041
|
-
Addressable::Template::InvalidTemplateOperatorError
|
2042
|
-
)
|
2043
|
-
end
|
2044
|
-
end
|
2045
|
-
|
2046
|
-
describe Addressable::Template, "with a partially expanded template" do
|
2047
|
-
before do
|
2048
|
-
@initial_template = Addressable::Template.new(
|
2049
|
-
"http://example.com/{-list|/|numbers}/{-list|/|letters}/"
|
2050
|
-
)
|
2051
|
-
@partial_template = @initial_template.partial_expand({})
|
2052
|
-
end
|
2053
|
-
|
2054
|
-
it "should produce the same result when fully expanded" do
|
2055
|
-
@initial_template.expand({
|
2056
|
-
"numbers" => ["1", "2", "3"], "letters" => ["a", "b", "c"]
|
2057
|
-
}).to_str.should == @partial_template.expand({
|
2058
|
-
"numbers" => ["1", "2", "3"], "letters" => ["a", "b", "c"]
|
2059
|
-
}).to_str
|
2060
|
-
end
|
2061
|
-
|
2062
|
-
it "should produce the correct result when fully expanded" do
|
2063
|
-
@partial_template.expand({}).to_str.should == "http://example.com///"
|
2064
|
-
end
|
2065
|
-
|
2066
|
-
it "should produce the correct result when fully expanded" do
|
2067
|
-
@partial_template.pattern.should == @initial_template.pattern
|
2068
|
-
end
|
2069
|
-
end
|
2070
|
-
|
2071
|
-
describe Addressable::Template, "with a partially expanded template" do
|
2072
|
-
before do
|
2073
|
-
@initial_template = Addressable::Template.new(
|
2074
|
-
"http://example.com/{-list|/|numbers}/{-list|/|letters}/"
|
2075
|
-
)
|
2076
|
-
@partial_template = @initial_template.partial_expand({
|
2077
|
-
"numbers" => ["1", "2", "3"]
|
2078
|
-
})
|
2079
|
-
end
|
2080
|
-
|
2081
|
-
it "should produce the same result when fully expanded" do
|
2082
|
-
@initial_template.expand({
|
2083
|
-
"numbers" => ["1", "2", "3"], "letters" => ["a", "b", "c"]
|
2084
|
-
}).to_str.should == @partial_template.expand({
|
2085
|
-
"letters" => ["a", "b", "c"]
|
2086
|
-
}).to_str
|
2087
|
-
end
|
2088
|
-
|
2089
|
-
it "should produce the correct result when fully expanded" do
|
2090
|
-
@partial_template.expand({}).to_str.should == "http://example.com/1/2/3//"
|
2091
|
-
end
|
2092
|
-
end
|
2093
|
-
|
2094
|
-
describe Addressable::Template, "with a partially expanded template" do
|
2095
|
-
before do
|
2096
|
-
@initial_template = Addressable::Template.new(
|
2097
|
-
"http://example.com/{-list|/|numbers}/{-list|/|letters}/"
|
2098
|
-
)
|
2099
|
-
@partial_template = @initial_template.partial_expand({
|
2100
|
-
"letters" => ["a", "b", "c"]
|
2101
|
-
})
|
2102
|
-
end
|
2103
|
-
|
2104
|
-
it "should produce the same result when fully expanded" do
|
2105
|
-
@initial_template.expand({
|
2106
|
-
"numbers" => ["1", "2", "3"], "letters" => ["a", "b", "c"]
|
2107
|
-
}).to_str.should == @partial_template.expand({
|
2108
|
-
"numbers" => ["1", "2", "3"]
|
2109
|
-
}).to_str
|
2110
|
-
end
|
2111
|
-
|
2112
|
-
it "should produce the correct result when fully expanded" do
|
2113
|
-
@partial_template.expand({}).to_str.should == "http://example.com//a/b/c/"
|
2114
|
-
end
|
2115
|
-
end
|
2116
|
-
|
2117
|
-
describe Addressable::Template, "with a partially expanded template" do
|
2118
|
-
before do
|
2119
|
-
@initial_template = Addressable::Template.new(
|
2120
|
-
"http://example.com/{-list|/|numbers}/{-list|/|letters}/"
|
2121
|
-
)
|
2122
|
-
end
|
2123
|
-
|
2124
|
-
it "should raise an error when partially expanding a bogus operator" do
|
2125
|
-
(lambda do
|
2126
|
-
@initial_template.partial_expand({"numbers" => "1"})
|
2127
|
-
end).should raise_error(
|
2128
|
-
Addressable::Template::InvalidTemplateOperatorError
|
2129
|
-
)
|
2130
|
-
(lambda do
|
2131
|
-
@initial_template.partial_expand({"letters" => "a"})
|
2132
|
-
end).should raise_error(
|
2133
|
-
Addressable::Template::InvalidTemplateOperatorError
|
2134
|
-
)
|
2135
|
-
end
|
2136
|
-
end
|
2137
|
-
|
2138
|
-
describe Addressable::Template, "with a partially expanded template" do
|
2139
|
-
before do
|
2140
|
-
@initial_template = Addressable::Template.new(
|
2141
|
-
"http://example.com/{-bogus|/|one,two}/"
|
2142
|
-
)
|
2143
|
-
end
|
2144
|
-
|
2145
|
-
it "should raise an error when partially expanding a bogus operator" do
|
2146
|
-
(lambda do
|
2147
|
-
@initial_template.partial_expand({"one" => "1"})
|
2148
|
-
end).should raise_error(
|
2149
|
-
Addressable::Template::InvalidTemplateOperatorError
|
2150
|
-
)
|
1408
|
+
describe '[]' do
|
1409
|
+
context 'string key' do
|
1410
|
+
it 'returns the corresponding capture' do
|
1411
|
+
expect(its['foo']).to eq('ab')
|
1412
|
+
expect(its['bar']).to eq('cd')
|
1413
|
+
end
|
1414
|
+
it 'returns nil for unknown keys' do
|
1415
|
+
expect(its['baz']).to be_nil
|
1416
|
+
end
|
1417
|
+
end
|
1418
|
+
context 'symbol key' do
|
1419
|
+
it 'returns the corresponding capture' do
|
1420
|
+
expect(its[:foo]).to eq('ab')
|
1421
|
+
expect(its[:bar]).to eq('cd')
|
1422
|
+
end
|
1423
|
+
it 'returns nil for unknown keys' do
|
1424
|
+
expect(its[:baz]).to be_nil
|
1425
|
+
end
|
1426
|
+
end
|
1427
|
+
context 'integer key' do
|
1428
|
+
it 'returns the full URI for index 0' do
|
1429
|
+
expect(its[0]).to eq('ab/cd')
|
1430
|
+
end
|
1431
|
+
it 'returns the corresponding capture' do
|
1432
|
+
expect(its[1]).to eq('ab')
|
1433
|
+
expect(its[2]).to eq('cd')
|
1434
|
+
end
|
1435
|
+
it 'returns nil for unknown keys' do
|
1436
|
+
expect(its[3]).to be_nil
|
1437
|
+
end
|
1438
|
+
end
|
1439
|
+
context 'other key' do
|
1440
|
+
it 'raises an exception' do
|
1441
|
+
expect { its[Object.new] }.to raise_error(TypeError)
|
1442
|
+
end
|
1443
|
+
end
|
1444
|
+
context 'with length' do
|
1445
|
+
it 'returns an array starting at index with given length' do
|
1446
|
+
expect(its[0, 2]).to eq(['ab/cd', 'ab'])
|
1447
|
+
expect(its[2, 1]).to eq(['cd'])
|
1448
|
+
end
|
1449
|
+
end
|
2151
1450
|
end
|
2152
1451
|
end
|