addressable 2.5.1 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/CHANGELOG.md +36 -0
- data/Gemfile +13 -17
- data/README.md +14 -14
- data/Rakefile +5 -3
- data/addressable.gemspec +37 -0
- data/lib/addressable/idna/native.rb +4 -2
- data/lib/addressable/idna/pure.rb +54 -53
- data/lib/addressable/idna.rb +2 -0
- data/lib/addressable/template.rb +42 -76
- data/lib/addressable/uri.rb +128 -64
- data/lib/addressable/version.rb +4 -2
- data/lib/addressable.rb +2 -0
- data/spec/addressable/idna_spec.rb +23 -7
- data/spec/addressable/net_http_compat_spec.rb +2 -0
- data/spec/addressable/security_spec.rb +2 -0
- data/spec/addressable/template_spec.rb +42 -1
- data/spec/addressable/uri_spec.rb +408 -207
- data/spec/spec_helper.rb +12 -0
- data/tasks/clobber.rake +2 -0
- data/tasks/gem.rake +8 -7
- data/tasks/git.rake +2 -0
- data/tasks/metrics.rake +2 -0
- data/tasks/profile.rake +72 -0
- data/tasks/rspec.rake +3 -1
- data/tasks/yard.rake +2 -0
- metadata +22 -16
- data/spec/addressable/rack_mount_compat_spec.rb +0 -104
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,39 @@
|
|
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
|
+
|
20
|
+
# Addressable 2.6.0
|
21
|
+
- added `tld=` method to allow assignment to the public suffix
|
22
|
+
- most `heuristic_parse` patterns are now case-insensitive
|
23
|
+
- `heuristic_parse` handles more `file://` URI variations
|
24
|
+
- fixes bug in `heuristic_parse` when uri starts with digit
|
25
|
+
- fixes bug in `request_uri=` with query strings
|
26
|
+
- fixes template issues with `nil` and `?` operator
|
27
|
+
- `frozen_string_literal` pragmas added
|
28
|
+
- minor performance improvements in regexps
|
29
|
+
- fixes to eliminate warnings
|
30
|
+
|
31
|
+
# Addressable 2.5.2
|
32
|
+
- better support for frozen string literals
|
33
|
+
- fixed bug w/ uppercase characters in scheme
|
34
|
+
- IDNA errors w/ emoji URLs
|
35
|
+
- compatibility w/ public_suffix 3.x
|
36
|
+
|
1
37
|
# Addressable 2.5.1
|
2
38
|
- allow unicode normalization to be disabled for URI Template expansion
|
3
39
|
- removed duplicate test
|
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,23 +7,23 @@
|
|
7
7
|
<dt>License</dt><dd>Apache 2.0</dd>
|
8
8
|
</dl>
|
9
9
|
|
10
|
-
[][gemnasium]
|
10
|
+
[][gem]
|
11
|
+
[][actions]
|
13
12
|
[][coveralls]
|
14
|
-
[][inch]
|
15
14
|
|
16
15
|
[gem]: https://rubygems.org/gems/addressable
|
17
|
-
[
|
18
|
-
[gemnasium]: https://gemnasium.com/sporkmonger/addressable
|
16
|
+
[actions]: https://github.com/sporkmonger/addressable/actions
|
19
17
|
[coveralls]: https://coveralls.io/r/sporkmonger/addressable
|
20
|
-
[inch]:
|
18
|
+
[inch]: https://inch-ci.org/github/sporkmonger/addressable
|
21
19
|
|
22
20
|
# Description
|
23
21
|
|
24
|
-
Addressable is
|
25
|
-
Ruby's standard library. It
|
26
|
-
|
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).
|
27
27
|
|
28
28
|
# Reference
|
29
29
|
|
@@ -58,7 +58,7 @@ For more details, see [RFC 6570](https://www.rfc-editor.org/rfc/rfc6570.txt).
|
|
58
58
|
|
59
59
|
require "addressable/template"
|
60
60
|
|
61
|
-
template = Addressable::Template.new("http://example.com/{?query*}
|
61
|
+
template = Addressable::Template.new("http://example.com/{?query*}")
|
62
62
|
template.expand({
|
63
63
|
"query" => {
|
64
64
|
'foo' => 'bar',
|
@@ -98,19 +98,19 @@ You may optionally turn on native IDN support by installing libidn and the
|
|
98
98
|
idn gem:
|
99
99
|
|
100
100
|
```console
|
101
|
-
$ sudo apt-get install
|
101
|
+
$ sudo apt-get install libidn11-dev # Debian/Ubuntu
|
102
102
|
$ brew install libidn # OS X
|
103
103
|
$ gem install idn-ruby
|
104
104
|
```
|
105
105
|
|
106
106
|
# Semantic Versioning
|
107
107
|
|
108
|
-
This project uses
|
108
|
+
This project uses [Semantic Versioning](https://semver.org/). You can (and should) specify your
|
109
109
|
dependency using a pessimistic version constraint covering the major and minor
|
110
110
|
values:
|
111
111
|
|
112
112
|
```ruby
|
113
|
-
spec.add_dependency 'addressable', '~> 2.
|
113
|
+
spec.add_dependency 'addressable', '~> 2.7'
|
114
114
|
```
|
115
115
|
|
116
116
|
If you need a specific bug fix, you can also specify minimum tiny versions
|
data/Rakefile
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'rubygems'
|
2
4
|
require 'rake'
|
3
5
|
|
@@ -12,9 +14,9 @@ RELEASE_NAME = "REL #{PKG_VERSION}"
|
|
12
14
|
|
13
15
|
PKG_SUMMARY = "URI Implementation"
|
14
16
|
PKG_DESCRIPTION = <<-TEXT
|
15
|
-
Addressable is
|
16
|
-
Ruby's standard library. It
|
17
|
-
|
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.
|
18
20
|
TEXT
|
19
21
|
|
20
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
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# encoding:utf-8
|
2
4
|
#--
|
3
5
|
# Copyright (C) Bob Aman
|
@@ -35,7 +37,7 @@ module Addressable
|
|
35
37
|
def self.to_ascii(value)
|
36
38
|
value.to_s.split('.', -1).map do |segment|
|
37
39
|
if segment.size > 0 && segment.size < 64
|
38
|
-
IDN::Idna.toASCII(segment)
|
40
|
+
IDN::Idna.toASCII(segment, IDN::Idna::ALLOW_UNASSIGNED)
|
39
41
|
elsif segment.size >= 64
|
40
42
|
segment
|
41
43
|
else
|
@@ -47,7 +49,7 @@ module Addressable
|
|
47
49
|
def self.to_unicode(value)
|
48
50
|
value.to_s.split('.', -1).map do |segment|
|
49
51
|
if segment.size > 0 && segment.size < 64
|
50
|
-
IDN::Idna.toUnicode(segment)
|
52
|
+
IDN::Idna.toUnicode(segment, IDN::Idna::ALLOW_UNASSIGNED)
|
51
53
|
elsif segment.size >= 64
|
52
54
|
segment
|
53
55
|
else
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# encoding:utf-8
|
2
4
|
#--
|
3
5
|
# Copyright (C) Bob Aman
|
@@ -133,7 +135,7 @@ module Addressable
|
|
133
135
|
unpacked.map! { |codepoint| lookup_unicode_lowercase(codepoint) }
|
134
136
|
return unpacked.pack("U*")
|
135
137
|
end
|
136
|
-
|
138
|
+
private_class_method :unicode_downcase
|
137
139
|
|
138
140
|
def self.unicode_compose(unpacked)
|
139
141
|
unpacked_result = []
|
@@ -146,22 +148,19 @@ module Addressable
|
|
146
148
|
starter_cc = 256 if starter_cc != 0
|
147
149
|
for i in 1...length
|
148
150
|
ch = unpacked[i]
|
149
|
-
cc = lookup_unicode_combining_class(ch)
|
150
151
|
|
151
152
|
if (starter_cc == 0 &&
|
152
153
|
(composite = unicode_compose_pair(starter, ch)) != nil)
|
153
154
|
starter = composite
|
154
|
-
startercc = lookup_unicode_combining_class(composite)
|
155
155
|
else
|
156
156
|
unpacked_result << starter
|
157
157
|
starter = ch
|
158
|
-
startercc = cc
|
159
158
|
end
|
160
159
|
end
|
161
160
|
unpacked_result << starter
|
162
161
|
return unpacked_result
|
163
162
|
end
|
164
|
-
|
163
|
+
private_class_method :unicode_compose
|
165
164
|
|
166
165
|
def self.unicode_compose_pair(ch_one, ch_two)
|
167
166
|
if ch_one >= HANGUL_LBASE && ch_one < HANGUL_LBASE + HANGUL_LCOUNT &&
|
@@ -179,43 +178,45 @@ module Addressable
|
|
179
178
|
end
|
180
179
|
|
181
180
|
p = []
|
182
|
-
ucs4_to_utf8 = lambda do |ch|
|
183
|
-
if ch < 128
|
184
|
-
p << ch
|
185
|
-
elsif ch < 2048
|
186
|
-
p << (ch >> 6 | 192)
|
187
|
-
p << (ch & 63 | 128)
|
188
|
-
elsif ch < 0x10000
|
189
|
-
p << (ch >> 12 | 224)
|
190
|
-
p << (ch >> 6 & 63 | 128)
|
191
|
-
p << (ch & 63 | 128)
|
192
|
-
elsif ch < 0x200000
|
193
|
-
p << (ch >> 18 | 240)
|
194
|
-
p << (ch >> 12 & 63 | 128)
|
195
|
-
p << (ch >> 6 & 63 | 128)
|
196
|
-
p << (ch & 63 | 128)
|
197
|
-
elsif ch < 0x4000000
|
198
|
-
p << (ch >> 24 | 248)
|
199
|
-
p << (ch >> 18 & 63 | 128)
|
200
|
-
p << (ch >> 12 & 63 | 128)
|
201
|
-
p << (ch >> 6 & 63 | 128)
|
202
|
-
p << (ch & 63 | 128)
|
203
|
-
elsif ch < 0x80000000
|
204
|
-
p << (ch >> 30 | 252)
|
205
|
-
p << (ch >> 24 & 63 | 128)
|
206
|
-
p << (ch >> 18 & 63 | 128)
|
207
|
-
p << (ch >> 12 & 63 | 128)
|
208
|
-
p << (ch >> 6 & 63 | 128)
|
209
|
-
p << (ch & 63 | 128)
|
210
|
-
end
|
211
|
-
end
|
212
181
|
|
213
|
-
ucs4_to_utf8
|
214
|
-
ucs4_to_utf8
|
182
|
+
ucs4_to_utf8(ch_one, p)
|
183
|
+
ucs4_to_utf8(ch_two, p)
|
215
184
|
|
216
185
|
return lookup_unicode_composition(p)
|
217
186
|
end
|
218
|
-
|
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
|
219
220
|
|
220
221
|
def self.unicode_sort_canonical(unpacked)
|
221
222
|
unpacked = unpacked.dup
|
@@ -239,7 +240,7 @@ module Addressable
|
|
239
240
|
end
|
240
241
|
return unpacked
|
241
242
|
end
|
242
|
-
|
243
|
+
private_class_method :unicode_sort_canonical
|
243
244
|
|
244
245
|
def self.unicode_decompose(unpacked)
|
245
246
|
unpacked_result = []
|
@@ -260,7 +261,7 @@ module Addressable
|
|
260
261
|
end
|
261
262
|
return unpacked_result
|
262
263
|
end
|
263
|
-
|
264
|
+
private_class_method :unicode_decompose
|
264
265
|
|
265
266
|
def self.unicode_decompose_hangul(codepoint)
|
266
267
|
sindex = codepoint - HANGUL_SBASE;
|
@@ -277,7 +278,7 @@ module Addressable
|
|
277
278
|
end
|
278
279
|
return l, v, t
|
279
280
|
end
|
280
|
-
|
281
|
+
private_class_method :unicode_decompose_hangul
|
281
282
|
|
282
283
|
def self.lookup_unicode_combining_class(codepoint)
|
283
284
|
codepoint_data = UNICODE_DATA[codepoint]
|
@@ -285,14 +286,14 @@ module Addressable
|
|
285
286
|
(codepoint_data[UNICODE_DATA_COMBINING_CLASS] || 0) :
|
286
287
|
0)
|
287
288
|
end
|
288
|
-
|
289
|
+
private_class_method :lookup_unicode_combining_class
|
289
290
|
|
290
291
|
def self.lookup_unicode_compatibility(codepoint)
|
291
292
|
codepoint_data = UNICODE_DATA[codepoint]
|
292
293
|
(codepoint_data ?
|
293
294
|
codepoint_data[UNICODE_DATA_COMPATIBILITY] : nil)
|
294
295
|
end
|
295
|
-
|
296
|
+
private_class_method :lookup_unicode_compatibility
|
296
297
|
|
297
298
|
def self.lookup_unicode_lowercase(codepoint)
|
298
299
|
codepoint_data = UNICODE_DATA[codepoint]
|
@@ -300,12 +301,12 @@ module Addressable
|
|
300
301
|
(codepoint_data[UNICODE_DATA_LOWERCASE] || codepoint) :
|
301
302
|
codepoint)
|
302
303
|
end
|
303
|
-
|
304
|
+
private_class_method :lookup_unicode_lowercase
|
304
305
|
|
305
306
|
def self.lookup_unicode_composition(unpacked)
|
306
307
|
return COMPOSITION_TABLE[unpacked]
|
307
308
|
end
|
308
|
-
|
309
|
+
private_class_method :lookup_unicode_composition
|
309
310
|
|
310
311
|
HANGUL_SBASE = 0xac00
|
311
312
|
HANGUL_LBASE = 0x1100
|
@@ -342,7 +343,7 @@ module Addressable
|
|
342
343
|
end
|
343
344
|
|
344
345
|
COMPOSITION_TABLE = {}
|
345
|
-
|
346
|
+
UNICODE_DATA.each do |codepoint, data|
|
346
347
|
canonical = data[UNICODE_DATA_CANONICAL]
|
347
348
|
exclusion = data[UNICODE_DATA_EXCLUSION]
|
348
349
|
|
@@ -501,7 +502,7 @@ module Addressable
|
|
501
502
|
|
502
503
|
output[0..outlen].map { |x| x.chr }.join("").sub(/\0+\z/, "")
|
503
504
|
end
|
504
|
-
|
505
|
+
private_class_method :punycode_encode
|
505
506
|
|
506
507
|
def self.punycode_decode(punycode)
|
507
508
|
input = []
|
@@ -623,22 +624,22 @@ module Addressable
|
|
623
624
|
|
624
625
|
output.pack("U*")
|
625
626
|
end
|
626
|
-
|
627
|
+
private_class_method :punycode_decode
|
627
628
|
|
628
629
|
def self.punycode_basic?(codepoint)
|
629
630
|
codepoint < 0x80
|
630
631
|
end
|
631
|
-
|
632
|
+
private_class_method :punycode_basic?
|
632
633
|
|
633
634
|
def self.punycode_delimiter?(codepoint)
|
634
635
|
codepoint == PUNYCODE_DELIMITER
|
635
636
|
end
|
636
|
-
|
637
|
+
private_class_method :punycode_delimiter?
|
637
638
|
|
638
639
|
def self.punycode_encode_digit(d)
|
639
640
|
d + 22 + 75 * ((d < 26) ? 1 : 0)
|
640
641
|
end
|
641
|
-
|
642
|
+
private_class_method :punycode_encode_digit
|
642
643
|
|
643
644
|
# Returns the numeric value of a basic codepoint
|
644
645
|
# (for use in representing integers) in the range 0 to
|
@@ -654,7 +655,7 @@ module Addressable
|
|
654
655
|
PUNYCODE_BASE
|
655
656
|
end
|
656
657
|
end
|
657
|
-
|
658
|
+
private_class_method :punycode_decode_digit
|
658
659
|
|
659
660
|
# Bias adaptation method
|
660
661
|
def self.punycode_adapt(delta, numpoints, firsttime)
|
@@ -671,7 +672,7 @@ module Addressable
|
|
671
672
|
|
672
673
|
k + (difference + 1) * delta / (delta + PUNYCODE_SKEW)
|
673
674
|
end
|
674
|
-
|
675
|
+
private_class_method :punycode_adapt
|
675
676
|
end
|
676
677
|
# :startdoc:
|
677
678
|
end
|
data/lib/addressable/idna.rb
CHANGED
data/lib/addressable/template.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# encoding:utf-8
|
2
4
|
#--
|
3
5
|
# Copyright (C) Bob Aman
|
@@ -35,7 +37,7 @@ module Addressable
|
|
35
37
|
Addressable::URI::CharacterClasses::DIGIT + '_'
|
36
38
|
|
37
39
|
var_char =
|
38
|
-
"(
|
40
|
+
"(?>(?:[#{variable_char_class}]|%[a-fA-F0-9][a-fA-F0-9])+)"
|
39
41
|
RESERVED =
|
40
42
|
"(?:[#{anything}]|%[a-fA-F0-9][a-fA-F0-9])"
|
41
43
|
UNRESERVED =
|
@@ -410,7 +412,7 @@ module Addressable
|
|
410
412
|
# match.captures
|
411
413
|
# #=> ["a", ["b", "c"]]
|
412
414
|
def match(uri, processor=nil)
|
413
|
-
uri = Addressable::URI.parse(uri)
|
415
|
+
uri = Addressable::URI.parse(uri) unless uri.is_a?(Addressable::URI)
|
414
416
|
mapping = {}
|
415
417
|
|
416
418
|
# First, we need to process the pattern, and extract the values.
|
@@ -651,40 +653,6 @@ module Addressable
|
|
651
653
|
self.to_regexp.named_captures
|
652
654
|
end
|
653
655
|
|
654
|
-
##
|
655
|
-
# Generates a route result for a given set of parameters.
|
656
|
-
# Should only be used by rack-mount.
|
657
|
-
#
|
658
|
-
# @param params [Hash] The set of parameters used to expand the template.
|
659
|
-
# @param recall [Hash] Default parameters used to expand the template.
|
660
|
-
# @param options [Hash] Either a `:processor` or a `:parameterize` block.
|
661
|
-
#
|
662
|
-
# @api private
|
663
|
-
def generate(params={}, recall={}, options={})
|
664
|
-
merged = recall.merge(params)
|
665
|
-
if options[:processor]
|
666
|
-
processor = options[:processor]
|
667
|
-
elsif options[:parameterize]
|
668
|
-
# TODO: This is sending me into fits trying to shoe-horn this into
|
669
|
-
# the existing API. I think I've got this backwards and processors
|
670
|
-
# should be a set of 4 optional blocks named :validate, :transform,
|
671
|
-
# :match, and :restore. Having to use a singleton here is a huge
|
672
|
-
# code smell.
|
673
|
-
processor = Object.new
|
674
|
-
class <<processor
|
675
|
-
attr_accessor :block
|
676
|
-
def transform(name, value)
|
677
|
-
block.call(name, value)
|
678
|
-
end
|
679
|
-
end
|
680
|
-
processor.block = options[:parameterize]
|
681
|
-
else
|
682
|
-
processor = nil
|
683
|
-
end
|
684
|
-
result = self.expand(merged, processor)
|
685
|
-
result.to_s if result
|
686
|
-
end
|
687
|
-
|
688
656
|
private
|
689
657
|
def ordered_variable_defaults
|
690
658
|
@ordered_variable_defaults ||= begin
|
@@ -728,54 +696,32 @@ module Addressable
|
|
728
696
|
normalize_values = true)
|
729
697
|
_, operator, varlist = *capture.match(EXPRESSION)
|
730
698
|
|
731
|
-
vars = varlist.split(
|
699
|
+
vars = varlist.split(",")
|
732
700
|
|
733
|
-
if
|
701
|
+
if operator == "?"
|
734
702
|
# partial expansion of form style query variables sometimes requires a
|
735
703
|
# slight reordering of the variables to produce a valid url.
|
736
704
|
first_to_expand = vars.find { |varspec|
|
737
705
|
_, name, _ = *varspec.match(VARSPEC)
|
738
|
-
mapping.key? name
|
706
|
+
mapping.key?(name) && !mapping[name].nil?
|
739
707
|
}
|
740
708
|
|
741
709
|
vars = [first_to_expand] + vars.reject {|varspec| varspec == first_to_expand} if first_to_expand
|
742
710
|
end
|
743
711
|
|
744
|
-
vars
|
745
|
-
|
746
|
-
.reduce("") do |acc, (varspec, op)|
|
712
|
+
vars.
|
713
|
+
inject("".dup) do |acc, varspec|
|
747
714
|
_, name, _ = *varspec.match(VARSPEC)
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
##
|
759
|
-
# Creates a lazy Enumerator of the operators that should be used to expand
|
760
|
-
# variables in a varlist starting with `operator`. For example, an operator
|
761
|
-
# `"?"` results in the sequence `"?","&","&"...`
|
762
|
-
#
|
763
|
-
# @param [String] operator from which to generate a sequence
|
764
|
-
#
|
765
|
-
# @return [Enumerator] sequence of operators
|
766
|
-
def operator_sequence(operator)
|
767
|
-
rest_operator = if "?" == operator
|
768
|
-
"&"
|
769
|
-
else
|
770
|
-
operator
|
771
|
-
end
|
772
|
-
head_operator = operator
|
773
|
-
|
774
|
-
Enumerator.new do |y|
|
775
|
-
y << head_operator.to_s
|
776
|
-
while true
|
777
|
-
y << rest_operator.to_s
|
778
|
-
end
|
715
|
+
next_val = if mapping.key? name
|
716
|
+
transform_capture(mapping, "{#{operator}#{varspec}}",
|
717
|
+
processor, normalize_values)
|
718
|
+
else
|
719
|
+
"{#{operator}#{varspec}}"
|
720
|
+
end
|
721
|
+
# If we've already expanded at least one '?' operator with non-empty
|
722
|
+
# value, change to '&'
|
723
|
+
operator = "&" if (operator == "?") && (next_val != "")
|
724
|
+
acc << next_val
|
779
725
|
end
|
780
726
|
end
|
781
727
|
|
@@ -993,15 +939,35 @@ module Addressable
|
|
993
939
|
end
|
994
940
|
end
|
995
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
|
+
|
996
961
|
##
|
997
962
|
# Generates the <tt>Regexp</tt> that parses a template pattern.
|
998
963
|
#
|
999
964
|
# @param [String] pattern The URI template pattern.
|
1000
965
|
# @param [#match] processor The template processor to use.
|
1001
966
|
#
|
1002
|
-
# @return [Regexp]
|
1003
|
-
#
|
1004
|
-
|
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)
|
1005
971
|
# Escape the pattern. The two gsubs restore the escaped curly braces
|
1006
972
|
# back to their original form. Basically, escape everything that isn't
|
1007
973
|
# within an expansion.
|