maxmind-geoip2 0.2.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 (40) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +17 -0
  3. data/Gemfile +11 -0
  4. data/Gemfile.lock +70 -0
  5. data/LICENSE-APACHE +202 -0
  6. data/LICENSE-MIT +17 -0
  7. data/README.dev.md +4 -0
  8. data/README.md +326 -0
  9. data/Rakefile +14 -0
  10. data/lib/maxmind/geoip2.rb +4 -0
  11. data/lib/maxmind/geoip2/client.rb +313 -0
  12. data/lib/maxmind/geoip2/errors.rb +48 -0
  13. data/lib/maxmind/geoip2/model/abstract.rb +27 -0
  14. data/lib/maxmind/geoip2/model/anonymous_ip.rb +63 -0
  15. data/lib/maxmind/geoip2/model/asn.rb +39 -0
  16. data/lib/maxmind/geoip2/model/city.rb +75 -0
  17. data/lib/maxmind/geoip2/model/connection_type.rb +32 -0
  18. data/lib/maxmind/geoip2/model/country.rb +70 -0
  19. data/lib/maxmind/geoip2/model/domain.rb +32 -0
  20. data/lib/maxmind/geoip2/model/enterprise.rb +15 -0
  21. data/lib/maxmind/geoip2/model/insights.rb +14 -0
  22. data/lib/maxmind/geoip2/model/isp.rb +53 -0
  23. data/lib/maxmind/geoip2/reader.rb +277 -0
  24. data/lib/maxmind/geoip2/record/abstract.rb +22 -0
  25. data/lib/maxmind/geoip2/record/city.rb +38 -0
  26. data/lib/maxmind/geoip2/record/continent.rb +37 -0
  27. data/lib/maxmind/geoip2/record/country.rb +54 -0
  28. data/lib/maxmind/geoip2/record/location.rb +73 -0
  29. data/lib/maxmind/geoip2/record/maxmind.rb +17 -0
  30. data/lib/maxmind/geoip2/record/place.rb +28 -0
  31. data/lib/maxmind/geoip2/record/postal.rb +30 -0
  32. data/lib/maxmind/geoip2/record/represented_country.rb +23 -0
  33. data/lib/maxmind/geoip2/record/subdivision.rb +48 -0
  34. data/lib/maxmind/geoip2/record/traits.rb +200 -0
  35. data/maxmind-geoip2.gemspec +25 -0
  36. data/test/test_client.rb +424 -0
  37. data/test/test_model_country.rb +80 -0
  38. data/test/test_model_names.rb +47 -0
  39. data/test/test_reader.rb +459 -0
  40. metadata +116 -0
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'maxmind/geoip2/model/abstract'
4
+
5
+ module MaxMind::GeoIP2::Model
6
+ # Model class for the GeoLite2 ASN database.
7
+ class ASN < Abstract
8
+ # The autonomous system number associated with the IP address.
9
+ #
10
+ # @return [Integer, nil]
11
+ def autonomous_system_number
12
+ get('autonomous_system_number')
13
+ end
14
+
15
+ # The organization associated with the registered autonomous system number
16
+ # for the IP address.
17
+ #
18
+ # @return [String, nil]
19
+ def autonomous_system_organization
20
+ get('autonomous_system_organization')
21
+ end
22
+
23
+ # The IP address that the data in the model is for.
24
+ #
25
+ # @return [String]
26
+ def ip_address
27
+ get('ip_address')
28
+ end
29
+
30
+ # The network in CIDR notation associated with the record. In particular,
31
+ # this is the largest network where all of the fields besides ip_address
32
+ # have the same value.
33
+ #
34
+ # @return [String]
35
+ def network
36
+ get('network')
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'maxmind/geoip2/model/country'
4
+ require 'maxmind/geoip2/record/city'
5
+ require 'maxmind/geoip2/record/location'
6
+ require 'maxmind/geoip2/record/postal'
7
+ require 'maxmind/geoip2/record/subdivision'
8
+
9
+ module MaxMind::GeoIP2::Model
10
+ # Model class for the data returned by the GeoIP2 City web service and
11
+ # database. It is also used for GeoLite2 City lookups.
12
+ #
13
+ # The only difference between the City and Insights model classes is which
14
+ # fields in each record may be populated. See
15
+ # https://dev.maxmind.com/geoip/geoip2/web-services for more details.
16
+ #
17
+ # See {MaxMind::GeoIP2::Model::Country} for inherited methods.
18
+ class City < Country
19
+ # City data for the IP address.
20
+ #
21
+ # @return [MaxMind::GeoIP2::Record::City]
22
+ attr_reader :city
23
+
24
+ # Location data for the IP address.
25
+ #
26
+ # @return [MaxMind::GeoIP2::Record::Location]
27
+ attr_reader :location
28
+
29
+ # Postal data for the IP address.
30
+ #
31
+ # @return [MaxMind::GeoIP2::Record::Postal]
32
+ attr_reader :postal
33
+
34
+ # The country subdivisions for the IP address.
35
+ #
36
+ # The number and type of subdivisions varies by country, but a subdivision
37
+ # is typically a state, province, country, etc. Subdivisions are ordered
38
+ # from most general (largest) to most specific (smallest).
39
+ #
40
+ # If the response did not contain any subdivisions, this attribute will be
41
+ # an empty array.
42
+ #
43
+ # @return [Array<MaxMind::GeoIP2::Record::Subdivision>]
44
+ attr_reader :subdivisions
45
+
46
+ # @!visibility private
47
+ def initialize(record, locales)
48
+ super(record, locales)
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
+
55
+ # The most specific subdivision returned.
56
+ #
57
+ # If the response did not contain any subdivisions, this method returns
58
+ # nil.
59
+ #
60
+ # @return [MaxMind::GeoIP2::Record::Subdivision, nil]
61
+ def most_specific_subdivision
62
+ @subdivisions.last
63
+ end
64
+
65
+ private
66
+
67
+ def create_subdivisions(subdivisions, locales)
68
+ return [] if subdivisions.nil?
69
+
70
+ subdivisions.map do |s|
71
+ MaxMind::GeoIP2::Record::Subdivision.new(s, locales)
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'maxmind/geoip2/model/abstract'
4
+
5
+ module MaxMind::GeoIP2::Model
6
+ # Model class for the GeoIP2 Connection Type database.
7
+ class ConnectionType < Abstract
8
+ # The connection type may take the following values: "Dialup", "Cable/DSL",
9
+ # "Corporate", "Cellular". Additional values may be added in the future.
10
+ #
11
+ # @return [String, nil]
12
+ def connection_type
13
+ get('connection_type')
14
+ end
15
+
16
+ # The IP address that the data in the model is for.
17
+ #
18
+ # @return [String]
19
+ def ip_address
20
+ get('ip_address')
21
+ end
22
+
23
+ # The network in CIDR notation associated with the record. In particular,
24
+ # this is the largest network where all of the fields besides ip_address
25
+ # have the same value.
26
+ #
27
+ # @return [String]
28
+ def network
29
+ get('network')
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'maxmind/geoip2/record/continent'
4
+ require 'maxmind/geoip2/record/country'
5
+ require 'maxmind/geoip2/record/maxmind'
6
+ require 'maxmind/geoip2/record/represented_country'
7
+ require 'maxmind/geoip2/record/traits'
8
+
9
+ module MaxMind::GeoIP2::Model
10
+ # Model class for the data returned by the GeoIP2 Country web service and
11
+ # database. It is also used for GeoLite2 Country lookups.
12
+ class Country
13
+ # Continent data for the IP address.
14
+ #
15
+ # @return [MaxMind::GeoIP2::Record::Continent]
16
+ attr_reader :continent
17
+
18
+ # Country data for the IP address. This object represents the country where
19
+ # MaxMind believes the end user is located.
20
+ #
21
+ # @return [MaxMind::GeoIP2::Record::Country]
22
+ attr_reader :country
23
+
24
+ # Data related to your MaxMind account.
25
+ #
26
+ # @return [MaxMind::GeoIP2::Record::MaxMind]
27
+ attr_reader :maxmind
28
+
29
+ # Registered country data for the IP address. This record represents the
30
+ # country where the ISP has registered a given IP block and may differ from
31
+ # the user's country.
32
+ #
33
+ # @return [MaxMind::GeoIP2::Record::Country]
34
+ attr_reader :registered_country
35
+
36
+ # Represented country data for the IP address. The represented country is
37
+ # used for things like military bases. It is only present when the
38
+ # represented country differs from the country.
39
+ #
40
+ # @return [MaxMind::GeoIP2::Record::RepresentedCountry]
41
+ attr_reader :represented_country
42
+
43
+ # Data for the traits of the IP address.
44
+ #
45
+ # @return [MaxMind::GeoIP2::Record::Traits]
46
+ attr_reader :traits
47
+
48
+ # @!visibility private
49
+ def initialize(record, locales)
50
+ @continent = MaxMind::GeoIP2::Record::Continent.new(
51
+ record['continent'],
52
+ locales,
53
+ )
54
+ @country = MaxMind::GeoIP2::Record::Country.new(
55
+ record['country'],
56
+ locales,
57
+ )
58
+ @maxmind = MaxMind::GeoIP2::Record::MaxMind.new(record['maxmind'])
59
+ @registered_country = MaxMind::GeoIP2::Record::Country.new(
60
+ record['registered_country'],
61
+ locales,
62
+ )
63
+ @represented_country = MaxMind::GeoIP2::Record::RepresentedCountry.new(
64
+ record['represented_country'],
65
+ locales,
66
+ )
67
+ @traits = MaxMind::GeoIP2::Record::Traits.new(record['traits'])
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'maxmind/geoip2/model/abstract'
4
+
5
+ module MaxMind::GeoIP2::Model
6
+ # Model class for the GeoIP2 Domain database.
7
+ class Domain < Abstract
8
+ # The second level domain associated with the IP address. This will be
9
+ # something like "example.com" or "example.co.uk", not "foo.example.com".
10
+ #
11
+ # @return [String, nil]
12
+ def domain
13
+ get('domain')
14
+ end
15
+
16
+ # The IP address that the data in the model is for.
17
+ #
18
+ # @return [String]
19
+ def ip_address
20
+ get('ip_address')
21
+ end
22
+
23
+ # The network in CIDR notation associated with the record. In particular,
24
+ # this is the largest network where all of the fields besides ip_address
25
+ # have the same value.
26
+ #
27
+ # @return [String]
28
+ def network
29
+ get('network')
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'maxmind/geoip2/model/city'
4
+
5
+ module MaxMind::GeoIP2::Model
6
+ # Model class for the data returned by GeoIP2 Enterprise database lookups.
7
+ #
8
+ # The only difference between the City and Insights model classes is which
9
+ # fields in each record may be populated. See
10
+ # https://dev.maxmind.com/geoip/geoip2/web-services for more details.
11
+ #
12
+ # See {MaxMind::GeoIP2::Model::City} for inherited methods.
13
+ class Enterprise < City
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'maxmind/geoip2/model/city'
4
+
5
+ module MaxMind::GeoIP2::Model
6
+ # Model class for the data returned by the GeoIP2 Precision Insights web
7
+ # service.
8
+ #
9
+ # The only difference between the City and Insights model classes is which
10
+ # fields in each record may be populated. See
11
+ # https://dev.maxmind.com/geoip/geoip2/web-services for more details.
12
+ class Insights < City
13
+ end
14
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'maxmind/geoip2/model/abstract'
4
+
5
+ module MaxMind::GeoIP2::Model
6
+ # Model class for the GeoIP2 ISP database.
7
+ class ISP < Abstract
8
+ # The autonomous system number associated with the IP address.
9
+ #
10
+ # @return [Integer, nil]
11
+ def autonomous_system_number
12
+ get('autonomous_system_number')
13
+ end
14
+
15
+ # The organization associated with the registered autonomous system number
16
+ # for the IP address.
17
+ #
18
+ # @return [String, nil]
19
+ def autonomous_system_organization
20
+ get('autonomous_system_organization')
21
+ end
22
+
23
+ # The IP address that the data in the model is for.
24
+ #
25
+ # @return [String]
26
+ def ip_address
27
+ get('ip_address')
28
+ end
29
+
30
+ # The name of the ISP associated with the IP address.
31
+ #
32
+ # @return [String, nil]
33
+ def isp
34
+ get('isp')
35
+ end
36
+
37
+ # The network in CIDR notation associated with the record. In particular,
38
+ # this is the largest network where all of the fields besides ip_address
39
+ # have the same value.
40
+ #
41
+ # @return [String]
42
+ def network
43
+ get('network')
44
+ end
45
+
46
+ # The name of the organization associated with the IP address.
47
+ #
48
+ # @return [String, nil]
49
+ def organization
50
+ get('organization')
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,277 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'maxmind/db'
4
+ require 'maxmind/geoip2/errors'
5
+ require 'maxmind/geoip2/model/anonymous_ip'
6
+ require 'maxmind/geoip2/model/asn'
7
+ require 'maxmind/geoip2/model/city'
8
+ require 'maxmind/geoip2/model/connection_type'
9
+ require 'maxmind/geoip2/model/country'
10
+ require 'maxmind/geoip2/model/domain'
11
+ require 'maxmind/geoip2/model/enterprise'
12
+ require 'maxmind/geoip2/model/isp'
13
+
14
+ module MaxMind::GeoIP2
15
+ # Reader is a reader for the GeoIP2/GeoLite2 database format. IP addresses
16
+ # can be looked up using the database specific methods.
17
+ #
18
+ # == Example
19
+ #
20
+ # require 'maxmind/geoip2'
21
+ #
22
+ # reader = MaxMind::GeoIP2::Reader.new('GeoIP2-Country.mmdb')
23
+ #
24
+ # record = reader.country('1.2.3.4')
25
+ # puts record.country.iso_code
26
+ #
27
+ # reader.close
28
+ class Reader
29
+ # Create a Reader for looking up IP addresses in a GeoIP2/GeoLite2 database
30
+ # file.
31
+ #
32
+ # If you're performing multiple lookups, it's most efficient to create one
33
+ # Reader and reuse it.
34
+ #
35
+ # Once created, the Reader is safe to use for lookups from multiple
36
+ # threads. It is safe to use after forking only if you use
37
+ # MaxMind::DB::MODE_MEMORY or if your version of Ruby supports IO#pread.
38
+ #
39
+ # @param database [String] a path to a GeoIP2/GeoLite2 database file.
40
+ #
41
+ # @param locales [Array<String>] a list of locale codes to use in the name
42
+ # property from most preferred to least preferred.
43
+ #
44
+ # @param options [Hash<Symbol, Symbol>] options controlling the behavior of
45
+ # the Reader.
46
+ #
47
+ # @option options [Symbol] :mode Defines how to open the database. It may
48
+ # be one of 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.
52
+ #
53
+ # @raise [MaxMind::DB::InvalidDatabaseError] if the database is corrupt or
54
+ # invalid.
55
+ #
56
+ # @raise [ArgumentError] if the mode is invalid.
57
+ def initialize(database, locales = ['en'], options = {})
58
+ @reader = MaxMind::DB.new(database, options)
59
+ @type = @reader.metadata.database_type
60
+ locales = ['en'] if locales.empty?
61
+ @locales = locales
62
+ end
63
+
64
+ # Look up the IP address in the database.
65
+ #
66
+ # @param ip_address [String] a string in the standard notation. It may be
67
+ # IPv4 or IPv6.
68
+ #
69
+ # @return [MaxMind::GeoIP2::Model::AnonymousIP]
70
+ #
71
+ # @raise [ArgumentError] if used against a non-Anonymous IP database or if
72
+ # you attempt to look up an IPv6 address in an IPv4 only database.
73
+ #
74
+ # @raise [AddressNotFoundError] if the IP address is not found in the
75
+ # database.
76
+ #
77
+ # @raise [MaxMind::DB::InvalidDatabaseError] if the database appears
78
+ # corrupt.
79
+ def anonymous_ip(ip_address)
80
+ flat_model_for(
81
+ Model::AnonymousIP,
82
+ 'anonymous_ip',
83
+ 'GeoIP2-Anonymous-IP',
84
+ ip_address,
85
+ )
86
+ end
87
+
88
+ # Look up the IP address in an ASN database.
89
+ #
90
+ # @param ip_address [String] a string in the standard notation. It may be
91
+ # IPv4 or IPv6.
92
+ #
93
+ # @return [MaxMind::GeoIP2::Model::ASN]
94
+ #
95
+ # @raise [ArgumentError] if used against a non-ASN database or if you
96
+ # attempt to look up an IPv6 address in an IPv4 only database.
97
+ #
98
+ # @raise [AddressNotFoundError] if the IP address is not found in the
99
+ # database.
100
+ #
101
+ # @raise [MaxMind::DB::InvalidDatabaseError] if the database appears
102
+ # corrupt.
103
+ def asn(ip_address)
104
+ flat_model_for(Model::ASN, 'asn', 'GeoLite2-ASN', ip_address)
105
+ end
106
+
107
+ # Look up the IP address in a City database.
108
+ #
109
+ # @param ip_address [String] a string in the standard notation. It may be
110
+ # IPv4 or IPv6.
111
+ #
112
+ # @return [MaxMind::GeoIP2::Model::City]
113
+ #
114
+ # @raise [ArgumentError] if used against a non-City database or if you
115
+ # attempt to look up an IPv6 address in an IPv4 only database.
116
+ #
117
+ # @raise [AddressNotFoundError] if the IP address is not found in the
118
+ # database.
119
+ #
120
+ # @raise [MaxMind::DB::InvalidDatabaseError] if the database appears
121
+ # corrupt.
122
+ def city(ip_address)
123
+ model_for(Model::City, 'city', 'City', ip_address)
124
+ end
125
+
126
+ # Look up the IP address in a Connection Type database.
127
+ #
128
+ # @param ip_address [String] a string in the standard notation. It may be
129
+ # IPv4 or IPv6.
130
+ #
131
+ # @return [MaxMind::GeoIP2::Model::ConnectionType]
132
+ #
133
+ # @raise [ArgumentError] if used against a non-Connection Type database or if
134
+ # you attempt to look up an IPv6 address in an IPv4 only database.
135
+ #
136
+ # @raise [AddressNotFoundError] if the IP address is not found in the
137
+ # database.
138
+ #
139
+ # @raise [MaxMind::DB::InvalidDatabaseError] if the database appears
140
+ # corrupt.
141
+ def connection_type(ip_address)
142
+ flat_model_for(
143
+ Model::ConnectionType,
144
+ 'connection_type',
145
+ 'GeoIP2-Connection-Type',
146
+ ip_address,
147
+ )
148
+ end
149
+
150
+ # Look up the IP address in a Country database.
151
+ #
152
+ # @param ip_address [String] a string in the standard notation. It may be
153
+ # IPv4 or IPv6.
154
+ #
155
+ # @return [MaxMind::GeoIP2::Model::Country]
156
+ #
157
+ # @raise [ArgumentError] if used against a non-Country database or if you
158
+ # attempt to look up an IPv6 address in an IPv4 only database.
159
+ #
160
+ # @raise [AddressNotFoundError] if the IP address is not found in the
161
+ # database.
162
+ #
163
+ # @raise [MaxMind::DB::InvalidDatabaseError] if the database appears
164
+ # corrupt.
165
+ def country(ip_address)
166
+ model_for(Model::Country, 'country', 'Country', ip_address)
167
+ end
168
+
169
+ # Look up the IP address in a Domain database.
170
+ #
171
+ # @param ip_address [String] a string in the standard notation. It may be
172
+ # IPv4 or IPv6.
173
+ #
174
+ # @return [MaxMind::GeoIP2::Model::Domain]
175
+ #
176
+ # @raise [ArgumentError] if used against a non-Domain database or if you
177
+ # attempt to look up an IPv6 address in an IPv4 only database.
178
+ #
179
+ # @raise [AddressNotFoundError] if the IP address is not found in the
180
+ # database.
181
+ #
182
+ # @raise [MaxMind::DB::InvalidDatabaseError] if the database appears
183
+ # corrupt.
184
+ def domain(ip_address)
185
+ flat_model_for(Model::Domain, 'domain', 'GeoIP2-Domain', ip_address)
186
+ end
187
+
188
+ # Look up the IP address in an Enterprise database.
189
+ #
190
+ # @param ip_address [String] a string in the standard notation. It may be
191
+ # IPv4 or IPv6.
192
+ #
193
+ # @return [MaxMind::GeoIP2::Model::Enterprise]
194
+ #
195
+ # @raise [ArgumentError] if used against a non-Enterprise database or if
196
+ # you attempt to look up an IPv6 address in an IPv4 only database.
197
+ #
198
+ # @raise [AddressNotFoundError] if the IP address is not found in the
199
+ # database.
200
+ #
201
+ # @raise [MaxMind::DB::InvalidDatabaseError] if the database appears
202
+ # corrupt.
203
+ def enterprise(ip_address)
204
+ model_for(Model::Enterprise, 'enterprise', 'Enterprise', ip_address)
205
+ end
206
+
207
+ # Look up the IP address in an ISP database.
208
+ #
209
+ # @param ip_address [String] a string in the standard notation. It may be
210
+ # IPv4 or IPv6.
211
+ #
212
+ # @return [MaxMind::GeoIP2::Model::ISP]
213
+ #
214
+ # @raise [ArgumentError] if used against a non-ISP database or if you
215
+ # attempt to look up an IPv6 address in an IPv4 only database.
216
+ #
217
+ # @raise [AddressNotFoundError] if the IP address is not found in the
218
+ # database.
219
+ #
220
+ # @raise [MaxMind::DB::InvalidDatabaseError] if the database appears
221
+ # corrupt.
222
+ def isp(ip_address)
223
+ flat_model_for(Model::ISP, 'isp', 'GeoIP2-ISP', ip_address)
224
+ end
225
+
226
+ # Return the metadata associated with the database.
227
+ #
228
+ # @return [MaxMind::DB::Metadata]
229
+ def metadata
230
+ @reader.metadata
231
+ end
232
+
233
+ # Close the Reader and return resources to the system.
234
+ #
235
+ # @return [void]
236
+ def close
237
+ @reader.close
238
+ end
239
+
240
+ private
241
+
242
+ def model_for(model_class, method, type, ip_address)
243
+ record, prefix_length = get_record(method, type, ip_address)
244
+
245
+ record['traits'] = {} if !record.key?('traits')
246
+ record['traits']['ip_address'] = ip_address
247
+ record['traits']['prefix_length'] = prefix_length
248
+
249
+ model_class.new(record, @locales)
250
+ end
251
+
252
+ def get_record(method, type, ip_address)
253
+ if !@type.include?(type)
254
+ raise ArgumentError,
255
+ "The #{method} method cannot be used with the #{@type} database."
256
+ end
257
+
258
+ record, prefix_length = @reader.get_with_prefix_length(ip_address)
259
+
260
+ if record.nil?
261
+ raise AddressNotFoundError,
262
+ "The address #{ip_address} is not in the database."
263
+ end
264
+
265
+ [record, prefix_length]
266
+ end
267
+
268
+ def flat_model_for(model_class, method, type, ip_address)
269
+ record, prefix_length = get_record(method, type, ip_address)
270
+
271
+ record['ip_address'] = ip_address
272
+ record['prefix_length'] = prefix_length
273
+
274
+ model_class.new(record)
275
+ end
276
+ end
277
+ end