pico_phone 0.5.0 → 0.6.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 +4 -4
- data/ext/pico_phone/pico_phone.cpp +143 -2
- data/lib/pico_phone/phone_number.rb +54 -0
- data/lib/pico_phone/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bac62c280ce5ac633b95536c04c0bc7bb0672beaa0a44928ba128b367c845b93
|
|
4
|
+
data.tar.gz: b567f397b99d3a93b9309c19c6797eb6b96a4db3e7c3860d2c5e9d0a9033fc41
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 17a4f165dc820b929d587401ab31c895701d74d4802cfb414e1c044345e7e733b787a7956e02e5dd55228ab83f9bbf917c575b0550f62597120577c5bcc2df05
|
|
7
|
+
data.tar.gz: 4aa9e0e6507d71f14fcaf11242d2a0b666707eebb60afffbf85988414a771bc6596d13638cbe8e9ea5ffb66e0bd08720d1064e3fa799683eb87c1d34340f3724
|
|
@@ -14,13 +14,18 @@
|
|
|
14
14
|
// any ICU header is reachable.
|
|
15
15
|
#undef UChar
|
|
16
16
|
#include <phonenumbers/geocoding/phonenumber_offline_geocoder.h>
|
|
17
|
+
#include <phonenumbers/phonenumbermatcher.h>
|
|
18
|
+
#include <phonenumbers/phonenumbermatch.h>
|
|
17
19
|
#include "carrier_mapper.h"
|
|
18
20
|
#include "timezone_mapper.h"
|
|
19
21
|
|
|
22
|
+
#include <climits>
|
|
23
|
+
|
|
20
24
|
using namespace Rice;
|
|
21
25
|
using namespace i18n::phonenumbers;
|
|
22
26
|
|
|
23
27
|
static VALUE rb_cPhoneNumber;
|
|
28
|
+
static VALUE rb_cPhoneNumberMatch;
|
|
24
29
|
static VALUE rb_mPicoPhone;
|
|
25
30
|
|
|
26
31
|
size_t phone_number_size(const void *data) { return sizeof(PhoneNumber); }
|
|
@@ -195,6 +200,112 @@ Object pico_phone_is_alpha_number(Object self, String str) {
|
|
|
195
200
|
return phone_util.IsAlphaNumber(str.c_str()) ? Qtrue : Qfalse;
|
|
196
201
|
}
|
|
197
202
|
|
|
203
|
+
int pico_phone_country_calling_code(Object self, String region) {
|
|
204
|
+
const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
|
|
205
|
+
return phone_util.GetCountryCodeForRegion(std::string(region.c_str()));
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
static VALUE match_type_to_symbol(PhoneNumberUtil::MatchType match_type) {
|
|
209
|
+
switch (match_type) {
|
|
210
|
+
case PhoneNumberUtil::INVALID_NUMBER: return rb_id2sym(rb_intern("invalid_number"));
|
|
211
|
+
case PhoneNumberUtil::NO_MATCH: return rb_id2sym(rb_intern("no_match"));
|
|
212
|
+
case PhoneNumberUtil::SHORT_NSN_MATCH: return rb_id2sym(rb_intern("short_nsn_match"));
|
|
213
|
+
case PhoneNumberUtil::NSN_MATCH: return rb_id2sym(rb_intern("nsn_match"));
|
|
214
|
+
case PhoneNumberUtil::EXACT_MATCH: return rb_id2sym(rb_intern("exact_match"));
|
|
215
|
+
default: return rb_id2sym(rb_intern("no_match"));
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
Object pico_phone_number_match(Object self, String first, String second) {
|
|
220
|
+
const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
|
|
221
|
+
return match_type_to_symbol(phone_util.IsNumberMatchWithTwoStrings(first.c_str(), second.c_str()));
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
Object parsed_number_match_type(Object self, Object other) {
|
|
225
|
+
PhoneNumber *phone_number;
|
|
226
|
+
TypedData_Get_Struct(self, PhoneNumber, &phone_number_type, phone_number);
|
|
227
|
+
const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
|
|
228
|
+
|
|
229
|
+
if (RTEST(rb_obj_is_kind_of(other, rb_cPhoneNumber))) {
|
|
230
|
+
PhoneNumber *other_number;
|
|
231
|
+
TypedData_Get_Struct(other, PhoneNumber, &phone_number_type, other_number);
|
|
232
|
+
return match_type_to_symbol(phone_util.IsNumberMatch(*phone_number, *other_number));
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
VALUE other_val = other.value();
|
|
236
|
+
std::string other_str(StringValuePtr(other_val), RSTRING_LEN(other_val));
|
|
237
|
+
return match_type_to_symbol(phone_util.IsNumberMatchWithOneString(*phone_number, other_str));
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
static PhoneNumberMatcher::Leniency symbol_to_leniency(VALUE sym) {
|
|
241
|
+
ID id = rb_to_id(sym);
|
|
242
|
+
if (id == rb_intern("possible")) return PhoneNumberMatcher::POSSIBLE;
|
|
243
|
+
if (id == rb_intern("strict_grouping")) return PhoneNumberMatcher::STRICT_GROUPING;
|
|
244
|
+
if (id == rb_intern("exact_grouping")) return PhoneNumberMatcher::EXACT_GROUPING;
|
|
245
|
+
return PhoneNumberMatcher::VALID;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
Object phone_number_match_start(Object self) {
|
|
249
|
+
return rb_ivar_get(self, rb_intern("@start"));
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
Object phone_number_match_end_index(Object self) {
|
|
253
|
+
return rb_ivar_get(self, rb_intern("@end_index"));
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
Object phone_number_match_raw_string(Object self) {
|
|
257
|
+
return rb_ivar_get(self, rb_intern("@raw_string"));
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
Object phone_number_match_number(Object self) {
|
|
261
|
+
return rb_ivar_get(self, rb_intern("@number"));
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
VALUE pico_phone_find_numbers(int argc, VALUE *argv, VALUE self) {
|
|
265
|
+
VALUE text, region, kwargs;
|
|
266
|
+
rb_scan_args(argc, argv, "2:", &text, ®ion, &kwargs);
|
|
267
|
+
|
|
268
|
+
ID kwarg_ids[1] = { rb_intern("leniency") };
|
|
269
|
+
VALUE kwarg_vals[1];
|
|
270
|
+
rb_get_kwargs(kwargs, kwarg_ids, 0, 1, kwarg_vals);
|
|
271
|
+
|
|
272
|
+
PhoneNumberMatcher::Leniency leniency = PhoneNumberMatcher::VALID;
|
|
273
|
+
if (kwarg_vals[0] != Qundef) {
|
|
274
|
+
leniency = symbol_to_leniency(kwarg_vals[0]);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
std::string text_str(StringValuePtr(text), RSTRING_LEN(text));
|
|
278
|
+
std::string region_str(StringValuePtr(region), RSTRING_LEN(region));
|
|
279
|
+
|
|
280
|
+
const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
|
|
281
|
+
PhoneNumberMatcher matcher(phone_util, text_str, region_str, leniency, INT_MAX);
|
|
282
|
+
|
|
283
|
+
Array result;
|
|
284
|
+
PhoneNumberMatch match;
|
|
285
|
+
while (matcher.HasNext()) {
|
|
286
|
+
matcher.Next(&match);
|
|
287
|
+
|
|
288
|
+
int start_pos = match.start();
|
|
289
|
+
int end_pos = match.end();
|
|
290
|
+
std::string raw = match.raw_string();
|
|
291
|
+
|
|
292
|
+
std::string e164;
|
|
293
|
+
phone_util.Format(match.number(), PhoneNumberUtil::E164, &e164);
|
|
294
|
+
VALUE num_args[1] = { rb_str_new(e164.c_str(), e164.size()) };
|
|
295
|
+
VALUE number_obj = rb_class_new_instance(1, num_args, rb_cPhoneNumber);
|
|
296
|
+
|
|
297
|
+
VALUE match_obj = rb_obj_alloc(rb_cPhoneNumberMatch);
|
|
298
|
+
rb_ivar_set(match_obj, rb_intern("@start"), INT2FIX(start_pos));
|
|
299
|
+
rb_ivar_set(match_obj, rb_intern("@end_index"), INT2FIX(end_pos));
|
|
300
|
+
rb_ivar_set(match_obj, rb_intern("@raw_string"), rb_str_new(raw.c_str(), raw.size()));
|
|
301
|
+
rb_ivar_set(match_obj, rb_intern("@number"), number_obj);
|
|
302
|
+
|
|
303
|
+
result.push(Object(match_obj));
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
return result;
|
|
307
|
+
}
|
|
308
|
+
|
|
198
309
|
static const ShortNumberInfo& GetShortNumberInfo() {
|
|
199
310
|
static ShortNumberInfo instance;
|
|
200
311
|
return instance;
|
|
@@ -850,6 +961,24 @@ Object parsed_number_possible_for_type(Object self, Object type_sym) {
|
|
|
850
961
|
return phone_util.IsPossibleNumberForType(*phone_number, type) ? Qtrue : Qfalse;
|
|
851
962
|
}
|
|
852
963
|
|
|
964
|
+
Object parsed_number_truncate(Object self) {
|
|
965
|
+
PhoneNumber *phone_number;
|
|
966
|
+
TypedData_Get_Struct(self, PhoneNumber, &phone_number_type, phone_number);
|
|
967
|
+
const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
|
|
968
|
+
|
|
969
|
+
// TruncateTooLongNumber returns true for already-valid numbers without
|
|
970
|
+
// modifying them. Guard so callers get nil for the "nothing to do" case.
|
|
971
|
+
if (phone_util.IsValidNumber(*phone_number)) return Qnil;
|
|
972
|
+
|
|
973
|
+
PhoneNumber copy(*phone_number);
|
|
974
|
+
if (!phone_util.TruncateTooLongNumber(©)) return Qnil;
|
|
975
|
+
|
|
976
|
+
std::string formatted;
|
|
977
|
+
phone_util.Format(copy, PhoneNumberUtil::E164, &formatted);
|
|
978
|
+
VALUE args[1] = { rb_str_new(formatted.c_str(), formatted.size()) };
|
|
979
|
+
return rb_class_new_instance(1, args, rb_cPhoneNumber);
|
|
980
|
+
}
|
|
981
|
+
|
|
853
982
|
extern "C"
|
|
854
983
|
void Init_pico_phone() {
|
|
855
984
|
rb_mPicoPhone = define_module("PicoPhone")
|
|
@@ -863,12 +992,16 @@ void Init_pico_phone() {
|
|
|
863
992
|
.define_singleton_method("supported_regions", &pico_phone_supported_regions)
|
|
864
993
|
.define_singleton_method("convert_alpha_characters", &pico_phone_convert_alpha_characters)
|
|
865
994
|
.define_singleton_method("alpha_number?", &pico_phone_is_alpha_number)
|
|
995
|
+
.define_singleton_method("number_match", &pico_phone_number_match)
|
|
866
996
|
.define_singleton_method("emergency_number?", &pico_phone_is_emergency_number)
|
|
867
997
|
.define_singleton_method("short_number_valid?", &pico_phone_is_short_number_valid)
|
|
868
998
|
.define_singleton_method("short_number_cost", &pico_phone_short_number_cost)
|
|
869
999
|
.define_singleton_method("supported_types_for_region", &pico_phone_supported_types_for_region)
|
|
870
1000
|
.define_singleton_method("example_number", &pico_phone_example_number)
|
|
871
|
-
.define_singleton_method("example_number_for_type", &pico_phone_example_number_for_type)
|
|
1001
|
+
.define_singleton_method("example_number_for_type", &pico_phone_example_number_for_type)
|
|
1002
|
+
.define_singleton_method("country_calling_code", &pico_phone_country_calling_code);
|
|
1003
|
+
|
|
1004
|
+
rb_define_singleton_method(rb_mPicoPhone, "find_numbers", reinterpret_cast<VALUE (*)(...)>(pico_phone_find_numbers), -1);
|
|
872
1005
|
|
|
873
1006
|
rb_define_module_function(rb_mPicoPhone, "default_country=", reinterpret_cast<VALUE (*)(...)>(pico_phone_set_default_country), 1);
|
|
874
1007
|
rb_define_module_function(rb_mPicoPhone, "default_extension_prefix=", reinterpret_cast<VALUE (*)(...)>(pico_phone_set_default_extension_prefix), 1);
|
|
@@ -909,7 +1042,15 @@ void Init_pico_phone() {
|
|
|
909
1042
|
.define_method("geographical?", &parsed_number_geographical)
|
|
910
1043
|
.define_method("can_be_internationally_dialled?", &parsed_number_can_be_internationally_dialled)
|
|
911
1044
|
.define_method("possible_for_type?", &parsed_number_possible_for_type)
|
|
912
|
-
.define_method("timezones", &parsed_number_timezones)
|
|
1045
|
+
.define_method("timezones", &parsed_number_timezones)
|
|
1046
|
+
.define_method("truncate", &parsed_number_truncate)
|
|
1047
|
+
.define_method("match_type", &parsed_number_match_type);
|
|
1048
|
+
|
|
1049
|
+
rb_cPhoneNumberMatch = define_class_under(rb_mPicoPhone, "PhoneNumberMatch")
|
|
1050
|
+
.define_method("start", &phone_number_match_start)
|
|
1051
|
+
.define_method("end_index", &phone_number_match_end_index)
|
|
1052
|
+
.define_method("raw_string", &phone_number_match_raw_string)
|
|
1053
|
+
.define_method("number", &phone_number_match_number);
|
|
913
1054
|
|
|
914
1055
|
rb_define_alloc_func(rb_cPhoneNumber, rb_phone_number_alloc);
|
|
915
1056
|
rb_define_method(rb_cPhoneNumber, "initialize", reinterpret_cast<VALUE (*)(...)>(phone_number_initialize), -1);
|
|
@@ -79,6 +79,46 @@ module PicoPhone
|
|
|
79
79
|
# @param string [String]
|
|
80
80
|
# @return [Boolean]
|
|
81
81
|
|
|
82
|
+
# @!method self.country_calling_code(region)
|
|
83
|
+
# Returns the international calling code for a region.
|
|
84
|
+
# Returns 0 for unknown or invalid region codes.
|
|
85
|
+
# @param region [String] ISO 3166-1 alpha-2 region code (e.g. "US")
|
|
86
|
+
# @return [Integer] e.g. 1 for "US", 33 for "FR", 0 for unknown
|
|
87
|
+
|
|
88
|
+
# @!method self.number_match(first, second)
|
|
89
|
+
# Compare two phone number strings and return how closely they match.
|
|
90
|
+
# Neither string requires a region hint; E.164 input gives the most precise result.
|
|
91
|
+
# @param first [String]
|
|
92
|
+
# @param second [String]
|
|
93
|
+
# @return [Symbol] :exact_match, :nsn_match, :short_nsn_match, :no_match, or :invalid_number
|
|
94
|
+
|
|
95
|
+
# @!method self.find_numbers(text, region, leniency: :valid)
|
|
96
|
+
# Scan a block of text and return every phone number found in it.
|
|
97
|
+
# @param text [String] arbitrary text to search (must be valid UTF-8)
|
|
98
|
+
# @param region [String] ISO 3166-1 alpha-2 default region for numbers without a country code
|
|
99
|
+
# @param leniency [Symbol] :possible, :valid (default), :strict_grouping, or :exact_grouping
|
|
100
|
+
# @return [Array<PhoneNumberMatch>]
|
|
101
|
+
|
|
102
|
+
# Represents a single phone number match found by {PicoPhone.find_numbers}.
|
|
103
|
+
class PhoneNumberMatch
|
|
104
|
+
# Byte offset of the match start within the searched text.
|
|
105
|
+
# @return [Integer]
|
|
106
|
+
def start; end
|
|
107
|
+
|
|
108
|
+
# Exclusive byte offset of the match end within the searched text.
|
|
109
|
+
# The matched substring is text[start...end_index].
|
|
110
|
+
# @return [Integer]
|
|
111
|
+
def end_index; end
|
|
112
|
+
|
|
113
|
+
# The substring of the searched text that was matched.
|
|
114
|
+
# @return [String]
|
|
115
|
+
def raw_string; end
|
|
116
|
+
|
|
117
|
+
# The parsed phone number.
|
|
118
|
+
# @return [PhoneNumber]
|
|
119
|
+
def number; end
|
|
120
|
+
end
|
|
121
|
+
|
|
82
122
|
class PhoneNumber
|
|
83
123
|
# @param string [String, nil] raw phone number input
|
|
84
124
|
# @param region [String, nil] ISO 3166-1 alpha-2 region hint (e.g. "US")
|
|
@@ -226,6 +266,14 @@ module PicoPhone
|
|
|
226
266
|
# @return [Boolean]
|
|
227
267
|
def geographical?; end
|
|
228
268
|
|
|
269
|
+
# Compare this number against another and return how closely they match.
|
|
270
|
+
# Pass a String or a PhoneNumber. When passed a PhoneNumber, the country code
|
|
271
|
+
# stored in the proto is used for comparison, giving more precise results than
|
|
272
|
+
# a bare national-format string.
|
|
273
|
+
# @param other [String, PhoneNumber]
|
|
274
|
+
# @return [Symbol] :exact_match, :nsn_match, :short_nsn_match, :no_match, or :invalid_number
|
|
275
|
+
def match_type(other); end
|
|
276
|
+
|
|
229
277
|
# True when the number's digit count is consistent with the given type in its region.
|
|
230
278
|
# More permissive than {#type}: a 10-digit US number is possible for both
|
|
231
279
|
# :fixed_line_or_mobile and :toll_free since they share the same digit count.
|
|
@@ -236,5 +284,11 @@ module PicoPhone
|
|
|
236
284
|
# False for numbers that only work within their own country.
|
|
237
285
|
# @return [Boolean]
|
|
238
286
|
def can_be_internationally_dialled?; end
|
|
287
|
+
|
|
288
|
+
# Removes trailing digits until the number is valid, returning the truncated
|
|
289
|
+
# number as a new PhoneNumber. Returns nil if the number was not too long or
|
|
290
|
+
# if no valid truncation exists. Does not mutate the receiver.
|
|
291
|
+
# @return [PhoneNumber, nil]
|
|
292
|
+
def truncate; end
|
|
239
293
|
end
|
|
240
294
|
end
|
data/lib/pico_phone/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: pico_phone
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.6.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Gabi Jack
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-07-
|
|
11
|
+
date: 2026-07-18 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rice
|