erlang-etf 1.1.0 → 1.1.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c065a1c33b75cf6235b7911022718a22fa44204c
4
- data.tar.gz: 57fb1fc1ce89f1826ac5bcef122f1eb085430baa
3
+ metadata.gz: 320c12034e0d50d1f92aeeadcc0042a121f972de
4
+ data.tar.gz: c739e92472dbdef20ab555ddfb53b8404a7100d0
5
5
  SHA512:
6
- metadata.gz: 3979a241f92a3f08a19e81042c266381fc8e17837e08f7f7dd7be0d34d637bacc051d0fff6a808237c57386b23fed4cc13970247efb70054c7f3ba0355668f79
7
- data.tar.gz: 8947fad90e772020fff53c997d7c5240b73cb9cd298e4ab0f3f951d76aefc90ab193225a4241b4636f022c2031fecdb4d29f12bab2fdeb02e4003fc7795e6189
6
+ metadata.gz: d793115fb5b5bfe1694c0a23a0b0819435e206c91f8c55876cdbd0327e4bec433f0eafa9a4893e6e292832fb0a698e63c95db38c56d0a69857c3a87e4f2e34bd
7
+ data.tar.gz: 6d05ec4e5619e8eedc9d95dadb904b2b4d6aaef75c857572f5aa21cb9e2573ab37e88e09d31336ef7b6d46d14d7b29b36f5ed7e2be3dc0f826031503bc5bdd89
@@ -0,0 +1 @@
1
+ service_name: travis-ci
@@ -2,3 +2,5 @@ language: ruby
2
2
  rvm:
3
3
  - 1.9.3
4
4
  - 2.0.0
5
+ - 2.1.1
6
+ env: CI="travis"
data/Gemfile CHANGED
@@ -5,10 +5,16 @@ platforms :ruby do
5
5
  gem "pry"
6
6
  gem "pry-doc"
7
7
  gem "redcarpet"
8
- gem "simplecov", require: false
9
8
  gem "yard"
10
9
  end
11
10
  end
12
11
 
12
+ group :test do
13
+ gem "simplecov", require: false
14
+ if ENV['CI']
15
+ gem 'coveralls', require: false
16
+ end
17
+ end
18
+
13
19
  # Specify your gem's dependencies in erlang-etf.gemspec
14
20
  gemspec
data/README.md CHANGED
@@ -1,6 +1,4 @@
1
- # Erlang::ETF
2
-
3
- [![Build Status](https://travis-ci.org/potatosalad/erlang-etf.png)](https://travis-ci.org/potatosalad/erlang-etf)
1
+ # Erlang::ETF [![Build Status](https://travis-ci.org/potatosalad/erlang-etf.png)](https://travis-ci.org/potatosalad/erlang-etf) [![Coverage Status](https://coveralls.io/repos/potatosalad/erlang-etf/badge.png)](https://coveralls.io/r/potatosalad/erlang-etf)
4
2
 
5
3
  Erlang [External Term Format](http://erlang.org/doc/apps/erts/erl_ext_dist.html) (ETF) for Ruby.
6
4
 
@@ -33,6 +31,13 @@ Erlang.term_to_binary(:atom)
33
31
  # => "\x83s\x04atom"
34
32
  ```
35
33
 
34
+ Compression is optional and valid arguments are `false`, `true`, and integers `0-9`.
35
+
36
+ ```ruby
37
+ Erlang.term_to_binary([1] * 100, compressed: true)
38
+ # => "\x83P\x00\x00\x00\xCEx\x9C\xCBa``HId\x1C\x1E0\v\x00\xE85'\x83"
39
+ ```
40
+
36
41
  ### `Erlang.binary_to_term(binary)`
37
42
 
38
43
  ```ruby
@@ -12,9 +12,13 @@ module Erlang
12
12
 
13
13
  ERLANG_MAGIC_BYTE = 131.chr.freeze
14
14
 
15
- def encode(term, buffer = "")
15
+ def encode(term, buffer = "", options = {})
16
16
  buffer << ERLANG_MAGIC_BYTE
17
- term.__erlang_dump__(buffer)
17
+ if options[:compressed]
18
+ Compressed.new(term.__erlang_evolve__, options[:compressed]).serialize(buffer)
19
+ else
20
+ term.__erlang_dump__(buffer)
21
+ end
18
22
  end
19
23
 
20
24
  def decode(buffer)
@@ -33,8 +37,15 @@ module Erlang
33
37
  ETF.decode(buffer)
34
38
  end
35
39
 
36
- def self.term_to_binary(term, buffer = "")
37
- ETF.encode(term, buffer)
40
+ def self.term_to_binary(term, buffer_or_options = "", options = nil)
41
+ if buffer_or_options.kind_of?(::Hash)
42
+ buffer = options || ""
43
+ options = buffer_or_options
44
+ else
45
+ buffer = buffer_or_options
46
+ end
47
+ options ||= {}
48
+ ETF.encode(term, buffer, options)
38
49
  end
39
50
 
40
51
  end
@@ -0,0 +1,66 @@
1
+ require 'zlib'
2
+
3
+ module Erlang
4
+ module ETF
5
+
6
+ #
7
+ # 1 | 4 | N
8
+ # --- | ---------------- | -------------------
9
+ # 80 | UncompressedSize | Zlib-compressedData
10
+ #
11
+ # Uncompressed Size (unsigned 32 bit integer in big-endian
12
+ # byte order) is the size of the data before it was compressed.
13
+ # The compressed data has the following format when it has been expanded:
14
+ #
15
+ # 1 | Uncompressed Size
16
+ # ---- | -----------------
17
+ # Tag | Data
18
+ #
19
+ # (see [`External Term Format`] and [`term_to_binary/2`])
20
+ #
21
+ # [`External Term Format`]: http://erlang.org/doc/apps/erts/erl_ext_dist.html#overall_format
22
+ # [`term_to_binary/2`]: http://www.erlang.org/doc/man/erlang.html#term_to_binary-2
23
+ #
24
+ class Compressed
25
+ include Term
26
+
27
+ uint8 :tag, always: Terms::COMPRESSED
28
+
29
+ uint32be :uncompressed_size, always: -> { data.serialize.bytesize }
30
+
31
+ term :data
32
+
33
+ deserialize do |buffer|
34
+ uncompressed_size, = buffer.read(BYTES_32).unpack(UINT32BE_PACK)
35
+ compressed_data = buffer.read()
36
+ uncompressed_data = ::Zlib::Inflate.inflate(compressed_data)
37
+ if uncompressed_size == uncompressed_data.bytesize
38
+ deserialize_data(::StringIO.new(uncompressed_data))
39
+ else
40
+ raise ::Zlib::DataError, "UncompressedSize value did not match the size of the uncompressed data"
41
+ end
42
+ end
43
+
44
+ undef serialize_data
45
+ def serialize_data(buffer)
46
+ uncompressed_data = data.serialize
47
+ compressed_data = ::Zlib::Deflate.deflate(uncompressed_data, @level)
48
+ buffer << compressed_data
49
+ end
50
+
51
+ finalize
52
+
53
+ LEVEL_RANGE = (0..9).freeze
54
+ LEVEL_DEFAULT = 6.freeze
55
+
56
+ def initialize(data, level = LEVEL_DEFAULT)
57
+ @data = data
58
+ @level = LEVEL_RANGE.include?(level) ? level : LEVEL_DEFAULT
59
+ end
60
+
61
+ def __ruby_evolve__
62
+ data.__ruby_evolve__
63
+ end
64
+ end
65
+ end
66
+ end
@@ -1,7 +1,12 @@
1
1
  module Erlang
2
2
  module ETF
3
+
4
+ #
5
+ # See [`erts/emulator/beam/external.h`]
6
+ #
7
+ # [`erts/emulator/beam/external.h`]: https://github.com/erlang/otp/blob/master/erts/emulator/beam/external.h
8
+ #
3
9
  module Terms
4
- ATOM_CACHE_REF = 82.freeze # not implemented
5
10
  SMALL_INTEGER_EXT = 97.freeze
6
11
  INTEGER_EXT = 98.freeze
7
12
  FLOAT_EXT = 99.freeze
@@ -27,6 +32,14 @@ module Erlang
27
32
  ATOM_UTF8_EXT = 118.freeze
28
33
  SMALL_ATOM_UTF8_EXT = 119.freeze
29
34
  MAP_EXT = 116.freeze
35
+
36
+ DIST_HEADER = 68.freeze # not implemented
37
+ ATOM_CACHE_REF = 82.freeze # not implemented
38
+ ATOM_INTERNAL_REF2 = 73.freeze # not implemented
39
+ ATOM_INTERNAL_REF3 = 75.freeze # not implemented
40
+ BINARY_INTERNAL_REF = 74.freeze # not implemented
41
+ BIT_BINARY_INTERNAL_REF = 76.freeze # not implemented
42
+ COMPRESSED = 80.freeze
30
43
  end
31
44
  end
32
45
  end
@@ -38,6 +51,7 @@ require "erlang/etf/atom"
38
51
  require "erlang/etf/atom_utf8"
39
52
  require "erlang/etf/binary"
40
53
  require "erlang/etf/bit_binary"
54
+ require "erlang/etf/compressed"
41
55
  require "erlang/etf/export"
42
56
  require "erlang/etf/float"
43
57
  require "erlang/etf/fun"
@@ -64,7 +78,7 @@ module Erlang
64
78
  module ETF
65
79
  module Terms
66
80
  MAP = {}
67
- # MAP[ATOM_CACHE_REF] = undefined
81
+
68
82
  MAP[SMALL_INTEGER_EXT] = ETF::SmallInteger
69
83
  MAP[INTEGER_EXT] = ETF::Integer
70
84
  MAP[FLOAT_EXT] = ETF::Float
@@ -91,6 +105,16 @@ module Erlang
91
105
  MAP[SMALL_ATOM_UTF8_EXT] = ETF::SmallAtomUTF8
92
106
  MAP[MAP_EXT] = ETF::Map
93
107
 
108
+ # MAP[DIST_HEADER] = NotImplementedError
109
+ # MAP[ATOM_CACHE_REF] = NotImplementedError
110
+ # MAP[ATOM_INTERNAL_REF2] = NotImplementedError
111
+ # MAP[ATOM_INTERNAL_REF3] = NotImplementedError
112
+ # MAP[BINARY_INTERNAL_REF] = NotImplementedError
113
+ # MAP[BIT_BINARY_INTERNAL_REF] = NotImplementedError
114
+ MAP[COMPRESSED] = ETF::Compressed
115
+
116
+ MAP.freeze
117
+
94
118
  def self.deserialize(buffer)
95
119
  key, = buffer.read(1).unpack(::Binary::Protocol::UINT8_PACK)
96
120
  if MAP.key?(key)
@@ -1,5 +1,5 @@
1
1
  module Erlang
2
2
  module ETF
3
- VERSION = "1.1.0"
3
+ VERSION = "1.1.1"
4
4
  end
5
5
  end
@@ -0,0 +1,37 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Erlang::ETF::Compressed do
6
+ let(:term_class) { Erlang::ETF::Compressed }
7
+
8
+ describe '[class]' do
9
+ describe 'deserialize' do
10
+ let(:buffer) { StringIO.new(bytes.pack('C*')) }
11
+ subject { term_class.deserialize(buffer) }
12
+
13
+ context "valid zlib bytes" do
14
+ let(:bytes) { [0, 0, 0, 18, 120, 218, 203, 102, 224, 103, 68, 5, 0, 9, 0, 0, 138] }
15
+
16
+ its(:uncompressed_size) { should eq(18) }
17
+ its(:data) { should eq(::Erlang::ETF::String.new(([1] * 15).pack('C*').from_utf8_binary).tap { |s| s.len = 15 }) }
18
+ its(:__ruby_evolve__) { should eq(::Erlang::String.new(([1] * 15).pack('C*').from_utf8_binary)) }
19
+ end
20
+
21
+ context "invalid zlib bytes" do
22
+ subject { -> { term_class.deserialize(buffer) } }
23
+ let(:bytes) { [0, 0, 0, 18, 120, 218, 203, 102, 224, 103, 68, 5, 0, 9, 0, 0] }
24
+
25
+ it { should raise_error(::Zlib::BufError) }
26
+ end
27
+
28
+ context "valid zlib bytes, invalid uncompressed size" do
29
+ subject { -> { term_class.deserialize(buffer) } }
30
+ let(:bytes) { [0, 0, 0, 17, 120, 218, 203, 102, 224, 103, 68, 5, 0, 9, 0, 0, 138] }
31
+
32
+ it { should raise_error(::Zlib::DataError) }
33
+ end
34
+ end
35
+ end
36
+
37
+ end
@@ -21,6 +21,10 @@ describe Erlang do
21
21
  expect(term).to eq(Erlang.binary_to_term(Erlang.term_to_binary(term)))
22
22
  end
23
23
 
24
+ def roundtrip_compressed(term, compression)
25
+ expect(term).to eq(Erlang.binary_to_term(Erlang.term_to_binary(term, compressed: compression)))
26
+ end
27
+
24
28
  roundtrip_variables = [
25
29
  1,
26
30
  1.0,
@@ -78,4 +82,14 @@ describe Erlang do
78
82
  roundtrip(roundtrip_variable)
79
83
  end
80
84
  end
85
+
86
+ [false, true, *Erlang::ETF::Compressed::LEVEL_RANGE].each do |compression|
87
+ context "when compression is #{compression}" do
88
+ roundtrip_variables.each do |roundtrip_variable|
89
+ it "roundtrips #{roundtrip_variable.inspect}" do
90
+ roundtrip_compressed(roundtrip_variable, compression)
91
+ end
92
+ end
93
+ end
94
+ end
81
95
  end
@@ -1,7 +1,31 @@
1
- if ENV["COVERAGE"]
1
+ if ENV['CI']
2
+ require 'simplecov'
3
+ require 'coveralls'
4
+
5
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
6
+ SimpleCov::Formatter::HTMLFormatter,
7
+ Coveralls::SimpleCov::Formatter
8
+ ]
9
+ SimpleCov.start do
10
+ add_filter 'spec'
11
+ end
12
+ elsif ENV['COVERAGE']
2
13
  require 'simplecov'
3
14
  SimpleCov.start
4
15
  end
5
16
 
6
17
  $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
7
18
  require 'erlang/etf'
19
+
20
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
21
+ RSpec.configure do |config|
22
+ config.treat_symbols_as_metadata_keys_with_true_values = true
23
+ config.run_all_when_everything_filtered = true
24
+ config.filter_run :focus
25
+
26
+ # Run specs in random order to surface order dependencies. If you find an
27
+ # order dependency and want to debug it, you can fix the order by providing
28
+ # the seed, which is printed after each run.
29
+ # --seed 1234
30
+ config.order = 'random'
31
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: erlang-etf
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Bennett
@@ -87,6 +87,7 @@ executables: []
87
87
  extensions: []
88
88
  extra_rdoc_files: []
89
89
  files:
90
+ - .coveralls.yml
90
91
  - .gitignore
91
92
  - .rspec
92
93
  - .travis.yml
@@ -102,6 +103,7 @@ files:
102
103
  - lib/erlang/etf/bert.rb
103
104
  - lib/erlang/etf/binary.rb
104
105
  - lib/erlang/etf/bit_binary.rb
106
+ - lib/erlang/etf/compressed.rb
105
107
  - lib/erlang/etf/export.rb
106
108
  - lib/erlang/etf/extensions.rb
107
109
  - lib/erlang/etf/extensions/array.rb
@@ -151,6 +153,7 @@ files:
151
153
  - spec/erlang/etf/atom_utf8_spec.rb
152
154
  - spec/erlang/etf/binary_spec.rb
153
155
  - spec/erlang/etf/bit_binary_spec.rb
156
+ - spec/erlang/etf/compressed_spec.rb
154
157
  - spec/erlang/etf/export_spec.rb
155
158
  - spec/erlang/etf/extensions/array_spec.rb
156
159
  - spec/erlang/etf/extensions/big_decimal_spec.rb
@@ -226,6 +229,7 @@ test_files:
226
229
  - spec/erlang/etf/atom_utf8_spec.rb
227
230
  - spec/erlang/etf/binary_spec.rb
228
231
  - spec/erlang/etf/bit_binary_spec.rb
232
+ - spec/erlang/etf/compressed_spec.rb
229
233
  - spec/erlang/etf/export_spec.rb
230
234
  - spec/erlang/etf/extensions/array_spec.rb
231
235
  - spec/erlang/etf/extensions/big_decimal_spec.rb