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,6 @@
1
+ require_relative '../../domain/nodes/node'
2
+ require_relative '../../domain/nodes/resourceless_node'
3
+
4
+ class Gate < ResourcelessNode
5
+
6
+ end
@@ -0,0 +1,166 @@
1
+ require_relative '../../domain/modules/common/invariant'
2
+ require_relative '../../domain/modules/common/hash_init'
3
+
4
+ class Node
5
+
6
+ include Invariant
7
+ include HashInit
8
+
9
+ attr_reader :name,:types
10
+
11
+
12
+ def attach_condition(condition)
13
+ conditions.push(condition)
14
+ end
15
+
16
+ def conditions
17
+ @conditions ||= Array.new
18
+ end
19
+
20
+ def edges
21
+ if @edges.is_a? Array
22
+ @edges
23
+ else
24
+ @edges = Array.new
25
+ @edges
26
+ end
27
+ end
28
+
29
+ def incoming_edges
30
+ edges.select{|e| e.to == self}
31
+ end
32
+
33
+ def outgoing_edges
34
+ edges.select{|e| e.from == self}
35
+ end
36
+
37
+ def attach_edge(edge)
38
+ edges.push(edge)
39
+ end
40
+
41
+ def attach_edge!(edge)
42
+ attach_edge(edge)
43
+ self
44
+ end
45
+
46
+ def detach_edge(edge)
47
+ if edges.include?(edge)
48
+ edges.pop(edge)
49
+ else
50
+ raise RuntimeError "This #{self.class} does not include this #{edge.class}"
51
+ end
52
+ end
53
+
54
+ def detach_edge!(edge)
55
+ detach_edge(edge)
56
+ self
57
+ end
58
+
59
+ def typed?
60
+ !untyped?
61
+ end
62
+
63
+ def untyped?
64
+ types.empty?
65
+ end
66
+
67
+ def attach_trigger(trig)
68
+ triggers.push(trig+[true])
69
+ end
70
+
71
+ def triggers
72
+ @triggers ||= Array.new
73
+ end
74
+
75
+ def clear_triggers
76
+ triggers.each do |t|
77
+ t[2]=true
78
+ end
79
+ end
80
+
81
+ def fire_triggers!
82
+ triggers.each do |n|
83
+ if (n[0].is_a? Proc) && n[2]
84
+ if n[0].call
85
+ n[2]=false
86
+ n[1].trigger!
87
+ end
88
+ elsif n[0] && n[2]
89
+ n[2]=false
90
+ n[1].trigger!
91
+ end
92
+ end
93
+ end
94
+
95
+ def enabled?
96
+ res=true
97
+ conditions.each do |cond|
98
+ if cond.is_a? Proc
99
+ res=res && cond.call
100
+ elsif cond === false
101
+ return false
102
+ elsif cond === true
103
+ # do nothing
104
+ end
105
+ end
106
+ res
107
+ end
108
+
109
+ def disabled?
110
+ !enabled?
111
+ end
112
+
113
+ def commit!
114
+ clear_triggers
115
+ self
116
+ end
117
+
118
+ def pull?
119
+ @mode === :pull || @mode === :pull_any || @mode === :pull_all
120
+ end
121
+
122
+ def push?
123
+ @mode === :push || @mode === :push_any || @mode === :push_all
124
+ end
125
+
126
+ def automatic?
127
+ @activation === :automatic
128
+ end
129
+
130
+ def passive?
131
+ @activation === :passive
132
+ end
133
+
134
+ def start?
135
+ @activation === :start
136
+ end
137
+
138
+ def any?
139
+ @mode === :push_any || @mode === :pull_any
140
+ end
141
+
142
+ def all?
143
+ @mode === :push_all || @mode === :pull_all
144
+ end
145
+
146
+ # Tries to take any resource that, when yielded to expression, returns true.
147
+ # In other words, tries to take any resource which matches the expression
148
+ # block given as parameter.
149
+ #
150
+ # @raise [RuntimeError] in case no resources in this node match given
151
+ # expression block.
152
+ # @param expression [Proc] the expression
153
+ def take_resource!(&expression)
154
+ raise NotImplementedError, "Please update class #{self.class} to respond to: :#{__callee__}"
155
+ end
156
+
157
+ # Places a single resource into this Node. Each subclass may then
158
+ # decide what to do with it; examples are to store the resource and/or to
159
+ # fire triggers.
160
+ #
161
+ # @raise [RuntimeError] in case this node won't take the resource
162
+ def put_resource!(res,edge=nil)
163
+ raise NotImplementedError, "Please update class #{self.class} to respond to: :#{__callee__}"
164
+ end
165
+
166
+ end
@@ -0,0 +1,267 @@
1
+ require_relative '../../domain/nodes/resourceful_node'
2
+ require_relative '../../domain/nodes/node'
3
+ require_relative '../../domain/resources/token'
4
+ require_relative '../resource_bag'
5
+ require_relative '../../domain/exceptions/no_elements_matching_condition_error'
6
+
7
+
8
+ class Pool < ResourcefulNode
9
+
10
+ def initialize(hsh={})
11
+
12
+ check_options!(hsh)
13
+ params = set_defaults(hsh)
14
+
15
+ @resources = get_initial_resources(params[:initial_value])
16
+
17
+ @types = get_types(params[:initial_value], params[:types])
18
+
19
+ #reference to the underlying diagram
20
+ @diagram = params[:diagram]
21
+
22
+ #this node's identifier
23
+ @name = params[:name]
24
+
25
+ #whether this node is passive or automatic (active)
26
+ @activation = params.fetch(:activation)
27
+
28
+ #pull or push
29
+ @mode = params.fetch(:mode)
30
+
31
+ #calling parent constructor to setup other variables.
32
+ super(hsh)
33
+
34
+ end
35
+
36
+ def trigger!
37
+
38
+ if enabled?
39
+ if push? && any?
40
+
41
+ push_any!
42
+
43
+ elsif pull? && any?
44
+
45
+ pull_any!
46
+
47
+ end
48
+
49
+ end
50
+ end
51
+
52
+ def resource_count(type=nil, &block)
53
+
54
+ raise ArgumentError.new('Please provide either a type or a block, but not both.') if block_given? && !type.nil?
55
+
56
+ if type.nil? && !block_given?
57
+ resources.count_where { |r| r.unlocked? }
58
+ elsif type.is_a?(Class) && type <= Token
59
+
60
+ if supports? type
61
+ resources.count_where { |r|
62
+ r.unlocked? && r.is_type?(type)
63
+ }
64
+ else
65
+ raise UnsupportedTypeError.new "Unsupported type: #{type.name}"
66
+ end
67
+ elsif block_given?
68
+
69
+ # client doesn't need to know about locked vs unlocked resources
70
+ unlock_condition = Proc.new { |r| r.unlocked? }
71
+
72
+ resources.count_where { |r| unlock_condition.match?(r) && block.match?(r) }
73
+
74
+ else
75
+ raise ArgumentError.new("Wrong parameter types passed to #{__callee__}")
76
+ end
77
+ end
78
+
79
+ def instant_resource_count(type=nil)
80
+ if type.nil?
81
+ @resources.count_where { true }
82
+ else
83
+
84
+ if supports? type
85
+ @resources.count_where { |r|
86
+ r.instance_of?(type)
87
+ }
88
+ else
89
+ raise UnsupportedTypeError.new "Unsupported type: #{type.name}"
90
+ end
91
+ end
92
+ end
93
+
94
+
95
+ def commit!
96
+
97
+ unlock_resources!
98
+
99
+ super
100
+
101
+ end
102
+
103
+
104
+ def put_resource!(obj, edge=nil)
105
+
106
+ inv { obj.unlocked? }
107
+
108
+ if supports? obj.class
109
+ @resources_added[obj.class] += 1
110
+ resources.add!(obj.lock!)
111
+ fire_triggers!
112
+ else
113
+ raise UnsupportedTypeError.new
114
+ end
115
+ end
116
+
117
+ def take_resource!(&expression)
118
+
119
+ unless block_given?
120
+ # if no conditions given, then anything goes.
121
+ expression = Proc.new{ |res| true }
122
+ end
123
+
124
+ raise RuntimeError.new unless resources.count_where(&expression) > 0
125
+
126
+ res=remove_resource! &expression
127
+
128
+ fire_triggers!
129
+
130
+ res
131
+
132
+ end
133
+
134
+ def to_s
135
+ "Pool '#{@name}': #{@resources.to_s}"
136
+ end
137
+
138
+ # TODO this smells. where is this used? can i do without it?
139
+ def get_initial_resources(initial_value)
140
+ inv { !self.instance_variable_defined?(:@resources) }
141
+
142
+ bag = ResourceBag.new
143
+
144
+ if initial_value.is_a?(Fixnum)
145
+ initial_value.times { bag.add!(Token.new) }
146
+ elsif initial_value.is_a?(Hash)
147
+ initial_value.each do |type, quantity|
148
+ quantity.times { bag.add!(type.new) }
149
+ end
150
+ end
151
+
152
+ return bag
153
+
154
+ end
155
+
156
+ # TODO document this or else refactor it out
157
+ def get_types(initial_value, given_types)
158
+ inv { !self.instance_variable_defined?(:@types) }
159
+
160
+ if initial_value.is_a?(Fixnum) && given_types.empty?
161
+ # nothing to do
162
+ elsif initial_value == 0 && !given_types.empty?
163
+ # nothing to do
164
+ elsif initial_value.is_a?(Hash)
165
+ initial_value.each_key { |type| given_types.push(type) }
166
+ else
167
+ raise ArgumentError.new
168
+ end
169
+
170
+ given_types.uniq
171
+
172
+ end
173
+
174
+
175
+ def types
176
+ @types
177
+ end
178
+
179
+ private
180
+
181
+ attr_reader :resources
182
+
183
+ def remove_resource!(&expression)
184
+
185
+ # client doesn't need to know about locked vs unlocked resources
186
+ unlocked_expression = Proc.new { |r| r.unlocked? }
187
+
188
+ res=resources.get_where { |r| unlocked_expression.call(r) && expression.call(r) }
189
+
190
+ @resources_removed[res.class] += 1
191
+
192
+ res
193
+ end
194
+
195
+ def add_resource!(res)
196
+
197
+ resources.add!(res) and @resources_added[res.type]+=1
198
+
199
+ end
200
+
201
+ def options
202
+ [:conditions, :name, :activation, :mode, :types, :initial_value, :diagram]
203
+ end
204
+
205
+ def defaults
206
+ {
207
+ activation: :passive,
208
+ mode: :pull_any,
209
+ types: [],
210
+ initial_value: 0
211
+ }
212
+ end
213
+
214
+ def aliases
215
+ {:initial_values => :initial_value}
216
+ end
217
+
218
+ def push_any!
219
+
220
+ outgoing_edges.shuffle.each do |edge|
221
+ begin
222
+ blk = edge.push_expression
223
+ rescue => ex
224
+ # Could not get a block for one Edge, but this is push_any so I'll go ahead.
225
+ next #other edges might still be able to serve me.
226
+ end
227
+
228
+ edge.label.times do
229
+ begin
230
+ res = remove_resource!(&blk)
231
+ rescue => ex
232
+ # Failed to remove this resource. Let's try another Edge, perhaps?
233
+ break
234
+ end
235
+
236
+ edge.push!(res)
237
+
238
+ end
239
+
240
+ end
241
+ end
242
+
243
+ def pull_any!
244
+ incoming_edges.shuffle.each do |edge|
245
+ begin
246
+ blk = edge.pull_expression
247
+ rescue RuntimeError => ex
248
+ # Could not get a block for one Edge, but this is pull_any so I'll go ahead.
249
+ next #other edges might still be able to serve me.
250
+ end
251
+
252
+ edge.label.times do
253
+ begin
254
+ res = edge.pull!(&blk)
255
+ rescue RuntimeError => ex
256
+ # Let's try another Edge, perhaps?
257
+ break
258
+ end
259
+
260
+ add_resource!(res.lock!)
261
+
262
+ end
263
+
264
+ end
265
+ end
266
+
267
+ end
@@ -0,0 +1,96 @@
1
+ require 'set'
2
+ require_relative '../../domain/resources/token'
3
+ require_relative '../../domain/nodes/node'
4
+
5
+ class ResourcefulNode < Node
6
+
7
+ include Invariant
8
+
9
+ def initialize(hsh=nil)
10
+ @resources_added=Hash.new(0)
11
+ @resources_removed=Hash.new(0)
12
+ end
13
+
14
+ def initialize_copy(orig)
15
+ super
16
+
17
+ #need to clone the resource bag as well...
18
+ @resources = @resources.clone()
19
+
20
+ #don't need this. takes too much space
21
+ @diagram = nil
22
+
23
+ end
24
+
25
+ # pools are about resources
26
+
27
+ def supports?(klass)
28
+ if klass.eql?(Token)
29
+ untyped?
30
+ else
31
+ #untyped nodes support everything.
32
+ if untyped?
33
+ true
34
+ else
35
+ typed? && types.include?(klass)
36
+ end
37
+ end
38
+ end
39
+
40
+ alias_method :support?, :supports?
41
+
42
+
43
+ def resources_added(klass=nil)
44
+ if klass.nil?
45
+ @resources_added.values.reduce(0) { |acc, elem| acc += elem }
46
+ else
47
+ @resources_added[klass]
48
+ end
49
+ end
50
+
51
+ def resources_removed(klass=nil)
52
+ if klass.nil?
53
+ @resources_removed.values.reduce(0) { |acc, elem| acc += elem }
54
+ else
55
+ @resources_removed[klass]
56
+ end
57
+ end
58
+
59
+ def commit!
60
+ super
61
+ end
62
+
63
+ def unlock_resources!
64
+ @resources.each_where { |r|
65
+ if r.locked?
66
+ r.unlock!
67
+ end
68
+ }
69
+ end
70
+
71
+ def trigger!
72
+ raise NotImplementedError, "Please update class #{self.class} to respond to: :#{__callee__}"
73
+ end
74
+
75
+ def resource_count(type=nil)
76
+ raise NotImplementedError, "Please update class #{self.class} to respond to: :#{__callee__}"
77
+ end
78
+
79
+ def push_any
80
+ raise NotImplementedError, "Please update class #{self.class} to respond to: :#{__callee__}"
81
+ end
82
+
83
+ def push_all
84
+ raise NotImplementedError, "Please update class #{self.class} to respond to: :#{__callee__}"
85
+ end
86
+
87
+ def pull_any
88
+ raise NotImplementedError, "Please update class #{self.class} to respond to: :#{__callee__}"
89
+ end
90
+
91
+ def pull_all
92
+ raise NotImplementedError, "Please update class #{self.class} to respond to: :#{__callee__}"
93
+ end
94
+
95
+ end
96
+