pico_phone 0.4.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/LICENSE.txt +21 -0
- data/THIRD_PARTY_LICENSES.txt +353 -0
- data/ext/pico_phone/carrier_data.cc +68763 -0
- data/ext/pico_phone/carrier_mapper.cc +127 -0
- data/ext/pico_phone/carrier_mapper.h +88 -0
- data/ext/pico_phone/extconf.rb +8 -0
- data/ext/pico_phone/pico_phone.cpp +193 -2
- data/ext/pico_phone/timezone_data.cc +6648 -0
- data/ext/pico_phone/timezone_data.h +25 -0
- data/ext/pico_phone/timezone_mapper.cc +54 -0
- data/ext/pico_phone/timezone_mapper.h +49 -0
- data/ext/pico_phone/vendor_headers/phonenumbers/geocoding/area_code_map.h +92 -0
- data/ext/pico_phone/vendor_headers/phonenumbers/geocoding/carrier_data.h +52 -0
- data/ext/pico_phone/vendor_headers/phonenumbers/geocoding/geocoding_data.h +93 -0
- data/ext/pico_phone/vendor_headers/phonenumbers/geocoding/mapping_file_provider.h +89 -0
- data/lib/pico_phone/phone_number.rb +73 -0
- data/lib/pico_phone/version.rb +1 -1
- metadata +15 -2
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// First-party pico_phone file. See carrier_mapper.h.
|
|
2
|
+
|
|
3
|
+
#include "carrier_mapper.h"
|
|
4
|
+
|
|
5
|
+
#include <algorithm>
|
|
6
|
+
#include <cstring>
|
|
7
|
+
#include <string>
|
|
8
|
+
|
|
9
|
+
#include "phonenumbers/geocoding/area_code_map.h"
|
|
10
|
+
#include "phonenumbers/geocoding/carrier_data.h"
|
|
11
|
+
#include "phonenumbers/geocoding/mapping_file_provider.h"
|
|
12
|
+
#include "phonenumbers/phonenumber.pb.h"
|
|
13
|
+
|
|
14
|
+
#include "absl/synchronization/mutex.h"
|
|
15
|
+
|
|
16
|
+
namespace i18n {
|
|
17
|
+
namespace phonenumbers {
|
|
18
|
+
|
|
19
|
+
using std::string;
|
|
20
|
+
|
|
21
|
+
namespace {
|
|
22
|
+
|
|
23
|
+
// Returns true if s1 comes strictly before s2 in lexicographic order.
|
|
24
|
+
bool IsLowerThan(const char* s1, const char* s2) {
|
|
25
|
+
return strcmp(s1, s2) < 0;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
} // namespace
|
|
29
|
+
|
|
30
|
+
PhoneNumberCarrierMapper::PhoneNumberCarrierMapper() {
|
|
31
|
+
provider_.reset(new MappingFileProvider(get_carrier_country_calling_codes(),
|
|
32
|
+
get_carrier_country_calling_codes_size(),
|
|
33
|
+
get_carrier_country_languages));
|
|
34
|
+
prefix_language_code_pairs_ = get_carrier_prefix_language_code_pairs();
|
|
35
|
+
prefix_language_code_pairs_size_ = get_carrier_prefix_language_code_pairs_size();
|
|
36
|
+
get_prefix_descriptions_ = get_carrier_prefix_descriptions;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
PhoneNumberCarrierMapper::~PhoneNumberCarrierMapper() {
|
|
40
|
+
// Pointer-taking constructor, not the reference-taking one: this file
|
|
41
|
+
// compiles against two different Abseil versions depending on build path
|
|
42
|
+
// (vendored 20260526.0 for the static/native build, whatever Debian/Ubuntu
|
|
43
|
+
// packages for the dynamic/apt-linked build), and only the older
|
|
44
|
+
// pointer-taking overload exists in both. The vendored geocoder itself hit
|
|
45
|
+
// the same tension in the other direction (see build_deps.sh's
|
|
46
|
+
// absl::MutexLock patch) -- there it's a -Werror'd deprecation inside
|
|
47
|
+
// libphonenumber's own CMake build; here it's just a harmless warning
|
|
48
|
+
// since pico_phone's own extension build doesn't set -Werror.
|
|
49
|
+
absl::MutexLock l(&mu_);
|
|
50
|
+
for (AreaCodeMaps::const_iterator it = available_maps_.begin();
|
|
51
|
+
it != available_maps_.end(); ++it) {
|
|
52
|
+
delete it->second;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const AreaCodeMap* PhoneNumberCarrierMapper::GetPhonePrefixDescriptions(
|
|
57
|
+
int prefix, const string& language, const string& script,
|
|
58
|
+
const string& region) const {
|
|
59
|
+
string filename;
|
|
60
|
+
provider_->GetFileName(prefix, language, script, region, &filename);
|
|
61
|
+
if (filename.empty()) {
|
|
62
|
+
return NULL;
|
|
63
|
+
}
|
|
64
|
+
AreaCodeMaps::const_iterator it = available_maps_.find(filename);
|
|
65
|
+
if (it == available_maps_.end()) {
|
|
66
|
+
return LoadAreaCodeMapFromFile(filename);
|
|
67
|
+
}
|
|
68
|
+
return it->second;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const AreaCodeMap* PhoneNumberCarrierMapper::LoadAreaCodeMapFromFile(
|
|
72
|
+
const string& filename) const {
|
|
73
|
+
const char** const prefix_language_code_pairs_end =
|
|
74
|
+
prefix_language_code_pairs_ + prefix_language_code_pairs_size_;
|
|
75
|
+
const char** const prefix_language_code_pair =
|
|
76
|
+
std::lower_bound(prefix_language_code_pairs_,
|
|
77
|
+
prefix_language_code_pairs_end,
|
|
78
|
+
filename.c_str(), IsLowerThan);
|
|
79
|
+
if (prefix_language_code_pair != prefix_language_code_pairs_end &&
|
|
80
|
+
filename.compare(*prefix_language_code_pair) == 0) {
|
|
81
|
+
AreaCodeMap* const m = new AreaCodeMap();
|
|
82
|
+
m->ReadAreaCodeMap(get_prefix_descriptions_(
|
|
83
|
+
prefix_language_code_pair - prefix_language_code_pairs_));
|
|
84
|
+
return available_maps_.insert(AreaCodeMaps::value_type(filename, m))
|
|
85
|
+
.first->second;
|
|
86
|
+
}
|
|
87
|
+
return NULL;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const char* PhoneNumberCarrierMapper::GetAreaDescription(
|
|
91
|
+
const PhoneNumber& number, const string& lang, const string& script,
|
|
92
|
+
const string& region) const {
|
|
93
|
+
const int country_calling_code = number.country_code();
|
|
94
|
+
// NANPA area is not split in C++ code (matches PhoneNumberOfflineGeocoder).
|
|
95
|
+
const int phone_prefix = country_calling_code;
|
|
96
|
+
absl::MutexLock l(&mu_);
|
|
97
|
+
const AreaCodeMap* const descriptions = GetPhonePrefixDescriptions(
|
|
98
|
+
phone_prefix, lang, script, region);
|
|
99
|
+
const char* description = descriptions ? descriptions->Lookup(number) : NULL;
|
|
100
|
+
// When a carrier name is not available in the requested language, fall
|
|
101
|
+
// back to English.
|
|
102
|
+
if ((!description || *description == '\0') && MayFallBackToEnglish(lang)) {
|
|
103
|
+
const AreaCodeMap* default_descriptions = GetPhonePrefixDescriptions(
|
|
104
|
+
phone_prefix, "en", "", "");
|
|
105
|
+
if (!default_descriptions) {
|
|
106
|
+
return "";
|
|
107
|
+
}
|
|
108
|
+
description = default_descriptions->Lookup(number);
|
|
109
|
+
}
|
|
110
|
+
return description ? description : "";
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Don't fall back to English if the requested language is among the following:
|
|
114
|
+
// - Chinese
|
|
115
|
+
// - Japanese
|
|
116
|
+
// - Korean
|
|
117
|
+
bool PhoneNumberCarrierMapper::MayFallBackToEnglish(const string& lang) const {
|
|
118
|
+
return lang.compare("zh") && lang.compare("ja") && lang.compare("ko");
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
string PhoneNumberCarrierMapper::GetNameForNumber(
|
|
122
|
+
const PhoneNumber& number, const string& lang) const {
|
|
123
|
+
return GetAreaDescription(number, lang, "", "");
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
} // namespace phonenumbers
|
|
127
|
+
} // namespace i18n
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// First-party pico_phone file. A trimmed mirror of libphonenumber's
|
|
2
|
+
// PhoneNumberOfflineGeocoder (phonenumbers/geocoding/
|
|
3
|
+
// phonenumber_offline_geocoder.h in the vendored source), reusing the same
|
|
4
|
+
// AreaCodeMap/MappingFileProvider machinery -- lazy per (country calling
|
|
5
|
+
// code, language) file loading, cached for the life of the process -- but
|
|
6
|
+
// backed by carrier_data.cc instead of geocoding_data.cc, and with the
|
|
7
|
+
// ICU-based country-name fallback removed: carrier data has no natural
|
|
8
|
+
// "fall back to the country name" concept (unlike geocoding), so an
|
|
9
|
+
// unmapped prefix returns an empty string, matching phonelib's carrier
|
|
10
|
+
// semantics. This also means, unlike the geocoder, this class has no ICU
|
|
11
|
+
// dependency at all.
|
|
12
|
+
|
|
13
|
+
#ifndef PICO_PHONE_CARRIER_MAPPER_H_
|
|
14
|
+
#define PICO_PHONE_CARRIER_MAPPER_H_
|
|
15
|
+
|
|
16
|
+
#include <map>
|
|
17
|
+
#include <string>
|
|
18
|
+
|
|
19
|
+
#include "absl/synchronization/mutex.h"
|
|
20
|
+
#include "phonenumbers/base/memory/scoped_ptr.h"
|
|
21
|
+
|
|
22
|
+
namespace i18n {
|
|
23
|
+
namespace phonenumbers {
|
|
24
|
+
|
|
25
|
+
class AreaCodeMap;
|
|
26
|
+
class MappingFileProvider;
|
|
27
|
+
class PhoneNumber;
|
|
28
|
+
struct CountryLanguages;
|
|
29
|
+
struct PrefixDescriptions;
|
|
30
|
+
|
|
31
|
+
class PhoneNumberCarrierMapper {
|
|
32
|
+
private:
|
|
33
|
+
typedef std::map<std::string, const AreaCodeMap*> AreaCodeMaps;
|
|
34
|
+
|
|
35
|
+
public:
|
|
36
|
+
PhoneNumberCarrierMapper();
|
|
37
|
+
|
|
38
|
+
PhoneNumberCarrierMapper(const PhoneNumberCarrierMapper&) = delete;
|
|
39
|
+
PhoneNumberCarrierMapper& operator=(const PhoneNumberCarrierMapper&) = delete;
|
|
40
|
+
|
|
41
|
+
~PhoneNumberCarrierMapper();
|
|
42
|
+
|
|
43
|
+
// Returns the carrier name for the given phone number in the given
|
|
44
|
+
// language, or an empty string if no carrier mapping is available for
|
|
45
|
+
// this prefix. lang is a two or three-letter lowercase ISO 639 language
|
|
46
|
+
// code, as with PhoneNumberOfflineGeocoder.
|
|
47
|
+
//
|
|
48
|
+
// The carrier name is the one the number was originally allocated to,
|
|
49
|
+
// however if the country supports mobile number portability the number
|
|
50
|
+
// might not belong to the returned carrier anymore (same caveat as
|
|
51
|
+
// upstream's Java-only PhoneNumberToCarrierMapper.getNameForNumber,
|
|
52
|
+
// verbatim -- see java/carrier/src/.../PhoneNumberToCarrierMapper.java
|
|
53
|
+
// in the vendored source tree).
|
|
54
|
+
std::string GetNameForNumber(const PhoneNumber& number,
|
|
55
|
+
const std::string& lang) const;
|
|
56
|
+
|
|
57
|
+
private:
|
|
58
|
+
typedef const PrefixDescriptions* (*prefix_descriptions_getter)(int index);
|
|
59
|
+
|
|
60
|
+
const AreaCodeMap* LoadAreaCodeMapFromFile(
|
|
61
|
+
const std::string& filename) const ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
|
|
62
|
+
|
|
63
|
+
const AreaCodeMap* GetPhonePrefixDescriptions(
|
|
64
|
+
int prefix, const std::string& language, const std::string& script,
|
|
65
|
+
const std::string& region) const ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
|
|
66
|
+
|
|
67
|
+
const char* GetAreaDescription(const PhoneNumber& number,
|
|
68
|
+
const std::string& lang,
|
|
69
|
+
const std::string& script,
|
|
70
|
+
const std::string& region) const
|
|
71
|
+
ABSL_LOCKS_EXCLUDED(mu_);
|
|
72
|
+
|
|
73
|
+
bool MayFallBackToEnglish(const std::string& lang) const;
|
|
74
|
+
|
|
75
|
+
scoped_ptr<const MappingFileProvider> provider_;
|
|
76
|
+
|
|
77
|
+
const char** prefix_language_code_pairs_;
|
|
78
|
+
int prefix_language_code_pairs_size_;
|
|
79
|
+
prefix_descriptions_getter get_prefix_descriptions_;
|
|
80
|
+
|
|
81
|
+
mutable absl::Mutex mu_;
|
|
82
|
+
mutable AreaCodeMaps available_maps_ ABSL_GUARDED_BY(mu_);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
} // namespace phonenumbers
|
|
86
|
+
} // namespace i18n
|
|
87
|
+
|
|
88
|
+
#endif // PICO_PHONE_CARRIER_MAPPER_H_
|
data/ext/pico_phone/extconf.rb
CHANGED
|
@@ -2,6 +2,14 @@ require "mkmf-rice"
|
|
|
2
2
|
|
|
3
3
|
$CXXFLAGS << ' -std=c++17'
|
|
4
4
|
|
|
5
|
+
# carrier_mapper.cc needs AreaCodeMap/MappingFileProvider/the
|
|
6
|
+
# CountryLanguages+PrefixDescriptions structs, none of which libphonenumber
|
|
7
|
+
# installs publicly (only phonenumber_offline_geocoder.h is installed) in
|
|
8
|
+
# either build path below. Headers vendored verbatim under
|
|
9
|
+
# vendor_headers/phonenumbers/geocoding/ -- see that directory's own
|
|
10
|
+
# comments. Needed unconditionally, regardless of NATIVE_BUILD.
|
|
11
|
+
$INCFLAGS << " -I#{File.expand_path("vendor_headers", __dir__)}"
|
|
12
|
+
|
|
5
13
|
VENDOR_INSTALL = File.expand_path("vendor/install", __dir__)
|
|
6
14
|
NATIVE_BUILD = ENV["PICO_PHONE_NATIVE_BUILD"] == "1"
|
|
7
15
|
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
#include <string.h>
|
|
4
4
|
#include <list>
|
|
5
5
|
#include <set>
|
|
6
|
+
#include <vector>
|
|
6
7
|
#include <phonenumbers/phonenumber.pb.h>
|
|
7
8
|
#include <phonenumbers/phonenumberutil.h>
|
|
8
9
|
#include <phonenumbers/shortnumberinfo.h>
|
|
@@ -13,11 +14,18 @@
|
|
|
13
14
|
// any ICU header is reachable.
|
|
14
15
|
#undef UChar
|
|
15
16
|
#include <phonenumbers/geocoding/phonenumber_offline_geocoder.h>
|
|
17
|
+
#include <phonenumbers/phonenumbermatcher.h>
|
|
18
|
+
#include <phonenumbers/phonenumbermatch.h>
|
|
19
|
+
#include "carrier_mapper.h"
|
|
20
|
+
#include "timezone_mapper.h"
|
|
21
|
+
|
|
22
|
+
#include <climits>
|
|
16
23
|
|
|
17
24
|
using namespace Rice;
|
|
18
25
|
using namespace i18n::phonenumbers;
|
|
19
26
|
|
|
20
27
|
static VALUE rb_cPhoneNumber;
|
|
28
|
+
static VALUE rb_cPhoneNumberMatch;
|
|
21
29
|
static VALUE rb_mPicoPhone;
|
|
22
30
|
|
|
23
31
|
size_t phone_number_size(const void *data) { return sizeof(PhoneNumber); }
|
|
@@ -192,6 +200,112 @@ Object pico_phone_is_alpha_number(Object self, String str) {
|
|
|
192
200
|
return phone_util.IsAlphaNumber(str.c_str()) ? Qtrue : Qfalse;
|
|
193
201
|
}
|
|
194
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
|
+
|
|
195
309
|
static const ShortNumberInfo& GetShortNumberInfo() {
|
|
196
310
|
static ShortNumberInfo instance;
|
|
197
311
|
return instance;
|
|
@@ -223,6 +337,51 @@ VALUE parsed_number_geo_name(int argc, VALUE *argv, VALUE self) {
|
|
|
223
337
|
return rb_str_new(description.c_str(), description.size());
|
|
224
338
|
}
|
|
225
339
|
|
|
340
|
+
// PhoneNumberCarrierMapper mirrors PhoneNumberOfflineGeocoder's lazy
|
|
341
|
+
// per-(prefix, language) file loading and caching -- see carrier_mapper.h.
|
|
342
|
+
static const PhoneNumberCarrierMapper& GetCarrierMapper() {
|
|
343
|
+
static PhoneNumberCarrierMapper instance;
|
|
344
|
+
return instance;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
VALUE parsed_number_carrier_name(int argc, VALUE *argv, VALUE self) {
|
|
348
|
+
VALUE language;
|
|
349
|
+
rb_scan_args(argc, argv, "01", &language);
|
|
350
|
+
|
|
351
|
+
std::string language_code = RB_NIL_P(language)
|
|
352
|
+
? "en"
|
|
353
|
+
: std::string(StringValuePtr(language), RSTRING_LEN(language));
|
|
354
|
+
|
|
355
|
+
PhoneNumber *phone_number;
|
|
356
|
+
TypedData_Get_Struct(self, PhoneNumber, &phone_number_type, phone_number);
|
|
357
|
+
|
|
358
|
+
std::string name = GetCarrierMapper().GetNameForNumber(*phone_number, language_code);
|
|
359
|
+
|
|
360
|
+
return rb_str_new(name.c_str(), name.size());
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// PhoneNumberTimeZonesMapper eagerly loads its single flat prefix table
|
|
364
|
+
// once at construction (unlike the geocoder/carrier mappers, there's no
|
|
365
|
+
// per-language dimension or lazy per-file loading to do here) -- see
|
|
366
|
+
// timezone_mapper.h.
|
|
367
|
+
static const PhoneNumberTimeZonesMapper& GetTimeZonesMapper() {
|
|
368
|
+
static PhoneNumberTimeZonesMapper instance;
|
|
369
|
+
return instance;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
Array parsed_number_timezones(Object self) {
|
|
373
|
+
PhoneNumber *phone_number;
|
|
374
|
+
TypedData_Get_Struct(self, PhoneNumber, &phone_number_type, phone_number);
|
|
375
|
+
|
|
376
|
+
std::vector<std::string> zones = GetTimeZonesMapper().GetTimeZonesForNumber(*phone_number);
|
|
377
|
+
|
|
378
|
+
Array result;
|
|
379
|
+
for (const auto& zone : zones) {
|
|
380
|
+
result.push(Object(rb_str_new(zone.c_str(), zone.size())));
|
|
381
|
+
}
|
|
382
|
+
return result;
|
|
383
|
+
}
|
|
384
|
+
|
|
226
385
|
Object pico_phone_is_emergency_number(Object self, String number, String region) {
|
|
227
386
|
return GetShortNumberInfo().IsEmergencyNumber(number.c_str(), region.c_str()) ? Qtrue : Qfalse;
|
|
228
387
|
}
|
|
@@ -802,6 +961,24 @@ Object parsed_number_possible_for_type(Object self, Object type_sym) {
|
|
|
802
961
|
return phone_util.IsPossibleNumberForType(*phone_number, type) ? Qtrue : Qfalse;
|
|
803
962
|
}
|
|
804
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
|
+
|
|
805
982
|
extern "C"
|
|
806
983
|
void Init_pico_phone() {
|
|
807
984
|
rb_mPicoPhone = define_module("PicoPhone")
|
|
@@ -815,12 +992,16 @@ void Init_pico_phone() {
|
|
|
815
992
|
.define_singleton_method("supported_regions", &pico_phone_supported_regions)
|
|
816
993
|
.define_singleton_method("convert_alpha_characters", &pico_phone_convert_alpha_characters)
|
|
817
994
|
.define_singleton_method("alpha_number?", &pico_phone_is_alpha_number)
|
|
995
|
+
.define_singleton_method("number_match", &pico_phone_number_match)
|
|
818
996
|
.define_singleton_method("emergency_number?", &pico_phone_is_emergency_number)
|
|
819
997
|
.define_singleton_method("short_number_valid?", &pico_phone_is_short_number_valid)
|
|
820
998
|
.define_singleton_method("short_number_cost", &pico_phone_short_number_cost)
|
|
821
999
|
.define_singleton_method("supported_types_for_region", &pico_phone_supported_types_for_region)
|
|
822
1000
|
.define_singleton_method("example_number", &pico_phone_example_number)
|
|
823
|
-
.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);
|
|
824
1005
|
|
|
825
1006
|
rb_define_module_function(rb_mPicoPhone, "default_country=", reinterpret_cast<VALUE (*)(...)>(pico_phone_set_default_country), 1);
|
|
826
1007
|
rb_define_module_function(rb_mPicoPhone, "default_extension_prefix=", reinterpret_cast<VALUE (*)(...)>(pico_phone_set_default_extension_prefix), 1);
|
|
@@ -860,9 +1041,19 @@ void Init_pico_phone() {
|
|
|
860
1041
|
.define_method("possible_with_reason", &parsed_number_possible_with_reason)
|
|
861
1042
|
.define_method("geographical?", &parsed_number_geographical)
|
|
862
1043
|
.define_method("can_be_internationally_dialled?", &parsed_number_can_be_internationally_dialled)
|
|
863
|
-
.define_method("possible_for_type?", &parsed_number_possible_for_type)
|
|
1044
|
+
.define_method("possible_for_type?", &parsed_number_possible_for_type)
|
|
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);
|
|
864
1054
|
|
|
865
1055
|
rb_define_alloc_func(rb_cPhoneNumber, rb_phone_number_alloc);
|
|
866
1056
|
rb_define_method(rb_cPhoneNumber, "initialize", reinterpret_cast<VALUE (*)(...)>(phone_number_initialize), -1);
|
|
867
1057
|
rb_define_method(rb_cPhoneNumber, "geo_name", reinterpret_cast<VALUE (*)(...)>(parsed_number_geo_name), -1);
|
|
1058
|
+
rb_define_method(rb_cPhoneNumber, "carrier_name", reinterpret_cast<VALUE (*)(...)>(parsed_number_carrier_name), -1);
|
|
868
1059
|
}
|