tmm1-erlectricity 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
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 +51 -0
  5. data/Rakefile +71 -0
  6. data/examples/gruff/gruff.erl +62 -0
  7. data/examples/gruff/gruff_provider.rb +36 -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 +37 -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 +78 -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 +102 -0
@@ -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,37 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), *%w[.. ext])
2
+
3
+ require 'stringio'
4
+
5
+ require 'erlectricity/constants'
6
+
7
+ require 'erlectricity/types/new_reference'
8
+ require 'erlectricity/types/pid'
9
+ require 'erlectricity/types/function'
10
+ require 'erlectricity/types/list'
11
+
12
+
13
+ begin
14
+ #try to load the decoder C extension
15
+ require 'decoder'
16
+ rescue LoadError
17
+ #load the pure ruby instead
18
+ require 'erlectricity/decoder'
19
+ end
20
+
21
+ require 'erlectricity/encoder'
22
+
23
+ require 'erlectricity/port'
24
+ require 'erlectricity/matcher'
25
+
26
+ require 'erlectricity/condition'
27
+ require 'erlectricity/conditions/hash'
28
+ require 'erlectricity/conditions/static'
29
+ require 'erlectricity/conditions/type'
30
+
31
+ require 'erlectricity/receiver'
32
+
33
+ require 'erlectricity/errors/erlectricity_error'
34
+ require 'erlectricity/errors/decode_error'
35
+ require 'erlectricity/errors/encode_error'
36
+
37
+ 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