erlectricity 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/Manifest.txt +41 -0
  2. data/README.txt +3 -0
  3. data/Rakefile +68 -0
  4. data/examples/gruff/gruff.erl +62 -0
  5. data/examples/gruff/gruff_provider.rb +38 -0
  6. data/examples/gruff/gruff_run.erl +17 -0
  7. data/examples/gruff/stat_run.erl +18 -0
  8. data/examples/gruff/stat_writer.erl +40 -0
  9. data/examples/tinderl/tinderl.erl +41 -0
  10. data/examples/tinderl/tinderl.rb +23 -0
  11. data/lib/erlectricity/condition.rb +48 -0
  12. data/lib/erlectricity/conditions/hash.rb +15 -0
  13. data/lib/erlectricity/conditions/static.rb +17 -0
  14. data/lib/erlectricity/conditions/type.rb +19 -0
  15. data/lib/erlectricity/constants.rb +37 -0
  16. data/lib/erlectricity/decoder.rb +202 -0
  17. data/lib/erlectricity/encoder.rb +127 -0
  18. data/lib/erlectricity/errors/decode_error.rb +3 -0
  19. data/lib/erlectricity/errors/encode_error.rb +3 -0
  20. data/lib/erlectricity/errors/erlectricity_error.rb +3 -0
  21. data/lib/erlectricity/match_context.rb +20 -0
  22. data/lib/erlectricity/matcher.rb +60 -0
  23. data/lib/erlectricity/port.rb +46 -0
  24. data/lib/erlectricity/receiver.rb +74 -0
  25. data/lib/erlectricity/types/function.rb +3 -0
  26. data/lib/erlectricity/types/new_function.rb +3 -0
  27. data/lib/erlectricity/types/new_reference.rb +3 -0
  28. data/lib/erlectricity/types/pid.rb +3 -0
  29. data/lib/erlectricity/types/reference.rb +3 -0
  30. data/lib/erlectricity/version.rb +9 -0
  31. data/lib/erlectricity.rb +23 -0
  32. data/setup.rb +1585 -0
  33. data/test/condition_spec.rb +78 -0
  34. data/test/decode_spec.rb +133 -0
  35. data/test/encode_spec.rb +125 -0
  36. data/test/matcher_spec.rb +73 -0
  37. data/test/port_spec.rb +35 -0
  38. data/test/receiver_spec.rb +105 -0
  39. data/test/spec_suite.rb +2 -0
  40. data/test/test_erlectricity.rb +2 -0
  41. data/test/test_helper.rb +36 -0
  42. metadata +87 -0
@@ -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 Array then write_tuple(obj)
23
+ when String then write_binary(obj)
24
+ else
25
+ fail(obj)
26
+ end
27
+ end
28
+
29
+ def write_1(byte)
30
+ out.write([byte].pack("C"))
31
+ end
32
+
33
+ def write_2(short)
34
+ out.write([short].pack("n"))
35
+ end
36
+
37
+ def write_4(long)
38
+ out.write([long].pack("N"))
39
+ end
40
+
41
+ def write_string(string)
42
+ out.write(string)
43
+ end
44
+
45
+ def write_symbol(sym)
46
+ fail(sym) unless sym.is_a? Symbol
47
+ data = sym.to_s
48
+ write_1 ATOM
49
+ write_2 data.length
50
+ write_string data
51
+ end
52
+
53
+ def write_fixnum(num)
54
+ if num >= 0 && num < 256
55
+ write_1 SMALL_INT
56
+ write_1 num
57
+ elsif num <= Erlectricity::External::MAX_INT && num >= Erlectricity::External::MIN_INT
58
+ write_1 INT
59
+ write_4 num
60
+ else
61
+ write_bignum num
62
+ end
63
+ end
64
+
65
+ def write_float(float)
66
+ write_1 FLOAT
67
+ write_string format("%15.15e", float).ljust(31, "\000")
68
+ end
69
+
70
+ def write_bignum(num)
71
+ fail(num)
72
+ end
73
+
74
+ def write_new_reference(ref)
75
+ fail(ref) unless ref.is_a? Erlectricity::NewReference
76
+ write_1 NEW_REF
77
+ write_2 ref.id.length
78
+ write_symbol(ref.node)
79
+ write_1 ref.creation
80
+ write_string ref.id.pack('N' * ref.id.length)
81
+ end
82
+
83
+ def write_pid(pid)
84
+ fail(pid) unless pid.is_a? Erlectricity::Pid
85
+ write_1 PID
86
+ write_symbol(pid.node)
87
+ write_4 pid.id
88
+ write_4 pid.serial
89
+ write_1 pid.creation
90
+ end
91
+
92
+ def write_tuple(data)
93
+ fail(data) unless data.is_a? Array
94
+ if data.length < 256
95
+ write_1 SMALL_TUPLE
96
+ write_1 data.length
97
+ else
98
+ write_1 LARGE_TUPLE
99
+ write_4 data.length
100
+ end
101
+
102
+ data.each{|e| write_any_raw e }
103
+ end
104
+
105
+ def write_list(data)
106
+ fail(data) unless data.is_a? Array
107
+ write_1 NIL and return if data.empty?
108
+
109
+ #NOTE: we do not ever encode as the string format.
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
@@ -0,0 +1,3 @@
1
+ class DecodeError < ErlectricityError
2
+
3
+ end
@@ -0,0 +1,3 @@
1
+ class EncodeError < ErlectricityError
2
+
3
+ end
@@ -0,0 +1,3 @@
1
+ class ErlectricityError < StandardError
2
+
3
+ end
@@ -0,0 +1,20 @@
1
+ module Erlectricity
2
+ class MatchContext
3
+ attr_accessor :receiver
4
+ def initialize(receiver)
5
+ self.receiver = receiver
6
+ end
7
+
8
+ def receive(&block)
9
+ receiver.receive(&block)
10
+ end
11
+
12
+ def receive_loop
13
+ receiver.receive_loop
14
+ end
15
+
16
+ def send!(*term)
17
+ receiver.send!(*term)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,60 @@
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
+ context = MatchContext.new(self.receiver)
14
+
15
+ populate_context context, arg
16
+ context.instance_eval &block
17
+ end
18
+
19
+ def matches?(arg)
20
+ if @condition.is_a?(Array)
21
+ return false unless arg.is_a?(Array)
22
+ return false if @condition.length != arg.length
23
+ @condition.zip(arg).all?{|l,r| l.satisfies?(r)}
24
+ else
25
+ @condition.satisfies?(arg)
26
+ end
27
+ end
28
+
29
+
30
+ private
31
+ def populate_context(context, arg)
32
+ if @condition.is_a?(Array) && arg.is_a?(Array)
33
+ @condition.zip(arg).all?{|l,r| set_binding(context, l, r)}
34
+ else
35
+ set_binding(context, condition, arg)
36
+ end
37
+ end
38
+
39
+ def set_binding(context, condition, arg)
40
+ condition.bindings_for(arg).each do |k, v|
41
+ add_to_context(context, k, v)
42
+ end
43
+ end
44
+
45
+ def add_to_context(context, name, value)
46
+ return if name.nil?
47
+
48
+ context.instance_eval <<-EOS
49
+ def #{name}
50
+ @#{name}
51
+ end
52
+ def #{name}= (value)
53
+ @#{name} = value
54
+ end
55
+ EOS
56
+
57
+ context.send(:"#{name}=", value)
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,46 @@
1
+ module Erlectricity
2
+ class Port
3
+ attr_reader :input, :output
4
+ attr_reader :skipped
5
+ attr_reader :queue
6
+
7
+ def initialize(input=STDIN, output=STDOUT)
8
+ @input = input
9
+ @output = output
10
+
11
+ input.sync = true
12
+ output.sync = true
13
+
14
+ @encoder = Erlectricity::Encoder.new(nil)
15
+ @skipped = []
16
+ @queue = []
17
+ end
18
+
19
+ def receive
20
+ queue.empty? ? read_from_input : queue.shift
21
+ end
22
+
23
+ def send(term)
24
+ @encoder.out = StringIO.new('', 'w')
25
+ @encoder.write_any(term)
26
+ data = @encoder.out.string
27
+ output.write([data.length].pack("N"))
28
+ output.write data
29
+ end
30
+
31
+ def restore_skipped
32
+ @queue = self.skipped + self.queue
33
+ end
34
+
35
+ private
36
+ def read_from_input
37
+ raw = input.read(4)
38
+ return nil unless raw
39
+
40
+ packet_length = raw.unpack('N').first
41
+ data = input.read(packet_length)
42
+ result = Erlectricity::Decoder.read_any_from(data)
43
+ result
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,74 @@
1
+ module Erlectricity
2
+ class Receiver
3
+ include Conditions
4
+
5
+ attr_accessor :port
6
+ attr_accessor :parent
7
+ attr_accessor :matchers
8
+
9
+ RECEIVE_LOOP = Object.new
10
+ NO_MATCH = Object.new
11
+
12
+ def initialize(port, parent=nil, &block)
13
+ @port = port
14
+ @parent = parent
15
+ @matchers = []
16
+ instance_eval &block if block
17
+ end
18
+
19
+ def process(arg)
20
+ matcher = @matchers.find{|r| r.matches? arg}
21
+
22
+ if(matcher)
23
+ port.restore_skipped
24
+ matcher.run arg
25
+ else
26
+ NO_MATCH
27
+ end
28
+ end
29
+
30
+ def match(*args, &block)
31
+ args = args.map{|a| a.is_a?(Condition) ? a : StaticCondition.new(a)}
32
+
33
+ args = args.first if args.length == 1
34
+ @matchers << Matcher.new(self, args, block)
35
+ end
36
+
37
+ def run
38
+
39
+ loop do
40
+ msg = port.receive
41
+ return if msg.nil?
42
+
43
+ case result = process(msg)
44
+ when RECEIVE_LOOP then next
45
+ when NO_MATCH
46
+ port.skipped << msg
47
+ next
48
+ else
49
+ break result
50
+ end
51
+ end
52
+ end
53
+
54
+ def receive(&block)
55
+ Receiver.new(port, self, &block).run
56
+ end
57
+
58
+ def receive_loop
59
+ RECEIVE_LOOP
60
+ end
61
+
62
+ def send!(*term)
63
+ term = term.first if term.length == 1
64
+ port.send(term)
65
+ end
66
+ end
67
+ end
68
+
69
+
70
+ module Kernel
71
+ def receive(input=STDIN, output=STDOUT, &block)
72
+ Erlectricity::Receiver.new(Erlectricity::Port.new(input, output), nil, &block).run
73
+ end
74
+ end
@@ -0,0 +1,3 @@
1
+ module Erlectricity
2
+ Function = Struct.new :pid, :module, :index, :uniq, :free_vars
3
+ end
@@ -0,0 +1,3 @@
1
+ module Erlectricity
2
+ NewFunction = Struct.new :arity, :uniq, :index,:num_free, :module, :old_index, :old_uniq, :pid, :free_vars
3
+ end
@@ -0,0 +1,3 @@
1
+ module Erlectricity
2
+ NewReference = Struct.new :node, :creation, :id
3
+ end
@@ -0,0 +1,3 @@
1
+ module Erlectricity
2
+ Pid = Struct.new :node, :id, :serial, :creation
3
+ end
@@ -0,0 +1,3 @@
1
+ module Erlectricity
2
+ Reference = Struct.new :node, :id, :creator
3
+ end
@@ -0,0 +1,9 @@
1
+ module Erlectricity #:nodoc:
2
+ module VERSION #:nodoc:
3
+ MAJOR = 0
4
+ MINOR = 1
5
+ TINY = 0
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ end
9
+ end
@@ -0,0 +1,23 @@
1
+ require 'erlectricity/constants'
2
+
3
+ require 'erlectricity/types/new_reference'
4
+ require 'erlectricity/types/pid'
5
+ require 'erlectricity/types/function'
6
+
7
+ require 'erlectricity/decoder'
8
+ require 'erlectricity/encoder'
9
+
10
+ require 'erlectricity/port'
11
+ require 'erlectricity/matcher'
12
+ require 'erlectricity/match_context'
13
+
14
+ require 'erlectricity/condition'
15
+ require 'erlectricity/conditions/hash'
16
+ require 'erlectricity/conditions/static'
17
+ require 'erlectricity/conditions/type'
18
+
19
+ require 'erlectricity/receiver'
20
+
21
+ require 'erlectricity/errors/erlectricity_error'
22
+ require 'erlectricity/errors/decode_error'
23
+ require 'erlectricity/errors/encode_error'