dataflow 0.2.1 → 0.3.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.
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