rachinations 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -16
- data/Gemfile.lock +2 -0
- data/lib/rachinations/domain/diagrams/diagram.rb +46 -14
- data/lib/rachinations/domain/edges/edge.rb +34 -20
- data/lib/rachinations/domain/modules/common/hash_init.rb +2 -1
- data/lib/rachinations/domain/modules/common/invariant.rb +2 -2
- data/lib/rachinations/domain/modules/common/refiners/number_modifiers.rb +22 -0
- data/lib/rachinations/domain/nodes/converter.rb +5 -5
- data/lib/rachinations/domain/nodes/gate.rb +77 -0
- data/lib/rachinations/domain/nodes/node.rb +69 -36
- data/lib/rachinations/domain/nodes/pool.rb +121 -74
- data/lib/rachinations/domain/nodes/resourceful_node.rb +0 -1
- data/lib/rachinations/domain/nodes/sink.rb +3 -0
- data/lib/rachinations/domain/nodes/source.rb +3 -2
- data/lib/rachinations/domain/resource_bag.rb +3 -4
- data/lib/rachinations/dsl/bad_dsl.rb +2 -0
- data/lib/rachinations/dsl/bootstrap.rb +59 -0
- data/lib/rachinations/dsl/diagram_shorthand_methods.rb +107 -0
- data/lib/rachinations/dsl/helpers/parser.rb +170 -0
- data/lib/rachinations/extras/constant_hash.rb +25 -0
- data/lib/rachinations/extras/fifo.rb +25 -19
- data/lib/rachinations/helpers/edge_helper.rb +40 -0
- data/lib/rachinations/utils/string_helper.rb +7 -0
- data/lib/rachinations/version.rb +1 -1
- data/lib/rachinations.rb +13 -5
- data/rachinations.gemspec +3 -2
- data/testing/simulations/modelo1.rb +1 -1
- data/testing/simulations/sequencial.rb +1 -1
- data/testing/simulations/sobonito.rb +1 -1
- data/testing/simulations/sobonitowhile.rb +1 -1
- data/testing/simulations/whatIwish1.rb +2 -2
- data/testing/spec/canon/conditions_spec.rb +3 -4
- data/testing/spec/converter_spec.rb +3 -4
- data/testing/spec/diagram_spec.rb +293 -238
- data/testing/spec/edge_spec.rb +28 -14
- data/testing/spec/gate_spec.rb +34 -0
- data/testing/spec/pool_spec.rb +8 -10
- data/testing/spec/release1/dsl_spec.rb +204 -0
- data/testing/spec/spec_helper.rb +1 -0
- data/testing/spec/xexeo_spec.rb +39 -40
- metadata +30 -8
- data/lib/rachinations/domain/edges/random_edge.rb +0 -4
- data/lib/rachinations/dsl/dsl.rb +0 -63
- data/testing/spec/canon/trigger_spec.rb +0 -128
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b207a47240a7f2ac500c459b3ebf5a3eebbbee31
|
4
|
+
data.tar.gz: a2c6097eeb47737aab5f9b19f0f93221101911e5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3742c0dde3133a7776eaf8b7d08f134d7355806012f3f974952b46c0d32da999b4573eb75ca1aebfa7cbb7e29267d4ed9705935ed85cf9938793108139a5bc83
|
7
|
+
data.tar.gz: 2b90e71c41aad90e5858b9682d84be9a9ace1d7b45569d1956a1b3e512df16c33a3dee7b86e199a09b4c2f59a49f606ad685ddd36fa588e5802ed726f18752af
|
data/Gemfile
CHANGED
@@ -1,19 +1,4 @@
|
|
1
1
|
source 'https://rubygems.org'
|
2
2
|
|
3
3
|
# Specify your gem's dependencies in rachinations.gemspec
|
4
|
-
gemspec
|
5
|
-
|
6
|
-
|
7
|
-
# ruby '2.1.1'
|
8
|
-
#
|
9
|
-
# gem 'rake'
|
10
|
-
# gem 'activesupport','3.0.0'
|
11
|
-
# gem 'i18n'
|
12
|
-
# gem 'minitest'
|
13
|
-
# gem 'minitest-reporters'
|
14
|
-
# gem 'rspec'
|
15
|
-
# gem 'cucumber'
|
16
|
-
# gem 'coveralls', require: false
|
17
|
-
|
18
|
-
|
19
|
-
|
4
|
+
gemspec
|
data/Gemfile.lock
CHANGED
@@ -4,6 +4,7 @@ PATH
|
|
4
4
|
rachinations (0.0.3)
|
5
5
|
activesupport (= 3.0.0)
|
6
6
|
i18n (= 0.6.11)
|
7
|
+
weighted_distribution
|
7
8
|
|
8
9
|
GEM
|
9
10
|
remote: https://rubygems.org/
|
@@ -65,6 +66,7 @@ GEM
|
|
65
66
|
tins (~> 1.0)
|
66
67
|
thor (0.19.1)
|
67
68
|
tins (1.3.0)
|
69
|
+
weighted_distribution (1.0.0)
|
68
70
|
|
69
71
|
PLATFORMS
|
70
72
|
ruby
|
@@ -8,13 +8,14 @@ class Diagram
|
|
8
8
|
|
9
9
|
attr_accessor :name, :max_iterations, :nodes, :edges
|
10
10
|
|
11
|
-
def initialize(name)
|
11
|
+
def initialize(name='Anonymous diagram')
|
12
12
|
@nodes = NodeCollection.new
|
13
13
|
@edges = EdgeCollection.new
|
14
14
|
@name = name
|
15
15
|
@max_iterations = 999
|
16
16
|
end
|
17
17
|
|
18
|
+
|
18
19
|
def get_node(name)
|
19
20
|
|
20
21
|
nodes.each do |node|
|
@@ -26,12 +27,36 @@ class Diagram
|
|
26
27
|
raise RuntimeError, "Node with name='#{name}' not found."
|
27
28
|
end
|
28
29
|
|
30
|
+
def get_edge(name)
|
31
|
+
edges.each do |edge|
|
32
|
+
if edge.name == name
|
33
|
+
return edge
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
raise RuntimeError, "Edge with name='#{name}' not found."
|
38
|
+
end
|
39
|
+
|
29
40
|
def add_node!(node_klass, params)
|
30
41
|
|
31
42
|
params.store(:diagram, self)
|
32
43
|
|
44
|
+
#if there's a condition, return it, otherwise return default condition
|
45
|
+
condition = params.delete(:condition) { lambda { true } }
|
46
|
+
|
47
|
+
#similarly, if nodes are supposed to be triggered by another node
|
48
|
+
triggered_by = params.delete(:triggered_by) { nil }
|
49
|
+
|
33
50
|
node = node_klass.new(params)
|
34
51
|
|
52
|
+
node.attach_condition &condition
|
53
|
+
|
54
|
+
if !triggered_by.nil?
|
55
|
+
# ask the current class (diagram) to evaluate what node it is
|
56
|
+
triggerer = self.send(triggered_by.to_sym)
|
57
|
+
triggerer.attach_trigger(node)
|
58
|
+
end
|
59
|
+
|
35
60
|
nodes.push(node)
|
36
61
|
|
37
62
|
self
|
@@ -43,8 +68,8 @@ class Diagram
|
|
43
68
|
params.store(:diagram, self)
|
44
69
|
|
45
70
|
#we need to send the actual nodes, not their names
|
46
|
-
from = get_node(params.
|
47
|
-
to = get_node(params.
|
71
|
+
from = get_node(params.delete(:from))
|
72
|
+
to = get_node(params.delete(:to))
|
48
73
|
|
49
74
|
params.store(:from, from)
|
50
75
|
params.store(:to, to)
|
@@ -78,7 +103,7 @@ class Diagram
|
|
78
103
|
|
79
104
|
i=1
|
80
105
|
|
81
|
-
#if given condition block turned false, it's time to stop
|
106
|
+
# if given condition block turned false, it's time to stop
|
82
107
|
while yield i do
|
83
108
|
|
84
109
|
break unless sanity_check? i
|
@@ -106,7 +131,7 @@ class Diagram
|
|
106
131
|
def resource_count(klass=nil)
|
107
132
|
total=0
|
108
133
|
@nodes.each do |n|
|
109
|
-
total+=n.resource_count(klass)
|
134
|
+
total+=n.resource_count(type: klass)
|
110
135
|
end
|
111
136
|
total
|
112
137
|
end
|
@@ -128,7 +153,7 @@ class Diagram
|
|
128
153
|
|
129
154
|
def run_first_round!
|
130
155
|
|
131
|
-
enabled_nodes.select { |
|
156
|
+
enabled_nodes.select { |node| node.automatic? || node.start? }.shuffle.each { |node| node.trigger! }
|
132
157
|
|
133
158
|
commit_nodes!
|
134
159
|
|
@@ -136,7 +161,7 @@ class Diagram
|
|
136
161
|
|
137
162
|
def run_round!
|
138
163
|
|
139
|
-
enabled_nodes.select { |
|
164
|
+
enabled_nodes.select { |node| node.automatic? }.shuffle.each { |node| node.trigger! }
|
140
165
|
|
141
166
|
commit_nodes!
|
142
167
|
|
@@ -144,26 +169,33 @@ class Diagram
|
|
144
169
|
|
145
170
|
def commit_nodes!
|
146
171
|
#only after all nodes have run do we update the actual resources and changes, to be used in the next round.
|
147
|
-
nodes.shuffle.each { |
|
172
|
+
nodes.shuffle.each { |node| node.commit! }
|
173
|
+
|
148
174
|
end
|
149
175
|
|
150
176
|
def enabled_nodes
|
151
|
-
nodes.select{|
|
177
|
+
nodes.select { |node| node.enabled? }
|
178
|
+
|
152
179
|
end
|
153
180
|
|
154
181
|
#template method
|
155
|
-
def before_round(node_no)
|
182
|
+
def before_round(node_no)
|
183
|
+
end
|
156
184
|
|
157
185
|
#template method
|
158
|
-
def after_round(node_no)
|
186
|
+
def after_round(node_no)
|
187
|
+
end
|
159
188
|
|
160
189
|
#template method
|
161
|
-
def before_run;
|
190
|
+
def before_run;
|
191
|
+
end
|
162
192
|
|
163
193
|
#template method
|
164
|
-
def after_run;
|
194
|
+
def after_run;
|
195
|
+
end
|
165
196
|
|
166
197
|
#template method
|
167
|
-
def sanity_check_message;
|
198
|
+
def sanity_check_message;
|
199
|
+
end
|
168
200
|
|
169
201
|
end
|
@@ -1,24 +1,31 @@
|
|
1
1
|
require_relative '../strategies/valid_types'
|
2
2
|
require_relative '../../domain/exceptions/no_elements_found'
|
3
|
+
require_relative '../../../../lib/rachinations/domain/modules/common/hash_init'
|
4
|
+
require_relative '../../../../lib/rachinations/domain/modules/common/refiners/number_modifiers'
|
3
5
|
|
4
6
|
class Edge
|
7
|
+
include HashInit
|
8
|
+
using NumberModifiers
|
9
|
+
|
5
10
|
|
6
11
|
attr_reader :from, :to, :name, :label, :types
|
7
12
|
|
8
13
|
|
9
14
|
def initialize(hsh)
|
10
15
|
|
11
|
-
|
16
|
+
check_options!(hsh)
|
17
|
+
|
18
|
+
params = set_defaults(hsh)
|
19
|
+
|
20
|
+
@name = params.fetch(:name, 'anonymous')
|
12
21
|
|
13
|
-
@from =
|
22
|
+
@from = params.fetch(:from)
|
14
23
|
|
15
|
-
@to =
|
24
|
+
@to = params.fetch(:to)
|
16
25
|
|
17
|
-
|
18
|
-
hsh = defaults.merge hsh
|
26
|
+
@label = params.fetch(:label)
|
19
27
|
|
20
|
-
@
|
21
|
-
@types = hsh.fetch(:types)
|
28
|
+
@types = params.fetch(:types)
|
22
29
|
|
23
30
|
end
|
24
31
|
|
@@ -31,12 +38,12 @@ class Edge
|
|
31
38
|
#
|
32
39
|
# @return [Boolean] true in case a ping! on this Edge
|
33
40
|
# would return true. False otherwise.
|
34
|
-
def test_ping?(require_all
|
41
|
+
def test_ping?(require_all:false)
|
35
42
|
return false if from.disabled? || to.disabled?
|
36
43
|
|
37
44
|
condition = strategy.condition
|
38
45
|
|
39
|
-
available_resources = from.resource_count(
|
46
|
+
available_resources = from.resource_count(expr: condition)
|
40
47
|
|
41
48
|
if available_resources == 0
|
42
49
|
false
|
@@ -45,17 +52,19 @@ class Edge
|
|
45
52
|
elsif available_resources < label && require_all
|
46
53
|
false
|
47
54
|
else
|
48
|
-
# only some resources are able to pass but it's not require_all
|
55
|
+
# only some resources are able to pass but it's not require_all,
|
56
|
+
# so the ping takes place
|
49
57
|
true
|
50
58
|
end
|
51
59
|
|
52
60
|
end
|
53
61
|
|
54
|
-
# the code is the
|
62
|
+
# the code is the same but sometimes it helps to specify what action
|
55
63
|
# we are talking about so as to make code more understandable
|
56
64
|
alias_method :test_pull?, :test_ping?
|
57
65
|
alias_method :test_push?, :test_ping?
|
58
66
|
|
67
|
+
|
59
68
|
def supports?(type)
|
60
69
|
types.empty? || types.include?(type)
|
61
70
|
end
|
@@ -107,15 +116,14 @@ class Edge
|
|
107
116
|
#
|
108
117
|
# @raise [RuntimeError] in case the receiving node or this Edge
|
109
118
|
# won't accept the resource sent.
|
110
|
-
# @param res the resource to send.
|
119
|
+
# @param res [Token] the resource to send.
|
111
120
|
def push!(res)
|
112
|
-
raise RuntimeError
|
121
|
+
raise RuntimeError, "This Edge does not support type: #{res.type}" unless supports?(res.type)
|
113
122
|
|
114
123
|
begin
|
115
|
-
to.put_resource!(res,self)
|
116
|
-
rescue
|
117
|
-
|
118
|
-
raise RuntimeError.new(e.message+" => "+'Push failed')
|
124
|
+
to.put_resource!(res, self)
|
125
|
+
rescue UnsupportedTypeError
|
126
|
+
raise RuntimeError, "unsupported type"
|
119
127
|
end
|
120
128
|
end
|
121
129
|
|
@@ -126,10 +134,12 @@ class Edge
|
|
126
134
|
# should send.
|
127
135
|
# @raise [RuntimeError] in case the other node could provide no resources
|
128
136
|
# that satisfy this condition block.
|
129
|
-
# @return a
|
130
|
-
|
137
|
+
# @return [Token,nil] a Resource that satisfies the given block or nil,
|
138
|
+
# if the pull was not performed for some reason (e.g. it's probabilistic)
|
139
|
+
def pull!(blk)
|
140
|
+
|
131
141
|
begin
|
132
|
-
res=from.take_resource!(
|
142
|
+
res=from.take_resource!(blk)
|
133
143
|
rescue => e
|
134
144
|
# just to make it clear that it bubbles
|
135
145
|
raise RuntimeError.new("Pull failed")
|
@@ -156,4 +166,8 @@ class Edge
|
|
156
166
|
}
|
157
167
|
end
|
158
168
|
|
169
|
+
def options
|
170
|
+
[:name,:label,:types,:from,:to,:diagram]
|
171
|
+
end
|
172
|
+
|
159
173
|
end
|
@@ -33,8 +33,9 @@ module HashInit
|
|
33
33
|
hsh.each_pair do |key, value|
|
34
34
|
|
35
35
|
if !options.include_option?(key) && aliases_for(key).none?{|ali| options.include_option?(ali) }
|
36
|
-
raise BadOptions.new "
|
36
|
+
raise BadOptions.new "Class #{self.class}: unknown option in constructor: :#{key} (using HashInit)"
|
37
37
|
end
|
38
|
+
|
38
39
|
end
|
39
40
|
|
40
41
|
#make sure all required ones are there
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module NumberModifiers
|
2
|
+
|
3
|
+
|
4
|
+
# allow user to modify Numbers in order to express
|
5
|
+
# percentages ( 12.percent ) and also fractions, for
|
6
|
+
# example.
|
7
|
+
refine Fixnum do
|
8
|
+
|
9
|
+
def /(other)
|
10
|
+
fdiv(other)
|
11
|
+
end
|
12
|
+
|
13
|
+
# # but Fixnums are frozen by default so they can't change state.
|
14
|
+
# # so that i can know whether the user has explicitly called #percent
|
15
|
+
# # i would like to add an instance variable to this number
|
16
|
+
def percent
|
17
|
+
fdiv(100)
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -41,7 +41,7 @@ class Converter < ResourcefulNode
|
|
41
41
|
|
42
42
|
if all?
|
43
43
|
|
44
|
-
if incoming_edges.all? { |edge| edge.test_pull?(true) } && outgoing_edges.all? { |edge| edge.test_push?(true) }
|
44
|
+
if incoming_edges.all? { |edge| edge.test_pull?(require_all: true) } && outgoing_edges.all? { |edge| edge.test_push?(require_all:true) }
|
45
45
|
pull_all!
|
46
46
|
push_all!
|
47
47
|
else
|
@@ -53,7 +53,7 @@ class Converter < ResourcefulNode
|
|
53
53
|
pull_any!
|
54
54
|
|
55
55
|
if in_conditions_met?
|
56
|
-
if outgoing_edges.all? { |edge| edge.test_push?(true) }
|
56
|
+
if outgoing_edges.all? { |edge| edge.test_push?(require_all: true) }
|
57
57
|
push_all!
|
58
58
|
clear_stored_resources!
|
59
59
|
end # converters are always push_all
|
@@ -94,7 +94,7 @@ class Converter < ResourcefulNode
|
|
94
94
|
#TODO use argument (edge) on the call to super and make sure tests still pass
|
95
95
|
# that way it's clearer that it is being passed on to super
|
96
96
|
super
|
97
|
-
resources_contributed.store(edge, Fifo.new)
|
97
|
+
resources_contributed.store(edge, Extras::Fifo.new)
|
98
98
|
self
|
99
99
|
end
|
100
100
|
|
@@ -153,7 +153,7 @@ class Converter < ResourcefulNode
|
|
153
153
|
|
154
154
|
edge.label.times do
|
155
155
|
begin
|
156
|
-
res = edge.pull!(
|
156
|
+
res = edge.pull!(blk)
|
157
157
|
rescue RuntimeError => ex
|
158
158
|
# Let's try another Edge, perhaps?
|
159
159
|
break
|
@@ -183,7 +183,7 @@ class Converter < ResourcefulNode
|
|
183
183
|
|
184
184
|
edge.label.times do
|
185
185
|
begin
|
186
|
-
res = edge.pull!(
|
186
|
+
res = edge.pull!(blk)
|
187
187
|
res=nil # we do not store the results
|
188
188
|
rescue RuntimeError => ex
|
189
189
|
raise RuntimeError.new "One edge failed to pull; the whole operation failed."
|
@@ -1,6 +1,83 @@
|
|
1
1
|
require_relative '../../domain/nodes/node'
|
2
2
|
require_relative '../../domain/nodes/resourceless_node'
|
3
3
|
|
4
|
+
require 'weighted_distribution'
|
5
|
+
|
4
6
|
class Gate < ResourcelessNode
|
5
7
|
|
8
|
+
|
9
|
+
def initialize(hsh={})
|
10
|
+
check_options!(hsh)
|
11
|
+
params = set_defaults(hsh)
|
12
|
+
|
13
|
+
@diagram = params[:diagram]
|
14
|
+
@name = params[:name]
|
15
|
+
@activation = params[:activation]
|
16
|
+
@mode = params[:mode]
|
17
|
+
@types = get_types(given_types: params[:types])
|
18
|
+
|
19
|
+
super(hsh)
|
20
|
+
end
|
21
|
+
|
22
|
+
def put_resource!(res,edge)
|
23
|
+
|
24
|
+
inv("Edges must be either all defaults or all probabilities") { outgoing_edges.all?{|e| e.label == 1 } || outgoing_edges.all?{|e| e.label.class == Float} }
|
25
|
+
inv("If probabilities given, their sum must not exceed 1"){ outgoing_edges.reduce(0){|acc,el| acc + el.label } <= 1 || !outgoing_edges.all?{|e| e.label.class == Float} }
|
26
|
+
|
27
|
+
maybe_edge = pick_one(outgoing_edges)
|
28
|
+
|
29
|
+
if(maybe_edge.nil?)
|
30
|
+
# do nothing - resource has 'vanished' - happens every other day
|
31
|
+
else
|
32
|
+
maybe_edge.push!(res)
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_s
|
38
|
+
"Gate '#{@name}'\n\n"
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def pick_one(edges)
|
44
|
+
|
45
|
+
if(edges.all?{|e| e.label == 1})
|
46
|
+
#edges is probably an enumerable but only arrays can be sample()'d
|
47
|
+
edges.to_a.sample
|
48
|
+
elsif(edges.all?{|e| e.label.class == Float})
|
49
|
+
#{edge=>weight} is the shape required by WeightedRandomizer
|
50
|
+
weights = edges.reduce(Hash.new){|acc,el| acc[el] = el.label; acc }
|
51
|
+
|
52
|
+
sum = edges.reduce(0){|acc,el|acc + el.label }
|
53
|
+
|
54
|
+
remaining = 1.0 - sum
|
55
|
+
|
56
|
+
#resource 'vanishes'
|
57
|
+
weights[nil] = remaining
|
58
|
+
|
59
|
+
edge_distribution = WeightedDistribution.new(weights)
|
60
|
+
edge_distribution.sample
|
61
|
+
else
|
62
|
+
raise RuntimeError.new('Invalid setup')
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
def options
|
68
|
+
[:name, :diagram, :activation, :mode, :types]
|
69
|
+
end
|
70
|
+
|
71
|
+
def aliases
|
72
|
+
{}
|
73
|
+
end
|
74
|
+
|
75
|
+
def defaults
|
76
|
+
{
|
77
|
+
activation: :passive,
|
78
|
+
mode: :push_any,
|
79
|
+
types: []
|
80
|
+
}
|
81
|
+
end
|
82
|
+
|
6
83
|
end
|
@@ -6,17 +6,36 @@ class Node
|
|
6
6
|
include Invariant
|
7
7
|
include HashInit
|
8
8
|
|
9
|
-
attr_reader :name
|
9
|
+
attr_reader :name, :types
|
10
10
|
|
11
|
+
# Tries to figure out this Node's types based upon what's passed as
|
12
|
+
# parameters. If types were given then just set those as this Node
|
13
|
+
# types. If initial_values were given then try to work out the types
|
14
|
+
# from those.
|
15
|
+
#
|
16
|
+
# @param initial_value [Hash,Fixnum] initial values for this node
|
17
|
+
# @param given_types [Array] provided types
|
18
|
+
# @return [Array] the computed types for this node
|
19
|
+
def get_types(initial_value: 0, given_types: [])
|
20
|
+
inv { !self.instance_variable_defined?(:@types) }
|
21
|
+
|
22
|
+
actual_types = given_types
|
23
|
+
|
24
|
+
if initial_value.is_a?(Fixnum) && given_types.empty?
|
25
|
+
# nothing to do
|
26
|
+
elsif initial_value == 0 && !given_types.empty?
|
27
|
+
# nothing to do
|
28
|
+
elsif initial_value.is_a?(Hash)
|
29
|
+
initial_value.each_key { |type| actual_types.push(type) }
|
30
|
+
else
|
31
|
+
raise ArgumentError.new
|
32
|
+
end
|
11
33
|
|
12
|
-
|
13
|
-
conditions.push(condition)
|
14
|
-
end
|
34
|
+
actual_types.uniq
|
15
35
|
|
16
|
-
def conditions
|
17
|
-
@conditions ||= Array.new
|
18
36
|
end
|
19
37
|
|
38
|
+
|
20
39
|
def edges
|
21
40
|
if @edges.is_a? Array
|
22
41
|
@edges
|
@@ -27,11 +46,11 @@ class Node
|
|
27
46
|
end
|
28
47
|
|
29
48
|
def incoming_edges
|
30
|
-
edges.select{|e| e.to == self}
|
49
|
+
edges.select { |e| e.to == self }
|
31
50
|
end
|
32
51
|
|
33
52
|
def outgoing_edges
|
34
|
-
edges.select{|e| e.from == self}
|
53
|
+
edges.select { |e| e.from == self }
|
35
54
|
end
|
36
55
|
|
37
56
|
def attach_edge(edge)
|
@@ -64,46 +83,60 @@ class Node
|
|
64
83
|
types.empty?
|
65
84
|
end
|
66
85
|
|
67
|
-
def
|
68
|
-
|
86
|
+
def attach_condition(&blk)
|
87
|
+
conditions.push(blk)
|
69
88
|
end
|
70
89
|
|
71
|
-
def
|
72
|
-
@
|
90
|
+
def conditions
|
91
|
+
@conditions = @conditions || Array.new
|
92
|
+
@conditions
|
73
93
|
end
|
74
94
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
95
|
+
|
96
|
+
def attach_trigger(target_node)
|
97
|
+
triggers.push(target_node)
|
98
|
+
end
|
99
|
+
|
100
|
+
def triggers
|
101
|
+
@triggers = @triggers || Array.new
|
102
|
+
@triggers
|
79
103
|
end
|
80
104
|
|
105
|
+
# def clear_triggers
|
106
|
+
# triggers.each do |t|
|
107
|
+
# t[2]=true
|
108
|
+
# end
|
109
|
+
# end
|
110
|
+
|
111
|
+
# Call trigger! on each node stored in self.triggers
|
112
|
+
#
|
81
113
|
def fire_triggers!
|
82
|
-
triggers.each do |
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
114
|
+
triggers.each do |node|
|
115
|
+
node.trigger!
|
116
|
+
# if (n[0].is_a? Proc) && n[2]
|
117
|
+
# if n[0].call
|
118
|
+
# n[2]=false
|
119
|
+
# n[1].trigger!
|
120
|
+
# end
|
121
|
+
# elsif n[0] && n[2]
|
122
|
+
# n[2]=false
|
123
|
+
# n[1].trigger!
|
124
|
+
# end
|
92
125
|
end
|
93
126
|
end
|
94
127
|
|
95
128
|
def enabled?
|
96
|
-
|
97
|
-
conditions.each do |
|
98
|
-
if
|
99
|
-
|
100
|
-
elsif
|
129
|
+
status=true
|
130
|
+
conditions.each do |condition|
|
131
|
+
if condition.is_a? Proc
|
132
|
+
status = (status && condition.call)
|
133
|
+
elsif condition === false
|
101
134
|
return false
|
102
|
-
elsif
|
135
|
+
elsif condition === true
|
103
136
|
# do nothing
|
104
137
|
end
|
105
138
|
end
|
106
|
-
|
139
|
+
status
|
107
140
|
end
|
108
141
|
|
109
142
|
def disabled?
|
@@ -111,8 +144,8 @@ class Node
|
|
111
144
|
end
|
112
145
|
|
113
146
|
def commit!
|
114
|
-
clear_triggers
|
115
|
-
self
|
147
|
+
# clear_triggers
|
148
|
+
#self
|
116
149
|
end
|
117
150
|
|
118
151
|
def pull?
|
@@ -159,7 +192,7 @@ class Node
|
|
159
192
|
# fire triggers.
|
160
193
|
#
|
161
194
|
# @raise [RuntimeError] in case this node won't take the resource
|
162
|
-
def put_resource!(res,edge=nil)
|
195
|
+
def put_resource!(res, edge=nil)
|
163
196
|
raise NotImplementedError, "Please update class #{self.class} to respond to: :#{__callee__}"
|
164
197
|
end
|
165
198
|
|