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 +4 -4
- data/.coveralls.yml +1 -0
- data/.travis.yml +2 -0
- data/Gemfile +7 -1
- data/README.md +8 -3
- data/lib/erlang/etf.rb +15 -4
- data/lib/erlang/etf/compressed.rb +66 -0
- data/lib/erlang/etf/terms.rb +26 -2
- data/lib/erlang/etf/version.rb +1 -1
- data/spec/erlang/etf/compressed_spec.rb +37 -0
- data/spec/erlang_spec.rb +14 -0
- data/spec/spec_helper.rb +25 -1
- metadata +5 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 320c12034e0d50d1f92aeeadcc0042a121f972de
|
4
|
+
data.tar.gz: c739e92472dbdef20ab555ddfb53b8404a7100d0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d793115fb5b5bfe1694c0a23a0b0819435e206c91f8c55876cdbd0327e4bec433f0eafa9a4893e6e292832fb0a698e63c95db38c56d0a69857c3a87e4f2e34bd
|
7
|
+
data.tar.gz: 6d05ec4e5619e8eedc9d95dadb904b2b4d6aaef75c857572f5aa21cb9e2573ab37e88e09d31336ef7b6d46d14d7b29b36f5ed7e2be3dc0f826031503bc5bdd89
|
data/.coveralls.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
service_name: travis-ci
|
data/.travis.yml
CHANGED
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
|
-
[](https://travis-ci.org/potatosalad/erlang-etf)
|
1
|
+
# Erlang::ETF [](https://travis-ci.org/potatosalad/erlang-etf) [](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
|
data/lib/erlang/etf.rb
CHANGED
@@ -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
|
-
|
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,
|
37
|
-
|
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
|
data/lib/erlang/etf/terms.rb
CHANGED
@@ -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
|
-
|
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)
|
data/lib/erlang/etf/version.rb
CHANGED
@@ -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
|
data/spec/erlang_spec.rb
CHANGED
@@ -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
|
data/spec/spec_helper.rb
CHANGED
@@ -1,7 +1,31 @@
|
|
1
|
-
if ENV[
|
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.
|
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
|