maxmind-geoip2 0.3.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +35 -0
  3. data/Gemfile +1 -7
  4. data/README.dev.md +1 -1
  5. data/README.md +37 -15
  6. data/lib/maxmind/geoip2/client.rb +48 -26
  7. data/lib/maxmind/geoip2/model/anonymous_ip.rb +8 -0
  8. data/lib/maxmind/geoip2/reader.rb +43 -18
  9. data/lib/maxmind/geoip2/record/traits.rb +12 -3
  10. data/maxmind-geoip2.gemspec +12 -5
  11. data/test/data/bad-data/maxminddb-python/bad-unicode-in-map-key.mmdb +0 -0
  12. data/test/data/source-data/GeoIP2-Anonymous-IP-Test.json +1 -0
  13. data/test/data/source-data/GeoIP2-ISP-Test.json +3 -1
  14. data/test/data/source-data/GeoIP2-Precision-Enterprise-Test.json +87 -0
  15. data/test/data/test-data/GeoIP2-Anonymous-IP-Test.mmdb +0 -0
  16. data/test/data/test-data/GeoIP2-City-Test-Broken-Double-Format.mmdb +0 -0
  17. data/test/data/test-data/GeoIP2-City-Test-Invalid-Node-Count.mmdb +0 -0
  18. data/test/data/test-data/GeoIP2-City-Test.mmdb +0 -0
  19. data/test/data/test-data/GeoIP2-Connection-Type-Test.mmdb +0 -0
  20. data/test/data/test-data/GeoIP2-Country-Test.mmdb +0 -0
  21. data/test/data/test-data/GeoIP2-DensityIncome-Test.mmdb +0 -0
  22. data/test/data/test-data/GeoIP2-Domain-Test.mmdb +0 -0
  23. data/test/data/test-data/GeoIP2-Enterprise-Test.mmdb +0 -0
  24. data/test/data/test-data/GeoIP2-ISP-Test.mmdb +0 -0
  25. data/test/data/test-data/GeoIP2-Precision-Enterprise-Test.mmdb +0 -0
  26. data/test/data/test-data/GeoIP2-Static-IP-Score-Test.mmdb +0 -0
  27. data/test/data/test-data/GeoIP2-User-Count-Test.mmdb +0 -0
  28. data/test/data/test-data/GeoLite2-ASN-Test.mmdb +0 -0
  29. data/test/data/test-data/MaxMind-DB-no-ipv4-search-tree.mmdb +0 -0
  30. data/test/data/test-data/MaxMind-DB-string-value-entries.mmdb +0 -0
  31. data/test/data/test-data/MaxMind-DB-test-broken-pointers-24.mmdb +0 -0
  32. data/test/data/test-data/MaxMind-DB-test-broken-search-tree-24.mmdb +0 -0
  33. data/test/data/test-data/MaxMind-DB-test-decoder.mmdb +0 -0
  34. data/test/data/test-data/MaxMind-DB-test-ipv4-24.mmdb +0 -0
  35. data/test/data/test-data/MaxMind-DB-test-ipv4-28.mmdb +0 -0
  36. data/test/data/test-data/MaxMind-DB-test-ipv4-32.mmdb +0 -0
  37. data/test/data/test-data/MaxMind-DB-test-ipv6-24.mmdb +0 -0
  38. data/test/data/test-data/MaxMind-DB-test-ipv6-28.mmdb +0 -0
  39. data/test/data/test-data/MaxMind-DB-test-ipv6-32.mmdb +0 -0
  40. data/test/data/test-data/MaxMind-DB-test-metadata-pointers.mmdb +0 -0
  41. data/test/data/test-data/MaxMind-DB-test-mixed-24.mmdb +0 -0
  42. data/test/data/test-data/MaxMind-DB-test-mixed-28.mmdb +0 -0
  43. data/test/data/test-data/MaxMind-DB-test-mixed-32.mmdb +0 -0
  44. data/test/data/test-data/MaxMind-DB-test-nested.mmdb +0 -0
  45. data/test/data/test-data/MaxMind-DB-test-pointer-decoder.mmdb +0 -0
  46. data/test/data/test-data/write-test-data.pl +68 -18
  47. data/test/test_client.rb +4 -2
  48. data/test/test_model_country.rb +16 -0
  49. data/test/test_reader.rb +59 -0
  50. metadata +100 -10
  51. data/Gemfile.lock +0 -70
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 42699226c0ab8ec1152f4c56929c830916d7c226097082ae95959199d8796aa8
4
- data.tar.gz: 97d399a1c58fb932171cfb4aa5c6b19cfb64af382771e2cdfc693e72bba2abd1
3
+ metadata.gz: 874135d664c0af2e82c184ce30fffbdfe72bb6badc1aa53ee0ec5eba626e5a1d
4
+ data.tar.gz: 7aec662f3893322c983f647545f4a155b27bda20b7fd6349201fc386264bdc88
5
5
  SHA512:
6
- metadata.gz: cd7fac3bc1738b562586e23722eb62919a3d157a32619511ca2246b0b23c91eabcf9a3565e9f33ff080680bdb9e42a6cfaf984689de9231e8cc2b4edab5b5fa9
7
- data.tar.gz: 05ce00df88e5de2ecfc7fceacc868fdf5d0b371091d7da5aae63089f9699c72195aaf70175fcdd8e16c3af4d251cd2cf8b78f06e462c2936ea66cc82a4ed622d
6
+ metadata.gz: 3b5d57920b467ccae6144b6f4aca8266721124481917014025390f02f6728138b704513137596593226506f82d554cf77afb215921a13fa8622e1b4e3a4f8b43
7
+ data.tar.gz: 28be946c7ea163e61b641029f3094de7b47ac2ce8bec6d1c68f9ddd5d084f55419403daeb30762fce3d0346ea0fb083de0d946621f6d659eabe03cafe3c3d0dd
data/CHANGELOG.md CHANGED
@@ -1,5 +1,40 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.0 (2021-05-14)
4
+
5
+ * Ruby 2.4 is no longer supported. If you're using Ruby 2.4, please use
6
+ version 0.7.0 of this gem.
7
+ * Expand accepted versions of the `http` gem to include 5.0+.
8
+ * Bump version to 1.0.0 since we have been at 0.x for over a year. There is
9
+ no breaking change.
10
+
11
+ ## 0.7.0 (2021-03-24)
12
+
13
+ * Ensured defaults are set when creating a `MaxMind::GeoIP2::Client` in the
14
+ case when args are explicitly passed in as `nil`. Pull Request by Manoj
15
+ Dayaram. GitHub #31.
16
+
17
+ ## 0.6.0 (2021-03-23)
18
+
19
+ * Updated the `MaxMind::GeoIP2::Reader` constructor to support being called
20
+ using keyword arguments. For example, you may now create a `Reader` using
21
+ `MaxMind::GeoIP2::Reader.new(database: 'GeoIP2-Country.mmdb')` instead of
22
+ using positional arguments. This is intended to make it easier to pass in
23
+ optional arguments. Positional argument calling is still supported.
24
+ * Proxy support was fixed. Pull request by Manoj Dayaram. GitHub #30.
25
+
26
+ ## 0.5.0 (2020-09-25)
27
+
28
+ * Added the `residential_proxy?` method to
29
+ `MaxMind::GeoIP2::Model::AnonymousIP` and
30
+ `MaxMind::GeoIP2::Record::Traits` for use with the Anonymous IP database
31
+ and GeoIP2 Precision Insights.
32
+
33
+ ## 0.4.0 (2020-03-06)
34
+
35
+ * HTTP connections are now persistent. There is a new parameter that
36
+ controls the maximum number of connections the client will use.
37
+
3
38
  ## 0.3.0 (2020-03-04)
4
39
 
5
40
  * Modules are now always be defined. Previously we used a shorthand syntax
data/Gemfile CHANGED
@@ -2,10 +2,4 @@
2
2
 
3
3
  source 'https://rubygems.org'
4
4
 
5
- gem 'http'
6
- gem 'maxmind-db'
7
- gem 'minitest', group: :development
8
- gem 'rake', group: :development
9
- gem 'rubocop', group: :development
10
- gem 'rubocop-performance', group: :development
11
- gem 'webmock', group: :development
5
+ gemspec
data/README.dev.md CHANGED
@@ -1,4 +1,4 @@
1
1
  # How to release
2
2
 
3
3
  See
4
- [here](https://github.com/maxmind/MaxMind-DB-Reader-ruby/blob/master/README.dev.md).
4
+ [here](https://github.com/maxmind/MaxMind-DB-Reader-ruby/blob/main/README.dev.md).
data/README.md CHANGED
@@ -47,7 +47,9 @@ for more details.
47
47
  require 'maxmind/geoip2'
48
48
 
49
49
  # This creates the Reader object which should be reused across lookups.
50
- reader = MaxMind::GeoIP2::Reader.new('/usr/share/GeoIP/GeoIP2-City.mmdb')
50
+ reader = MaxMind::GeoIP2::Reader.new(
51
+ database: '/usr/share/GeoIP/GeoIP2-City.mmdb',
52
+ )
51
53
 
52
54
  record = reader.city('128.101.101.101')
53
55
 
@@ -74,7 +76,9 @@ puts record.traits.network # 128.101.101.101/32
74
76
  require 'maxmind/geoip2'
75
77
 
76
78
  # This creates the Reader object which should be reused across lookups.
77
- reader = MaxMind::GeoIP2::Reader.new('/usr/share/GeoIP/GeoIP2-Country.mmdb')
79
+ reader = MaxMind::GeoIP2::Reader.new(
80
+ database: '/usr/share/GeoIP/GeoIP2-Country.mmdb',
81
+ )
78
82
 
79
83
  record = reader.country('128.101.101.101')
80
84
 
@@ -89,7 +93,9 @@ puts record.country.names['zh-CN'] # '美国'
89
93
  require 'maxmind/geoip2'
90
94
 
91
95
  # This creates the Reader object which should be reused across lookups.
92
- reader = MaxMind::GeoIP2::Reader.new('/usr/share/GeoIP/GeoIP2-Enterprise.mmdb')
96
+ reader = MaxMind::GeoIP2::Reader.new(
97
+ database: '/usr/share/GeoIP/GeoIP2-Enterprise.mmdb',
98
+ )
93
99
 
94
100
  record = reader.enterprise('128.101.101.101')
95
101
 
@@ -120,7 +126,9 @@ puts record.traits.network # 128.101.101.101/32
120
126
  require 'maxmind/geoip2'
121
127
 
122
128
  # This creates the Reader object which should be reused across lookups.
123
- reader = MaxMind::GeoIP2::Reader.new('/usr/share/GeoIP/GeoIP2-Anonymous-IP.mmdb')
129
+ reader = MaxMind::GeoIP2::Reader.new(
130
+ database: '/usr/share/GeoIP/GeoIP2-Anonymous-IP.mmdb',
131
+ )
124
132
 
125
133
  record = reader.anonymous_ip('128.101.101.101')
126
134
 
@@ -133,7 +141,9 @@ puts "Anonymous" if record.is_anonymous
133
141
  require 'maxmind/geoip2'
134
142
 
135
143
  # This creates the Reader object which should be reused across lookups.
136
- reader = MaxMind::GeoIP2::Reader.new('/usr/share/GeoIP/GeoLite2-ASN.mmdb')
144
+ reader = MaxMind::GeoIP2::Reader.new(
145
+ database: '/usr/share/GeoIP/GeoLite2-ASN.mmdb',
146
+ )
137
147
 
138
148
  record = reader.asn('128.101.101.101')
139
149
 
@@ -147,7 +157,9 @@ puts record.autonomous_system_organization # Example Ltd
147
157
  require 'maxmind/geoip2'
148
158
 
149
159
  # This creates the Reader object which should be reused across lookups.
150
- reader = MaxMind::GeoIP2::Reader.new('/usr/share/GeoIP/GeoIP2-Connection-Type.mmdb')
160
+ reader = MaxMind::GeoIP2::Reader.new(
161
+ database: '/usr/share/GeoIP/GeoIP2-Connection-Type.mmdb',
162
+ )
151
163
 
152
164
  record = reader.connection_type('128.101.101.101')
153
165
 
@@ -160,7 +172,9 @@ puts record.connection_type # Cable/DSL
160
172
  require 'maxmind/geoip2'
161
173
 
162
174
  # This creates the Reader object which should be reused across lookups.
163
- reader = MaxMind::GeoIP2::Reader.new('/usr/share/GeoIP/GeoIP2-Domain.mmdb')
175
+ reader = MaxMind::GeoIP2::Reader.new(
176
+ database: '/usr/share/GeoIP/GeoIP2-Domain.mmdb',
177
+ )
164
178
 
165
179
  record = reader.domain('128.101.101.101')
166
180
 
@@ -173,7 +187,9 @@ puts record.domain # example.com
173
187
  require 'maxmind/geoip2'
174
188
 
175
189
  # This creates the Reader object which should be reused across lookups.
176
- reader = MaxMind::GeoIP2::Reader.new('/usr/share/GeoIP/GeoIP2-ISP.mmdb')
190
+ reader = MaxMind::GeoIP2::Reader.new(
191
+ database: '/usr/share/GeoIP/GeoIP2-ISP.mmdb',
192
+ )
177
193
 
178
194
  record = reader.isp('128.101.101.101')
179
195
 
@@ -188,9 +204,10 @@ puts record.organization # University of Minnesota
188
204
  ### Usage
189
205
 
190
206
  To use this API, you must create a new `MaxMind::GeoIP2::Client` object
191
- with your account ID and license key, then you call the method
192
- corresponding to a specific end point, passing it the IP address you want
193
- to look up.
207
+ with your account ID and license key. To use the GeoLite2 web service, you
208
+ may also set the `host` parameter to `geolite.info`. You may then you call
209
+ the method corresponding to a specific end point, passing it the IP address
210
+ you want to look up.
194
211
 
195
212
  If the request succeeds, the method call will return a model class for the end
196
213
  point you called. This model in turn contains multiple record classes, each of
@@ -212,13 +229,18 @@ require 'maxmind/geoip2'
212
229
  client = MaxMind::GeoIP2::Client.new(
213
230
  account_id: 42,
214
231
  license_key: 'license_key',
232
+
233
+ # To use the GeoLite2 web service instead of GeoIP2 Precision, set
234
+ # the host parameter to "geolite.info":
235
+ # host: 'geolite.info',
215
236
  )
216
237
 
217
238
  # Replace "city" with the method corresponding to the web service that
218
- # you are using, e.g., "country", "insights".
239
+ # you are using, e.g., "country", "insights". Please note that Insights
240
+ # is only supported by GeoIP2 Precision and not the GeoLite2 web service.
219
241
  record = client.city('128.101.101.101')
220
242
 
221
- puts record.country.isoCode # US
243
+ puts record.country.iso_code # US
222
244
  puts record.country.name # United States
223
245
  puts record.country.names['zh-CN'] # 美国
224
246
 
@@ -307,7 +329,7 @@ client API, please see [our support page](https://www.maxmind.com/en/support).
307
329
 
308
330
  ## Requirements
309
331
 
310
- This code requires Ruby version 2.4 or higher.
332
+ This code requires Ruby version 2.5 or higher.
311
333
 
312
334
  ## Contributing
313
335
 
@@ -320,7 +342,7 @@ This library uses [Semantic Versioning](https://semver.org/).
320
342
 
321
343
  ## Copyright and License
322
344
 
323
- This software is Copyright (c) 2020 by MaxMind, Inc.
345
+ This software is Copyright (c) 2020-2021 by MaxMind, Inc.
324
346
 
325
347
  This is free software, licensed under the [Apache License, Version
326
348
  2.0](LICENSE-APACHE) or the [MIT License](LICENSE-MIT), at your option.
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'connection_pool'
3
4
  require 'http'
4
5
  require 'json'
5
6
  require 'maxmind/geoip2/errors'
@@ -54,6 +55,8 @@ module MaxMind
54
55
  # puts record.country.iso_code
55
56
  class Client
56
57
  # rubocop:disable Metrics/ParameterLists
58
+ # rubocop:disable Metrics/CyclomaticComplexity
59
+ # rubocop:disable Metrics/PerceivedComplexity
57
60
 
58
61
  # Create a Client that may be used to query a GeoIP2 Precision web service.
59
62
  #
@@ -67,7 +70,9 @@ module MaxMind
67
70
  # @param locales [Array<String>] a list of locale codes to use in the name
68
71
  # property from most preferred to least preferred.
69
72
  #
70
- # @param host [String] the host to use when querying the web service.
73
+ # @param host [String] the host to use when querying the web service. Set
74
+ # this to "geolite.info" to use the GeoLite2 web service instead of
75
+ # GeoIP2 Precision.
71
76
  #
72
77
  # @param timeout [Integer] the number of seconds to wait for a request
73
78
  # before timing out. If 0, no timeout is set.
@@ -79,6 +84,8 @@ module MaxMind
79
84
  # @param proxy_username [String] proxy username to use, if any.
80
85
  #
81
86
  # @param proxy_password [String] proxy password to use, if any.
87
+ #
88
+ # @param pool_size [Integer] HTTP connection pool size
82
89
  def initialize(
83
90
  account_id:,
84
91
  license_key:,
@@ -88,21 +95,29 @@ module MaxMind
88
95
  proxy_address: '',
89
96
  proxy_port: 0,
90
97
  proxy_username: '',
91
- proxy_password: ''
98
+ proxy_password: '',
99
+ pool_size: 5
92
100
  )
93
101
  @account_id = account_id
94
102
  @license_key = license_key
95
- @locales = locales
96
- @host = host
97
- @timeout = timeout
98
- @proxy_address = proxy_address
99
- @proxy_port = proxy_port
100
- @proxy_username = proxy_username
101
- @proxy_password = proxy_password
103
+ @locales = locales || ['en']
104
+ @host = host || 'geoip.maxmind.com'
105
+ @timeout = timeout || 0
106
+ @proxy_address = proxy_address || ''
107
+ @proxy_port = proxy_port || 0
108
+ @proxy_username = proxy_username || ''
109
+ @proxy_password = proxy_password || ''
110
+ @pool_size = pool_size || 5
111
+
112
+ @connection_pool = ConnectionPool.new(size: @pool_size) do
113
+ make_http_client.persistent("https://#{@host}")
114
+ end
102
115
  end
116
+ # rubocop:enable Metrics/PerceivedComplexity
117
+ # rubocop:enable Metrics/CyclomaticComplexity
103
118
  # rubocop:enable Metrics/ParameterLists
104
119
 
105
- # This method calls the GeoIP2 Precision City web service.
120
+ # This method calls the City web service.
106
121
  #
107
122
  # @param ip_address [String] IPv4 or IPv6 address as a string. If no
108
123
  # address is provided, the address that the web service is called from is
@@ -139,7 +154,7 @@ module MaxMind
139
154
  response_for('city', MaxMind::GeoIP2::Model::City, ip_address)
140
155
  end
141
156
 
142
- # This method calls the GeoIP2 Precision Country web service.
157
+ # This method calls the Country web service.
143
158
  #
144
159
  # @param ip_address [String] IPv4 or IPv6 address as a string. If no
145
160
  # address is provided, the address that the web service is called from is
@@ -176,7 +191,10 @@ module MaxMind
176
191
  response_for('country', MaxMind::GeoIP2::Model::Country, ip_address)
177
192
  end
178
193
 
179
- # This method calls the GeoIP2 Precision Insights web service.
194
+ # This method calls the Insights web service.
195
+ #
196
+ # Insights is only supported by the GeoIP2 Precision web service. The
197
+ # GeoLite2 web service does not support it.
180
198
  #
181
199
  # @param ip_address [String] IPv4 or IPv6 address as a string. If no
182
200
  # address is provided, the address that the web service is called from is
@@ -221,11 +239,7 @@ module MaxMind
221
239
  model_class.new(record, @locales)
222
240
  end
223
241
 
224
- # rubocop:disable Metrics/CyclomaticComplexity
225
- # rubocop:disable Metrics/PerceivedComplexity
226
- def get(endpoint, ip_address)
227
- url = 'https://' + @host + '/geoip/v2.1/' + endpoint + '/' + ip_address
228
-
242
+ def make_http_client
229
243
  headers = HTTP.basic_auth(user: @account_id, pass: @license_key)
230
244
  .headers(
231
245
  accept: 'application/json',
@@ -235,16 +249,26 @@ module MaxMind
235
249
 
236
250
  proxy = timeout
237
251
  if @proxy_address != ''
238
- opts = {}
239
- opts[:proxy_port] = @proxy_port if @proxy_port != 0
240
- opts[:proxy_username] = @proxy_username if @proxy_username != ''
241
- opts[:proxy_password] = @proxy_password if @proxy_password != ''
242
- proxy = timeout.via(@proxy_address, opts)
252
+ proxy_params = [@proxy_address]
253
+ proxy_params << (@proxy_port == 0 ? nil : @proxy_port)
254
+ proxy_params << (@proxy_username == '' ? nil : @proxy_username)
255
+ proxy_params << (@proxy_password == '' ? nil : @proxy_password)
256
+ proxy = timeout.via(*proxy_params)
243
257
  end
244
258
 
245
- response = proxy.get(url)
259
+ proxy
260
+ end
261
+
262
+ def get(endpoint, ip_address)
263
+ url = "/geoip/v2.1/#{endpoint}/#{ip_address}"
264
+
265
+ response = nil
266
+ body = nil
267
+ @connection_pool.with do |client|
268
+ response = client.get(url)
269
+ body = response.to_s
270
+ end
246
271
 
247
- body = response.to_s
248
272
  is_json = response.headers[:content_type]&.include?('json')
249
273
 
250
274
  if response.status.client_error?
@@ -263,8 +287,6 @@ module MaxMind
263
287
 
264
288
  handle_success(endpoint, body, is_json)
265
289
  end
266
- # rubocop:enable Metrics/CyclomaticComplexity
267
- # rubocop:enable Metrics/PerceivedComplexity
268
290
 
269
291
  # rubocop:disable Metrics/CyclomaticComplexity
270
292
  def handle_client_error(endpoint, status, body, is_json)
@@ -55,6 +55,14 @@ module MaxMind
55
55
  get('is_public_proxy')
56
56
  end
57
57
 
58
+ # This is true if the IP address is on a suspected anonymizing network
59
+ # and belongs to a residential ISP.
60
+ #
61
+ # @return [Boolean]
62
+ def residential_proxy?
63
+ get('is_residential_proxy')
64
+ end
65
+
58
66
  # This is true if the IP address is a Tor exit node.
59
67
  #
60
68
  # @return [Boolean]
@@ -20,13 +20,16 @@ module MaxMind
20
20
  #
21
21
  # require 'maxmind/geoip2'
22
22
  #
23
- # reader = MaxMind::GeoIP2::Reader.new('GeoIP2-Country.mmdb')
23
+ # reader = MaxMind::GeoIP2::Reader.new(database: 'GeoIP2-Country.mmdb')
24
24
  #
25
25
  # record = reader.country('1.2.3.4')
26
26
  # puts record.country.iso_code
27
27
  #
28
28
  # reader.close
29
29
  class Reader
30
+ # rubocop:disable Metrics/CyclomaticComplexity
31
+ # rubocop:disable Metrics/PerceivedComplexity
32
+
30
33
  # Create a Reader for looking up IP addresses in a GeoIP2/GeoLite2 database
31
34
  # file.
32
35
  #
@@ -37,30 +40,52 @@ module MaxMind
37
40
  # threads. It is safe to use after forking only if you use
38
41
  # MaxMind::DB::MODE_MEMORY or if your version of Ruby supports IO#pread.
39
42
  #
40
- # @param database [String] a path to a GeoIP2/GeoLite2 database file.
41
- #
42
- # @param locales [Array<String>] a list of locale codes to use in the name
43
- # property from most preferred to least preferred.
44
- #
45
- # @param options [Hash<Symbol, Symbol>] options controlling the behavior of
46
- # the Reader.
43
+ # @overload initialize(database:, locales: ['en'], mode: MaxMind::DB::MODE_AUTO)
44
+ # @param database [String] a path to a GeoIP2/GeoLite2 database file.
45
+ # @param locales [Array<String>] a list of locale codes to use in the name
46
+ # property from most preferred to least preferred.
47
+ # @param mode [Symbol] Defines how to open the database. It may be one of
48
+ # MaxMind::DB::MODE_AUTO, MaxMind::DB::MODE_FILE, or
49
+ # MaxMind::DB::MODE_MEMORY. If you don't provide one, the Reader uses
50
+ # MaxMind::DB::MODE_AUTO. Refer to the definition of those constants in
51
+ # MaxMind::DB for an explanation of their meaning.
47
52
  #
48
- # @option options [Symbol] :mode Defines how to open the database. It may
49
- # be one of MaxMind::DB::MODE_AUTO, MaxMind::DB::MODE_FILE, or
50
- # MaxMind::DB::MODE_MEMORY. If you don't provide one, the Reader uses
51
- # MaxMind::DB::MODE_AUTO. Refer to the definition of those constants in
52
- # MaxMind::DB for an explanation of their meaning.
53
- #
54
- # @raise [MaxMind::DB::InvalidDatabaseError] if the database is corrupt or
55
- # invalid.
53
+ # @raise [MaxMind::DB::InvalidDatabaseError] if the database is corrupt
54
+ # or invalid.
56
55
  #
57
56
  # @raise [ArgumentError] if the mode is invalid.
58
- def initialize(database, locales = ['en'], options = {})
57
+ def initialize(*args)
58
+ # This if statement is to let us support calling as though we are using
59
+ # Ruby 2.0 keyword arguments. We can't use keyword argument syntax as
60
+ # we want to be backwards compatible with the old way we accepted
61
+ # parameters, which looked like:
62
+ # def initialize(database, locales = ['en'], options = {})
63
+ if args.length == 1 && args[0].instance_of?(Hash)
64
+ database = args[0][:database]
65
+ locales = args[0][:locales]
66
+ mode = args[0][:mode]
67
+ else
68
+ database = args[0]
69
+ locales = args[1]
70
+ mode = args[2].instance_of?(Hash) ? args[2][:mode] : nil
71
+ end
72
+
73
+ if !database.instance_of?(String)
74
+ raise ArgumentError, 'Invalid database parameter'
75
+ end
76
+
77
+ locales = ['en'] if locales.nil? || locales.empty?
78
+
79
+ options = {}
80
+ options[:mode] = mode if !mode.nil?
59
81
  @reader = MaxMind::DB.new(database, options)
82
+
60
83
  @type = @reader.metadata.database_type
61
- locales = ['en'] if locales.empty?
84
+
62
85
  @locales = locales
63
86
  end
87
+ # rubocop:enable Metrics/CyclomaticComplexity
88
+ # rubocop:enable Metrics/PerceivedComplexity
64
89
 
65
90
  # Look up the IP address in the database.
66
91
  #