addressable 2.2.8 → 2.3.2

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.

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