mojombo-erlectricity 0.2.1

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 (46) hide show
  1. data/CONTRIBUTORS +2 -0
  2. data/History.txt +1 -0
  3. data/Manifest.txt +45 -0
  4. data/README.txt +43 -0
  5. data/Rakefile +71 -0
  6. data/examples/gruff/gruff.erl +62 -0
  7. data/examples/gruff/gruff_provider.rb +38 -0
  8. data/examples/gruff/gruff_run.erl +17 -0
  9. data/examples/gruff/stat_run.erl +18 -0
  10. data/examples/gruff/stat_writer.erl +40 -0
  11. data/examples/tinderl/tinderl.erl +45 -0
  12. data/examples/tinderl/tinderl.rb +27 -0
  13. data/ext/decoder.c +391 -0
  14. data/ext/extconf.rb +11 -0
  15. data/lib/erlectricity.rb +36 -0
  16. data/lib/erlectricity/condition.rb +51 -0
  17. data/lib/erlectricity/conditions/hash.rb +14 -0
  18. data/lib/erlectricity/conditions/static.rb +13 -0
  19. data/lib/erlectricity/conditions/type.rb +17 -0
  20. data/lib/erlectricity/constants.rb +37 -0
  21. data/lib/erlectricity/decoder.rb +204 -0
  22. data/lib/erlectricity/encoder.rb +127 -0
  23. data/lib/erlectricity/errors/decode_error.rb +3 -0
  24. data/lib/erlectricity/errors/encode_error.rb +3 -0
  25. data/lib/erlectricity/errors/erlectricity_error.rb +3 -0
  26. data/lib/erlectricity/matcher.rb +38 -0
  27. data/lib/erlectricity/port.rb +46 -0
  28. data/lib/erlectricity/receiver.rb +79 -0
  29. data/lib/erlectricity/types/function.rb +3 -0
  30. data/lib/erlectricity/types/list.rb +1 -0
  31. data/lib/erlectricity/types/new_function.rb +3 -0
  32. data/lib/erlectricity/types/new_reference.rb +3 -0
  33. data/lib/erlectricity/types/pid.rb +3 -0
  34. data/lib/erlectricity/types/reference.rb +3 -0
  35. data/lib/erlectricity/version.rb +9 -0
  36. data/setup.rb +1585 -0
  37. data/test/condition_spec.rb +73 -0
  38. data/test/decode_spec.rb +129 -0
  39. data/test/encode_spec.rb +132 -0
  40. data/test/matcher_spec.rb +69 -0
  41. data/test/port_spec.rb +35 -0
  42. data/test/receiver_spec.rb +105 -0
  43. data/test/spec_suite.rb +2 -0
  44. data/test/test_erlectricity.rb +2 -0
  45. data/test/test_helper.rb +42 -0
  46. metadata +110 -0
data/ext/extconf.rb ADDED
@@ -0,0 +1,11 @@
1
+ # Loads mkmf which is used to make makefiles for Ruby extensions
2
+ require 'mkmf'
3
+
4
+ # Give it a name
5
+ extension_name = 'decoder'
6
+
7
+ # The destination
8
+ dir_config(extension_name)
9
+
10
+ # Do the work
11
+ create_makefile(extension_name)
@@ -0,0 +1,36 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), *%w[.. ext])
2
+
3
+
4
+ require 'erlectricity/constants'
5
+
6
+ require 'erlectricity/types/new_reference'
7
+ require 'erlectricity/types/pid'
8
+ require 'erlectricity/types/function'
9
+ require 'erlectricity/types/list'
10
+
11
+
12
+ begin
13
+ #try to load the decoder C extension
14
+ require 'decoder'
15
+ rescue LoadError
16
+ #load the pure ruby instead
17
+ require 'erlectricity/decoder'
18
+ end
19
+
20
+ require 'erlectricity/encoder'
21
+
22
+ require 'erlectricity/port'
23
+ require 'erlectricity/matcher'
24
+
25
+ require 'erlectricity/condition'
26
+ require 'erlectricity/conditions/hash'
27
+ require 'erlectricity/conditions/static'
28
+ require 'erlectricity/conditions/type'
29
+
30
+ require 'erlectricity/receiver'
31
+
32
+ require 'erlectricity/errors/erlectricity_error'
33
+ require 'erlectricity/errors/decode_error'
34
+ require 'erlectricity/errors/encode_error'
35
+
36
+ Erl = Erlectricity
@@ -0,0 +1,51 @@
1
+ module Erlectricity
2
+ class Condition
3
+
4
+ def initialize
5
+ end
6
+
7
+ def binding_for(arg)
8
+ nil
9
+ end
10
+
11
+ def satisfies?(arg)
12
+ false
13
+ end
14
+
15
+ alias === satisfies?
16
+ end
17
+
18
+ module Conditions
19
+ def atom()
20
+ TypeCondition.new(Symbol)
21
+ end
22
+
23
+ def any()
24
+ TypeCondition.new(Object)
25
+ end
26
+
27
+ def number()
28
+ TypeCondition.new(Fixnum)
29
+ end
30
+
31
+ def pid()
32
+ TypeCondition.new(Erlectricity::Pid)
33
+ end
34
+
35
+ def string()
36
+ TypeCondition.new(String)
37
+ end
38
+
39
+ def list()
40
+ TypeCondition.new(Array)
41
+ end
42
+
43
+ def hash()
44
+ HashCondition.new()
45
+ end
46
+ end
47
+
48
+ extend Conditions
49
+ end
50
+
51
+ Any = Object
@@ -0,0 +1,14 @@
1
+ module Erlectricity
2
+ class HashCondition < Condition
3
+
4
+ def satisfies?(arg)
5
+ return false unless arg.class == Array
6
+ arg.all?{|x| x.class == Array && x.length == 2}
7
+ end
8
+
9
+ def binding_for(arg)
10
+ flattened = arg.inject([]){|memo, kv| memo + kv}
11
+ Hash[*flattened]
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ module Erlectricity
2
+ class StaticCondition < Condition
3
+ attr_accessor :value
4
+ def initialize(value)
5
+ self.value = value
6
+ end
7
+
8
+ def satisfies?(arg)
9
+ arg.eql? value
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,17 @@
1
+ module Erlectricity
2
+ class TypeCondition < Condition
3
+ attr_accessor :type
4
+
5
+ def initialize(type)
6
+ self.type = type
7
+ end
8
+
9
+ def satisfies?(arg)
10
+ arg.is_a? self.type
11
+ end
12
+
13
+ def binding_for(arg)
14
+ arg
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,37 @@
1
+ module Erlectricity
2
+ module External
3
+ module Types
4
+ SMALL_INT = 97
5
+ INT = 98
6
+
7
+ SMALL_BIGNUM = 110
8
+ LARGE_BIGNUM = 111
9
+
10
+ FLOAT = 99
11
+
12
+ ATOM = 100
13
+ REF = 101 #old style reference
14
+ NEW_REF = 114
15
+ PORT = 102 #not supported accross node boundaries
16
+ PID = 103
17
+
18
+ SMALL_TUPLE = 104
19
+ LARGE_TUPLE = 105
20
+
21
+ NIL = 106
22
+ STRING = 107
23
+ LIST = 108
24
+ BIN = 109
25
+
26
+ FUN = 117
27
+ NEW_FUN = 112
28
+ end
29
+
30
+ VERSION = 131
31
+
32
+ MAX_INT = (1 << 27) -1
33
+ MIN_INT = -(1 << 27)
34
+ MAX_ATOM = 255
35
+ end
36
+
37
+ end
@@ -0,0 +1,204 @@
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}")
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
+ 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
+ end
204
+ end
@@ -0,0 +1,127 @@
1
+ module Erlectricity
2
+ class Encoder
3
+ include Erlectricity::External::Types
4
+ attr_accessor :out
5
+ def initialize(out)
6
+ self.out = out
7
+ end
8
+
9
+ def write_any obj
10
+ write_1 Erlectricity::External::VERSION
11
+ write_any_raw obj
12
+
13
+ end
14
+
15
+ def write_any_raw obj
16
+ 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)
27
+ end
28
+ end
29
+
30
+ def write_1(byte)
31
+ out.write([byte].pack("C"))
32
+ end
33
+
34
+ def write_2(short)
35
+ out.write([short].pack("n"))
36
+ end
37
+
38
+ def write_4(long)
39
+ out.write([long].pack("N"))
40
+ end
41
+
42
+ def write_string(string)
43
+ out.write(string)
44
+ end
45
+
46
+ def write_symbol(sym)
47
+ fail(sym) unless sym.is_a? Symbol
48
+ data = sym.to_s
49
+ write_1 ATOM
50
+ write_2 data.length
51
+ write_string data
52
+ end
53
+
54
+ def write_fixnum(num)
55
+ if num >= 0 && num < 256
56
+ write_1 SMALL_INT
57
+ write_1 num
58
+ elsif num <= Erlectricity::External::MAX_INT && num >= Erlectricity::External::MIN_INT
59
+ write_1 INT
60
+ write_4 num
61
+ else
62
+ write_bignum num
63
+ end
64
+ end
65
+
66
+ def write_float(float)
67
+ write_1 FLOAT
68
+ write_string format("%15.15e", float).ljust(31, "\000")
69
+ end
70
+
71
+ def write_bignum(num)
72
+ fail(num)
73
+ end
74
+
75
+ def write_new_reference(ref)
76
+ fail(ref) unless ref.is_a? Erlectricity::NewReference
77
+ write_1 NEW_REF
78
+ write_2 ref.id.length
79
+ write_symbol(ref.node)
80
+ write_1 ref.creation
81
+ write_string ref.id.pack('N' * ref.id.length)
82
+ end
83
+
84
+ def write_pid(pid)
85
+ fail(pid) unless pid.is_a? Erlectricity::Pid
86
+ write_1 PID
87
+ write_symbol(pid.node)
88
+ write_4 pid.id
89
+ write_4 pid.serial
90
+ write_1 pid.creation
91
+ end
92
+
93
+ def write_tuple(data)
94
+ fail(data) unless data.is_a? Array
95
+ if data.length < 256
96
+ write_1 SMALL_TUPLE
97
+ write_1 data.length
98
+ else
99
+ write_1 LARGE_TUPLE
100
+ write_4 data.length
101
+ end
102
+
103
+ data.each{|e| write_any_raw e }
104
+ end
105
+
106
+ def write_list(data)
107
+ fail(data) unless data.is_a? Array
108
+ write_1 NIL and return if data.empty?
109
+
110
+ write_1 LIST
111
+ write_4 data.length
112
+ data.each{|e| write_any_raw e }
113
+ write_1 NIL
114
+ end
115
+
116
+ def write_binary(data)
117
+ write_1 BIN
118
+ write_4 data.length
119
+ write_string data
120
+ end
121
+
122
+ private
123
+ def fail(obj)
124
+ raise EncodeError, "Cannot encode to erlang external format: #{obj.inspect}"
125
+ end
126
+ end
127
+ end