beambridge 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +23 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/History.txt +35 -0
- data/LICENSE +20 -0
- data/README.md +130 -0
- data/Rakefile +44 -0
- data/VERSION.yml +4 -0
- data/beambridge.gemspec +29 -0
- data/benchmarks/bench.rb +21 -0
- data/examples/echo/README.md +12 -0
- data/examples/echo/echo.erl +13 -0
- data/examples/echo/echo.rb +10 -0
- data/examples/gruff/gruff.erl +61 -0
- data/examples/gruff/gruff_provider.rb +30 -0
- data/examples/gruff/gruff_run.sh +19 -0
- data/examples/gruff/stat_run.sh +20 -0
- data/examples/gruff/stat_writer.erl +40 -0
- data/examples/simple/README.md +5 -0
- data/examples/simple/rerl.rb +110 -0
- data/examples/simple/rerl.sh +37 -0
- data/examples/tinderl/README.md +14 -0
- data/examples/tinderl/tinderl.erl +43 -0
- data/examples/tinderl/tinderl.rb +27 -0
- data/ext/decoder.c +398 -0
- data/ext/extconf.rb +11 -0
- data/lib/beambridge.rb +34 -0
- data/lib/beambridge/condition.rb +66 -0
- data/lib/beambridge/conditions/boolean.rb +11 -0
- data/lib/beambridge/conditions/hash.rb +13 -0
- data/lib/beambridge/conditions/static.rb +34 -0
- data/lib/beambridge/conditions/type.rb +17 -0
- data/lib/beambridge/constants.rb +36 -0
- data/lib/beambridge/decoder.rb +212 -0
- data/lib/beambridge/encoder.rb +164 -0
- data/lib/beambridge/errors/beambridge_error.rb +3 -0
- data/lib/beambridge/errors/decode_error.rb +3 -0
- data/lib/beambridge/errors/encode_error.rb +3 -0
- data/lib/beambridge/matcher.rb +21 -0
- data/lib/beambridge/port.rb +48 -0
- data/lib/beambridge/receiver.rb +69 -0
- data/lib/beambridge/types/function.rb +3 -0
- data/lib/beambridge/types/list.rb +3 -0
- data/lib/beambridge/types/new_function.rb +3 -0
- data/lib/beambridge/types/new_reference.rb +3 -0
- data/lib/beambridge/types/pid.rb +3 -0
- data/lib/beambridge/types/reference.rb +3 -0
- data/lib/beambridge/version.rb +3 -0
- data/spec/condition_spec.rb +72 -0
- data/spec/decode_spec.rb +143 -0
- data/spec/encode_spec.rb +152 -0
- data/spec/matcher_spec.rb +81 -0
- data/spec/port_spec.rb +34 -0
- data/spec/receiver_spec.rb +103 -0
- data/spec/spec_helper.rb +47 -0
- metadata +153 -0
@@ -0,0 +1,21 @@
|
|
1
|
+
module Beambridge
|
2
|
+
class Matcher
|
3
|
+
attr_accessor :condition, :block
|
4
|
+
attr_accessor :receiver
|
5
|
+
|
6
|
+
def initialize(parent, condition, block)
|
7
|
+
self.receiver = parent
|
8
|
+
@block = block
|
9
|
+
@condition = Condition.for(condition)
|
10
|
+
end
|
11
|
+
|
12
|
+
def run(arg)
|
13
|
+
args = @condition.binding_for(arg)
|
14
|
+
block.call(*args)
|
15
|
+
end
|
16
|
+
|
17
|
+
def matches?(arg)
|
18
|
+
@condition.satisfies?(arg)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Beambridge
|
2
|
+
class Port
|
3
|
+
attr_reader :input, :output
|
4
|
+
attr_reader :skipped
|
5
|
+
attr_reader :queue
|
6
|
+
|
7
|
+
def initialize(input=STDIN, output=STDOUT)
|
8
|
+
@input = input
|
9
|
+
@output = output
|
10
|
+
|
11
|
+
input.sync = true
|
12
|
+
output.sync = true
|
13
|
+
|
14
|
+
output.set_encoding("ASCII-8BIT")
|
15
|
+
|
16
|
+
@encoder = Beambridge::Encoder.new(nil)
|
17
|
+
@skipped = []
|
18
|
+
@queue = []
|
19
|
+
end
|
20
|
+
|
21
|
+
def receive
|
22
|
+
queue.empty? ? read_from_input : queue.shift
|
23
|
+
end
|
24
|
+
|
25
|
+
def send(term)
|
26
|
+
@encoder.out = StringIO.new('', 'w')
|
27
|
+
@encoder.write_any(term)
|
28
|
+
data = @encoder.out.string
|
29
|
+
output.write([data.length].pack("N"))
|
30
|
+
output.write(data)
|
31
|
+
end
|
32
|
+
|
33
|
+
def restore_skipped
|
34
|
+
@queue = self.skipped + self.queue
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def read_from_input
|
40
|
+
raw = input.read(4)
|
41
|
+
return nil unless raw
|
42
|
+
|
43
|
+
packet_length = raw.unpack('N').first
|
44
|
+
data = input.read(packet_length)
|
45
|
+
Beambridge::Decoder.decode(data)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Beambridge
|
2
|
+
class Receiver
|
3
|
+
attr_accessor :port
|
4
|
+
attr_accessor :parent
|
5
|
+
attr_accessor :matchers
|
6
|
+
|
7
|
+
RECEIVE_LOOP = Object.new
|
8
|
+
NO_MATCH = Object.new
|
9
|
+
|
10
|
+
def initialize(port, parent = nil, &block)
|
11
|
+
@port = port
|
12
|
+
@parent = parent
|
13
|
+
@matchers = []
|
14
|
+
block.call(self) if block
|
15
|
+
end
|
16
|
+
|
17
|
+
def process(arg)
|
18
|
+
matcher = @matchers.find { |r| r.matches?(arg) }
|
19
|
+
|
20
|
+
if matcher
|
21
|
+
port.restore_skipped
|
22
|
+
matcher.run(arg)
|
23
|
+
else
|
24
|
+
NO_MATCH
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def when(arg, &block)
|
29
|
+
condition = Condition.for(arg)
|
30
|
+
@matchers << Matcher.new(self, condition, block)
|
31
|
+
end
|
32
|
+
|
33
|
+
def run
|
34
|
+
loop do
|
35
|
+
msg = port.receive
|
36
|
+
return if msg.nil?
|
37
|
+
|
38
|
+
case result = process(msg)
|
39
|
+
when RECEIVE_LOOP then next
|
40
|
+
when NO_MATCH
|
41
|
+
port.skipped << msg
|
42
|
+
next
|
43
|
+
else
|
44
|
+
break result
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def receive(&block)
|
50
|
+
Receiver.new(port, self, &block).run
|
51
|
+
end
|
52
|
+
|
53
|
+
def receive_loop
|
54
|
+
RECEIVE_LOOP
|
55
|
+
end
|
56
|
+
|
57
|
+
def send!(term)
|
58
|
+
port.send(term)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
module Kernel
|
64
|
+
def receive(input = nil, output = nil, &block)
|
65
|
+
input ||= IO.new(3)
|
66
|
+
output ||= IO.new(4)
|
67
|
+
Beambridge::Receiver.new(Beambridge::Port.new(input, output), nil, &block).run
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "Beambridge::StaticConditions" do
|
4
|
+
it "should satisfy on the same value" do
|
5
|
+
Beambridge::StaticCondition.new(:foo).satisfies?(:foo).should == true
|
6
|
+
Beambridge::StaticCondition.new([:foo]).satisfies?([:foo]).should == true
|
7
|
+
Beambridge::StaticCondition.new(3).satisfies?(3).should == true
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should not satisfy on different values" do
|
11
|
+
Beambridge::StaticCondition.new(:foo).satisfies?("foo").should == false
|
12
|
+
Beambridge::StaticCondition.new([:foo]).satisfies?(:foo).should == false
|
13
|
+
Beambridge::StaticCondition.new(Object.new).satisfies?(Object.new).should == false
|
14
|
+
Beambridge::StaticCondition.new(3).satisfies?(3.0).should == false
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should not produce any bindings" do
|
18
|
+
s = Beambridge::StaticCondition.new(:foo)
|
19
|
+
s.binding_for(:foo).should == nil
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "Beambridge::TypeConditions" do
|
24
|
+
it "should be satisfied when the arg has the same class" do
|
25
|
+
Beambridge::TypeCondition.new(Symbol).satisfies?(:foo).should == true
|
26
|
+
Beambridge::TypeCondition.new(Symbol).satisfies?(:bar).should == true
|
27
|
+
Beambridge::TypeCondition.new(String).satisfies?("foo").should == true
|
28
|
+
Beambridge::TypeCondition.new(String).satisfies?("bar").should == true
|
29
|
+
Beambridge::TypeCondition.new(Array).satisfies?([]).should == true
|
30
|
+
Beambridge::TypeCondition.new(Fixnum).satisfies?(3).should == true
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should be satisfied when the arg is of a descendent class" do
|
34
|
+
Beambridge::TypeCondition.new(Object).satisfies?(:foo).should == true
|
35
|
+
Beambridge::TypeCondition.new(Object).satisfies?("foo").should == true
|
36
|
+
Beambridge::TypeCondition.new(Object).satisfies?(3).should == true
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should not be satisfied when the arg is of a different class" do
|
40
|
+
Beambridge::TypeCondition.new(String).satisfies?(:foo).should == false
|
41
|
+
Beambridge::TypeCondition.new(Symbol).satisfies?("foo").should == false
|
42
|
+
Beambridge::TypeCondition.new(Fixnum).satisfies?(3.0).should == false
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should bind the arg with no transormations" do
|
46
|
+
s = Beambridge::TypeCondition.new(Symbol)
|
47
|
+
s.binding_for(:foo).should == :foo
|
48
|
+
s.binding_for(:bar).should == :bar
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "Beambridge::HashConditions" do
|
53
|
+
it "should satisfy an args of the form [[key, value], [key, value]]" do
|
54
|
+
Beambridge::HashCondition.new.satisfies?([[:foo, 3], [:bar, Object.new]]).should == true
|
55
|
+
Beambridge::HashCondition.new.satisfies?([[:foo, 3]]).should == true
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should satisfy on empty arrays" do
|
59
|
+
Beambridge::HashCondition.new.satisfies?([]).should == true
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should nat satisfy other args" do
|
63
|
+
Beambridge::HashCondition.new.satisfies?(:foo).should == false
|
64
|
+
Beambridge::HashCondition.new.satisfies?("foo").should == false
|
65
|
+
Beambridge::HashCondition.new.satisfies?(3.0).should == false
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should bind to a Hash" do
|
69
|
+
s = Beambridge::HashCondition.new()
|
70
|
+
s.binding_for([[:foo, 3], [:bar, [3,4,5]]]).should == {:foo => 3, :bar => [3,4,5] }
|
71
|
+
end
|
72
|
+
end
|
data/spec/decode_spec.rb
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "When unpacking from a binary stream" do
|
4
|
+
|
5
|
+
it "an erlang atom should decode to a ruby symbol" do
|
6
|
+
get("haha").should == :haha
|
7
|
+
end
|
8
|
+
|
9
|
+
it "an erlang number encoded as a small_int (< 255) should decode to a fixnum" do
|
10
|
+
get("0").should == 0
|
11
|
+
get("255").should == 255
|
12
|
+
end
|
13
|
+
|
14
|
+
it "an erlang number encoded as a int (signed 27-bit number) should decode to a fixnum" do
|
15
|
+
get("256").should == 256
|
16
|
+
get("#{(1 << 27) -1}").should == (1 << 27) -1
|
17
|
+
get("-1").should == -1
|
18
|
+
get("#{-(1 << 27)}").should == -(1 << 27)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "an erlang number encoded as a small bignum (1 byte length) should decode to fixnum if it can" do
|
22
|
+
get("#{(1 << 27)}").should == (1 << 27)
|
23
|
+
get("#{-(1 << 27) - 1}").should == -(1 << 27) - 1
|
24
|
+
get("#{(1 << word_length) - 1}").should == (1 << word_length) - 1
|
25
|
+
get("#{-(1 << word_length)}").should == -(1 << word_length)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "an erlang number encoded as a small bignum (1 byte length) should decode to bignum if it can't be a fixnum" do
|
29
|
+
get("#{(1 << word_length)}").should == (1 << word_length)
|
30
|
+
get("#{-(1 << word_length) - 1}").should == -(1 << word_length) - 1
|
31
|
+
get("#{(1 << (255 * 8)) - 1}").should == (1 << (255 * 8)) - 1
|
32
|
+
get("#{-((1 << (255 * 8)) - 1)}").should == -((1 << (255 * 8)) - 1)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "an erlang number encoded as a big bignum (4 byte length) should decode to bignum" do
|
36
|
+
get("#{(1 << (255 * 8)) }").should == (1 << (255 * 8))
|
37
|
+
get("#{-(1 << (255 * 8))}").should == -(1 << (255 * 8))
|
38
|
+
get("#{(1 << (512 * 8)) }").should == (1 << (512 * 8))
|
39
|
+
get("#{-(1 << (512 * 8))}").should == -(1 << (512 * 8))
|
40
|
+
end
|
41
|
+
|
42
|
+
it "an erlang float should decode to a Float" do
|
43
|
+
get("#{1.0}").should == 1.0
|
44
|
+
get("#{-1.0}").should == -1.0
|
45
|
+
get("#{123.456}").should == 123.456
|
46
|
+
get("#{123.456789012345}").should == 123.456789012345
|
47
|
+
end
|
48
|
+
|
49
|
+
it "an erlang reference should decode to a Reference object" do
|
50
|
+
ref = get("make_ref()")
|
51
|
+
ref.should be_an_instance_of Beambridge::NewReference
|
52
|
+
ref.node.should be_an_instance_of Symbol
|
53
|
+
end
|
54
|
+
|
55
|
+
it "an erlang pid should decode to a Pid object" do
|
56
|
+
pid = get("spawn(fun() -> 3 end)")
|
57
|
+
pid.should be_an_instance_of Beambridge::Pid
|
58
|
+
pid.node.should be_an_instance_of Symbol
|
59
|
+
end
|
60
|
+
|
61
|
+
it "an erlang tuple encoded as a small tuple (1-byte length) should decode to an array" do
|
62
|
+
ref = get("{3}")
|
63
|
+
ref.length.should == 1
|
64
|
+
ref.first.should == 3
|
65
|
+
|
66
|
+
ref = get("{3, a, make_ref()}")
|
67
|
+
ref.length.should == 3
|
68
|
+
ref[0].should == 3
|
69
|
+
ref[1].should == :a
|
70
|
+
ref[2].class.should == Beambridge::NewReference
|
71
|
+
|
72
|
+
tuple_meat = (['3'] * 255).join(', ')
|
73
|
+
ref = get("{#{tuple_meat}}")
|
74
|
+
ref.length.should == 255
|
75
|
+
ref.each{|r| r.should == 3}
|
76
|
+
end
|
77
|
+
|
78
|
+
it "an erlang tuple encoded as a large tuple (4-byte length) should decode to an array" do
|
79
|
+
tuple_meat = (['3'] * 256).join(', ')
|
80
|
+
ref = get("{#{tuple_meat}}")
|
81
|
+
ref.length.should == 256
|
82
|
+
ref.each{|r| r.should == 3}
|
83
|
+
|
84
|
+
tuple_meat = (['3'] * 512).join(', ')
|
85
|
+
ref = get("{#{tuple_meat}}")
|
86
|
+
ref.length.should == 512
|
87
|
+
ref.each{|r| r.should == 3}
|
88
|
+
end
|
89
|
+
|
90
|
+
it "an empty erlang list encoded as a nil should decode to an array" do
|
91
|
+
get("[]").class.should == Erl::List
|
92
|
+
get("[]").should == []
|
93
|
+
end
|
94
|
+
|
95
|
+
it "an erlang list encoded as a string should decode to an array of bytes (less than ideal, but consistent)" do
|
96
|
+
get("\"asdasd\"").class.should == Erl::List
|
97
|
+
get("\"asdasd\"").should == "asdasd".bytes.to_a
|
98
|
+
get("\"#{'a' * 65534}\"").should == "a".bytes.to_a * 65534
|
99
|
+
end
|
100
|
+
|
101
|
+
it "an erlang list encoded as a list should decode to an erl::list" do
|
102
|
+
get("[3,4,256]").class.should == Erl::List
|
103
|
+
get("[3,4,256]").should == [3,4,256]
|
104
|
+
get("\"#{'a' * 65535 }\"").should == [97] * 65535
|
105
|
+
get("[3,4, foo, {3,4,5,bar}, 256]").should == [3,4, :foo, [3,4,5,:bar], 256]
|
106
|
+
end
|
107
|
+
|
108
|
+
it "an erlang binary should decode to a string" do
|
109
|
+
get("<< 3,4,255 >>").should == "\003\004\377"
|
110
|
+
get("<< \"whatup\" >>").should == "whatup"
|
111
|
+
get("<< 99,0,99 >>").should == "c\000c"
|
112
|
+
end
|
113
|
+
|
114
|
+
it "the empty atom should decode to the empty symbol" do
|
115
|
+
empty_symbol = get("''")
|
116
|
+
empty_symbol.should be_an_instance_of Symbol
|
117
|
+
empty_symbol.to_s.should == ""
|
118
|
+
end
|
119
|
+
|
120
|
+
it "erlang atomic booleans should decode to ruby booleans" do
|
121
|
+
get("true").should == true
|
122
|
+
get("false").should == false
|
123
|
+
get("falsereio").should == :falsereio
|
124
|
+
get("t").should == :t
|
125
|
+
get("f").should == :f
|
126
|
+
end
|
127
|
+
|
128
|
+
it "massive binaries should not overflow the stack" do
|
129
|
+
bin = [131,109,0,128,0,0].pack('c*') + ('a' * (8 * 1024 * 1024))
|
130
|
+
Beambridge::Decoder.decode(bin).size.should eq(8 * 1024 * 1024)
|
131
|
+
end
|
132
|
+
|
133
|
+
it "a good thing should be awesome" do
|
134
|
+
get(%Q-[{options,{struct,[{test,<<"I'm chargin' mah lazer">>}]}},{passage,<<"Why doesn't this work?">>}]-).should ==
|
135
|
+
[[:options, [:struct, [[:test, "I'm chargin' mah lazer"]]]], [:passage, "Why doesn't this work?"]]
|
136
|
+
end
|
137
|
+
|
138
|
+
def get(str)
|
139
|
+
x = "term_to_binary(#{str.gsub(/"/, '\\\"')})"
|
140
|
+
bin = run_erl(x)
|
141
|
+
Beambridge::Decoder.decode(bin)
|
142
|
+
end
|
143
|
+
end
|
data/spec/encode_spec.rb
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require "spec_helper"
|
3
|
+
|
4
|
+
describe "When packing to a binary stream" do
|
5
|
+
|
6
|
+
let(:encoder) { Beambridge::Encoder.new(StringIO.new('', 'w')) }
|
7
|
+
|
8
|
+
it "A symbol should be encoded to an erlang atom" do
|
9
|
+
get{encoder.write_symbol :haha}.should == get_erl("haha")
|
10
|
+
write_any(:haha).should == get_erl_with_magic("haha")
|
11
|
+
end
|
12
|
+
|
13
|
+
it "A boolean should be encoded to an erlang atom" do
|
14
|
+
get{encoder.write_boolean true}.should == get_erl("true")
|
15
|
+
get{encoder.write_boolean false}.should == get_erl("false")
|
16
|
+
write_any(true).should == get_erl_with_magic("true")
|
17
|
+
write_any(false).should == get_erl_with_magic("false")
|
18
|
+
end
|
19
|
+
|
20
|
+
it "A number should be encoded as an erlang number would be" do
|
21
|
+
#SMALL_INTS
|
22
|
+
get{encoder.write_fixnum 0}.should == get_erl("0")
|
23
|
+
get{encoder.write_fixnum 255}.should == get_erl("255")
|
24
|
+
write_any(0).should == get_erl_with_magic("0")
|
25
|
+
write_any(255).should == get_erl_with_magic("255")
|
26
|
+
|
27
|
+
#INTS
|
28
|
+
get{encoder.write_fixnum 256}.should == get_erl("256")
|
29
|
+
get{encoder.write_fixnum((1 << 27) - 1)}.should == get_erl("#{(1 << 27) - 1}")
|
30
|
+
get{encoder.write_fixnum(-1)}.should == get_erl("-1")
|
31
|
+
get{encoder.write_fixnum(-(1 << 27))}.should == get_erl("#{-(1 << 27)}")
|
32
|
+
write_any(256).should == get_erl_with_magic("256")
|
33
|
+
write_any((1 << 27) - 1).should == get_erl_with_magic("#{(1 << 27) - 1}")
|
34
|
+
write_any(-1).should == get_erl_with_magic("-1")
|
35
|
+
write_any(-(1 << 27)).should == get_erl_with_magic("#{-(1 << 27)}")
|
36
|
+
|
37
|
+
# #SMALL_BIGNUMS
|
38
|
+
get{encoder.write_fixnum(10_000_000_000_000_000_000)}.should == get_erl("10000000000000000000")
|
39
|
+
# get{encoder.write_fixnum(1254976067)}.should == get_erl("1254976067")
|
40
|
+
# get{encoder.write_fixnum(-1254976067)}.should == get_erl("-1254976067")
|
41
|
+
# get{encoder.write_fixnum((1 << word_length))}.should == get_erl("#{(1 << word_length)}")
|
42
|
+
# get{encoder.write_fixnum(-(1 << word_length) - 1)}.should == get_erl("#{-(1 << word_length) - 1}")
|
43
|
+
# get{encoder.write_fixnum((1 << (255 * 8)) - 1)}.should == get_erl("#{(1 << (255 * 8)) - 1}")
|
44
|
+
# get{encoder.write_fixnum(-((1 << (255 * 8)) - 1))}.should == get_erl("#{-((1 << (255 * 8)) - 1)}")
|
45
|
+
#
|
46
|
+
# write_any((1 << word_length)).should == get_erl_with_magic("#{(1 << word_length)}")
|
47
|
+
# write_any(-(1 << word_length) - 1).should == get_erl_with_magic("#{-(1 << word_length) - 1}")
|
48
|
+
# write_any((1 << (255 * 8)) - 1).should == get_erl_with_magic("#{(1 << (255 * 8)) - 1}")
|
49
|
+
# write_any(-((1 << (255 * 8)) - 1)).should == get_erl_with_magic("#{-((1 << (255 * 8)) - 1)}")
|
50
|
+
#
|
51
|
+
# #LARGE_BIGNUMS
|
52
|
+
x = 1254976067 ** 256
|
53
|
+
get{encoder.write_fixnum(x)}.should == get_erl("#{x}")
|
54
|
+
get{encoder.write_fixnum(-x)}.should == get_erl("-#{x}")
|
55
|
+
# get{encoder.write_fixnum((1 << (255 * 8)))}.should == get_erl("#{(1 << (255 * 8))}")
|
56
|
+
# get{encoder.write_fixnum(-(1 << (255 * 8))}.should == get_erl("#{-(1 << (255 * 8)}")
|
57
|
+
# get{encoder.write_fixnum((1 << (512 * 8))}.should == get_erl("#{(1 << (512 * 8))}")
|
58
|
+
# get{encoder.write_fixnum(-((1 << (512 * 8)) - 1))}.should == get_erl("#{-((1 << (512 * 8)) - 1)}")
|
59
|
+
#
|
60
|
+
# write_any((1 << (255 * 8))).should == get_erl_with_magic("#{(1 << (255 * 8))}")
|
61
|
+
# write_any(-(1 << (255 * 8)).should == get_erl_with_magic("#{-(1 << (255 * 8)}")
|
62
|
+
# write_any((1 << (512 * 8))).should == get_erl_with_magic("#{(1 << (512 * 8))}")
|
63
|
+
# write_any(-((1 << (512 * 8)) - 1)).should == get_erl_with_magic("#{-((1 << (512 * 8)) - 1)}")
|
64
|
+
end
|
65
|
+
|
66
|
+
# it "A float (that is within the truncated precision of ruby compared to erlang) should encode as erlang does" do
|
67
|
+
# get{encoder.write_float 1.0}.should == get_erl("1.0")
|
68
|
+
# get{encoder.write_float -1.0}.should == get_erl("-1.0")
|
69
|
+
# get{encoder.write_float 123.456}.should == get_erl("123.456")
|
70
|
+
# get{encoder.write_float 123.456789012345}.should == get_erl("123.456789012345")
|
71
|
+
# end
|
72
|
+
|
73
|
+
it "An Erlectiricity::NewReference should encode back to its original form" do
|
74
|
+
ref_bin = run_erl("term_to_binary(make_ref())")
|
75
|
+
ruby_ref = Beambridge::Decoder.decode(ref_bin)
|
76
|
+
|
77
|
+
get{encoder.write_new_reference(ruby_ref)}.should == ref_bin[1..-1].bytes.to_a
|
78
|
+
write_any(ruby_ref).should == ref_bin.bytes.to_a
|
79
|
+
end
|
80
|
+
|
81
|
+
it "An Erlectiricity::Pid should encode back to its original form" do
|
82
|
+
pid_bin = run_erl("term_to_binary(spawn(fun() -> 3 end))")
|
83
|
+
ruby_pid = Beambridge::Decoder.decode(pid_bin)
|
84
|
+
|
85
|
+
get{encoder.write_pid(ruby_pid)}.should == pid_bin[1..-1].bytes.to_a
|
86
|
+
write_any(ruby_pid).should == pid_bin.bytes.to_a
|
87
|
+
end
|
88
|
+
|
89
|
+
it "An array written with write_tuple should encode as erlang would a tuple" do
|
90
|
+
get{encoder.write_tuple [1,2,3]}.should == get_erl("{1,2,3}")
|
91
|
+
get{encoder.write_tuple [3] * 255}.should == get_erl("{#{([3] * 255).join(',')}}")
|
92
|
+
get{encoder.write_tuple [3] * 256}.should == get_erl("{#{([3] * 256).join(',')}}")
|
93
|
+
get{encoder.write_tuple [3] * 512}.should == get_erl("{#{([3] * 512).join(',')}}")
|
94
|
+
end
|
95
|
+
|
96
|
+
it "An array should by default be written as a tuple" do
|
97
|
+
write_any([1,2,3]).should == get_erl_with_magic("{1,2,3}")
|
98
|
+
write_any([3] * 255).should == get_erl_with_magic("{#{([3] * 255).join(',')}}")
|
99
|
+
write_any([3] * 256).should == get_erl_with_magic("{#{([3] * 256).join(',')}}")
|
100
|
+
write_any([3] * 512).should == get_erl_with_magic("{#{([3] * 512).join(',')}}")
|
101
|
+
end
|
102
|
+
|
103
|
+
it "An Beambridge::List should by default be written as a list" do
|
104
|
+
write_any(Erl::List.new([1,2,300])).should == get_erl_with_magic("[1,2,300]")
|
105
|
+
write_any(Erl::List.new([300] * 255)).should == get_erl_with_magic("[#{([300] * 255).join(',')}]")
|
106
|
+
write_any(Erl::List.new([300] * 256)).should == get_erl_with_magic("[#{([300] * 256).join(',')}]")
|
107
|
+
write_any(Erl::List.new([300] * 512)).should == get_erl_with_magic("[#{([300] * 512).join(',')}]")
|
108
|
+
end
|
109
|
+
|
110
|
+
it "An array written with write_list should encode as erlang would a list" do
|
111
|
+
get{encoder.write_list [1,2,300]}.should == get_erl("[1,2,300]")
|
112
|
+
get{encoder.write_list [300] * 255}.should == get_erl("[#{([300] * 255).join(',')}]")
|
113
|
+
get{encoder.write_list [300] * 256}.should == get_erl("[#{([300] * 256).join(',')}]")
|
114
|
+
get{encoder.write_list [300] * 256}.should == get_erl("[#{([300] * 256).join(',')}]")
|
115
|
+
end
|
116
|
+
|
117
|
+
it "a string should be encoded as a erlang binary would be" do
|
118
|
+
get{encoder.write_binary "hey who"}.should == get_erl("<< \"hey who\" >>")
|
119
|
+
get{encoder.write_binary ""}.should == get_erl("<< \"\" >>")
|
120
|
+
get{encoder.write_binary "c\000c"}.should == get_erl("<< 99,0,99 >>")
|
121
|
+
|
122
|
+
write_any("hey who").should == get_erl_with_magic("<< \"hey who\" >>")
|
123
|
+
write_any("").should == get_erl_with_magic("<< \"\" >>")
|
124
|
+
end
|
125
|
+
|
126
|
+
it "encodes a string with unicode characters with the correct length" do
|
127
|
+
write_any([:hi, "😸", :bye]).should == [
|
128
|
+
131, 104, 3, 100, 0, 2, 104, 105, 109, 0, 0, 0, 4,
|
129
|
+
240, 159, 152, 184, 100, 0, 3, 98, 121, 101
|
130
|
+
]
|
131
|
+
end
|
132
|
+
|
133
|
+
def get
|
134
|
+
encoder.out = StringIO.new('', 'w')
|
135
|
+
yield
|
136
|
+
encoder.out.string.bytes.to_a
|
137
|
+
end
|
138
|
+
|
139
|
+
def write_any(term)
|
140
|
+
encoder.out = StringIO.new('', 'w')
|
141
|
+
encoder.write_any term
|
142
|
+
encoder.out.string.bytes.to_a
|
143
|
+
end
|
144
|
+
|
145
|
+
def get_erl(str)
|
146
|
+
get_erl_with_magic(str)[1..-1] #[1..-1] to chop off the magic number
|
147
|
+
end
|
148
|
+
|
149
|
+
def get_erl_with_magic(str)
|
150
|
+
run_erl("term_to_binary(#{str.gsub(/"/, '\\\"')})").bytes.to_a
|
151
|
+
end
|
152
|
+
end
|