countries 1.2.5 → 2.0.0.pre

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.
Files changed (117) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -1
  3. data/CHANGELOG.md +6 -2
  4. data/Gemfile +1 -0
  5. data/README.markdown +33 -7
  6. data/Rakefile +15 -20
  7. data/countries.gemspec +1 -1
  8. data/lib/countries/cache/countries +0 -0
  9. data/lib/countries/cache/locales/af +0 -0
  10. data/lib/countries/cache/locales/am +0 -0
  11. data/lib/countries/cache/locales/ar +0 -0
  12. data/lib/countries/cache/locales/as +0 -0
  13. data/lib/countries/cache/locales/az +0 -0
  14. data/lib/countries/cache/locales/be +0 -0
  15. data/lib/countries/cache/locales/bg +0 -0
  16. data/lib/countries/cache/locales/bn +0 -0
  17. data/lib/countries/cache/locales/br +0 -0
  18. data/lib/countries/cache/locales/bs +0 -0
  19. data/lib/countries/cache/locales/ca +0 -0
  20. data/lib/countries/cache/locales/cs +0 -0
  21. data/lib/countries/cache/locales/cy +0 -0
  22. data/lib/countries/cache/locales/da +0 -0
  23. data/lib/countries/cache/locales/de +0 -0
  24. data/lib/countries/cache/locales/dz +0 -0
  25. data/lib/countries/cache/locales/el +0 -0
  26. data/lib/countries/cache/locales/en +0 -0
  27. data/lib/countries/cache/locales/eo +0 -0
  28. data/lib/countries/cache/locales/es +0 -0
  29. data/lib/countries/cache/locales/et +0 -0
  30. data/lib/countries/cache/locales/eu +0 -0
  31. data/lib/countries/cache/locales/fa +0 -0
  32. data/lib/countries/cache/locales/fi +0 -0
  33. data/lib/countries/cache/locales/fo +0 -0
  34. data/lib/countries/cache/locales/fr +0 -0
  35. data/lib/countries/cache/locales/ga +0 -0
  36. data/lib/countries/cache/locales/gl +0 -0
  37. data/lib/countries/cache/locales/gu +0 -0
  38. data/lib/countries/cache/locales/he +0 -0
  39. data/lib/countries/cache/locales/hi +0 -0
  40. data/lib/countries/cache/locales/hr +0 -0
  41. data/lib/countries/cache/locales/hu +0 -0
  42. data/lib/countries/cache/locales/hy +0 -0
  43. data/lib/countries/cache/locales/ia +0 -0
  44. data/lib/countries/cache/locales/id +0 -0
  45. data/lib/countries/cache/locales/is +0 -0
  46. data/lib/countries/cache/locales/it +0 -0
  47. data/lib/countries/cache/locales/ja +0 -0
  48. data/lib/countries/cache/locales/ka +0 -0
  49. data/lib/countries/cache/locales/kk +0 -0
  50. data/lib/countries/cache/locales/km +0 -0
  51. data/lib/countries/cache/locales/kn +0 -0
  52. data/lib/countries/cache/locales/ko +0 -0
  53. data/lib/countries/cache/locales/ku +0 -0
  54. data/lib/countries/cache/locales/lt +0 -0
  55. data/lib/countries/cache/locales/lv +0 -0
  56. data/lib/countries/cache/locales/mi +0 -0
  57. data/lib/countries/cache/locales/mk +0 -0
  58. data/lib/countries/cache/locales/ml +0 -0
  59. data/lib/countries/cache/locales/mn +0 -0
  60. data/lib/countries/cache/locales/mr +0 -0
  61. data/lib/countries/cache/locales/ms +0 -0
  62. data/lib/countries/cache/locales/mt +0 -0
  63. data/lib/countries/cache/locales/nb +0 -0
  64. data/lib/countries/cache/locales/ne +0 -0
  65. data/lib/countries/cache/locales/nl +0 -0
  66. data/lib/countries/cache/locales/nn +0 -0
  67. data/lib/countries/cache/locales/oc +0 -0
  68. data/lib/countries/cache/locales/or +0 -0
  69. data/lib/countries/cache/locales/pa +0 -0
  70. data/lib/countries/cache/locales/pl +0 -0
  71. data/lib/countries/cache/locales/ps +0 -0
  72. data/lib/countries/cache/locales/pt +0 -0
  73. data/lib/countries/cache/locales/ro +0 -0
  74. data/lib/countries/cache/locales/ru +0 -0
  75. data/lib/countries/cache/locales/rw +0 -0
  76. data/lib/countries/cache/locales/si +0 -0
  77. data/lib/countries/cache/locales/sk +0 -0
  78. data/lib/countries/cache/locales/sl +0 -0
  79. data/lib/countries/cache/locales/so +0 -0
  80. data/lib/countries/cache/locales/sq +0 -0
  81. data/lib/countries/cache/locales/sr +0 -0
  82. data/lib/countries/cache/locales/sv +0 -0
  83. data/lib/countries/cache/locales/sw +0 -0
  84. data/lib/countries/cache/locales/ta +0 -0
  85. data/lib/countries/cache/locales/te +0 -0
  86. data/lib/countries/cache/locales/th +0 -0
  87. data/lib/countries/cache/locales/ti +0 -0
  88. data/lib/countries/cache/locales/tk +0 -0
  89. data/lib/countries/cache/locales/tl +0 -0
  90. data/lib/countries/cache/locales/tr +0 -0
  91. data/lib/countries/cache/locales/tt +0 -0
  92. data/lib/countries/cache/locales/ug +0 -0
  93. data/lib/countries/cache/locales/uk +0 -0
  94. data/lib/countries/cache/locales/ve +0 -0
  95. data/lib/countries/cache/locales/vi +0 -0
  96. data/lib/countries/cache/locales/wa +0 -0
  97. data/lib/countries/cache/locales/wo +0 -0
  98. data/lib/countries/cache/locales/xh +0 -0
  99. data/lib/countries/cache/locales/zh +0 -0
  100. data/lib/countries/cache/locales/zu +0 -0
  101. data/lib/countries/configuration.rb +37 -0
  102. data/lib/countries/country.rb +115 -159
  103. data/lib/countries/country/attr_readers.rb +49 -0
  104. data/lib/countries/data.rb +76 -13
  105. data/lib/countries/iso3166.rb +4 -2
  106. data/lib/countries/setup.rb +7 -7
  107. data/lib/countries/timezones.rb +11 -0
  108. data/lib/countries/version.rb +1 -1
  109. data/spec/configuration_spec.rb +43 -0
  110. data/spec/country_spec.rb +22 -36
  111. data/spec/data_spec.rb +73 -0
  112. data/spec/global_spec.rb +29 -0
  113. data/spec/mongoid_spec.rb +1 -1
  114. data/spec/spec_helper.rb +24 -0
  115. data/spec/timezone_spec.rb +32 -0
  116. metadata +110 -9
  117. data/spec/setup_spec.rb +0 -14
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2ee687bca4e24ba2898509688d95338b53b593bd
4
- data.tar.gz: cda7ae980090e58b83d2bcb7a47635019c9412d4
3
+ metadata.gz: e56e233e585a77d0e16537d69e5055d9db7f1201
4
+ data.tar.gz: 8e0d126fdd580391306a14f444b1cb1f767b088b
5
5
  SHA512:
6
- metadata.gz: b4a58a0e7b18602487f105c53e73d8fb94e0b400465ff7a021e3ce8429adfd7285da97ff0b3ed645d43be8f974034b795dc298de827e841cef665d365f6bea74
7
- data.tar.gz: 5c2f7e88a4969b272cedb5dad3bdd82c8716f8db98438f74b9fe0056e5b550df9b76881923fc963680bae828c1dd4435799b20522145dd2a1545ba78aa3d5645
6
+ metadata.gz: 1110e82fab2598d0242edcad19c73e398bda739bfd8cd8201dd9c2d6944a2edf2b789526cf42dcf8292ff8c661ce5247b39d94d69991693480a931ffcdc04aa9
7
+ data.tar.gz: 2dc3bf71824639180e6daba333f31ba15d7fc6ad74c0da9fdd0df9d884ba89259d2417a5c728baf823e39087eb6873bf32087963b2380e717b972506a9577dd7
data/.gitignore CHANGED
@@ -21,5 +21,5 @@ tmp
21
21
  .ruby-gemset
22
22
  .idea/
23
23
  Gemfile.lock
24
- rspec
24
+ bin/rspec
25
25
  examples.txt
@@ -2,8 +2,12 @@
2
2
  All notable changes to this project will be documented in this file.
3
3
  This project adheres to [Semantic Versioning](http://semver.org/).
4
4
 
5
- ## 1.2.5 @ 2016-01-22
6
- - Rebuilding cache
5
+ ## 2.0.0 (unreleased)
6
+ - Selective loading translations of countries
7
+ - Auto detect I18n locales to load
8
+ - Add Configuration methods to force locales to load
9
+ - Dropped currencies gem in favor of money
10
+ - Add Time Zone Support
7
11
 
8
12
  ## 1.2.4 @ 2016-01-21
9
13
  - Romanian Standard VAT rate is 20% as of 2016-01-01 #325 @dougal
data/Gemfile CHANGED
@@ -2,6 +2,7 @@ source 'https://rubygems.org'
2
2
  gem 'rake'
3
3
  gem 'geocoder'
4
4
  gem 'retryable'
5
+ gem 'tzinfo'
5
6
 
6
7
  # Specify your gem's dependencies in countries.gemspec
7
8
  gemspec
@@ -35,9 +35,6 @@ has become
35
35
  Basic Usage
36
36
  -----------
37
37
 
38
- Note that Country class still exist by default.
39
- (is inherited from ISO3166::Country to keep backward compatibility).
40
-
41
38
  Simply load a new country object using Country.new(*alpha2*) or the shortcut Country[*alpha2*]. An example works best.
42
39
 
43
40
  c = ISO3166::Country.new('US')
@@ -45,6 +42,24 @@ Simply load a new country object using Country.new(*alpha2*) or the shortcut Cou
45
42
  # with global Country Helper
46
43
  c = Country['US']
47
44
 
45
+ Configuration
46
+
47
+ As of 2.0 you can selectively load locales to reduce memory usage in production.
48
+
49
+ By default we load I18n.available_locales if I18n is present, otherwise only [:en]. This means almost any rails environment will only bring in it's supported translations.
50
+
51
+ You can add all the locales like this.
52
+
53
+ ISO3166.configure do |config|
54
+ config.locales = [:af, :am, :ar, :as, :az, :be, :bg, :bn, :br, :bs, :ca, :cs, :cy, :da, :de, :dz, :el, :en, :eo, :es, :et, :eu, :fa, :fi, :fo, :fr, :ga, :gl, :gu, :he, :hi, :hr, :hu, :hy, :ia, :id, :is, :it, :ja, :ka, :kk, :km, :kn, :ko, :ku, :lt, :lv, :mi, :mk, :ml, :mn, :mr, :ms, :mt, :nb, :ne, :nl, :nn, :oc, :or, :pa, :pl, :ps, :pt, :ro, :ru, :rw, :si, :sk, :sl, :so, :sq, :sr, :sv, :sw, :ta, :te, :th, :ti, :tk, :tl, :tr, :tt, :ug, :uk, :ve, :vi, :wa, :wo, :xh, :zh, :zu]
55
+ end
56
+
57
+ or something a bit more simple
58
+
59
+ ISO3166.configure do |config|
60
+ config.locales = [:en, :de, :fr, :es]
61
+ end
62
+
48
63
  Attribute-Based Finder Methods
49
64
  ------------
50
65
 
@@ -101,6 +116,17 @@ Country Info
101
116
  c.region #=> "Americas"
102
117
  c.subregion #=> "Northern America"
103
118
 
119
+ Timezones **(optional)**
120
+
121
+ Add tzinfo to your gemfile, ensure it's required, Countries will not do this for you.
122
+
123
+ gem 'tzinfo', '~> 1.2', '>= 1.2.2'
124
+
125
+ c.timezones.zone_identifiers #=> ["America/New_York", "America/Detroit", "America/Kentucky/Louisville", ...]
126
+ ```c.timezones.zone_info``` # see [tzinfo docs]( http://www.rubydoc.info/gems/tzinfo/TZInfo/CountryInfo)
127
+
128
+ ```c.timezones``` # see [tzinfo docs]( http://www.rubydoc.info/gems/tzinfo/TZInfo/Country)
129
+
104
130
  Telephone Routing (E164)
105
131
 
106
132
  c.country_code #=> "1"
@@ -123,11 +149,11 @@ Country Info
123
149
  Currencies
124
150
  ----------
125
151
 
126
- Countries now uses the [Currencies][] gem. What this means is you now get back a Currency object that gives you access to all the currency information. It acts the same as a hash so the same ['name'] methods still work.
152
+ Countries now uses the [Money](https://github.com/RubyMoney/money) gem. What this means is you now get back a Money::Currency object that gives you access to all the currency information.
127
153
 
128
- c.currency['code'] #=> 'USD'
129
- c.currency['name'] #=> 'Dollars'
130
- c.currency['symbol'] #=> '$'
154
+ c.currency.iso_code #=> 'USD'
155
+ c.currency.name #=> 'Dollars'
156
+ c.currency.symbol #=> '$'
131
157
 
132
158
  Address Formatting
133
159
  ------------------
data/Rakefile CHANGED
@@ -52,14 +52,11 @@ task :update_cache do
52
52
  end
53
53
  end
54
54
 
55
- codes.each do |alpha2|
56
- data[alpha2] ||= YAML.load_file(File.join(File.dirname(__FILE__), 'lib', 'countries', 'data', 'countries', "#{alpha2}.yaml"))[alpha2]
57
- data[alpha2]['translations'] ||= empty_translations_hash.dup
58
- data[alpha2]['translations'][locale] = local_names[alpha2]
59
- data[alpha2]['translated_names'] ||= []
60
- data[alpha2]['translated_names'] << local_names[alpha2]
61
- data[alpha2]['translated_names'] = data[alpha2]['translated_names'].uniq
62
- end
55
+ File.open(File.join(File.dirname(__FILE__), 'lib', 'countries', 'cache', 'locales', locale), 'wb') { |f| f.write(Marshal.dump(local_names)) }
56
+ end
57
+
58
+ codes.each do |alpha2|
59
+ data[alpha2] ||= YAML.load_file(File.join(File.dirname(__FILE__), 'lib', 'countries', 'data', 'countries', "#{alpha2}.yaml"))[alpha2]
63
60
  end
64
61
 
65
62
  File.open(File.join(File.dirname(__FILE__), 'lib', 'countries', 'cache', 'countries'), 'wb') { |f| f.write(Marshal.dump(data)) }
@@ -97,19 +94,17 @@ task :fetch_subdivisions do
97
94
  location = "#{data['name']} State, United States"
98
95
  end
99
96
 
100
- if (result = geocode(location))
101
- geometry = result.geometry
102
- if geometry['location']
103
- state_data[code]['latitude'] = geometry['location']['lat']
104
- state_data[code]['longitude'] = geometry['location']['lng']
105
- end
106
- if geometry['bounds']
107
- state_data[code]['min_latitude'] = geometry['bounds']['southwest']['lat']
108
- state_data[code]['min_longitude'] = geometry['bounds']['southwest']['lng']
109
- state_data[code]['max_latitude'] = geometry['bounds']['northeast']['lat']
110
- state_data[code]['max_longitude'] = geometry['bounds']['northeast']['lng']
111
- end
97
+ next unless (result = geocode(location))
98
+ geometry = result.geometry
99
+ if geometry['location']
100
+ state_data[code]['latitude'] = geometry['location']['lat']
101
+ state_data[code]['longitude'] = geometry['location']['lng']
112
102
  end
103
+ next unless geometry['bounds']
104
+ state_data[code]['min_latitude'] = geometry['bounds']['southwest']['lat']
105
+ state_data[code]['min_longitude'] = geometry['bounds']['southwest']['lng']
106
+ state_data[code]['max_latitude'] = geometry['bounds']['northeast']['lat']
107
+ state_data[code]['max_longitude'] = geometry['bounds']['northeast']['lng']
113
108
  end
114
109
  # Write updated YAML for current country
115
110
  File.open(File.join(File.dirname(__FILE__), 'lib', 'data', 'subdivisions', "#{c.alpha2}.yaml"), 'w+') { |f| f.write state_data.to_yaml }
@@ -16,7 +16,7 @@ Gem::Specification.new do |gem|
16
16
  gem.version = Countries::VERSION
17
17
 
18
18
  gem.add_dependency('i18n_data', '~> 0.7.0')
19
- gem.add_dependency('currencies', '~> 0.4.2')
19
+ gem.add_dependency('money', '~> 6.0')
20
20
  gem.add_development_dependency('rspec', '>= 3')
21
21
  gem.add_development_dependency('actionview', '>= 3')
22
22
  gem.add_development_dependency 'yard'
@@ -0,0 +1,37 @@
1
+ module ISO3166
2
+ class << self
3
+ attr_writer :configuration
4
+ end
5
+
6
+ def self.configuration
7
+ @configuration ||= Configuration.new
8
+ end
9
+
10
+ def self.reset
11
+ @configuration = Configuration.new
12
+ Data.reset
13
+ end
14
+
15
+ def self.configure
16
+ yield(configuration)
17
+ end
18
+
19
+ class Configuration
20
+ attr_accessor :locales, :loaded_locales
21
+
22
+ def initialize
23
+ @locales = default_locales
24
+ @loaded_locales = []
25
+ end
26
+
27
+ private
28
+
29
+ def default_locales
30
+ if Object.const_defined?('I18n') && I18n.respond_to?(:available_locales)
31
+ I18n.available_locales
32
+ else
33
+ [:en]
34
+ end
35
+ end
36
+ end
37
+ end
@@ -1,201 +1,157 @@
1
- module ISO3166; end
2
-
3
- class ISO3166::Country
4
- Setup = ISO3166::Setup.new
5
-
6
- AttrReaders = [
7
- :number,
8
- :alpha2,
9
- :alpha3,
10
- :name,
11
- :names,
12
- :latitude,
13
- :longitude,
14
- :continent,
15
- :region,
16
- :subregion,
17
- :world_region,
18
- :country_code,
19
- :national_destination_code_lengths,
20
- :national_number_lengths,
21
- :international_prefix,
22
- :national_prefix,
23
- :address_format,
24
- :translations,
25
- :translated_names,
26
- :ioc,
27
- :gec,
28
- :un_locode,
29
- :languages,
30
- :nationality,
31
- :dissolved_on,
32
- :eu_member,
33
- :alt_currency,
34
- :vat_rates,
35
- :postal_code,
36
- :min_longitude,
37
- :min_latitude,
38
- :max_longitude,
39
- :max_latitude,
40
- :latitude_dec,
41
- :longitude_dec
42
- ]
43
-
44
- AttrReaders.each do |meth|
45
- define_method meth do
46
- @data[meth.to_s]
47
- end
48
- end
49
-
50
- attr_reader :data
51
-
52
- def initialize(country_data)
53
- @data = country_data.is_a?(Hash) ? country_data : ISO3166::Data.new(country_data).call
54
- end
55
-
56
- def valid?
57
- !(@data.nil? || @data.empty?)
58
- end
1
+ module ISO3166
2
+ class Country
3
+ attr_reader :data
59
4
 
60
- alias_method :zip, :postal_code
61
- alias_method :zip?, :postal_code
62
- alias_method :postal_code?, :postal_code
63
-
64
- def ==(other)
65
- other == data
66
- end
67
-
68
- def <=>(other)
69
- to_s <=> other.to_s
70
- end
71
-
72
- def currency
73
- ISO4217::Currency.from_code(@data['currency'])
74
- end
5
+ include ISO3166::Countries::AttrReaders
75
6
 
76
- def currency_code
77
- @data['currency']
78
- end
7
+ def initialize(country_data)
8
+ @data = country_data.is_a?(Hash) ? country_data : ISO3166::Data.new(country_data).call
9
+ end
79
10
 
80
- def subdivisions
81
- @subdivisions ||= subdivisions? ? YAML.load_file(File.join(File.dirname(__FILE__), 'data', 'subdivisions', "#{alpha2}.yaml")) : {}
82
- end
11
+ def valid?
12
+ !(@data.nil? || @data.empty?)
13
+ end
83
14
 
84
- alias_method :states, :subdivisions
15
+ alias_method :zip, :postal_code
16
+ alias_method :zip?, :postal_code
17
+ alias_method :postal_code?, :postal_code
85
18
 
86
- def subdivisions?
87
- File.exist?(File.join(File.dirname(__FILE__), 'data', 'subdivisions', "#{alpha2}.yaml"))
88
- end
19
+ def ==(other)
20
+ other == data
21
+ end
89
22
 
90
- def in_eu?
91
- @data['eu_member'].nil? ? false : @data['eu_member']
92
- end
23
+ def <=>(other)
24
+ to_s <=> other.to_s
25
+ end
93
26
 
94
- def to_s
95
- @data['name']
96
- end
27
+ def currency
28
+ Money::Currency.find(@data['currency'])
29
+ end
97
30
 
98
- def translation(locale = 'en')
99
- @data['translations'][locale.downcase.to_s]
100
- end
31
+ def currency_code
32
+ @data['currency']
33
+ end
101
34
 
102
- def local_names
103
- @local_names ||= languages.map { |language| translations[language] }
104
- end
35
+ def subdivisions
36
+ @subdivisions ||= subdivisions? ? YAML.load_file(File.join(File.dirname(__FILE__), 'data', 'subdivisions', "#{alpha2}.yaml")) : {}
37
+ end
105
38
 
106
- def local_name
107
- @local_name ||= local_names.first
108
- end
39
+ alias_method :states, :subdivisions
109
40
 
110
- class << self
111
- def new(country_data)
112
- super if country_data.is_a?(Hash) || codes.include?(country_data.to_s.upcase)
41
+ def subdivisions?
42
+ File.exist?(File.join(File.dirname(__FILE__), 'data', 'subdivisions', "#{alpha2}.yaml"))
113
43
  end
114
44
 
115
- def codes
116
- Setup.codes
45
+ def in_eu?
46
+ @data['eu_member'].nil? ? false : @data['eu_member']
117
47
  end
118
48
 
119
- def all(&blk)
120
- blk ||= proc { |_alpha2, d| ISO3166::Country.new(d) }
121
- Setup.data.map(&blk)
49
+ def to_s
50
+ @data['name']
122
51
  end
123
52
 
124
- alias_method :countries, :all
125
-
126
- def all_translated(locale = 'en')
127
- translations(locale).values
53
+ def translation(locale = 'en')
54
+ @data['translations'][locale.to_s.downcase]
128
55
  end
129
56
 
130
- def all_names_with_codes(locale = 'en')
131
- ISO3166::Country.all.map do |c|
132
- [(c.translation(locale) || c.name).html_safe, c.alpha2]
133
- end.sort_by { |d| d[0] }
57
+ def local_names
58
+ @local_names ||= languages.map { |language| translations[language] }
134
59
  end
135
60
 
136
- def translations(locale = 'en')
137
- I18nData.countries(locale.upcase)
61
+ def local_name
62
+ @local_name ||= local_names.first
138
63
  end
139
64
 
140
- def search(query)
141
- country = new(query.to_s.upcase)
142
- (country && country.valid?) ? country : nil
143
- end
65
+ class << self
66
+ def new(country_data)
67
+ super if country_data.is_a?(Hash) || codes.include?(country_data.to_s.upcase)
68
+ end
144
69
 
145
- def [](query)
146
- search(query)
147
- end
70
+ def codes
71
+ ISO3166::Data.codes
72
+ end
148
73
 
149
- def method_missing(*m)
150
- regex = m.first.to_s.match(/^find_(all_)?(country_|countries_)?by_(.+)/)
151
- super unless regex
74
+ def all(&blk)
75
+ blk ||= proc { |_alpha2, d| ISO3166::Country.new(d) }
76
+ ISO3166::Data.cache.map(&blk)
77
+ end
152
78
 
153
- countries = find_by(Regexp.last_match[3], m[1], Regexp.last_match[2])
154
- Regexp.last_match[1] ? countries : countries.last
155
- end
79
+ alias_method :countries, :all
80
+
81
+ def all_translated(locale = 'en')
82
+ translations(locale).values
83
+ end
156
84
 
157
- def find_all_by(attribute, val)
158
- attributes, value = parse_attributes(attribute, val)
85
+ def all_names_with_codes(locale = 'en')
86
+ ISO3166::Country.all.map do |c|
87
+ [(c.translation(locale) || c.name).html_safe, c.alpha2]
88
+ end.sort_by { |d| d[0] }
89
+ end
159
90
 
160
- Setup.data.select do |_, v|
161
- attributes.map do |attr|
162
- Array(v[attr]).any? { |n| value === n.to_s.downcase }
163
- end.include?(true)
91
+ def translations(locale = 'en')
92
+ I18nData.countries(locale.upcase)
164
93
  end
165
- end
166
94
 
167
- protected
95
+ def search(query)
96
+ country = new(query.to_s.upcase)
97
+ (country && country.valid?) ? country : nil
98
+ end
99
+
100
+ def [](query)
101
+ search(query)
102
+ end
168
103
 
169
- def parse_attributes(attribute, val)
170
- fail "Invalid attribute name '#{attribute}'" unless instance_methods.include?(attribute.to_sym)
104
+ def method_missing(*m)
105
+ regex = m.first.to_s.match(/^find_(all_)?(country_|countries_)?by_(.+)/)
106
+ super unless regex
171
107
 
172
- attributes = Array(attribute.to_s)
173
- if attributes == ['name']
174
- attributes << 'names'
175
- # TODO: Revisit when better data from i18n_data
176
- # attributes << 'translated_names'
108
+ countries = find_by(Regexp.last_match[3], m[1], Regexp.last_match[2])
109
+ Regexp.last_match[1] ? countries : countries.last
177
110
  end
178
111
 
179
- val = (val.is_a?(Regexp) ? Regexp.new(val.source, 'i') : val.to_s.downcase)
112
+ def find_all_by(attribute, val)
113
+ attributes, value = parse_attributes(attribute, val)
180
114
 
181
- [attributes, val]
182
- end
115
+ ISO3166::Data.cache.select do |_, v|
116
+ attributes.map do |attr|
117
+ Array(v[attr]).any? { |n| value === n.to_s.downcase }
118
+ end.include?(true)
119
+ end
120
+ end
121
+
122
+ protected
123
+
124
+ def parse_attributes(attribute, val)
125
+ fail "Invalid attribute name '#{attribute}'" unless instance_methods.include?(attribute.to_sym)
183
126
 
184
- def find_by(attribute, value, obj = nil)
185
- find_all_by(attribute.downcase, value).map do |country|
186
- obj.nil? ? country : new(country.last)
127
+ attributes = Array(attribute.to_s)
128
+ if attributes == ['name']
129
+ attributes << 'names'
130
+ # TODO: Revisit when better data from i18n_data
131
+ # attributes << 'translated_names'
132
+ end
133
+
134
+ val = (val.is_a?(Regexp) ? Regexp.new(val.source, 'i') : val.to_s.downcase)
135
+
136
+ [attributes, val]
137
+ end
138
+
139
+ def find_by(attribute, value, obj = nil)
140
+ find_all_by(attribute.downcase, value).map do |country|
141
+ obj.nil? ? country : new(country.last)
142
+ end
187
143
  end
188
144
  end
189
145
  end
190
- end
191
146
 
192
- def ISO3166::Country(country_data_or_country)
193
- case country_data_or_country
194
- when ISO3166::Country
195
- country_data_or_country
196
- when String, Symbol
197
- ISO3166::Country.search(country_data_or_country)
198
- else
199
- fail TypeError, "can't convert #{country_data_or_country.class.name} into ISO3166::Country"
147
+ def ISO3166::Country(country_data_or_country)
148
+ case country_data_or_country
149
+ when ISO3166::Country
150
+ country_data_or_country
151
+ when String, Symbol
152
+ ISO3166::Country.search(country_data_or_country)
153
+ else
154
+ fail TypeError, "can't convert #{country_data_or_country.class.name} into ISO3166::Country"
155
+ end
200
156
  end
201
157
  end