countries 4.2.3 → 5.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/codeql-analysis.yml +70 -0
- data/.github/workflows/tests.yml +1 -5
- data/.rubocop.yml +40 -1
- data/.rubocop_todo.yml +8 -41
- data/CHANGELOG.md +7 -2
- data/Gemfile +5 -3
- data/README.markdown +22 -5
- data/Rakefile +13 -31
- data/bin/console +1 -0
- data/countries.gemspec +7 -5
- data/lib/countries/cache/countries.json +1 -1
- data/lib/countries/configuration.rb +2 -0
- data/lib/countries/country/class_methods.rb +12 -97
- data/lib/countries/country/currency_methods.rb +2 -0
- data/lib/countries/country/emoji.rb +2 -3
- data/lib/countries/country/finder_methods.rb +81 -0
- data/lib/countries/country.rb +3 -40
- data/lib/countries/data/countries/KN.yaml +0 -1
- data/lib/countries/data.rb +34 -37
- data/lib/countries/global.rb +2 -0
- data/lib/countries/iso3166.rb +3 -0
- data/lib/countries/kwarg_struct.rb +2 -0
- data/lib/countries/mongoid.rb +2 -0
- data/lib/countries/sources/cldr/downloader.rb +8 -8
- data/lib/countries/sources/cldr/subdivision.rb +3 -0
- data/lib/countries/sources/cldr/subdivision_updater.rb +23 -17
- data/lib/countries/sources/local/cached_loader.rb +3 -0
- data/lib/countries/sources/local/subdivision.rb +5 -2
- data/lib/countries/sources.rb +2 -0
- data/lib/countries/structure.rb +1 -1
- data/lib/countries/subdivision.rb +2 -0
- data/lib/countries/tasks/geocoding.rake +15 -6
- data/lib/countries/tasks/postal_codes.rake +5 -3
- data/lib/countries/timezones.rb +5 -2
- data/lib/countries/translations.rb +2 -0
- data/lib/countries/version.rb +3 -1
- data/lib/countries.rb +2 -0
- data/spec/00_global_spec.rb +2 -0
- data/spec/configuration_spec.rb +11 -5
- data/spec/country_spec.rb +71 -22
- data/spec/data_spec.rb +24 -18
- data/spec/mongoid_spec.rb +2 -2
- data/spec/perf_spec.rb +16 -16
- data/spec/spec_helper.rb +2 -0
- data/spec/subdivision_spec.rb +6 -4
- data/spec/thread_safety_spec.rb +4 -3
- data/spec/timezone_spec.rb +2 -0
- metadata +14 -12
- data/lib/countries/setup.rb +0 -18
@@ -1,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'sixarm_ruby_unaccent'
|
2
4
|
|
3
5
|
module ISO3166
|
4
6
|
UNSEARCHABLE_METHODS = [:translations].freeze
|
5
7
|
|
6
|
-
def self
|
8
|
+
def self.Country(country_data_or_country)
|
7
9
|
case country_data_or_country
|
8
10
|
when ISO3166::Country
|
9
11
|
country_data_or_country
|
@@ -15,9 +17,6 @@ module ISO3166
|
|
15
17
|
end
|
16
18
|
|
17
19
|
module CountryClassMethods
|
18
|
-
FIND_BY_REGEX = /^find_(all_)?(country_|countries_)?by_(.+)/
|
19
|
-
SEARCH_TERM_FILTER_REGEX = /\(|\)|\[\]|,/
|
20
|
-
|
21
20
|
def new(country_data)
|
22
21
|
super if country_data.is_a?(Hash) || codes.include?(country_data.to_s.upcase)
|
23
22
|
end
|
@@ -33,10 +32,6 @@ module ISO3166
|
|
33
32
|
|
34
33
|
alias countries all
|
35
34
|
|
36
|
-
def all_translated(locale = 'en')
|
37
|
-
translations(locale).values
|
38
|
-
end
|
39
|
-
|
40
35
|
def all_names_with_codes(locale = 'en')
|
41
36
|
Country.all.map do |c|
|
42
37
|
lc = (c.translation(locale) || c.iso_short_name)
|
@@ -50,6 +45,10 @@ module ISO3166
|
|
50
45
|
end
|
51
46
|
end
|
52
47
|
|
48
|
+
def all_translated(locale = 'en')
|
49
|
+
translations(locale).values
|
50
|
+
end
|
51
|
+
|
53
52
|
def translations(locale = 'en')
|
54
53
|
i18n_data_countries = I18nData.countries(locale.upcase)
|
55
54
|
|
@@ -62,54 +61,6 @@ module ISO3166
|
|
62
61
|
i18n_data_countries.merge(custom_countries)
|
63
62
|
end
|
64
63
|
|
65
|
-
def search(query)
|
66
|
-
country = new(query.to_s.upcase)
|
67
|
-
country && country.valid? ? country : nil
|
68
|
-
end
|
69
|
-
|
70
|
-
def [](query)
|
71
|
-
search(query)
|
72
|
-
end
|
73
|
-
|
74
|
-
def method_missing(method_name, *arguments)
|
75
|
-
matches = method_name.to_s.match(FIND_BY_REGEX)
|
76
|
-
return_all = matches[1]
|
77
|
-
super unless matches
|
78
|
-
|
79
|
-
if matches[3] == 'names'
|
80
|
-
if RUBY_VERSION =~ /^3\.\d\.\d/
|
81
|
-
warn "DEPRECATION WARNING: 'find_by_name' and 'find_*_by_name' methods are deprecated, please refer to the README file for more information on this change.", uplevel: 1, category: :deprecated
|
82
|
-
else
|
83
|
-
warn "DEPRECATION WARNING: 'find_by_name' and 'find_*_by_name' methods are deprecated, please refer to the README file for more information on this change.", uplevel: 1
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
countries = find_by(matches[3], arguments[0], matches[2])
|
88
|
-
return_all ? countries : countries.last
|
89
|
-
end
|
90
|
-
|
91
|
-
def respond_to_missing?(method_name, include_private = false)
|
92
|
-
matches = method_name.to_s.match(FIND_BY_REGEX)
|
93
|
-
if matches && matches[3]
|
94
|
-
instance_methods.include?(matches[3].to_sym)
|
95
|
-
else
|
96
|
-
super
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
def find_all_by(attribute, val)
|
101
|
-
attributes, lookup_value = parse_attributes(attribute, val)
|
102
|
-
|
103
|
-
ISO3166::Data.cache.select do |_, v|
|
104
|
-
country = Country.new(v)
|
105
|
-
attributes.any? do |attr|
|
106
|
-
Array(country.send(attr)).any? do |n|
|
107
|
-
lookup_value === cached(n) { parse_value(n) }
|
108
|
-
end
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
64
|
def subdivisions(alpha2)
|
114
65
|
@subdivisions ||= {}
|
115
66
|
@subdivisions[alpha2] ||= create_subdivisions(subdivision_data(alpha2))
|
@@ -124,51 +75,14 @@ module ISO3166
|
|
124
75
|
|
125
76
|
protected
|
126
77
|
|
127
|
-
def strip_accents(
|
128
|
-
if
|
129
|
-
Regexp.new(
|
78
|
+
def strip_accents(string)
|
79
|
+
if string.is_a?(Regexp)
|
80
|
+
Regexp.new(string.source.unaccent, 'i')
|
130
81
|
else
|
131
|
-
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
def parse_attributes(attribute, val)
|
136
|
-
raise "Invalid attribute name '#{attribute}'" unless searchable_attribute?(attribute.to_sym)
|
137
|
-
|
138
|
-
attributes = Array(attribute.to_s)
|
139
|
-
if attribute.to_s == 'name'
|
140
|
-
if RUBY_VERSION =~ /^3\.\d\.\d/
|
141
|
-
warn "DEPRECATION WARNING: 'find_by_name' and 'find_*_by_name' methods are deprecated, please refer to the README file for more information on this change.", uplevel: 1, category: :deprecated
|
142
|
-
else
|
143
|
-
warn "DEPRECATION WARNING: 'find_by_name' and 'find_*_by_name' methods are deprecated, please refer to the README file for more information on this change.", uplevel: 1
|
144
|
-
end
|
145
|
-
# 'find_by_name' and 'find_*_by_name' will be changed for 5.0
|
146
|
-
# The addition of 'iso_short_name' here ensures the behaviour of 4.1 is kept for 4.2
|
147
|
-
attributes = %w[iso_short_name unofficial_names translated_names]
|
148
|
-
end
|
149
|
-
|
150
|
-
[attributes, parse_value(val)]
|
151
|
-
end
|
152
|
-
|
153
|
-
def searchable_attribute?(attribute)
|
154
|
-
searchable_attributes.include?(attribute.to_sym)
|
155
|
-
end
|
156
|
-
|
157
|
-
def searchable_attributes
|
158
|
-
instance_methods - UNSEARCHABLE_METHODS
|
159
|
-
end
|
160
|
-
|
161
|
-
def find_by(attribute, value, obj = nil)
|
162
|
-
find_all_by(attribute.downcase, value).map do |country|
|
163
|
-
obj.nil? ? country : new(country.last)
|
82
|
+
string.to_s.unaccent.downcase
|
164
83
|
end
|
165
84
|
end
|
166
85
|
|
167
|
-
def parse_value(value)
|
168
|
-
value = value.gsub(SEARCH_TERM_FILTER_REGEX, '') if value.respond_to?(:gsub)
|
169
|
-
strip_accents(value)
|
170
|
-
end
|
171
|
-
|
172
86
|
def subdivision_data(alpha2)
|
173
87
|
file = subdivision_file_path(alpha2)
|
174
88
|
File.exist?(file) ? YAML.load_file(file) : {}
|
@@ -190,6 +104,7 @@ module ISO3166
|
|
190
104
|
def cached(value)
|
191
105
|
@_parsed_values_cache ||= {}
|
192
106
|
return @_parsed_values_cache[value] if @_parsed_values_cache[value]
|
107
|
+
|
193
108
|
@_parsed_values_cache[value] = yield
|
194
109
|
end
|
195
110
|
end
|
@@ -1,5 +1,4 @@
|
|
1
|
-
|
2
|
-
# encoding: utf-8
|
1
|
+
# frozen_string_literal: true
|
3
2
|
|
4
3
|
module ISO3166
|
5
4
|
module Emoji
|
@@ -36,7 +35,7 @@ module ISO3166
|
|
36
35
|
#
|
37
36
|
# The emoji flag for this country, using Unicode Regional Indicator characters. e.g: "U+1F1FA U+1F1F8" for 🇺🇸
|
38
37
|
def emoji_flag
|
39
|
-
alpha2.downcase.chars.map { |c| CODE_POINTS[c] }.join
|
38
|
+
alpha2.downcase.chars.map { |c| CODE_POINTS[c] }.join
|
40
39
|
end
|
41
40
|
end
|
42
41
|
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ISO3166
|
4
|
+
module CountryFinderMethods
|
5
|
+
FIND_BY_REGEX = /^find_(all_)?(country_|countries_)?by_(.+)/.freeze
|
6
|
+
SEARCH_TERM_FILTER_REGEX = /\(|\)|\[\]|,/.freeze
|
7
|
+
|
8
|
+
def search(query)
|
9
|
+
country = new(query.to_s.upcase)
|
10
|
+
country&.valid? ? country : nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def [](query)
|
14
|
+
search(query)
|
15
|
+
end
|
16
|
+
|
17
|
+
def find_all_by(attribute, val)
|
18
|
+
attributes, lookup_value = parse_attributes(attribute, val)
|
19
|
+
|
20
|
+
ISO3166::Data.cache.select do |_, v|
|
21
|
+
country = Country.new(v)
|
22
|
+
attributes.any? do |attr|
|
23
|
+
Array(country.send(attr)).any? do |n|
|
24
|
+
lookup_value === cached(n) { parse_value(n) }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def method_missing(method_name, *arguments)
|
31
|
+
matches = method_name.to_s.match(FIND_BY_REGEX)
|
32
|
+
return_all = matches[1]
|
33
|
+
super unless matches
|
34
|
+
|
35
|
+
countries = find_by(matches[3], arguments[0], matches[2])
|
36
|
+
return_all ? countries : countries.last
|
37
|
+
end
|
38
|
+
|
39
|
+
def respond_to_missing?(method_name, include_private = false)
|
40
|
+
matches = method_name.to_s.match(FIND_BY_REGEX)
|
41
|
+
if matches && matches[3]
|
42
|
+
instance_methods.include?(matches[3].to_sym)
|
43
|
+
else
|
44
|
+
super
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
protected
|
49
|
+
|
50
|
+
def find_by(attribute, value, obj = nil)
|
51
|
+
find_all_by(attribute.downcase, value).map do |country|
|
52
|
+
obj.nil? ? country : new(country.last)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def parse_attributes(attribute, val)
|
57
|
+
raise "Invalid attribute name '#{attribute}'" unless searchable_attribute?(attribute.to_sym)
|
58
|
+
|
59
|
+
attributes = Array(attribute.to_s)
|
60
|
+
if attribute.to_s == 'any_name'
|
61
|
+
attributes = %w[iso_long_name iso_short_name unofficial_names translated_names]
|
62
|
+
end
|
63
|
+
|
64
|
+
[attributes, parse_value(val)]
|
65
|
+
end
|
66
|
+
|
67
|
+
def parse_value(value)
|
68
|
+
value = value.gsub(SEARCH_TERM_FILTER_REGEX, '') if value.respond_to?(:gsub)
|
69
|
+
strip_accents(value)
|
70
|
+
end
|
71
|
+
|
72
|
+
def searchable_attribute?(attribute)
|
73
|
+
searchable_attributes.include?(attribute.to_sym)
|
74
|
+
end
|
75
|
+
|
76
|
+
def searchable_attributes
|
77
|
+
# Add name and names until we complete the deprecation of the finders
|
78
|
+
instance_methods - UNSEARCHABLE_METHODS + [:name, :names, :any_name]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
data/lib/countries/country.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ISO3166
|
2
4
|
class Country
|
3
5
|
extend CountryClassMethods
|
6
|
+
extend CountryFinderMethods
|
4
7
|
include Emoji
|
5
8
|
attr_reader :data
|
6
9
|
|
@@ -31,24 +34,6 @@ module ISO3166
|
|
31
34
|
alias zip_format postal_code_format
|
32
35
|
alias languages languages_official
|
33
36
|
|
34
|
-
def latitude_dec
|
35
|
-
if RUBY_VERSION =~ /^3\.\d\.\d/
|
36
|
-
warn "DEPRECATION WARNING: The Country#latitude_dec method has been deprecated and will be removed in 5.0. Please use Country#latitude instead.", uplevel: 1, category: :deprecated
|
37
|
-
else
|
38
|
-
warn "DEPRECATION WARNING: The Country#latitude_dec method has been deprecated and will be removed in 5.0. Please use Country#latitude instead.", uplevel: 1
|
39
|
-
end
|
40
|
-
latitude
|
41
|
-
end
|
42
|
-
|
43
|
-
def longitude_dec
|
44
|
-
if RUBY_VERSION =~ /^3\.\d\.\d/
|
45
|
-
warn "DEPRECATION WARNING: The Country#longitude_dec method has been deprecated and will be removed in 5.0. Please use Country#longitude instead.", uplevel: 1, category: :deprecated
|
46
|
-
else
|
47
|
-
warn "DEPRECATION WARNING: The Country#longitude_dec method has been deprecated and will be removed in 5.0. Please use Country#longitude instead.", uplevel: 1
|
48
|
-
end
|
49
|
-
longitude
|
50
|
-
end
|
51
|
-
|
52
37
|
def ==(other)
|
53
38
|
other.respond_to?(:alpha2) && other.alpha2 == alpha2
|
54
39
|
end
|
@@ -136,28 +121,6 @@ module ISO3166
|
|
136
121
|
@local_name ||= local_names.first
|
137
122
|
end
|
138
123
|
|
139
|
-
# @return [String] This Country's ISO Short Name
|
140
|
-
# @deprecated Use {#iso_short_name} instead.
|
141
|
-
def name
|
142
|
-
if RUBY_VERSION =~ /^3\.\d\.\d/
|
143
|
-
warn "DEPRECATION WARNING: The Country#name method has been deprecated. Please use Country#iso_short_name instead or refer to the README file for more information on this change.", uplevel: 1, category: :deprecated
|
144
|
-
else
|
145
|
-
warn "DEPRECATION WARNING: The Country#name method has been deprecated. Please use Country#iso_short_name instead or refer to the README file for more information on this change.", uplevel: 1
|
146
|
-
end
|
147
|
-
iso_short_name
|
148
|
-
end
|
149
|
-
|
150
|
-
# @return [Array<String>] Array of unofficial, slang names or aliases for this Country
|
151
|
-
# @deprecated Use {#unofficial_names} instead.
|
152
|
-
def names
|
153
|
-
if RUBY_VERSION =~ /^3\.\d\.\d/
|
154
|
-
warn "DEPRECATION WARNING: The Country#names method has been deprecated. Please use Country#unofficial_names instead or refer to the README file for more information on this change.", uplevel: 1, category: :deprecated
|
155
|
-
else
|
156
|
-
warn "DEPRECATION WARNING: The Country#names method has been deprecated. Please use Country#unofficial_names instead or refer to the README file for more information on this change.", uplevel: 1
|
157
|
-
end
|
158
|
-
unofficial_names
|
159
|
-
end
|
160
|
-
|
161
124
|
# @!attribute alpha2
|
162
125
|
# @return [String] the ISO3166 alpha-2 code for this Country
|
163
126
|
#
|
data/lib/countries/data.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ISO3166
|
2
4
|
# Handles building the in memory store of countries data
|
3
5
|
class Data
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
6
|
+
@cache_dir = [File.dirname(__FILE__), 'cache']
|
7
|
+
@cache = {}
|
8
|
+
@registered_data = {}
|
9
|
+
@mutex = Mutex.new
|
8
10
|
|
9
11
|
def initialize(alpha2)
|
10
12
|
@alpha2 = alpha2.to_s.upcase
|
@@ -15,30 +17,23 @@ module ISO3166
|
|
15
17
|
end
|
16
18
|
|
17
19
|
class << self
|
18
|
-
def cache_dir
|
19
|
-
@@cache_dir
|
20
|
-
end
|
21
|
-
|
22
|
-
def cache_dir=(value)
|
23
|
-
@@cache_dir = value
|
24
|
-
end
|
25
20
|
|
26
21
|
# Registers a new Country with custom data.
|
27
22
|
# If you are overriding an existing country, this does not perform a deep merge so you will need to __bring in all data you wish to be available__.
|
28
23
|
# Overriding an existing country will also remove it from the internal management of translations.
|
29
24
|
def register(data)
|
30
25
|
alpha2 = data[:alpha2].upcase
|
31
|
-
|
32
|
-
|
26
|
+
@registered_data[alpha2] = deep_stringify_keys(data)
|
27
|
+
@registered_data[alpha2]['translations'] = \
|
33
28
|
Translations.new.merge(data['translations'] || {})
|
34
|
-
|
29
|
+
@cache = cache.merge(@registered_data)
|
35
30
|
end
|
36
31
|
|
37
32
|
# Removes a country from the loaded data
|
38
33
|
def unregister(alpha2)
|
39
34
|
alpha2 = alpha2.to_s.upcase
|
40
|
-
|
41
|
-
|
35
|
+
@cache.delete(alpha2)
|
36
|
+
@registered_data.delete(alpha2)
|
42
37
|
end
|
43
38
|
|
44
39
|
def cache
|
@@ -47,8 +42,8 @@ module ISO3166
|
|
47
42
|
|
48
43
|
# Resets the loaded data and cache
|
49
44
|
def reset
|
50
|
-
|
51
|
-
|
45
|
+
@cache = {}
|
46
|
+
@registered_data = {}
|
52
47
|
ISO3166.configuration.loaded_locales = []
|
53
48
|
end
|
54
49
|
|
@@ -60,16 +55,19 @@ module ISO3166
|
|
60
55
|
def update_cache
|
61
56
|
load_data!
|
62
57
|
sync_translations!
|
63
|
-
|
58
|
+
@cache
|
64
59
|
end
|
65
60
|
|
61
|
+
private
|
62
|
+
|
66
63
|
def load_data!
|
67
|
-
return
|
64
|
+
return @cache unless load_required?
|
65
|
+
|
68
66
|
synchronized do
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
67
|
+
@cache = load_cache %w[countries.json]
|
68
|
+
@_country_codes = @cache.keys
|
69
|
+
@cache = @cache.merge(@registered_data)
|
70
|
+
@cache
|
73
71
|
end
|
74
72
|
end
|
75
73
|
|
@@ -85,11 +83,9 @@ module ISO3166
|
|
85
83
|
end
|
86
84
|
end
|
87
85
|
|
88
|
-
private
|
89
|
-
|
90
86
|
def synchronized(&block)
|
91
87
|
if use_mutex?
|
92
|
-
|
88
|
+
@mutex.synchronize(&block)
|
93
89
|
else
|
94
90
|
block.call
|
95
91
|
end
|
@@ -102,17 +98,17 @@ module ISO3166
|
|
102
98
|
|
103
99
|
def load_required?
|
104
100
|
synchronized do
|
105
|
-
|
101
|
+
@cache.empty?
|
106
102
|
end
|
107
103
|
end
|
108
104
|
|
109
105
|
def loaded_codes
|
110
|
-
|
106
|
+
@cache.keys
|
111
107
|
end
|
112
108
|
|
113
109
|
# Codes that we have translations for in dataset
|
114
110
|
def internal_codes
|
115
|
-
|
111
|
+
@_country_codes - @registered_data.keys
|
116
112
|
end
|
117
113
|
|
118
114
|
def cache_flush_required?
|
@@ -139,9 +135,9 @@ module ISO3166
|
|
139
135
|
synchronized do
|
140
136
|
locale_names = load_cache(['locales', "#{locale}.json"])
|
141
137
|
internal_codes.each do |alpha2|
|
142
|
-
|
143
|
-
|
144
|
-
|
138
|
+
@cache[alpha2]['translations'] ||= Translations.new
|
139
|
+
@cache[alpha2]['translations'][locale] = locale_names[alpha2].freeze
|
140
|
+
@cache[alpha2]['translated_names'] = @cache[alpha2]['translations'].values.freeze
|
145
141
|
end
|
146
142
|
ISO3166.configuration.loaded_locales << locale
|
147
143
|
end
|
@@ -150,8 +146,8 @@ module ISO3166
|
|
150
146
|
def unload_translations(locale)
|
151
147
|
synchronized do
|
152
148
|
internal_codes.each do |alpha2|
|
153
|
-
|
154
|
-
|
149
|
+
@cache[alpha2]['translations'].delete(locale)
|
150
|
+
@cache[alpha2]['translated_names'] = @cache[alpha2]['translations'].values.freeze
|
155
151
|
end
|
156
152
|
ISO3166.configuration.loaded_locales.delete(locale)
|
157
153
|
end
|
@@ -163,7 +159,7 @@ module ISO3166
|
|
163
159
|
end
|
164
160
|
|
165
161
|
def datafile_path(file_array)
|
166
|
-
File.join([
|
162
|
+
File.join([@cache_dir] + file_array)
|
167
163
|
end
|
168
164
|
|
169
165
|
def deep_stringify_keys(data)
|
@@ -171,7 +167,8 @@ module ISO3166
|
|
171
167
|
data.transform_values! do |v|
|
172
168
|
v.is_a?(Hash) ? deep_stringify_keys(v) : v
|
173
169
|
end
|
174
|
-
|
170
|
+
|
171
|
+
data
|
175
172
|
end
|
176
173
|
end
|
177
174
|
end
|
data/lib/countries/global.rb
CHANGED
data/lib/countries/iso3166.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'yaml'
|
2
4
|
require 'json'
|
3
5
|
require 'i18n_data'
|
@@ -8,6 +10,7 @@ require 'countries/data'
|
|
8
10
|
require 'countries/structure'
|
9
11
|
require 'countries/translations'
|
10
12
|
require 'countries/country/class_methods'
|
13
|
+
require 'countries/country/finder_methods'
|
11
14
|
require 'countries/country/emoji'
|
12
15
|
require 'countries/country'
|
13
16
|
require 'countries/subdivision'
|
data/lib/countries/mongoid.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'uri'
|
2
4
|
require 'net/http'
|
3
5
|
require 'nokogiri'
|
@@ -19,19 +21,17 @@ module Sources
|
|
19
21
|
def download_folder(type)
|
20
22
|
folder = File.join(ISO3166_ROOT_PATH, 'tmp', 'cldr', 'trunk', 'common', type)
|
21
23
|
FileUtils.mkdir_p(folder)
|
22
|
-
url = URI.parse("https://api.github.com/repos/unicode-org/cldr/contents/common
|
24
|
+
url = URI.parse("https://api.github.com/repos/unicode-org/cldr/contents/common/#{type}")
|
23
25
|
path_listing = JSON.parse(Net::HTTP.get_response(url).body)
|
24
26
|
path_listing.each do |path|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
27
|
+
next unless path['name'] =~ /\.xml$/
|
28
|
+
|
29
|
+
File.open(File.join(folder, path['name']), 'w') do |f|
|
30
|
+
raw_url = URI.parse(path['download_url'])
|
31
|
+
f.write(Net::HTTP.get_response(raw_url).body)
|
30
32
|
end
|
31
33
|
end
|
32
34
|
end
|
33
|
-
|
34
35
|
end
|
35
36
|
end
|
36
37
|
end
|
37
|
-
|
@@ -1,8 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Sources
|
2
4
|
module CLDR
|
3
5
|
# Auxiliary Subdivision class to support loading Unicode CLDR data to update local files
|
4
6
|
class Subdivision
|
5
7
|
attr_reader :xml, :language_code
|
8
|
+
|
6
9
|
def initialize(language_code:, xml:)
|
7
10
|
@language_code = language_code
|
8
11
|
@xml = xml
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'active_support'
|
2
4
|
require 'active_support/core_ext/hash/deep_merge'
|
3
5
|
require 'nokogiri'
|
@@ -9,25 +11,29 @@ module Sources
|
|
9
11
|
class SubdivisionUpdater
|
10
12
|
def call
|
11
13
|
d = Dir['./tmp/cldr/trunk/common/subdivisions/*.xml']
|
12
|
-
loader = Sources::Local::CachedLoader.new(Sources::Local::Subdivision)
|
13
|
-
d.each
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
14
|
+
@loader = Sources::Local::CachedLoader.new(Sources::Local::Subdivision)
|
15
|
+
d.each { |file_path| update_locale(file_path) }
|
16
|
+
end
|
17
|
+
|
18
|
+
def update_locale(file_path)
|
19
|
+
language_data = Nokogiri::XML(File.read(file_path))
|
20
|
+
language_code = File.basename(file_path, '.*')
|
21
|
+
subdivisions = language_data.css('subdivision')
|
22
|
+
next if subdivisions.empty?
|
23
|
+
|
24
|
+
last_country_code_seen = nil
|
19
25
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
last_country_code_seen = subdivision.country_code
|
26
|
+
subdivisions.each_with_index do |subdivision, index|
|
27
|
+
subdivision = Sources::CLDR::Subdivision.new(language_code: language_code, xml: subdivision)
|
28
|
+
data = @loader.load(subdivision.country_code)
|
29
|
+
data[subdivision.code] ||= {}
|
30
|
+
data[subdivision.code] = data[subdivision.code].deep_merge(subdivision.to_h)
|
31
|
+
if (last_country_code_seen && last_country_code_seen != subdivision.country_code) ||
|
32
|
+
index == subdivisions.size - 1
|
33
|
+
puts "Updated #{subdivision.country_code} with language_code #{language_code}"
|
34
|
+
@loader.save(subdivision.country_code, data)
|
30
35
|
end
|
36
|
+
last_country_code_seen = subdivision.country_code
|
31
37
|
end
|
32
38
|
end
|
33
39
|
end
|
@@ -1,9 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Sources
|
2
4
|
# Support code to allow updating subdivision data from the Unicode CLDR repository
|
3
5
|
module Local
|
4
6
|
# Loader for locally-cached data, to allow merging Unicode CLDR data with existing local data
|
5
7
|
class CachedLoader
|
6
8
|
attr_reader :klass
|
9
|
+
|
7
10
|
def initialize(klass)
|
8
11
|
@klass = klass
|
9
12
|
@loaded_countries = {}
|
@@ -1,8 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Sources
|
2
4
|
module Local
|
3
5
|
# Auxiliary Subdivision class to support loading the local subdivision data to be updated with Unicode CLDR data
|
4
6
|
class Subdivision
|
5
7
|
attr_reader :code
|
8
|
+
|
6
9
|
def initialize(code)
|
7
10
|
@code = code
|
8
11
|
end
|
@@ -16,8 +19,8 @@ module Sources
|
|
16
19
|
end
|
17
20
|
|
18
21
|
def save(data)
|
19
|
-
File.
|
20
|
-
rescue
|
22
|
+
File.write(file_path, data.to_yaml)
|
23
|
+
rescue StandardError
|
21
24
|
puts "failed to read #{file}: #{$ERROR_INFO}"
|
22
25
|
end
|
23
26
|
|