autodeps 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|