autodeps 0.0.1 → 0.0.2
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.
- checksums.yaml +4 -4
- data/Gemfile +1 -0
- data/README.md +84 -0
- data/autodeps.gemspec +2 -0
- data/lib/autodeps.rb +1 -0
- data/lib/autodeps/autodeps.rb +141 -4
- data/lib/autodeps/computation.rb +45 -10
- data/lib/autodeps/dependency.rb +8 -4
- data/lib/autodeps/version.rb +1 -1
- data/test/autodep_test.rb +192 -0
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 78d3bef272635791a3db6c22f57a91207ce38736
|
4
|
+
data.tar.gz: a749c7af7789588b1842ae39fccfe1f3de603569
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fb3fa0654c138919354941a09988bb8c2392f9da56e6fcca577fdb7334cc6a18d61998d18aeb68bc562be0d4bd2e23e7f377657194142226fea22c59231228d8
|
7
|
+
data.tar.gz: 511df559b1d3fefd0667bddcf7983c4859d3f3df55e42d8b21032e4b56e537cdbe7fd21ac60d5ddf8596961dc210103d1fcdc50cac7c30a0cbfd6853129aba12
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -19,6 +19,90 @@ Or install it yourself as:
|
|
19
19
|
## Usage
|
20
20
|
|
21
21
|
TODO: Write usage instructions here
|
22
|
+
two parts
|
23
|
+
1.ReactivePersistency
|
24
|
+
2.ReactiveData
|
25
|
+
|
26
|
+
ReactivePersistency is used in data storage layer, like you have an activerecord/mongomapper persistency layer,
|
27
|
+
when some properties you want to copy to other table(denormalization), and want to be automatically synced when
|
28
|
+
main table's property changes,
|
29
|
+
then just include Autodeps::Persistency and call depend_on method:
|
30
|
+
like you have User table, and Laud table, where you copy user.name to Laud.user_name and Laud.dest_user_name
|
31
|
+
```
|
32
|
+
class Laud
|
33
|
+
|
34
|
+
include MongoMapper::Document
|
35
|
+
include Autodeps::Persistency #这里添加对Autodeps::Persistency 的依赖
|
36
|
+
|
37
|
+
key :user_id, Integer, :required => true
|
38
|
+
key :user_name, String
|
39
|
+
depend_on "User", :value_mapping => {:name => :user_name} #默认可以省略 :key_mapping=> {:id=>:user_id}
|
40
|
+
|
41
|
+
key :dest_user_id, Integer, :required => true
|
42
|
+
key :dest_user_name, String
|
43
|
+
depend_on "User", :key_mapping => {:id => :dest_user_id}, :value_mapping => {:name => :dest_user_name}
|
44
|
+
|
45
|
+
timestamps!
|
46
|
+
|
47
|
+
ensure_index([[:user_id,1],[:dest_user_id,1]])
|
48
|
+
end
|
49
|
+
```
|
50
|
+
then when you change user's name
|
51
|
+
```
|
52
|
+
user.name = "some value"
|
53
|
+
user.save
|
54
|
+
```
|
55
|
+
the name change will automatically propagated to Laud table/collection.
|
56
|
+
|
57
|
+
because in development environment, when User loads, the Laud class may not been loaded, so you may want to
|
58
|
+
do this:
|
59
|
+
#user.rb
|
60
|
+
class User
|
61
|
+
#some attributes
|
62
|
+
end
|
63
|
+
Laud #just adds a reference here to cause rails to load Laud
|
64
|
+
|
65
|
+
2.ReactiveData
|
66
|
+
what ReactiveData means, if you want to say a=b+c
|
67
|
+
if b or c is ReactiveData, then when b or c's value changes,
|
68
|
+
a's value automatically changes,it's the concept copyed from meteor:)
|
69
|
+
|
70
|
+
see autodeps_test.rb
|
71
|
+
where a,b is ReactiveData
|
72
|
+
|
73
|
+
def test_reactive_integer
|
74
|
+
a = Autodeps::ReactiveData.new(3)
|
75
|
+
b = nil
|
76
|
+
computation = Autodeps.autorun do |computation| #the block will be rerun if a changes
|
77
|
+
b = a.value
|
78
|
+
end
|
79
|
+
assert_equal b,3
|
80
|
+
|
81
|
+
a.change_to 5
|
82
|
+
|
83
|
+
assert_equal b,5
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_reactive_integer_add
|
87
|
+
a = Autodeps::ReactiveData.new(3)
|
88
|
+
b = Autodeps::ReactiveData.new(5)
|
89
|
+
c = nil
|
90
|
+
computation = Autodeps.autorun do |computation| #the block will be rerun if a or b changes
|
91
|
+
c = a.value + b.value
|
92
|
+
end
|
93
|
+
assert_equal c,8
|
94
|
+
|
95
|
+
a.change_to 5
|
96
|
+
|
97
|
+
assert_equal c,10
|
98
|
+
|
99
|
+
b.change_to 15
|
100
|
+
|
101
|
+
assert_equal c,20
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
|
22
106
|
|
23
107
|
## Contributing
|
24
108
|
|
data/autodeps.gemspec
CHANGED
data/lib/autodeps.rb
CHANGED
data/lib/autodeps/autodeps.rb
CHANGED
@@ -1,8 +1,13 @@
|
|
1
|
+
require 'logger'
|
1
2
|
module Autodeps
|
2
|
-
|
3
|
-
|
3
|
+
class << self
|
4
|
+
attr_accessor :logger
|
5
|
+
end
|
6
|
+
self.logger = Logger.new(STDOUT)
|
7
|
+
@pending_computations = ThreadSafe::Array.new
|
8
|
+
@after_flush_callbacks = ThreadSafe::Array.new
|
4
9
|
@constructingComputation = false
|
5
|
-
|
10
|
+
|
6
11
|
|
7
12
|
class << self
|
8
13
|
attr_accessor :active
|
@@ -16,9 +21,26 @@ module Autodeps
|
|
16
21
|
@constructingComputation = true
|
17
22
|
c = Computation.new(block, Autodeps.current_computation);
|
18
23
|
|
24
|
+
|
25
|
+
if (Autodeps.active)
|
26
|
+
Autodeps.on_invalidate do
|
27
|
+
c.stop();
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
19
31
|
return c
|
20
32
|
end
|
21
33
|
|
34
|
+
def nonreactive(&f)
|
35
|
+
previous = self.current_computation;
|
36
|
+
self.current_computation = nil;
|
37
|
+
begin
|
38
|
+
f.call()
|
39
|
+
ensure
|
40
|
+
self.current_computation = previous;
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
22
44
|
def flush
|
23
45
|
|
24
46
|
#if (inFlush)
|
@@ -59,10 +81,125 @@ module Autodeps
|
|
59
81
|
|
60
82
|
end
|
61
83
|
|
84
|
+
def on_invalidate(&f)
|
85
|
+
if (! Autodeps.active)
|
86
|
+
raise "AutoDeps.on_invalidate requires a currentComputation"
|
87
|
+
end
|
88
|
+
|
89
|
+
Autodeps.current_computation.on_invalidate(f);
|
90
|
+
end
|
91
|
+
|
92
|
+
def afterFlush(&f)
|
93
|
+
@after_flush_callbacks.push(f);
|
94
|
+
end
|
95
|
+
|
96
|
+
def isolateValue(equals=nil, &f)
|
97
|
+
raise "must define a block in isolateValue" unless f
|
98
|
+
if (!Autodeps.active)
|
99
|
+
return f.call();
|
100
|
+
end
|
101
|
+
|
102
|
+
result_dep = Autodeps::Dependency.new;
|
103
|
+
orig_result = nil
|
104
|
+
Autodeps.autorun do |c|
|
105
|
+
result = f.call();
|
106
|
+
if (c.first_run)
|
107
|
+
orig_result = result;
|
108
|
+
elsif (!(equals ? equals(result, orig_result) :
|
109
|
+
result == orig_result))
|
110
|
+
result_dep.changed();
|
111
|
+
end
|
112
|
+
end
|
113
|
+
result_dep.depend();
|
114
|
+
|
115
|
+
return orig_result;
|
116
|
+
end
|
117
|
+
|
118
|
+
def embox(equals=nil, &func)
|
119
|
+
raise "must define a block in embox" unless func
|
120
|
+
|
121
|
+
|
122
|
+
curResult = nil;
|
123
|
+
#There's one shared Dependency and Computation for all callers of
|
124
|
+
|
125
|
+
# our box function. It gets kicked off if necessary, and when
|
126
|
+
# there are no more dependents, it gets stopped to avoid leaking
|
127
|
+
# memory.
|
128
|
+
resultDep = nil;
|
129
|
+
computation = nil;
|
130
|
+
|
131
|
+
return proc do
|
132
|
+
if (!computation)
|
133
|
+
if (!Autodeps.active)
|
134
|
+
# Not in a reactive context. Just call func, and don't start a
|
135
|
+
# computation if there isn't one running already.
|
136
|
+
break func.call();
|
137
|
+
end
|
138
|
+
|
139
|
+
# No running computation, so kick one off. Since this computation
|
140
|
+
# will be shared, avoid any association with the current computation
|
141
|
+
# by using `Deps.nonreactive`.
|
142
|
+
resultDep = Autodeps::Dependency.new;
|
143
|
+
|
144
|
+
computation = Autodeps.nonreactive do
|
145
|
+
break Autodeps.autorun do |c|
|
146
|
+
oldResult = curResult;
|
147
|
+
curResult = func.call();
|
148
|
+
if (!c.first_run)
|
149
|
+
if (!(equals ? equals.call(curResult, oldResult) :
|
150
|
+
curResult == oldResult))
|
151
|
+
resultDep.changed();
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
if (Autodeps.active)
|
159
|
+
is_new = resultDep.depend();
|
160
|
+
if (is_new)
|
161
|
+
# For each new dependent, schedule a task for after that dependents
|
162
|
+
# invalidation time and the subsequent flush. The task checks
|
163
|
+
# whether the computation should be torn down.
|
164
|
+
Autodeps.on_invalidate do
|
165
|
+
if (resultDep && !resultDep.hasDependents())
|
166
|
+
Autodeps.afterFlush do
|
167
|
+
# use a second afterFlush to bump ourselves to the END of the
|
168
|
+
# flush, after computation re-runs have had a chance to
|
169
|
+
# re-establish their connections to our computation.
|
170
|
+
Autodeps.afterFlush do
|
171
|
+
if (resultDep && !resultDep.hasDependents())
|
172
|
+
computation.stop();
|
173
|
+
computation = nil;
|
174
|
+
resultDep = nil;
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
curResult
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def embox_value(value, equals=nil)
|
188
|
+
raise "embox_value on a direct value not implemented"
|
189
|
+
end
|
190
|
+
|
191
|
+
def active
|
192
|
+
Thread.current["Autodeps::active"]
|
193
|
+
end
|
194
|
+
|
195
|
+
def active= (active)
|
196
|
+
Thread.current["Autodeps::active"] = active
|
197
|
+
end
|
198
|
+
|
62
199
|
def current_computation
|
63
200
|
Thread.current["Autodeps::current_computation"]
|
64
201
|
end
|
65
|
-
def current_computation=(computation)
|
202
|
+
def current_computation= (computation)
|
66
203
|
Thread.current["Autodeps::current_computation"] = computation
|
67
204
|
self.active = !! computation;
|
68
205
|
end
|
data/lib/autodeps/computation.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Autodeps
|
2
2
|
class Computation
|
3
|
-
attr_accessor :stopped, :invalidated, :first_run, :parent, :block, :recomputing
|
3
|
+
attr_accessor :stopped, :invalidated, :first_run, :parent, :block, :recomputing,:_on_invalidate_callbacks
|
4
4
|
def initialize(block, parent=nil)
|
5
5
|
self.stopped = false;
|
6
6
|
self.invalidated = false;
|
@@ -9,6 +9,7 @@ module Autodeps
|
|
9
9
|
self.parent = parent;
|
10
10
|
self.block = block;
|
11
11
|
self.recomputing = false;
|
12
|
+
self._on_invalidate_callbacks = ThreadSafe::Array.new
|
12
13
|
|
13
14
|
errored = true;
|
14
15
|
begin
|
@@ -31,6 +32,9 @@ module Autodeps
|
|
31
32
|
in_compute = true;
|
32
33
|
begin
|
33
34
|
block.call(self)
|
35
|
+
#rescue => e
|
36
|
+
# Autodeps.logger.error(e.message) if Autodeps.logger
|
37
|
+
# Autodeps.logger.error(e.backtrace.join("\n")) if Autodeps.logger
|
34
38
|
ensure
|
35
39
|
Autodeps.current_computation = previous;
|
36
40
|
in_compute = false;
|
@@ -41,7 +45,12 @@ module Autodeps
|
|
41
45
|
self.recomputing = true
|
42
46
|
|
43
47
|
while (self.invalidated && !self.stopped)
|
44
|
-
|
48
|
+
begin
|
49
|
+
self.compute()
|
50
|
+
rescue => e
|
51
|
+
Autodeps.logger.error(e.message) if Autodeps.logger
|
52
|
+
Autodeps.logger.error(e.backtrace.join("\n")) if Autodeps.logger
|
53
|
+
end
|
45
54
|
end
|
46
55
|
|
47
56
|
self.recomputing = false;
|
@@ -58,26 +67,52 @@ module Autodeps
|
|
58
67
|
Autodeps::flush
|
59
68
|
end
|
60
69
|
|
61
|
-
|
62
70
|
def invalidate
|
63
|
-
|
71
|
+
##we request an immediate flush because we don't have timeout
|
64
72
|
|
65
73
|
|
66
74
|
|
67
75
|
if (! self.invalidated)
|
68
|
-
|
69
|
-
|
70
|
-
|
76
|
+
# if we're currently in _recompute(), don't enqueue
|
77
|
+
# ourselves, since we'll rerun immediately anyway.
|
78
|
+
|
71
79
|
self.invalidated = true;
|
72
|
-
|
73
|
-
|
74
|
-
|
80
|
+
self._on_invalidate_callbacks.each do |f|
|
81
|
+
f.call(); #// already bound with self as argument
|
82
|
+
end
|
83
|
+
self._on_invalidate_callbacks = ThreadSafe::Array.new;
|
75
84
|
|
85
|
+
if (! self.recomputing && ! self.stopped)
|
86
|
+
self.invalidated = true;
|
76
87
|
|
88
|
+
Autodeps.add_pending_computation(self);
|
89
|
+
require_flush();
|
90
|
+
end
|
77
91
|
|
78
92
|
# callbacks can't add callbacks, because
|
79
93
|
#self.invalidated === true.
|
94
|
+
|
95
|
+
|
80
96
|
end
|
81
97
|
end
|
98
|
+
|
99
|
+
def on_invalidate(f=nil, &block)
|
100
|
+
if block_given?
|
101
|
+
f = block
|
102
|
+
end
|
103
|
+
raise ("on_invalidate requires a block") unless f;
|
104
|
+
|
105
|
+
g = proc do
|
106
|
+
Autodeps.nonreactive do
|
107
|
+
f.call(self);
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
if (self.invalidated)
|
112
|
+
g();
|
113
|
+
else
|
114
|
+
self._on_invalidate_callbacks.push(g);
|
115
|
+
end
|
116
|
+
end
|
82
117
|
end
|
83
118
|
end
|
data/lib/autodeps/dependency.rb
CHANGED
@@ -2,7 +2,7 @@ module Autodeps
|
|
2
2
|
class Dependency
|
3
3
|
attr_accessor :dependents
|
4
4
|
def initialize
|
5
|
-
@dependents =
|
5
|
+
@dependents = ThreadSafe::Array.new
|
6
6
|
end
|
7
7
|
def depend(computation = Autodeps.current_computation)
|
8
8
|
|
@@ -12,9 +12,9 @@ module Autodeps
|
|
12
12
|
end
|
13
13
|
if !@dependents.include?(computation)
|
14
14
|
@dependents << computation
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
computation.on_invalidate do
|
16
|
+
@dependents.delete(computation)
|
17
|
+
end
|
18
18
|
return true
|
19
19
|
else
|
20
20
|
return false;
|
@@ -27,5 +27,9 @@ module Autodeps
|
|
27
27
|
computation.invalidate
|
28
28
|
end
|
29
29
|
end
|
30
|
+
|
31
|
+
def hasDependents
|
32
|
+
!@dependents.empty?
|
33
|
+
end
|
30
34
|
end
|
31
35
|
end
|
data/lib/autodeps/version.rb
CHANGED
data/test/autodep_test.rb
CHANGED
@@ -48,4 +48,196 @@ class AutoDepsTest < Test::Unit::TestCase
|
|
48
48
|
|
49
49
|
assert_equal c,20
|
50
50
|
end
|
51
|
+
|
52
|
+
def test_exception
|
53
|
+
a = Autodeps::ReactiveData.new(3)
|
54
|
+
b = Autodeps::ReactiveData.new(5)
|
55
|
+
c = nil
|
56
|
+
computation = nil
|
57
|
+
begin
|
58
|
+
Autodeps.autorun do |_computation|
|
59
|
+
computation = _computation
|
60
|
+
c = a.value + b.value
|
61
|
+
dd
|
62
|
+
end
|
63
|
+
rescue
|
64
|
+
end
|
65
|
+
#puts computation
|
66
|
+
#assert_equal c,8
|
67
|
+
#
|
68
|
+
#a.change_to 5
|
69
|
+
#
|
70
|
+
#assert_equal c,10
|
71
|
+
#
|
72
|
+
#b.change_to 15
|
73
|
+
#
|
74
|
+
#assert_equal c,20
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_isolation
|
78
|
+
a = Autodeps::ReactiveData.new(3)
|
79
|
+
b = Autodeps::ReactiveData.new(5)
|
80
|
+
c = nil
|
81
|
+
count = 0
|
82
|
+
computation = nil
|
83
|
+
result = nil
|
84
|
+
Autodeps.autorun do ###1
|
85
|
+
count += 1
|
86
|
+
result = Autodeps.isolateValue do ###2
|
87
|
+
a.value >= 3
|
88
|
+
end
|
89
|
+
end
|
90
|
+
assert_equal true, result
|
91
|
+
assert_equal 1, count #the ###1 blocks gets run first_time
|
92
|
+
a.change_to 5
|
93
|
+
assert_equal true, result
|
94
|
+
assert_equal 1, count #the ###1 blocks doesn't gets run again because ###2's value doesn't change, the isolateValue call isolates it
|
95
|
+
a.change_to 2
|
96
|
+
assert_equal false, result
|
97
|
+
assert_equal 2, count #the ###1 blocks gets run again, because the isolated block's value changes
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_embox
|
102
|
+
a = Autodeps::ReactiveData.new(3)
|
103
|
+
b = Autodeps::ReactiveData.new(5)
|
104
|
+
c = nil
|
105
|
+
count = 0
|
106
|
+
|
107
|
+
inner = proc do
|
108
|
+
a.value
|
109
|
+
count += 1
|
110
|
+
end
|
111
|
+
|
112
|
+
outter = Autodeps.embox do
|
113
|
+
inner.call
|
114
|
+
end
|
115
|
+
|
116
|
+
Autodeps.autorun do ###1
|
117
|
+
inner.call
|
118
|
+
end
|
119
|
+
Autodeps.autorun do ###1
|
120
|
+
inner.call
|
121
|
+
end
|
122
|
+
assert_equal 2, count
|
123
|
+
|
124
|
+
|
125
|
+
a.change_to 4
|
126
|
+
assert_equal 4, count
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_embox1
|
130
|
+
a = Autodeps::ReactiveData.new(3)
|
131
|
+
b = Autodeps::ReactiveData.new(5)
|
132
|
+
c = nil
|
133
|
+
count = 0
|
134
|
+
|
135
|
+
inner = proc do
|
136
|
+
a.value
|
137
|
+
count += 1
|
138
|
+
end
|
139
|
+
|
140
|
+
outter = Autodeps.embox do
|
141
|
+
inner.call
|
142
|
+
end
|
143
|
+
|
144
|
+
Autodeps.autorun do ###1
|
145
|
+
outter.call
|
146
|
+
end
|
147
|
+
Autodeps.autorun do ###1
|
148
|
+
outter.call
|
149
|
+
end
|
150
|
+
assert_equal 1, count
|
151
|
+
|
152
|
+
|
153
|
+
a.change_to 4
|
154
|
+
assert_equal 2, count
|
155
|
+
end
|
156
|
+
|
157
|
+
def test_nested_computation
|
158
|
+
a = Autodeps::ReactiveData.new(3)
|
159
|
+
b = Autodeps::ReactiveData.new(5)
|
160
|
+
|
161
|
+
count_1 = 0
|
162
|
+
count_2 = 0
|
163
|
+
compuation1 = nil
|
164
|
+
compuation2 = nil
|
165
|
+
|
166
|
+
compuation1 = Autodeps.autorun do ###1
|
167
|
+
a.value
|
168
|
+
count_1 += 1
|
169
|
+
compuation2 = Autodeps.autorun do ###1
|
170
|
+
b.value
|
171
|
+
count_2 += 1
|
172
|
+
puts "b is " + b.value.to_s + " , count: " + count_2.to_s
|
173
|
+
end
|
174
|
+
end
|
175
|
+
assert_equal 1, count_1
|
176
|
+
assert_equal 1, count_2
|
177
|
+
tmp_compuation1 = compuation1
|
178
|
+
tmp_compuation2 = compuation2
|
179
|
+
b.change_to 2
|
180
|
+
|
181
|
+
assert_equal 1, count_1
|
182
|
+
assert_equal 2, count_2
|
183
|
+
assert_equal tmp_compuation1, compuation1
|
184
|
+
assert_equal tmp_compuation2, compuation2
|
185
|
+
|
186
|
+
a.change_to 15
|
187
|
+
#todo: clear b's deps's 2 sizes array
|
188
|
+
#in which one(the original one) is stopped,
|
189
|
+
#so we need to sometime clear in order not to
|
190
|
+
#let the deps grow larger and larger.
|
191
|
+
assert_equal 2, count_1
|
192
|
+
assert_equal 3, count_2
|
193
|
+
assert_equal tmp_compuation1, compuation1
|
194
|
+
assert_not_equal tmp_compuation2, compuation2
|
195
|
+
|
196
|
+
puts "before"
|
197
|
+
b.change_to 10
|
198
|
+
assert_equal 4, count_2
|
199
|
+
puts "after"
|
200
|
+
|
201
|
+
end
|
202
|
+
|
203
|
+
def test_thread
|
204
|
+
a = Autodeps::ReactiveData.new(3)
|
205
|
+
b = Autodeps::ReactiveData.new(5)
|
206
|
+
c = nil
|
207
|
+
computation = Autodeps.autorun do |computation|
|
208
|
+
c = a.value + b.value
|
209
|
+
end
|
210
|
+
assert_equal c,8
|
211
|
+
|
212
|
+
thread = Thread.new do
|
213
|
+
a.change_to 5
|
214
|
+
end
|
215
|
+
thread.join
|
216
|
+
assert_equal c,10
|
217
|
+
|
218
|
+
thread = Thread.new do
|
219
|
+
b.change_to 15
|
220
|
+
end
|
221
|
+
thread.join
|
222
|
+
assert_equal c,20
|
223
|
+
end
|
224
|
+
|
225
|
+
def test_active
|
226
|
+
a = Autodeps::ReactiveData.new(3)
|
227
|
+
b = Autodeps::ReactiveData.new(5)
|
228
|
+
c = nil
|
229
|
+
computation = Autodeps.autorun do |computation|
|
230
|
+
c = a.value + b.value
|
231
|
+
end
|
232
|
+
assert_equal c,8
|
233
|
+
|
234
|
+
|
235
|
+
thread = Thread.new do
|
236
|
+
assert_equal nil, Autodeps.active
|
237
|
+
end
|
238
|
+
thread.join
|
239
|
+
|
240
|
+
end
|
241
|
+
|
242
|
+
|
51
243
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: autodeps
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- femto
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-02-
|
11
|
+
date: 2014-02-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - '>='
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: thread_safe
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
41
55
|
description: autodeps
|
42
56
|
email:
|
43
57
|
- femtowin@gmail.com
|