maxmind-geoip2 1.4.0 → 1.6.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 (112) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +20 -0
  3. data/README.md +16 -16
  4. data/lib/maxmind/geoip2/client.rb +56 -44
  5. data/lib/maxmind/geoip2/model/anonymous_plus.rb +1 -0
  6. data/lib/maxmind/geoip2/model/asn.rb +1 -1
  7. data/lib/maxmind/geoip2/model/city.rb +3 -3
  8. data/lib/maxmind/geoip2/model/connection_type.rb +1 -1
  9. data/lib/maxmind/geoip2/model/country.rb +2 -2
  10. data/lib/maxmind/geoip2/model/domain.rb +1 -1
  11. data/lib/maxmind/geoip2/model/enterprise.rb +2 -2
  12. data/lib/maxmind/geoip2/model/insights.rb +2 -2
  13. data/lib/maxmind/geoip2/model/isp.rb +1 -1
  14. data/lib/maxmind/geoip2/reader.rb +21 -21
  15. data/lib/maxmind/geoip2/record/anonymizer.rb +17 -1
  16. data/lib/maxmind/geoip2/record/anonymizer_feed.rb +53 -0
  17. data/lib/maxmind/geoip2/record/city.rb +1 -1
  18. data/lib/maxmind/geoip2/record/country.rb +1 -1
  19. data/lib/maxmind/geoip2/record/location.rb +1 -1
  20. data/lib/maxmind/geoip2/record/postal.rb +1 -1
  21. data/lib/maxmind/geoip2/record/subdivision.rb +1 -1
  22. data/lib/maxmind/geoip2/record/traits.rb +14 -7
  23. data/lib/maxmind/geoip2/version.rb +1 -1
  24. metadata +15 -96
  25. data/CLAUDE.md +0 -390
  26. data/Gemfile +0 -5
  27. data/Gemfile.lock +0 -126
  28. data/README.dev.md +0 -4
  29. data/Rakefile +0 -14
  30. data/maxmind-geoip2.gemspec +0 -41
  31. data/test/data/LICENSE-APACHE +0 -202
  32. data/test/data/LICENSE-MIT +0 -17
  33. data/test/data/MaxMind-DB-spec.md +0 -573
  34. data/test/data/README.md +0 -11
  35. data/test/data/bad-data/README.md +0 -7
  36. data/test/data/bad-data/libmaxminddb/libmaxminddb-offset-integer-overflow.mmdb +0 -0
  37. data/test/data/bad-data/maxminddb-golang/cyclic-data-structure.mmdb +0 -0
  38. data/test/data/bad-data/maxminddb-golang/invalid-bytes-length.mmdb +0 -1
  39. data/test/data/bad-data/maxminddb-golang/invalid-data-record-offset.mmdb +0 -0
  40. data/test/data/bad-data/maxminddb-golang/invalid-map-key-length.mmdb +0 -0
  41. data/test/data/bad-data/maxminddb-golang/invalid-string-length.mmdb +0 -1
  42. data/test/data/bad-data/maxminddb-golang/metadata-is-an-uint128.mmdb +0 -1
  43. data/test/data/bad-data/maxminddb-golang/unexpected-bytes.mmdb +0 -0
  44. data/test/data/bad-data/maxminddb-python/bad-unicode-in-map-key.mmdb +0 -0
  45. data/test/data/cmd/write-test-data/main.go +0 -68
  46. data/test/data/go.mod +0 -13
  47. data/test/data/go.sum +0 -16
  48. data/test/data/pkg/writer/decoder.go +0 -178
  49. data/test/data/pkg/writer/geoip2.go +0 -184
  50. data/test/data/pkg/writer/ip.go +0 -39
  51. data/test/data/pkg/writer/maxmind.go +0 -246
  52. data/test/data/pkg/writer/nestedstructures.go +0 -73
  53. data/test/data/pkg/writer/writer.go +0 -61
  54. data/test/data/source-data/GeoIP-Anonymous-Plus-Test.json +0 -175
  55. data/test/data/source-data/GeoIP2-Anonymous-IP-Test.json +0 -55
  56. data/test/data/source-data/GeoIP2-City-Test.json +0 -13272
  57. data/test/data/source-data/GeoIP2-Connection-Type-Test.json +0 -127
  58. data/test/data/source-data/GeoIP2-Country-Test.json +0 -15978
  59. data/test/data/source-data/GeoIP2-DensityIncome-Test.json +0 -14
  60. data/test/data/source-data/GeoIP2-Domain-Test.json +0 -457
  61. data/test/data/source-data/GeoIP2-Enterprise-Test.json +0 -1110
  62. data/test/data/source-data/GeoIP2-IP-Risk-Test.json +0 -31
  63. data/test/data/source-data/GeoIP2-ISP-Test.json +0 -12605
  64. data/test/data/source-data/GeoIP2-Precision-Enterprise-Sandbox-Test.json +0 -296
  65. data/test/data/source-data/GeoIP2-Precision-Enterprise-Test.json +0 -3189
  66. data/test/data/source-data/GeoIP2-Static-IP-Score-Test.json +0 -2147
  67. data/test/data/source-data/GeoIP2-User-Count-Test.json +0 -2855
  68. data/test/data/source-data/GeoLite2-ASN-Test.json +0 -4120
  69. data/test/data/source-data/GeoLite2-City-Test.json +0 -12969
  70. data/test/data/source-data/GeoLite2-Country-Test.json +0 -11369
  71. data/test/data/test-data/GeoIP-Anonymous-Plus-Test.mmdb +0 -0
  72. data/test/data/test-data/GeoIP2-Anonymous-IP-Test.mmdb +0 -0
  73. data/test/data/test-data/GeoIP2-City-Test-Broken-Double-Format.mmdb +0 -0
  74. data/test/data/test-data/GeoIP2-City-Test-Invalid-Node-Count.mmdb +0 -0
  75. data/test/data/test-data/GeoIP2-City-Test.mmdb +0 -0
  76. data/test/data/test-data/GeoIP2-Connection-Type-Test.mmdb +0 -0
  77. data/test/data/test-data/GeoIP2-Country-Test.mmdb +0 -0
  78. data/test/data/test-data/GeoIP2-DensityIncome-Test.mmdb +0 -0
  79. data/test/data/test-data/GeoIP2-Domain-Test.mmdb +0 -0
  80. data/test/data/test-data/GeoIP2-Enterprise-Test.mmdb +0 -0
  81. data/test/data/test-data/GeoIP2-IP-Risk-Test.mmdb +0 -0
  82. data/test/data/test-data/GeoIP2-ISP-Test.mmdb +0 -0
  83. data/test/data/test-data/GeoIP2-Precision-Enterprise-Test.mmdb +0 -0
  84. data/test/data/test-data/GeoIP2-Static-IP-Score-Test.mmdb +0 -0
  85. data/test/data/test-data/GeoIP2-User-Count-Test.mmdb +0 -0
  86. data/test/data/test-data/GeoLite2-ASN-Test.mmdb +0 -0
  87. data/test/data/test-data/GeoLite2-City-Test.mmdb +0 -0
  88. data/test/data/test-data/GeoLite2-Country-Test.mmdb +0 -0
  89. data/test/data/test-data/MaxMind-DB-no-ipv4-search-tree.mmdb +0 -0
  90. data/test/data/test-data/MaxMind-DB-string-value-entries.mmdb +0 -0
  91. data/test/data/test-data/MaxMind-DB-test-broken-pointers-24.mmdb +0 -0
  92. data/test/data/test-data/MaxMind-DB-test-broken-search-tree-24.mmdb +0 -0
  93. data/test/data/test-data/MaxMind-DB-test-decoder.mmdb +0 -0
  94. data/test/data/test-data/MaxMind-DB-test-ipv4-24.mmdb +0 -0
  95. data/test/data/test-data/MaxMind-DB-test-ipv4-28.mmdb +0 -0
  96. data/test/data/test-data/MaxMind-DB-test-ipv4-32.mmdb +0 -0
  97. data/test/data/test-data/MaxMind-DB-test-ipv6-24.mmdb +0 -0
  98. data/test/data/test-data/MaxMind-DB-test-ipv6-28.mmdb +0 -0
  99. data/test/data/test-data/MaxMind-DB-test-ipv6-32.mmdb +0 -0
  100. data/test/data/test-data/MaxMind-DB-test-metadata-pointers.mmdb +0 -0
  101. data/test/data/test-data/MaxMind-DB-test-mixed-24.mmdb +0 -0
  102. data/test/data/test-data/MaxMind-DB-test-mixed-28.mmdb +0 -0
  103. data/test/data/test-data/MaxMind-DB-test-mixed-32.mmdb +0 -0
  104. data/test/data/test-data/MaxMind-DB-test-nested.mmdb +0 -0
  105. data/test/data/test-data/MaxMind-DB-test-pointer-decoder.mmdb +0 -0
  106. data/test/data/test-data/README.md +0 -42
  107. data/test/data/test-data/maps-with-pointers.raw +0 -0
  108. data/test/data/tidyall.ini +0 -5
  109. data/test/test_client.rb +0 -467
  110. data/test/test_model_country.rb +0 -95
  111. data/test/test_model_names.rb +0 -50
  112. data/test/test_reader.rb +0 -589
@@ -13,7 +13,7 @@ module MaxMind
13
13
  class Country < Place
14
14
  # A value from 0-100 indicating MaxMind's confidence that the country is
15
15
  # correct. This attribute is only available from the Insights service and
16
- # the GeoIP2 Enterprise database.
16
+ # the GeoIP Enterprise database.
17
17
  #
18
18
  # @return [Integer, nil]
19
19
  def confidence
@@ -63,7 +63,7 @@ module MaxMind
63
63
  get('population_density')
64
64
  end
65
65
 
66
- # The time zone associated with location, as specified by the IANA Time
66
+ # The time zone associated with the location, as specified by the IANA Time
67
67
  # Zone Database, e.g., "America/New_York". See
68
68
  # https://www.iana.org/time-zones.
69
69
  #
@@ -22,7 +22,7 @@ module MaxMind
22
22
 
23
23
  # A value from 0-100 indicating MaxMind's confidence that the postal code
24
24
  # is correct. This attribute is only available from the Insights service
25
- # and the GeoIP2 Enterprise database.
25
+ # and the GeoIP Enterprise database.
26
26
  #
27
27
  # @return [Integer, nil]
28
28
  def confidence
@@ -14,7 +14,7 @@ module MaxMind
14
14
  class Subdivision < Place
15
15
  # This is a value from 0-100 indicating MaxMind's confidence that the
16
16
  # subdivision is correct. This attribute is only available from the
17
- # Insights service and the GeoIP2 Enterprise database.
17
+ # Insights service and the GeoIP Enterprise database.
18
18
  #
19
19
  # @return [Integer, nil]
20
20
  def confidence
@@ -41,9 +41,9 @@ module MaxMind
41
41
  get('autonomous_system_organization')
42
42
  end
43
43
 
44
- # The connection type may take the following values: "Dialup",
45
- # "Cable/DSL", "Corporate", "Cellular", and "Satellite". Additional
46
- # values may be added in the future. This attribute is only available
44
+ # The connection type may take the following values: "Cable/DSL",
45
+ # "Corporate", "Cellular", and "Satellite". Additional values may be
46
+ # added in the future. This attribute is only available
47
47
  # from the City Plus and Insights web services and the Enterprise
48
48
  # database.
49
49
  #
@@ -52,7 +52,7 @@ module MaxMind
52
52
  get('connection_type')
53
53
  end
54
54
 
55
- # The second level domain associated with the IP address. This will be
55
+ # The second-level domain associated with the IP address. This will be
56
56
  # something like "example.com" or "example.co.uk", not "foo.example.com".
57
57
  # This attribute is only available from the City Plus and Insights web
58
58
  # services and the Enterprise database.
@@ -103,7 +103,7 @@ module MaxMind
103
103
  # {https://en.wikipedia.org/wiki/Anycast anycast network}.
104
104
  #
105
105
  # This property is only available from the Country, City Plus, and
106
- # Insights web services and the GeoIP2 Country, City, and Enterprise
106
+ # Insights web services and the GeoIP Country, City, and Enterprise
107
107
  # databases.
108
108
  #
109
109
  # @return [Boolean]
@@ -242,7 +242,15 @@ module MaxMind
242
242
  # services is more static than the IP risk score provided in minFraud
243
243
  # and is not responsive to traffic on your network. If you need realtime
244
244
  # IP risk scoring based on behavioral signals on your own network, please
245
- # use minFraud. This property is only available from Insights.
245
+ # use minFraud.
246
+ #
247
+ # We do not provide an IP risk snapshot for low-risk networks. If this
248
+ # field is not populated, we either do not have signals for the network
249
+ # or the signals we have show that the network is low-risk. If you would
250
+ # like to get signals for low-risk networks, please use the minFraud web
251
+ # services.
252
+ #
253
+ # This property is only available from Insights.
246
254
  #
247
255
  # @return [Float, nil]
248
256
  def ip_risk_snapshot
@@ -258,7 +266,6 @@ module MaxMind
258
266
  # * college
259
267
  # * consumer_privacy_network
260
268
  # * content_delivery_network
261
- # * dialup
262
269
  # * government
263
270
  # * hosting
264
271
  # * library
@@ -3,6 +3,6 @@
3
3
  module MaxMind
4
4
  module GeoIP2
5
5
  # The Gem version.
6
- VERSION = '1.4.0'
6
+ VERSION = '1.6.0'
7
7
  end
8
8
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: maxmind-geoip2
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
4
+ version: 1.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - William Storey
@@ -13,16 +13,22 @@ dependencies:
13
13
  name: connection_pool
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
- - - "~>"
16
+ - - ">="
17
17
  - !ruby/object:Gem::Version
18
18
  version: '2.2'
19
+ - - "<"
20
+ - !ruby/object:Gem::Version
21
+ version: '4.0'
19
22
  type: :runtime
20
23
  prerelease: false
21
24
  version_requirements: !ruby/object:Gem::Requirement
22
25
  requirements:
23
- - - "~>"
26
+ - - ">="
24
27
  - !ruby/object:Gem::Version
25
28
  version: '2.2'
29
+ - - "<"
30
+ - !ruby/object:Gem::Version
31
+ version: '4.0'
26
32
  - !ruby/object:Gem::Dependency
27
33
  name: http
28
34
  requirement: !ruby/object:Gem::Requirement
@@ -32,7 +38,7 @@ dependencies:
32
38
  version: '4.3'
33
39
  - - "<"
34
40
  - !ruby/object:Gem::Version
35
- version: '6.0'
41
+ version: '7.0'
36
42
  type: :runtime
37
43
  prerelease: false
38
44
  version_requirements: !ruby/object:Gem::Requirement
@@ -42,7 +48,7 @@ dependencies:
42
48
  version: '4.3'
43
49
  - - "<"
44
50
  - !ruby/object:Gem::Version
45
- version: '6.0'
51
+ version: '7.0'
46
52
  - !ruby/object:Gem::Dependency
47
53
  name: maxmind-db
48
54
  requirement: !ruby/object:Gem::Requirement
@@ -169,7 +175,7 @@ dependencies:
169
175
  - - ">="
170
176
  - !ruby/object:Gem::Version
171
177
  version: '0'
172
- description: A gem for interacting with the GeoIP2 webservices and databases. MaxMind
178
+ description: A gem for interacting with the GeoIP webservices and databases. MaxMind
173
179
  provides geolocation data as downloadable databases as well as through a webservice.
174
180
  email: support@maxmind.com
175
181
  executables: []
@@ -177,14 +183,9 @@ extensions: []
177
183
  extra_rdoc_files: []
178
184
  files:
179
185
  - CHANGELOG.md
180
- - CLAUDE.md
181
- - Gemfile
182
- - Gemfile.lock
183
186
  - LICENSE-APACHE
184
187
  - LICENSE-MIT
185
- - README.dev.md
186
188
  - README.md
187
- - Rakefile
188
189
  - lib/maxmind/geoip2.rb
189
190
  - lib/maxmind/geoip2/client.rb
190
191
  - lib/maxmind/geoip2/errors.rb
@@ -202,6 +203,7 @@ files:
202
203
  - lib/maxmind/geoip2/reader.rb
203
204
  - lib/maxmind/geoip2/record/abstract.rb
204
205
  - lib/maxmind/geoip2/record/anonymizer.rb
206
+ - lib/maxmind/geoip2/record/anonymizer_feed.rb
205
207
  - lib/maxmind/geoip2/record/city.rb
206
208
  - lib/maxmind/geoip2/record/continent.rb
207
209
  - lib/maxmind/geoip2/record/country.rb
@@ -213,89 +215,6 @@ files:
213
215
  - lib/maxmind/geoip2/record/subdivision.rb
214
216
  - lib/maxmind/geoip2/record/traits.rb
215
217
  - lib/maxmind/geoip2/version.rb
216
- - maxmind-geoip2.gemspec
217
- - test/data/LICENSE-APACHE
218
- - test/data/LICENSE-MIT
219
- - test/data/MaxMind-DB-spec.md
220
- - test/data/README.md
221
- - test/data/bad-data/README.md
222
- - test/data/bad-data/libmaxminddb/libmaxminddb-offset-integer-overflow.mmdb
223
- - test/data/bad-data/maxminddb-golang/cyclic-data-structure.mmdb
224
- - test/data/bad-data/maxminddb-golang/invalid-bytes-length.mmdb
225
- - test/data/bad-data/maxminddb-golang/invalid-data-record-offset.mmdb
226
- - test/data/bad-data/maxminddb-golang/invalid-map-key-length.mmdb
227
- - test/data/bad-data/maxminddb-golang/invalid-string-length.mmdb
228
- - test/data/bad-data/maxminddb-golang/metadata-is-an-uint128.mmdb
229
- - test/data/bad-data/maxminddb-golang/unexpected-bytes.mmdb
230
- - test/data/bad-data/maxminddb-python/bad-unicode-in-map-key.mmdb
231
- - test/data/cmd/write-test-data/main.go
232
- - test/data/go.mod
233
- - test/data/go.sum
234
- - test/data/pkg/writer/decoder.go
235
- - test/data/pkg/writer/geoip2.go
236
- - test/data/pkg/writer/ip.go
237
- - test/data/pkg/writer/maxmind.go
238
- - test/data/pkg/writer/nestedstructures.go
239
- - test/data/pkg/writer/writer.go
240
- - test/data/source-data/GeoIP-Anonymous-Plus-Test.json
241
- - test/data/source-data/GeoIP2-Anonymous-IP-Test.json
242
- - test/data/source-data/GeoIP2-City-Test.json
243
- - test/data/source-data/GeoIP2-Connection-Type-Test.json
244
- - test/data/source-data/GeoIP2-Country-Test.json
245
- - test/data/source-data/GeoIP2-DensityIncome-Test.json
246
- - test/data/source-data/GeoIP2-Domain-Test.json
247
- - test/data/source-data/GeoIP2-Enterprise-Test.json
248
- - test/data/source-data/GeoIP2-IP-Risk-Test.json
249
- - test/data/source-data/GeoIP2-ISP-Test.json
250
- - test/data/source-data/GeoIP2-Precision-Enterprise-Sandbox-Test.json
251
- - test/data/source-data/GeoIP2-Precision-Enterprise-Test.json
252
- - test/data/source-data/GeoIP2-Static-IP-Score-Test.json
253
- - test/data/source-data/GeoIP2-User-Count-Test.json
254
- - test/data/source-data/GeoLite2-ASN-Test.json
255
- - test/data/source-data/GeoLite2-City-Test.json
256
- - test/data/source-data/GeoLite2-Country-Test.json
257
- - test/data/test-data/GeoIP-Anonymous-Plus-Test.mmdb
258
- - test/data/test-data/GeoIP2-Anonymous-IP-Test.mmdb
259
- - test/data/test-data/GeoIP2-City-Test-Broken-Double-Format.mmdb
260
- - test/data/test-data/GeoIP2-City-Test-Invalid-Node-Count.mmdb
261
- - test/data/test-data/GeoIP2-City-Test.mmdb
262
- - test/data/test-data/GeoIP2-Connection-Type-Test.mmdb
263
- - test/data/test-data/GeoIP2-Country-Test.mmdb
264
- - test/data/test-data/GeoIP2-DensityIncome-Test.mmdb
265
- - test/data/test-data/GeoIP2-Domain-Test.mmdb
266
- - test/data/test-data/GeoIP2-Enterprise-Test.mmdb
267
- - test/data/test-data/GeoIP2-IP-Risk-Test.mmdb
268
- - test/data/test-data/GeoIP2-ISP-Test.mmdb
269
- - test/data/test-data/GeoIP2-Precision-Enterprise-Test.mmdb
270
- - test/data/test-data/GeoIP2-Static-IP-Score-Test.mmdb
271
- - test/data/test-data/GeoIP2-User-Count-Test.mmdb
272
- - test/data/test-data/GeoLite2-ASN-Test.mmdb
273
- - test/data/test-data/GeoLite2-City-Test.mmdb
274
- - test/data/test-data/GeoLite2-Country-Test.mmdb
275
- - test/data/test-data/MaxMind-DB-no-ipv4-search-tree.mmdb
276
- - test/data/test-data/MaxMind-DB-string-value-entries.mmdb
277
- - test/data/test-data/MaxMind-DB-test-broken-pointers-24.mmdb
278
- - test/data/test-data/MaxMind-DB-test-broken-search-tree-24.mmdb
279
- - test/data/test-data/MaxMind-DB-test-decoder.mmdb
280
- - test/data/test-data/MaxMind-DB-test-ipv4-24.mmdb
281
- - test/data/test-data/MaxMind-DB-test-ipv4-28.mmdb
282
- - test/data/test-data/MaxMind-DB-test-ipv4-32.mmdb
283
- - test/data/test-data/MaxMind-DB-test-ipv6-24.mmdb
284
- - test/data/test-data/MaxMind-DB-test-ipv6-28.mmdb
285
- - test/data/test-data/MaxMind-DB-test-ipv6-32.mmdb
286
- - test/data/test-data/MaxMind-DB-test-metadata-pointers.mmdb
287
- - test/data/test-data/MaxMind-DB-test-mixed-24.mmdb
288
- - test/data/test-data/MaxMind-DB-test-mixed-28.mmdb
289
- - test/data/test-data/MaxMind-DB-test-mixed-32.mmdb
290
- - test/data/test-data/MaxMind-DB-test-nested.mmdb
291
- - test/data/test-data/MaxMind-DB-test-pointer-decoder.mmdb
292
- - test/data/test-data/README.md
293
- - test/data/test-data/maps-with-pointers.raw
294
- - test/data/tidyall.ini
295
- - test/test_client.rb
296
- - test/test_model_country.rb
297
- - test/test_model_names.rb
298
- - test/test_reader.rb
299
218
  homepage: https://github.com/maxmind/GeoIP2-ruby
300
219
  licenses:
301
220
  - Apache-2.0
@@ -321,7 +240,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
321
240
  - !ruby/object:Gem::Version
322
241
  version: '0'
323
242
  requirements: []
324
- rubygems_version: 3.6.9
243
+ rubygems_version: 4.0.10
325
244
  specification_version: 4
326
- summary: A gem for interacting with the GeoIP2 webservices and databases.
245
+ summary: A gem for interacting with the GeoIP webservices and databases.
327
246
  test_files: []
data/CLAUDE.md DELETED
@@ -1,390 +0,0 @@
1
- # CLAUDE.md
2
-
3
- This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
-
5
- ## Project Overview
6
-
7
- **GeoIP2-ruby** is MaxMind's official Ruby client library for:
8
- - **GeoIP2/GeoLite2 Web Services**: Country, City, and Insights endpoints
9
- - **GeoIP2/GeoLite2 Databases**: Local MMDB file reading for various database types (City, Country, ASN, Anonymous IP, Anonymous Plus, ISP, etc.)
10
-
11
- The library provides both web service clients and database readers that return strongly-typed model objects containing geographic, ISP, anonymizer, and other IP-related data.
12
-
13
- **Key Technologies:**
14
- - Ruby 3.2+ (uses frozen string literals and modern Ruby features)
15
- - MaxMind DB Reader for binary database files
16
- - HTTP gem for web service client functionality
17
- - Minitest for testing
18
- - RuboCop with multiple plugins for code quality
19
-
20
- ## Code Architecture
21
-
22
- ### Package Structure
23
-
24
- ```
25
- lib/maxmind/geoip2/
26
- ├── model/ # Response models (City, Insights, AnonymousIP, etc.)
27
- ├── record/ # Data records (City, Location, Traits, etc.)
28
- ├── client.rb # HTTP client for MaxMind web services
29
- ├── reader.rb # Local MMDB file reader
30
- ├── errors.rb # Custom exceptions for error handling
31
- └── version.rb # Version constant
32
- ```
33
-
34
- ### Key Design Patterns
35
-
36
- #### 1. **Attr Reader Pattern for Immutable Data**
37
-
38
- Models expose data through `attr_reader` attributes that are initialized in the constructor. Unlike PHP's readonly properties, Ruby uses instance variables with attr_reader:
39
-
40
- ```ruby
41
- class City < Country
42
- attr_reader :city
43
- attr_reader :location
44
- attr_reader :postal
45
- attr_reader :subdivisions
46
-
47
- def initialize(record, locales)
48
- super
49
- @city = MaxMind::GeoIP2::Record::City.new(record['city'], locales)
50
- @location = MaxMind::GeoIP2::Record::Location.new(record['location'])
51
- @postal = MaxMind::GeoIP2::Record::Postal.new(record['postal'])
52
- @subdivisions = create_subdivisions(record['subdivisions'], locales)
53
- end
54
- end
55
- ```
56
-
57
- **Key Points:**
58
- - Instance variables are set in the constructor
59
- - Use `attr_reader` to expose them
60
- - Models and records are initialized from hash data (from JSON/DB)
61
- - Records are composed objects (City contains City record, Location record, etc.)
62
-
63
- #### 2. **Inheritance Hierarchies**
64
-
65
- Models follow clear inheritance patterns:
66
- - `Country` → base model with country/continent data
67
- - `City` extends `Country` → adds city, location, postal, subdivisions
68
- - `Insights` extends `City` → adds additional web service fields (web service only)
69
- - `Enterprise` extends `City` → adds enterprise-specific fields
70
-
71
- Records have similar patterns:
72
- - `Abstract` → base with `get` method for accessing hash data
73
- - `Place` extends `Abstract` → adds names/locales handling
74
- - Specific records (`City`, `Country`, etc.) extend `Place` or `Abstract`
75
-
76
- #### 3. **Get Method Pattern for Data Access**
77
-
78
- Both models and records use a protected `get` method to safely access hash data:
79
-
80
- ```ruby
81
- def get(key)
82
- if @record.nil? || !@record.key?(key)
83
- return false if key.start_with?('is_')
84
- return nil
85
- end
86
-
87
- @record[key]
88
- end
89
- ```
90
-
91
- - Returns `false` for missing boolean fields (starting with `is_`)
92
- - Returns `nil` for missing optional fields
93
- - Records store the raw hash in `@record` instance variable
94
-
95
- Public methods expose data through the `get` method:
96
-
97
- ```ruby
98
- def anonymizer_confidence
99
- get('anonymizer_confidence')
100
- end
101
-
102
- def provider_name
103
- get('provider_name')
104
- end
105
- ```
106
-
107
- #### 4. **Lazy Parsing for Special Types**
108
-
109
- Some fields require parsing and are computed lazily:
110
-
111
- ```ruby
112
- def network_last_seen
113
- return @network_last_seen if defined?(@network_last_seen)
114
-
115
- date_string = get('network_last_seen')
116
-
117
- if !date_string
118
- return nil
119
- end
120
-
121
- @network_last_seen = Date.parse(date_string)
122
- end
123
- ```
124
-
125
- - Use `defined?(@variable)` to check if already parsed
126
- - Parse only once and cache in instance variable
127
- - Handle nil cases before parsing
128
-
129
- #### 5. **Web Service Only vs Database Models**
130
-
131
- Some models are only used by web services and do **not** need MaxMind DB support:
132
-
133
- **Web Service Only Models**:
134
- - Models that are exclusive to web service responses
135
- - Simpler implementation, just inherit and define in model hierarchy
136
- - Example: `Insights` (extends City but used only for web service)
137
-
138
- **Database-Supported Models**:
139
- - Models used by both web services and database files
140
- - Reader has specific methods (e.g., `anonymous_ip`, `anonymous_plus`, `city`)
141
- - Must handle MaxMind DB format data structures
142
- - Example: `City`, `Country`, `AnonymousIP`, `AnonymousPlus`
143
-
144
- ## Testing Conventions
145
-
146
- ### Running Tests
147
-
148
- ```bash
149
- # Install dependencies
150
- bundle install
151
-
152
- # Run all tests
153
- bundle exec rake test
154
-
155
- # Run tests and RuboCop
156
- bundle exec rake # default task
157
-
158
- # Run RuboCop only
159
- bundle exec rake rubocop
160
-
161
- # Run specific test file
162
- ruby -Ilib:test test/test_reader.rb
163
- ```
164
-
165
- ### Test Structure
166
-
167
- Tests are organized by functionality:
168
- - `test/test_reader.rb` - Database reader tests
169
- - `test/test_client.rb` - Web service client tests
170
- - `test/test_model_*.rb` - Model-specific tests
171
- - `test/data/` - Test fixtures and sample database files
172
-
173
- ### Test Patterns
174
-
175
- Tests use Minitest with a constant for test data:
176
-
177
- ```ruby
178
- class CountryModelTest < Minitest::Test
179
- RAW = {
180
- 'continent' => {
181
- 'code' => 'NA',
182
- 'geoname_id' => 42,
183
- 'names' => { 'en' => 'North America' },
184
- },
185
- 'country' => {
186
- 'geoname_id' => 1,
187
- 'iso_code' => 'US',
188
- 'names' => { 'en' => 'United States of America' },
189
- },
190
- 'traits' => {
191
- 'ip_address' => '1.2.3.4',
192
- 'prefix_length' => 24,
193
- },
194
- }.freeze
195
-
196
- def test_values
197
- model = MaxMind::GeoIP2::Model::Country.new(RAW, ['en'])
198
-
199
- assert_equal(42, model.continent.geoname_id)
200
- assert_equal('NA', model.continent.code)
201
- assert_equal('United States of America', model.country.name)
202
- end
203
- end
204
- ```
205
-
206
- When adding new fields to models:
207
- 1. Update the `RAW` constant to include the new field
208
- 2. Add assertions to verify the field is properly populated
209
- 3. Test both presence and absence of the field (nil handling)
210
- 4. Test with different values if applicable
211
-
212
- ## Working with This Codebase
213
-
214
- ### Adding New Fields to Existing Models
215
-
216
- For database models (like AnonymousPlus):
217
-
218
- 1. **Add a public method** that calls `get`:
219
- ```ruby
220
- # A description of the field.
221
- #
222
- # @return [Type, nil]
223
- def field_name
224
- get('field_name')
225
- end
226
- ```
227
-
228
- 2. **For fields requiring parsing** (dates, complex types), use lazy loading:
229
- ```ruby
230
- def network_last_seen
231
- return @network_last_seen if defined?(@network_last_seen)
232
-
233
- date_string = get('network_last_seen')
234
-
235
- if !date_string
236
- return nil
237
- end
238
-
239
- @network_last_seen = Date.parse(date_string)
240
- end
241
- ```
242
-
243
- For composed models (like City, Country):
244
-
245
- 1. **Add `attr_reader`** for the new record/field:
246
- ```ruby
247
- attr_reader :new_field
248
- ```
249
-
250
- 2. **Initialize in constructor**:
251
- ```ruby
252
- def initialize(record, locales)
253
- super
254
- @new_field = record['new_field']
255
- end
256
- ```
257
-
258
- 3. **Provide comprehensive YARD documentation** (`@return` tags)
259
- 4. **Update tests** to include the new field in test data and assertions
260
- 5. **Update CHANGELOG.md** with the change
261
-
262
- ### Adding New Models
263
-
264
- When creating a new model class:
265
-
266
- 1. **Determine if web service only or database-supported**
267
- 2. **Follow the pattern** from existing similar models
268
- 3. **Extend the appropriate base class** (e.g., `Country`, `City`, or standalone)
269
- 4. **Use `attr_reader`** for composed record objects
270
- 5. **Provide comprehensive YARD documentation** for all public methods
271
- 6. **Add corresponding tests** with full coverage
272
- 7. **If database-supported**, add a method to `Reader` class
273
-
274
- ### Deprecation Guidelines
275
-
276
- When deprecating fields:
277
-
278
- 1. **Use `@deprecated` in YARD doc** with version and alternative:
279
- ```ruby
280
- # This field is deprecated as of version 2.0.0.
281
- # Use the anonymizer object from the Insights response instead.
282
- #
283
- # @return [Boolean]
284
- # @deprecated since 2.0.0
285
- def is_anonymous
286
- get('is_anonymous')
287
- end
288
- ```
289
-
290
- 2. **Keep deprecated fields functional** - don't break existing code
291
- 3. **Update CHANGELOG.md** with deprecation notices
292
- 4. **Document alternatives** in the deprecation message
293
-
294
- ### CHANGELOG.md Format
295
-
296
- Always update `CHANGELOG.md` for user-facing changes.
297
-
298
- **Important**: Do not add a date to changelog entries until release time.
299
-
300
- - If there's an existing version entry without a date (e.g., `1.5.0`), add your changes there
301
- - If creating a new version entry, don't include a date - it will be added at release time
302
- - Use past tense for descriptions
303
-
304
- ```markdown
305
- ## 1.5.0
306
-
307
- * A new `field_name` method has been added to `MaxMind::GeoIP2::Model::ModelName`.
308
- This method provides information about...
309
- * The `old_field` method in `MaxMind::GeoIP2::Model::ModelName` has been deprecated.
310
- Please use `new_field` instead.
311
- ```
312
-
313
- ## Common Pitfalls and Solutions
314
-
315
- ### Problem: Incorrect Nil Handling
316
-
317
- Using the wrong nil check can cause unexpected behavior.
318
-
319
- **Solution**: Follow these patterns:
320
- - Use `if !variable` or `if variable.nil?` to check for nil
321
- - The `get` method returns `nil` for missing keys (except `is_*` keys which return `false`)
322
- - Use `defined?(@variable)` to check if an instance variable has been set (for lazy loading)
323
-
324
- ### Problem: Missing YARD Documentation
325
-
326
- New methods without documentation make the API harder to use.
327
-
328
- **Solution**: Always add YARD documentation:
329
- - Use `@return [Type, nil]` for the return type
330
- - Add a description of what the method returns
331
- - Use `@deprecated since X.Y.Z` for deprecated methods
332
- - Include examples in model class documentation if helpful
333
-
334
- ### Problem: Test Failures After Adding Fields
335
-
336
- Tests fail because fixtures don't include new fields.
337
-
338
- **Solution**: Update all related tests:
339
- 1. Add field to test `RAW` constant or test data hash
340
- 2. Add assertions for the new field
341
- 3. Test nil case if field is optional
342
- 4. Test different data types if applicable
343
-
344
- ## Code Style Requirements
345
-
346
- - **RuboCop enforced** with multiple plugins (minitest, performance, rake, thread_safety)
347
- - **Frozen string literals** (`# frozen_string_literal: true`) in all files
348
- - **Target Ruby 3.2+**
349
- - **No metrics cops** - AbcSize, ClassLength, MethodLength disabled
350
- - **Trailing commas allowed** in arrays, hashes, and arguments
351
- - **Use `if !condition`** instead of `unless condition` (NegatedIf disabled)
352
-
353
- Key RuboCop configurations:
354
- - Line length not enforced
355
- - Format string token checks disabled
356
- - Numeric predicates allowed in any style
357
- - Multiple assertions allowed in tests
358
-
359
- ## Development Workflow
360
-
361
- ### Setup
362
- ```bash
363
- bundle install
364
- ```
365
-
366
- ### Before Committing
367
- ```bash
368
- # Run tests and linting
369
- bundle exec rake
370
-
371
- # Or run separately
372
- bundle exec rake test
373
- bundle exec rake rubocop
374
- ```
375
-
376
- ### Running Single Test
377
- ```bash
378
- ruby -Ilib:test test/test_reader.rb
379
- ```
380
-
381
- ### Version Requirements
382
- - **Ruby 3.2+** required
383
- - Target compatibility should match current supported Ruby versions (3.2-3.4)
384
-
385
- ## Additional Resources
386
-
387
- - [API Documentation](https://www.rubydoc.info/gems/maxmind-geoip2)
388
- - [GeoIP2 Web Services Docs](https://dev.maxmind.com/geoip/docs/web-services)
389
- - [MaxMind DB Format](https://maxmind.github.io/MaxMind-DB/)
390
- - GitHub Issues: https://github.com/maxmind/GeoIP2-ruby/issues
data/Gemfile DELETED
@@ -1,5 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- source 'https://rubygems.org'
4
-
5
- gemspec