addressable 2.6.0 → 2.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +19 -0
- data/Gemfile +13 -17
- data/README.md +12 -10
- data/Rakefile +3 -3
- data/addressable.gemspec +37 -0
- data/lib/addressable/idna/pure.rb +52 -50
- data/lib/addressable/template.rb +25 -39
- data/lib/addressable/uri.rb +80 -34
- data/lib/addressable/version.rb +1 -1
- data/spec/addressable/idna_spec.rb +3 -1
- data/spec/addressable/template_spec.rb +9 -0
- data/spec/addressable/uri_spec.rb +327 -207
- data/spec/spec_helper.rb +9 -0
- data/tasks/gem.rake +6 -7
- data/tasks/profile.rake +72 -0
- data/tasks/rspec.rake +1 -1
- metadata +10 -10
- data/spec/addressable/rack_mount_compat_spec.rb +0 -106
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 03a21b1eab156a16e90bd7963af85980edfbddc8f3dbe052766303dba76cc000
|
4
|
+
data.tar.gz: 03eca5d86f4c70f9320000f36e3cff4fd8023342a4e0ac855d0ef1ec89ee6183
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d504f9475ad823f5bb077b9c039a2c91c83e52c20896247a7289b61725c61b1ddefe8ae06155fb018fc67087cf04276081b42105a18394b45e2374ad0b2fadb0
|
7
|
+
data.tar.gz: b81766fbcb9335d5ca94403b62d3b2a6fae31b66cd3c05f48e1885eaf07883bfa1321b6930271fe1415135aec687af51312a26ce27bd4b83b2ac6424dec597c9
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,22 @@
|
|
1
|
+
# Addressable 2.8.0
|
2
|
+
- fixes ReDoS vulnerability in Addressable::Template#match
|
3
|
+
- no longer replaces `+` with spaces in queries for non-http(s) schemes
|
4
|
+
- fixed encoding ipv6 literals
|
5
|
+
- the `:compacted` flag for `normalized_query` now dedupes parameters
|
6
|
+
- fix broken `escape_component` alias
|
7
|
+
- dropping support for Ruby 2.0 and 2.1
|
8
|
+
- adding Ruby 3.0 compatibility for development tasks
|
9
|
+
- drop support for `rack-mount` and remove Addressable::Template#generate
|
10
|
+
- performance improvements
|
11
|
+
- switch CI/CD to GitHub Actions
|
12
|
+
|
13
|
+
# Addressable 2.7.0
|
14
|
+
- added `:compacted` flag to `normalized_query`
|
15
|
+
- `heuristic_parse` handles `mailto:` more intuitively
|
16
|
+
- dropped explicit support for JRuby 9.0.5.0
|
17
|
+
- compatibility w/ public_suffix 4.x
|
18
|
+
- performance improvements
|
19
|
+
|
1
20
|
# Addressable 2.6.0
|
2
21
|
- added `tld=` method to allow assignment to the public suffix
|
3
22
|
- most `heuristic_parse` patterns are now case-insensitive
|
data/Gemfile
CHANGED
@@ -1,10 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
source 'https://rubygems.org'
|
2
4
|
|
3
|
-
gemspec
|
5
|
+
gemspec(path: __FILE__ == "(eval)" ? ".." : ".")
|
4
6
|
|
5
7
|
group :test do
|
6
|
-
gem 'rspec', '~> 3.
|
7
|
-
gem 'rspec-its', '~> 1.
|
8
|
+
gem 'rspec', '~> 3.8'
|
9
|
+
gem 'rspec-its', '~> 1.3'
|
10
|
+
end
|
11
|
+
|
12
|
+
group :coverage do
|
13
|
+
gem "coveralls", "> 0.7", require: false, platforms: :mri
|
14
|
+
gem "simplecov", require: false
|
8
15
|
end
|
9
16
|
|
10
17
|
group :development do
|
@@ -14,19 +21,8 @@ group :development do
|
|
14
21
|
end
|
15
22
|
|
16
23
|
group :test, :development do
|
17
|
-
gem '
|
18
|
-
gem
|
19
|
-
gem 'coveralls', :require => false, :platforms => [
|
20
|
-
:ruby_20, :ruby_21, :ruby_22, :ruby_23
|
21
|
-
]
|
22
|
-
# Used to test compatibility.
|
23
|
-
gem 'rack-mount', git: 'https://github.com/sporkmonger/rack-mount.git', require: 'rack/mount'
|
24
|
-
|
25
|
-
if RUBY_VERSION.start_with?('2.0', '2.1')
|
26
|
-
gem 'rack', '< 2', :require => false
|
27
|
-
else
|
28
|
-
gem 'rack', :require => false
|
29
|
-
end
|
24
|
+
gem 'memory_profiler'
|
25
|
+
gem "rake", ">= 12.3.3"
|
30
26
|
end
|
31
27
|
|
32
|
-
gem
|
28
|
+
gem "idn-ruby", platform: :mri
|
data/README.md
CHANGED
@@ -7,21 +7,23 @@
|
|
7
7
|
<dt>License</dt><dd>Apache 2.0</dd>
|
8
8
|
</dl>
|
9
9
|
|
10
|
-
[![Gem Version](
|
11
|
-
[![Build Status](https://
|
10
|
+
[![Gem Version](https://img.shields.io/gem/dt/addressable.svg)][gem]
|
11
|
+
[![Build Status](https://github.com/sporkmonger/addressable/workflows/CI/badge.svg)][actions]
|
12
12
|
[![Test Coverage Status](https://img.shields.io/coveralls/sporkmonger/addressable.svg)][coveralls]
|
13
|
-
[![Documentation Coverage Status](
|
13
|
+
[![Documentation Coverage Status](https://inch-ci.org/github/sporkmonger/addressable.svg?branch=master)][inch]
|
14
14
|
|
15
15
|
[gem]: https://rubygems.org/gems/addressable
|
16
|
-
[
|
16
|
+
[actions]: https://github.com/sporkmonger/addressable/actions
|
17
17
|
[coveralls]: https://coveralls.io/r/sporkmonger/addressable
|
18
|
-
[inch]:
|
18
|
+
[inch]: https://inch-ci.org/github/sporkmonger/addressable
|
19
19
|
|
20
20
|
# Description
|
21
21
|
|
22
|
-
Addressable is
|
23
|
-
Ruby's standard library. It
|
24
|
-
|
22
|
+
Addressable is an alternative implementation to the URI implementation
|
23
|
+
that is part of Ruby's standard library. It is flexible, offers heuristic
|
24
|
+
parsing, and additionally provides extensive support for IRIs and URI templates.
|
25
|
+
|
26
|
+
Addressable closely conforms to RFC 3986, RFC 3987, and RFC 6570 (level 4).
|
25
27
|
|
26
28
|
# Reference
|
27
29
|
|
@@ -96,7 +98,7 @@ You may optionally turn on native IDN support by installing libidn and the
|
|
96
98
|
idn gem:
|
97
99
|
|
98
100
|
```console
|
99
|
-
$ sudo apt-get install
|
101
|
+
$ sudo apt-get install libidn11-dev # Debian/Ubuntu
|
100
102
|
$ brew install libidn # OS X
|
101
103
|
$ gem install idn-ruby
|
102
104
|
```
|
@@ -108,7 +110,7 @@ dependency using a pessimistic version constraint covering the major and minor
|
|
108
110
|
values:
|
109
111
|
|
110
112
|
```ruby
|
111
|
-
spec.add_dependency 'addressable', '~> 2.
|
113
|
+
spec.add_dependency 'addressable', '~> 2.7'
|
112
114
|
```
|
113
115
|
|
114
116
|
If you need a specific bug fix, you can also specify minimum tiny versions
|
data/Rakefile
CHANGED
@@ -14,9 +14,9 @@ RELEASE_NAME = "REL #{PKG_VERSION}"
|
|
14
14
|
|
15
15
|
PKG_SUMMARY = "URI Implementation"
|
16
16
|
PKG_DESCRIPTION = <<-TEXT
|
17
|
-
Addressable is
|
18
|
-
Ruby's standard library. It
|
19
|
-
|
17
|
+
Addressable is an alternative implementation to the URI implementation that is
|
18
|
+
part of Ruby's standard library. It is flexible, offers heuristic parsing, and
|
19
|
+
additionally provides extensive support for IRIs and URI templates.
|
20
20
|
TEXT
|
21
21
|
|
22
22
|
PKG_FILES = FileList[
|
data/addressable.gemspec
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
# stub: addressable 2.8.0 ruby lib
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "addressable".freeze
|
6
|
+
s.version = "2.8.0"
|
7
|
+
|
8
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
9
|
+
s.require_paths = ["lib".freeze]
|
10
|
+
s.authors = ["Bob Aman".freeze]
|
11
|
+
s.date = "2021-07-03"
|
12
|
+
s.description = "Addressable is an alternative implementation to the URI implementation that is\npart of Ruby's standard library. It is flexible, offers heuristic parsing, and\nadditionally provides extensive support for IRIs and URI templates.\n".freeze
|
13
|
+
s.email = "bob@sporkmonger.com".freeze
|
14
|
+
s.extra_rdoc_files = ["README.md".freeze]
|
15
|
+
s.files = ["CHANGELOG.md".freeze, "Gemfile".freeze, "LICENSE.txt".freeze, "README.md".freeze, "Rakefile".freeze, "addressable.gemspec".freeze, "data/unicode.data".freeze, "lib/addressable.rb".freeze, "lib/addressable/idna.rb".freeze, "lib/addressable/idna/native.rb".freeze, "lib/addressable/idna/pure.rb".freeze, "lib/addressable/template.rb".freeze, "lib/addressable/uri.rb".freeze, "lib/addressable/version.rb".freeze, "spec/addressable/idna_spec.rb".freeze, "spec/addressable/net_http_compat_spec.rb".freeze, "spec/addressable/security_spec.rb".freeze, "spec/addressable/template_spec.rb".freeze, "spec/addressable/uri_spec.rb".freeze, "spec/spec_helper.rb".freeze, "tasks/clobber.rake".freeze, "tasks/gem.rake".freeze, "tasks/git.rake".freeze, "tasks/metrics.rake".freeze, "tasks/profile.rake".freeze, "tasks/rspec.rake".freeze, "tasks/yard.rake".freeze]
|
16
|
+
s.homepage = "https://github.com/sporkmonger/addressable".freeze
|
17
|
+
s.licenses = ["Apache-2.0".freeze]
|
18
|
+
s.rdoc_options = ["--main".freeze, "README.md".freeze]
|
19
|
+
s.required_ruby_version = Gem::Requirement.new(">= 2.0".freeze)
|
20
|
+
s.rubygems_version = "3.0.3".freeze
|
21
|
+
s.summary = "URI Implementation".freeze
|
22
|
+
|
23
|
+
if s.respond_to? :specification_version then
|
24
|
+
s.specification_version = 4
|
25
|
+
|
26
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
27
|
+
s.add_runtime_dependency(%q<public_suffix>.freeze, [">= 2.0.2", "< 5.0"])
|
28
|
+
s.add_development_dependency(%q<bundler>.freeze, [">= 1.0", "< 3.0"])
|
29
|
+
else
|
30
|
+
s.add_dependency(%q<public_suffix>.freeze, [">= 2.0.2", "< 5.0"])
|
31
|
+
s.add_dependency(%q<bundler>.freeze, [">= 1.0", "< 3.0"])
|
32
|
+
end
|
33
|
+
else
|
34
|
+
s.add_dependency(%q<public_suffix>.freeze, [">= 2.0.2", "< 5.0"])
|
35
|
+
s.add_dependency(%q<bundler>.freeze, [">= 1.0", "< 3.0"])
|
36
|
+
end
|
37
|
+
end
|
@@ -135,7 +135,7 @@ module Addressable
|
|
135
135
|
unpacked.map! { |codepoint| lookup_unicode_lowercase(codepoint) }
|
136
136
|
return unpacked.pack("U*")
|
137
137
|
end
|
138
|
-
|
138
|
+
private_class_method :unicode_downcase
|
139
139
|
|
140
140
|
def self.unicode_compose(unpacked)
|
141
141
|
unpacked_result = []
|
@@ -160,7 +160,7 @@ module Addressable
|
|
160
160
|
unpacked_result << starter
|
161
161
|
return unpacked_result
|
162
162
|
end
|
163
|
-
|
163
|
+
private_class_method :unicode_compose
|
164
164
|
|
165
165
|
def self.unicode_compose_pair(ch_one, ch_two)
|
166
166
|
if ch_one >= HANGUL_LBASE && ch_one < HANGUL_LBASE + HANGUL_LCOUNT &&
|
@@ -178,43 +178,45 @@ module Addressable
|
|
178
178
|
end
|
179
179
|
|
180
180
|
p = []
|
181
|
-
ucs4_to_utf8 = lambda do |ch|
|
182
|
-
if ch < 128
|
183
|
-
p << ch
|
184
|
-
elsif ch < 2048
|
185
|
-
p << (ch >> 6 | 192)
|
186
|
-
p << (ch & 63 | 128)
|
187
|
-
elsif ch < 0x10000
|
188
|
-
p << (ch >> 12 | 224)
|
189
|
-
p << (ch >> 6 & 63 | 128)
|
190
|
-
p << (ch & 63 | 128)
|
191
|
-
elsif ch < 0x200000
|
192
|
-
p << (ch >> 18 | 240)
|
193
|
-
p << (ch >> 12 & 63 | 128)
|
194
|
-
p << (ch >> 6 & 63 | 128)
|
195
|
-
p << (ch & 63 | 128)
|
196
|
-
elsif ch < 0x4000000
|
197
|
-
p << (ch >> 24 | 248)
|
198
|
-
p << (ch >> 18 & 63 | 128)
|
199
|
-
p << (ch >> 12 & 63 | 128)
|
200
|
-
p << (ch >> 6 & 63 | 128)
|
201
|
-
p << (ch & 63 | 128)
|
202
|
-
elsif ch < 0x80000000
|
203
|
-
p << (ch >> 30 | 252)
|
204
|
-
p << (ch >> 24 & 63 | 128)
|
205
|
-
p << (ch >> 18 & 63 | 128)
|
206
|
-
p << (ch >> 12 & 63 | 128)
|
207
|
-
p << (ch >> 6 & 63 | 128)
|
208
|
-
p << (ch & 63 | 128)
|
209
|
-
end
|
210
|
-
end
|
211
181
|
|
212
|
-
ucs4_to_utf8
|
213
|
-
ucs4_to_utf8
|
182
|
+
ucs4_to_utf8(ch_one, p)
|
183
|
+
ucs4_to_utf8(ch_two, p)
|
214
184
|
|
215
185
|
return lookup_unicode_composition(p)
|
216
186
|
end
|
217
|
-
|
187
|
+
private_class_method :unicode_compose_pair
|
188
|
+
|
189
|
+
def self.ucs4_to_utf8(char, buffer)
|
190
|
+
if char < 128
|
191
|
+
buffer << char
|
192
|
+
elsif char < 2048
|
193
|
+
buffer << (char >> 6 | 192)
|
194
|
+
buffer << (char & 63 | 128)
|
195
|
+
elsif char < 0x10000
|
196
|
+
buffer << (char >> 12 | 224)
|
197
|
+
buffer << (char >> 6 & 63 | 128)
|
198
|
+
buffer << (char & 63 | 128)
|
199
|
+
elsif char < 0x200000
|
200
|
+
buffer << (char >> 18 | 240)
|
201
|
+
buffer << (char >> 12 & 63 | 128)
|
202
|
+
buffer << (char >> 6 & 63 | 128)
|
203
|
+
buffer << (char & 63 | 128)
|
204
|
+
elsif char < 0x4000000
|
205
|
+
buffer << (char >> 24 | 248)
|
206
|
+
buffer << (char >> 18 & 63 | 128)
|
207
|
+
buffer << (char >> 12 & 63 | 128)
|
208
|
+
buffer << (char >> 6 & 63 | 128)
|
209
|
+
buffer << (char & 63 | 128)
|
210
|
+
elsif char < 0x80000000
|
211
|
+
buffer << (char >> 30 | 252)
|
212
|
+
buffer << (char >> 24 & 63 | 128)
|
213
|
+
buffer << (char >> 18 & 63 | 128)
|
214
|
+
buffer << (char >> 12 & 63 | 128)
|
215
|
+
buffer << (char >> 6 & 63 | 128)
|
216
|
+
buffer << (char & 63 | 128)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
private_class_method :ucs4_to_utf8
|
218
220
|
|
219
221
|
def self.unicode_sort_canonical(unpacked)
|
220
222
|
unpacked = unpacked.dup
|
@@ -238,7 +240,7 @@ module Addressable
|
|
238
240
|
end
|
239
241
|
return unpacked
|
240
242
|
end
|
241
|
-
|
243
|
+
private_class_method :unicode_sort_canonical
|
242
244
|
|
243
245
|
def self.unicode_decompose(unpacked)
|
244
246
|
unpacked_result = []
|
@@ -259,7 +261,7 @@ module Addressable
|
|
259
261
|
end
|
260
262
|
return unpacked_result
|
261
263
|
end
|
262
|
-
|
264
|
+
private_class_method :unicode_decompose
|
263
265
|
|
264
266
|
def self.unicode_decompose_hangul(codepoint)
|
265
267
|
sindex = codepoint - HANGUL_SBASE;
|
@@ -276,7 +278,7 @@ module Addressable
|
|
276
278
|
end
|
277
279
|
return l, v, t
|
278
280
|
end
|
279
|
-
|
281
|
+
private_class_method :unicode_decompose_hangul
|
280
282
|
|
281
283
|
def self.lookup_unicode_combining_class(codepoint)
|
282
284
|
codepoint_data = UNICODE_DATA[codepoint]
|
@@ -284,14 +286,14 @@ module Addressable
|
|
284
286
|
(codepoint_data[UNICODE_DATA_COMBINING_CLASS] || 0) :
|
285
287
|
0)
|
286
288
|
end
|
287
|
-
|
289
|
+
private_class_method :lookup_unicode_combining_class
|
288
290
|
|
289
291
|
def self.lookup_unicode_compatibility(codepoint)
|
290
292
|
codepoint_data = UNICODE_DATA[codepoint]
|
291
293
|
(codepoint_data ?
|
292
294
|
codepoint_data[UNICODE_DATA_COMPATIBILITY] : nil)
|
293
295
|
end
|
294
|
-
|
296
|
+
private_class_method :lookup_unicode_compatibility
|
295
297
|
|
296
298
|
def self.lookup_unicode_lowercase(codepoint)
|
297
299
|
codepoint_data = UNICODE_DATA[codepoint]
|
@@ -299,12 +301,12 @@ module Addressable
|
|
299
301
|
(codepoint_data[UNICODE_DATA_LOWERCASE] || codepoint) :
|
300
302
|
codepoint)
|
301
303
|
end
|
302
|
-
|
304
|
+
private_class_method :lookup_unicode_lowercase
|
303
305
|
|
304
306
|
def self.lookup_unicode_composition(unpacked)
|
305
307
|
return COMPOSITION_TABLE[unpacked]
|
306
308
|
end
|
307
|
-
|
309
|
+
private_class_method :lookup_unicode_composition
|
308
310
|
|
309
311
|
HANGUL_SBASE = 0xac00
|
310
312
|
HANGUL_LBASE = 0x1100
|
@@ -341,7 +343,7 @@ module Addressable
|
|
341
343
|
end
|
342
344
|
|
343
345
|
COMPOSITION_TABLE = {}
|
344
|
-
|
346
|
+
UNICODE_DATA.each do |codepoint, data|
|
345
347
|
canonical = data[UNICODE_DATA_CANONICAL]
|
346
348
|
exclusion = data[UNICODE_DATA_EXCLUSION]
|
347
349
|
|
@@ -500,7 +502,7 @@ module Addressable
|
|
500
502
|
|
501
503
|
output[0..outlen].map { |x| x.chr }.join("").sub(/\0+\z/, "")
|
502
504
|
end
|
503
|
-
|
505
|
+
private_class_method :punycode_encode
|
504
506
|
|
505
507
|
def self.punycode_decode(punycode)
|
506
508
|
input = []
|
@@ -622,22 +624,22 @@ module Addressable
|
|
622
624
|
|
623
625
|
output.pack("U*")
|
624
626
|
end
|
625
|
-
|
627
|
+
private_class_method :punycode_decode
|
626
628
|
|
627
629
|
def self.punycode_basic?(codepoint)
|
628
630
|
codepoint < 0x80
|
629
631
|
end
|
630
|
-
|
632
|
+
private_class_method :punycode_basic?
|
631
633
|
|
632
634
|
def self.punycode_delimiter?(codepoint)
|
633
635
|
codepoint == PUNYCODE_DELIMITER
|
634
636
|
end
|
635
|
-
|
637
|
+
private_class_method :punycode_delimiter?
|
636
638
|
|
637
639
|
def self.punycode_encode_digit(d)
|
638
640
|
d + 22 + 75 * ((d < 26) ? 1 : 0)
|
639
641
|
end
|
640
|
-
|
642
|
+
private_class_method :punycode_encode_digit
|
641
643
|
|
642
644
|
# Returns the numeric value of a basic codepoint
|
643
645
|
# (for use in representing integers) in the range 0 to
|
@@ -653,7 +655,7 @@ module Addressable
|
|
653
655
|
PUNYCODE_BASE
|
654
656
|
end
|
655
657
|
end
|
656
|
-
|
658
|
+
private_class_method :punycode_decode_digit
|
657
659
|
|
658
660
|
# Bias adaptation method
|
659
661
|
def self.punycode_adapt(delta, numpoints, firsttime)
|
@@ -670,7 +672,7 @@ module Addressable
|
|
670
672
|
|
671
673
|
k + (difference + 1) * delta / (delta + PUNYCODE_SKEW)
|
672
674
|
end
|
673
|
-
|
675
|
+
private_class_method :punycode_adapt
|
674
676
|
end
|
675
677
|
# :startdoc:
|
676
678
|
end
|
data/lib/addressable/template.rb
CHANGED
@@ -37,7 +37,7 @@ module Addressable
|
|
37
37
|
Addressable::URI::CharacterClasses::DIGIT + '_'
|
38
38
|
|
39
39
|
var_char =
|
40
|
-
"(
|
40
|
+
"(?>(?:[#{variable_char_class}]|%[a-fA-F0-9][a-fA-F0-9])+)"
|
41
41
|
RESERVED =
|
42
42
|
"(?:[#{anything}]|%[a-fA-F0-9][a-fA-F0-9])"
|
43
43
|
UNRESERVED =
|
@@ -412,7 +412,7 @@ module Addressable
|
|
412
412
|
# match.captures
|
413
413
|
# #=> ["a", ["b", "c"]]
|
414
414
|
def match(uri, processor=nil)
|
415
|
-
uri = Addressable::URI.parse(uri)
|
415
|
+
uri = Addressable::URI.parse(uri) unless uri.is_a?(Addressable::URI)
|
416
416
|
mapping = {}
|
417
417
|
|
418
418
|
# First, we need to process the pattern, and extract the values.
|
@@ -653,40 +653,6 @@ module Addressable
|
|
653
653
|
self.to_regexp.named_captures
|
654
654
|
end
|
655
655
|
|
656
|
-
##
|
657
|
-
# Generates a route result for a given set of parameters.
|
658
|
-
# Should only be used by rack-mount.
|
659
|
-
#
|
660
|
-
# @param params [Hash] The set of parameters used to expand the template.
|
661
|
-
# @param recall [Hash] Default parameters used to expand the template.
|
662
|
-
# @param options [Hash] Either a `:processor` or a `:parameterize` block.
|
663
|
-
#
|
664
|
-
# @api private
|
665
|
-
def generate(params={}, recall={}, options={})
|
666
|
-
merged = recall.merge(params)
|
667
|
-
if options[:processor]
|
668
|
-
processor = options[:processor]
|
669
|
-
elsif options[:parameterize]
|
670
|
-
# TODO: This is sending me into fits trying to shoe-horn this into
|
671
|
-
# the existing API. I think I've got this backwards and processors
|
672
|
-
# should be a set of 4 optional blocks named :validate, :transform,
|
673
|
-
# :match, and :restore. Having to use a singleton here is a huge
|
674
|
-
# code smell.
|
675
|
-
processor = Object.new
|
676
|
-
class <<processor
|
677
|
-
attr_accessor :block
|
678
|
-
def transform(name, value)
|
679
|
-
block.call(name, value)
|
680
|
-
end
|
681
|
-
end
|
682
|
-
processor.block = options[:parameterize]
|
683
|
-
else
|
684
|
-
processor = nil
|
685
|
-
end
|
686
|
-
result = self.expand(merged, processor)
|
687
|
-
result.to_s if result
|
688
|
-
end
|
689
|
-
|
690
656
|
private
|
691
657
|
def ordered_variable_defaults
|
692
658
|
@ordered_variable_defaults ||= begin
|
@@ -973,15 +939,35 @@ module Addressable
|
|
973
939
|
end
|
974
940
|
end
|
975
941
|
|
942
|
+
##
|
943
|
+
# Generates the <tt>Regexp</tt> that parses a template pattern. Memoizes the
|
944
|
+
# value if template processor not set (processors may not be deterministic)
|
945
|
+
#
|
946
|
+
# @param [String] pattern The URI template pattern.
|
947
|
+
# @param [#match] processor The template processor to use.
|
948
|
+
#
|
949
|
+
# @return [Array, Regexp]
|
950
|
+
# An array of expansion variables nad a regular expression which may be
|
951
|
+
# used to parse a template pattern
|
952
|
+
def parse_template_pattern(pattern, processor = nil)
|
953
|
+
if processor.nil? && pattern == @pattern
|
954
|
+
@cached_template_parse ||=
|
955
|
+
parse_new_template_pattern(pattern, processor)
|
956
|
+
else
|
957
|
+
parse_new_template_pattern(pattern, processor)
|
958
|
+
end
|
959
|
+
end
|
960
|
+
|
976
961
|
##
|
977
962
|
# Generates the <tt>Regexp</tt> that parses a template pattern.
|
978
963
|
#
|
979
964
|
# @param [String] pattern The URI template pattern.
|
980
965
|
# @param [#match] processor The template processor to use.
|
981
966
|
#
|
982
|
-
# @return [Regexp]
|
983
|
-
#
|
984
|
-
|
967
|
+
# @return [Array, Regexp]
|
968
|
+
# An array of expansion variables nad a regular expression which may be
|
969
|
+
# used to parse a template pattern
|
970
|
+
def parse_new_template_pattern(pattern, processor = nil)
|
985
971
|
# Escape the pattern. The two gsubs restore the escaped curly braces
|
986
972
|
# back to their original form. Basically, escape everything that isn't
|
987
973
|
# within an expansion.
|