maxmind-db 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +15 -0
  3. data/Gemfile +1 -4
  4. data/README.dev.md +17 -5
  5. data/README.md +2 -11
  6. data/bin/mmdb-benchmark.rb +3 -3
  7. data/lib/maxmind/db/decoder.rb +7 -2
  8. data/lib/maxmind/db/errors.rb +1 -1
  9. data/lib/maxmind/db/file_reader.rb +32 -13
  10. data/lib/maxmind/db/memory_reader.rb +4 -4
  11. data/lib/maxmind/db/metadata.rb +28 -2
  12. data/lib/maxmind/db.rb +43 -40
  13. data/maxmind-db.gemspec +10 -4
  14. data/test/data/LICENSE +4 -0
  15. data/test/data/MaxMind-DB-spec.md +574 -0
  16. data/test/data/README.md +4 -0
  17. data/test/data/bad-data/README.md +7 -0
  18. data/test/data/bad-data/libmaxminddb/libmaxminddb-offset-integer-overflow.mmdb +0 -0
  19. data/test/data/bad-data/maxminddb-golang/cyclic-data-structure.mmdb +0 -0
  20. data/test/data/bad-data/maxminddb-golang/invalid-bytes-length.mmdb +1 -0
  21. data/test/data/bad-data/maxminddb-golang/invalid-data-record-offset.mmdb +0 -0
  22. data/test/data/bad-data/maxminddb-golang/invalid-map-key-length.mmdb +0 -0
  23. data/test/data/bad-data/maxminddb-golang/invalid-string-length.mmdb +1 -0
  24. data/test/data/bad-data/maxminddb-golang/metadata-is-an-uint128.mmdb +1 -0
  25. data/test/data/bad-data/maxminddb-golang/unexpected-bytes.mmdb +0 -0
  26. data/test/data/bad-data/maxminddb-python/bad-unicode-in-map-key.mmdb +0 -0
  27. data/test/data/perltidyrc +12 -0
  28. data/test/data/source-data/GeoIP2-Anonymous-IP-Test.json +49 -0
  29. data/test/data/source-data/GeoIP2-City-Test.json +12885 -0
  30. data/test/data/source-data/GeoIP2-Connection-Type-Test.json +122 -0
  31. data/test/data/source-data/GeoIP2-Country-Test.json +15904 -0
  32. data/test/data/source-data/GeoIP2-DensityIncome-Test.json +14 -0
  33. data/test/data/source-data/GeoIP2-Domain-Test.json +452 -0
  34. data/test/data/source-data/GeoIP2-Enterprise-Test.json +745 -0
  35. data/test/data/source-data/GeoIP2-ISP-Test.json +12605 -0
  36. data/test/data/source-data/GeoIP2-Precision-Enterprise-Test.json +2205 -0
  37. data/test/data/source-data/GeoIP2-Static-IP-Score-Test.json +2132 -0
  38. data/test/data/source-data/GeoIP2-User-Count-Test.json +2837 -0
  39. data/test/data/source-data/GeoLite2-ASN-Test.json +4120 -0
  40. data/test/data/source-data/GeoLite2-City-Test.json +12804 -0
  41. data/test/data/source-data/GeoLite2-Country-Test.json +11280 -0
  42. data/test/data/source-data/README +15 -0
  43. data/test/data/test-data/GeoIP2-Anonymous-IP-Test.mmdb +0 -0
  44. data/test/data/test-data/GeoIP2-City-Test-Broken-Double-Format.mmdb +0 -0
  45. data/test/data/test-data/GeoIP2-City-Test-Invalid-Node-Count.mmdb +0 -0
  46. data/test/data/test-data/GeoIP2-City-Test.mmdb +0 -0
  47. data/test/data/test-data/GeoIP2-Connection-Type-Test.mmdb +0 -0
  48. data/test/data/test-data/GeoIP2-Country-Test.mmdb +0 -0
  49. data/test/data/test-data/GeoIP2-DensityIncome-Test.mmdb +0 -0
  50. data/test/data/test-data/GeoIP2-Domain-Test.mmdb +0 -0
  51. data/test/data/test-data/GeoIP2-Enterprise-Test.mmdb +0 -0
  52. data/test/data/test-data/GeoIP2-ISP-Test.mmdb +0 -0
  53. data/test/data/test-data/GeoIP2-Precision-Enterprise-Test.mmdb +0 -0
  54. data/test/data/test-data/GeoIP2-Static-IP-Score-Test.mmdb +0 -0
  55. data/test/data/test-data/GeoIP2-User-Count-Test.mmdb +0 -0
  56. data/test/data/test-data/GeoLite2-ASN-Test.mmdb +0 -0
  57. data/test/data/test-data/GeoLite2-City-Test.mmdb +0 -0
  58. data/test/data/test-data/GeoLite2-Country-Test.mmdb +0 -0
  59. data/test/data/test-data/MaxMind-DB-no-ipv4-search-tree.mmdb +0 -0
  60. data/test/data/test-data/MaxMind-DB-string-value-entries.mmdb +0 -0
  61. data/test/data/test-data/MaxMind-DB-test-broken-pointers-24.mmdb +0 -0
  62. data/test/data/test-data/MaxMind-DB-test-broken-search-tree-24.mmdb +0 -0
  63. data/test/data/test-data/MaxMind-DB-test-decoder.mmdb +0 -0
  64. data/test/data/test-data/MaxMind-DB-test-ipv4-24.mmdb +0 -0
  65. data/test/data/test-data/MaxMind-DB-test-ipv4-28.mmdb +0 -0
  66. data/test/data/test-data/MaxMind-DB-test-ipv4-32.mmdb +0 -0
  67. data/test/data/test-data/MaxMind-DB-test-ipv6-24.mmdb +0 -0
  68. data/test/data/test-data/MaxMind-DB-test-ipv6-28.mmdb +0 -0
  69. data/test/data/test-data/MaxMind-DB-test-ipv6-32.mmdb +0 -0
  70. data/test/data/test-data/MaxMind-DB-test-metadata-pointers.mmdb +0 -0
  71. data/test/data/test-data/MaxMind-DB-test-mixed-24.mmdb +0 -0
  72. data/test/data/test-data/MaxMind-DB-test-mixed-28.mmdb +0 -0
  73. data/test/data/test-data/MaxMind-DB-test-mixed-32.mmdb +0 -0
  74. data/test/data/test-data/MaxMind-DB-test-nested.mmdb +0 -0
  75. data/test/data/test-data/MaxMind-DB-test-pointer-decoder.mmdb +0 -0
  76. data/test/data/test-data/README.md +26 -0
  77. data/test/data/test-data/maps-with-pointers.raw +0 -0
  78. data/test/data/test-data/write-test-data.pl +695 -0
  79. data/test/data/tidyall.ini +5 -0
  80. data/test/mmdb_util.rb +1 -1
  81. data/test/test_decoder.rb +7 -7
  82. data/test/test_reader.rb +36 -14
  83. metadata +130 -9
  84. data/Gemfile.lock +0 -34
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: e8404a64573590d7a01fd9199ae1be5bb1892407
4
- data.tar.gz: cfdec2ef12cae84fa914784b90c386d1006fdf47
2
+ SHA256:
3
+ metadata.gz: d5705dca32ee40fdadd07a1f6abc8a0ff56e23b699ecb9ba159344a9325c8456
4
+ data.tar.gz: d71304945c1c09f3af09a85b03dbbcf8cbeb4652456441a7f6978b2cb9db6adc
5
5
  SHA512:
6
- metadata.gz: 263eff4235eadc529e14266772c3db95bc17950ebc7d73fbb3f5d20ee76f3b2f50035c97ad2e39454e5dbd65dd6093fc56f3a6dd3b8d91a69037b8e396986366
7
- data.tar.gz: 8fe05ac4631539293ee2d1485fe7c1908858ef952d76e60e75d9f601f356263bb47928bc8dd670c2989df4437cb0d2a876869c662b1f4aab36d0e8a81ce19552
6
+ metadata.gz: b8c1a541fcf270945c34254e2e5817ac52864f6cea427d223cb4b5c9c4036afdc61380954462fe063beeacd3407507a647eff776ab8913a561eef6eed71a6730
7
+ data.tar.gz: 70c1967f07e22885938b7fb1e9cbd0a73c9d4f3efab144a6aa4c2e40bac81ce8445d2702ad51d2b32e028a6eef053f132542d9d9c1086030d224575a4bb39e64
data/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.2.0 (2023-11-22)
4
+
5
+ * Ruby 2.4 is no longer supported. If you're using Ruby 2.4, please use
6
+ version 1.1.1 of this gem.
7
+ * `Object#respond_to?` is no longer called on every read. Pull request by
8
+ Jean byroot Boussier. GitHub #65.
9
+ * The `get` and `get_prefix_length` methods now accept the IP addresses as
10
+ `IPAddr` objects. Strings are still accepted too. Pull request by Eddie
11
+ Lebow. GitHub #69.
12
+
13
+ ## 1.1.1 (2020-06-23)
14
+
15
+ * Fixed the memory reader's inspect method to no longer attempt to modify a
16
+ frozen string. Pull request by Tietew. GitHub #35.
17
+
3
18
  ## 1.1.0 (2020-01-08)
4
19
 
5
20
  * The method `get_with_prefix_length` was added. This method returns both
data/Gemfile CHANGED
@@ -2,7 +2,4 @@
2
2
 
3
3
  source 'https://rubygems.org'
4
4
 
5
- gem 'minitest', group: :development
6
- gem 'rake', group: :development
7
- gem 'rubocop', group: :development
8
- gem 'rubocop-performance', group: :development
5
+ gemspec
data/README.dev.md CHANGED
@@ -1,14 +1,22 @@
1
1
  # How to release
2
- * Update changelog and set release date
3
- * Bump version in `maxmind-db.gemspec`
2
+ * Ensure tests pass: `rake`
3
+ * Update changelog: Set version and release date
4
+ * Set version in `maxmind-db.gemspec`
5
+ * Add them: `git add -p`
6
+ * Create a branch e.g. `horgh/release` and switch to it.
7
+ * `main` is protected.
4
8
  * Commit: `git commit -m v1.0.0`
5
9
  * Tag: `git tag -a v1.0.0 -m v1.0.0`
6
10
  * Clean up to be sure nothing stray gets into gem: `git clean -dxff`
7
11
  * Create `.gem` file: `gem build maxmind-db.gemspec`
8
12
  * Complete prerequisites (see below)
13
+ * You only need to do this once. You can tell if this is necessary if you
14
+ are lacking `:rubygems_api_key` in `~/.local/share/gem/credentials`
15
+ (previously `~/.gem/credentials`)
9
16
  * Upload to rubygems.org: `gem push maxmind-db-1.0.0.gem`
10
17
  * Push: `git push`
11
18
  * Push tag: `git push --tags`
19
+ * Make a PR and get it merged.
12
20
  * Double check it looks okay at https://rubygems.org/gems/maxmind-db and
13
21
  https://www.rubydoc.info/gems/maxmind-db
14
22
 
@@ -18,7 +26,7 @@
18
26
  ## Step 1
19
27
  Sign up for an account at rubygems.org if you don't have one.
20
28
 
21
- Enable multi factor authentication.
29
+ Enable multi factor authentication (for both UI and API).
22
30
 
23
31
 
24
32
  ## Step 2
@@ -29,5 +37,9 @@ They do this by using the `gem owner` command
29
37
 
30
38
 
31
39
  ## Step 3
32
- Go to your rubygems.org profile and find the curl command to run to
33
- download your API key.
40
+ Run `gem signin`. This will prompt you for your username and password, and
41
+ then create an API key for you. Select the scopes `index_rubygems` and
42
+ `push_rubygem` (I'm not sure the former is required, but anyway).
43
+
44
+ Note you may need an up to date version of rubygems to do this as I believe
45
+ support for API keys like this is a newer addition.
data/README.md CHANGED
@@ -6,20 +6,12 @@ This is the Ruby API for reading [MaxMind
6
6
  DB](https://maxmind.github.io/MaxMind-DB/) files. MaxMind DB is a binary
7
7
  file format that stores data indexed by IP address subnets (IPv4 or IPv6).
8
8
 
9
-
10
9
  ## Installation
11
10
 
12
11
  ```
13
12
  gem install maxmind-db
14
13
  ```
15
14
 
16
- Or from source:
17
-
18
- ```
19
- gem build maxmind-db.spec
20
- gem install ./maxmind-db-xxx.gem
21
- ```
22
-
23
15
  ## Usage
24
16
 
25
17
  ```ruby
@@ -43,8 +35,7 @@ For more information see the
43
35
 
44
36
  ## Requirements
45
37
 
46
- This code requires Ruby version 2.4 or higher. Older versions may work, but
47
- are not supported.
38
+ This code requires Ruby version 2.5 or higher.
48
39
 
49
40
  ## Contributing
50
41
 
@@ -65,7 +56,7 @@ This library uses [Semantic Versioning](https://semver.org/).
65
56
 
66
57
  ## Copyright and License
67
58
 
68
- This software is Copyright (c) 2018 - 2020 by MaxMind, Inc.
59
+ This software is Copyright (c) 2018 - 2023 by MaxMind, Inc.
69
60
 
70
61
  This is free software, licensed under the [Apache License, Version
71
62
  2.0](LICENSE-APACHE) or the [MIT License](LICENSE-MIT), at your option.
@@ -29,9 +29,9 @@ end
29
29
 
30
30
  def print_usage
31
31
  # rubocop:disable Style/StderrPuts
32
- STDERR.puts "Usage: #{$PROGRAM_NAME} <MMDB file> <IP file>"
33
- STDERR.puts
34
- STDERR.puts 'Benchmark by reading IPs from the IP file and looking up each one in the MMDB file.'
32
+ $stderr.puts "Usage: #{$PROGRAM_NAME} <MMDB file> <IP file>"
33
+ $stderr.puts
34
+ $stderr.puts 'Benchmark by reading IPs from the IP file and looking up each one in the MMDB file.'
35
35
  # rubocop:enable Style/StderrPuts
36
36
  end
37
37
 
@@ -2,14 +2,18 @@
2
2
 
3
3
  require 'maxmind/db/errors'
4
4
 
5
- module MaxMind # :nodoc:
5
+ module MaxMind
6
6
  class DB
7
7
  # +Decoder+ decodes a {MaxMind DB}[https://maxmind.github.io/MaxMind-DB/]
8
8
  # data section.
9
9
  #
10
10
  # Typically you will interact with this class through a Reader rather than
11
11
  # directly.
12
- class Decoder # :nodoc:
12
+ #
13
+ # @!visibility private
14
+ class Decoder
15
+ # rubocop:disable Style/OptionalBooleanParameter
16
+
13
17
  # Create a +Decoder+.
14
18
  #
15
19
  # +io+ is the DB. It must provide a +read+ method. It must be opened in
@@ -26,6 +30,7 @@ module MaxMind # :nodoc:
26
30
  @pointer_base = pointer_base
27
31
  @pointer_test = pointer_test
28
32
  end
33
+ # rubocop:enable Style/OptionalBooleanParameter
29
34
 
30
35
  private
31
36
 
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module MaxMind # :nodoc:
3
+ module MaxMind
4
4
  class DB
5
5
  # An InvalidDatabaseError means the {MaxMind
6
6
  # DB}[https://maxmind.github.io/MaxMind-DB/] file is corrupt or invalid.
@@ -2,13 +2,40 @@
2
2
 
3
3
  require 'maxmind/db/errors'
4
4
 
5
- module MaxMind # :nodoc:
5
+ module MaxMind
6
6
  class DB
7
- class FileReader # :nodoc:
7
+ # @!visibility private
8
+ class FileReader
9
+ if ::File.method_defined?(:pread)
10
+ PReadFile = ::File
11
+ else
12
+ # For Windows support
13
+ class PReadFile
14
+ def initialize(filename, mode)
15
+ @mutex = Mutex.new
16
+ @file = File.new(filename, mode)
17
+ end
18
+
19
+ def size
20
+ @file.size
21
+ end
22
+
23
+ def close
24
+ @file.close
25
+ end
26
+
27
+ def pread(size, offset)
28
+ @mutex.synchronize do
29
+ @file.seek(offset, IO::SEEK_SET)
30
+ @file.read(size)
31
+ end
32
+ end
33
+ end
34
+ end
35
+
8
36
  def initialize(filename)
9
- @fh = File.new(filename, 'rb')
37
+ @fh = PReadFile.new(filename, 'rb')
10
38
  @size = @fh.size
11
- @mutex = Mutex.new
12
39
  end
13
40
 
14
41
  attr_reader :size
@@ -20,15 +47,7 @@ module MaxMind # :nodoc:
20
47
  def read(offset, size)
21
48
  return ''.b if size == 0
22
49
 
23
- # When we support only Ruby 2.5+, remove this and require pread.
24
- if @fh.respond_to?(:pread)
25
- buf = @fh.pread(size, offset)
26
- else
27
- @mutex.synchronize do
28
- @fh.seek(offset, IO::SEEK_SET)
29
- buf = @fh.read(size)
30
- end
31
- end
50
+ buf = @fh.pread(size, offset)
32
51
 
33
52
  raise InvalidDatabaseError, 'The MaxMind DB file contains bad data' if buf.nil? || buf.length != size
34
53
 
@@ -1,8 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module MaxMind # :nodoc:
3
+ module MaxMind
4
4
  class DB
5
- class MemoryReader # :nodoc:
5
+ # @!visibility private
6
+ class MemoryReader
6
7
  def initialize(filename, options = {})
7
8
  if options[:is_buffer]
8
9
  @buf = filename
@@ -18,8 +19,7 @@ module MaxMind # :nodoc:
18
19
 
19
20
  # Override to not show @buf in inspect to avoid showing it in irb.
20
21
  def inspect
21
- s = "#<#{self.class.name}:0x#{self.class.object_id.to_s(16)} "
22
- s << '@size=' << @size.inspect << '>'
22
+ "#<#{self.class.name}:0x#{self.class.object_id.to_s(16)}, @size=#{@size.inspect}>"
23
23
  end
24
24
 
25
25
  def close; end
@@ -1,42 +1,64 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module MaxMind # :nodoc:
3
+ module MaxMind
4
4
  class DB
5
5
  # Metadata holds metadata about a {MaxMind
6
- # DB}[https://maxmind.github.io/MaxMind-DB/] file.
6
+ # DB}[https://maxmind.github.io/MaxMind-DB/] file. See
7
+ # https://maxmind.github.io/MaxMind-DB/#database-metadata for the
8
+ # specification.
7
9
  class Metadata
8
10
  # The number of nodes in the database.
11
+ #
12
+ # @return [Integer]
9
13
  attr_reader :node_count
10
14
 
11
15
  # The bit size of a record in the search tree.
16
+ #
17
+ # @return [Integer]
12
18
  attr_reader :record_size
13
19
 
14
20
  # The IP version of the data in the database. A value of 4 means the
15
21
  # database only supports IPv4. A database with a value of 6 may support
16
22
  # both IPv4 and IPv6 lookups.
23
+ #
24
+ # @return [Integer]
17
25
  attr_reader :ip_version
18
26
 
19
27
  # A string identifying the database type. e.g., "GeoIP2-City".
28
+ #
29
+ # @return [String]
20
30
  attr_reader :database_type
21
31
 
22
32
  # An array of locale codes supported by the database.
33
+ #
34
+ # @return [Array<String>]
23
35
  attr_reader :languages
24
36
 
25
37
  # The major version number of the binary format used when creating the
26
38
  # database.
39
+ #
40
+ # @return [Integer]
27
41
  attr_reader :binary_format_major_version
28
42
 
29
43
  # The minor version number of the binary format used when creating the
30
44
  # database.
45
+ #
46
+ # @return [Integer]
31
47
  attr_reader :binary_format_minor_version
32
48
 
33
49
  # The Unix epoch for the build time of the database.
50
+ #
51
+ # @return [Integer]
34
52
  attr_reader :build_epoch
35
53
 
36
54
  # A hash from locales to text descriptions of the database.
55
+ #
56
+ # @return [Hash<String, String>]
37
57
  attr_reader :description
38
58
 
39
59
  # +m+ is a hash representing the metadata map.
60
+ #
61
+ # @!visibility private
40
62
  def initialize(map)
41
63
  @node_count = map['node_count']
42
64
  @record_size = map['record_size']
@@ -50,11 +72,15 @@ module MaxMind # :nodoc:
50
72
  end
51
73
 
52
74
  # The size of a node in bytes.
75
+ #
76
+ # @return [Integer]
53
77
  def node_byte_size
54
78
  @record_size / 4
55
79
  end
56
80
 
57
81
  # The size of the search tree in bytes.
82
+ #
83
+ # @return [Integer]
58
84
  def search_tree_size
59
85
  @node_count * node_byte_size
60
86
  end
data/lib/maxmind/db.rb CHANGED
@@ -3,11 +3,11 @@
3
3
  require 'ipaddr'
4
4
  require 'maxmind/db/decoder'
5
5
  require 'maxmind/db/errors'
6
- require 'maxmind/db/file_reader.rb'
7
- require 'maxmind/db/memory_reader.rb'
8
- require 'maxmind/db/metadata.rb'
6
+ require 'maxmind/db/file_reader'
7
+ require 'maxmind/db/memory_reader'
8
+ require 'maxmind/db/metadata'
9
9
 
10
- module MaxMind # :nodoc:
10
+ module MaxMind
11
11
  # DB provides a way to read {MaxMind DB
12
12
  # files}[https://maxmind.github.io/MaxMind-DB/].
13
13
  #
@@ -31,11 +31,6 @@ module MaxMind # :nodoc:
31
31
  # end
32
32
  #
33
33
  # reader.close
34
- #
35
- # == Exceptions
36
- #
37
- # DB raises an InvalidDatabaseError if the database is corrupt or invalid. It
38
- # can raise other exceptions, such as ArgumentError, if other errors occur.
39
34
  class DB
40
35
  # Choose the default method to open the database. Currently the default is
41
36
  # MODE_FILE.
@@ -47,7 +42,9 @@ module MaxMind # :nodoc:
47
42
  MODE_MEMORY = :MODE_MEMORY
48
43
  # Treat the database parameter as containing a database already read into
49
44
  # memory. It must be a binary string. This primarily exists for testing.
50
- MODE_PARAM_IS_BUFFER = :MODE_PARAM_IS_BUFFER # :nodoc:
45
+ #
46
+ # @!visibility private
47
+ MODE_PARAM_IS_BUFFER = :MODE_PARAM_IS_BUFFER
51
48
 
52
49
  DATA_SECTION_SEPARATOR_SIZE = 16
53
50
  private_constant :DATA_SECTION_SEPARATOR_SIZE
@@ -59,7 +56,9 @@ module MaxMind # :nodoc:
59
56
  private_constant :METADATA_MAX_SIZE
60
57
 
61
58
  # Return the metadata associated with the {MaxMind
62
- # DB}[https://maxmind.github.io/MaxMind-DB/] as a Metadata object.
59
+ # DB}[https://maxmind.github.io/MaxMind-DB/]
60
+ #
61
+ # @return [MaxMind::DB::Metadata]
63
62
  attr_reader :metadata
64
63
 
65
64
  # Create a DB. A DB provides a way to read {MaxMind DB
@@ -70,20 +69,20 @@ module MaxMind # :nodoc:
70
69
  # is safe to use after forking only if you use MODE_MEMORY or if your
71
70
  # version of Ruby supports IO#pread.
72
71
  #
73
- # Creating the DB may raise an exception if initialization fails.
72
+ # @param database [String] a path to a {MaxMind
73
+ # DB}[https://maxmind.github.io/MaxMind-DB/].
74
74
  #
75
- # +database+ is a path to a {MaxMind
76
- # DB}[https://maxmind.github.io/MaxMind-DB/].
75
+ # @param options [Hash<Symbol, Symbol>] options controlling the behavior of
76
+ # the DB.
77
77
  #
78
- # +options+ is an option hash where each key is a symbol. The options
79
- # control the behaviour of the DB.
78
+ # @option options [Symbol] :mode Defines how to open the database. It may
79
+ # be one of MODE_AUTO, MODE_FILE, or MODE_MEMORY. If you don't provide
80
+ # one, DB uses MODE_AUTO. Refer to the definition of those constants for
81
+ # an explanation of their meaning.
80
82
  #
81
- # The available options are:
83
+ # @raise [InvalidDatabaseError] if the database is corrupt or invalid.
82
84
  #
83
- # [+:mode+] defines how to open the database. It may be one of MODE_AUTO,
84
- # MODE_FILE, or MODE_MEMORY. If you don't provide one, DB uses
85
- # MODE_AUTO. Refer to the definition of those constants for an
86
- # explanation of their meaning.
85
+ # @raise [ArgumentError] if the mode is invalid.
87
86
  def initialize(database, options = {})
88
87
  options[:mode] = MODE_AUTO unless options.key?(:mode)
89
88
 
@@ -125,37 +124,45 @@ module MaxMind # :nodoc:
125
124
  end
126
125
  end
127
126
 
128
- # Return the record for the +ip_address+ in the {MaxMind
127
+ # Return the record for the IP address in the {MaxMind
129
128
  # DB}[https://maxmind.github.io/MaxMind-DB/]. The record can be one of
130
129
  # several types and depends on the contents of the database.
131
130
  #
132
- # If no record is found for +ip_address+, +get+ returns +nil+.
131
+ # If no record is found for the IP address, +get+ returns +nil+.
132
+ #
133
+ # @param ip_address [String, IPAddr] IPv4 or IPv6 address.
133
134
  #
134
- # +get+ raises an exception if there is an error performing the lookup.
135
+ # @raise [ArgumentError] if you attempt to look up an IPv6 address in an
136
+ # IPv4-only database.
135
137
  #
136
- # +ip_address+ is a string in the standard notation. It may be IPv4 or
137
- # IPv6.
138
+ # @raise [InvalidDatabaseError] if the database is corrupt or invalid.
139
+ #
140
+ # @return [Object, nil]
138
141
  def get(ip_address)
139
142
  record, = get_with_prefix_length(ip_address)
140
143
 
141
144
  record
142
145
  end
143
146
 
144
- # Return an array containing the record for the +ip_address+ in the
147
+ # Return an array containing the record for the IP address in the
145
148
  # {MaxMind DB}[https://maxmind.github.io/MaxMind-DB/] and its associated
146
149
  # network prefix length. The record can be one of several types and
147
150
  # depends on the contents of the database.
148
151
  #
149
- # If no record is found for +ip_address+, the record will be +nil+ and
152
+ # If no record is found for the IP address, the record will be +nil+ and
150
153
  # the prefix length will be the value for the missing network.
151
154
  #
152
- # +get_with_prefix_length+ raises an exception if there is an error
153
- # performing the lookup.
155
+ # @param ip_address [String, IPAddr] IPv4 or IPv6 address.
156
+ #
157
+ # @raise [ArgumentError] if you attempt to look up an IPv6 address in an
158
+ # IPv4-only database.
159
+ #
160
+ # @raise [InvalidDatabaseError] if the database is corrupt or invalid.
154
161
  #
155
- # +ip_address+ is a string in the standard notation. It may be IPv4 or
156
- # IPv6.
162
+ # @return [Array<(Object, Integer)>]
157
163
  def get_with_prefix_length(ip_address)
158
- ip = IPAddr.new(ip_address)
164
+ ip = ip_address.is_a?(IPAddr) ? ip_address : IPAddr.new(ip_address)
165
+
159
166
  # We could check the IP has the correct prefix (32 or 128) but I do not
160
167
  # for performance reasons.
161
168
 
@@ -192,7 +199,7 @@ module MaxMind # :nodoc:
192
199
  break if depth >= bit_count || node >= node_count
193
200
 
194
201
  c = packed[depth >> 3].ord
195
- bit = 1 & (c >> 7 - (depth % 8))
202
+ bit = 1 & (c >> (7 - (depth % 8)))
196
203
  node = read_node(node, bit)
197
204
  depth += 1
198
205
  end
@@ -221,8 +228,6 @@ module MaxMind # :nodoc:
221
228
 
222
229
  # Read a record from the indicated node. Index indicates whether it's the
223
230
  # left (0) or right (1) record.
224
- #
225
- # rubocop:disable Metrics/CyclomaticComplexity
226
231
  def read_node(node_number, index)
227
232
  base_offset = node_number * @node_byte_size
228
233
 
@@ -253,7 +258,6 @@ module MaxMind # :nodoc:
253
258
 
254
259
  raise InvalidDatabaseError, "Unsupported record size: #{@record_size}"
255
260
  end
256
- # rubocop:enable Metrics/CyclomaticComplexity
257
261
 
258
262
  def resolve_data_pointer(pointer)
259
263
  offset_in_file = pointer - @node_count + @search_tree_size
@@ -268,7 +272,7 @@ module MaxMind # :nodoc:
268
272
  end
269
273
 
270
274
  def find_metadata_start
271
- metadata_max_size = @size < METADATA_MAX_SIZE ? @size : METADATA_MAX_SIZE
275
+ metadata_max_size = [@size, METADATA_MAX_SIZE].min
272
276
 
273
277
  stop_index = @size - metadata_max_size
274
278
  index = @size - METADATA_START_MARKER_LENGTH
@@ -290,8 +294,7 @@ module MaxMind # :nodoc:
290
294
 
291
295
  # Close the DB and return resources to the system.
292
296
  #
293
- # There is no useful return value. #close raises an exception if there is
294
- # an error.
297
+ # @return [void]
295
298
  def close
296
299
  @io.close
297
300
  end
data/maxmind-db.gemspec CHANGED
@@ -5,7 +5,7 @@ Gem::Specification.new do |s|
5
5
  s.files = Dir['**/*']
6
6
  s.name = 'maxmind-db'
7
7
  s.summary = 'A gem for reading MaxMind DB files.'
8
- s.version = '1.1.0'
8
+ s.version = '1.2.0'
9
9
 
10
10
  s.description = 'A gem for reading MaxMind DB files. MaxMind DB is a binary file format that stores data indexed by IP address subnets (IPv4 or IPv6).'
11
11
  s.email = 'support@maxmind.com'
@@ -13,10 +13,16 @@ Gem::Specification.new do |s|
13
13
  s.licenses = ['Apache-2.0', 'MIT']
14
14
  s.metadata = {
15
15
  'bug_tracker_uri' => 'https://github.com/maxmind/MaxMind-DB-Reader-ruby/issues',
16
- 'changelog_uri' => 'https://github.com/maxmind/MaxMind-DB-Reader-ruby/blob/master/CHANGELOG.md',
17
- 'documentation_uri' => 'https://github.com/maxmind/MaxMind-DB-Reader-ruby',
16
+ 'changelog_uri' => 'https://github.com/maxmind/MaxMind-DB-Reader-ruby/blob/main/CHANGELOG.md',
17
+ 'documentation_uri' => 'https://www.rubydoc.info/gems/maxmind-db',
18
18
  'homepage_uri' => 'https://github.com/maxmind/MaxMind-DB-Reader-ruby',
19
19
  'source_code_uri' => 'https://github.com/maxmind/MaxMind-DB-Reader-ruby',
20
+ 'rubygems_mfa_required' => 'true',
20
21
  }
21
- s.required_ruby_version = '>= 2.4.0'
22
+ s.required_ruby_version = '>= 2.5.0'
23
+
24
+ s.add_development_dependency 'minitest'
25
+ s.add_development_dependency 'rake'
26
+ s.add_development_dependency 'rubocop'
27
+ s.add_development_dependency 'rubocop-performance'
22
28
  end
data/test/data/LICENSE ADDED
@@ -0,0 +1,4 @@
1
+ This work is licensed under the Creative Commons Attribution-ShareAlike 3.0
2
+ Unported License. To view a copy of this license, visit
3
+ http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative
4
+ Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA.