maxmind-geoip2 0.2.0 → 0.3.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 (90) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +6 -0
  3. data/Gemfile.lock +3 -3
  4. data/lib/maxmind/geoip2/client.rb +269 -267
  5. data/lib/maxmind/geoip2/errors.rb +0 -7
  6. data/lib/maxmind/geoip2/model/abstract.rb +19 -15
  7. data/lib/maxmind/geoip2/model/anonymous_ip.rb +54 -50
  8. data/lib/maxmind/geoip2/model/asn.rb +33 -29
  9. data/lib/maxmind/geoip2/model/city.rb +59 -55
  10. data/lib/maxmind/geoip2/model/connection_type.rb +27 -23
  11. data/lib/maxmind/geoip2/model/country.rb +57 -53
  12. data/lib/maxmind/geoip2/model/domain.rb +27 -23
  13. data/lib/maxmind/geoip2/model/enterprise.rb +13 -9
  14. data/lib/maxmind/geoip2/model/insights.rb +12 -8
  15. data/lib/maxmind/geoip2/model/isp.rb +45 -41
  16. data/lib/maxmind/geoip2/reader.rb +242 -240
  17. data/lib/maxmind/geoip2/record/abstract.rb +17 -13
  18. data/lib/maxmind/geoip2/record/city.rb +33 -29
  19. data/lib/maxmind/geoip2/record/continent.rb +32 -28
  20. data/lib/maxmind/geoip2/record/country.rb +47 -43
  21. data/lib/maxmind/geoip2/record/location.rb +64 -60
  22. data/lib/maxmind/geoip2/record/maxmind.rb +14 -10
  23. data/lib/maxmind/geoip2/record/place.rb +22 -18
  24. data/lib/maxmind/geoip2/record/postal.rb +26 -22
  25. data/lib/maxmind/geoip2/record/represented_country.rb +20 -16
  26. data/lib/maxmind/geoip2/record/subdivision.rb +42 -38
  27. data/lib/maxmind/geoip2/record/traits.rb +195 -191
  28. data/maxmind-geoip2.gemspec +1 -1
  29. data/test/data/LICENSE +4 -0
  30. data/test/data/MaxMind-DB-spec.md +570 -0
  31. data/test/data/MaxMind-DB-test-metadata-pointers.mmdb +0 -0
  32. data/test/data/README.md +4 -0
  33. data/test/data/bad-data/README.md +7 -0
  34. data/test/data/bad-data/libmaxminddb/libmaxminddb-offset-integer-overflow.mmdb +0 -0
  35. data/test/data/bad-data/maxminddb-golang/cyclic-data-structure.mmdb +0 -0
  36. data/test/data/bad-data/maxminddb-golang/invalid-bytes-length.mmdb +1 -0
  37. data/test/data/bad-data/maxminddb-golang/invalid-data-record-offset.mmdb +0 -0
  38. data/test/data/bad-data/maxminddb-golang/invalid-map-key-length.mmdb +0 -0
  39. data/test/data/bad-data/maxminddb-golang/invalid-string-length.mmdb +1 -0
  40. data/test/data/bad-data/maxminddb-golang/metadata-is-an-uint128.mmdb +1 -0
  41. data/test/data/bad-data/maxminddb-golang/unexpected-bytes.mmdb +0 -0
  42. data/test/data/perltidyrc +12 -0
  43. data/test/data/source-data/GeoIP2-Anonymous-IP-Test.json +48 -0
  44. data/test/data/source-data/GeoIP2-City-Test.json +12852 -0
  45. data/test/data/source-data/GeoIP2-Connection-Type-Test.json +102 -0
  46. data/test/data/source-data/GeoIP2-Country-Test.json +15916 -0
  47. data/test/data/source-data/GeoIP2-DensityIncome-Test.json +14 -0
  48. data/test/data/source-data/GeoIP2-Domain-Test.json +452 -0
  49. data/test/data/source-data/GeoIP2-Enterprise-Test.json +687 -0
  50. data/test/data/source-data/GeoIP2-ISP-Test.json +12593 -0
  51. data/test/data/source-data/GeoIP2-Precision-Enterprise-Test.json +2061 -0
  52. data/test/data/source-data/GeoIP2-Static-IP-Score-Test.json +2132 -0
  53. data/test/data/source-data/GeoIP2-User-Count-Test.json +2837 -0
  54. data/test/data/source-data/GeoLite2-ASN-Test.json +37 -0
  55. data/test/data/source-data/README +15 -0
  56. data/test/data/test-data/GeoIP2-Anonymous-IP-Test.mmdb +0 -0
  57. data/test/data/test-data/GeoIP2-City-Test-Broken-Double-Format.mmdb +0 -0
  58. data/test/data/test-data/GeoIP2-City-Test-Invalid-Node-Count.mmdb +0 -0
  59. data/test/data/test-data/GeoIP2-City-Test.mmdb +0 -0
  60. data/test/data/test-data/GeoIP2-Connection-Type-Test.mmdb +0 -0
  61. data/test/data/test-data/GeoIP2-Country-Test.mmdb +0 -0
  62. data/test/data/test-data/GeoIP2-DensityIncome-Test.mmdb +0 -0
  63. data/test/data/test-data/GeoIP2-Domain-Test.mmdb +0 -0
  64. data/test/data/test-data/GeoIP2-Enterprise-Test.mmdb +0 -0
  65. data/test/data/test-data/GeoIP2-ISP-Test.mmdb +0 -0
  66. data/test/data/test-data/GeoIP2-Precision-Enterprise-Test.mmdb +0 -0
  67. data/test/data/test-data/GeoIP2-Static-IP-Score-Test.mmdb +0 -0
  68. data/test/data/test-data/GeoIP2-User-Count-Test.mmdb +0 -0
  69. data/test/data/test-data/GeoLite2-ASN-Test.mmdb +0 -0
  70. data/test/data/test-data/MaxMind-DB-no-ipv4-search-tree.mmdb +0 -0
  71. data/test/data/test-data/MaxMind-DB-string-value-entries.mmdb +0 -0
  72. data/test/data/test-data/MaxMind-DB-test-broken-pointers-24.mmdb +0 -0
  73. data/test/data/test-data/MaxMind-DB-test-broken-search-tree-24.mmdb +0 -0
  74. data/test/data/test-data/MaxMind-DB-test-decoder.mmdb +0 -0
  75. data/test/data/test-data/MaxMind-DB-test-ipv4-24.mmdb +0 -0
  76. data/test/data/test-data/MaxMind-DB-test-ipv4-28.mmdb +0 -0
  77. data/test/data/test-data/MaxMind-DB-test-ipv4-32.mmdb +0 -0
  78. data/test/data/test-data/MaxMind-DB-test-ipv6-24.mmdb +0 -0
  79. data/test/data/test-data/MaxMind-DB-test-ipv6-28.mmdb +0 -0
  80. data/test/data/test-data/MaxMind-DB-test-ipv6-32.mmdb +0 -0
  81. data/test/data/test-data/MaxMind-DB-test-metadata-pointers.mmdb +0 -0
  82. data/test/data/test-data/MaxMind-DB-test-mixed-24.mmdb +0 -0
  83. data/test/data/test-data/MaxMind-DB-test-mixed-28.mmdb +0 -0
  84. data/test/data/test-data/MaxMind-DB-test-mixed-32.mmdb +0 -0
  85. data/test/data/test-data/MaxMind-DB-test-nested.mmdb +0 -0
  86. data/test/data/test-data/README.md +26 -0
  87. data/test/data/test-data/maps-with-pointers.raw +0 -0
  88. data/test/data/test-data/write-test-data.pl +641 -0
  89. data/test/data/tidyall.ini +5 -0
  90. metadata +64 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 107c7822a5a2de18a3339637547ca8fd8eef5163
4
- data.tar.gz: 8d730256e5f036178cf13cbd69ed5be2b86afc10
2
+ SHA256:
3
+ metadata.gz: 42699226c0ab8ec1152f4c56929c830916d7c226097082ae95959199d8796aa8
4
+ data.tar.gz: 97d399a1c58fb932171cfb4aa5c6b19cfb64af382771e2cdfc693e72bba2abd1
5
5
  SHA512:
6
- metadata.gz: 1c9dc8f9b3a115494fa9f20c603f772721568a3759b9e2619fde20751ba71a50109d911effeb7d702d286a2011e56d71049ff6a2b854b177f012bbf6bd904291
7
- data.tar.gz: a895b54353186ad7fdffec41d9fcf0efa03f093f2dd44a7bbe31e417e13e726a971bb4b88a8a7357c424b16d864061aa563aa150b87160a087d025e852be9a60
6
+ metadata.gz: cd7fac3bc1738b562586e23722eb62919a3d157a32619511ca2246b0b23c91eabcf9a3565e9f33ff080680bdb9e42a6cfaf984689de9231e8cc2b4edab5b5fa9
7
+ data.tar.gz: 05ce00df88e5de2ecfc7fceacc868fdf5d0b371091d7da5aae63089f9699c72195aaf70175fcdd8e16c3af4d251cd2cf8b78f06e462c2936ea66cc82a4ed622d
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.0 (2020-03-04)
4
+
5
+ * Modules are now always be defined. Previously we used a shorthand syntax
6
+ which meant including individual classes could leave module constants
7
+ undefined.
8
+
3
9
  ## 0.2.0 (2020-02-26)
4
10
 
5
11
  * Added support for the GeoIP2 Precision web services: Country, City, and
@@ -12,7 +12,7 @@ GEM
12
12
  ffi-compiler (1.0.1)
13
13
  ffi (>= 1.0.0)
14
14
  rake
15
- hashdiff (1.0.0)
15
+ hashdiff (1.0.1)
16
16
  http (4.3.0)
17
17
  addressable (~> 2.3)
18
18
  http-cookie (~> 1.0)
@@ -27,13 +27,13 @@ GEM
27
27
  maxmind-db (1.1.0)
28
28
  minitest (5.14.0)
29
29
  parallel (1.19.1)
30
- parser (2.7.0.2)
30
+ parser (2.7.0.4)
31
31
  ast (~> 2.4.0)
32
32
  public_suffix (4.0.3)
33
33
  rainbow (3.0.0)
34
34
  rake (13.0.1)
35
35
  rexml (3.2.4)
36
- rubocop (0.80.0)
36
+ rubocop (0.80.1)
37
37
  jaro_winkler (~> 1.5.1)
38
38
  parallel (~> 1.10)
39
39
  parser (>= 2.7.0.1)
@@ -7,307 +7,309 @@ require 'maxmind/geoip2/model/city'
7
7
  require 'maxmind/geoip2/model/country'
8
8
  require 'maxmind/geoip2/model/insights'
9
9
 
10
- module MaxMind::GeoIP2
11
- # This class provides a client API for all the
12
- # {https://dev.maxmind.com/geoip/geoip2/web-services/ GeoIP2 Precision web
13
- # services}. The services are Country, City, and Insights. Each service
14
- # returns a different set of data about an IP address, with Country returning
15
- # the least data and Insights the most.
16
- #
17
- # Each web service is represented by a different model class, and these model
18
- # classes in turn contain multiple record classes. The record classes have
19
- # attributes which contain data about the IP address.
20
- #
21
- # If the web service does not return a particular piece of data for an IP
22
- # address, the associated attribute is not populated.
23
- #
24
- # The web service may not return any information for an entire record, in
25
- # which case all of the attributes for that record class will be empty.
26
- #
27
- # == Usage
28
- #
29
- # The basic API for this class is the same for all of the web service end
30
- # points. First you create a web service client object with your MaxMind
31
- # account ID and license key, then you call the method corresponding to a
32
- # specific end point, passing it the IP address you want to look up.
33
- #
34
- # If the request succeeds, the method call will return a model class for the
35
- # service you called. This model in turn contains multiple record classes,
36
- # each of which represents part of the data returned by the web service.
37
- #
38
- # If the request fails, the client class throws an exception.
39
- #
40
- # == Example
41
- #
42
- # require 'maxmind/geoip2'
43
- #
44
- # client = MaxMind::GeoIP2::Client.new(
45
- # account_id: 42,
46
- # license_key: 'abcdef123456',
47
- # )
48
- #
49
- # # Replace 'city' with the method corresponding to the web service you
50
- # # are using, e.g., 'country', 'insights'.
51
- # record = client.city('128.101.101.101')
52
- #
53
- # puts record.country.iso_code
54
- class Client
55
- # rubocop:disable Metrics/ParameterLists
56
-
57
- # Create a Client that may be used to query a GeoIP2 Precision web service.
58
- #
59
- # Once created, the Client is safe to use for lookups from multiple
60
- # threads.
61
- #
62
- # @param account_id [Integer] your MaxMind account ID.
63
- #
64
- # @param license_key [String] your MaxMind license key.
10
+ module MaxMind
11
+ module GeoIP2
12
+ # This class provides a client API for all the
13
+ # {https://dev.maxmind.com/geoip/geoip2/web-services/ GeoIP2 Precision web
14
+ # services}. The services are Country, City, and Insights. Each service
15
+ # returns a different set of data about an IP address, with Country returning
16
+ # the least data and Insights the most.
65
17
  #
66
- # @param locales [Array<String>] a list of locale codes to use in the name
67
- # property from most preferred to least preferred.
18
+ # Each web service is represented by a different model class, and these model
19
+ # classes in turn contain multiple record classes. The record classes have
20
+ # attributes which contain data about the IP address.
68
21
  #
69
- # @param host [String] the host to use when querying the web service.
22
+ # If the web service does not return a particular piece of data for an IP
23
+ # address, the associated attribute is not populated.
70
24
  #
71
- # @param timeout [Integer] the number of seconds to wait for a request
72
- # before timing out. If 0, no timeout is set.
25
+ # The web service may not return any information for an entire record, in
26
+ # which case all of the attributes for that record class will be empty.
73
27
  #
74
- # @param proxy_address [String] proxy address to use, if any.
28
+ # == Usage
75
29
  #
76
- # @param proxy_port [Integer] proxy port to use, if any.
77
- #
78
- # @param proxy_username [String] proxy username to use, if any.
79
- #
80
- # @param proxy_password [String] proxy password to use, if any.
81
- def initialize(
82
- account_id:,
83
- license_key:,
84
- locales: ['en'],
85
- host: 'geoip.maxmind.com',
86
- timeout: 0,
87
- proxy_address: '',
88
- proxy_port: 0,
89
- proxy_username: '',
90
- proxy_password: ''
91
- )
92
- @account_id = account_id
93
- @license_key = license_key
94
- @locales = locales
95
- @host = host
96
- @timeout = timeout
97
- @proxy_address = proxy_address
98
- @proxy_port = proxy_port
99
- @proxy_username = proxy_username
100
- @proxy_password = proxy_password
101
- end
102
- # rubocop:enable Metrics/ParameterLists
103
-
104
- # This method calls the GeoIP2 Precision City web service.
30
+ # The basic API for this class is the same for all of the web service end
31
+ # points. First you create a web service client object with your MaxMind
32
+ # account ID and license key, then you call the method corresponding to a
33
+ # specific end point, passing it the IP address you want to look up.
105
34
  #
106
- # @param ip_address [String] IPv4 or IPv6 address as a string. If no
107
- # address is provided, the address that the web service is called from is
108
- # used.
35
+ # If the request succeeds, the method call will return a model class for the
36
+ # service you called. This model in turn contains multiple record classes,
37
+ # each of which represents part of the data returned by the web service.
109
38
  #
110
- # @raise [HTTP::Error] if there was an error performing the HTTP request,
111
- # such as an error connecting.
39
+ # If the request fails, the client class throws an exception.
112
40
  #
113
- # @raise [JSON::ParserError] if there was invalid JSON in the response.
41
+ # == Example
114
42
  #
115
- # @raise [HTTPError] if there was a problem with the HTTP response, such as
116
- # an unexpected HTTP status code.
43
+ # require 'maxmind/geoip2'
117
44
  #
118
- # @raise [AddressInvalidError] if the web service believes the IP address
119
- # to be invalid or missing.
45
+ # client = MaxMind::GeoIP2::Client.new(
46
+ # account_id: 42,
47
+ # license_key: 'abcdef123456',
48
+ # )
120
49
  #
121
- # @raise [AddressNotFoundError] if the IP address was not found.
50
+ # # Replace 'city' with the method corresponding to the web service you
51
+ # # are using, e.g., 'country', 'insights'.
52
+ # record = client.city('128.101.101.101')
122
53
  #
123
- # @raise [AddressReservedError] if the IP address is reserved.
124
- #
125
- # @raise [AuthenticationError] if there was a problem authenticating to the
126
- # web service, such as an invalid or missing license key.
127
- #
128
- # @raise [InsufficientFundsError] if your account is out of credit.
129
- #
130
- # @raise [PermissionRequiredError] if your account does not have permission
131
- # to use the web service.
132
- #
133
- # @raise [InvalidRequestError] if the web service responded with an error
134
- # and there is no more specific error to raise.
135
- #
136
- # @return [MaxMind::GeoIP2::Model::City]
137
- def city(ip_address = 'me')
138
- response_for('city', MaxMind::GeoIP2::Model::City, ip_address)
139
- end
54
+ # puts record.country.iso_code
55
+ class Client
56
+ # rubocop:disable Metrics/ParameterLists
140
57
 
141
- # This method calls the GeoIP2 Precision Country web service.
142
- #
143
- # @param ip_address [String] IPv4 or IPv6 address as a string. If no
144
- # address is provided, the address that the web service is called from is
145
- # used.
146
- #
147
- # @raise [HTTP::Error] if there was an error performing the HTTP request,
148
- # such as an error connecting.
149
- #
150
- # @raise [JSON::ParserError] if there was invalid JSON in the response.
151
- #
152
- # @raise [HTTPError] if there was a problem with the HTTP response, such as
153
- # an unexpected HTTP status code.
154
- #
155
- # @raise [AddressInvalidError] if the web service believes the IP address
156
- # to be invalid or missing.
157
- #
158
- # @raise [AddressNotFoundError] if the IP address was not found.
159
- #
160
- # @raise [AddressReservedError] if the IP address is reserved.
161
- #
162
- # @raise [AuthenticationError] if there was a problem authenticating to the
163
- # web service, such as an invalid or missing license key.
164
- #
165
- # @raise [InsufficientFundsError] if your account is out of credit.
166
- #
167
- # @raise [PermissionRequiredError] if your account does not have permission
168
- # to use the web service.
169
- #
170
- # @raise [InvalidRequestError] if the web service responded with an error
171
- # and there is no more specific error to raise.
172
- #
173
- # @return [MaxMind::GeoIP2::Model::Country]
174
- def country(ip_address = 'me')
175
- response_for('country', MaxMind::GeoIP2::Model::Country, ip_address)
176
- end
177
-
178
- # This method calls the GeoIP2 Precision Insights web service.
179
- #
180
- # @param ip_address [String] IPv4 or IPv6 address as a string. If no
181
- # address is provided, the address that the web service is called from is
182
- # used.
183
- #
184
- # @raise [HTTP::Error] if there was an error performing the HTTP request,
185
- # such as an error connecting.
186
- #
187
- # @raise [JSON::ParserError] if there was invalid JSON in the response.
188
- #
189
- # @raise [HTTPError] if there was a problem with the HTTP response, such as
190
- # an unexpected HTTP status code.
191
- #
192
- # @raise [AddressInvalidError] if the web service believes the IP address
193
- # to be invalid or missing.
194
- #
195
- # @raise [AddressNotFoundError] if the IP address was not found.
196
- #
197
- # @raise [AddressReservedError] if the IP address is reserved.
198
- #
199
- # @raise [AuthenticationError] if there was a problem authenticating to the
200
- # web service, such as an invalid or missing license key.
201
- #
202
- # @raise [InsufficientFundsError] if your account is out of credit.
203
- #
204
- # @raise [PermissionRequiredError] if your account does not have permission
205
- # to use the web service.
206
- #
207
- # @raise [InvalidRequestError] if the web service responded with an error
208
- # and there is no more specific error to raise.
209
- #
210
- # @return [MaxMind::GeoIP2::Model::Insights]
211
- def insights(ip_address = 'me')
212
- response_for('insights', MaxMind::GeoIP2::Model::Insights, ip_address)
213
- end
58
+ # Create a Client that may be used to query a GeoIP2 Precision web service.
59
+ #
60
+ # Once created, the Client is safe to use for lookups from multiple
61
+ # threads.
62
+ #
63
+ # @param account_id [Integer] your MaxMind account ID.
64
+ #
65
+ # @param license_key [String] your MaxMind license key.
66
+ #
67
+ # @param locales [Array<String>] a list of locale codes to use in the name
68
+ # property from most preferred to least preferred.
69
+ #
70
+ # @param host [String] the host to use when querying the web service.
71
+ #
72
+ # @param timeout [Integer] the number of seconds to wait for a request
73
+ # before timing out. If 0, no timeout is set.
74
+ #
75
+ # @param proxy_address [String] proxy address to use, if any.
76
+ #
77
+ # @param proxy_port [Integer] proxy port to use, if any.
78
+ #
79
+ # @param proxy_username [String] proxy username to use, if any.
80
+ #
81
+ # @param proxy_password [String] proxy password to use, if any.
82
+ def initialize(
83
+ account_id:,
84
+ license_key:,
85
+ locales: ['en'],
86
+ host: 'geoip.maxmind.com',
87
+ timeout: 0,
88
+ proxy_address: '',
89
+ proxy_port: 0,
90
+ proxy_username: '',
91
+ proxy_password: ''
92
+ )
93
+ @account_id = account_id
94
+ @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
102
+ end
103
+ # rubocop:enable Metrics/ParameterLists
214
104
 
215
- private
105
+ # This method calls the GeoIP2 Precision City web service.
106
+ #
107
+ # @param ip_address [String] IPv4 or IPv6 address as a string. If no
108
+ # address is provided, the address that the web service is called from is
109
+ # used.
110
+ #
111
+ # @raise [HTTP::Error] if there was an error performing the HTTP request,
112
+ # such as an error connecting.
113
+ #
114
+ # @raise [JSON::ParserError] if there was invalid JSON in the response.
115
+ #
116
+ # @raise [HTTPError] if there was a problem with the HTTP response, such as
117
+ # an unexpected HTTP status code.
118
+ #
119
+ # @raise [AddressInvalidError] if the web service believes the IP address
120
+ # to be invalid or missing.
121
+ #
122
+ # @raise [AddressNotFoundError] if the IP address was not found.
123
+ #
124
+ # @raise [AddressReservedError] if the IP address is reserved.
125
+ #
126
+ # @raise [AuthenticationError] if there was a problem authenticating to the
127
+ # web service, such as an invalid or missing license key.
128
+ #
129
+ # @raise [InsufficientFundsError] if your account is out of credit.
130
+ #
131
+ # @raise [PermissionRequiredError] if your account does not have permission
132
+ # to use the web service.
133
+ #
134
+ # @raise [InvalidRequestError] if the web service responded with an error
135
+ # and there is no more specific error to raise.
136
+ #
137
+ # @return [MaxMind::GeoIP2::Model::City]
138
+ def city(ip_address = 'me')
139
+ response_for('city', MaxMind::GeoIP2::Model::City, ip_address)
140
+ end
216
141
 
217
- def response_for(endpoint, model_class, ip_address)
218
- record = get(endpoint, ip_address)
142
+ # This method calls the GeoIP2 Precision Country web service.
143
+ #
144
+ # @param ip_address [String] IPv4 or IPv6 address as a string. If no
145
+ # address is provided, the address that the web service is called from is
146
+ # used.
147
+ #
148
+ # @raise [HTTP::Error] if there was an error performing the HTTP request,
149
+ # such as an error connecting.
150
+ #
151
+ # @raise [JSON::ParserError] if there was invalid JSON in the response.
152
+ #
153
+ # @raise [HTTPError] if there was a problem with the HTTP response, such as
154
+ # an unexpected HTTP status code.
155
+ #
156
+ # @raise [AddressInvalidError] if the web service believes the IP address
157
+ # to be invalid or missing.
158
+ #
159
+ # @raise [AddressNotFoundError] if the IP address was not found.
160
+ #
161
+ # @raise [AddressReservedError] if the IP address is reserved.
162
+ #
163
+ # @raise [AuthenticationError] if there was a problem authenticating to the
164
+ # web service, such as an invalid or missing license key.
165
+ #
166
+ # @raise [InsufficientFundsError] if your account is out of credit.
167
+ #
168
+ # @raise [PermissionRequiredError] if your account does not have permission
169
+ # to use the web service.
170
+ #
171
+ # @raise [InvalidRequestError] if the web service responded with an error
172
+ # and there is no more specific error to raise.
173
+ #
174
+ # @return [MaxMind::GeoIP2::Model::Country]
175
+ def country(ip_address = 'me')
176
+ response_for('country', MaxMind::GeoIP2::Model::Country, ip_address)
177
+ end
219
178
 
220
- model_class.new(record, @locales)
221
- end
179
+ # This method calls the GeoIP2 Precision Insights web service.
180
+ #
181
+ # @param ip_address [String] IPv4 or IPv6 address as a string. If no
182
+ # address is provided, the address that the web service is called from is
183
+ # used.
184
+ #
185
+ # @raise [HTTP::Error] if there was an error performing the HTTP request,
186
+ # such as an error connecting.
187
+ #
188
+ # @raise [JSON::ParserError] if there was invalid JSON in the response.
189
+ #
190
+ # @raise [HTTPError] if there was a problem with the HTTP response, such as
191
+ # an unexpected HTTP status code.
192
+ #
193
+ # @raise [AddressInvalidError] if the web service believes the IP address
194
+ # to be invalid or missing.
195
+ #
196
+ # @raise [AddressNotFoundError] if the IP address was not found.
197
+ #
198
+ # @raise [AddressReservedError] if the IP address is reserved.
199
+ #
200
+ # @raise [AuthenticationError] if there was a problem authenticating to the
201
+ # web service, such as an invalid or missing license key.
202
+ #
203
+ # @raise [InsufficientFundsError] if your account is out of credit.
204
+ #
205
+ # @raise [PermissionRequiredError] if your account does not have permission
206
+ # to use the web service.
207
+ #
208
+ # @raise [InvalidRequestError] if the web service responded with an error
209
+ # and there is no more specific error to raise.
210
+ #
211
+ # @return [MaxMind::GeoIP2::Model::Insights]
212
+ def insights(ip_address = 'me')
213
+ response_for('insights', MaxMind::GeoIP2::Model::Insights, ip_address)
214
+ end
222
215
 
223
- # rubocop:disable Metrics/CyclomaticComplexity
224
- # rubocop:disable Metrics/PerceivedComplexity
225
- def get(endpoint, ip_address)
226
- url = 'https://' + @host + '/geoip/v2.1/' + endpoint + '/' + ip_address
216
+ private
227
217
 
228
- headers = HTTP.basic_auth(user: @account_id, pass: @license_key)
229
- .headers(
230
- accept: 'application/json',
231
- user_agent: 'MaxMind-GeoIP2-ruby',
232
- )
233
- timeout = @timeout > 0 ? headers.timeout(@timeout) : headers
218
+ def response_for(endpoint, model_class, ip_address)
219
+ record = get(endpoint, ip_address)
234
220
 
235
- proxy = timeout
236
- if @proxy_address != ''
237
- opts = {}
238
- opts[:proxy_port] = @proxy_port if @proxy_port != 0
239
- opts[:proxy_username] = @proxy_username if @proxy_username != ''
240
- opts[:proxy_password] = @proxy_password if @proxy_password != ''
241
- proxy = timeout.via(@proxy_address, opts)
221
+ model_class.new(record, @locales)
242
222
  end
243
223
 
244
- response = proxy.get(url)
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
245
228
 
246
- body = response.to_s
247
- is_json = response.headers[:content_type]&.include?('json')
229
+ headers = HTTP.basic_auth(user: @account_id, pass: @license_key)
230
+ .headers(
231
+ accept: 'application/json',
232
+ user_agent: 'MaxMind-GeoIP2-ruby',
233
+ )
234
+ timeout = @timeout > 0 ? headers.timeout(@timeout) : headers
248
235
 
249
- if response.status.client_error?
250
- return handle_client_error(endpoint, response.code, body, is_json)
251
- end
236
+ proxy = timeout
237
+ 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)
243
+ end
252
244
 
253
- if response.status.server_error?
254
- raise HTTPError,
255
- "Received server error response (#{response.code}) for #{endpoint} with body #{body}"
256
- end
245
+ response = proxy.get(url)
257
246
 
258
- if response.code != 200
259
- raise HTTPError,
260
- "Received unexpected response (#{response.code}) for #{endpoint} with body #{body}"
261
- end
247
+ body = response.to_s
248
+ is_json = response.headers[:content_type]&.include?('json')
262
249
 
263
- handle_success(endpoint, body, is_json)
264
- end
265
- # rubocop:enable Metrics/CyclomaticComplexity
266
- # rubocop:enable Metrics/PerceivedComplexity
250
+ if response.status.client_error?
251
+ return handle_client_error(endpoint, response.code, body, is_json)
252
+ end
267
253
 
268
- # rubocop:disable Metrics/CyclomaticComplexity
269
- def handle_client_error(endpoint, status, body, is_json)
270
- if !is_json
271
- raise HTTPError,
272
- "Received client error response (#{status}) for #{endpoint} but it is not JSON: #{body}"
273
- end
254
+ if response.status.server_error?
255
+ raise HTTPError,
256
+ "Received server error response (#{response.code}) for #{endpoint} with body #{body}"
257
+ end
274
258
 
275
- error = JSON.parse(body)
259
+ if response.code != 200
260
+ raise HTTPError,
261
+ "Received unexpected response (#{response.code}) for #{endpoint} with body #{body}"
262
+ end
276
263
 
277
- if !error.key?('code') || !error.key?('error')
278
- raise HTTPError,
279
- "Received client error response (#{status}) that is JSON but does not specify code or error keys: #{body}"
264
+ handle_success(endpoint, body, is_json)
280
265
  end
266
+ # rubocop:enable Metrics/CyclomaticComplexity
267
+ # rubocop:enable Metrics/PerceivedComplexity
281
268
 
282
- case error['code']
283
- when 'IP_ADDRESS_INVALID', 'IP_ADDRESS_REQUIRED'
284
- raise AddressInvalidError, error['error']
285
- when 'IP_ADDRESS_NOT_FOUND'
286
- raise AddressNotFoundError, error['error']
287
- when 'IP_ADDRESS_RESERVED'
288
- raise AddressReservedError, error['error']
289
- when 'ACCOUNT_ID_REQUIRED',
290
- 'ACCOUNT_ID_UNKNOWN',
291
- 'AUTHORIZATION_INVALID',
292
- 'LICENSE_KEY_REQUIRED'
293
- raise AuthenticationError, error['error']
294
- when 'INSUFFICIENT_FUNDS'
295
- raise InsufficientFundsError, error['error']
296
- when 'PERMISSION_REQUIRED'
297
- raise PermissionRequiredError, error['error']
298
- else
299
- raise InvalidRequestError, error['error']
300
- end
301
- end
302
- # rubocop:enable Metrics/CyclomaticComplexity
269
+ # rubocop:disable Metrics/CyclomaticComplexity
270
+ def handle_client_error(endpoint, status, body, is_json)
271
+ if !is_json
272
+ raise HTTPError,
273
+ "Received client error response (#{status}) for #{endpoint} but it is not JSON: #{body}"
274
+ end
275
+
276
+ error = JSON.parse(body)
303
277
 
304
- def handle_success(endpoint, body, is_json)
305
- if !is_json
306
- raise HTTPError,
307
- "Received a success response for #{endpoint} but it is not JSON: #{body}"
278
+ if !error.key?('code') || !error.key?('error')
279
+ raise HTTPError,
280
+ "Received client error response (#{status}) that is JSON but does not specify code or error keys: #{body}"
281
+ end
282
+
283
+ case error['code']
284
+ when 'IP_ADDRESS_INVALID', 'IP_ADDRESS_REQUIRED'
285
+ raise AddressInvalidError, error['error']
286
+ when 'IP_ADDRESS_NOT_FOUND'
287
+ raise AddressNotFoundError, error['error']
288
+ when 'IP_ADDRESS_RESERVED'
289
+ raise AddressReservedError, error['error']
290
+ when 'ACCOUNT_ID_REQUIRED',
291
+ 'ACCOUNT_ID_UNKNOWN',
292
+ 'AUTHORIZATION_INVALID',
293
+ 'LICENSE_KEY_REQUIRED'
294
+ raise AuthenticationError, error['error']
295
+ when 'INSUFFICIENT_FUNDS'
296
+ raise InsufficientFundsError, error['error']
297
+ when 'PERMISSION_REQUIRED'
298
+ raise PermissionRequiredError, error['error']
299
+ else
300
+ raise InvalidRequestError, error['error']
301
+ end
308
302
  end
303
+ # rubocop:enable Metrics/CyclomaticComplexity
304
+
305
+ def handle_success(endpoint, body, is_json)
306
+ if !is_json
307
+ raise HTTPError,
308
+ "Received a success response for #{endpoint} but it is not JSON: #{body}"
309
+ end
309
310
 
310
- JSON.parse(body)
311
+ JSON.parse(body)
312
+ end
311
313
  end
312
314
  end
313
315
  end