erlang-etf 1.1.0 → 1.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
[![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
|
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
|