mini_phone 1.0.2 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Dockerfile.dev +9 -0
- data/Gemfile +1 -0
- data/README.md +17 -15
- data/Rakefile +29 -2
- data/debug/memory_plot/memory.rb +33 -0
- data/debug/memory_plot/plot.sh +6 -0
- data/ext/mini_phone/mini_phone.cc +229 -58
- data/lib/mini_phone/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 89fa88b742202101e6bb0204bad2fd20545946a19447d227f61312dd1f9e251c
|
|
4
|
+
data.tar.gz: 49a1d96d9a61aa00c24b88c7e6d3b51dab2929f9ec12043ce2508fc6af374da2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5e719bb7cade41a127cd601f06ca5f2529dae2994112c89bf56ace37202230a2c4a3fae7c0738632d78d032cae0f6b7d1e20365a48f57f0ff046bc0241b2f023
|
|
7
|
+
data.tar.gz: f4ba0f376645bea9b1c25c94f5ba696d744988a1e11a44ff4081af0435165b7a573e24f3101b12dd652add2dccf2e23596bf75ed21b43a5e2fd0a44b1772ef35
|
data/Dockerfile.dev
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
FROM ruby:2.7-alpine
|
|
2
|
+
|
|
3
|
+
WORKDiR /app
|
|
4
|
+
|
|
5
|
+
# RUN apt-get update -y && apt-get install -y valgrind libphonenumber
|
|
6
|
+
RUN apk add --no-cache libphonenumber-dev valgrind git make libffi-dev build-base
|
|
7
|
+
COPY Gemfile Gemfile.lock mini_phone.gemspec ./
|
|
8
|
+
COPY lib/mini_phone/version.rb ./lib/mini_phone/version.rb
|
|
9
|
+
RUN bundle install -j4
|
data/Gemfile
CHANGED
|
@@ -7,6 +7,7 @@ gemspec
|
|
|
7
7
|
|
|
8
8
|
gem 'rake', require: false
|
|
9
9
|
# https://github.com/rake-compiler/rake-compiler/pull/166
|
|
10
|
+
gem 'get_process_mem', require: false
|
|
10
11
|
gem 'rake-compiler', github: 'larskanis/rake-compiler', branch: 'fix-native-version'
|
|
11
12
|
gem 'rspec', '~> 3.0', require: false
|
|
12
13
|
gem 'rspec-github', require: false
|
data/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# MiniPhone
|
|
2
2
|
|
|
3
|
-
A Ruby gem which plugs directly
|
|
4
|
-
[libphonenumber](https://github.com/google/libphonenumber) for
|
|
3
|
+
A Ruby gem which plugs directly into Google's native C++
|
|
4
|
+
[libphonenumber](https://github.com/google/libphonenumber) for extremely
|
|
5
5
|
_fast_ and _robust_ phone number parsing, validation, and formatting. On
|
|
6
|
-
average, most methods are 40x
|
|
6
|
+
average, most methods are 40x to 50x faster than other Ruby phone number
|
|
7
7
|
libraries.
|
|
8
8
|
|
|
9
9
|
## Usage
|
|
@@ -23,10 +23,12 @@ MiniPhone.default_country = 'US'
|
|
|
23
23
|
|
|
24
24
|
phone_number = MiniPhone.parse('404-384-1399')
|
|
25
25
|
|
|
26
|
-
phone_number.e164
|
|
27
|
-
phone_number.national
|
|
28
|
-
phone_number.
|
|
29
|
-
phone_number.
|
|
26
|
+
phone_number.e164 # +14043841399
|
|
27
|
+
phone_number.national # (404) 384-1399
|
|
28
|
+
phone_number.raw_national # 4043841399
|
|
29
|
+
phone_number.dasherized_national # 404-384-1399
|
|
30
|
+
phone_number.international # +1 404-384-1399
|
|
31
|
+
phone_number.rfc3966 # tel:+1-404-384-1384
|
|
30
32
|
```
|
|
31
33
|
|
|
32
34
|
### Checking if a phone number is possible
|
|
@@ -41,7 +43,7 @@ phone_number.possible? # false
|
|
|
41
43
|
|
|
42
44
|
```ruby
|
|
43
45
|
MiniPhone.parse('+12423570000').type # :mobile
|
|
44
|
-
MiniPhone.parse
|
|
46
|
+
MiniPhone.parse('+12423651234').type # :fixed_line
|
|
45
47
|
```
|
|
46
48
|
|
|
47
49
|
The possible types are directly mapped from [this
|
|
@@ -65,14 +67,14 @@ enum](https://github.com/google/libphonenumber/blob/4e9954edea7cf263532c5dd3861a
|
|
|
65
67
|
## Compatibility with PhoneLib
|
|
66
68
|
|
|
67
69
|
MiniPhone aims to be compatible with
|
|
68
|
-
[Phonelib](https://github.com/daddyz/phonelib)
|
|
69
|
-
drop in replacement. It has a smaller feature set, so
|
|
70
|
-
|
|
70
|
+
[Phonelib](https://github.com/daddyz/phonelib). In many cases it can be a
|
|
71
|
+
drop in replacement. It has a smaller feature set, so it is not a
|
|
72
|
+
replacement for every use case. If there is a feature you need, open
|
|
71
73
|
an issue and we will try to support it.
|
|
72
74
|
|
|
73
75
|
## Benchmarks
|
|
74
76
|
|
|
75
|
-
On average, most methods are 40x
|
|
77
|
+
On average, most methods are 40x to 50x faster than other libraries. To run
|
|
76
78
|
the benchmarks locally, execute: `bundle exec rake bench`
|
|
77
79
|
|
|
78
80
|
```
|
|
@@ -132,10 +134,10 @@ push git commits and tags, and push the `.gem` file to
|
|
|
132
134
|
## Contributing
|
|
133
135
|
|
|
134
136
|
Bug reports and pull requests are welcome on GitHub at
|
|
135
|
-
https://github.com/
|
|
137
|
+
https://github.com/ianks/mini_phone. This project is intended to be a
|
|
136
138
|
safe, welcoming space for collaboration, and contributors are expected to
|
|
137
139
|
adhere to the [code of
|
|
138
|
-
conduct](https://github.com/
|
|
140
|
+
conduct](https://github.com/ianks/mini_phone/blob/master/CODE_OF_CONDUCT.md).
|
|
139
141
|
|
|
140
142
|
## License
|
|
141
143
|
|
|
@@ -146,4 +148,4 @@ License](https://opensource.org/licenses/MIT).
|
|
|
146
148
|
|
|
147
149
|
Everyone interacting in the MiniPhone project's codebases, issue trackers,
|
|
148
150
|
chat rooms and mailing lists is expected to follow the [code of
|
|
149
|
-
conduct](https://github.com/
|
|
151
|
+
conduct](https://github.com/ianks/mini_phone/blob/master/CODE_OF_CONDUCT.md).
|
data/Rakefile
CHANGED
|
@@ -9,7 +9,7 @@ RSpec::Core::RakeTask.new(:spec)
|
|
|
9
9
|
|
|
10
10
|
task build: :compile
|
|
11
11
|
|
|
12
|
-
task default: %i[clobber compile spec]
|
|
12
|
+
task default: %i[clobber compile spec lint]
|
|
13
13
|
|
|
14
14
|
spec = Gem::Specification.load(File.expand_path('mini_phone.gemspec', __dir__))
|
|
15
15
|
|
|
@@ -28,7 +28,16 @@ task bench: %i[clobber compile] do
|
|
|
28
28
|
end
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
-
task :
|
|
31
|
+
task :lint do
|
|
32
|
+
sh 'bundle exec rubocop'
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
task :format do
|
|
36
|
+
sh 'bundle exec rubocop -A'
|
|
37
|
+
sh 'clang-format -i ext/**/*.{h,cc}'
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
task deploy: :default do
|
|
32
41
|
sh 'code -w ./lib/mini_phone/version.rb'
|
|
33
42
|
version = `ruby -r ./lib/mini_phone/version.rb -e 'print MiniPhone::VERSION'`.strip
|
|
34
43
|
sh "git commit -am 'Bump to v#{version} :confetti_ball:'"
|
|
@@ -67,3 +76,21 @@ namespace :publish do
|
|
|
67
76
|
push_to_github_registry(g)
|
|
68
77
|
end
|
|
69
78
|
end
|
|
79
|
+
|
|
80
|
+
desc 'Run valgrind test'
|
|
81
|
+
|
|
82
|
+
namespace :debug do
|
|
83
|
+
desc 'Plot memory'
|
|
84
|
+
task :memory do
|
|
85
|
+
sh 'debug/memory_plot/plot.sh'
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
task :valgrind do
|
|
89
|
+
sh 'docker build --tag mini_phone_dev -f Dockerfile.dev .'
|
|
90
|
+
args = '--tool=memcheck --num-callers=15 --partial-loads-ok=yes --undef-value-errors=no'
|
|
91
|
+
script = 'ruby debug/memory_plot/memory.rb --once'
|
|
92
|
+
cmd = "docker run -it --rm -v #{Dir.pwd}:/app -w /app mini_phone_dev valgrind #{args} #{script}"
|
|
93
|
+
puts cmd
|
|
94
|
+
system cmd
|
|
95
|
+
end
|
|
96
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'bundler/setup'
|
|
4
|
+
require 'mini_phone'
|
|
5
|
+
require 'get_process_mem'
|
|
6
|
+
|
|
7
|
+
10.times do
|
|
8
|
+
GC.start
|
|
9
|
+
GC.compact
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
$stdout.sync = true
|
|
13
|
+
|
|
14
|
+
loop do
|
|
15
|
+
10_000.times do
|
|
16
|
+
pn = MiniPhone::PhoneNumber.new('+1 404 388 1299')
|
|
17
|
+
pn.e164
|
|
18
|
+
pn.valid?
|
|
19
|
+
pn.possible?
|
|
20
|
+
pn.raw_national
|
|
21
|
+
pn.international
|
|
22
|
+
pn.country_code
|
|
23
|
+
pn.area_code
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
4.times { GC.start }
|
|
27
|
+
|
|
28
|
+
memory_mb = GetProcessMem.new.mb
|
|
29
|
+
|
|
30
|
+
$stdout.puts memory_mb
|
|
31
|
+
|
|
32
|
+
break if ARGV.first == '--once'
|
|
33
|
+
end
|
|
@@ -1,28 +1,58 @@
|
|
|
1
1
|
#include "mini_phone.h"
|
|
2
|
+
#include "phonenumbers/phonemetadata.pb.h"
|
|
3
|
+
#include "phonenumbers/phonenumber.pb.h"
|
|
2
4
|
#include "phonenumbers/phonenumberutil.h"
|
|
3
5
|
|
|
4
6
|
using namespace ::i18n::phonenumbers;
|
|
5
7
|
|
|
8
|
+
using google::protobuf::RepeatedPtrField;
|
|
9
|
+
|
|
6
10
|
static VALUE rb_mMiniPhone;
|
|
7
11
|
|
|
8
12
|
static VALUE rb_cPhoneNumber;
|
|
9
13
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
static RepeatedPtrField<NumberFormat> raw_national_format;
|
|
15
|
+
static RepeatedPtrField<NumberFormat> dasherized_national_format;
|
|
16
|
+
|
|
17
|
+
extern "C" struct PhoneNumberInfo { PhoneNumber *phone_number; };
|
|
18
|
+
|
|
19
|
+
extern "C" size_t phone_number_info_size(const void *data) { return sizeof(PhoneNumberInfo) + sizeof(PhoneNumber); }
|
|
20
|
+
|
|
21
|
+
extern "C" void phone_number_info_free(void *data) {
|
|
22
|
+
PhoneNumberInfo *phone_number_info = static_cast<PhoneNumberInfo *>(data);
|
|
23
|
+
phone_number_info->phone_number->~PhoneNumber();
|
|
24
|
+
xfree(phone_number_info->phone_number);
|
|
25
|
+
phone_number_info->~PhoneNumberInfo();
|
|
26
|
+
xfree(data);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
extern "C" const rb_data_type_t phone_number_info_type = {
|
|
30
|
+
.wrap_struct_name = "MiniPhone/PhoneNumberInfo",
|
|
31
|
+
.function =
|
|
32
|
+
{
|
|
33
|
+
.dmark = NULL,
|
|
34
|
+
.dfree = phone_number_info_free,
|
|
35
|
+
.dsize = phone_number_info_size,
|
|
36
|
+
},
|
|
37
|
+
.parent = NULL,
|
|
38
|
+
.data = NULL,
|
|
39
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY,
|
|
14
40
|
};
|
|
15
41
|
|
|
16
42
|
static inline VALUE is_phone_number_valid(VALUE self, VALUE str, VALUE cc) {
|
|
43
|
+
if (NIL_P(str) || NIL_P(cc)) {
|
|
44
|
+
return Qfalse;
|
|
45
|
+
}
|
|
46
|
+
|
|
17
47
|
PhoneNumber parsed_number;
|
|
18
|
-
PhoneNumberUtil *
|
|
48
|
+
const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
|
|
19
49
|
|
|
20
50
|
std::string phone_number(RSTRING_PTR(str), RSTRING_LEN(str));
|
|
21
51
|
std::string country_code(RSTRING_PTR(cc), RSTRING_LEN(cc));
|
|
22
52
|
|
|
23
|
-
auto result = phone_util
|
|
53
|
+
auto result = phone_util.ParseAndKeepRawInput(phone_number, country_code, &parsed_number);
|
|
24
54
|
|
|
25
|
-
if (result == PhoneNumberUtil::NO_PARSING_ERROR && phone_util
|
|
55
|
+
if (result == PhoneNumberUtil::NO_PARSING_ERROR && phone_util.IsValidNumber(parsed_number)) {
|
|
26
56
|
return Qtrue;
|
|
27
57
|
} else {
|
|
28
58
|
return Qfalse;
|
|
@@ -35,6 +65,20 @@ extern "C" VALUE rb_is_phone_number_valid(VALUE self, VALUE str) {
|
|
|
35
65
|
return is_phone_number_valid(self, str, def_cc);
|
|
36
66
|
}
|
|
37
67
|
|
|
68
|
+
extern "C" VALUE rb_normalize_digits_only(VALUE self, VALUE str) {
|
|
69
|
+
if (NIL_P(str)) {
|
|
70
|
+
return Qnil;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
|
|
74
|
+
|
|
75
|
+
std::string phone_number(RSTRING_PTR(str), RSTRING_LEN(str));
|
|
76
|
+
|
|
77
|
+
phone_util.NormalizeDigitsOnly(&phone_number);
|
|
78
|
+
|
|
79
|
+
return rb_str_new(phone_number.c_str(), phone_number.size());
|
|
80
|
+
}
|
|
81
|
+
|
|
38
82
|
extern "C" VALUE rb_is_phone_number_valid_for_country(VALUE self, VALUE str, VALUE cc) {
|
|
39
83
|
return is_phone_number_valid(self, str, cc);
|
|
40
84
|
}
|
|
@@ -48,16 +92,20 @@ extern "C" VALUE rb_is_phone_number_invalid_for_country(VALUE self, VALUE str, V
|
|
|
48
92
|
}
|
|
49
93
|
|
|
50
94
|
extern "C" VALUE rb_is_phone_number_possible(VALUE self, VALUE str) {
|
|
95
|
+
if (NIL_P(str)) {
|
|
96
|
+
return Qnil;
|
|
97
|
+
}
|
|
98
|
+
|
|
51
99
|
PhoneNumber parsed_number;
|
|
52
|
-
PhoneNumberUtil *
|
|
100
|
+
const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
|
|
53
101
|
|
|
54
102
|
VALUE def_cc = rb_iv_get(rb_mMiniPhone, "@default_country");
|
|
55
103
|
std::string phone_number(RSTRING_PTR(str), RSTRING_LEN(str));
|
|
56
104
|
std::string country_code(RSTRING_PTR(def_cc), RSTRING_LEN(def_cc));
|
|
57
105
|
|
|
58
|
-
auto result = phone_util
|
|
106
|
+
auto result = phone_util.Parse(phone_number, country_code, &parsed_number);
|
|
59
107
|
|
|
60
|
-
if (result == PhoneNumberUtil::NO_PARSING_ERROR && phone_util
|
|
108
|
+
if (result == PhoneNumberUtil::NO_PARSING_ERROR && phone_util.IsPossibleNumber(parsed_number)) {
|
|
61
109
|
return Qtrue;
|
|
62
110
|
} else {
|
|
63
111
|
return Qfalse;
|
|
@@ -69,27 +117,36 @@ extern "C" VALUE rb_is_phone_number_impossible(VALUE self, VALUE str) {
|
|
|
69
117
|
}
|
|
70
118
|
|
|
71
119
|
extern "C" VALUE rb_set_default_country(VALUE self, VALUE str_code) {
|
|
120
|
+
if (NIL_P(str_code)) {
|
|
121
|
+
str_code = rb_str_new("ZZ", 2);
|
|
122
|
+
}
|
|
123
|
+
|
|
72
124
|
return rb_iv_set(self, "@default_country", str_code);
|
|
73
125
|
}
|
|
74
126
|
|
|
75
127
|
extern "C" VALUE rb_get_default_country(VALUE self) { return rb_iv_get(self, "@default_country"); }
|
|
76
128
|
|
|
77
|
-
extern "C" void rb_phone_number_dealloc(PhoneNumberInfo *phone_number_info) { delete phone_number_info; }
|
|
78
|
-
|
|
79
129
|
extern "C" VALUE rb_phone_number_parse(int argc, VALUE *argv, VALUE self) {
|
|
80
130
|
return rb_class_new_instance(argc, argv, rb_cPhoneNumber);
|
|
81
131
|
}
|
|
82
132
|
|
|
83
133
|
extern "C" VALUE rb_phone_number_alloc(VALUE self) {
|
|
84
|
-
|
|
134
|
+
void *phone_number_data = ALLOC(PhoneNumber);
|
|
135
|
+
void *data = ALLOC(PhoneNumberInfo);
|
|
136
|
+
PhoneNumberInfo *phone_number_info = new (data) PhoneNumberInfo();
|
|
137
|
+
PhoneNumber *phone_number = new (phone_number_data) PhoneNumber();
|
|
138
|
+
phone_number_info->phone_number = phone_number;
|
|
85
139
|
|
|
86
|
-
|
|
87
|
-
return Data_Wrap_Struct(self, NULL, &rb_phone_number_dealloc, phone_number_info);
|
|
140
|
+
return TypedData_Wrap_Struct(self, &phone_number_info_type, phone_number_info);
|
|
88
141
|
}
|
|
89
142
|
|
|
90
143
|
static inline VALUE rb_phone_number_nullify_ivars(VALUE self) {
|
|
91
144
|
rb_iv_set(self, "@national", Qnil);
|
|
145
|
+
rb_iv_set(self, "@raw_national", Qnil);
|
|
146
|
+
rb_iv_set(self, "@dasherized_national", Qnil);
|
|
92
147
|
rb_iv_set(self, "@international", Qnil);
|
|
148
|
+
rb_iv_set(self, "@raw_international", Qnil);
|
|
149
|
+
rb_iv_set(self, "@dasherized_international", Qnil);
|
|
93
150
|
rb_iv_set(self, "@e164", Qnil);
|
|
94
151
|
rb_iv_set(self, "@country_code", Qnil);
|
|
95
152
|
rb_iv_set(self, "@region_code", Qnil);
|
|
@@ -97,6 +154,7 @@ static inline VALUE rb_phone_number_nullify_ivars(VALUE self) {
|
|
|
97
154
|
rb_iv_set(self, "@type", Qnil);
|
|
98
155
|
rb_iv_set(self, "@valid", Qfalse);
|
|
99
156
|
rb_iv_set(self, "@possible", Qfalse);
|
|
157
|
+
rb_iv_set(self, "@area_code", Qnil);
|
|
100
158
|
|
|
101
159
|
return Qtrue;
|
|
102
160
|
}
|
|
@@ -122,19 +180,19 @@ extern "C" VALUE rb_phone_number_initialize(int argc, VALUE *argv, VALUE self) {
|
|
|
122
180
|
PhoneNumberInfo *phone_number_info;
|
|
123
181
|
PhoneNumber parsed_number;
|
|
124
182
|
|
|
125
|
-
|
|
183
|
+
TypedData_Get_Struct(self, PhoneNumberInfo, &phone_number_info_type, phone_number_info);
|
|
126
184
|
|
|
127
|
-
PhoneNumberUtil *
|
|
185
|
+
const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
|
|
128
186
|
|
|
129
187
|
std::string phone_number(RSTRING_PTR(str), RSTRING_LEN(str));
|
|
130
188
|
std::string country_code(RSTRING_PTR(def_cc), RSTRING_LEN(def_cc));
|
|
131
189
|
|
|
132
|
-
auto result = phone_util
|
|
190
|
+
auto result = phone_util.Parse(phone_number, country_code, &parsed_number);
|
|
133
191
|
|
|
134
192
|
if (result != PhoneNumberUtil::NO_PARSING_ERROR) {
|
|
135
193
|
rb_phone_number_nullify_ivars(self);
|
|
136
194
|
} else {
|
|
137
|
-
phone_number_info->phone_number
|
|
195
|
+
phone_number_info->phone_number->Swap(&parsed_number);
|
|
138
196
|
}
|
|
139
197
|
|
|
140
198
|
return self;
|
|
@@ -143,11 +201,11 @@ extern "C" VALUE rb_phone_number_initialize(int argc, VALUE *argv, VALUE self) {
|
|
|
143
201
|
static inline VALUE rb_phone_number_format(VALUE self, PhoneNumberUtil::PhoneNumberFormat fmt) {
|
|
144
202
|
std::string formatted_number;
|
|
145
203
|
PhoneNumberInfo *phone_number_info;
|
|
146
|
-
|
|
204
|
+
TypedData_Get_Struct(self, PhoneNumberInfo, &phone_number_info_type, phone_number_info);
|
|
147
205
|
|
|
148
|
-
PhoneNumberUtil *
|
|
149
|
-
PhoneNumber parsed_number = phone_number_info->phone_number;
|
|
150
|
-
phone_util
|
|
206
|
+
const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
|
|
207
|
+
PhoneNumber *parsed_number = phone_number_info->phone_number;
|
|
208
|
+
phone_util.Format(*parsed_number, fmt, &formatted_number);
|
|
151
209
|
|
|
152
210
|
return rb_str_new(formatted_number.c_str(), formatted_number.size());
|
|
153
211
|
}
|
|
@@ -185,6 +243,78 @@ extern "C" VALUE rb_phone_number_rfc3966(VALUE self) {
|
|
|
185
243
|
return rb_iv_set(self, "@rfc3966", rb_phone_number_format(self, PhoneNumberUtil::PhoneNumberFormat::RFC3966));
|
|
186
244
|
}
|
|
187
245
|
|
|
246
|
+
VALUE format_by_pattern_national(VALUE self, RepeatedPtrField<NumberFormat> format) {
|
|
247
|
+
std::string formatted_number;
|
|
248
|
+
PhoneNumberInfo *phone_number_info;
|
|
249
|
+
const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
|
|
250
|
+
TypedData_Get_Struct(self, PhoneNumberInfo, &phone_number_info_type, phone_number_info);
|
|
251
|
+
|
|
252
|
+
phone_util.FormatByPattern(*phone_number_info->phone_number, PhoneNumberUtil::NATIONAL, format, &formatted_number);
|
|
253
|
+
|
|
254
|
+
return rb_str_new(formatted_number.c_str(), formatted_number.size());
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
extern "C" VALUE rb_phone_number_raw_national(VALUE self) {
|
|
258
|
+
if (rb_ivar_defined(self, rb_intern("@raw_national"))) {
|
|
259
|
+
return rb_iv_get(self, "@raw_national");
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
VALUE result = format_by_pattern_national(self, raw_national_format);
|
|
263
|
+
|
|
264
|
+
return rb_iv_set(self, "@raw_national", result);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
extern "C" VALUE rb_phone_number_dasherized_national(VALUE self) {
|
|
268
|
+
if (rb_ivar_defined(self, rb_intern("@dasherized_national"))) {
|
|
269
|
+
return rb_iv_get(self, "@dasherized_national");
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
VALUE result = format_by_pattern_national(self, dasherized_national_format);
|
|
273
|
+
|
|
274
|
+
return rb_iv_set(self, "@dasherized_national", result);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
extern "C" VALUE rb_phone_number_country_code(VALUE self) {
|
|
278
|
+
if (rb_ivar_defined(self, rb_intern("@country_code"))) {
|
|
279
|
+
return rb_iv_get(self, "@country_code");
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
PhoneNumberInfo *phone_number_info;
|
|
283
|
+
TypedData_Get_Struct(self, PhoneNumberInfo, &phone_number_info_type, phone_number_info);
|
|
284
|
+
|
|
285
|
+
int code = phone_number_info->phone_number->country_code();
|
|
286
|
+
|
|
287
|
+
VALUE result = INT2NUM(code);
|
|
288
|
+
|
|
289
|
+
return rb_iv_set(self, "@country_code", result);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
extern "C" VALUE rb_phone_number_dasherized_international(VALUE self) {
|
|
293
|
+
if (rb_ivar_defined(self, rb_intern("@dasherized_international"))) {
|
|
294
|
+
return rb_iv_get(self, "@dasherized_international");
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
VALUE national = rb_phone_number_dasherized_national(self);
|
|
298
|
+
VALUE cc = rb_fix2str(rb_phone_number_country_code(self), 10);
|
|
299
|
+
VALUE dash = rb_str_new("-", 1);
|
|
300
|
+
VALUE prefix = rb_str_concat(cc, dash);
|
|
301
|
+
VALUE result = rb_str_concat(prefix, national);
|
|
302
|
+
|
|
303
|
+
return rb_iv_set(self, "@dasherized_international", result);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
extern "C" VALUE rb_phone_number_raw_international(VALUE self) {
|
|
307
|
+
if (rb_ivar_defined(self, rb_intern("@raw_international"))) {
|
|
308
|
+
return rb_iv_get(self, "@raw_international");
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
VALUE national = rb_phone_number_raw_national(self);
|
|
312
|
+
VALUE cc = rb_fix2str(rb_phone_number_country_code(self), 10);
|
|
313
|
+
VALUE result = rb_str_concat(cc, national);
|
|
314
|
+
|
|
315
|
+
return rb_iv_set(self, "@raw_international", result);
|
|
316
|
+
}
|
|
317
|
+
|
|
188
318
|
extern "C" VALUE rb_phone_number_valid_eh(VALUE self) {
|
|
189
319
|
if (rb_ivar_defined(self, rb_intern("@valid"))) {
|
|
190
320
|
return rb_iv_get(self, "@valid");
|
|
@@ -192,11 +322,11 @@ extern "C" VALUE rb_phone_number_valid_eh(VALUE self) {
|
|
|
192
322
|
|
|
193
323
|
std::string formatted_number;
|
|
194
324
|
PhoneNumberInfo *phone_number_info;
|
|
195
|
-
|
|
325
|
+
TypedData_Get_Struct(self, PhoneNumberInfo, &phone_number_info_type, phone_number_info);
|
|
196
326
|
|
|
197
|
-
PhoneNumberUtil *
|
|
327
|
+
const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
|
|
198
328
|
|
|
199
|
-
if (phone_util
|
|
329
|
+
if (phone_util.IsValidNumber(*phone_number_info->phone_number)) {
|
|
200
330
|
return rb_iv_set(self, "@valid", Qtrue);
|
|
201
331
|
} else {
|
|
202
332
|
return rb_iv_set(self, "@valid", Qfalse);
|
|
@@ -214,11 +344,11 @@ extern "C" VALUE rb_phone_number_possible_eh(VALUE self) {
|
|
|
214
344
|
|
|
215
345
|
std::string formatted_number;
|
|
216
346
|
PhoneNumberInfo *phone_number_info;
|
|
217
|
-
|
|
347
|
+
TypedData_Get_Struct(self, PhoneNumberInfo, &phone_number_info_type, phone_number_info);
|
|
218
348
|
|
|
219
|
-
PhoneNumberUtil *
|
|
349
|
+
const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
|
|
220
350
|
|
|
221
|
-
if (phone_util
|
|
351
|
+
if (phone_util.IsPossibleNumber(*phone_number_info->phone_number)) {
|
|
222
352
|
return rb_iv_set(self, "@possible", Qtrue);
|
|
223
353
|
} else {
|
|
224
354
|
return rb_iv_set(self, "@possible", Qfalse);
|
|
@@ -236,44 +366,30 @@ extern "C" VALUE rb_phone_number_region_code(VALUE self) {
|
|
|
236
366
|
|
|
237
367
|
PhoneNumberInfo *phone_number_info;
|
|
238
368
|
std::string code;
|
|
239
|
-
|
|
240
|
-
PhoneNumberUtil *
|
|
369
|
+
TypedData_Get_Struct(self, PhoneNumberInfo, &phone_number_info_type, phone_number_info);
|
|
370
|
+
const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
|
|
241
371
|
|
|
242
|
-
phone_util
|
|
372
|
+
phone_util.GetRegionCodeForCountryCode(phone_number_info->phone_number->country_code(), &code);
|
|
243
373
|
|
|
244
374
|
VALUE result = rb_str_new(code.c_str(), code.size());
|
|
245
375
|
|
|
246
376
|
return rb_iv_set(self, "@region_code", result);
|
|
247
377
|
}
|
|
248
378
|
|
|
249
|
-
extern "C" VALUE rb_phone_number_country_code(VALUE self) {
|
|
250
|
-
if (rb_ivar_defined(self, rb_intern("@country_code"))) {
|
|
251
|
-
return rb_iv_get(self, "@country_code");
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
PhoneNumberInfo *phone_number_info;
|
|
255
|
-
Data_Get_Struct(self, PhoneNumberInfo, phone_number_info);
|
|
256
|
-
|
|
257
|
-
int code = phone_number_info->phone_number.country_code();
|
|
258
|
-
|
|
259
|
-
VALUE result = INT2NUM(code);
|
|
260
|
-
|
|
261
|
-
return rb_iv_set(self, "@country_code", result);
|
|
262
|
-
}
|
|
263
|
-
|
|
264
379
|
extern "C" VALUE rb_phone_number_eql_eh(VALUE self, VALUE other) {
|
|
265
380
|
if (!rb_obj_is_instance_of(other, rb_cPhoneNumber)) {
|
|
266
381
|
return Qfalse;
|
|
267
382
|
}
|
|
268
383
|
|
|
269
|
-
PhoneNumberUtil *
|
|
384
|
+
const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
|
|
270
385
|
|
|
271
386
|
PhoneNumberInfo *self_phone_number_info;
|
|
272
|
-
|
|
387
|
+
TypedData_Get_Struct(self, PhoneNumberInfo, &phone_number_info_type, self_phone_number_info);
|
|
273
388
|
|
|
274
389
|
PhoneNumberInfo *other_phone_number_info;
|
|
275
|
-
|
|
276
|
-
|
|
390
|
+
TypedData_Get_Struct(other, PhoneNumberInfo, &phone_number_info_type, other_phone_number_info);
|
|
391
|
+
|
|
392
|
+
if (phone_util.IsNumberMatch(*other_phone_number_info->phone_number, *self_phone_number_info->phone_number)) {
|
|
277
393
|
return Qtrue;
|
|
278
394
|
} else {
|
|
279
395
|
return Qfalse;
|
|
@@ -286,14 +402,14 @@ extern "C" VALUE rb_phone_number_type(VALUE self) {
|
|
|
286
402
|
}
|
|
287
403
|
|
|
288
404
|
PhoneNumberInfo *phone_number_info;
|
|
289
|
-
|
|
290
|
-
PhoneNumberUtil *
|
|
405
|
+
TypedData_Get_Struct(self, PhoneNumberInfo, &phone_number_info_type, phone_number_info);
|
|
406
|
+
const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
|
|
291
407
|
|
|
292
408
|
VALUE result;
|
|
293
409
|
|
|
294
410
|
// @see
|
|
295
411
|
// https://github.com/google/libphonenumber/blob/4e9954edea7cf263532c5dd3861a801104c3f012/cpp/src/phonenumbers/phonenumberutil.h#L91
|
|
296
|
-
switch (phone_util
|
|
412
|
+
switch (phone_util.GetNumberType(*phone_number_info->phone_number)) {
|
|
297
413
|
case PhoneNumberUtil::PREMIUM_RATE:
|
|
298
414
|
result = rb_intern("premium_rate");
|
|
299
415
|
break;
|
|
@@ -335,7 +451,50 @@ extern "C" VALUE rb_phone_number_type(VALUE self) {
|
|
|
335
451
|
return rb_iv_set(self, "@type", ID2SYM(result));
|
|
336
452
|
}
|
|
337
453
|
|
|
454
|
+
extern "C" VALUE rb_phone_number_area_code(VALUE self) {
|
|
455
|
+
if (rb_ivar_defined(self, rb_intern("@area_code"))) {
|
|
456
|
+
return rb_iv_get(self, "@area_code");
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
const PhoneNumberUtil &phone_util(*PhoneNumberUtil::GetInstance());
|
|
460
|
+
PhoneNumberInfo *phone_number_info;
|
|
461
|
+
TypedData_Get_Struct(self, PhoneNumberInfo, &phone_number_info_type, phone_number_info);
|
|
462
|
+
|
|
463
|
+
PhoneNumber *number = phone_number_info->phone_number;
|
|
464
|
+
string national_significant_number;
|
|
465
|
+
phone_util.GetNationalSignificantNumber(*number, &national_significant_number);
|
|
466
|
+
string area_code;
|
|
467
|
+
string subscriber_number;
|
|
468
|
+
|
|
469
|
+
int area_code_length = phone_util.GetLengthOfGeographicalAreaCode(*number);
|
|
470
|
+
if (area_code_length > 0) {
|
|
471
|
+
area_code = national_significant_number.substr(0, area_code_length);
|
|
472
|
+
subscriber_number = national_significant_number.substr(area_code_length, string::npos);
|
|
473
|
+
} else {
|
|
474
|
+
area_code = "";
|
|
475
|
+
subscriber_number = national_significant_number;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
VALUE result = rb_str_new(area_code.c_str(), area_code.size());
|
|
479
|
+
|
|
480
|
+
return rb_iv_set(self, "@area_code", result);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
static inline void setup_formats() {
|
|
484
|
+
// Raw
|
|
485
|
+
NumberFormat *raw_fmt = raw_national_format.Add();
|
|
486
|
+
raw_fmt->set_pattern("(\\d{3})(\\d{3})(\\d{4})");
|
|
487
|
+
raw_fmt->set_format("$1$2$3");
|
|
488
|
+
|
|
489
|
+
// Dasherized
|
|
490
|
+
NumberFormat *dsh_fmt = dasherized_national_format.Add();
|
|
491
|
+
dsh_fmt->set_pattern("(\\d{3})(\\d{3})(\\d{4})");
|
|
492
|
+
dsh_fmt->set_format("$1-$2-$3");
|
|
493
|
+
}
|
|
494
|
+
|
|
338
495
|
extern "C" void Init_mini_phone(void) {
|
|
496
|
+
setup_formats();
|
|
497
|
+
|
|
339
498
|
rb_mMiniPhone = rb_define_module("MiniPhone");
|
|
340
499
|
|
|
341
500
|
// Unknown
|
|
@@ -350,11 +509,13 @@ extern "C" void Init_mini_phone(void) {
|
|
|
350
509
|
rb_define_module_function(rb_mMiniPhone, "possible?", reinterpret_cast<VALUE (*)(...)>(rb_is_phone_number_valid), 1);
|
|
351
510
|
rb_define_module_function(rb_mMiniPhone, "impossible?", reinterpret_cast<VALUE (*)(...)>(rb_is_phone_number_invalid),
|
|
352
511
|
1);
|
|
353
|
-
rb_define_module_function(rb_mMiniPhone,
|
|
354
|
-
|
|
355
|
-
rb_define_module_function(rb_mMiniPhone, "default_country",
|
|
356
|
-
|
|
512
|
+
rb_define_module_function(rb_mMiniPhone, "default_country=", reinterpret_cast<VALUE (*)(...)>(rb_set_default_country),
|
|
513
|
+
1);
|
|
514
|
+
rb_define_module_function(rb_mMiniPhone, "default_country", reinterpret_cast<VALUE (*)(...)>(rb_get_default_country),
|
|
515
|
+
0);
|
|
357
516
|
rb_define_module_function(rb_mMiniPhone, "parse", reinterpret_cast<VALUE (*)(...)>(rb_phone_number_parse), -1);
|
|
517
|
+
rb_define_module_function(rb_mMiniPhone, "normalize_digits_only",
|
|
518
|
+
reinterpret_cast<VALUE (*)(...)>(rb_normalize_digits_only), 1);
|
|
358
519
|
|
|
359
520
|
rb_cPhoneNumber = rb_define_class_under(rb_mMiniPhone, "PhoneNumber", rb_cObject);
|
|
360
521
|
|
|
@@ -367,11 +528,21 @@ extern "C" void Init_mini_phone(void) {
|
|
|
367
528
|
rb_define_method(rb_cPhoneNumber, "impossible?", reinterpret_cast<VALUE (*)(...)>(rb_phone_number_impossible_eh), 0);
|
|
368
529
|
rb_define_method(rb_cPhoneNumber, "e164", reinterpret_cast<VALUE (*)(...)>(rb_phone_number_e164), 0);
|
|
369
530
|
rb_define_method(rb_cPhoneNumber, "national", reinterpret_cast<VALUE (*)(...)>(rb_phone_number_national), 0);
|
|
531
|
+
|
|
532
|
+
rb_define_method(rb_cPhoneNumber, "raw_national", reinterpret_cast<VALUE (*)(...)>(rb_phone_number_raw_national), 0);
|
|
533
|
+
rb_define_method(rb_cPhoneNumber, "raw_international",
|
|
534
|
+
reinterpret_cast<VALUE (*)(...)>(rb_phone_number_raw_international), 0);
|
|
535
|
+
rb_define_method(rb_cPhoneNumber, "dasherized_international",
|
|
536
|
+
reinterpret_cast<VALUE (*)(...)>(rb_phone_number_dasherized_international), 0);
|
|
537
|
+
rb_define_method(rb_cPhoneNumber, "dasherized_national",
|
|
538
|
+
reinterpret_cast<VALUE (*)(...)>(rb_phone_number_dasherized_national), 0);
|
|
370
539
|
rb_define_method(rb_cPhoneNumber, "international", reinterpret_cast<VALUE (*)(...)>(rb_phone_number_international),
|
|
371
540
|
0);
|
|
372
541
|
rb_define_method(rb_cPhoneNumber, "rfc3966", reinterpret_cast<VALUE (*)(...)>(rb_phone_number_rfc3966), 0);
|
|
373
542
|
rb_define_method(rb_cPhoneNumber, "region_code", reinterpret_cast<VALUE (*)(...)>(rb_phone_number_region_code), 0);
|
|
543
|
+
rb_define_method(rb_cPhoneNumber, "country", reinterpret_cast<VALUE (*)(...)>(rb_phone_number_region_code), 0);
|
|
374
544
|
rb_define_method(rb_cPhoneNumber, "country_code", reinterpret_cast<VALUE (*)(...)>(rb_phone_number_country_code), 0);
|
|
375
545
|
rb_define_method(rb_cPhoneNumber, "type", reinterpret_cast<VALUE (*)(...)>(rb_phone_number_type), 0);
|
|
546
|
+
rb_define_method(rb_cPhoneNumber, "area_code", reinterpret_cast<VALUE (*)(...)>(rb_phone_number_area_code), 0);
|
|
376
547
|
rb_define_method(rb_cPhoneNumber, "eql?", reinterpret_cast<VALUE (*)(...)>(rb_phone_number_eql_eh), 1);
|
|
377
548
|
}
|
data/lib/mini_phone/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mini_phone
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0
|
|
4
|
+
version: 1.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ian Ker-Seymer
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2021-01-
|
|
11
|
+
date: 2021-01-16 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: Plugs directly in the the Google's native C++ [libphonenumber](https://github.com/google/libphonenumber)
|
|
14
14
|
for extemely _fast_ and _robust_ phone number parsing, validation, and formatting.
|
|
@@ -22,10 +22,13 @@ extra_rdoc_files: []
|
|
|
22
22
|
files:
|
|
23
23
|
- CHANGELOG.md
|
|
24
24
|
- CODE_OF_CONDUCT.md
|
|
25
|
+
- Dockerfile.dev
|
|
25
26
|
- Gemfile
|
|
26
27
|
- LICENSE.txt
|
|
27
28
|
- README.md
|
|
28
29
|
- Rakefile
|
|
30
|
+
- debug/memory_plot/memory.rb
|
|
31
|
+
- debug/memory_plot/plot.sh
|
|
29
32
|
- ext/mini_phone/extconf.rb
|
|
30
33
|
- ext/mini_phone/mini_phone.cc
|
|
31
34
|
- ext/mini_phone/mini_phone.h
|