erlectricity-funbox 1.1.2
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.
- data/.gitignore +24 -0
- data/History.txt +35 -0
- data/LICENSE +20 -0
- data/README.md +130 -0
- data/Rakefile +74 -0
- data/VERSION.yml +4 -0
- data/benchmarks/bench.rb +21 -0
- data/erlectricity.gemspec +105 -0
- data/examples/echo/README.md +12 -0
- data/examples/echo/echo.erl +13 -0
- data/examples/echo/echo.rb +11 -0
- data/examples/gruff/gruff.erl +61 -0
- data/examples/gruff/gruff_provider.rb +31 -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 +111 -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 +28 -0
- data/ext/decoder.c +398 -0
- data/ext/extconf.rb +11 -0
- data/lib/erlectricity.rb +33 -0
- data/lib/erlectricity/condition.rb +66 -0
- data/lib/erlectricity/conditions/boolean.rb +11 -0
- data/lib/erlectricity/conditions/hash.rb +13 -0
- data/lib/erlectricity/conditions/static.rb +34 -0
- data/lib/erlectricity/conditions/type.rb +17 -0
- data/lib/erlectricity/constants.rb +36 -0
- data/lib/erlectricity/decoder.rb +212 -0
- data/lib/erlectricity/encoder.rb +164 -0
- data/lib/erlectricity/errors/decode_error.rb +3 -0
- data/lib/erlectricity/errors/encode_error.rb +3 -0
- data/lib/erlectricity/errors/erlectricity_error.rb +3 -0
- data/lib/erlectricity/matcher.rb +21 -0
- data/lib/erlectricity/port.rb +46 -0
- data/lib/erlectricity/receiver.rb +69 -0
- data/lib/erlectricity/types/function.rb +3 -0
- data/lib/erlectricity/types/list.rb +3 -0
- data/lib/erlectricity/types/new_function.rb +3 -0
- data/lib/erlectricity/types/new_reference.rb +3 -0
- data/lib/erlectricity/types/pid.rb +3 -0
- data/lib/erlectricity/types/reference.rb +3 -0
- data/lib/erlectricity/version.rb +9 -0
- data/test/condition_spec.rb +72 -0
- data/test/decode_spec.rb +145 -0
- data/test/encode_spec.rb +146 -0
- data/test/matcher_spec.rb +81 -0
- data/test/port_spec.rb +34 -0
- data/test/receiver_spec.rb +103 -0
- data/test/spec_suite.rb +2 -0
- data/test/test_helper.rb +46 -0
- metadata +116 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
module Erlectricity
|
|
2
|
+
class Encoder
|
|
3
|
+
include Erlectricity::External::Types
|
|
4
|
+
|
|
5
|
+
attr_accessor :out
|
|
6
|
+
|
|
7
|
+
def initialize(out)
|
|
8
|
+
self.out = out
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.encode(data)
|
|
12
|
+
io = StringIO.new
|
|
13
|
+
self.new(io).write_any(data)
|
|
14
|
+
io.string
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def write_any obj
|
|
18
|
+
write_1 Erlectricity::External::VERSION
|
|
19
|
+
write_any_raw obj
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def write_any_raw obj
|
|
23
|
+
case obj
|
|
24
|
+
when Symbol then write_symbol(obj)
|
|
25
|
+
when Fixnum, Bignum then write_fixnum(obj)
|
|
26
|
+
when Float then write_float(obj)
|
|
27
|
+
when Erlectricity::NewReference then write_new_reference(obj)
|
|
28
|
+
when Erlectricity::Pid then write_pid(obj)
|
|
29
|
+
when Erlectricity::List then write_list(obj)
|
|
30
|
+
when Array then write_tuple(obj)
|
|
31
|
+
when String then write_binary(obj)
|
|
32
|
+
when Time then write_any_raw(obj.to_i.divmod(1000000) + [obj.usec])
|
|
33
|
+
when TrueClass, FalseClass then write_boolean(obj)
|
|
34
|
+
else
|
|
35
|
+
fail(obj)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def write_1(byte)
|
|
40
|
+
out.write([byte].pack("C"))
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def write_2(short)
|
|
44
|
+
out.write([short].pack("n"))
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def write_4(long)
|
|
48
|
+
out.write([long].pack("N"))
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def write_string(string)
|
|
52
|
+
out.write(string)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def write_boolean(bool)
|
|
56
|
+
write_symbol(bool.to_s.to_sym)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def write_symbol(sym)
|
|
60
|
+
fail(sym) unless sym.is_a?(Symbol)
|
|
61
|
+
data = sym.to_s
|
|
62
|
+
write_1 ATOM
|
|
63
|
+
write_2 data.length
|
|
64
|
+
write_string data
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def write_fixnum(num)
|
|
68
|
+
if num >= 0 && num < 256
|
|
69
|
+
write_1 SMALL_INT
|
|
70
|
+
write_1 num
|
|
71
|
+
elsif num <= Erlectricity::External::MAX_INT && num >= Erlectricity::External::MIN_INT
|
|
72
|
+
write_1 INT
|
|
73
|
+
write_4 num
|
|
74
|
+
else
|
|
75
|
+
write_bignum num
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def write_float(float)
|
|
80
|
+
write_1 FLOAT
|
|
81
|
+
write_string format("%15.15e", float).ljust(31, "\000")
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def write_bignum(num)
|
|
85
|
+
if num.is_a?(Bignum)
|
|
86
|
+
n = num.size
|
|
87
|
+
else
|
|
88
|
+
n = (num.to_s(2).size / 8.0).ceil
|
|
89
|
+
end
|
|
90
|
+
if n <= 256
|
|
91
|
+
write_1 SMALL_BIGNUM
|
|
92
|
+
write_1 n
|
|
93
|
+
write_bignum_guts(num)
|
|
94
|
+
else
|
|
95
|
+
write_1 LARGE_BIGNUM
|
|
96
|
+
write_4 n
|
|
97
|
+
write_bignum_guts(num)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def write_bignum_guts(num)
|
|
102
|
+
write_1 (num >= 0 ? 0 : 1)
|
|
103
|
+
num = num.abs
|
|
104
|
+
while num != 0
|
|
105
|
+
rem = num % 256
|
|
106
|
+
write_1 rem
|
|
107
|
+
num = num >> 8
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def write_new_reference(ref)
|
|
112
|
+
fail(ref) unless ref.is_a?(Erlectricity::NewReference)
|
|
113
|
+
write_1 NEW_REF
|
|
114
|
+
write_2 ref.id.length
|
|
115
|
+
write_symbol(ref.node)
|
|
116
|
+
write_1 ref.creation
|
|
117
|
+
write_string ref.id.pack('N' * ref.id.length)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def write_pid(pid)
|
|
121
|
+
fail(pid) unless pid.is_a? Erlectricity::Pid
|
|
122
|
+
write_1 PID
|
|
123
|
+
write_symbol(pid.node)
|
|
124
|
+
write_4 pid.id
|
|
125
|
+
write_4 pid.serial
|
|
126
|
+
write_1 pid.creation
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def write_tuple(data)
|
|
130
|
+
fail(data) unless data.is_a? Array
|
|
131
|
+
|
|
132
|
+
if data.length < 256
|
|
133
|
+
write_1 SMALL_TUPLE
|
|
134
|
+
write_1 data.length
|
|
135
|
+
else
|
|
136
|
+
write_1 LARGE_TUPLE
|
|
137
|
+
write_4 data.length
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
data.each { |e| write_any_raw e }
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def write_list(data)
|
|
144
|
+
fail(data) unless data.is_a? Array
|
|
145
|
+
write_1 NIL and return if data.empty?
|
|
146
|
+
write_1 LIST
|
|
147
|
+
write_4 data.length
|
|
148
|
+
data.each{|e| write_any_raw e }
|
|
149
|
+
write_1 NIL
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def write_binary(data)
|
|
153
|
+
write_1 BIN
|
|
154
|
+
write_4 data.respond_to?(:bytesize) ? data.bytesize : data.length
|
|
155
|
+
write_string data
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
private
|
|
159
|
+
|
|
160
|
+
def fail(obj)
|
|
161
|
+
raise EncodeError, "Cannot encode to erlang external format: #{obj.inspect}"
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Erlectricity
|
|
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,46 @@
|
|
|
1
|
+
module Erlectricity
|
|
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
|
+
@encoder = Erlectricity::Encoder.new(nil)
|
|
15
|
+
@skipped = []
|
|
16
|
+
@queue = []
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def receive
|
|
20
|
+
queue.empty? ? read_from_input : queue.shift
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def send(term)
|
|
24
|
+
@encoder.out = StringIO.new('', 'w')
|
|
25
|
+
@encoder.write_any(term)
|
|
26
|
+
data = @encoder.out.string
|
|
27
|
+
output.write([data.length].pack("N"))
|
|
28
|
+
output.write(data)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def restore_skipped
|
|
32
|
+
@queue = self.skipped + self.queue
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def read_from_input
|
|
38
|
+
raw = input.read(4)
|
|
39
|
+
return nil unless raw
|
|
40
|
+
|
|
41
|
+
packet_length = raw.unpack('N').first
|
|
42
|
+
data = input.read(packet_length)
|
|
43
|
+
Erlectricity::Decoder.decode(data)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
module Erlectricity
|
|
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
|
+
Erlectricity::Receiver.new(Erlectricity::Port.new(input, output), nil, &block).run
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
|
2
|
+
|
|
3
|
+
context "Erlectricity::StaticConditions" do
|
|
4
|
+
specify "should satisfy on the same value" do
|
|
5
|
+
Erlectricity::StaticCondition.new(:foo).satisfies?(:foo).should == true
|
|
6
|
+
Erlectricity::StaticCondition.new([:foo]).satisfies?([:foo]).should == true
|
|
7
|
+
Erlectricity::StaticCondition.new(3).satisfies?(3).should == true
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
specify "should not satisfy on different values" do
|
|
11
|
+
Erlectricity::StaticCondition.new(:foo).satisfies?("foo").should == false
|
|
12
|
+
Erlectricity::StaticCondition.new([:foo]).satisfies?(:foo).should == false
|
|
13
|
+
Erlectricity::StaticCondition.new(Object.new).satisfies?(Object.new).should == false
|
|
14
|
+
Erlectricity::StaticCondition.new(3).satisfies?(3.0).should == false
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
specify "should not produce any bindings" do
|
|
18
|
+
s = Erlectricity::StaticCondition.new(:foo)
|
|
19
|
+
s.binding_for(:foo).should == nil
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
context "Erlectricity::TypeConditions" do
|
|
24
|
+
specify "should be satisfied when the arg has the same class" do
|
|
25
|
+
Erlectricity::TypeCondition.new(Symbol).satisfies?(:foo).should == true
|
|
26
|
+
Erlectricity::TypeCondition.new(Symbol).satisfies?(:bar).should == true
|
|
27
|
+
Erlectricity::TypeCondition.new(String).satisfies?("foo").should == true
|
|
28
|
+
Erlectricity::TypeCondition.new(String).satisfies?("bar").should == true
|
|
29
|
+
Erlectricity::TypeCondition.new(Array).satisfies?([]).should == true
|
|
30
|
+
Erlectricity::TypeCondition.new(Fixnum).satisfies?(3).should == true
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
specify "should be satisfied when the arg is of a descendent class" do
|
|
34
|
+
Erlectricity::TypeCondition.new(Object).satisfies?(:foo).should == true
|
|
35
|
+
Erlectricity::TypeCondition.new(Object).satisfies?("foo").should == true
|
|
36
|
+
Erlectricity::TypeCondition.new(Object).satisfies?(3).should == true
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
specify "should not be satisfied when the arg is of a different class" do
|
|
40
|
+
Erlectricity::TypeCondition.new(String).satisfies?(:foo).should == false
|
|
41
|
+
Erlectricity::TypeCondition.new(Symbol).satisfies?("foo").should == false
|
|
42
|
+
Erlectricity::TypeCondition.new(Fixnum).satisfies?(3.0).should == false
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
specify "should bind the arg with no transormations" do
|
|
46
|
+
s = Erlectricity::TypeCondition.new(Symbol)
|
|
47
|
+
s.binding_for(:foo).should == :foo
|
|
48
|
+
s.binding_for(:bar).should == :bar
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
context "Erlectricity::HashConditions" do
|
|
53
|
+
specify "should satisfy an args of the form [[key, value], [key, value]]" do
|
|
54
|
+
Erlectricity::HashCondition.new.satisfies?([[:foo, 3], [:bar, Object.new]]).should == true
|
|
55
|
+
Erlectricity::HashCondition.new.satisfies?([[:foo, 3]]).should == true
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
specify "should satisfy on empty arrays" do
|
|
59
|
+
Erlectricity::HashCondition.new.satisfies?([]).should == true
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
specify "should nat satisfy other args" do
|
|
63
|
+
Erlectricity::HashCondition.new.satisfies?(:foo).should == false
|
|
64
|
+
Erlectricity::HashCondition.new.satisfies?("foo").should == false
|
|
65
|
+
Erlectricity::HashCondition.new.satisfies?(3.0).should == false
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
specify "should bind to a Hash" do
|
|
69
|
+
s = Erlectricity::HashCondition.new()
|
|
70
|
+
s.binding_for([[:foo, 3], [:bar, [3,4,5]]]).should == {:foo => 3, :bar => [3,4,5] }
|
|
71
|
+
end
|
|
72
|
+
end
|
data/test/decode_spec.rb
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
|
2
|
+
|
|
3
|
+
context "When unpacking from a binary stream" do
|
|
4
|
+
setup do
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
specify "an erlang atom should decode to a ruby symbol" do
|
|
8
|
+
get("haha").should == :haha
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
specify "an erlang number encoded as a small_int (< 255) should decode to a fixnum" do
|
|
12
|
+
get("0").should == 0
|
|
13
|
+
get("255").should == 255
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
specify "an erlang number encoded as a int (signed 27-bit number) should decode to a fixnum" do
|
|
17
|
+
get("256").should == 256
|
|
18
|
+
get("#{(1 << 27) -1}").should == (1 << 27) -1
|
|
19
|
+
get("-1").should == -1
|
|
20
|
+
get("#{-(1 << 27)}").should == -(1 << 27)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
specify "an erlang number encoded as a small bignum (1 byte length) should decode to fixnum if it can" do
|
|
24
|
+
get("#{(1 << 27)}").should == (1 << 27)
|
|
25
|
+
get("#{-(1 << 27) - 1}").should == -(1 << 27) - 1
|
|
26
|
+
get("#{(1 << word_length) - 1}").should == (1 << word_length) - 1
|
|
27
|
+
get("#{-(1 << word_length)}").should == -(1 << word_length)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
specify "an erlang number encoded as a small bignum (1 byte length) should decode to bignum if it can't be a fixnum" do
|
|
31
|
+
get("#{(1 << word_length)}").should == (1 << word_length)
|
|
32
|
+
get("#{-(1 << word_length) - 1}").should == -(1 << word_length) - 1
|
|
33
|
+
get("#{(1 << (255 * 8)) - 1}").should == (1 << (255 * 8)) - 1
|
|
34
|
+
get("#{-((1 << (255 * 8)) - 1)}").should == -((1 << (255 * 8)) - 1)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
specify "an erlang number encoded as a big bignum (4 byte length) should decode to bignum" do
|
|
38
|
+
get("#{(1 << (255 * 8)) }").should == (1 << (255 * 8))
|
|
39
|
+
get("#{-(1 << (255 * 8))}").should == -(1 << (255 * 8))
|
|
40
|
+
get("#{(1 << (512 * 8)) }").should == (1 << (512 * 8))
|
|
41
|
+
get("#{-(1 << (512 * 8))}").should == -(1 << (512 * 8))
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
specify "an erlang float should decode to a Float" do
|
|
45
|
+
get("#{1.0}").should == 1.0
|
|
46
|
+
get("#{-1.0}").should == -1.0
|
|
47
|
+
get("#{123.456}").should == 123.456
|
|
48
|
+
get("#{123.456789012345}").should == 123.456789012345
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
specify "an erlang reference should decode to a Reference object" do
|
|
52
|
+
ref = get("make_ref()")
|
|
53
|
+
ref.should.be.instance_of Erlectricity::NewReference
|
|
54
|
+
ref.node.should.be.instance_of Symbol
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
specify "an erlang pid should decode to a Pid object" do
|
|
58
|
+
pid = get("spawn(fun() -> 3 end)")
|
|
59
|
+
pid.should.be.instance_of Erlectricity::Pid
|
|
60
|
+
pid.node.should.be.instance_of Symbol
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
specify "an erlang tuple encoded as a small tuple (1-byte length) should decode to an array" do
|
|
64
|
+
ref = get("{3}")
|
|
65
|
+
ref.length.should == 1
|
|
66
|
+
ref.first.should == 3
|
|
67
|
+
|
|
68
|
+
ref = get("{3, a, make_ref()}")
|
|
69
|
+
ref.length.should == 3
|
|
70
|
+
ref[0].should == 3
|
|
71
|
+
ref[1].should == :a
|
|
72
|
+
ref[2].class.should == Erlectricity::NewReference
|
|
73
|
+
|
|
74
|
+
tuple_meat = (['3'] * 255).join(', ')
|
|
75
|
+
ref = get("{#{tuple_meat}}")
|
|
76
|
+
ref.length.should == 255
|
|
77
|
+
ref.each{|r| r.should == 3}
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
specify "an erlang tuple encoded as a large tuple (4-byte length) should decode to an array" do
|
|
81
|
+
tuple_meat = (['3'] * 256).join(', ')
|
|
82
|
+
ref = get("{#{tuple_meat}}")
|
|
83
|
+
ref.length.should == 256
|
|
84
|
+
ref.each{|r| r.should == 3}
|
|
85
|
+
|
|
86
|
+
tuple_meat = (['3'] * 512).join(', ')
|
|
87
|
+
ref = get("{#{tuple_meat}}")
|
|
88
|
+
ref.length.should == 512
|
|
89
|
+
ref.each{|r| r.should == 3}
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
specify "an empty erlang list encoded as a nil should decode to an array" do
|
|
93
|
+
get("[]").class.should == Erl::List
|
|
94
|
+
get("[]").should == []
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
specify "an erlang list encoded as a string should decode to an array of bytes (less than ideal, but consistent)" do
|
|
98
|
+
get("\"asdasd\"").class.should == Erl::List
|
|
99
|
+
get("\"asdasd\"").should == "asdasd".split('').map{|c| c[0]}
|
|
100
|
+
get("\"#{'a' * 65534}\"").should == ['a'[0]] * 65534
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
specify "an erlang list encoded as a list should decode to an erl::list" do
|
|
104
|
+
get("[3,4,256]").class.should == Erl::List
|
|
105
|
+
get("[3,4,256]").should == [3,4,256]
|
|
106
|
+
get("\"#{'a' * 65535 }\"").should == [97] * 65535
|
|
107
|
+
get("[3,4, foo, {3,4,5,bar}, 256]").should == [3,4, :foo, [3,4,5,:bar], 256]
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
specify "an erlang binary should decode to a string" do
|
|
111
|
+
get("<< 3,4,255 >>").should == "\003\004\377"
|
|
112
|
+
get("<< \"whatup\" >>").should == "whatup"
|
|
113
|
+
get("<< 99,0,99 >>").should == "c\000c"
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
specify "the empty atom should decode to the empty symbol" do
|
|
117
|
+
empty_symbol = get("''")
|
|
118
|
+
empty_symbol.should.be.instance_of Symbol
|
|
119
|
+
empty_symbol.to_s.should == ""
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
specify "erlang atomic booleans should decode to ruby booleans" do
|
|
123
|
+
get("true").should == true
|
|
124
|
+
get("false").should == false
|
|
125
|
+
get("falsereio").should == :falsereio
|
|
126
|
+
get("t").should == :t
|
|
127
|
+
get("f").should == :f
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
specify "massive binaries should not overflow the stack" do
|
|
131
|
+
bin = [131,109,0,128,0,0].pack('c*') + ('a' * (8 * 1024 * 1024))
|
|
132
|
+
assert_equal (8 * 1024 * 1024), Erlectricity::Decoder.decode(bin).size
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
specify "a good thing should be awesome" do
|
|
136
|
+
get(%Q-[{options,{struct,[{test,<<"I'm chargin' mah lazer">>}]}},{passage,<<"Why doesn't this work?">>}]-).should ==
|
|
137
|
+
[[:options, [:struct, [[:test, "I'm chargin' mah lazer"]]]], [:passage, "Why doesn't this work?"]]
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def get(str)
|
|
141
|
+
x = "term_to_binary(#{str.gsub(/"/, '\\\"')})"
|
|
142
|
+
bin = run_erl(x)
|
|
143
|
+
Erlectricity::Decoder.decode(bin)
|
|
144
|
+
end
|
|
145
|
+
end
|