beambridge 0.9.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.
- 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
|