mojombo-erlectricity 0.2.1 → 1.0.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.
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