ruby_postal 0.3.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4f086499e7f616564eb1b1fad3434ee4dd054405
4
+ data.tar.gz: 500ba8273135f3efb36e2ef9a5ccbd8611b8e934
5
+ SHA512:
6
+ metadata.gz: 9698cada39c15abfe404155c8cf82a6b3c17ba7818e8736e0ca7e92d5fa62bd442fccf98b2beb58401035a935e0a92eab68ef54d7a54a73597d6ba9d53a45891
7
+ data.tar.gz: 0f4e2f17ec4593fda1b4e0107e1c45e4256fd1c1c1956089c12f6e6c1b8858f7af9c838fbc6e3e42405d688723b74b07c65b39db3481be7b17b9c219ce126fa5
@@ -0,0 +1,243 @@
1
+ #include <libpostal/libpostal.h>
2
+
3
+ #include <ruby.h>
4
+
5
+ #ifdef HAVE_RUBY_ENCODING_H
6
+ #include <ruby/encoding.h>
7
+ static rb_encoding *utf8Encoding;
8
+
9
+ #define ENCODED_STR_NEW2(str, encoding) \
10
+ ({ \
11
+ VALUE _string = rb_str_new2((const char *)str); \
12
+ int _enc = rb_enc_get_index(encoding); \
13
+ rb_enc_associate_index(_string, _enc); \
14
+ _string; \
15
+ })
16
+
17
+ #else
18
+
19
+ #define ENCODED_STR_NEW2(str, encoding) \
20
+ rb_str_new2((const char *)str)
21
+
22
+ #endif
23
+
24
+ /* Older versions of Ruby (< 1.8.6) need these */
25
+ #ifndef RSTRING_PTR
26
+ #define RSTRING_PTR(s) (RSTRING(s)->ptr)
27
+ #endif
28
+ #ifndef RSTRING_LEN
29
+ #define RSTRING_LEN(s) (RSTRING(s)->len)
30
+ #endif
31
+ #ifndef RARRAY_PTR
32
+ #define RARRAY_PTR(s) (RARRAY(s)->ptr)
33
+ #endif
34
+ #ifndef RARRAY_LEN
35
+ #define RARRAY_LEN(s) (RARRAY(s)->len)
36
+ #endif
37
+
38
+ VALUE rb_expand = Qnil;
39
+
40
+
41
+ VALUE hash_get_symbol_or_string(VALUE hash, char *key) {
42
+ VALUE value = rb_hash_aref(hash, rb_str_new2(key));
43
+
44
+ if (value != Qnil) {
45
+ return value;
46
+ }
47
+
48
+ return rb_hash_aref(hash, ID2SYM(rb_intern(key)));
49
+ }
50
+
51
+
52
+ VALUE rb_expand_address(int argc, VALUE *argv, VALUE self) {
53
+ if (argc < 2) { // there should only be 1 or 2 arguments
54
+ rb_raise(rb_eArgError, "Usage: expand_address(address, options = {})");
55
+ return Qnil;
56
+ }
57
+
58
+ VALUE input;
59
+ VALUE rb_options;
60
+
61
+ rb_scan_args(argc, argv, "2", &input, &rb_options);
62
+
63
+ if (TYPE(rb_options) != T_HASH) {
64
+ rb_raise(rb_eArgError, "options must be a hash");
65
+ return Qnil;
66
+ }
67
+
68
+ VALUE rb_languages = hash_get_symbol_or_string(rb_options, "languages");
69
+ if (rb_languages != Qnil && (TYPE(rb_languages) != T_ARRAY || RARRAY_LEN(rb_languages) == 0)) {
70
+ rb_raise(rb_eArgError, "options['languages'] must be a non-empty array");
71
+ return Qnil;
72
+ }
73
+
74
+ size_t len_languages = 0;
75
+
76
+ if (rb_languages != Qnil) {
77
+ len_languages = (size_t)RARRAY_LEN(rb_languages);
78
+ }
79
+
80
+ normalize_options_t options = get_libpostal_default_options();
81
+
82
+ size_t i;
83
+ char **languages = NULL;
84
+ size_t num_languages = 0;
85
+
86
+ if (len_languages > 0) {
87
+ languages = malloc(sizeof(char *) * len_languages);
88
+
89
+ for (i = 0; i < len_languages; i++) {
90
+ VALUE rb_lang = rb_ary_entry(rb_languages, (int)i);
91
+ if (rb_lang != Qnil && TYPE(rb_lang) == T_STRING) {
92
+ size_t rb_lang_len = RSTRING_LEN(rb_lang);
93
+ if (rb_lang_len > 0 && rb_lang_len < MAX_LANGUAGE_LEN) {
94
+ char *lang = RSTRING_PTR(rb_lang);
95
+ languages[num_languages++] = lang;
96
+ }
97
+ }
98
+ }
99
+ }
100
+
101
+ options.num_languages = num_languages;
102
+ options.languages = languages;
103
+
104
+ char *address = RSTRING_PTR(input);
105
+
106
+ VALUE address_components = hash_get_symbol_or_string(rb_options, "languages");
107
+ if (address_components != Qnil && TYPE(address_components) == T_FIXNUM) {
108
+ options.address_components = (uint16_t) NUM2UINT(address_components);
109
+ }
110
+
111
+ VALUE latin_ascii = hash_get_symbol_or_string(rb_options, "latin_ascii");
112
+ if (latin_ascii != Qnil) {
113
+ options.latin_ascii = RTEST(latin_ascii);
114
+ }
115
+
116
+ VALUE transliterate = hash_get_symbol_or_string(rb_options, "transliterate");
117
+ if (transliterate != Qnil) {
118
+ options.transliterate = RTEST(transliterate);
119
+ }
120
+
121
+ VALUE strip_accents = hash_get_symbol_or_string(rb_options, "strip_accents");
122
+ if (strip_accents != Qnil) {
123
+ options.strip_accents = RTEST(strip_accents);
124
+ }
125
+
126
+ VALUE decompose = hash_get_symbol_or_string(rb_options, "decompose");
127
+ if (decompose != Qnil) {
128
+ options.decompose = RTEST(decompose);
129
+ }
130
+
131
+ VALUE lowercase = hash_get_symbol_or_string(rb_options, "lowercase");
132
+ if (lowercase != Qnil) {
133
+ options.lowercase = RTEST(lowercase);
134
+ }
135
+
136
+ VALUE trim_string = hash_get_symbol_or_string(rb_options, "trim_string");
137
+ if (trim_string != Qnil) {
138
+ options.trim_string = RTEST(trim_string);
139
+ }
140
+
141
+ VALUE drop_parentheticals = hash_get_symbol_or_string(rb_options, "drop_parentheticals");
142
+ if (drop_parentheticals != Qnil) {
143
+ options.drop_parentheticals = RTEST(drop_parentheticals);
144
+ }
145
+
146
+ VALUE replace_numeric_hyphens = hash_get_symbol_or_string(rb_options, "replace_numeric_hyphens");
147
+ if (replace_numeric_hyphens != Qnil) {
148
+ options.replace_numeric_hyphens = RTEST(replace_numeric_hyphens);
149
+ }
150
+
151
+ VALUE delete_numeric_hyphens = hash_get_symbol_or_string(rb_options, "delete_numeric_hyphens");
152
+ if (delete_numeric_hyphens != Qnil) {
153
+ options.delete_numeric_hyphens = RTEST(delete_numeric_hyphens);
154
+ }
155
+
156
+ VALUE split_alpha_from_numeric = hash_get_symbol_or_string(rb_options, "split_alpha_from_numeric");
157
+ if (split_alpha_from_numeric != Qnil) {
158
+ options.split_alpha_from_numeric = RTEST(split_alpha_from_numeric);
159
+ }
160
+
161
+ VALUE replace_word_hyphens = hash_get_symbol_or_string(rb_options, "replace_word_hyphens");
162
+ if (replace_word_hyphens != Qnil) {
163
+ options.replace_word_hyphens = RTEST(replace_word_hyphens);
164
+ }
165
+
166
+ VALUE delete_word_hyphens = hash_get_symbol_or_string(rb_options, "delete_word_hyphens");
167
+ if (delete_word_hyphens != Qnil) {
168
+ options.delete_word_hyphens = RTEST(delete_word_hyphens);
169
+ }
170
+
171
+ VALUE delete_final_periods = hash_get_symbol_or_string(rb_options, "delete_final_periods");
172
+ if (delete_final_periods != Qnil) {
173
+ options.delete_final_periods = RTEST(delete_final_periods);
174
+ }
175
+
176
+
177
+ VALUE delete_acronym_periods = hash_get_symbol_or_string(rb_options, "delete_acronym_periods");
178
+ if (delete_acronym_periods != Qnil) {
179
+ options.delete_acronym_periods = RTEST(delete_acronym_periods);
180
+ }
181
+
182
+ VALUE drop_english_possessives = hash_get_symbol_or_string(rb_options, "drop_english_possessives");
183
+ if (drop_english_possessives != Qnil) {
184
+ options.drop_english_possessives = RTEST(drop_english_possessives);
185
+ }
186
+
187
+ VALUE delete_apostrophes = hash_get_symbol_or_string(rb_options, "delete_apostrophes");
188
+ if (delete_apostrophes != Qnil) {
189
+ options.delete_apostrophes = RTEST(delete_apostrophes);
190
+ }
191
+
192
+ VALUE expand_numex = hash_get_symbol_or_string(rb_options, "expand_numex");
193
+ if (expand_numex != Qnil) {
194
+ options.expand_numex = RTEST(expand_numex);
195
+ }
196
+
197
+ VALUE roman_numerals = hash_get_symbol_or_string(rb_options, "roman_numerals");
198
+ if (roman_numerals != Qnil) {
199
+ options.roman_numerals = RTEST(roman_numerals);
200
+ }
201
+
202
+ size_t num_expansions = 0;
203
+ char **expansions = expand_address(address, options, &num_expansions);
204
+
205
+ VALUE rb_expansions = rb_ary_new2(num_expansions);
206
+ for (size_t i = 0; i < num_expansions; i++) {
207
+ char *expansion = expansions[i];
208
+ VALUE rb_expansion = rb_str_new2(expansion);
209
+ rb_ary_store(rb_expansions, i, rb_expansion);
210
+ free(expansion);
211
+ }
212
+ free(expansions);
213
+
214
+ return rb_expansions;
215
+ }
216
+
217
+ void Init_expand() {
218
+ if (!libpostal_setup() || !libpostal_setup_language_classifier()) {
219
+ rb_raise(rb_eLoadError, "Could not load libpostal");
220
+ return;
221
+ }
222
+
223
+ rb_expand = rb_define_module("CExpand");
224
+
225
+ rb_define_module_function(rb_expand, "expand_address", rb_expand_address, -1);
226
+
227
+ rb_define_global_const("ADDRESS_NONE", UINT2NUM(ADDRESS_NONE));
228
+ rb_define_global_const("ADDRESS_ANY", UINT2NUM(ADDRESS_ANY));
229
+ rb_define_global_const("ADDRESS_NAME", UINT2NUM(ADDRESS_NAME));
230
+ rb_define_global_const("ADDRESS_HOUSE_NUMBER", UINT2NUM(ADDRESS_HOUSE_NUMBER));
231
+ rb_define_global_const("ADDRESS_STREET", UINT2NUM(ADDRESS_STREET));
232
+ rb_define_global_const("ADDRESS_UNIT", UINT2NUM(ADDRESS_UNIT));
233
+ rb_define_global_const("ADDRESS_LOCALITY", UINT2NUM(ADDRESS_LOCALITY));
234
+ rb_define_global_const("ADDRESS_ADMIN1", UINT2NUM(ADDRESS_ADMIN1));
235
+ rb_define_global_const("ADDRESS_ADMIN2", UINT2NUM(ADDRESS_ADMIN2));
236
+ rb_define_global_const("ADDRESS_ADMIN3", UINT2NUM(ADDRESS_ADMIN3));
237
+ rb_define_global_const("ADDRESS_ADMIN4", UINT2NUM(ADDRESS_ADMIN4));
238
+ rb_define_global_const("ADDRESS_ADMIN_OTHER", UINT2NUM(ADDRESS_ADMIN_OTHER));
239
+ rb_define_global_const("ADDRESS_POSTAL_CODE", UINT2NUM(ADDRESS_POSTAL_CODE));
240
+ rb_define_global_const("ADDRESS_NEIGHBORHOOD", UINT2NUM(ADDRESS_NEIGHBORHOOD));
241
+ rb_define_global_const("ADDRESS_ALL", UINT2NUM(ADDRESS_ALL));
242
+ }
243
+
@@ -0,0 +1,40 @@
1
+ require 'mkmf'
2
+ require 'rbconfig'
3
+
4
+ LIBDIR = RbConfig::CONFIG['libdir']
5
+ INCLUDEDIR = RbConfig::CONFIG['includedir']
6
+
7
+ HEADER_DIRS = [
8
+ # First search /opt/local for macports
9
+ '/opt/local/include',
10
+
11
+ # Then search /usr/local for people that installed from source
12
+ '/usr/local/include',
13
+
14
+ # Check the ruby install locations
15
+ INCLUDEDIR,
16
+
17
+ # Finally fall back to /usr
18
+ '/usr/include',
19
+ ]
20
+
21
+ LIB_DIRS = [
22
+ # First search /opt/local for macports
23
+ '/opt/local/lib',
24
+
25
+ # Then search /usr/local for people that installed from source
26
+ '/usr/local/lib',
27
+
28
+ # Check the ruby install locations
29
+ LIBDIR,
30
+
31
+ # Finally fall back to /usr
32
+ '/usr/lib',
33
+ ]
34
+
35
+ dir_config('libpostal', HEADER_DIRS, LIB_DIRS)
36
+
37
+ $CFLAGS << " -std=gnu99"
38
+ $LIBS << " -lpostal"
39
+
40
+ create_makefile('cpostal/expand')
@@ -0,0 +1,40 @@
1
+ require 'mkmf'
2
+ require 'rbconfig'
3
+
4
+ LIBDIR = RbConfig::CONFIG['libdir']
5
+ INCLUDEDIR = RbConfig::CONFIG['includedir']
6
+
7
+ HEADER_DIRS = [
8
+ # First search /opt/local for macports
9
+ '/opt/local/include',
10
+
11
+ # Then search /usr/local for people that installed from source
12
+ '/usr/local/include',
13
+
14
+ # Check the ruby install locations
15
+ INCLUDEDIR,
16
+
17
+ # Finally fall back to /usr
18
+ '/usr/include',
19
+ ]
20
+
21
+ LIB_DIRS = [
22
+ # First search /opt/local for macports
23
+ '/opt/local/lib',
24
+
25
+ # Then search /usr/local for people that installed from source
26
+ '/usr/local/lib',
27
+
28
+ # Check the ruby install locations
29
+ LIBDIR,
30
+
31
+ # Finally fall back to /usr
32
+ '/usr/lib',
33
+ ]
34
+
35
+ dir_config('libpostal', HEADER_DIRS, LIB_DIRS)
36
+
37
+ $CFLAGS << " -std=gnu99"
38
+ $LIBS << " -lpostal"
39
+
40
+ create_makefile('cpostal/parser')
@@ -0,0 +1,112 @@
1
+ #include <libpostal/libpostal.h>
2
+
3
+ #include <ruby.h>
4
+
5
+ #ifdef HAVE_RUBY_ENCODING_H
6
+ #include <ruby/encoding.h>
7
+ static rb_encoding *utf8Encoding;
8
+
9
+ #define ENCODED_STR_NEW2(str, encoding) \
10
+ ({ \
11
+ VALUE _string = rb_str_new2((const char *)str); \
12
+ int _enc = rb_enc_get_index(encoding); \
13
+ rb_enc_associate_index(_string, _enc); \
14
+ _string; \
15
+ })
16
+
17
+ #else
18
+
19
+ #define ENCODED_STR_NEW2(str, encoding) \
20
+ rb_str_new2((const char *)str)
21
+
22
+ #endif
23
+
24
+ /* Older versions of Ruby (< 1.8.6) need these */
25
+ #ifndef RSTRING_PTR
26
+ #define RSTRING_PTR(s) (RSTRING(s)->ptr)
27
+ #endif
28
+ #ifndef RSTRING_LEN
29
+ #define RSTRING_LEN(s) (RSTRING(s)->len)
30
+ #endif
31
+ #ifndef RARRAY_PTR
32
+ #define RARRAY_PTR(s) (RARRAY(s)->ptr)
33
+ #endif
34
+ #ifndef RARRAY_LEN
35
+ #define RARRAY_LEN(s) (RARRAY(s)->len)
36
+ #endif
37
+
38
+ VALUE rb_parser = Qnil;
39
+
40
+ VALUE hash_get_symbol_or_string(VALUE hash, char *key) {
41
+ VALUE value = rb_hash_aref(hash, rb_str_new2(key));
42
+
43
+ if (value != Qnil) {
44
+ return value;
45
+ }
46
+
47
+ return rb_hash_aref(hash, ID2SYM(rb_intern(key)));
48
+ }
49
+
50
+
51
+ VALUE rb_parse_address(int argc, VALUE *argv, VALUE self) {
52
+ if (argc < 2) { // there should only be 1 or 2 arguments
53
+ rb_raise(rb_eArgError, "Usage: parse_address(address, options = {})");
54
+ }
55
+
56
+ VALUE input;
57
+ VALUE rb_options;
58
+
59
+ rb_scan_args(argc, argv, "2", &input, &rb_options);
60
+
61
+ if (TYPE(rb_options) != T_HASH) {
62
+ rb_raise(rb_eArgError, "options must be a hash");
63
+ return Qnil;
64
+ }
65
+
66
+ VALUE rb_language = hash_get_symbol_or_string(rb_options, "language");
67
+ VALUE rb_country = hash_get_symbol_or_string(rb_options, "country");
68
+
69
+ char *address = RSTRING_PTR(input);
70
+
71
+ address_parser_response_t *parsed;
72
+ address_parser_options_t options = get_libpostal_address_parser_default_options();
73
+ if (rb_language != Qnil) {
74
+ options.language = RSTRING_PTR(rb_language);
75
+ }
76
+
77
+ if (rb_country != Qnil) {
78
+ options.country = RSTRING_PTR(rb_country);
79
+ }
80
+
81
+ if ((parsed = parse_address(address, options))) {
82
+ size_t n = parsed->num_components;
83
+ VALUE rb_parse_result = rb_ary_new2(n);
84
+
85
+ for (size_t i = 0; i < n; i++) {
86
+ VALUE rb_component = rb_ary_new2(2);
87
+ rb_ary_store(rb_component, 0, rb_str_new2(parsed->components[i]));
88
+ rb_ary_store(rb_component, 1, ID2SYM(rb_intern(parsed->labels[i])));
89
+
90
+ rb_ary_store(rb_parse_result, i, rb_component);
91
+ }
92
+
93
+ address_parser_response_destroy(parsed);
94
+
95
+ return rb_parse_result;
96
+ }
97
+
98
+ return Qnil;
99
+
100
+ }
101
+
102
+ void Init_parser() {
103
+ if (!libpostal_setup() || !libpostal_setup_parser()) {
104
+ rb_raise(rb_eLoadError, "Could not load libpostal");
105
+ return;
106
+ }
107
+
108
+ rb_parser = rb_define_module("CParser");
109
+
110
+ rb_define_module_function(rb_parser, "parse_address", rb_parse_address, -1);
111
+ }
112
+
data/ext/rb_utils.c ADDED
@@ -0,0 +1,11 @@
1
+ #include "rb_utils.h"
2
+
3
+ VALUE hash_get_symbol_or_string(VALUE hash, char *key) {
4
+ VALUE value = rb_hash_aref(hash, rb_str_new2(key));
5
+
6
+ if (value != Qnil) {
7
+ return value;
8
+ }
9
+
10
+ return rb_hash_aref(hash, ID2SYM(rb_intern(key)));
11
+ }
@@ -0,0 +1,5 @@
1
+ require "ruby_postal/version"
2
+
3
+ module Postal
4
+
5
+ end
@@ -0,0 +1,9 @@
1
+ require 'ruby_postal/cpostal/expand'
2
+
3
+ module Postal
4
+ class Expand
5
+ def self.expand_address(address, options={})
6
+ CExpand.expand_address address, options
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ require 'ruby_postal/cpostal/parser'
2
+
3
+ module Postal
4
+ class Parser
5
+ def self.parse_address(address, options={})
6
+ parse_result = CParser.parse_address address, options
7
+ parse_result.map{|s, c| {:label => c, :value => s}}
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,3 @@
1
+ module Postal
2
+ VERSION = "0.3.0"
3
+ end
metadata ADDED
@@ -0,0 +1,113 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby_postal
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ platform: ruby
6
+ authors:
7
+ - Al Barrentine
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-03-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake-compiler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description:
70
+ email:
71
+ - pelias@mapzen.com
72
+ executables: []
73
+ extensions:
74
+ - ext/expand/extconf.rb
75
+ - ext/parser/extconf.rb
76
+ extra_rdoc_files: []
77
+ files:
78
+ - ext/expand/expand.c
79
+ - ext/expand/extconf.rb
80
+ - ext/parser/extconf.rb
81
+ - ext/parser/parser.c
82
+ - ext/rb_utils.c
83
+ - lib/ruby_postal.rb
84
+ - lib/ruby_postal/expand.rb
85
+ - lib/ruby_postal/parser.rb
86
+ - lib/ruby_postal/version.rb
87
+ homepage: https://github.com/openvenues/ruby_postal
88
+ licenses:
89
+ - MIT
90
+ metadata:
91
+ allowed_push_host: https://rubygems.org
92
+ post_install_message:
93
+ rdoc_options: []
94
+ require_paths:
95
+ - lib
96
+ - ext
97
+ required_ruby_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ requirements: []
108
+ rubyforge_project:
109
+ rubygems_version: 2.4.1
110
+ signing_key:
111
+ specification_version: 4
112
+ summary: Ruby bindings for libpostal (fast address parsing/normalization)
113
+ test_files: []