addressable 2.3.6 → 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 +76 -0
- data/Gemfile +18 -18
- data/README.md +37 -18
- data/Rakefile +8 -11
- data/addressable.gemspec +37 -0
- data/lib/addressable/idna/native.rb +24 -6
- data/lib/addressable/idna/pure.rb +67 -58
- data/lib/addressable/idna.rb +3 -1
- data/lib/addressable/template.rb +126 -33
- data/lib/addressable/uri.rb +416 -211
- data/lib/addressable/version.rb +5 -3
- data/lib/addressable.rb +4 -0
- data/spec/addressable/idna_spec.rb +110 -46
- data/spec/addressable/net_http_compat_spec.rb +4 -2
- data/spec/addressable/security_spec.rb +59 -0
- data/spec/addressable/template_spec.rb +297 -165
- data/spec/addressable/uri_spec.rb +2054 -1329
- data/spec/spec_helper.rb +28 -1
- data/tasks/clobber.rake +2 -0
- data/tasks/gem.rake +22 -16
- data/tasks/git.rake +3 -1
- data/tasks/metrics.rake +2 -0
- data/tasks/profile.rake +72 -0
- data/tasks/rspec.rake +10 -45
- data/tasks/yard.rake +2 -0
- metadata +44 -45
- data/tasks/rubyforge.rake +0 -73
- data/website/index.html +0 -110
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,79 @@
|
|
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
|
+
|
37
|
+
# Addressable 2.5.1
|
38
|
+
- allow unicode normalization to be disabled for URI Template expansion
|
39
|
+
- removed duplicate test
|
40
|
+
|
41
|
+
# Addressable 2.5.0
|
42
|
+
- dropping support for Ruby 1.9
|
43
|
+
- adding support for Ruby 2.4 preview
|
44
|
+
- add support for public suffixes and tld; first runtime dependency
|
45
|
+
- hostname escaping should match RFC; underscores in hostnames no longer escaped
|
46
|
+
- paths beginning with // and missing an authority are now considered invalid
|
47
|
+
- validation now also takes place after setting a path
|
48
|
+
- handle backslashes in authority more like a browser for `heuristic_parse`
|
49
|
+
- unescaped backslashes in host now raise an `InvalidURIError`
|
50
|
+
- `merge!`, `join!`, `omit!` and `normalize!` don't disable deferred validation
|
51
|
+
- `heuristic_parse` now trims whitespace before parsing
|
52
|
+
- host parts longer than 63 bytes will be ignored and not passed to libidn
|
53
|
+
- normalized values always encoded as UTF-8
|
54
|
+
|
55
|
+
# Addressable 2.4.0
|
56
|
+
- support for 1.8.x dropped
|
57
|
+
- double quotes in a host now raises an error
|
58
|
+
- newlines in host will no longer get unescaped during normalization
|
59
|
+
- stricter handling of bogus scheme values
|
60
|
+
- stricter handling of encoded port values
|
61
|
+
- calling `require 'addressable'` will now load both the URI and Template files
|
62
|
+
- assigning to the `hostname` component with an `IPAddr` object is now supported
|
63
|
+
- assigning to the `origin` component is now supported
|
64
|
+
- fixed minor bug where an exception would be thrown for a missing ACE suffix
|
65
|
+
- better partial expansion of URI templates
|
66
|
+
|
67
|
+
# Addressable 2.3.8
|
68
|
+
- fix warnings
|
69
|
+
- update dependency gems
|
70
|
+
- support for 1.8.x officially deprecated
|
71
|
+
|
72
|
+
# Addressable 2.3.7
|
73
|
+
- fix scenario in which invalid URIs don't get an exception until inspected
|
74
|
+
- handle hostnames with two adjacent periods correctly
|
75
|
+
- upgrade of RSpec
|
76
|
+
|
1
77
|
# Addressable 2.3.6
|
2
78
|
- normalization drops empty query string
|
3
79
|
- better handling in template extract for missing values
|
data/Gemfile
CHANGED
@@ -1,28 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
source 'https://rubygems.org'
|
2
4
|
|
3
|
-
|
4
|
-
gem 'launchy'
|
5
|
-
gem 'yard'
|
6
|
-
gem 'redcarpet', :platform => :mri_19
|
7
|
-
gem 'rubyforge'
|
8
|
-
end
|
5
|
+
gemspec(path: __FILE__ == "(eval)" ? ".." : ".")
|
9
6
|
|
10
|
-
group :test
|
11
|
-
gem '
|
12
|
-
gem 'rspec', '
|
13
|
-
gem 'coveralls', :require => false
|
7
|
+
group :test do
|
8
|
+
gem 'rspec', '~> 3.8'
|
9
|
+
gem 'rspec-its', '~> 1.3'
|
14
10
|
end
|
15
11
|
|
16
|
-
|
17
|
-
gem
|
12
|
+
group :coverage do
|
13
|
+
gem "coveralls", "> 0.7", require: false, platforms: :mri
|
14
|
+
gem "simplecov", require: false
|
15
|
+
end
|
18
16
|
|
19
|
-
|
20
|
-
gem '
|
17
|
+
group :development do
|
18
|
+
gem 'launchy', '~> 2.4', '>= 2.4.3'
|
19
|
+
gem 'redcarpet', :platform => :mri_19
|
20
|
+
gem 'yard'
|
21
21
|
end
|
22
22
|
|
23
|
-
|
24
|
-
gem '
|
25
|
-
gem
|
23
|
+
group :test, :development do
|
24
|
+
gem 'memory_profiler'
|
25
|
+
gem "rake", ">= 12.3.3"
|
26
26
|
end
|
27
27
|
|
28
|
-
|
28
|
+
gem "idn-ruby", platform: :mri
|
data/README.md
CHANGED
@@ -1,27 +1,29 @@
|
|
1
1
|
# Addressable
|
2
2
|
|
3
3
|
<dl>
|
4
|
-
<dt>Homepage</dt><dd><a href="
|
4
|
+
<dt>Homepage</dt><dd><a href="https://github.com/sporkmonger/addressable">github.com/sporkmonger/addressable</a></dd>
|
5
5
|
<dt>Author</dt><dd><a href="mailto:bob@sporkmonger.com">Bob Aman</a></dd>
|
6
|
-
<dt>Copyright</dt><dd>Copyright ©
|
6
|
+
<dt>Copyright</dt><dd>Copyright © Bob Aman</dd>
|
7
7
|
<dt>License</dt><dd>Apache 2.0</dd>
|
8
8
|
</dl>
|
9
9
|
|
10
|
-
[![Gem Version](https://
|
11
|
-
[![Build Status](https://
|
12
|
-
[![
|
13
|
-
[![Coverage 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
|
+
[![Test Coverage Status](https://img.shields.io/coveralls/sporkmonger/addressable.svg)][coveralls]
|
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
|
-
[
|
17
|
-
[gemnasium]: https://gemnasium.com/sporkmonger/addressable
|
16
|
+
[actions]: https://github.com/sporkmonger/addressable/actions
|
18
17
|
[coveralls]: https://coveralls.io/r/sporkmonger/addressable
|
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
|
|
@@ -56,7 +58,7 @@ For more details, see [RFC 6570](https://www.rfc-editor.org/rfc/rfc6570.txt).
|
|
56
58
|
|
57
59
|
require "addressable/template"
|
58
60
|
|
59
|
-
template = Addressable::Template.new("http://example.com/{?query*}
|
61
|
+
template = Addressable::Template.new("http://example.com/{?query*}")
|
60
62
|
template.expand({
|
61
63
|
"query" => {
|
62
64
|
'foo' => 'bar',
|
@@ -65,12 +67,12 @@ template.expand({
|
|
65
67
|
})
|
66
68
|
#=> #<Addressable::URI:0xc9d95c URI:http://example.com/?foo=bar&color=red>
|
67
69
|
|
68
|
-
template = Addressable::Template.new("http://example.com/{?one,two,three}
|
70
|
+
template = Addressable::Template.new("http://example.com/{?one,two,three}")
|
69
71
|
template.partial_expand({"one" => "1", "three" => 3}).pattern
|
70
72
|
#=> "http://example.com/?one=1{&two}&three=3"
|
71
73
|
|
72
74
|
template = Addressable::Template.new(
|
73
|
-
"http://{host}{/segments}/{?one,two,bogus}{#fragment}"
|
75
|
+
"http://{host}{/segments*}/{?one,two,bogus}{#fragment}"
|
74
76
|
)
|
75
77
|
uri = Addressable::URI.parse(
|
76
78
|
"http://example.com/a/b/c/?one=1&two=2#foo"
|
@@ -89,14 +91,31 @@ template.extract(uri)
|
|
89
91
|
# Install
|
90
92
|
|
91
93
|
```console
|
92
|
-
$
|
94
|
+
$ gem install addressable
|
93
95
|
```
|
94
96
|
|
95
97
|
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
|
100
|
-
$
|
101
|
-
$
|
101
|
+
$ sudo apt-get install libidn11-dev # Debian/Ubuntu
|
102
|
+
$ brew install libidn # OS X
|
103
|
+
$ gem install idn-ruby
|
104
|
+
```
|
105
|
+
|
106
|
+
# Semantic Versioning
|
107
|
+
|
108
|
+
This project uses [Semantic Versioning](https://semver.org/). You can (and should) specify your
|
109
|
+
dependency using a pessimistic version constraint covering the major and minor
|
110
|
+
values:
|
111
|
+
|
112
|
+
```ruby
|
113
|
+
spec.add_dependency 'addressable', '~> 2.7'
|
114
|
+
```
|
115
|
+
|
116
|
+
If you need a specific bug fix, you can also specify minimum tiny versions
|
117
|
+
without preventing updates to the latest minor release:
|
118
|
+
|
119
|
+
```ruby
|
120
|
+
spec.add_dependency 'addressable', '~> 2.3', '>= 2.3.7'
|
102
121
|
```
|
data/Rakefile
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'rubygems'
|
2
4
|
require 'rake'
|
3
5
|
|
@@ -10,25 +12,20 @@ PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
|
|
10
12
|
|
11
13
|
RELEASE_NAME = "REL #{PKG_VERSION}"
|
12
14
|
|
13
|
-
RUBY_FORGE_PROJECT = PKG_NAME
|
14
|
-
RUBY_FORGE_USER = "sporkmonger"
|
15
|
-
RUBY_FORGE_PATH = "/var/www/gforge-projects/#{RUBY_FORGE_PROJECT}"
|
16
|
-
RUBY_FORGE_URL = "http://#{RUBY_FORGE_PROJECT}.rubyforge.org/"
|
17
|
-
|
18
15
|
PKG_SUMMARY = "URI Implementation"
|
19
16
|
PKG_DESCRIPTION = <<-TEXT
|
20
|
-
Addressable is
|
21
|
-
Ruby's standard library. It
|
22
|
-
|
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.
|
23
20
|
TEXT
|
24
21
|
|
25
22
|
PKG_FILES = FileList[
|
26
23
|
"lib/**/*", "spec/**/*", "vendor/**/*", "data/**/*",
|
27
|
-
"tasks/**/*",
|
24
|
+
"tasks/**/*",
|
28
25
|
"[A-Z]*", "Rakefile"
|
29
|
-
].exclude(/
|
26
|
+
].exclude(/pkg/).exclude(/database\.yml/).
|
27
|
+
exclude(/Gemfile\.lock/).exclude(/[_\.]git$/)
|
30
28
|
|
31
|
-
RCOV_ENABLED = (RUBY_PLATFORM != "java" && RUBY_VERSION =~ /^1\.8/)
|
32
29
|
task :default => "spec"
|
33
30
|
|
34
31
|
WINDOWS = (RUBY_PLATFORM =~ /mswin|win32|mingw|bccwin|cygwin/) rescue false
|
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,6 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# encoding:utf-8
|
2
4
|
#--
|
3
|
-
# Copyright (C)
|
5
|
+
# Copyright (C) Bob Aman
|
4
6
|
#
|
5
7
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
8
|
# you may not use this file except in compliance with the License.
|
@@ -21,23 +23,39 @@ require "idn"
|
|
21
23
|
module Addressable
|
22
24
|
module IDNA
|
23
25
|
def self.punycode_encode(value)
|
24
|
-
IDN::Punycode.encode(value)
|
26
|
+
IDN::Punycode.encode(value.to_s)
|
25
27
|
end
|
26
28
|
|
27
29
|
def self.punycode_decode(value)
|
28
|
-
IDN::Punycode.decode(value)
|
30
|
+
IDN::Punycode.decode(value.to_s)
|
29
31
|
end
|
30
32
|
|
31
33
|
def self.unicode_normalize_kc(value)
|
32
|
-
IDN::Stringprep.nfkc_normalize(value)
|
34
|
+
IDN::Stringprep.nfkc_normalize(value.to_s)
|
33
35
|
end
|
34
36
|
|
35
37
|
def self.to_ascii(value)
|
36
|
-
|
38
|
+
value.to_s.split('.', -1).map do |segment|
|
39
|
+
if segment.size > 0 && segment.size < 64
|
40
|
+
IDN::Idna.toASCII(segment, IDN::Idna::ALLOW_UNASSIGNED)
|
41
|
+
elsif segment.size >= 64
|
42
|
+
segment
|
43
|
+
else
|
44
|
+
''
|
45
|
+
end
|
46
|
+
end.join('.')
|
37
47
|
end
|
38
48
|
|
39
49
|
def self.to_unicode(value)
|
40
|
-
|
50
|
+
value.to_s.split('.', -1).map do |segment|
|
51
|
+
if segment.size > 0 && segment.size < 64
|
52
|
+
IDN::Idna.toUnicode(segment, IDN::Idna::ALLOW_UNASSIGNED)
|
53
|
+
elsif segment.size >= 64
|
54
|
+
segment
|
55
|
+
else
|
56
|
+
''
|
57
|
+
end
|
58
|
+
end.join('.')
|
41
59
|
end
|
42
60
|
end
|
43
61
|
end
|
@@ -1,6 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# encoding:utf-8
|
2
4
|
#--
|
3
|
-
# Copyright (C)
|
5
|
+
# Copyright (C) Bob Aman
|
4
6
|
#
|
5
7
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
8
|
# you may not use this file except in compliance with the License.
|
@@ -64,6 +66,7 @@ module Addressable
|
|
64
66
|
# Converts from a Unicode internationalized domain name to an ASCII
|
65
67
|
# domain name as described in RFC 3490.
|
66
68
|
def self.to_ascii(input)
|
69
|
+
input = input.to_s unless input.is_a?(String)
|
67
70
|
input = input.dup
|
68
71
|
if input.respond_to?(:force_encoding)
|
69
72
|
input.force_encoding(Encoding::ASCII_8BIT)
|
@@ -89,10 +92,16 @@ module Addressable
|
|
89
92
|
# Converts from an ASCII domain name to a Unicode internationalized
|
90
93
|
# domain name as described in RFC 3490.
|
91
94
|
def self.to_unicode(input)
|
95
|
+
input = input.to_s unless input.is_a?(String)
|
92
96
|
parts = input.split('.')
|
93
97
|
parts.map! do |part|
|
94
|
-
if part =~ /^#{ACE_PREFIX}/
|
95
|
-
|
98
|
+
if part =~ /^#{ACE_PREFIX}(.+)/
|
99
|
+
begin
|
100
|
+
punycode_decode(part[/^#{ACE_PREFIX}(.+)/, 1])
|
101
|
+
rescue Addressable::IDNA::PunycodeBadInput
|
102
|
+
# toUnicode is explicitly defined as never-fails by the spec
|
103
|
+
part
|
104
|
+
end
|
96
105
|
else
|
97
106
|
part
|
98
107
|
end
|
@@ -121,11 +130,12 @@ module Addressable
|
|
121
130
|
# The input string.
|
122
131
|
# @return [String] The downcased result.
|
123
132
|
def self.unicode_downcase(input)
|
133
|
+
input = input.to_s unless input.is_a?(String)
|
124
134
|
unpacked = input.unpack("U*")
|
125
135
|
unpacked.map! { |codepoint| lookup_unicode_lowercase(codepoint) }
|
126
136
|
return unpacked.pack("U*")
|
127
137
|
end
|
128
|
-
|
138
|
+
private_class_method :unicode_downcase
|
129
139
|
|
130
140
|
def self.unicode_compose(unpacked)
|
131
141
|
unpacked_result = []
|
@@ -138,22 +148,19 @@ module Addressable
|
|
138
148
|
starter_cc = 256 if starter_cc != 0
|
139
149
|
for i in 1...length
|
140
150
|
ch = unpacked[i]
|
141
|
-
cc = lookup_unicode_combining_class(ch)
|
142
151
|
|
143
152
|
if (starter_cc == 0 &&
|
144
153
|
(composite = unicode_compose_pair(starter, ch)) != nil)
|
145
154
|
starter = composite
|
146
|
-
startercc = lookup_unicode_combining_class(composite)
|
147
155
|
else
|
148
156
|
unpacked_result << starter
|
149
157
|
starter = ch
|
150
|
-
startercc = cc
|
151
158
|
end
|
152
159
|
end
|
153
160
|
unpacked_result << starter
|
154
161
|
return unpacked_result
|
155
162
|
end
|
156
|
-
|
163
|
+
private_class_method :unicode_compose
|
157
164
|
|
158
165
|
def self.unicode_compose_pair(ch_one, ch_two)
|
159
166
|
if ch_one >= HANGUL_LBASE && ch_one < HANGUL_LBASE + HANGUL_LCOUNT &&
|
@@ -171,44 +178,45 @@ module Addressable
|
|
171
178
|
end
|
172
179
|
|
173
180
|
p = []
|
174
|
-
ucs4_to_utf8 = lambda do |ch|
|
175
|
-
# For some reason, rcov likes to drop BUS errors here.
|
176
|
-
if ch < 128
|
177
|
-
p << ch
|
178
|
-
elsif ch < 2048
|
179
|
-
p << (ch >> 6 | 192)
|
180
|
-
p << (ch & 63 | 128)
|
181
|
-
elsif ch < 0x10000
|
182
|
-
p << (ch >> 12 | 224)
|
183
|
-
p << (ch >> 6 & 63 | 128)
|
184
|
-
p << (ch & 63 | 128)
|
185
|
-
elsif ch < 0x200000
|
186
|
-
p << (ch >> 18 | 240)
|
187
|
-
p << (ch >> 12 & 63 | 128)
|
188
|
-
p << (ch >> 6 & 63 | 128)
|
189
|
-
p << (ch & 63 | 128)
|
190
|
-
elsif ch < 0x4000000
|
191
|
-
p << (ch >> 24 | 248)
|
192
|
-
p << (ch >> 18 & 63 | 128)
|
193
|
-
p << (ch >> 12 & 63 | 128)
|
194
|
-
p << (ch >> 6 & 63 | 128)
|
195
|
-
p << (ch & 63 | 128)
|
196
|
-
elsif ch < 0x80000000
|
197
|
-
p << (ch >> 30 | 252)
|
198
|
-
p << (ch >> 24 & 63 | 128)
|
199
|
-
p << (ch >> 18 & 63 | 128)
|
200
|
-
p << (ch >> 12 & 63 | 128)
|
201
|
-
p << (ch >> 6 & 63 | 128)
|
202
|
-
p << (ch & 63 | 128)
|
203
|
-
end
|
204
|
-
end
|
205
181
|
|
206
|
-
ucs4_to_utf8
|
207
|
-
ucs4_to_utf8
|
182
|
+
ucs4_to_utf8(ch_one, p)
|
183
|
+
ucs4_to_utf8(ch_two, p)
|
208
184
|
|
209
185
|
return lookup_unicode_composition(p)
|
210
186
|
end
|
211
|
-
|
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
|
212
220
|
|
213
221
|
def self.unicode_sort_canonical(unpacked)
|
214
222
|
unpacked = unpacked.dup
|
@@ -232,7 +240,7 @@ module Addressable
|
|
232
240
|
end
|
233
241
|
return unpacked
|
234
242
|
end
|
235
|
-
|
243
|
+
private_class_method :unicode_sort_canonical
|
236
244
|
|
237
245
|
def self.unicode_decompose(unpacked)
|
238
246
|
unpacked_result = []
|
@@ -253,7 +261,7 @@ module Addressable
|
|
253
261
|
end
|
254
262
|
return unpacked_result
|
255
263
|
end
|
256
|
-
|
264
|
+
private_class_method :unicode_decompose
|
257
265
|
|
258
266
|
def self.unicode_decompose_hangul(codepoint)
|
259
267
|
sindex = codepoint - HANGUL_SBASE;
|
@@ -270,7 +278,7 @@ module Addressable
|
|
270
278
|
end
|
271
279
|
return l, v, t
|
272
280
|
end
|
273
|
-
|
281
|
+
private_class_method :unicode_decompose_hangul
|
274
282
|
|
275
283
|
def self.lookup_unicode_combining_class(codepoint)
|
276
284
|
codepoint_data = UNICODE_DATA[codepoint]
|
@@ -278,14 +286,14 @@ module Addressable
|
|
278
286
|
(codepoint_data[UNICODE_DATA_COMBINING_CLASS] || 0) :
|
279
287
|
0)
|
280
288
|
end
|
281
|
-
|
289
|
+
private_class_method :lookup_unicode_combining_class
|
282
290
|
|
283
291
|
def self.lookup_unicode_compatibility(codepoint)
|
284
292
|
codepoint_data = UNICODE_DATA[codepoint]
|
285
293
|
(codepoint_data ?
|
286
294
|
codepoint_data[UNICODE_DATA_COMPATIBILITY] : nil)
|
287
295
|
end
|
288
|
-
|
296
|
+
private_class_method :lookup_unicode_compatibility
|
289
297
|
|
290
298
|
def self.lookup_unicode_lowercase(codepoint)
|
291
299
|
codepoint_data = UNICODE_DATA[codepoint]
|
@@ -293,12 +301,12 @@ module Addressable
|
|
293
301
|
(codepoint_data[UNICODE_DATA_LOWERCASE] || codepoint) :
|
294
302
|
codepoint)
|
295
303
|
end
|
296
|
-
|
304
|
+
private_class_method :lookup_unicode_lowercase
|
297
305
|
|
298
306
|
def self.lookup_unicode_composition(unpacked)
|
299
307
|
return COMPOSITION_TABLE[unpacked]
|
300
308
|
end
|
301
|
-
|
309
|
+
private_class_method :lookup_unicode_composition
|
302
310
|
|
303
311
|
HANGUL_SBASE = 0xac00
|
304
312
|
HANGUL_LBASE = 0x1100
|
@@ -335,7 +343,7 @@ module Addressable
|
|
335
343
|
end
|
336
344
|
|
337
345
|
COMPOSITION_TABLE = {}
|
338
|
-
|
346
|
+
UNICODE_DATA.each do |codepoint, data|
|
339
347
|
canonical = data[UNICODE_DATA_CANONICAL]
|
340
348
|
exclusion = data[UNICODE_DATA_EXCLUSION]
|
341
349
|
|
@@ -376,6 +384,7 @@ module Addressable
|
|
376
384
|
class PunycodeOverflow < StandardError; end
|
377
385
|
|
378
386
|
def self.punycode_encode(unicode)
|
387
|
+
unicode = unicode.to_s unless unicode.is_a?(String)
|
379
388
|
input = unicode.unpack("U*")
|
380
389
|
output = [0] * (ACE_MAX_LENGTH + 1)
|
381
390
|
input_length = input.size
|
@@ -484,7 +493,7 @@ module Addressable
|
|
484
493
|
outlen.times do |j|
|
485
494
|
c = output[j]
|
486
495
|
unless c >= 0 && c <= 127
|
487
|
-
raise
|
496
|
+
raise StandardError, "Invalid output char."
|
488
497
|
end
|
489
498
|
unless PUNYCODE_PRINT_ASCII[c]
|
490
499
|
raise PunycodeBadInput, "Input is invalid."
|
@@ -493,7 +502,7 @@ module Addressable
|
|
493
502
|
|
494
503
|
output[0..outlen].map { |x| x.chr }.join("").sub(/\0+\z/, "")
|
495
504
|
end
|
496
|
-
|
505
|
+
private_class_method :punycode_encode
|
497
506
|
|
498
507
|
def self.punycode_decode(punycode)
|
499
508
|
input = []
|
@@ -615,22 +624,22 @@ module Addressable
|
|
615
624
|
|
616
625
|
output.pack("U*")
|
617
626
|
end
|
618
|
-
|
627
|
+
private_class_method :punycode_decode
|
619
628
|
|
620
629
|
def self.punycode_basic?(codepoint)
|
621
630
|
codepoint < 0x80
|
622
631
|
end
|
623
|
-
|
632
|
+
private_class_method :punycode_basic?
|
624
633
|
|
625
634
|
def self.punycode_delimiter?(codepoint)
|
626
635
|
codepoint == PUNYCODE_DELIMITER
|
627
636
|
end
|
628
|
-
|
637
|
+
private_class_method :punycode_delimiter?
|
629
638
|
|
630
639
|
def self.punycode_encode_digit(d)
|
631
640
|
d + 22 + 75 * ((d < 26) ? 1 : 0)
|
632
641
|
end
|
633
|
-
|
642
|
+
private_class_method :punycode_encode_digit
|
634
643
|
|
635
644
|
# Returns the numeric value of a basic codepoint
|
636
645
|
# (for use in representing integers) in the range 0 to
|
@@ -646,7 +655,7 @@ module Addressable
|
|
646
655
|
PUNYCODE_BASE
|
647
656
|
end
|
648
657
|
end
|
649
|
-
|
658
|
+
private_class_method :punycode_decode_digit
|
650
659
|
|
651
660
|
# Bias adaptation method
|
652
661
|
def self.punycode_adapt(delta, numpoints, firsttime)
|
@@ -663,7 +672,7 @@ module Addressable
|
|
663
672
|
|
664
673
|
k + (difference + 1) * delta / (delta + PUNYCODE_SKEW)
|
665
674
|
end
|
666
|
-
|
675
|
+
private_class_method :punycode_adapt
|
667
676
|
end
|
668
677
|
# :startdoc:
|
669
678
|
end
|
data/lib/addressable/idna.rb
CHANGED