erlectricity 0.2.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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.rb +4 -7
  22. data/lib/erlectricity/condition.rb +35 -20
  23. data/lib/erlectricity/conditions/boolean.rb +11 -0
  24. data/lib/erlectricity/conditions/hash.rb +9 -10
  25. data/lib/erlectricity/conditions/static.rb +31 -10
  26. data/lib/erlectricity/conditions/type.rb +14 -14
  27. data/lib/erlectricity/constants.rb +3 -4
  28. data/lib/erlectricity/decoder.rb +205 -199
  29. data/lib/erlectricity/encoder.rb +49 -35
  30. data/lib/erlectricity/errors/decode_error.rb +1 -1
  31. data/lib/erlectricity/errors/encode_error.rb +1 -1
  32. data/lib/erlectricity/errors/erlectricity_error.rb +1 -1
  33. data/lib/erlectricity/matcher.rb +15 -32
  34. data/lib/erlectricity/port.rb +11 -11
  35. data/lib/erlectricity/receiver.rb +54 -64
  36. data/lib/erlectricity/types/list.rb +3 -1
  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
@@ -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
@@ -3,44 +3,44 @@ module Erlectricity
3
3
  attr_reader :input, :output
4
4
  attr_reader :skipped
5
5
  attr_reader :queue
6
-
6
+
7
7
  def initialize(input=STDIN, output=STDOUT)
8
8
  @input = input
9
9
  @output = output
10
-
10
+
11
11
  input.sync = true
12
12
  output.sync = true
13
-
13
+
14
14
  @encoder = Erlectricity::Encoder.new(nil)
15
15
  @skipped = []
16
16
  @queue = []
17
17
  end
18
-
18
+
19
19
  def receive
20
20
  queue.empty? ? read_from_input : queue.shift
21
21
  end
22
-
22
+
23
23
  def send(term)
24
24
  @encoder.out = StringIO.new('', 'w')
25
25
  @encoder.write_any(term)
26
26
  data = @encoder.out.string
27
27
  output.write([data.length].pack("N"))
28
- output.write data
28
+ output.write(data)
29
29
  end
30
-
30
+
31
31
  def restore_skipped
32
32
  @queue = self.skipped + self.queue
33
33
  end
34
-
34
+
35
35
  private
36
+
36
37
  def read_from_input
37
38
  raw = input.read(4)
38
39
  return nil unless raw
39
-
40
+
40
41
  packet_length = raw.unpack('N').first
41
42
  data = input.read(packet_length)
42
- result = Erlectricity::Decoder.read_any_from(data)
43
- result
43
+ Erlectricity::Decoder.decode(data)
44
44
  end
45
45
  end
46
46
  end
@@ -1,79 +1,69 @@
1
1
  module Erlectricity
2
- class Receiver
3
-
4
- attr_accessor :port
5
- attr_accessor :parent
6
- attr_accessor :matchers
7
-
8
- RECEIVE_LOOP = Object.new
9
- NO_MATCH = Object.new
10
-
11
- def initialize(port, parent=nil, &block)
12
- @port = port
13
- @parent = parent
14
- @matchers = []
15
- block.call self if block
16
- end
17
-
18
- def process(arg)
19
- matcher = @matchers.find{|r| r.matches? arg}
2
+ class Receiver
3
+ attr_accessor :port
4
+ attr_accessor :parent
5
+ attr_accessor :matchers
6
+
7
+ RECEIVE_LOOP = Object.new
8
+ NO_MATCH = Object.new
20
9
 
21
- if(matcher)
22
- port.restore_skipped
23
- matcher.run arg
24
- else
25
- NO_MATCH
10
+ def initialize(port, parent = nil, &block)
11
+ @port = port
12
+ @parent = parent
13
+ @matchers = []
14
+ block.call(self) if block
26
15
  end
27
- end
28
-
29
- def when(*args, &block)
30
- args = args.map do |a|
31
- case a
32
- when Condition then a
33
- when Class then TypeCondition.new(a)
34
- else StaticCondition.new(a)
16
+
17
+ def process(arg)
18
+ matcher = @matchers.find { |r| r.matches?(arg) }
19
+
20
+ if matcher
21
+ port.restore_skipped
22
+ matcher.run(arg)
23
+ else
24
+ NO_MATCH
35
25
  end
36
26
  end
37
-
38
- args = args.first if args.length == 1
39
- @matchers << Matcher.new(self, args, block)
40
- end
41
-
42
- def run
43
-
44
- loop do
45
- msg = port.receive
46
- return if msg.nil?
47
-
48
- case result = process(msg)
49
- when RECEIVE_LOOP then next
50
- when NO_MATCH
51
- port.skipped << msg
52
- next
53
- else
54
- break result
27
+
28
+ def when(arg, &block)
29
+ condition = Condition.for(arg)
30
+ @matchers << Matcher.new(self, condition, block)
31
+ end
32
+
33
+ def run
34
+ loop do
35
+ msg = port.receive
36
+ return if msg.nil?
37
+
38
+ case result = process(msg)
39
+ when RECEIVE_LOOP then next
40
+ when NO_MATCH
41
+ port.skipped << msg
42
+ next
43
+ else
44
+ break result
45
+ end
55
46
  end
56
47
  end
57
- end
58
-
59
- def receive(&block)
60
- Receiver.new(port, self, &block).run
61
- end
62
48
 
63
- def receive_loop
64
- RECEIVE_LOOP
65
- end
66
-
67
- def send!(*term)
68
- term = term.first if term.length == 1
69
- port.send(term)
49
+ def receive(&block)
50
+ Receiver.new(port, self, &block).run
51
+ end
52
+
53
+ def receive_loop
54
+ RECEIVE_LOOP
55
+ end
56
+
57
+ def send!(term)
58
+ port.send(term)
59
+ end
70
60
  end
71
61
  end
72
- end
73
-
74
62
 
75
63
  module Kernel
76
- def receive(input=STDIN, output=STDOUT, &block)
64
+ def receive(input = nil, output = nil, &block)
65
+ input ||= IO.new(3)
66
+ output ||= IO.new(4)
77
67
  Erlectricity::Receiver.new(Erlectricity::Port.new(input, output), nil, &block).run
78
68
  end
79
69
  end
@@ -1 +1,3 @@
1
- class Erlectricity::List < Array ; end
1
+ class Erlectricity::List < Array
2
+
3
+ end
@@ -6,14 +6,14 @@ context "Erlectricity::StaticConditions" do
6
6
  Erlectricity::StaticCondition.new([:foo]).satisfies?([:foo]).should == true
7
7
  Erlectricity::StaticCondition.new(3).satisfies?(3).should == true
8
8
  end
9
-
9
+
10
10
  specify "should not satisfy on different values" do
11
11
  Erlectricity::StaticCondition.new(:foo).satisfies?("foo").should == false
12
12
  Erlectricity::StaticCondition.new([:foo]).satisfies?(:foo).should == false
13
13
  Erlectricity::StaticCondition.new(Object.new).satisfies?(Object.new).should == false
14
14
  Erlectricity::StaticCondition.new(3).satisfies?(3.0).should == false
15
15
  end
16
-
16
+
17
17
  specify "should not produce any bindings" do
18
18
  s = Erlectricity::StaticCondition.new(:foo)
19
19
  s.binding_for(:foo).should == nil
@@ -29,25 +29,24 @@ context "Erlectricity::TypeConditions" do
29
29
  Erlectricity::TypeCondition.new(Array).satisfies?([]).should == true
30
30
  Erlectricity::TypeCondition.new(Fixnum).satisfies?(3).should == true
31
31
  end
32
-
32
+
33
33
  specify "should be satisfied when the arg is of a descendent class" do
34
34
  Erlectricity::TypeCondition.new(Object).satisfies?(:foo).should == true
35
35
  Erlectricity::TypeCondition.new(Object).satisfies?("foo").should == true
36
36
  Erlectricity::TypeCondition.new(Object).satisfies?(3).should == true
37
37
  end
38
-
38
+
39
39
  specify "should not be satisfied when the arg is of a different class" do
40
40
  Erlectricity::TypeCondition.new(String).satisfies?(:foo).should == false
41
41
  Erlectricity::TypeCondition.new(Symbol).satisfies?("foo").should == false
42
42
  Erlectricity::TypeCondition.new(Fixnum).satisfies?(3.0).should == false
43
43
  end
44
-
44
+
45
45
  specify "should bind the arg with no transormations" do
46
46
  s = Erlectricity::TypeCondition.new(Symbol)
47
47
  s.binding_for(:foo).should == :foo
48
48
  s.binding_for(:bar).should == :bar
49
49
  end
50
-
51
50
  end
52
51
 
53
52
  context "Erlectricity::HashConditions" do
@@ -55,17 +54,17 @@ context "Erlectricity::HashConditions" do
55
54
  Erlectricity::HashCondition.new.satisfies?([[:foo, 3], [:bar, Object.new]]).should == true
56
55
  Erlectricity::HashCondition.new.satisfies?([[:foo, 3]]).should == true
57
56
  end
58
-
57
+
59
58
  specify "should satisfy on empty arrays" do
60
59
  Erlectricity::HashCondition.new.satisfies?([]).should == true
61
60
  end
62
-
61
+
63
62
  specify "should nat satisfy other args" do
64
63
  Erlectricity::HashCondition.new.satisfies?(:foo).should == false
65
64
  Erlectricity::HashCondition.new.satisfies?("foo").should == false
66
65
  Erlectricity::HashCondition.new.satisfies?(3.0).should == false
67
66
  end
68
-
67
+
69
68
  specify "should bind to a Hash" do
70
69
  s = Erlectricity::HashCondition.new()
71
70
  s.binding_for([[:foo, 3], [:bar, [3,4,5]]]).should == {:foo => 3, :bar => [3,4,5] }