nbt_utils 0.0.2 → 0.5.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 (51) hide show
  1. checksums.yaml +7 -0
  2. data/.github/dependabot.yml +6 -0
  3. data/.github/workflows/ci.yml +24 -0
  4. data/.gitignore +2 -0
  5. data/.rspec +1 -0
  6. data/.rubocop.yml +37 -0
  7. data/.ruby-version +1 -0
  8. data/Gemfile +2 -0
  9. data/Gemfile.lock +49 -4
  10. data/LICENSE +7 -0
  11. data/README.md +16 -18
  12. data/Rakefile +8 -0
  13. data/doc/bigtest_uncompressed.nbt +0 -0
  14. data/doc/test_uncompressed.nbt +0 -0
  15. data/lib/nbt_utils/file.rb +25 -8
  16. data/lib/nbt_utils/tag/byte.rb +4 -1
  17. data/lib/nbt_utils/tag/byte_array.rb +9 -7
  18. data/lib/nbt_utils/tag/compound.rb +22 -17
  19. data/lib/nbt_utils/tag/double.rb +4 -1
  20. data/lib/nbt_utils/tag/end.rb +6 -4
  21. data/lib/nbt_utils/tag/exceptions.rb +3 -1
  22. data/lib/nbt_utils/tag/float.rb +4 -1
  23. data/lib/nbt_utils/tag/int.rb +4 -1
  24. data/lib/nbt_utils/tag/int_array.rb +37 -0
  25. data/lib/nbt_utils/tag/list.rb +20 -15
  26. data/lib/nbt_utils/tag/long.rb +4 -1
  27. data/lib/nbt_utils/tag/short.rb +4 -1
  28. data/lib/nbt_utils/tag/string.rb +2 -0
  29. data/lib/nbt_utils/tag.rb +13 -17
  30. data/lib/nbt_utils/tag_name.rb +5 -3
  31. data/lib/nbt_utils/version.rb +3 -1
  32. data/lib/nbt_utils.rb +3 -0
  33. data/nbt_utils.gemspec +17 -11
  34. data/script.rb +21 -19
  35. data/spec/nbt_utils/file_spec.rb +60 -0
  36. data/spec/nbt_utils/tag/byte_array_spec.rb +5 -0
  37. data/spec/nbt_utils/tag/byte_spec.rb +5 -0
  38. data/spec/nbt_utils/tag/compound_spec.rb +5 -0
  39. data/spec/nbt_utils/tag/double_spec.rb +5 -0
  40. data/spec/nbt_utils/tag/end_spec.rb +5 -0
  41. data/spec/nbt_utils/tag/float_spec.rb +5 -0
  42. data/spec/nbt_utils/tag/int_array_spec.rb +5 -0
  43. data/spec/nbt_utils/tag/int_spec.rb +5 -0
  44. data/spec/nbt_utils/tag/list_spec.rb +5 -0
  45. data/spec/nbt_utils/tag/long_spec.rb +5 -0
  46. data/spec/nbt_utils/tag/short_spec.rb +5 -0
  47. data/spec/nbt_utils/tag/string_spec.rb +5 -0
  48. data/spec/nbt_utils/tag_name_spec.rb +20 -0
  49. data/spec/spec_helper.rb +102 -0
  50. data/spec/support/shared_examples/a_tag.rb +8 -0
  51. metadata +116 -54
data/lib/nbt_utils/tag.rb CHANGED
@@ -1,36 +1,34 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module NBTUtils
2
4
  module Tag
3
- attr_reader :name
4
- attr_reader :payload
5
+ attr_reader :name, :payload
5
6
 
6
7
  def self.included(base)
7
8
  base.extend ClassMethods
8
9
  end
9
10
 
10
- def initialize(io, named = true)
11
+ def initialize(io, named: true)
11
12
  read_name(io) if named
12
13
  @payload = self.class.payload_class.new.read(io)
13
14
  end
14
-
15
+
15
16
  def type_id
16
17
  self.class.type_id
17
18
  end
18
19
 
19
20
  def binary_type_id
20
- # I hope i'm doing this wrong.
21
- byte = ::BinData::Int8be.new
22
- byte.value = type_id
23
- byte.to_binary_s
21
+ type_id.chr
24
22
  end
25
23
 
26
24
  def to_s(indent = 0)
27
25
  klass = self.class.to_s.split('::').last
28
- (' ' * indent) + "TAG_#{klass}#{@name ? "(\"#{@name}\")" : ''}: #{@payload.value}"
26
+ (' ' * indent) + "TAG_#{klass}#{name ? "(\"#{name}\")" : ''}: #{payload.value}"
29
27
  end
30
28
 
31
- def to_nbt_string(named = true)
29
+ def to_nbt_string(named: true)
32
30
  result = named ? binary_type_id + name_to_nbt_string : ''
33
- result + @payload.to_binary_s
31
+ result + payload.to_binary_s
34
32
  end
35
33
 
36
34
  def read_name(io)
@@ -39,7 +37,7 @@ module NBTUtils
39
37
 
40
38
  def name_to_nbt_string
41
39
  nm = NBTUtils::TagName.new
42
- nm.data = @name
40
+ nm.data = name
43
41
  nm.to_binary_s
44
42
  end
45
43
 
@@ -47,8 +45,8 @@ module NBTUtils
47
45
  NBTUtils::Tag.tag_type_to_class(tag_type)
48
46
  end
49
47
 
50
- def set_value(new_value, index = nil)
51
- @payload.value = new_value
48
+ def set_value(new_value, _index = nil)
49
+ payload.value = new_value
52
50
  end
53
51
 
54
52
  module ClassMethods
@@ -71,11 +69,9 @@ module NBTUtils
71
69
  @tag_types[tag_type.to_i]
72
70
  end
73
71
 
74
- protected
75
-
76
72
  def self.add_tag_type(index, tag_type)
77
73
  @tag_types ||= []
78
74
  @tag_types[index] = tag_type
79
75
  end
80
76
  end
81
- end
77
+ end
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module NBTUtils
2
4
  class TagName < ::BinData::Record
3
5
  # Spec says this is a TAG_Short, which is signed. Staying strict
4
6
  # though this may really be unsigned in practice.
5
- int16be :len, :value => Proc.new { data.length }
6
- string :data, :read_length => :len
7
+ int16be :len, value: proc { data.length }
8
+ string :data, read_length: :len
7
9
 
8
10
  # things break for some reason if you just call the string :value
9
11
  def value
@@ -14,4 +16,4 @@ module NBTUtils
14
16
  self.data = (other_value)
15
17
  end
16
18
  end
17
- end
19
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module NBTUtils
2
- VERSION = "0.0.2"
4
+ VERSION = '0.5.0'
3
5
  end
data/lib/nbt_utils.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'zlib'
2
4
  require 'bindata'
3
5
 
@@ -17,3 +19,4 @@ require File.expand_path('nbt_utils/tag/byte_array', File.dirname(__FILE__))
17
19
  require File.expand_path('nbt_utils/tag/string', File.dirname(__FILE__))
18
20
  require File.expand_path('nbt_utils/tag/list', File.dirname(__FILE__))
19
21
  require File.expand_path('nbt_utils/tag/compound', File.dirname(__FILE__))
22
+ require File.expand_path('nbt_utils/tag/int_array', File.dirname(__FILE__))
data/nbt_utils.gemspec CHANGED
@@ -1,24 +1,30 @@
1
- # -*- encoding: utf-8 -*-
2
- require File.expand_path("../lib/nbt_utils/version", __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ require File.expand_path('lib/nbt_utils/version', __dir__)
3
4
 
4
5
  Gem::Specification.new do |s|
5
- s.name = "nbt_utils"
6
+ s.name = 'nbt_utils'
6
7
  s.version = NBTUtils::VERSION
7
8
  s.platform = Gem::Platform::RUBY
8
9
  s.authors = ['Michael Dungan']
9
10
  s.email = ['mpd@jesters-court.net']
10
- s.homepage = "http://rubygems.org/gems/nbt_utils"
11
- s.summary = "Set of classes to read and write Minecraft .nbt files"
12
- s.description = "Some classes to read and write Minecraft .nbt files. See http://www.minecraft.net/docs/NBT.txt for format description."
11
+ s.homepage = 'https://github.com/xxx/nbt_utils'
12
+ s.summary = 'Set of classes to read and write Minecraft .nbt files'
13
+ s.description = 'Some classes to read and write Minecraft .nbt files. '\
14
+ 'See NBT.txt in the /doc directory for format description.'
13
15
 
14
- s.required_rubygems_version = ">= 1.3.6"
16
+ s.required_rubygems_version = '>= 1.3.6'
15
17
 
16
- s.add_dependency "bindata", "~> 1.2"
17
- s.add_development_dependency "bundler", ">= 1.0.0"
18
+ s.add_dependency 'bindata', '~> 2'
19
+ s.add_development_dependency 'rspec', '~> 3'
20
+ s.add_development_dependency 'rubocop', '~> 1'
21
+ s.add_development_dependency 'rubocop-performance', '~> 1'
22
+ s.add_development_dependency 'rubocop-rspec', '~> 2'
18
23
 
19
- s.required_ruby_version = "~> 1.9"
24
+ s.required_ruby_version = '>= 2.7'
20
25
 
21
26
  s.files = `git ls-files`.split("\n")
22
- s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
27
+ s.executables = `git ls-files`.split("\n").filter_map { |f| f =~ %r{^bin/(.*)} ? Regexp.last_match(1) : nil }
23
28
  s.require_path = 'lib'
29
+ s.metadata['rubygems_mfa_required'] = 'true'
24
30
  end
data/script.rb CHANGED
@@ -1,4 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
1
3
  # encoding: UTF-8
4
+ # frozen_string_literal: true
2
5
 
3
6
  require 'bundler'
4
7
  Bundler.require :default
@@ -8,32 +11,31 @@ require 'zlib'
8
11
 
9
12
  @compound = nil
10
13
 
11
- #file = NBTUtils::File.new('doc/test.nbt')
12
- #@compound = file.read
14
+ # file = NBTUtils::File.new('doc/test.nbt')
15
+ # @compound = file.read
13
16
  #
14
- #puts @compound.to_s
17
+ # puts @compound.to_s
15
18
  #
16
- #@compound.update_tag('name', 'asdf')
17
- #puts @compound.to_s
19
+ # @compound.update_tag('name', 'asdf')
20
+ # puts @compound.to_s
18
21
  #
19
- #@compound.remove_tag('name')
20
- #puts @compound.to_s
21
-
22
- #puts @compound.to_nbt_string
23
- #NBTUtils::File.new.write('biglolwut.nbt', @compound)
22
+ # @compound.remove_tag('name')
23
+ # puts @compound.to_s
24
24
 
25
- #@compound = NBTUtils::File.new.read('doc/bigtest.nbt')
26
- #puts @compound.to_s
25
+ # puts @compound.to_nbt_string
26
+ # NBTUtils::File.new.write('biglolwut.nbt', @compound)
27
27
 
28
+ # @compound = NBTUtils::File.new.read('doc/bigtest.nbt')
29
+ # puts @compound.to_s
28
30
 
29
31
  @compound = NBTUtils::File.new.read('doc/test.mclevel')
30
32
  puts @compound.to_s
31
33
 
32
- #puts @compound.to_nbt_string
33
- #NBTUtils::File.new.write('biglolwut.nbt', @compound)
34
+ # puts @compound.to_nbt_string
35
+ # NBTUtils::File.new.write('biglolwut.nbt', @compound)
34
36
 
35
- #p @compound.find_tag(/Test/)
36
- #p @compound.find_tag('Test')
37
- #p @compound.find_tag('intTest')
38
- #p @compound.find_tags(/(?:byte|int)Test/)
39
- #p @compound.find_tags 'intasdf'
37
+ # p @compound.find_tag(/Test/)
38
+ # p @compound.find_tag('Test')
39
+ # p @compound.find_tag('intTest')
40
+ # p @compound.find_tags(/(?:byte|int)Test/)
41
+ # p @compound.find_tags 'intasdf'
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe NBTUtils::File do
4
+ let(:file) { described_class.new(File.expand_path("../../../doc/#{fixture}", __FILE__)) }
5
+ let(:fixture) { 'test_uncompressed.nbt' }
6
+
7
+ describe '#read' do
8
+ subject(:call) { file.read }
9
+
10
+ shared_examples 'reads the file' do
11
+ it 'reads the file and returns the root tag', :aggregate_failures do
12
+ expect(call.name).to eq('hello world')
13
+ expect(call.payload.first.payload.value).to eq('Bananrama')
14
+ end
15
+ end
16
+
17
+ context 'when the file is not compressed' do
18
+ let(:fixture) { 'test_uncompressed.nbt' }
19
+
20
+ include_examples 'reads the file'
21
+ end
22
+
23
+ context 'when the file is compressed' do
24
+ let(:fixture) { 'test.nbt' }
25
+
26
+ include_examples 'reads the file'
27
+ end
28
+ end
29
+
30
+ describe '#write' do
31
+ let(:root) { file.read }
32
+
33
+ let(:out_path) { "#{__dir__}/write-test.nbt" }
34
+
35
+ shared_examples 'writes the file' do
36
+ it 'writes the file out' do
37
+ tag = root.payload.first
38
+
39
+ file.write(out_path, tag, compressed)
40
+
41
+ read_in = described_class.new(out_path).read
42
+ expect(read_in.payload.value).to eq 'Bananrama'
43
+ ensure
44
+ File.delete(out_path) if File.exist?(out_path)
45
+ end
46
+ end
47
+
48
+ context 'when the file is not compressed' do
49
+ let(:compressed) { false }
50
+
51
+ include_examples 'writes the file'
52
+ end
53
+
54
+ context 'when the file is compressed' do
55
+ let(:compressed) { true }
56
+
57
+ include_examples 'writes the file'
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe NBTUtils::Tag::ByteArray do
4
+ it_behaves_like 'a tag', 7, nil
5
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe NBTUtils::Tag::Byte do
4
+ it_behaves_like 'a tag', 1, BinData::Int8be
5
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe NBTUtils::Tag::Compound do
4
+ it_behaves_like 'a tag', 10, nil
5
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe NBTUtils::Tag::Double do
4
+ it_behaves_like 'a tag', 6, BinData::DoubleBe
5
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe NBTUtils::Tag::End do
4
+ it_behaves_like 'a tag', 0, nil
5
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe NBTUtils::Tag::Float do
4
+ it_behaves_like 'a tag', 5, BinData::FloatBe
5
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe NBTUtils::Tag::IntArray do
4
+ it_behaves_like 'a tag', 11, nil
5
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe NBTUtils::Tag::Int do
4
+ it_behaves_like 'a tag', 3, BinData::Int32be
5
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe NBTUtils::Tag::List do
4
+ it_behaves_like 'a tag', 9, nil
5
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe NBTUtils::Tag::Long do
4
+ it_behaves_like 'a tag', 4, BinData::Int64be
5
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe NBTUtils::Tag::Short do
4
+ it_behaves_like 'a tag', 2, BinData::Int16be
5
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe NBTUtils::Tag::String do
4
+ it_behaves_like 'a tag', 8, NBTUtils::TagName
5
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe NBTUtils::TagName do
4
+ subject(:tag_name) { described_class.new }
5
+
6
+ describe '#value' do
7
+ it 'returns the data value' do
8
+ expect(tag_name.value).to eq('')
9
+ tag_name.data = 'foo'
10
+ expect(tag_name.value).to eq('foo')
11
+ end
12
+ end
13
+
14
+ describe '#value=' do
15
+ it 'returns the data value' do
16
+ tag_name.value = 'marf'
17
+ expect(tag_name.data).to eq('marf')
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'nbt_utils'
4
+
5
+ require 'support/shared_examples/a_tag'
6
+
7
+ # This file was generated by the `rspec --init` command. Conventionally, all
8
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
9
+ # The generated `.rspec` file contains `--require spec_helper` which will cause
10
+ # this file to always be loaded, without a need to explicitly require it in any
11
+ # files.
12
+ #
13
+ # Given that it is always loaded, you are encouraged to keep this file as
14
+ # light-weight as possible. Requiring heavyweight dependencies from this file
15
+ # will add to the boot time of your test suite on EVERY test run, even for an
16
+ # individual file that may not need all of that loaded. Instead, consider making
17
+ # a separate helper file that requires the additional dependencies and performs
18
+ # the additional setup, and require it from the spec files that actually need
19
+ # it.
20
+ #
21
+ # See https://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
22
+ RSpec.configure do |config|
23
+ # rspec-expectations config goes here. You can use an alternate
24
+ # assertion/expectation library such as wrong or the stdlib/minitest
25
+ # assertions if you prefer.
26
+ config.expect_with :rspec do |expectations|
27
+ # This option will default to `true` in RSpec 4. It makes the `description`
28
+ # and `failure_message` of custom matchers include text for helper methods
29
+ # defined using `chain`, e.g.:
30
+ # be_bigger_than(2).and_smaller_than(4).description
31
+ # # => "be bigger than 2 and smaller than 4"
32
+ # ...rather than:
33
+ # # => "be bigger than 2"
34
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
35
+ end
36
+
37
+ # rspec-mocks config goes here. You can use an alternate test double
38
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
39
+ config.mock_with :rspec do |mocks|
40
+ # Prevents you from mocking or stubbing a method that does not exist on
41
+ # a real object. This is generally recommended, and will default to
42
+ # `true` in RSpec 4.
43
+ mocks.verify_partial_doubles = true
44
+ end
45
+
46
+ # This option will default to `:apply_to_host_groups` in RSpec 4 (and will
47
+ # have no way to turn it off -- the option exists only for backwards
48
+ # compatibility in RSpec 3). It causes shared context metadata to be
49
+ # inherited by the metadata hash of host groups and examples, rather than
50
+ # triggering implicit auto-inclusion in groups with matching metadata.
51
+ config.shared_context_metadata_behavior = :apply_to_host_groups
52
+
53
+ # The settings below are suggested to provide a good initial experience
54
+ # with RSpec, but feel free to customize to your heart's content.
55
+ # This allows you to limit a spec run to individual examples or groups
56
+ # you care about by tagging them with `:focus` metadata. When nothing
57
+ # is tagged with `:focus`, all examples get run. RSpec also provides
58
+ # aliases for `it`, `describe`, and `context` that include `:focus`
59
+ # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
60
+ config.filter_run_when_matching :focus
61
+
62
+ # Allows RSpec to persist some state between runs in order to support
63
+ # the `--only-failures` and `--next-failure` CLI options. We recommend
64
+ # you configure your source control system to ignore this file.
65
+ # config.example_status_persistence_file_path = "spec/examples.txt"
66
+
67
+ # Limits the available syntax to the non-monkey patched syntax that is
68
+ # recommended. For more details, see:
69
+ # https://relishapp.com/rspec/rspec-core/docs/configuration/zero-monkey-patching-mode
70
+ config.disable_monkey_patching!
71
+
72
+ # This setting enables warnings. It's recommended, but in some cases may
73
+ # be too noisy due to issues in dependencies.
74
+ config.warnings = true
75
+
76
+ # Many RSpec users commonly either run the entire suite or an individual
77
+ # file, and it's useful to allow more verbose output when running an
78
+ # individual spec file.
79
+ if config.files_to_run.one?
80
+ # Use the documentation formatter for detailed output,
81
+ # unless a formatter has already been configured
82
+ # (e.g. via a command-line flag).
83
+ config.default_formatter = 'doc'
84
+ end
85
+
86
+ # Print the 10 slowest examples and example groups at the
87
+ # end of the spec run, to help surface which specs are running
88
+ # particularly slow.
89
+ config.profile_examples = 10
90
+
91
+ # Run specs in random order to surface order dependencies. If you find an
92
+ # order dependency and want to debug it, you can fix the order by providing
93
+ # the seed, which is printed after each run.
94
+ # --seed 1234
95
+ config.order = :random
96
+
97
+ # Seed global randomization in this process using the `--seed` CLI option.
98
+ # Setting this allows you to use `--seed` to deterministically reproduce
99
+ # test failures related to randomization by passing the same `--seed` value
100
+ # as the one that triggered the failure.
101
+ Kernel.srand config.seed
102
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.shared_examples_for 'a tag' do |type_id, payload_class|
4
+ it 'has the type_id and payload_class', :aggregate_failures do
5
+ expect(described_class.type_id).to eq(type_id)
6
+ expect(described_class.payload_class).to eq(payload_class)
7
+ end
8
+ end