maxmind-geoip2 0.3.0 → 1.0.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.
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
  #