erlectricity-funbox 1.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/.gitignore +24 -0
  2. data/History.txt +35 -0
  3. data/LICENSE +20 -0
  4. data/README.md +130 -0
  5. data/Rakefile +74 -0
  6. data/VERSION.yml +4 -0
  7. data/benchmarks/bench.rb +21 -0
  8. data/erlectricity.gemspec +105 -0
  9. data/examples/echo/README.md +12 -0
  10. data/examples/echo/echo.erl +13 -0
  11. data/examples/echo/echo.rb +11 -0
  12. data/examples/gruff/gruff.erl +61 -0
  13. data/examples/gruff/gruff_provider.rb +31 -0
  14. data/examples/gruff/gruff_run.sh +19 -0
  15. data/examples/gruff/stat_run.sh +20 -0
  16. data/examples/gruff/stat_writer.erl +40 -0
  17. data/examples/simple/README.md +5 -0
  18. data/examples/simple/rerl.rb +111 -0
  19. data/examples/simple/rerl.sh +37 -0
  20. data/examples/tinderl/README.md +14 -0
  21. data/examples/tinderl/tinderl.erl +43 -0
  22. data/examples/tinderl/tinderl.rb +28 -0
  23. data/ext/decoder.c +398 -0
  24. data/ext/extconf.rb +11 -0
  25. data/lib/erlectricity.rb +33 -0
  26. data/lib/erlectricity/condition.rb +66 -0
  27. data/lib/erlectricity/conditions/boolean.rb +11 -0
  28. data/lib/erlectricity/conditions/hash.rb +13 -0
  29. data/lib/erlectricity/conditions/static.rb +34 -0
  30. data/lib/erlectricity/conditions/type.rb +17 -0
  31. data/lib/erlectricity/constants.rb +36 -0
  32. data/lib/erlectricity/decoder.rb +212 -0
  33. data/lib/erlectricity/encoder.rb +164 -0
  34. data/lib/erlectricity/errors/decode_error.rb +3 -0
  35. data/lib/erlectricity/errors/encode_error.rb +3 -0
  36. data/lib/erlectricity/errors/erlectricity_error.rb +3 -0
  37. data/lib/erlectricity/matcher.rb +21 -0
  38. data/lib/erlectricity/port.rb +46 -0
  39. data/lib/erlectricity/receiver.rb +69 -0
  40. data/lib/erlectricity/types/function.rb +3 -0
  41. data/lib/erlectricity/types/list.rb +3 -0
  42. data/lib/erlectricity/types/new_function.rb +3 -0
  43. data/lib/erlectricity/types/new_reference.rb +3 -0
  44. data/lib/erlectricity/types/pid.rb +3 -0
  45. data/lib/erlectricity/types/reference.rb +3 -0
  46. data/lib/erlectricity/version.rb +9 -0
  47. data/test/condition_spec.rb +72 -0
  48. data/test/decode_spec.rb +145 -0
  49. data/test/encode_spec.rb +146 -0
  50. data/test/matcher_spec.rb +81 -0
  51. data/test/port_spec.rb +34 -0
  52. data/test/receiver_spec.rb +103 -0
  53. data/test/spec_suite.rb +2 -0
  54. data/test/test_helper.rb +46 -0
  55. metadata +116 -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,33 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), *%w[.. ext])
2
+
3
+ require 'stringio'
4
+
5
+ require 'erlectricity/constants'
6
+ require 'erlectricity/types/new_reference'
7
+ require 'erlectricity/types/pid'
8
+ require 'erlectricity/types/function'
9
+ require 'erlectricity/types/list'
10
+
11
+ begin
12
+ # try to load the decoder C extension
13
+ require 'decoder'
14
+ rescue LoadError
15
+ # fall back on the pure ruby version
16
+ require 'erlectricity/decoder'
17
+ end
18
+
19
+ require 'erlectricity/encoder'
20
+
21
+ require 'erlectricity/port'
22
+ require 'erlectricity/matcher'
23
+ require 'erlectricity/condition'
24
+ require 'erlectricity/conditions/boolean'
25
+ require 'erlectricity/conditions/hash'
26
+ require 'erlectricity/conditions/static'
27
+ require 'erlectricity/conditions/type'
28
+ require 'erlectricity/receiver'
29
+ require 'erlectricity/errors/erlectricity_error'
30
+ require 'erlectricity/errors/decode_error'
31
+ require 'erlectricity/errors/encode_error'
32
+
33
+ Erl = Erlectricity
@@ -0,0 +1,66 @@
1
+ module Erlectricity
2
+ class Condition
3
+ def self.for(a)
4
+ case a
5
+ when Condition then a
6
+ when Class then TypeCondition.new(a)
7
+ else StaticCondition.new(a)
8
+ end
9
+ end
10
+
11
+ def initialize
12
+ end
13
+
14
+ def binding_for(arg)
15
+ nil
16
+ end
17
+
18
+ def satisfies?(arg)
19
+ false
20
+ end
21
+
22
+ alias === satisfies?
23
+ end
24
+
25
+ module Conditions
26
+ def atom
27
+ TypeCondition.new(Symbol)
28
+ end
29
+
30
+ def any
31
+ TypeCondition.new(Object)
32
+ end
33
+
34
+ def number
35
+ TypeCondition.new(Fixnum)
36
+ end
37
+
38
+ def pid
39
+ TypeCondition.new(Erlectricity::Pid)
40
+ end
41
+
42
+ def ref
43
+ TypeCondition.new(Erlectricity::NewReference)
44
+ end
45
+
46
+ def string
47
+ TypeCondition.new(String)
48
+ end
49
+
50
+ def list
51
+ TypeCondition.new(Array)
52
+ end
53
+
54
+ def hash
55
+ HashCondition.new()
56
+ end
57
+
58
+ def boolean
59
+ BooleanCondition.new()
60
+ end
61
+ end
62
+
63
+ extend Conditions
64
+ end
65
+
66
+ Any = Object
@@ -0,0 +1,11 @@
1
+ module Erlectricity
2
+ class BooleanCondition < Condition
3
+ def satisfies?(arg)
4
+ [TrueClass, FalseClass].include?(arg.class)
5
+ end
6
+
7
+ def binding_for(arg)
8
+ arg
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ module Erlectricity
2
+ class HashCondition < Condition
3
+ def satisfies?(arg)
4
+ return false unless arg.class == Array
5
+ arg.all? { |x| x.class == Array && x.length == 2 }
6
+ end
7
+
8
+ def binding_for(arg)
9
+ flattened = arg.inject([]) { |memo, kv| memo + kv }
10
+ Hash[*flattened]
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,34 @@
1
+ module Erlectricity
2
+ class StaticCondition < Condition
3
+ attr_accessor :value
4
+ def initialize(value)
5
+ if value.is_a?(Array)
6
+ self.value = value.map do |v|
7
+ Condition.for(v)
8
+ end
9
+ else
10
+ self.value = value
11
+ end
12
+ end
13
+
14
+ def satisfies?(arg)
15
+ if value.is_a?(Array)
16
+ return false unless arg.is_a?(Array)
17
+ return false if value.length != arg.length
18
+ value.zip(arg).all? do |l, r|
19
+ l.respond_to?(:satisfies?) ? l.satisfies?(r) : l.eql?(r)
20
+ end
21
+ else
22
+ arg.eql?(value)
23
+ end
24
+ end
25
+
26
+ def binding_for(arg)
27
+ if value.is_a?(Array)
28
+ value.zip(arg).map { |l, r| l.binding_for(r) }.compact
29
+ else
30
+ nil
31
+ end
32
+ end
33
+ end
34
+ 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,36 @@
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
+ end
@@ -0,0 +1,212 @@
1
+ module Erlectricity
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
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
+ a = read_string(length)
96
+ case a
97
+ when "true"
98
+ true
99
+ when "false"
100
+ false
101
+ when ""
102
+ Marshal.load("\004\b:\005") # Workaround for inability to do ''.to_sym
103
+ else
104
+ a.to_sym
105
+ end
106
+ end
107
+
108
+ def read_small_int
109
+ fail("Invalid Type, not a small int") unless read_1 == SMALL_INT
110
+ read_1
111
+ end
112
+
113
+ def read_int
114
+ fail("Invalid Type, not an int") unless read_1 == INT
115
+ value = read_4
116
+ negative = (value >> 31)[0] == 1
117
+ value = (value - (1 << 32)) if negative
118
+ value = Fixnum.induced_from(value)
119
+ end
120
+
121
+ def read_small_bignum
122
+ fail("Invalid Type, not a small bignum") unless read_1 == SMALL_BIGNUM
123
+ size = read_1
124
+ sign = read_1
125
+ bytes = read_string(size).unpack("C" * size)
126
+ added = bytes.zip((0..bytes.length).to_a).inject(0) do |result, byte_index|
127
+ byte, index = *byte_index
128
+ value = (byte * (256 ** index))
129
+ sign != 0 ? (result - value) : (result + value)
130
+ end
131
+ Bignum.induced_from(added)
132
+ end
133
+
134
+ def read_large_bignum
135
+ fail("Invalid Type, not a large bignum") unless read_1 == LARGE_BIGNUM
136
+ size = read_4
137
+ sign = read_1
138
+ bytes = read_string(size).unpack("C" * size)
139
+ added = bytes.zip((0..bytes.length).to_a).inject(0) do |result, byte_index|
140
+ byte, index = *byte_index
141
+ value = (byte * (256 ** index))
142
+ sign != 0 ? (result - value) : (result + value)
143
+ end
144
+ Bignum.induced_from(added)
145
+ end
146
+
147
+ def read_float
148
+ fail("Invalid Type, not a float") unless read_1 == FLOAT
149
+ string_value = read_string(31)
150
+ result = string_value.to_f
151
+ end
152
+
153
+ def read_new_reference
154
+ fail("Invalid Type, not a new-style reference") unless read_1 == NEW_REF
155
+ size = read_2
156
+ node = read_atom
157
+ creation = read_1
158
+ id = (0...size).map { |i| read_4 }
159
+ NewReference.new(node, creation, id)
160
+ end
161
+
162
+ def read_pid
163
+ fail("Invalid Type, not a pid") unless read_1 == PID
164
+ node = read_atom
165
+ id = read_4
166
+ serial = read_4
167
+ creation = read_1
168
+ Pid.new(node, id, serial, creation)
169
+ end
170
+
171
+ def read_small_tuple
172
+ fail("Invalid Type, not a small tuple") unless read_1 == SMALL_TUPLE
173
+ arity = read_1
174
+ (0...arity).map { |i| read_any_raw }
175
+ end
176
+
177
+ def read_large_tuple
178
+ fail("Invalid Type, not a small tuple") unless read_1 == LARGE_TUPLE
179
+ arity = read_4
180
+ (0...arity).map { |i| read_any_raw }
181
+ end
182
+
183
+ def read_nil
184
+ fail("Invalid Type, not a nil list") unless read_1 == NIL
185
+ Erlectricity::List.new([])
186
+ end
187
+
188
+ def read_erl_string
189
+ fail("Invalid Type, not an erlang string") unless read_1 == STRING
190
+ length = read_2
191
+ Erlectricity::List.new(read_string(length).unpack('C' * length))
192
+ end
193
+
194
+ def read_list
195
+ fail("Invalid Type, not an erlang list") unless read_1 == LIST
196
+ length = read_4
197
+ list = (0...length).map { |i| read_any_raw }
198
+ read_1
199
+ Erlectricity::List.new(list)
200
+ end
201
+
202
+ def read_bin
203
+ fail("Invalid Type, not an erlang binary") unless read_1 == BIN
204
+ length = read_4
205
+ read_string(length)
206
+ end
207
+
208
+ def fail(str)
209
+ raise DecodeError, str
210
+ end
211
+ end
212
+ end