maxmind-geoip2 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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