pico_phone 0.6.2-aarch64-linux

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,1059 @@
1
+ #include <rice/rice.hpp>
2
+ #include <rice/stl.hpp>
3
+ #include <string.h>
4
+ #include <list>
5
+ #include <set>
6
+ #include <vector>
7
+ #include <phonenumbers/phonenumber.pb.h>
8
+ #include <phonenumbers/phonenumberutil.h>
9
+ #include <phonenumbers/shortnumberinfo.h>
10
+
11
+ // Ruby's regex engine (onigmo.h, pulled in via rice.hpp above) #defines UChar
12
+ // as unsigned char; ICU (pulled in transitively by the geocoding header)
13
+ // typedefs UChar as char16_t. We don't use Ruby's macro, so drop it before
14
+ // any ICU header is reachable.
15
+ #undef UChar
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>
23
+
24
+ using namespace Rice;
25
+ using namespace i18n::phonenumbers;
26
+
27
+ static VALUE rb_cPhoneNumber;
28
+ static VALUE rb_cPhoneNumberMatch;
29
+ static VALUE rb_mPicoPhone;
30
+
31
+ size_t phone_number_size(const void *data) { return sizeof(PhoneNumber); }
32
+
33
+ void phone_number_free(void *data) {
34
+ PhoneNumber *phone_number = static_cast<PhoneNumber *>(data);
35
+ phone_number->~PhoneNumber();
36
+ xfree(data);
37
+ }
38
+
39
+ static const rb_data_type_t phone_number_type = {
40
+ .wrap_struct_name = "phone_number",
41
+ .function =
42
+ {
43
+ .dmark = NULL,
44
+ .dfree = phone_number_free,
45
+ .dsize = phone_number_size,
46
+ },
47
+ .parent = NULL,
48
+ .data = NULL,
49
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
50
+ };
51
+
52
+ VALUE rb_phone_number_alloc(VALUE self) {
53
+ void *phone_number_data = ALLOC(PhoneNumber);
54
+ PhoneNumber *phone_number = new (phone_number_data) PhoneNumber();
55
+ phone_number = phone_number;
56
+
57
+ return TypedData_Wrap_Struct(self, &phone_number_type, phone_number);
58
+ }
59
+
60
+ VALUE pico_phone_phone_number_parse(int argc, VALUE *argv, Object self) {
61
+ return rb_class_new_instance(argc, argv, rb_cPhoneNumber);
62
+ }
63
+
64
+ void pico_phone_set_default_country(VALUE self, VALUE str_code) {
65
+ if (RB_NIL_P(str_code)) {
66
+ str_code = rb_str_new("ZZ", 2);
67
+ }
68
+
69
+ rb_ivar_set(self, rb_intern("@default_country"), str_code);
70
+ }
71
+
72
+ void pico_phone_set_default_extension_prefix(VALUE self, VALUE str_code) {
73
+ if (RB_NIL_P(str_code)) {
74
+ str_code = rb_str_new(";", 1);
75
+ }
76
+
77
+ rb_ivar_set(self, rb_intern("@default_extn_prefix"), str_code);
78
+ }
79
+
80
+ String pico_phone_get_default_country(Object self) {
81
+ return self.iv_get("@default_country");
82
+ }
83
+
84
+ Object is_phone_number_valid(Object self, String str, String cc) {
85
+ std::string phone_number = str.c_str();
86
+ std::string country = cc.c_str();
87
+
88
+ if (country.empty() || phone_number.empty()) {
89
+ return Qfalse;
90
+ }
91
+
92
+ PhoneNumber parsed_number;
93
+ const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
94
+
95
+ auto result = phone_util.ParseAndKeepRawInput(phone_number, country, &parsed_number);
96
+
97
+ if (result != PhoneNumberUtil::NO_PARSING_ERROR) {
98
+ return Qfalse;
99
+ }
100
+
101
+ if (country == "ZZ" && phone_util.IsValidNumber(parsed_number)) {
102
+ return Qtrue;
103
+ } else if (phone_util.IsValidNumberForRegion(parsed_number, country)) {
104
+ return Qtrue;
105
+ } else {
106
+ return Qfalse;
107
+ }
108
+ }
109
+
110
+ Object is_phone_number_possible(Object self, String str, String cc) {
111
+ std::string phone_number = str.c_str();
112
+ std::string country = cc.c_str();
113
+
114
+ if (country.empty() || phone_number.empty()) {
115
+ return Qnil;
116
+ }
117
+
118
+ PhoneNumber parsed_number;
119
+ const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
120
+
121
+ auto result = phone_util.Parse(phone_number, country, &parsed_number);
122
+
123
+ if (result == PhoneNumberUtil::NO_PARSING_ERROR && phone_util.IsPossibleNumber(parsed_number)) {
124
+ return Qtrue;
125
+ } else {
126
+ return Qfalse;
127
+ }
128
+ }
129
+
130
+ Object pico_phone_is_valid_for_default_country(Object self, String phone_number) {
131
+ String country = self.iv_get("@default_country");
132
+ return is_phone_number_valid(self, phone_number, country);
133
+ }
134
+
135
+ Object pico_phone_is_valid_for_country(Object self, String phone_number, String country) {
136
+ return is_phone_number_valid(self, phone_number, country);
137
+ }
138
+
139
+ Object pico_phone_is_possible_for_default_country(Object self, String phone_number) {
140
+ String country = self.iv_get("@default_country");
141
+ return is_phone_number_possible(self, phone_number, country);
142
+ }
143
+
144
+ Object pico_phone_is_possible_for_country(Object self, String phone_number, String country) {
145
+ return is_phone_number_possible(self, phone_number, country);
146
+ }
147
+
148
+ static Array regions_for_number(const PhoneNumber& number, bool strict) {
149
+ const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
150
+ std::list<std::string> regions;
151
+ phone_util.GetRegionCodesForCountryCallingCode(number.country_code(), &regions);
152
+
153
+ Array result;
154
+
155
+ // For the lenient (possible) check with a single region there is nothing to
156
+ // disambiguate, so a length-only check is sufficient and preferable: it lets
157
+ // possible_countries return the region for numbers that are the right length
158
+ // but fail strict pattern validation (e.g. a digit transposition in a French
159
+ // number still belongs to France). For ambiguous calling codes (+1, +7, +44,
160
+ // …) we must use IsValidNumberForRegion to distinguish between the candidate
161
+ // regions regardless of strictness, since IsPossibleNumber has no concept of
162
+ // region and would accept every candidate region equally.
163
+ if (!strict && regions.size() == 1) {
164
+ if (phone_util.IsPossibleNumber(number)) {
165
+ const auto& region = regions.front();
166
+ result.push(Object(rb_str_new(region.c_str(), region.size())));
167
+ }
168
+ return result;
169
+ }
170
+
171
+ for (const auto& region : regions) {
172
+ if (phone_util.IsValidNumberForRegion(number, region)) {
173
+ result.push(Object(rb_str_new(region.c_str(), region.size())));
174
+ }
175
+ }
176
+ return result;
177
+ }
178
+
179
+ Array pico_phone_supported_regions(Object self) {
180
+ const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
181
+ std::set<std::string> regions;
182
+ phone_util.GetSupportedRegions(&regions);
183
+
184
+ Array result;
185
+ for (const auto& region : regions) {
186
+ result.push(Object(rb_str_new(region.c_str(), region.size())));
187
+ }
188
+ return result;
189
+ }
190
+
191
+ String pico_phone_convert_alpha_characters(Object self, String str) {
192
+ std::string phone_str = str.c_str();
193
+ const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
194
+ phone_util.ConvertAlphaCharactersInNumber(&phone_str);
195
+ return rb_str_new(phone_str.c_str(), phone_str.size());
196
+ }
197
+
198
+ Object pico_phone_is_alpha_number(Object self, String str) {
199
+ const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
200
+ return phone_util.IsAlphaNumber(str.c_str()) ? Qtrue : Qfalse;
201
+ }
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
+
309
+ static const ShortNumberInfo& GetShortNumberInfo() {
310
+ static ShortNumberInfo instance;
311
+ return instance;
312
+ }
313
+
314
+ // PhoneNumberOfflineGeocoder lazily loads its area-code-to-description data
315
+ // one (country calling code, language) file at a time on first lookup, and
316
+ // caches each loaded file for the life of this instance -- unlike phonelib's
317
+ // extended data, nothing gets pulled into memory until it's actually queried.
318
+ static const PhoneNumberOfflineGeocoder& GetGeocoder() {
319
+ static PhoneNumberOfflineGeocoder instance;
320
+ return instance;
321
+ }
322
+
323
+ VALUE parsed_number_geo_name(int argc, VALUE *argv, VALUE self) {
324
+ VALUE language;
325
+ rb_scan_args(argc, argv, "01", &language);
326
+
327
+ std::string language_code = RB_NIL_P(language)
328
+ ? "en"
329
+ : std::string(StringValuePtr(language), RSTRING_LEN(language));
330
+
331
+ PhoneNumber *phone_number;
332
+ TypedData_Get_Struct(self, PhoneNumber, &phone_number_type, phone_number);
333
+
334
+ Locale locale(language_code.c_str());
335
+ std::string description = GetGeocoder().GetDescriptionForNumber(*phone_number, locale);
336
+
337
+ return rb_str_new(description.c_str(), description.size());
338
+ }
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
+
385
+ Object pico_phone_is_emergency_number(Object self, String number, String region) {
386
+ return GetShortNumberInfo().IsEmergencyNumber(number.c_str(), region.c_str()) ? Qtrue : Qfalse;
387
+ }
388
+
389
+ Object pico_phone_is_short_number_valid(Object self, String str, String region) {
390
+ std::string number_str = str.c_str();
391
+ std::string region_str = region.c_str();
392
+
393
+ PhoneNumber parsed;
394
+ if (PhoneNumberUtil::GetInstance()->Parse(number_str, region_str, &parsed) != PhoneNumberUtil::NO_PARSING_ERROR) {
395
+ return Qfalse;
396
+ }
397
+ return GetShortNumberInfo().IsValidShortNumberForRegion(parsed, region_str) ? Qtrue : Qfalse;
398
+ }
399
+
400
+ Object pico_phone_short_number_cost(Object self, String str, String region) {
401
+ std::string number_str = str.c_str();
402
+ std::string region_str = region.c_str();
403
+
404
+ PhoneNumber parsed;
405
+ if (PhoneNumberUtil::GetInstance()->Parse(number_str, region_str, &parsed) != PhoneNumberUtil::NO_PARSING_ERROR) {
406
+ return rb_id2sym(rb_intern("unknown_cost"));
407
+ }
408
+
409
+ VALUE cost;
410
+ switch (GetShortNumberInfo().GetExpectedCostForRegion(parsed, region_str)) {
411
+ case ShortNumberInfo::TOLL_FREE:
412
+ cost = rb_intern("toll_free");
413
+ break;
414
+ case ShortNumberInfo::STANDARD_RATE:
415
+ cost = rb_intern("standard_rate");
416
+ break;
417
+ case ShortNumberInfo::PREMIUM_RATE:
418
+ cost = rb_intern("premium_rate");
419
+ break;
420
+ default:
421
+ cost = rb_intern("unknown_cost");
422
+ break;
423
+ }
424
+ return rb_id2sym(cost);
425
+ }
426
+
427
+ Array pico_phone_possible_countries_for_string(Object self, String str) {
428
+ std::string phone_number_str = str.c_str();
429
+ if (phone_number_str.empty()) return Array();
430
+
431
+ PhoneNumber parsed_number;
432
+ const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
433
+
434
+ auto parse_result = phone_util.Parse(phone_number_str, "ZZ", &parsed_number);
435
+ if (parse_result != PhoneNumberUtil::NO_PARSING_ERROR) return Array();
436
+
437
+ return regions_for_number(parsed_number, false);
438
+ }
439
+
440
+ Array pico_phone_valid_countries_for_string(Object self, String str) {
441
+ std::string phone_number_str = str.c_str();
442
+ if (phone_number_str.empty()) return Array();
443
+
444
+ PhoneNumber parsed_number;
445
+ const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
446
+
447
+ auto parse_result = phone_util.Parse(phone_number_str, "ZZ", &parsed_number);
448
+ if (parse_result != PhoneNumberUtil::NO_PARSING_ERROR) return Array();
449
+
450
+ return regions_for_number(parsed_number, true);
451
+ }
452
+
453
+ Object parsed_number_possible_with_reason(Object self) {
454
+ if (rb_ivar_defined(self, rb_intern("@possible_with_reason"))) {
455
+ return rb_iv_get(self, "@possible_with_reason");
456
+ }
457
+
458
+ PhoneNumber *phone_number;
459
+ TypedData_Get_Struct(self, PhoneNumber, &phone_number_type, phone_number);
460
+ const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
461
+
462
+ VALUE reason;
463
+ switch (phone_util.IsPossibleNumberWithReason(*phone_number)) {
464
+ case PhoneNumberUtil::IS_POSSIBLE:
465
+ reason = rb_intern("is_possible");
466
+ break;
467
+ case PhoneNumberUtil::IS_POSSIBLE_LOCAL_ONLY:
468
+ reason = rb_intern("is_possible_local_only");
469
+ break;
470
+ case PhoneNumberUtil::TOO_SHORT:
471
+ reason = rb_intern("too_short");
472
+ break;
473
+ case PhoneNumberUtil::TOO_LONG:
474
+ reason = rb_intern("too_long");
475
+ break;
476
+ case PhoneNumberUtil::INVALID_COUNTRY_CODE:
477
+ reason = rb_intern("invalid_country_code");
478
+ break;
479
+ case PhoneNumberUtil::INVALID_LENGTH:
480
+ reason = rb_intern("invalid_length");
481
+ break;
482
+ default:
483
+ reason = rb_intern("unknown");
484
+ break;
485
+ }
486
+ return rb_iv_set(self, "@possible_with_reason", rb_id2sym(reason));
487
+ }
488
+
489
+ Object parsed_number_geographical(Object self) {
490
+ PhoneNumber *phone_number;
491
+ TypedData_Get_Struct(self, PhoneNumber, &phone_number_type, phone_number);
492
+ const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
493
+ return phone_util.IsNumberGeographical(*phone_number) ? Qtrue : Qfalse;
494
+ }
495
+
496
+ Object parsed_number_can_be_internationally_dialled(Object self) {
497
+ PhoneNumber *phone_number;
498
+ TypedData_Get_Struct(self, PhoneNumber, &phone_number_type, phone_number);
499
+ const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
500
+ return phone_util.CanBeInternationallyDialled(*phone_number) ? Qtrue : Qfalse;
501
+ }
502
+
503
+ VALUE phone_number_nullify_ivars(Object self) {
504
+ rb_iv_set(self, "@input_country", Qnil);
505
+ rb_iv_set(self, "@possible", Qfalse);
506
+ rb_iv_set(self, "@valid", Qfalse);
507
+ rb_iv_set(self, "@type", Qnil);
508
+ rb_iv_set(self, "@national", Qnil);
509
+ rb_iv_set(self, "@international", Qnil);
510
+ rb_iv_set(self, "@e164", Qnil);
511
+ rb_iv_set(self, "@country_code", Qnil);
512
+ rb_iv_set(self, "@country", Qnil);
513
+ rb_iv_set(self, "@area_code", Qnil);
514
+ rb_iv_set(self, "@local_number", Qnil);
515
+ rb_iv_set(self, "@original_format", Qnil);
516
+ rb_iv_set(self, "@raw_national", Qnil);
517
+ rb_iv_set(self, "@possible_with_reason", Qnil);
518
+
519
+ return Qtrue;
520
+ }
521
+
522
+ VALUE phone_number_initialize(int argc, VALUE *argv, VALUE self) {
523
+ VALUE str;
524
+ VALUE input_country;
525
+
526
+ rb_scan_args(argc, argv, "11", &str, &input_country);
527
+ rb_iv_set(self, "@input_country", input_country);
528
+ rb_iv_set(self, "@original", str);
529
+
530
+ if (RB_NIL_P(input_country)) {
531
+ input_country = rb_iv_get(rb_mPicoPhone, "@default_country");
532
+ }
533
+
534
+ if (RB_FIXNUM_P(str)) {
535
+ str = rb_fix2str(str, 10);
536
+ } else if (!RB_TYPE_P(str, T_STRING)) {
537
+ return phone_number_nullify_ivars(self);
538
+ }
539
+
540
+ PhoneNumber *phone_number;
541
+
542
+ TypedData_Get_Struct(self, PhoneNumber, &phone_number_type, phone_number);
543
+
544
+ const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
545
+ std::string phone_number_value(StringValuePtr(str), RSTRING_LEN(str));
546
+ std::string country(StringValuePtr(input_country), RSTRING_LEN(input_country));
547
+
548
+ PhoneNumber parsed_number;
549
+
550
+ auto result = phone_util.ParseAndKeepRawInput(phone_number_value, country, &parsed_number);
551
+
552
+ if (result != PhoneNumberUtil::NO_PARSING_ERROR) {
553
+ phone_number_nullify_ivars(self);
554
+ }
555
+
556
+ phone_number->Swap(&parsed_number);
557
+
558
+ return self;
559
+ }
560
+
561
+ Object is_parsed_phone_number_possible(Object self) {
562
+ if (rb_ivar_defined(self, rb_intern("@possible"))) {
563
+ return rb_iv_get(self, "@possible");
564
+ }
565
+
566
+ PhoneNumber *phone_number;
567
+
568
+ TypedData_Get_Struct(self, PhoneNumber, &phone_number_type, phone_number);
569
+
570
+ const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
571
+
572
+ if (phone_util.IsPossibleNumber(*phone_number)) {
573
+ return rb_iv_set(self, "@possible", Qtrue);
574
+ } else {
575
+ return rb_iv_set(self, "@possible", Qfalse);
576
+ }
577
+ }
578
+
579
+ Object is_parsed_phone_number_impossible(Object self) {
580
+ return (bool) is_parsed_phone_number_possible(self) ? Qfalse : Qtrue;
581
+ }
582
+
583
+ Object is_parsed_phone_number_valid(Object self) {
584
+ if (rb_ivar_defined(self, rb_intern("@valid"))) {
585
+ return rb_iv_get(self, "@valid");
586
+ }
587
+
588
+ VALUE input_country = rb_iv_get(self, "@input_country");
589
+ if (RB_NIL_P(input_country)) {
590
+ input_country = rb_iv_get(rb_mPicoPhone, "@default_country");
591
+ }
592
+
593
+ PhoneNumber *phone_number;
594
+ TypedData_Get_Struct(self, PhoneNumber, &phone_number_type, phone_number);
595
+
596
+ const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
597
+
598
+ if (!rb_str_equal(input_country, rb_str_new_literal("ZZ"))) {
599
+ std::string country(StringValuePtr(input_country), RSTRING_LEN(input_country));
600
+ if (phone_util.IsValidNumberForRegion(*phone_number, country)) {
601
+ return rb_iv_set(self, "@valid", Qtrue);
602
+ } else {
603
+ return rb_iv_set(self, "@valid", Qfalse);
604
+ }
605
+ }
606
+
607
+ if (phone_util.IsValidNumber(*phone_number)) {
608
+ return rb_iv_set(self, "@valid", Qtrue);
609
+ } else {
610
+ return rb_iv_set(self, "@valid", Qfalse);
611
+ }
612
+ }
613
+
614
+ Object is_parsed_phone_number_invalid(Object self) {
615
+ return (bool) is_parsed_phone_number_valid(self) ? Qfalse : Qtrue;
616
+ }
617
+
618
+ static VALUE phone_number_type_to_symbol(PhoneNumberUtil::PhoneNumberType type) {
619
+ switch (type) {
620
+ case PhoneNumberUtil::FIXED_LINE: return rb_id2sym(rb_intern("fixed_line"));
621
+ case PhoneNumberUtil::MOBILE: return rb_id2sym(rb_intern("mobile"));
622
+ case PhoneNumberUtil::FIXED_LINE_OR_MOBILE:return rb_id2sym(rb_intern("fixed_line_or_mobile"));
623
+ case PhoneNumberUtil::TOLL_FREE: return rb_id2sym(rb_intern("toll_free"));
624
+ case PhoneNumberUtil::PREMIUM_RATE: return rb_id2sym(rb_intern("premium_rate"));
625
+ case PhoneNumberUtil::SHARED_COST: return rb_id2sym(rb_intern("shared_cost"));
626
+ case PhoneNumberUtil::VOIP: return rb_id2sym(rb_intern("voip"));
627
+ case PhoneNumberUtil::PERSONAL_NUMBER: return rb_id2sym(rb_intern("personal_number"));
628
+ case PhoneNumberUtil::PAGER: return rb_id2sym(rb_intern("pager"));
629
+ case PhoneNumberUtil::UAN: return rb_id2sym(rb_intern("uan"));
630
+ case PhoneNumberUtil::VOICEMAIL: return rb_id2sym(rb_intern("voicemail"));
631
+ default: return rb_id2sym(rb_intern("unknown"));
632
+ }
633
+ }
634
+
635
+ static PhoneNumberUtil::PhoneNumberType symbol_to_phone_number_type(VALUE sym) {
636
+ ID id = rb_to_id(sym);
637
+ if (id == rb_intern("fixed_line")) return PhoneNumberUtil::FIXED_LINE;
638
+ if (id == rb_intern("mobile")) return PhoneNumberUtil::MOBILE;
639
+ if (id == rb_intern("fixed_line_or_mobile")) return PhoneNumberUtil::FIXED_LINE_OR_MOBILE;
640
+ if (id == rb_intern("toll_free")) return PhoneNumberUtil::TOLL_FREE;
641
+ if (id == rb_intern("premium_rate")) return PhoneNumberUtil::PREMIUM_RATE;
642
+ if (id == rb_intern("shared_cost")) return PhoneNumberUtil::SHARED_COST;
643
+ if (id == rb_intern("voip")) return PhoneNumberUtil::VOIP;
644
+ if (id == rb_intern("personal_number")) return PhoneNumberUtil::PERSONAL_NUMBER;
645
+ if (id == rb_intern("pager")) return PhoneNumberUtil::PAGER;
646
+ if (id == rb_intern("uan")) return PhoneNumberUtil::UAN;
647
+ if (id == rb_intern("voicemail")) return PhoneNumberUtil::VOICEMAIL;
648
+ return PhoneNumberUtil::UNKNOWN;
649
+ }
650
+
651
+ Object parsed_phone_type(Object self) {
652
+ if (rb_ivar_defined(self, rb_intern("@type"))) {
653
+ return rb_iv_get(self, "@type");
654
+ }
655
+
656
+ PhoneNumber *phone_number;
657
+ TypedData_Get_Struct(self, PhoneNumber, &phone_number_type, phone_number);
658
+
659
+ const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
660
+ return rb_iv_set(self, "@type", phone_number_type_to_symbol(phone_util.GetNumberType(*phone_number)));
661
+ }
662
+
663
+ static inline String format_parsed_phone_number(Object self, PhoneNumberUtil::PhoneNumberFormat selected_format, bool full_format = false) {
664
+ PhoneNumber *phone_number;
665
+
666
+ TypedData_Get_Struct(self, PhoneNumber, &phone_number_type, phone_number);
667
+ PhoneNumber copied_proto(*phone_number);
668
+
669
+ const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
670
+ std::string formatted_phone_number;
671
+ String extension_prefix = rb_iv_get(rb_mPicoPhone, "@default_extn_prefix");
672
+
673
+ // if the phone number has an extension
674
+ // remove it so it's not part of formatting
675
+ if (phone_number->has_extension()) {
676
+ copied_proto.clear_extension();
677
+ }
678
+
679
+ phone_util.Format(copied_proto, selected_format, &formatted_phone_number);
680
+
681
+ return (full_format && phone_number->has_extension()) ? formatted_phone_number.append(extension_prefix.c_str()).append(phone_number->extension()) : formatted_phone_number;
682
+ }
683
+
684
+ String format_parsed_number_national(Object self) {
685
+ if (rb_ivar_defined(self, rb_intern("@national"))) {
686
+ return rb_iv_get(self, "@national");
687
+ }
688
+
689
+ return rb_iv_set(self, "@national", format_parsed_phone_number(self, PhoneNumberUtil::PhoneNumberFormat::NATIONAL));
690
+ }
691
+
692
+ String format_parsed_number_full_national(Object self) {
693
+ return format_parsed_phone_number(self, PhoneNumberUtil::PhoneNumberFormat::NATIONAL, true);
694
+ }
695
+
696
+ String format_parsed_number_raw_national(Object self) {
697
+ if (rb_ivar_defined(self, rb_intern("@raw_national"))) {
698
+ return rb_iv_get(self, "@raw_national");
699
+ }
700
+
701
+ PhoneNumber *phone_number;
702
+ const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
703
+ TypedData_Get_Struct(self, PhoneNumber, &phone_number_type, phone_number);
704
+
705
+ std::string national_number;
706
+ phone_util.GetNationalSignificantNumber(*phone_number, &national_number);
707
+
708
+ return rb_iv_set(self, "@raw_national", rb_str_new(national_number.c_str(), national_number.size()));
709
+ }
710
+
711
+ String format_parsed_international(Object self) {
712
+ if (rb_ivar_defined(self, rb_intern("@international"))) {
713
+ return rb_iv_get(self, "@international");
714
+ }
715
+ return rb_iv_set(self, "@international", format_parsed_phone_number(self, PhoneNumberUtil::PhoneNumberFormat::INTERNATIONAL));
716
+ }
717
+
718
+ String format_parsed_full_international(Object self) {
719
+ return format_parsed_phone_number(self, PhoneNumberUtil::PhoneNumberFormat::INTERNATIONAL, true);
720
+ }
721
+
722
+ String format_parsed_number_raw_international(Object self) {
723
+ if (rb_ivar_defined(self, rb_intern("@raw_international"))) {
724
+ return rb_iv_get(self, "@raw_international");
725
+ }
726
+
727
+ String formatted;
728
+
729
+ if (rb_ivar_defined(self, rb_intern("@e164"))) {
730
+ formatted = rb_iv_get(self, "@e164");
731
+ } else {
732
+ formatted = format_parsed_phone_number(self, PhoneNumberUtil::PhoneNumberFormat::E164);
733
+ }
734
+
735
+ std::string formatted_raw = formatted.str().erase(0, 1);
736
+
737
+ return rb_iv_set(self, "@raw_international", (String) formatted_raw);
738
+ }
739
+
740
+ String format_parsed_number_e164(Object self) {
741
+ if (rb_ivar_defined(self, rb_intern("@e164"))) {
742
+ return rb_iv_get(self, "@e164");
743
+ }
744
+ return rb_iv_set(self, "@e164", format_parsed_phone_number(self, PhoneNumberUtil::PhoneNumberFormat::E164));
745
+ }
746
+
747
+ String format_parsed_number_full_e164(Object self) {
748
+ return format_parsed_phone_number(self, PhoneNumberUtil::PhoneNumberFormat::E164, true);
749
+ }
750
+
751
+ String format_parsed_number_in_original_format(Object self) {
752
+ if (rb_ivar_defined(self, rb_intern("@original_format"))) {
753
+ return rb_iv_get(self, "@original_format");
754
+ }
755
+
756
+ PhoneNumber *phone_number;
757
+ TypedData_Get_Struct(self, PhoneNumber, &phone_number_type, phone_number);
758
+ const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
759
+
760
+ VALUE input_country = rb_iv_get(self, "@input_country");
761
+ if (RB_NIL_P(input_country)) {
762
+ input_country = rb_iv_get(rb_mPicoPhone, "@default_country");
763
+ }
764
+ std::string region(StringValuePtr(input_country), RSTRING_LEN(input_country));
765
+
766
+ std::string formatted;
767
+ phone_util.FormatInOriginalFormat(*phone_number, region, &formatted);
768
+ return rb_iv_set(self, "@original_format", rb_str_new(formatted.c_str(), formatted.size()));
769
+ }
770
+
771
+ String format_parsed_number_out_of_country(Object self, String calling_from) {
772
+ PhoneNumber *phone_number;
773
+ TypedData_Get_Struct(self, PhoneNumber, &phone_number_type, phone_number);
774
+ const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
775
+
776
+ std::string formatted;
777
+ phone_util.FormatOutOfCountryCallingNumber(*phone_number, calling_from.c_str(), &formatted);
778
+ return rb_str_new(formatted.c_str(), formatted.size());
779
+ }
780
+
781
+ String format_parsed_number_mobile_dialing(Object self, String calling_from) {
782
+ PhoneNumber *phone_number;
783
+ TypedData_Get_Struct(self, PhoneNumber, &phone_number_type, phone_number);
784
+ const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
785
+
786
+ std::string formatted;
787
+ phone_util.FormatNumberForMobileDialing(*phone_number, calling_from.c_str(), true, &formatted);
788
+ return rb_str_new(formatted.c_str(), formatted.size());
789
+ }
790
+
791
+ Object parsed_phone_number_has_extension(Object self) {
792
+ PhoneNumber *phone_number;
793
+ TypedData_Get_Struct(self, PhoneNumber, &phone_number_type, phone_number);
794
+
795
+ return phone_number->has_extension() ? Qtrue : Qfalse;
796
+ }
797
+
798
+ // Returns the extension for the parsed phone number according to the pattern in
799
+ // libphonenumber library https://github.com/google/libphonenumber/blob/424617599369e7adba8a5d1509b910d9ce2e3e44/cpp/src/phonenumbers/phonenumberutil.cc#L220
800
+ String parsed_number_extension(Object self) {
801
+ PhoneNumber *phone_number;
802
+ TypedData_Get_Struct(self, PhoneNumber, &phone_number_type, phone_number);
803
+
804
+ if (phone_number->has_extension()) {
805
+ return phone_number->extension();
806
+ } else {
807
+ return String("");
808
+ }
809
+ }
810
+
811
+ Object parsed_number_country_code(Object self) {
812
+ if (rb_ivar_defined(self, rb_intern("@country_code"))) {
813
+ return rb_iv_get(self, "@country_code");
814
+ }
815
+
816
+ PhoneNumber *phone_number;
817
+ TypedData_Get_Struct(self, PhoneNumber, &phone_number_type, phone_number);
818
+
819
+ int code = phone_number->country_code();
820
+
821
+ return rb_iv_set(self, "@country_code", INT2FIX(code));
822
+ }
823
+
824
+ String parsed_number_country(Object self) {
825
+ if (rb_ivar_defined(self, rb_intern("@country"))) {
826
+ return rb_iv_get(self, "@country");
827
+ }
828
+
829
+ VALUE input_country = rb_iv_get(self, "@input_country");
830
+
831
+ if(RB_NIL_P(input_country)) {
832
+ PhoneNumber *phone_number;
833
+ std::string country;
834
+ TypedData_Get_Struct(self, PhoneNumber, &phone_number_type, phone_number);
835
+ const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
836
+ phone_util.GetRegionCodeForCountryCode(phone_number->country_code(), &country);
837
+
838
+ return rb_iv_set(self, "@country", rb_str_new(country.c_str(), country.size()));
839
+ } else {
840
+ return rb_iv_set(self, "@country", input_country);
841
+ }
842
+ }
843
+
844
+ String parsed_number_area_code(Object self) {
845
+ if (rb_ivar_defined(self, rb_intern("@area_code"))) {
846
+ return rb_iv_get(self, "@area_code");
847
+ }
848
+
849
+ PhoneNumber *phone_number;
850
+ TypedData_Get_Struct(self, PhoneNumber, &phone_number_type, phone_number);
851
+ const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
852
+ std::string national_significant_number;
853
+ std::string area_code;
854
+ int area_code_size = phone_util.GetLengthOfGeographicalAreaCode(*phone_number);
855
+
856
+ if (area_code_size > 0) {
857
+ phone_util.GetNationalSignificantNumber(*phone_number, &national_significant_number);
858
+ area_code = national_significant_number.substr(0, area_code_size);
859
+ } else {
860
+ area_code = "";
861
+ }
862
+
863
+ return rb_iv_set(self, "@area_code", rb_str_new(area_code.c_str(), area_code.size()));
864
+ }
865
+
866
+ String parsed_number_local_number(Object self) {
867
+ if (rb_ivar_defined(self, rb_intern("@local_number"))) {
868
+ return rb_iv_get(self, "@local_number");
869
+ }
870
+
871
+ PhoneNumber *phone_number;
872
+ TypedData_Get_Struct(self, PhoneNumber, &phone_number_type, phone_number);
873
+ const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
874
+
875
+ std::string national_significant_number;
876
+ phone_util.GetNationalSignificantNumber(*phone_number, &national_significant_number);
877
+
878
+ int area_code_length = phone_util.GetLengthOfGeographicalAreaCode(*phone_number);
879
+ std::string local = area_code_length > 0
880
+ ? national_significant_number.substr(area_code_length)
881
+ : national_significant_number;
882
+
883
+ return rb_iv_set(self, "@local_number", rb_str_new(local.c_str(), local.size()));
884
+ }
885
+
886
+ Object parsed_number_valid_for_country(Object self, String country) {
887
+ PhoneNumber *phone_number;
888
+ TypedData_Get_Struct(self, PhoneNumber, &phone_number_type, phone_number);
889
+ const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
890
+ return phone_util.IsValidNumberForRegion(*phone_number, country.c_str()) ? Qtrue : Qfalse;
891
+ }
892
+
893
+ Object parsed_number_invalid_for_country(Object self, String country) {
894
+ return RTEST(parsed_number_valid_for_country(self, country)) ? Qfalse : Qtrue;
895
+ }
896
+
897
+ Object parsed_number_original(Object self) {
898
+ return rb_iv_get(self, "@original");
899
+ }
900
+
901
+ Object parsed_number_to_s(Object self) {
902
+ if (RTEST(is_parsed_phone_number_valid(self))) {
903
+ return format_parsed_number_e164(self);
904
+ }
905
+ VALUE original = rb_iv_get(self, "@original");
906
+ return RB_NIL_P(original) ? Object(rb_str_new("", 0)) : Object(original);
907
+ }
908
+
909
+ Array parsed_number_possible_countries(Object self) {
910
+ PhoneNumber *phone_number;
911
+ TypedData_Get_Struct(self, PhoneNumber, &phone_number_type, phone_number);
912
+ return regions_for_number(*phone_number, false);
913
+ }
914
+
915
+ Array parsed_number_valid_countries(Object self) {
916
+ PhoneNumber *phone_number;
917
+ TypedData_Get_Struct(self, PhoneNumber, &phone_number_type, phone_number);
918
+ return regions_for_number(*phone_number, true);
919
+ }
920
+
921
+ Array pico_phone_supported_types_for_region(Object self, String region) {
922
+ const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
923
+ std::set<PhoneNumberUtil::PhoneNumberType> types;
924
+ phone_util.GetSupportedTypesForRegion(region.c_str(), &types);
925
+
926
+ Array result;
927
+ for (const auto& type : types) {
928
+ result.push(Object(phone_number_type_to_symbol(type)));
929
+ }
930
+ return result;
931
+ }
932
+
933
+ Object pico_phone_example_number(Object self, String region) {
934
+ const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
935
+ PhoneNumber example;
936
+ if (!phone_util.GetExampleNumber(region.c_str(), &example)) return Qnil;
937
+
938
+ std::string formatted;
939
+ phone_util.Format(example, PhoneNumberUtil::E164, &formatted);
940
+ VALUE args[1] = { rb_str_new(formatted.c_str(), formatted.size()) };
941
+ return rb_class_new_instance(1, args, rb_cPhoneNumber);
942
+ }
943
+
944
+ Object pico_phone_example_number_for_type(Object self, String region, Object type_sym) {
945
+ const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
946
+ PhoneNumber example;
947
+ PhoneNumberUtil::PhoneNumberType type = symbol_to_phone_number_type(type_sym);
948
+ if (!phone_util.GetExampleNumberForType(region.c_str(), type, &example)) return Qnil;
949
+
950
+ std::string formatted;
951
+ phone_util.Format(example, PhoneNumberUtil::E164, &formatted);
952
+ VALUE args[1] = { rb_str_new(formatted.c_str(), formatted.size()) };
953
+ return rb_class_new_instance(1, args, rb_cPhoneNumber);
954
+ }
955
+
956
+ Object parsed_number_possible_for_type(Object self, Object type_sym) {
957
+ PhoneNumber *phone_number;
958
+ TypedData_Get_Struct(self, PhoneNumber, &phone_number_type, phone_number);
959
+ const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
960
+ PhoneNumberUtil::PhoneNumberType type = symbol_to_phone_number_type(type_sym);
961
+ return phone_util.IsPossibleNumberForType(*phone_number, type) ? Qtrue : Qfalse;
962
+ }
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
+
982
+ extern "C"
983
+ void Init_pico_phone() {
984
+ rb_mPicoPhone = define_module("PicoPhone")
985
+ .define_singleton_method("default_country", &pico_phone_get_default_country)
986
+ .define_singleton_method("valid?", &pico_phone_is_valid_for_default_country)
987
+ .define_singleton_method("valid_for_country?", &pico_phone_is_valid_for_country)
988
+ .define_singleton_method("possible?", &pico_phone_is_possible_for_default_country)
989
+ .define_singleton_method("possible_for_country?", &pico_phone_is_possible_for_country)
990
+ .define_singleton_method("possible_countries", &pico_phone_possible_countries_for_string)
991
+ .define_singleton_method("valid_countries", &pico_phone_valid_countries_for_string)
992
+ .define_singleton_method("supported_regions", &pico_phone_supported_regions)
993
+ .define_singleton_method("convert_alpha_characters", &pico_phone_convert_alpha_characters)
994
+ .define_singleton_method("alpha_number?", &pico_phone_is_alpha_number)
995
+ .define_singleton_method("number_match", &pico_phone_number_match)
996
+ .define_singleton_method("emergency_number?", &pico_phone_is_emergency_number)
997
+ .define_singleton_method("short_number_valid?", &pico_phone_is_short_number_valid)
998
+ .define_singleton_method("short_number_cost", &pico_phone_short_number_cost)
999
+ .define_singleton_method("supported_types_for_region", &pico_phone_supported_types_for_region)
1000
+ .define_singleton_method("example_number", &pico_phone_example_number)
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);
1005
+
1006
+ rb_define_module_function(rb_mPicoPhone, "default_country=", reinterpret_cast<VALUE (*)(...)>(pico_phone_set_default_country), 1);
1007
+ rb_define_module_function(rb_mPicoPhone, "default_extension_prefix=", reinterpret_cast<VALUE (*)(...)>(pico_phone_set_default_extension_prefix), 1);
1008
+ rb_define_singleton_method(rb_mPicoPhone, "parse", reinterpret_cast<VALUE (*)(...)>(pico_phone_phone_number_parse), -1);
1009
+ rb_ivar_set(rb_mPicoPhone, rb_intern("@default_country"), rb_str_new("ZZ", 2));
1010
+ rb_ivar_set(rb_mPicoPhone, rb_intern("@default_extn_prefix"), rb_str_new(";", 1));
1011
+
1012
+ rb_cPhoneNumber = define_class_under(rb_mPicoPhone, "PhoneNumber")
1013
+ .define_method("possible?", &is_parsed_phone_number_possible)
1014
+ .define_method("impossible?", &is_parsed_phone_number_impossible)
1015
+ .define_method("valid?", &is_parsed_phone_number_valid)
1016
+ .define_method("invalid?", &is_parsed_phone_number_invalid)
1017
+ .define_method("type", &parsed_phone_type)
1018
+ .define_method("national", &format_parsed_number_national)
1019
+ .define_method("international", &format_parsed_international)
1020
+ .define_method("e164", &format_parsed_number_e164)
1021
+ .define_method("extension", &parsed_number_extension)
1022
+ .define_method("has_extension?", &parsed_phone_number_has_extension)
1023
+ .define_method("full_national", &format_parsed_number_full_national)
1024
+ .define_method("full_international", &format_parsed_full_international)
1025
+ .define_method("full_e164", &format_parsed_number_full_e164)
1026
+ .define_method("format_in_original_format", &format_parsed_number_in_original_format)
1027
+ .define_method("out_of_country_format", &format_parsed_number_out_of_country)
1028
+ .define_method("mobile_dialing_format", &format_parsed_number_mobile_dialing)
1029
+ .define_method("country_code", &parsed_number_country_code)
1030
+ .define_method("country", &parsed_number_country)
1031
+ .define_method("area_code", &parsed_number_area_code)
1032
+ .define_method("local_number", &parsed_number_local_number)
1033
+ .define_method("valid_for_country?", &parsed_number_valid_for_country)
1034
+ .define_method("invalid_for_country?", &parsed_number_invalid_for_country)
1035
+ .define_method("original", &parsed_number_original)
1036
+ .define_method("to_s", &parsed_number_to_s)
1037
+ .define_method("raw_national", &format_parsed_number_raw_national)
1038
+ .define_method("raw_international", &format_parsed_number_raw_international)
1039
+ .define_method("possible_countries", &parsed_number_possible_countries)
1040
+ .define_method("valid_countries", &parsed_number_valid_countries)
1041
+ .define_method("possible_with_reason", &parsed_number_possible_with_reason)
1042
+ .define_method("geographical?", &parsed_number_geographical)
1043
+ .define_method("can_be_internationally_dialled?", &parsed_number_can_be_internationally_dialled)
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);
1054
+
1055
+ rb_define_alloc_func(rb_cPhoneNumber, rb_phone_number_alloc);
1056
+ rb_define_method(rb_cPhoneNumber, "initialize", reinterpret_cast<VALUE (*)(...)>(phone_number_initialize), -1);
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);
1059
+ }