dataflow 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/HISTORY CHANGED
@@ -1,4 +1,26 @@
1
- == trunk
1
+ == 0.3.0 / 2009-08-29
2
+
3
+ * Major enhancements
4
+
5
+ * "flow" abstraction for threading (use it to create threads and optionally
6
+ pass it a variable to be bound output, or override it to modify need_later
7
+ for other threading strategies such as thread pools)
8
+
9
+ * Dataflow::FutureQueue
10
+
11
+ * Nested binding through variables possible
12
+
13
+ * Minor enhancements
14
+
15
+ * Better #inspect and UnificationError debugging output
16
+
17
+ * "barrier" abstraction for manually preventing execution until variable
18
+ arguments have been bound
19
+
20
+ * Use mixin methods as class/module methods optionally
21
+ e.g. Dataflow.local {|v| v }
22
+
23
+ == 0.2.1 / 2009-07-29
2
24
 
3
25
  * Minor enhancements
4
26
 
@@ -21,8 +43,7 @@
21
43
 
22
44
  * Minor enhancements
23
45
 
24
- * Got the "require_path" set correctly so rubygems can be used =)
25
-
46
+ * Got the "require_path" set correctly so rubygems can be used =)
26
47
 
27
48
  == 0.1.0 / 2009-06-13
28
49
 
@@ -1,7 +1,7 @@
1
1
  require 'monitor'
2
2
 
3
3
  module Dataflow
4
- VERSION = "0.2.1"
4
+ VERSION = "0.3.0"
5
5
 
6
6
  def self.included(cls)
7
7
  class << cls
@@ -31,13 +31,26 @@ module Dataflow
31
31
  Variable.new &block
32
32
  end
33
33
 
34
+ def barrier(*variables)
35
+ variables.each{|v| v.__wait__ }
36
+ end
37
+
38
+ def flow(output=nil, &block)
39
+ Thread.new do
40
+ result = block.call
41
+ unify output, result if output
42
+ end
43
+ end
44
+
34
45
  def need_later(&block)
35
46
  local do |future|
36
- Thread.new { unify future, block.call }
47
+ flow { unify future, block.call }
37
48
  future
38
49
  end
39
50
  end
40
51
 
52
+ extend self
53
+
41
54
  # Note that this class uses instance variables directly rather than nicely
42
55
  # initialized instance variables in get/set methods for memory and
43
56
  # performance reasons
@@ -53,7 +66,8 @@ module Dataflow
53
66
  LOCK.synchronize do
54
67
  __activate_trigger__ if @__trigger__
55
68
  if @__bound__
56
- raise UnificationError if self != value
69
+ return @__value__.__unify__(value) if @__value__.__dataflow__? rescue nil
70
+ raise UnificationError, "#{@__value__.inspect} != #{value.inspect}" if self != value
57
71
  else
58
72
  @__value__ = value
59
73
  @__bound__ = true
@@ -70,10 +84,9 @@ module Dataflow
70
84
  @__trigger__ = nil # GC
71
85
  end
72
86
 
73
- def method_missing(name, *args, &block)
87
+ def __wait__
74
88
  LOCK.synchronize do
75
- unless @__bound__
76
- return '#<Dataflow::Variable unbound>' if name == :inspect
89
+ unless @__bound__
77
90
  if @__trigger__
78
91
  __activate_trigger__
79
92
  else
@@ -81,8 +94,17 @@ module Dataflow
81
94
  end
82
95
  end
83
96
  end unless @__bound__
97
+ end
98
+
99
+ def method_missing(name, *args, &block)
100
+ return "#<Dataflow::Variable:#{__id__} unbound>" if !@__bound__ && name == :inspect
101
+ __wait__
84
102
  @__value__.__send__(name, *args, &block)
85
103
  end
104
+
105
+ def __dataflow__?
106
+ true
107
+ end
86
108
  end
87
109
 
88
110
  UnificationError = Class.new StandardError
@@ -90,3 +112,4 @@ end
90
112
 
91
113
  require "#{File.dirname(__FILE__)}/dataflow/port"
92
114
  require "#{File.dirname(__FILE__)}/dataflow/actor"
115
+ require "#{File.dirname(__FILE__)}/dataflow/future_queue"
@@ -0,0 +1,24 @@
1
+ module Dataflow
2
+ class FutureQueue
3
+ include Dataflow
4
+ declare :push_port, :pop_port
5
+
6
+ def initialize
7
+ local do |pushed, popped|
8
+ unify push_port, Dataflow::Port.new(pushed)
9
+ unify pop_port, Dataflow::Port.new(popped)
10
+
11
+ Thread.new {
12
+ loop do
13
+ barrier pushed.head, popped.head
14
+ unify popped.head, pushed.head
15
+ pushed, popped = pushed.tail, popped.tail
16
+ end
17
+ }
18
+ end
19
+ end
20
+
21
+ def push(x) push_port.send x end
22
+ def pop(x) pop_port.send x end
23
+ end
24
+ end
@@ -0,0 +1,25 @@
1
+ require "#{File.dirname(__FILE__)}/spec_helper"
2
+
3
+ describe 'A barrier' do
4
+ it 'waits for variables to be bound before continuing' do
5
+ local do |x, y, barrier_broken|
6
+ Thread.new do
7
+ barrier x, y
8
+ unify barrier_broken, true
9
+ end
10
+ Thread.new { unify x, :x }
11
+ Thread.new { unify y, :y }
12
+ barrier_broken.should be_true
13
+ end
14
+ end
15
+
16
+ it 'continues for variables that are already bound' do
17
+ local do |x, y, barrier_broken|
18
+ unify x, :x
19
+ unify y, :y
20
+ barrier x, y
21
+ unify barrier_broken, true
22
+ barrier_broken.should be_true
23
+ end
24
+ end
25
+ end
@@ -126,3 +126,26 @@ context 'Using "declare" for object-specific read-only attributes' do
126
126
  end
127
127
  end
128
128
  end
129
+
130
+ describe 'Binding a variable that proxies through another' do
131
+ it 'binds through successfully' do
132
+ local do |x, y|
133
+ lambda do
134
+ unify x, y
135
+ unify x, 1337
136
+ x.should == 1337
137
+ y.should == 1337
138
+ end.should_not raise_error
139
+ end
140
+ end
141
+ end
142
+
143
+ describe 'Using static/module method' do
144
+ it 'works like the mixin versions' do
145
+ Dataflow.local do |big_cat, small_cat|
146
+ Thread.new { Dataflow.unify big_cat, small_cat.upcase }
147
+ Dataflow.unify small_cat, 'cat'
148
+ big_cat.should == 'CAT'
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,25 @@
1
+ require "#{File.dirname(__FILE__)}/spec_helper"
2
+
3
+ describe 'Using flow without a parameter' do
4
+ it 'works like normal threads' do
5
+ local do |big_cat, small_cat|
6
+ flow { unify big_cat, small_cat.upcase }
7
+ unify small_cat, 'cat'
8
+ big_cat.should == 'CAT'
9
+ end
10
+ end
11
+ end
12
+
13
+ describe 'Using flow with a parameter' do
14
+ it 'binds the parameter to the last line of the block' do
15
+ local do |big_cat, small_cat, output|
16
+ flow(output) do
17
+ unify big_cat, small_cat.upcase
18
+ 'returned'
19
+ end
20
+ unify small_cat, 'cat'
21
+ big_cat.should == 'CAT'
22
+ output.should == 'returned'
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,31 @@
1
+ require "#{File.dirname(__FILE__)}/spec_helper"
2
+
3
+ describe 'A future queue' do
4
+ it 'accepts synchronous pushes and pops' do
5
+ local do |queue, first, second, third|
6
+ unify queue, Dataflow::FutureQueue.new
7
+ queue.pop first
8
+ queue.pop second
9
+ queue.push 1
10
+ queue.push 2
11
+ queue.push 3
12
+ queue.pop third
13
+
14
+ [first, second, third].should == [1, 2, 3]
15
+ end
16
+ end
17
+
18
+ it 'accepts asynchronous pushes and pops' do
19
+ local do |queue, first, second, third|
20
+ unify queue, Dataflow::FutureQueue.new
21
+ Thread.new { queue.pop first }
22
+ Thread.new { queue.pop second }
23
+ Thread.new { queue.push 1 }
24
+ Thread.new { queue.push 2 }
25
+ Thread.new { queue.push 3 }
26
+ Thread.new { queue.pop third }
27
+
28
+ [first, second, third].sort.should == [1, 2, 3]
29
+ end
30
+ end
31
+ end
@@ -3,7 +3,7 @@ require "#{File.dirname(__FILE__)}/spec_helper"
3
3
  describe "An unbound variable" do
4
4
  it "should be inspectable for debugging purposes" do
5
5
  local do |unbound|
6
- unbound.inspect.should == "#<Dataflow::Variable unbound>"
6
+ unbound.inspect.should =~ /#<Dataflow::Variable:[0-9]+ unbound>/
7
7
  end
8
8
  end
9
9
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dataflow
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Larry Diehl
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-07-30 00:00:00 -07:00
12
+ date: 2009-08-29 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -29,6 +29,7 @@ files:
29
29
  - dataflow.rb
30
30
  - dataflow/actor.rb
31
31
  - dataflow/equality.rb
32
+ - dataflow/future_queue.rb
32
33
  - dataflow/port.rb
33
34
  - examples/data_driven.rb
34
35
  - examples/dataflow_http_gets.rb
@@ -68,9 +69,12 @@ specification_version: 2
68
69
  summary: Dataflow concurrency for Ruby (inspired by the Oz language)
69
70
  test_files:
70
71
  - spec/actor_spec.rb
72
+ - spec/barrier_spec.rb
71
73
  - spec/by_need_spec.rb
72
74
  - spec/dataflow_spec.rb
73
75
  - spec/equality_spec.rb
76
+ - spec/flow_spec.rb
77
+ - spec/future_queue_spec.rb
74
78
  - spec/inspect_spec.rb
75
79
  - spec/need_later_spec.rb
76
80
  - spec/port_spec.rb