rachinations 0.0.1

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.
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
+