mojombo-erlectricity 0.2.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/History.txt +14 -1
  2. data/LICENSE +20 -0
  3. data/README.md +130 -0
  4. data/Rakefile +63 -60
  5. data/VERSION.yml +4 -0
  6. data/examples/echo/README.md +12 -0
  7. data/examples/echo/echo.erl +13 -0
  8. data/examples/echo/echo.rb +11 -0
  9. data/examples/gruff/gruff.erl +17 -18
  10. data/examples/gruff/gruff_provider.rb +12 -19
  11. data/examples/gruff/{gruff_run.erl → gruff_run.sh} +5 -3
  12. data/examples/gruff/{stat_run.erl → stat_run.sh} +5 -3
  13. data/examples/gruff/stat_writer.erl +6 -6
  14. data/examples/simple/README.md +5 -0
  15. data/examples/simple/rerl.rb +111 -0
  16. data/examples/simple/rerl.sh +37 -0
  17. data/examples/tinderl/README.md +14 -0
  18. data/examples/tinderl/tinderl.erl +19 -21
  19. data/examples/tinderl/tinderl.rb +11 -10
  20. data/ext/decoder.c +67 -60
  21. data/lib/erlectricity/condition.rb +35 -20
  22. data/lib/erlectricity/conditions/boolean.rb +11 -0
  23. data/lib/erlectricity/conditions/hash.rb +9 -10
  24. data/lib/erlectricity/conditions/static.rb +31 -10
  25. data/lib/erlectricity/conditions/type.rb +14 -14
  26. data/lib/erlectricity/constants.rb +3 -4
  27. data/lib/erlectricity/decoder.rb +205 -199
  28. data/lib/erlectricity/encoder.rb +49 -35
  29. data/lib/erlectricity/errors/decode_error.rb +1 -1
  30. data/lib/erlectricity/errors/encode_error.rb +1 -1
  31. data/lib/erlectricity/errors/erlectricity_error.rb +1 -1
  32. data/lib/erlectricity/matcher.rb +15 -32
  33. data/lib/erlectricity/port.rb +11 -11
  34. data/lib/erlectricity/receiver.rb +54 -64
  35. data/lib/erlectricity/types/list.rb +3 -1
  36. data/lib/erlectricity.rb +4 -7
  37. data/test/condition_spec.rb +8 -9
  38. data/test/decode_spec.rb +27 -28
  39. data/test/encode_spec.rb +31 -24
  40. data/test/matcher_spec.rb +24 -12
  41. data/test/port_spec.rb +3 -4
  42. data/test/receiver_spec.rb +18 -20
  43. data/test/test_helper.rb +9 -5
  44. metadata +36 -29
  45. data/CONTRIBUTORS +0 -2
  46. data/Manifest.txt +0 -45
  47. data/README.txt +0 -43
  48. data/setup.rb +0 -1585
  49. data/test/test_erlectricity.rb +0 -2
@@ -11,7 +11,7 @@ module Erlectricity
11
11
 
12
12
  ATOM = 100
13
13
  REF = 101 #old style reference
14
- NEW_REF = 114
14
+ NEW_REF = 114
15
15
  PORT = 102 #not supported accross node boundaries
16
16
  PID = 103
17
17
 
@@ -22,16 +22,15 @@ module Erlectricity
22
22
  STRING = 107
23
23
  LIST = 108
24
24
  BIN = 109
25
-
25
+
26
26
  FUN = 117
27
27
  NEW_FUN = 112
28
28
  end
29
29
 
30
30
  VERSION = 131
31
-
31
+
32
32
  MAX_INT = (1 << 27) -1
33
33
  MIN_INT = -(1 << 27)
34
34
  MAX_ATOM = 255
35
35
  end
36
-
37
36
  end
@@ -1,204 +1,210 @@
1
1
  module Erlectricity
2
- class Decoder
3
- attr_accessor :in
4
- include Erlectricity::External::Types
5
-
6
- def self.read_any_from(string)
7
- new(StringIO.new(string)).read_any
8
- end
9
-
10
- def initialize(ins)
11
- @in = ins
12
- @peeked = ""
13
- end
14
-
15
- def read_any
16
- fail("Bad Magic") unless read_1 == Erlectricity::External::VERSION
17
- read_any_raw
18
- end
19
-
20
- def read_any_raw
21
- case peek_1
22
- when ATOM then read_atom
23
- when SMALL_INT then read_small_int
24
- when INT then read_int
25
- when SMALL_BIGNUM then read_small_bignum
26
- when LARGE_BIGNUM then read_large_bignum
27
- when FLOAT then read_float
28
- when NEW_REF then read_new_reference
29
- when PID then read_pid
30
- when SMALL_TUPLE then read_small_tuple
31
- when LARGE_TUPLE then read_large_tuple
32
- when NIL then read_nil
33
- when STRING then read_erl_string
34
- when LIST then read_list
35
- when BIN then read_bin
36
- else
37
- fail("Unknown term tag: #{peek_1}")
2
+ class Decoder
3
+ attr_accessor :in
4
+ include Erlectricity::External::Types
5
+
6
+ def self.decode(string)
7
+ new(StringIO.new(string)).read_any
38
8
  end
39
- end
40
-
41
- def read(length)
42
- if length < @peeked.length
43
- result = @peeked[0...length]
44
- @peeked = @peeked[length..-1]
45
- length = 0
46
- else
47
- result = @peeked
48
- @peeked = ''
49
- length -= result.length
50
- end
51
-
52
- if length > 0
53
- result << @in.read(length)
54
- end
55
- result
56
- end
57
-
58
- def peek(length)
59
- if length <= @peeked.length
60
- @peeked[0...length]
61
- else
62
- read_bytes = @in.read(length - @peeked.length)
63
- @peeked << read_bytes if read_bytes
64
- @peeked
9
+
10
+ def initialize(ins)
11
+ @in = ins
12
+ @peeked = ""
13
+ end
14
+
15
+ def read_any
16
+ fail("Bad Magic") unless read_1 == Erlectricity::External::VERSION
17
+ read_any_raw
18
+ end
19
+
20
+ def read_any_raw
21
+ case peek_1
22
+ when ATOM then read_atom
23
+ when SMALL_INT then read_small_int
24
+ when INT then read_int
25
+ when SMALL_BIGNUM then read_small_bignum
26
+ when LARGE_BIGNUM then read_large_bignum
27
+ when FLOAT then read_float
28
+ when NEW_REF then read_new_reference
29
+ when PID then read_pid
30
+ when SMALL_TUPLE then read_small_tuple
31
+ when LARGE_TUPLE then read_large_tuple
32
+ when NIL then read_nil
33
+ when STRING then read_erl_string
34
+ when LIST then read_list
35
+ when BIN then read_bin
36
+ else
37
+ fail("Unknown term tag: #{peek_1}")
38
+ end
39
+ end
40
+
41
+ def read(length)
42
+ if length < @peeked.length
43
+ result = @peeked[0...length]
44
+ @peeked = @peeked[length..-1]
45
+ length = 0
46
+ else
47
+ result = @peeked
48
+ @peeked = ''
49
+ length -= result.length
50
+ end
51
+
52
+ if length > 0
53
+ result << @in.read(length)
54
+ end
55
+ result
56
+ end
57
+
58
+ def peek(length)
59
+ if length <= @peeked.length
60
+ @peeked[0...length]
61
+ else
62
+ read_bytes = @in.read(length - @peeked.length)
63
+ @peeked << read_bytes if read_bytes
64
+ @peeked
65
+ end
66
+ end
67
+
68
+ def peek_1
69
+ peek(1).unpack("C").first
70
+ end
71
+
72
+ def peek_2
73
+ peek(2).unpack("n").first
74
+ end
75
+
76
+ def read_1
77
+ read(1).unpack("C").first
78
+ end
79
+
80
+ def read_2
81
+ read(2).unpack("n").first
82
+ end
83
+
84
+ def read_4
85
+ read(4).unpack("N").first
86
+ end
87
+
88
+ def read_string(length)
89
+ read(length)
90
+ end
91
+
92
+ def read_atom
93
+ fail("Invalid Type, not an atom") unless read_1 == ATOM
94
+ length = read_2
95
+ a = read_string(length)
96
+ case a
97
+ when "true"
98
+ true
99
+ when "false"
100
+ false
101
+ else
102
+ a.to_sym
103
+ end
104
+ end
105
+
106
+ def read_small_int
107
+ fail("Invalid Type, not a small int") unless read_1 == SMALL_INT
108
+ read_1
109
+ end
110
+
111
+ def read_int
112
+ fail("Invalid Type, not an int") unless read_1 == INT
113
+ value = read_4
114
+ negative = (value >> 31)[0] == 1
115
+ value = (value - (1 << 32)) if negative
116
+ value = Fixnum.induced_from(value)
117
+ end
118
+
119
+ def read_small_bignum
120
+ fail("Invalid Type, not a small bignum") unless read_1 == SMALL_BIGNUM
121
+ size = read_1
122
+ sign = read_1
123
+ bytes = read_string(size).unpack("C" * size)
124
+ added = bytes.zip((0..bytes.length).to_a).inject(0) do |result, byte_index|
125
+ byte, index = *byte_index
126
+ value = (byte * (256 ** index))
127
+ sign != 0 ? (result - value) : (result + value)
128
+ end
129
+ Bignum.induced_from(added)
130
+ end
131
+
132
+ def read_large_bignum
133
+ fail("Invalid Type, not a large bignum") unless read_1 == LARGE_BIGNUM
134
+ size = read_4
135
+ sign = read_1
136
+ bytes = read_string(size).unpack("C" * size)
137
+ added = bytes.zip((0..bytes.length).to_a).inject(0) do |result, byte_index|
138
+ byte, index = *byte_index
139
+ value = (byte * (256 ** index))
140
+ sign != 0 ? (result - value) : (result + value)
141
+ end
142
+ Bignum.induced_from(added)
143
+ end
144
+
145
+ def read_float
146
+ fail("Invalid Type, not a float") unless read_1 == FLOAT
147
+ string_value = read_string(31)
148
+ result = string_value.to_f
149
+ end
150
+
151
+ def read_new_reference
152
+ fail("Invalid Type, not a new-style reference") unless read_1 == NEW_REF
153
+ size = read_2
154
+ node = read_atom
155
+ creation = read_1
156
+ id = (0...size).map { |i| read_4 }
157
+ NewReference.new(node, creation, id)
158
+ end
159
+
160
+ def read_pid
161
+ fail("Invalid Type, not a pid") unless read_1 == PID
162
+ node = read_atom
163
+ id = read_4
164
+ serial = read_4
165
+ creation = read_1
166
+ Pid.new(node, id, serial, creation)
167
+ end
168
+
169
+ def read_small_tuple
170
+ fail("Invalid Type, not a small tuple") unless read_1 == SMALL_TUPLE
171
+ arity = read_1
172
+ (0...arity).map { |i| read_any_raw }
173
+ end
174
+
175
+ def read_large_tuple
176
+ fail("Invalid Type, not a small tuple") unless read_1 == LARGE_TUPLE
177
+ arity = read_4
178
+ (0...arity).map { |i| read_any_raw }
179
+ end
180
+
181
+ def read_nil
182
+ fail("Invalid Type, not a nil list") unless read_1 == NIL
183
+ []
184
+ end
185
+
186
+ def read_erl_string
187
+ fail("Invalid Type, not an erlang string") unless read_1 == STRING
188
+ length = read_2
189
+ read_string(length).unpack('C' * length)
190
+ end
191
+
192
+ def read_list
193
+ fail("Invalid Type, not an erlang list") unless read_1 == LIST
194
+ length = read_4
195
+ list = (0...length).map { |i| read_any_raw }
196
+ read_1
197
+ list
198
+ end
199
+
200
+ def read_bin
201
+ fail("Invalid Type, not an erlang binary") unless read_1 == BIN
202
+ length = read_4
203
+ read_string(length)
204
+ end
205
+
206
+ def fail(str)
207
+ raise DecodeError, str
65
208
  end
66
209
  end
67
-
68
- def peek_1
69
- peek(1).unpack("C").first
70
- end
71
-
72
- def peek_2
73
- peek(2).unpack("n").first
74
- end
75
-
76
- def read_1
77
- read(1).unpack("C").first
78
- end
79
-
80
- def read_2
81
- read(2).unpack("n").first
82
- end
83
-
84
- def read_4
85
- read(4).unpack("N").first
86
- end
87
-
88
- def read_string(length)
89
- read(length)
90
- end
91
-
92
- def read_atom
93
- fail("Invalid Type, not an atom") unless read_1 == ATOM
94
- length = read_2
95
- read_string(length).to_sym
96
- end
97
-
98
- def read_small_int
99
- fail("Invalid Type, not a small int") unless read_1 == SMALL_INT
100
- read_1
101
- end
102
-
103
- def read_int
104
- fail("Invalid Type, not an int") unless read_1 == INT
105
- value = read_4
106
- negative = (value >> 31)[0] == 1
107
- value = (value - (1 << 32)) if negative
108
- value = Fixnum.induced_from(value)
109
- end
110
-
111
- def read_small_bignum
112
- fail("Invalid Type, not a small bignum") unless read_1 == SMALL_BIGNUM
113
- size = read_1
114
- sign = read_1
115
- bytes = read_string(size).unpack("C" * size)
116
- added = bytes.zip((0..bytes.length).to_a).inject(0) do |result, byte_index|
117
- byte, index = *byte_index
118
- value = (byte * (256 ** index))
119
- sign != 0 ? (result - value) : (result + value)
120
- end
121
- Bignum.induced_from(added)
122
- end
123
-
124
- def read_large_bignum
125
- fail("Invalid Type, not a large bignum") unless read_1 == LARGE_BIGNUM
126
- size = read_4
127
- sign = read_1
128
- bytes = read_string(size).unpack("C" * size)
129
- added = bytes.zip((0..bytes.length).to_a).inject(0) do |result, byte_index|
130
- byte, index = *byte_index
131
- value = (byte * (256 ** index))
132
- sign != 0 ? (result - value) : (result + value)
133
- end
134
- Bignum.induced_from(added)
135
- end
136
-
137
- def read_float
138
- fail("Invalid Type, not a float") unless read_1 == FLOAT
139
- string_value = read_string(31)
140
- result = string_value.to_f
141
- end
142
-
143
- def read_new_reference
144
- fail("Invalid Type, not a new-style reference") unless read_1 == NEW_REF
145
- size = read_2
146
- node = read_atom
147
- creation = read_1
148
- id = (0...size).map{|i| read_4 }
149
- NewReference.new(node, creation, id)
150
- end
151
-
152
- def read_pid
153
- fail("Invalid Type, not a pid") unless read_1 == PID
154
- node = read_atom
155
- id = read_4
156
- serial = read_4
157
- creation = read_1
158
- Pid.new(node, id, serial, creation)
159
- end
160
-
161
- def read_small_tuple
162
- fail("Invalid Type, not a small tuple") unless read_1 == SMALL_TUPLE
163
- arity = read_1
164
-
165
- (0...arity).map{|i| read_any_raw }
166
- end
167
-
168
- def read_large_tuple
169
- fail("Invalid Type, not a small tuple") unless read_1 == LARGE_TUPLE
170
- arity = read_4
171
- (0...arity).map{|i| read_any_raw}
172
- end
173
-
174
- def read_nil
175
- fail("Invalid Type, not a nil list") unless read_1 == NIL
176
- []
177
- end
178
-
179
- def read_erl_string
180
- fail("Invalid Type, not an erlang string") unless read_1 == STRING
181
- length = read_2
182
- read_string(length).unpack('C' * length)
183
- end
184
-
185
- def read_list
186
- fail("Invalid Type, not an erlang list") unless read_1 == LIST
187
- length = read_4
188
- list = (0...length).map{|i| read_any_raw}
189
- read_1
190
- list
191
- end
192
-
193
- def read_bin
194
- fail("Invalid Type, not an erlang binary") unless read_1 == BIN
195
- length = read_4
196
- read_string(length)
197
- end
198
-
199
- def fail(str)
200
- raise DecodeError, str
201
- end
202
-
203
210
  end
204
- end
@@ -1,56 +1,69 @@
1
1
  module Erlectricity
2
- class Encoder
2
+ class Encoder
3
3
  include Erlectricity::External::Types
4
+
4
5
  attr_accessor :out
6
+
5
7
  def initialize(out)
6
8
  self.out = out
7
9
  end
8
-
10
+
11
+ def self.encode(data)
12
+ io = StringIO.new
13
+ self.new(io).write_any(data)
14
+ io.string
15
+ end
16
+
9
17
  def write_any obj
10
18
  write_1 Erlectricity::External::VERSION
11
19
  write_any_raw obj
12
-
13
20
  end
14
-
21
+
15
22
  def write_any_raw obj
16
23
  case obj
17
- when Symbol then write_symbol(obj)
18
- when Fixnum, Bignum then write_fixnum(obj)
19
- when Float then write_float(obj)
20
- when Erlectricity::NewReference then write_new_reference(obj)
21
- when Erlectricity::Pid then write_pid(obj)
22
- when Erlectricity::List then write_list(obj)
23
- when Array then write_tuple(obj)
24
- when String then write_binary(obj)
25
- else
26
- fail(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)
27
36
  end
28
37
  end
29
-
38
+
30
39
  def write_1(byte)
31
40
  out.write([byte].pack("C"))
32
41
  end
33
-
42
+
34
43
  def write_2(short)
35
44
  out.write([short].pack("n"))
36
45
  end
37
-
46
+
38
47
  def write_4(long)
39
48
  out.write([long].pack("N"))
40
49
  end
41
-
50
+
42
51
  def write_string(string)
43
52
  out.write(string)
44
53
  end
45
-
54
+
55
+ def write_boolean(bool)
56
+ write_symbol(bool.to_s.to_sym)
57
+ end
58
+
46
59
  def write_symbol(sym)
47
- fail(sym) unless sym.is_a? Symbol
60
+ fail(sym) unless sym.is_a?(Symbol)
48
61
  data = sym.to_s
49
62
  write_1 ATOM
50
63
  write_2 data.length
51
64
  write_string data
52
65
  end
53
-
66
+
54
67
  def write_fixnum(num)
55
68
  if num >= 0 && num < 256
56
69
  write_1 SMALL_INT
@@ -62,25 +75,25 @@ class Encoder
62
75
  write_bignum num
63
76
  end
64
77
  end
65
-
78
+
66
79
  def write_float(float)
67
80
  write_1 FLOAT
68
81
  write_string format("%15.15e", float).ljust(31, "\000")
69
82
  end
70
-
83
+
71
84
  def write_bignum(num)
72
85
  fail(num)
73
86
  end
74
-
87
+
75
88
  def write_new_reference(ref)
76
- fail(ref) unless ref.is_a? Erlectricity::NewReference
89
+ fail(ref) unless ref.is_a?(Erlectricity::NewReference)
77
90
  write_1 NEW_REF
78
91
  write_2 ref.id.length
79
92
  write_symbol(ref.node)
80
93
  write_1 ref.creation
81
94
  write_string ref.id.pack('N' * ref.id.length)
82
95
  end
83
-
96
+
84
97
  def write_pid(pid)
85
98
  fail(pid) unless pid.is_a? Erlectricity::Pid
86
99
  write_1 PID
@@ -89,9 +102,10 @@ class Encoder
89
102
  write_4 pid.serial
90
103
  write_1 pid.creation
91
104
  end
92
-
105
+
93
106
  def write_tuple(data)
94
107
  fail(data) unless data.is_a? Array
108
+
95
109
  if data.length < 256
96
110
  write_1 SMALL_TUPLE
97
111
  write_1 data.length
@@ -99,29 +113,29 @@ class Encoder
99
113
  write_1 LARGE_TUPLE
100
114
  write_4 data.length
101
115
  end
102
-
103
- data.each{|e| write_any_raw e }
116
+
117
+ data.each { |e| write_any_raw e }
104
118
  end
105
-
119
+
106
120
  def write_list(data)
107
121
  fail(data) unless data.is_a? Array
108
122
  write_1 NIL and return if data.empty?
109
-
110
123
  write_1 LIST
111
124
  write_4 data.length
112
125
  data.each{|e| write_any_raw e }
113
126
  write_1 NIL
114
127
  end
115
-
128
+
116
129
  def write_binary(data)
117
130
  write_1 BIN
118
131
  write_4 data.length
119
132
  write_string data
120
133
  end
121
-
134
+
122
135
  private
136
+
123
137
  def fail(obj)
124
- raise EncodeError, "Cannot encode to erlang external format: #{obj.inspect}"
138
+ raise EncodeError, "Cannot encode to erlang external format: #{obj.inspect}"
125
139
  end
126
140
  end
127
- end
141
+ end
@@ -1,3 +1,3 @@
1
1
  class DecodeError < ErlectricityError
2
-
2
+
3
3
  end
@@ -1,3 +1,3 @@
1
1
  class EncodeError < ErlectricityError
2
-
2
+
3
3
  end
@@ -1,3 +1,3 @@
1
1
  class ErlectricityError < StandardError
2
-
2
+
3
3
  end
@@ -1,38 +1,21 @@
1
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
10
- end
11
-
12
- def run(arg)
13
- args = get_bound arg
14
- block.call *args
15
- end
16
-
17
- def matches?(arg)
18
- if @condition.is_a?(Array)
19
- return false unless arg.is_a?(Array)
20
- return false if @condition.length != arg.length
21
- @condition.zip(arg).all?{|l,r| l.satisfies?(r)}
22
- else
23
- @condition.satisfies?(arg)
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)
24
15
  end
25
- end
26
-
27
16
 
28
- private
29
-
30
- def get_bound(arg)
31
- if @condition.is_a?(Array) && arg.is_a?(Array)
32
- @condition.zip(arg).map{|l,r| l.binding_for r}.compact
33
- else
34
- @condition.binding_for(arg)
17
+ def matches?(arg)
18
+ @condition.satisfies?(arg)
35
19
  end
36
20
  end
37
21
  end
38
- end