rachinations 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +6 -0
  4. data/.travis.yml +8 -0
  5. data/.yardopts +1 -0
  6. data/Gemfile +19 -0
  7. data/Gemfile.lock +93 -0
  8. data/LICENSE.txt +21 -0
  9. data/README.md +18 -0
  10. data/Rakefile +16 -0
  11. data/lib/rachinations.rb +49 -0
  12. data/lib/rachinations/domain/diagrams/diagram.rb +167 -0
  13. data/lib/rachinations/domain/diagrams/non_deterministic_diagram.rb +16 -0
  14. data/lib/rachinations/domain/diagrams/verbose_diagram.rb +9 -0
  15. data/lib/rachinations/domain/edge_collection.rb +12 -0
  16. data/lib/rachinations/domain/edges/edge.rb +159 -0
  17. data/lib/rachinations/domain/edges/random_edge.rb +4 -0
  18. data/lib/rachinations/domain/exceptions/bad_options.rb +3 -0
  19. data/lib/rachinations/domain/exceptions/no_elements_found.rb +2 -0
  20. data/lib/rachinations/domain/exceptions/no_elements_matching_condition_error.rb +2 -0
  21. data/lib/rachinations/domain/exceptions/no_elements_of_given_type.rb +3 -0
  22. data/lib/rachinations/domain/exceptions/unsupported_type_error.rb +2 -0
  23. data/lib/rachinations/domain/modules/common/hash_init.rb +88 -0
  24. data/lib/rachinations/domain/modules/common/invariant.rb +17 -0
  25. data/lib/rachinations/domain/modules/diagrams/verbose.rb +30 -0
  26. data/lib/rachinations/domain/node_collection.rb +30 -0
  27. data/lib/rachinations/domain/nodes/converter.rb +276 -0
  28. data/lib/rachinations/domain/nodes/gate.rb +6 -0
  29. data/lib/rachinations/domain/nodes/node.rb +166 -0
  30. data/lib/rachinations/domain/nodes/pool.rb +267 -0
  31. data/lib/rachinations/domain/nodes/resourceful_node.rb +96 -0
  32. data/lib/rachinations/domain/nodes/resourceless_node.rb +11 -0
  33. data/lib/rachinations/domain/nodes/sink.rb +17 -0
  34. data/lib/rachinations/domain/nodes/source.rb +161 -0
  35. data/lib/rachinations/domain/nodes/trader.rb +6 -0
  36. data/lib/rachinations/domain/resource_bag.rb +131 -0
  37. data/lib/rachinations/domain/resources/token.rb +51 -0
  38. data/lib/rachinations/domain/strategies/strategy.rb +5 -0
  39. data/lib/rachinations/domain/strategies/valid_types.rb +69 -0
  40. data/lib/rachinations/dsl/dsl.rb +63 -0
  41. data/lib/rachinations/extras/fifo.rb +27 -0
  42. data/lib/rachinations/version.rb +3 -0
  43. data/machinations_diagrams/apenas_bonito.xml +22 -0
  44. data/machinations_diagrams/behavior_converter.xml +53 -0
  45. data/machinations_diagrams/behavior_converter_fim.xml +10 -0
  46. data/machinations_diagrams/canon/README.md +8 -0
  47. data/machinations_diagrams/canon/converters_differences.xml +27 -0
  48. data/machinations_diagrams/canon/converters_differences2.xml +34 -0
  49. data/machinations_diagrams/canon/converters_similarities.xml +63 -0
  50. data/machinations_diagrams/canon/converters_similarities2.xml +21 -0
  51. data/machinations_diagrams/canon/nodes_and_edges_differences.xml +15 -0
  52. data/machinations_diagrams/canon/nodes_and_edges_similarities.xml +20 -0
  53. data/machinations_diagrams/deterministic_example.xml +46 -0
  54. data/machinations_diagrams/economies_of_scale.xml +32 -0
  55. data/machinations_diagrams/feature_ou_bug.xml +5 -0
  56. data/machinations_diagrams/loop_in_trigger.xml +21 -0
  57. data/machinations_diagrams/naficadevendo.xml +12 -0
  58. data/machinations_diagrams/noreporting_equivalent.xml +22 -0
  59. data/machinations_diagrams/pull_all_example.xml +7 -0
  60. data/machinations_diagrams/sketch_of_memory.xml +41 -0
  61. data/machinations_diagrams/software_engineering_process 2.xml +130 -0
  62. data/machinations_diagrams/software_engineering_process v3.xml +168 -0
  63. data/machinations_diagrams/software_engineering_process v4.xml +192 -0
  64. data/machinations_diagrams/software_engineering_process.xml +65 -0
  65. data/machinations_diagrams/software_engineering_process_with_rework_after_test.xml +195 -0
  66. data/machinations_diagrams/startup_marketing.xml +35 -0
  67. data/machinations_diagrams/triggers_allow_multiple_stages_at_same_round.xml +19 -0
  68. data/machinations_diagrams/um_de_cada_vez_vs_todos_de_uma_vez.xml +20 -0
  69. data/rachinations.gemspec +35 -0
  70. data/testing/features/step_definitions/step_definitions.rb +11 -0
  71. data/testing/simulations/modelo1.rb +20 -0
  72. data/testing/simulations/modelo2.rb +49 -0
  73. data/testing/simulations/noreporting.rb +51 -0
  74. data/testing/simulations/sequencial.rb +19 -0
  75. data/testing/simulations/sobonito.rb +28 -0
  76. data/testing/simulations/sobonitowhile.rb +28 -0
  77. data/testing/simulations/whatIwish1.rb +20 -0
  78. data/testing/spec/canon/converter_spec.rb +33 -0
  79. data/testing/spec/canon/pool_spec.rb +68 -0
  80. data/testing/spec/conditions_spec.rb +10 -0
  81. data/testing/spec/converter_spec.rb +223 -0
  82. data/testing/spec/diagram_spec.rb +671 -0
  83. data/testing/spec/edge_spec.rb +256 -0
  84. data/testing/spec/hash_init_spec.rb +59 -0
  85. data/testing/spec/node_spec.rb +31 -0
  86. data/testing/spec/non_deterministic_diagram_spec.rb +112 -0
  87. data/testing/spec/pool_spec.rb +233 -0
  88. data/testing/spec/source_spec.rb +132 -0
  89. data/testing/spec/spec_helper.rb +34 -0
  90. data/testing/spec/xexeo_spec.rb +193 -0
  91. metadata +283 -0
@@ -0,0 +1,12 @@
1
+ require 'forwardable'
2
+
3
+ class EdgeCollection
4
+ extend Forwardable
5
+
6
+ def_delegators :@edges, :[], :<<, :each, :push, :map, :select, :detect, :reduce
7
+
8
+ def initialize
9
+ @edges = []
10
+ end
11
+
12
+ end
@@ -0,0 +1,159 @@
1
+ require_relative '../strategies/valid_types'
2
+ require_relative '../../domain/exceptions/no_elements_found'
3
+
4
+ class Edge
5
+
6
+ attr_reader :from, :to, :name, :label, :types
7
+
8
+
9
+ def initialize(hsh)
10
+
11
+ @name = hsh.fetch(:name)
12
+
13
+ @from = hsh.fetch(:from)
14
+
15
+ @to = hsh.fetch(:to)
16
+
17
+ #setting default values if needed.
18
+ hsh = defaults.merge hsh
19
+
20
+ @label = hsh.fetch(:label)
21
+ @types = hsh.fetch(:types)
22
+
23
+ end
24
+
25
+ # Simulates a ping!, but no resources get actually
26
+ # moved.
27
+ #
28
+ # @param [Boolean] require_all whether to require that the maximum
29
+ # number of Resources allowed (as per this Edge's label) be
30
+ # able to pass in order to return true.
31
+ #
32
+ # @return [Boolean] true in case a ping! on this Edge
33
+ # would return true. False otherwise.
34
+ def test_ping?(require_all=false)
35
+ return false if from.disabled? || to.disabled?
36
+
37
+ condition = strategy.condition
38
+
39
+ available_resources = from.resource_count(&condition)
40
+
41
+ if available_resources == 0
42
+ false
43
+ elsif available_resources >= label
44
+ true
45
+ elsif available_resources < label && require_all
46
+ false
47
+ else
48
+ # only some resources are able to pass but it's not require_all
49
+ true
50
+ end
51
+
52
+ end
53
+
54
+ # the code is the code but sometimes it helps to specify what action
55
+ # we are talking about so as to make code more understandable
56
+ alias_method :test_pull?, :test_ping?
57
+ alias_method :test_push?, :test_ping?
58
+
59
+ def supports?(type)
60
+ types.empty? || types.include?(type)
61
+ end
62
+
63
+ alias_method :support?, :supports?
64
+
65
+ def enabled?
66
+ true
67
+ end
68
+
69
+ def disabled?
70
+ not enabled?
71
+ end
72
+
73
+ def untyped?
74
+ types.empty?
75
+ end
76
+
77
+ def typed?
78
+ not untyped?
79
+ end
80
+
81
+ def from?(obj)
82
+ from.equal?(obj)
83
+ end
84
+
85
+ def to?(obj)
86
+ to.equal?(obj)
87
+ end
88
+
89
+ # Returns a block which will be later used by the calling node to search
90
+ # for a suitable resource.
91
+ #
92
+ # @return [Proc] a condition block
93
+ def push_expression
94
+ strategy.push_condition
95
+ end
96
+
97
+ # Returns a block which will be later used as a parameter
98
+ # to method pull!.
99
+ #
100
+ # @return [Proc] a condition block
101
+ def pull_expression
102
+ strategy.pull_condition
103
+ end
104
+
105
+ # Takes a resource and puts it into the node at the other
106
+ # end of this Edge.
107
+ #
108
+ # @raise [RuntimeError] in case the receiving node or this Edge
109
+ # won't accept the resource sent.
110
+ # @param res the resource to send.
111
+ def push!(res)
112
+ raise RuntimeError.new "This Edge does not support type: #{res.type}" unless supports?(res.type)
113
+
114
+ begin
115
+ to.put_resource!(res,self)
116
+ rescue => e
117
+ # just to make it clear that it bubbles
118
+ raise RuntimeError.new(e.message+" => "+'Push failed')
119
+ end
120
+ end
121
+
122
+ # Tries to take a resource matching given block
123
+ # from the node at the other end.
124
+ #
125
+ # @param [Proc] blk block that will define what resource the other node
126
+ # should send.
127
+ # @raise [RuntimeError] in case the other node could provide no resources
128
+ # that satisfy this condition block.
129
+ # @return a resource that satisfies the given block.
130
+ def pull!(&blk)
131
+ begin
132
+ res=from.take_resource!(&blk)
133
+ rescue => e
134
+ # just to make it clear that it bubbles
135
+ raise RuntimeError.new("Pull failed")
136
+ else
137
+ res
138
+ end
139
+
140
+ end
141
+
142
+ def to_s
143
+ "Edge '#{@name}', from '#{from.name}' to '#{to.name}'"
144
+ end
145
+
146
+ private
147
+
148
+ def strategy
149
+ ValidTypes.new(from, self, to)
150
+ end
151
+
152
+ def defaults
153
+ {
154
+ :label => 1,
155
+ :types => []
156
+ }
157
+ end
158
+
159
+ end
@@ -0,0 +1,4 @@
1
+ require_relative '../../domain/edges/edge'
2
+
3
+ class RandomEdge < Edge
4
+ end
@@ -0,0 +1,3 @@
1
+ class BadOptions < ArgumentError
2
+
3
+ end
@@ -0,0 +1,2 @@
1
+ class NoElementsFound < RuntimeError
2
+ end
@@ -0,0 +1,2 @@
1
+ class NoElementsMatchingConditionError < RuntimeError
2
+ end
@@ -0,0 +1,3 @@
1
+ class NoElementsOfGivenTypeError < RuntimeError
2
+
3
+ end
@@ -0,0 +1,2 @@
1
+ class UnsupportedTypeError < RuntimeError
2
+ end
@@ -0,0 +1,88 @@
1
+ #use this for classes you want to be able to instantiate
2
+ #using a hashful of parameters
3
+ module HashInit
4
+
5
+ class ::Array
6
+
7
+ def include_option? opt
8
+
9
+ each do |el|
10
+ if el == opt
11
+ return true
12
+ elsif el.is_a?(Hash) && el.has_key?(opt)
13
+ return true
14
+ end
15
+ end
16
+
17
+ false
18
+ end
19
+
20
+ end
21
+
22
+ def initialize(hsh={})
23
+
24
+ raise BadOptions.new 'This class requires a hash as parameter to its constructor.' if !hsh.is_a?(Hash)
25
+
26
+ check_options!(hsh)
27
+ hsh=set_defaults(hsh)
28
+ end
29
+
30
+ def check_options!(hsh)
31
+
32
+ #watch out for unknown options - might be typos!
33
+ hsh.each_pair do |key, value|
34
+
35
+ if !options.include_option?(key) && aliases_for(key).none?{|ali| options.include_option?(ali) }
36
+ raise BadOptions.new "Unknown option in parameter hash: :#{key} "
37
+ end
38
+ end
39
+
40
+ #make sure all required ones are there
41
+
42
+ options.each do |el|
43
+ if el.is_a? Hash
44
+
45
+ #we know for sure it's got only one key and one value
46
+ k = el.keys[0]
47
+ v = el.values[0]
48
+
49
+ if v == :required
50
+
51
+ if !hsh.has_key?(k) && hsh.keys.all?{|opt| aliases_for(opt).none?{|ali| ali == k } }
52
+ raise BadOptions.new "Required option #{k} was not found in parameter hash."
53
+ end
54
+ end
55
+
56
+ end
57
+ end
58
+
59
+ end
60
+
61
+ def aliases_for(opt)
62
+ aliases.select{|k,v| k == opt }.values
63
+ end
64
+
65
+ def set_defaults(hsh)
66
+ #in case the user hasn't passed full parameters to the constructor
67
+ defaults.merge hsh
68
+ end
69
+
70
+ # This method should be implemented by each client to indicate the options accepted.
71
+ #@return [Array] An array of accepted options.
72
+ #@example Many client Classes specify a :name option:
73
+ # def options
74
+ # [:name]
75
+ # end
76
+ def options
77
+ []
78
+ end
79
+
80
+ def defaults
81
+ {}
82
+ end
83
+
84
+ def aliases
85
+ {}
86
+ end
87
+
88
+ end
@@ -0,0 +1,17 @@
1
+ module Invariant
2
+
3
+ #used to insert assertions into code
4
+ #remember that assertions should not be used to control program flow!!! assert things that should ALWAYS be false.
5
+
6
+ class AssertionError < RuntimeError
7
+
8
+ end
9
+
10
+
11
+
12
+ def invariant &block
13
+ raise AssertionError unless yield
14
+ end
15
+
16
+ alias_method :inv, :invariant
17
+ end
@@ -0,0 +1,30 @@
1
+ module Verbose
2
+
3
+
4
+ def before_run
5
+ print "\033[1;32m===== INITIAL STATE =====\e[00m\n\n"
6
+
7
+ puts self
8
+ end
9
+
10
+ def after_run
11
+ print "\033[1;32m====== FINAL STATE ======\e[00m\n\n"
12
+
13
+ puts self
14
+
15
+ print "\033[1;31m========== END ==========\e[00m\n\n"
16
+ end
17
+
18
+ def before_round(round_no)
19
+ print "======= ROUND #{round_no} =======\n\n"
20
+ end
21
+
22
+ def after_round (round_no)
23
+ puts self
24
+ end
25
+
26
+ def sanity_check_message
27
+ print "\033[1;31m= SAFEGUARD CONDITION REACHED - ABORTING EXECUTION =\e[00m\n\n"
28
+ end
29
+
30
+ end
@@ -0,0 +1,30 @@
1
+ require 'forwardable'
2
+
3
+ class NodeCollection
4
+ extend Forwardable
5
+
6
+ def_delegators :@array, :[], :<<, :each, :push, :map, :select, :detect , :reduce, :shuffle, :sample
7
+
8
+
9
+ def initialize(init_array=nil)
10
+
11
+ if init_array.nil?
12
+ @array = []
13
+ else
14
+ @array = init_array
15
+ end
16
+ end
17
+
18
+ def passive
19
+ @array.select{|el| el.passive? }
20
+ end
21
+
22
+ def automatic
23
+ @array.select{|el| el.automatic? }
24
+ end
25
+
26
+ def detect_by_name(name)
27
+ @array.detect{|el| el.name === name }
28
+ end
29
+
30
+ end
@@ -0,0 +1,276 @@
1
+ require_relative '../../domain/nodes/node'
2
+ require_relative '../../domain/nodes/resourceless_node'
3
+
4
+ class Converter < ResourcefulNode
5
+
6
+ # VEJA O DIAGRAMA BEHAVIOR CONVERTER, inclusive com o equivalente dele
7
+
8
+ # um converter, ao ser ativado, deve tirar de um lugar e passar para outro
9
+ # nada fica guardado em um converter no sentido do pool, porém algumas coisas podem ficar
10
+ # temporariamente anotadas nele porque não foi completado ainda o & ou todos os recursos necessários
11
+
12
+ # um converter pode ser ativado de 3 maneiras
13
+ # por si mesmo
14
+ # quando um no que empurra empurra algo para ele
15
+ # quando um no que puxa puxa dele
16
+
17
+ # O tipo do conversor define o tipo de saida padrao
18
+ # porem o tipo do edge tem vantagem na definicao da saida
19
+ # O exemplo com 3 saidas mostra isso
20
+
21
+ def initialize(hsh={})
22
+ check_options!(hsh)
23
+ hsh = set_defaults(hsh)
24
+ @name = hsh.fetch(:name)
25
+ @mode = hsh.fetch(:mode)
26
+ @types = hsh.fetch(:types)
27
+ @activation = hsh.fetch(:activation)
28
+
29
+ # each edge may have contributed with some resources at any given time
30
+ @resources_contributed = init_resources
31
+
32
+ end
33
+
34
+ # Activates this Converter. It will try to pull from
35
+ # incoming nodes and, if successful, will push into
36
+ # outgoing nodes.
37
+ def trigger!
38
+
39
+ if all?
40
+
41
+ if incoming_edges.all? { |edge| edge.test_pull?(true) } && outgoing_edges.all? { |edge| edge.test_push?(true) }
42
+ pull_all!
43
+ push_all!
44
+ else
45
+ # does not trigger
46
+ end
47
+
48
+ elsif any?
49
+
50
+ pull_any!
51
+
52
+ if in_conditions_met?
53
+ if outgoing_edges.all? { |edge| edge.test_push?(true) }
54
+ push_all!
55
+ pop_stored_resources!
56
+ end # converters are always push_all
57
+ end # conditions weren't met this turn
58
+
59
+ else
60
+ raise ArgumentError.new "Unsupported mode :#{mode}"
61
+ end
62
+
63
+ end
64
+
65
+ # Puts a Resource into a Converter. The Edge may be used
66
+ # as index for internal states and the Resource may be
67
+ # used in case not all edge conditions have been met
68
+ # (only applicable when in pull_any mode).
69
+ #
70
+ def put_resource!(res, edge=nil)
71
+ inv { !edge.nil? }
72
+ if all?
73
+ if incoming_edges.all? { |e| e.test_push? }
74
+ push_all!
75
+ end
76
+ elsif any?
77
+ add_to_contributed_resources!(res, edge)
78
+ if in_conditions_met?
79
+ push_all!
80
+ end
81
+ end
82
+
83
+ end
84
+
85
+ # An override for the original method. The reason for this is
86
+ # that, when an Edge is attached to a Converter after it's been
87
+ # created, a key for it (frozen) needs to be created.
88
+ #
89
+ # @param [Edge] edge
90
+ def attach_edge!(edge)
91
+ #TODO use argument (edge) on the call to super and make sure tests still pass
92
+ # that way it's clearer that it is being passed on to super
93
+ super
94
+ resources_contributed.store(edge, Fifo.new)
95
+ self
96
+ end
97
+
98
+ def take_resource!(type=nil, &blk)
99
+ if incoming_edges.shuffle.all? { |edge| edge.test_pull? }
100
+ pull_all!
101
+ end
102
+ end
103
+
104
+
105
+ def resource_count(type=nil,&block)
106
+ return Float::INFINITY
107
+ end
108
+
109
+ def to_s
110
+ "Converter '#{@name}'"
111
+ end
112
+
113
+ private
114
+
115
+ # This method is used to test whether a Converter
116
+ # has had the conditions for incoming edges met.
117
+ #
118
+ # @return [Boolean] true if conditions for pull_any
119
+ # have all been met, false otherwise
120
+ def in_conditions_met?
121
+
122
+ edges = incoming_edges
123
+
124
+ incoming_edges
125
+ .all? { |edge| resources_contributed.keys.include?(edge) && resources_contributed.fetch(edge).length >= edge.label }
126
+ end
127
+
128
+ # This removes from the internal store just enough
129
+ # resources to accomplish one push_all (only applicable when in pull_any mode)
130
+ def pop_stored_resources!
131
+ #TODO
132
+ end
133
+
134
+
135
+ attr_accessor :resources_contributed
136
+
137
+ def pull_any!
138
+ incoming_edges
139
+ .shuffle
140
+ .each do |edge|
141
+ begin
142
+ blk = edge.pull_expression
143
+ rescue RuntimeError => ex
144
+ # Could not get a block for one Edge, but this is pull_any so I'll go ahead.
145
+ next #other edges might still be able to serve me.
146
+ end
147
+
148
+ edge.label.times do
149
+ begin
150
+ res = edge.pull!(&blk)
151
+ rescue RuntimeError => ex
152
+ # Let's try another Edge, perhaps?
153
+ break
154
+ end
155
+
156
+ # right here we would add the returned resource to the store,
157
+ # but with converters we dont store the resources; we just
158
+ # record that this edge has contributed one resource:
159
+ add_to_contributed_resources!(res, edge)
160
+
161
+ end
162
+
163
+ end
164
+
165
+ end
166
+
167
+ def pull_all!
168
+
169
+ incoming_edges
170
+ .shuffle
171
+ .each do |edge|
172
+ begin
173
+ blk = edge.pull_expression
174
+ rescue RuntimeError => ex
175
+ raise RuntimeError.new "One edge failed to provide an expression; the whole operation failed."
176
+ end
177
+
178
+ edge.label.times do
179
+ begin
180
+ res = edge.pull!(&blk)
181
+ res=nil # we do not store the results
182
+ rescue RuntimeError => ex
183
+ raise RuntimeError.new "One edge failed to pull; the whole operation failed."
184
+ end
185
+
186
+ end
187
+
188
+ end
189
+
190
+ end
191
+
192
+ def push_all!
193
+ outgoing_edges
194
+ .shuffle
195
+ .each do |edge|
196
+ begin
197
+ exp = edge.push_expression
198
+ rescue RuntimeError => ex
199
+ raise RuntimeError.new "One edge failed to provide an expression; the whole operation failed."
200
+ end
201
+
202
+ edge.label.times do
203
+
204
+ begin
205
+ res = make_resource(&exp)
206
+ rescue RuntimeError => ex
207
+ raise RuntimeError.new "This Converter cannot provide any suitable Resource."
208
+ end
209
+
210
+ begin
211
+ edge.push!(res)
212
+ rescue RuntimeError => e
213
+ raise RuntimeError.new e.message+" SO "+"One push over an edge failed; the whole operation failed."
214
+ end
215
+
216
+ end
217
+
218
+ end
219
+
220
+
221
+ end
222
+
223
+ def push_any!
224
+ raise NotImplementedError.new "Converters cannot push_any. Only push_all."
225
+ end
226
+
227
+ # Try to produce a Resource matching given condition.
228
+ #
229
+ # @return [Token] a token resource or any of its subtypes
230
+ # @raise [RuntimeError] in case this Converter cannot produce any
231
+ # Resource that matches the condition.
232
+ def make_resource(&condition)
233
+
234
+ if untyped?
235
+ res = Token.new
236
+ if condition.match_resource?(res)
237
+ res
238
+ else
239
+ raise RuntimeError.new "Failed to make Resource matching given conditions."
240
+ end
241
+ else
242
+ types.shuffle.each do |type|
243
+ res = type.new
244
+ if condition.match_resource?(res)
245
+ return res
246
+ end
247
+ end
248
+ raise RuntimeError.new "Failed to make Resource matching given conditions."
249
+ end
250
+
251
+ end
252
+
253
+ # A Converter may receive its needed resources across turns
254
+ # so there must be a way to keep count of which edges have already
255
+ # 'given their contribution' to this Converter.
256
+ def add_to_contributed_resources!(resource, edge)
257
+ resources_contributed.fetch(edge).put!(resource)
258
+ end
259
+
260
+ def init_resources
261
+ edges.reduce(Hash.new) { |hash, edge| hash.store(edge.object_id, Fifo.new) }
262
+ end
263
+
264
+ def options
265
+ [{name: :required}, :diagram, :mode, :activation, :types]
266
+ end
267
+
268
+ def defaults
269
+ {
270
+ mode: :pull_any,
271
+ activation: :passive,
272
+ types: []
273
+ }
274
+ end
275
+
276
+ end