itu-e164 0.1.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 +7 -0
- data/CHANGELOG.md +11 -0
- data/LICENSE.txt +22 -0
- data/README.md +141 -0
- data/SOURCES.md +46 -0
- data/lib/itu/e164/checker.rb +111 -0
- data/lib/itu/e164/data/v2026.rb +43 -0
- data/lib/itu/e164/invalid_number.rb +14 -0
- data/lib/itu/e164/result.rb +46 -0
- data/lib/itu/e164/validation_error.rb +11 -0
- data/lib/itu/e164/version.rb +7 -0
- data/lib/itu/e164.rb +29 -0
- metadata +105 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: '0469c614c83a4f49532e5f80645b5a44bf33b873c2bb7332852fd909ef421882'
|
|
4
|
+
data.tar.gz: 4ec2f4e91a83688670affd7d08dbe77908d615304783d286018ffe6bac43ad39
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: a81387d155baa30b4b8878dc7ab5cd9748305e3e102f90409d614b6030f71b0a3b08aa2ac3caedd477925a3c9331970991209dfca84c45fc2708c3bcc28a62f1
|
|
7
|
+
data.tar.gz: b729eb1db3f931748581ba1d24962d2b9abbdd1e8317fa9a3c843ba50073ff1dae4a9a3249a89d90fdbdc008c7344289c2b149759011706667f08fbefdfd1954
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0
|
|
4
|
+
|
|
5
|
+
- Add strict canonical validation for the geographic-area structure in
|
|
6
|
+
Recommendation ITU-T E.164 (02/2026).
|
|
7
|
+
- Add a dated ITU geographic country-code assignment snapshot.
|
|
8
|
+
- Return immutable, structured results suitable for existing validation layers.
|
|
9
|
+
- Recognize assigned non-geographic E.164 country codes and reject them with an
|
|
10
|
+
explicit profile-mismatch error.
|
|
11
|
+
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Olisti contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
data/README.md
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# itu-e164
|
|
2
|
+
|
|
3
|
+
`itu-e164` is a dependency-free Ruby utility for strict, auditable validation of
|
|
4
|
+
canonical geographic-area numbers against Recommendation ITU-T E.164 (02/2026).
|
|
5
|
+
It is deliberately not a Rails validator and does not contact a carrier.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
Add the gem to your bundle:
|
|
10
|
+
|
|
11
|
+
```ruby
|
|
12
|
+
gem "itu-e164"
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Then run `bundle install`.
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
```ruby
|
|
20
|
+
require "itu/e164"
|
|
21
|
+
|
|
22
|
+
result = ITU::E164.check("+393331234567")
|
|
23
|
+
|
|
24
|
+
result.conformant? # => true
|
|
25
|
+
result.country_code # => "39"
|
|
26
|
+
result.national_number # => "3331234567"
|
|
27
|
+
result.category # => :geographic
|
|
28
|
+
result.standard_version # => "02/2026"
|
|
29
|
+
result.dataset_version # => "itu-t-e164-2026-07-15"
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
For a boolean:
|
|
33
|
+
|
|
34
|
+
```ruby
|
|
35
|
+
ITU::E164.conformant?("+393331234567") # => true
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
For exception-based control flow:
|
|
39
|
+
|
|
40
|
+
```ruby
|
|
41
|
+
result = ITU::E164.check!("+393331234567")
|
|
42
|
+
|
|
43
|
+
begin
|
|
44
|
+
ITU::E164.check!("0039 333 123 4567")
|
|
45
|
+
rescue ITU::E164::InvalidNumber => error
|
|
46
|
+
error.result.error_codes # => [:invalid_representation]
|
|
47
|
+
end
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The accepted representation is intentionally strict: a `String` containing `+`
|
|
51
|
+
followed by ASCII decimal digits. Spaces, punctuation, `00`, URI parameters, and
|
|
52
|
+
extensions are rejected. Normalize user input before this boundary and store
|
|
53
|
+
extensions separately.
|
|
54
|
+
|
|
55
|
+
## Existing validation layers
|
|
56
|
+
|
|
57
|
+
The result is designed to be consumed without an Active Record dependency:
|
|
58
|
+
|
|
59
|
+
```ruby
|
|
60
|
+
result = ITU::E164.check(value)
|
|
61
|
+
|
|
62
|
+
unless result.conformant?
|
|
63
|
+
errors.add(:phone_number, result.errors.map(&:message).join(", "))
|
|
64
|
+
end
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
With Twilio Verify, use this gem before sending a verification:
|
|
68
|
+
|
|
69
|
+
```ruby
|
|
70
|
+
result = ITU::E164.check(candidate)
|
|
71
|
+
return validation_failure(result.errors) unless result.conformant?
|
|
72
|
+
|
|
73
|
+
twilio_verify(candidate)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The responsibilities stay separate:
|
|
77
|
+
|
|
78
|
+
- `itu-e164` checks canonical representation, E.164 length and field structure,
|
|
79
|
+
and the assigned geographic country-code snapshot.
|
|
80
|
+
- Twilio Verify checks whether a user controls a reachable endpoint.
|
|
81
|
+
|
|
82
|
+
## Exact scope
|
|
83
|
+
|
|
84
|
+
For `profile: :geographic` (the only profile in 0.1), a conformant result means:
|
|
85
|
+
|
|
86
|
+
- the input is canonical leading-plus notation;
|
|
87
|
+
- the E.164 digit sequence contains at most 15 digits;
|
|
88
|
+
- it starts with an assigned one-, two-, or three-digit geographic country code;
|
|
89
|
+
- at least one digit remains as the national (significant) number.
|
|
90
|
+
|
|
91
|
+
This is the complete E.164-level structure for the geographic category. E.164
|
|
92
|
+
leaves national destination-code and subscriber-number details to national
|
|
93
|
+
numbering authorities.
|
|
94
|
+
|
|
95
|
+
Accordingly, this gem does **not** claim that:
|
|
96
|
+
|
|
97
|
+
- the national number range is allocated or currently active;
|
|
98
|
+
- the number is mobile, SMS-capable, reachable, or owned by a user;
|
|
99
|
+
- a national trunk prefix was correctly removed;
|
|
100
|
+
- one of E.164's seven non-geographic categories satisfies its service-specific
|
|
101
|
+
numbering recommendation.
|
|
102
|
+
|
|
103
|
+
Assigned non-geographic country codes are recognized, but fail the geographic
|
|
104
|
+
profile with `:profile_mismatch`. Spare or unknown codes fail with
|
|
105
|
+
`:country_code_unassigned`.
|
|
106
|
+
|
|
107
|
+
## Results and errors
|
|
108
|
+
|
|
109
|
+
`ITU::E164.check` always returns an immutable `ITU::E164::Result`. Invalid input
|
|
110
|
+
has one or more immutable `ITU::E164::ValidationError` values:
|
|
111
|
+
|
|
112
|
+
```ruby
|
|
113
|
+
result = ITU::E164.check("+80012345678")
|
|
114
|
+
|
|
115
|
+
result.conformant? # => false
|
|
116
|
+
result.category # => :global_service
|
|
117
|
+
result.error_codes # => [:profile_mismatch]
|
|
118
|
+
result.to_h
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Current error codes are:
|
|
122
|
+
|
|
123
|
+
- `:not_a_string`
|
|
124
|
+
- `:invalid_representation`
|
|
125
|
+
- `:too_long`
|
|
126
|
+
- `:country_code_unassigned`
|
|
127
|
+
- `:missing_national_number`
|
|
128
|
+
- `:profile_mismatch`
|
|
129
|
+
|
|
130
|
+
Branch on error codes, not English messages.
|
|
131
|
+
|
|
132
|
+
## Versioning and updates
|
|
133
|
+
|
|
134
|
+
The recommendation version and assignment dataset are exposed separately because
|
|
135
|
+
a stable numbering structure can coexist with changing assignments. See
|
|
136
|
+
[SOURCES.md](SOURCES.md) for provenance and the update procedure.
|
|
137
|
+
|
|
138
|
+
## License
|
|
139
|
+
|
|
140
|
+
The gem is available under the MIT License.
|
|
141
|
+
|
data/SOURCES.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Normative basis and dataset provenance
|
|
2
|
+
|
|
3
|
+
`itu-e164` separates two things that evolve independently:
|
|
4
|
+
|
|
5
|
+
1. The numbering-plan structure comes from Recommendation ITU-T E.164 (02/2026).
|
|
6
|
+
2. Country-code assignment status comes from ITU-T service publications and is
|
|
7
|
+
represented by a dated data snapshot.
|
|
8
|
+
|
|
9
|
+
## Structure
|
|
10
|
+
|
|
11
|
+
- [Recommendation ITU-T E.164 (02/2026)](https://www.itu.int/rec/T-REC-E.164-202602-I/en)
|
|
12
|
+
- [Recommendation ITU-T E.164.1 (02/2026)](https://www.itu.int/rec/T-REC-E.164.1-202602-I/en)
|
|
13
|
+
- [Recommendation ITU-T E.123](https://www.itu.int/rec/T-REC-E.123/en), for the
|
|
14
|
+
leading-plus international notation accepted by this library
|
|
15
|
+
|
|
16
|
+
The implemented geographic profile follows these structural constraints:
|
|
17
|
+
|
|
18
|
+
- an international E.164 number contains decimal digits and has at most 15 digits;
|
|
19
|
+
- a geographic country code has one, two, or three digits;
|
|
20
|
+
- the national (significant) number occupies the remaining digits;
|
|
21
|
+
- international and national prefixes are not part of the number.
|
|
22
|
+
|
|
23
|
+
## Assignment snapshot
|
|
24
|
+
|
|
25
|
+
- Dataset identifier: `itu-t-e164-2026-07-15`
|
|
26
|
+
- Snapshot date: 15 July 2026
|
|
27
|
+
- [List of Recommendation ITU-T E.164 assigned country codes, baseline at
|
|
28
|
+
15 December 2016](https://www.itu.int/dms_pub/itu-t/opb/sp/t-sp-e.164d-2016-pdf-e.pdf)
|
|
29
|
+
- Numbered amendments through [ITU Operational Bulletin No. 1344,
|
|
30
|
+
15 July 2026](https://www.itu.int/pub/T-SP-OB.1344-2026)
|
|
31
|
+
- [ITU National Numbering Plans index](https://www.itu.int/oth/T0202.aspx?lang=en&parent=T0202),
|
|
32
|
+
cross-checked on 28 July 2026
|
|
33
|
+
|
|
34
|
+
The constants are derived assignment facts, not reproduced recommendation text
|
|
35
|
+
or diagrams.
|
|
36
|
+
|
|
37
|
+
## Updating the snapshot
|
|
38
|
+
|
|
39
|
+
Review each ITU Operational Bulletin after No. 1344 for amendments to the assigned
|
|
40
|
+
country-code list. Apply additions, returns, re-designations, and status changes to
|
|
41
|
+
`lib/itu/e164/data/v2026.rb`, advance `DATASET_VERSION`, and add regression tests
|
|
42
|
+
for every changed code.
|
|
43
|
+
|
|
44
|
+
Do not infer assignment status from a calling library or a carrier API. Assignment
|
|
45
|
+
status is an ITU-controlled dataset.
|
|
46
|
+
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "data/v2026"
|
|
4
|
+
require_relative "result"
|
|
5
|
+
require_relative "validation_error"
|
|
6
|
+
|
|
7
|
+
module ITU
|
|
8
|
+
module E164
|
|
9
|
+
class Checker
|
|
10
|
+
ASCII_INTERNATIONAL_NUMBER = /\A\+[0-9]+\z/
|
|
11
|
+
MAXIMUM_DIGITS = 15
|
|
12
|
+
SUPPORTED_PROFILES = [:geographic].freeze
|
|
13
|
+
ERROR_MESSAGES = {
|
|
14
|
+
not_a_string: "must be a String",
|
|
15
|
+
invalid_representation: "must be + followed by ASCII decimal digits",
|
|
16
|
+
too_long: "must contain at most 15 digits after +",
|
|
17
|
+
country_code_unassigned: "must start with an assigned geographic country code",
|
|
18
|
+
missing_national_number: "must include a national significant number after the country code",
|
|
19
|
+
profile_mismatch: "belongs to a non-geographic E.164 category"
|
|
20
|
+
}.freeze
|
|
21
|
+
|
|
22
|
+
def initialize(profile:)
|
|
23
|
+
unless SUPPORTED_PROFILES.include?(profile)
|
|
24
|
+
raise ArgumentError, "unsupported profile #{profile.inspect}; expected :geographic"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
@profile = profile
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def call(input)
|
|
31
|
+
return result(input:, errors: [error(:not_a_string)]) unless input.is_a?(String)
|
|
32
|
+
|
|
33
|
+
stable_input = immutable(input)
|
|
34
|
+
unless ASCII_INTERNATIONAL_NUMBER.match?(stable_input)
|
|
35
|
+
return result(input: stable_input, errors: [error(:invalid_representation)])
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
digits = immutable(stable_input.delete_prefix("+"))
|
|
39
|
+
errors = []
|
|
40
|
+
errors << error(:too_long) if digits.length > MAXIMUM_DIGITS
|
|
41
|
+
|
|
42
|
+
category, country_code = resolve_country_code(digits)
|
|
43
|
+
national_number = resolve_national_number(digits, category, country_code)
|
|
44
|
+
|
|
45
|
+
if category.nil?
|
|
46
|
+
errors << error(:country_code_unassigned)
|
|
47
|
+
elsif category != @profile
|
|
48
|
+
errors << error(:profile_mismatch)
|
|
49
|
+
elsif national_number.empty?
|
|
50
|
+
errors << error(:missing_national_number)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
result(
|
|
54
|
+
input: stable_input,
|
|
55
|
+
digits:,
|
|
56
|
+
canonical: errors.empty? ? stable_input : nil,
|
|
57
|
+
category:,
|
|
58
|
+
country_code:,
|
|
59
|
+
national_number:,
|
|
60
|
+
errors:
|
|
61
|
+
)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
private
|
|
65
|
+
|
|
66
|
+
def resolve_country_code(digits)
|
|
67
|
+
geographic_code = Data::V2026::GEOGRAPHIC_COUNTRY_CODES.find do |code|
|
|
68
|
+
digits.start_with?(code)
|
|
69
|
+
end
|
|
70
|
+
return [:geographic, immutable(geographic_code)] if geographic_code
|
|
71
|
+
|
|
72
|
+
non_geographic_code, category = Data::V2026::NON_GEOGRAPHIC_COUNTRY_CODES.find do |code, _|
|
|
73
|
+
digits.start_with?(code)
|
|
74
|
+
end
|
|
75
|
+
return [category, immutable(non_geographic_code)] if non_geographic_code
|
|
76
|
+
|
|
77
|
+
[nil, nil]
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def resolve_national_number(digits, category, country_code)
|
|
81
|
+
return nil unless category == :geographic
|
|
82
|
+
|
|
83
|
+
immutable(digits.delete_prefix(country_code))
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def result(input:, errors:, **attributes)
|
|
87
|
+
defaults = {
|
|
88
|
+
input:,
|
|
89
|
+
profile: @profile,
|
|
90
|
+
standard_version: E164::STANDARD_VERSION,
|
|
91
|
+
dataset_version: Data::V2026::DATASET_VERSION,
|
|
92
|
+
digits: nil,
|
|
93
|
+
canonical: nil,
|
|
94
|
+
category: nil,
|
|
95
|
+
country_code: nil,
|
|
96
|
+
national_number: nil
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
Result.new(**defaults, **attributes, errors: errors.freeze)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def immutable(value)
|
|
103
|
+
value&.dup&.freeze
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def error(code)
|
|
107
|
+
ValidationError.new(code:, message: ERROR_MESSAGES.fetch(code))
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ITU
|
|
4
|
+
module E164
|
|
5
|
+
module Data
|
|
6
|
+
module V2026
|
|
7
|
+
DATASET_VERSION = "itu-t-e164-2026-07-15"
|
|
8
|
+
|
|
9
|
+
GEOGRAPHIC_COUNTRY_CODES = %w[
|
|
10
|
+
1 7
|
|
11
|
+
20 27 30 31 32 33 34 36 39 40 41 43 44 45 46 47 48 49
|
|
12
|
+
51 52 53 54 55 56 57 58 60 61 62 63 64 65 66 81 82 84 86
|
|
13
|
+
90 91 92 93 94 95 98
|
|
14
|
+
211 212 213 216 218 220 221 222 223 224 225 226 227 228 229
|
|
15
|
+
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
|
|
16
|
+
245 246 247 248 249 250 251 252 253 254 255 256 257 258 260
|
|
17
|
+
261 262 263 264 265 266 267 268 269 290 291 297 298 299
|
|
18
|
+
350 351 352 353 354 355 356 357 358 359 370 371 372 373 374
|
|
19
|
+
375 376 377 378 380 381 382 383 385 386 387 389
|
|
20
|
+
420 421 423
|
|
21
|
+
500 501 502 503 504 505 506 507 508 509
|
|
22
|
+
590 591 592 593 594 595 596 597 598 599
|
|
23
|
+
670 672 673 674 675 676 677 678 679 680 681 682 683 685 686
|
|
24
|
+
687 688 689 690 691 692
|
|
25
|
+
850 852 853 855 856 880 886
|
|
26
|
+
960 961 962 963 964 965 966 967 968 970 971 972 973 974 975
|
|
27
|
+
976 977 992 993 994 995 996 998
|
|
28
|
+
].freeze
|
|
29
|
+
|
|
30
|
+
NON_GEOGRAPHIC_COUNTRY_CODES = {
|
|
31
|
+
"800" => :global_service,
|
|
32
|
+
"808" => :global_service,
|
|
33
|
+
"870" => :other_global_service,
|
|
34
|
+
"881" => :global_satellite_service,
|
|
35
|
+
"882" => :network,
|
|
36
|
+
"883" => :iot_m2m,
|
|
37
|
+
"979" => :global_service,
|
|
38
|
+
"991" => :trial
|
|
39
|
+
}.freeze
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ITU
|
|
4
|
+
module E164
|
|
5
|
+
Result = ::Data.define(
|
|
6
|
+
:input,
|
|
7
|
+
:profile,
|
|
8
|
+
:standard_version,
|
|
9
|
+
:dataset_version,
|
|
10
|
+
:digits,
|
|
11
|
+
:canonical,
|
|
12
|
+
:category,
|
|
13
|
+
:country_code,
|
|
14
|
+
:national_number,
|
|
15
|
+
:errors
|
|
16
|
+
) do
|
|
17
|
+
def conformant?
|
|
18
|
+
errors.empty?
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def failure?
|
|
22
|
+
!conformant?
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def error_codes
|
|
26
|
+
errors.map(&:code).freeze
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def to_h
|
|
30
|
+
{
|
|
31
|
+
input:,
|
|
32
|
+
profile:,
|
|
33
|
+
standard_version:,
|
|
34
|
+
dataset_version:,
|
|
35
|
+
digits:,
|
|
36
|
+
canonical:,
|
|
37
|
+
category:,
|
|
38
|
+
country_code:,
|
|
39
|
+
national_number:,
|
|
40
|
+
conformant: conformant?,
|
|
41
|
+
errors: errors.map(&:to_h)
|
|
42
|
+
}
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
data/lib/itu/e164.rb
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "e164/checker"
|
|
4
|
+
require_relative "e164/invalid_number"
|
|
5
|
+
require_relative "e164/version"
|
|
6
|
+
|
|
7
|
+
module ITU
|
|
8
|
+
module E164
|
|
9
|
+
STANDARD_VERSION = "02/2026"
|
|
10
|
+
PROFILE = :geographic
|
|
11
|
+
|
|
12
|
+
module_function
|
|
13
|
+
|
|
14
|
+
def check(input, profile: PROFILE)
|
|
15
|
+
Checker.new(profile:).call(input)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def check!(input, profile: PROFILE)
|
|
19
|
+
result = check(input, profile:)
|
|
20
|
+
raise InvalidNumber, result unless result.conformant?
|
|
21
|
+
|
|
22
|
+
result
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def conformant?(input, profile: PROFILE)
|
|
26
|
+
check(input, profile:).conformant?
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: itu-e164
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Maurizio De Magnis
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-07-28 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: rake
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '13.2'
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '13.2'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: rspec
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '3.13'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '3.13'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: rubocop
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '1.64'
|
|
48
|
+
- - "<"
|
|
49
|
+
- !ruby/object:Gem::Version
|
|
50
|
+
version: '2'
|
|
51
|
+
type: :development
|
|
52
|
+
prerelease: false
|
|
53
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
54
|
+
requirements:
|
|
55
|
+
- - ">="
|
|
56
|
+
- !ruby/object:Gem::Version
|
|
57
|
+
version: '1.64'
|
|
58
|
+
- - "<"
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '2'
|
|
61
|
+
description: |
|
|
62
|
+
A dependency-free Ruby utility that checks canonical geographic-area numbers
|
|
63
|
+
against Recommendation ITU-T E.164 (02/2026) and a dated ITU country-code
|
|
64
|
+
assignment snapshot.
|
|
65
|
+
email: root@olisti.co
|
|
66
|
+
executables: []
|
|
67
|
+
extensions: []
|
|
68
|
+
extra_rdoc_files: []
|
|
69
|
+
files:
|
|
70
|
+
- CHANGELOG.md
|
|
71
|
+
- LICENSE.txt
|
|
72
|
+
- README.md
|
|
73
|
+
- SOURCES.md
|
|
74
|
+
- lib/itu/e164.rb
|
|
75
|
+
- lib/itu/e164/checker.rb
|
|
76
|
+
- lib/itu/e164/data/v2026.rb
|
|
77
|
+
- lib/itu/e164/invalid_number.rb
|
|
78
|
+
- lib/itu/e164/result.rb
|
|
79
|
+
- lib/itu/e164/validation_error.rb
|
|
80
|
+
- lib/itu/e164/version.rb
|
|
81
|
+
homepage: https://source.olisti.co/olisti.co/itu-e164
|
|
82
|
+
licenses:
|
|
83
|
+
- MIT
|
|
84
|
+
metadata:
|
|
85
|
+
rubygems_mfa_required: 'true'
|
|
86
|
+
post_install_message:
|
|
87
|
+
rdoc_options: []
|
|
88
|
+
require_paths:
|
|
89
|
+
- lib
|
|
90
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
91
|
+
requirements:
|
|
92
|
+
- - ">="
|
|
93
|
+
- !ruby/object:Gem::Version
|
|
94
|
+
version: '3.2'
|
|
95
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
96
|
+
requirements:
|
|
97
|
+
- - ">="
|
|
98
|
+
- !ruby/object:Gem::Version
|
|
99
|
+
version: '0'
|
|
100
|
+
requirements: []
|
|
101
|
+
rubygems_version: 3.4.10
|
|
102
|
+
signing_key:
|
|
103
|
+
specification_version: 4
|
|
104
|
+
summary: Strict ITU-T E.164 (02/2026) geographic-number conformance for Ruby
|
|
105
|
+
test_files: []
|