erlectricity 0.2.1 → 1.0.0

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 (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] }