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.
@@ -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_
@@ -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, &region, &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(&copy)) 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
  }