rachinations 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -16
  3. data/Gemfile.lock +2 -0
  4. data/lib/rachinations/domain/diagrams/diagram.rb +46 -14
  5. data/lib/rachinations/domain/edges/edge.rb +34 -20
  6. data/lib/rachinations/domain/modules/common/hash_init.rb +2 -1
  7. data/lib/rachinations/domain/modules/common/invariant.rb +2 -2
  8. data/lib/rachinations/domain/modules/common/refiners/number_modifiers.rb +22 -0
  9. data/lib/rachinations/domain/nodes/converter.rb +5 -5
  10. data/lib/rachinations/domain/nodes/gate.rb +77 -0
  11. data/lib/rachinations/domain/nodes/node.rb +69 -36
  12. data/lib/rachinations/domain/nodes/pool.rb +121 -74
  13. data/lib/rachinations/domain/nodes/resourceful_node.rb +0 -1
  14. data/lib/rachinations/domain/nodes/sink.rb +3 -0
  15. data/lib/rachinations/domain/nodes/source.rb +3 -2
  16. data/lib/rachinations/domain/resource_bag.rb +3 -4
  17. data/lib/rachinations/dsl/bad_dsl.rb +2 -0
  18. data/lib/rachinations/dsl/bootstrap.rb +59 -0
  19. data/lib/rachinations/dsl/diagram_shorthand_methods.rb +107 -0
  20. data/lib/rachinations/dsl/helpers/parser.rb +170 -0
  21. data/lib/rachinations/extras/constant_hash.rb +25 -0
  22. data/lib/rachinations/extras/fifo.rb +25 -19
  23. data/lib/rachinations/helpers/edge_helper.rb +40 -0
  24. data/lib/rachinations/utils/string_helper.rb +7 -0
  25. data/lib/rachinations/version.rb +1 -1
  26. data/lib/rachinations.rb +13 -5
  27. data/rachinations.gemspec +3 -2
  28. data/testing/simulations/modelo1.rb +1 -1
  29. data/testing/simulations/sequencial.rb +1 -1
  30. data/testing/simulations/sobonito.rb +1 -1
  31. data/testing/simulations/sobonitowhile.rb +1 -1
  32. data/testing/simulations/whatIwish1.rb +2 -2
  33. data/testing/spec/canon/conditions_spec.rb +3 -4
  34. data/testing/spec/converter_spec.rb +3 -4
  35. data/testing/spec/diagram_spec.rb +293 -238
  36. data/testing/spec/edge_spec.rb +28 -14
  37. data/testing/spec/gate_spec.rb +34 -0
  38. data/testing/spec/pool_spec.rb +8 -10
  39. data/testing/spec/release1/dsl_spec.rb +204 -0
  40. data/testing/spec/spec_helper.rb +1 -0
  41. data/testing/spec/xexeo_spec.rb +39 -40
  42. metadata +30 -8
  43. data/lib/rachinations/domain/edges/random_edge.rb +0 -4
  44. data/lib/rachinations/dsl/dsl.rb +0 -63
  45. data/testing/spec/canon/trigger_spec.rb +0 -128
@@ -4,12 +4,14 @@ require_relative '../../domain/resources/token'
4
4
  require_relative '../resource_bag'
5
5
  require_relative '../../domain/exceptions/no_elements_matching_condition_error'
6
6
  require_relative '../../domain/modules/common/refiners/proc_convenience_methods'
7
-
7
+ require_relative '../../../../lib/rachinations/helpers/edge_helper'
8
8
 
9
9
  using ProcConvenienceMethods
10
10
 
11
11
  class Pool < ResourcefulNode
12
12
 
13
+ Helper = Helpers::EdgeHelper
14
+
13
15
  def initialize(hsh={})
14
16
 
15
17
  check_options!(hsh)
@@ -17,7 +19,8 @@ class Pool < ResourcefulNode
17
19
 
18
20
  @resources = get_initial_resources(params[:initial_value])
19
21
 
20
- @types = get_types(params[:initial_value], params[:types])
22
+ @types = get_types(initial_value: params[:initial_value],
23
+ given_types: params[:types])
21
24
 
22
25
  #reference to the underlying diagram
23
26
  @diagram = params[:diagram]
@@ -47,16 +50,25 @@ class Pool < ResourcefulNode
47
50
 
48
51
  pull_any!
49
52
 
50
- end
53
+ elsif push? && all?
54
+
55
+ push_all!
56
+
57
+ elsif pull? && all?
58
+
59
+ pull_all!
51
60
 
61
+ else
62
+
63
+ end
52
64
  end
53
65
  end
54
66
 
55
- def resource_count(type=nil, &block)
67
+ def resource_count(type: nil, expr: nil)
56
68
 
57
- raise ArgumentError.new('Please provide either a type or a block, but not both.') if block_given? && !type.nil?
69
+ raise ArgumentError.new('Please provide either a type or a block, but not both.') if !expr.nil? && !type.nil?
58
70
 
59
- if type.nil? && !block_given?
71
+ if type.nil? && expr.nil?
60
72
  resources.count_where { |r| r.unlocked? }
61
73
  elsif type.is_a?(Class) && type <= Token
62
74
 
@@ -67,12 +79,12 @@ class Pool < ResourcefulNode
67
79
  else
68
80
  raise UnsupportedTypeError.new "Unsupported type: #{type.name}"
69
81
  end
70
- elsif block_given?
82
+ elsif !expr.nil?
71
83
 
72
84
  # client doesn't need to know about locked vs unlocked resources
73
- unlock_condition = Proc.new { |r| r.unlocked? }
85
+ unlock_condition = proc { |r| r.unlocked? }
74
86
 
75
- resources.count_where { |r| unlock_condition.match?(r) && block.match?(r) }
87
+ resources.count_where { |r| unlock_condition.match?(r) && expr.match?(r) }
76
88
 
77
89
  else
78
90
  raise ArgumentError.new("Wrong parameter types passed to #{__callee__}")
@@ -117,16 +129,16 @@ class Pool < ResourcefulNode
117
129
  end
118
130
  end
119
131
 
120
- def take_resource!(&expression)
132
+ def take_resource!(expression=nil)
121
133
 
122
- unless block_given?
134
+ if expression.nil?
123
135
  # if no conditions given, then anything goes.
124
- expression = Proc.new{ |res| true }
136
+ expression = Proc.new { |res| true }
125
137
  end
126
138
 
127
139
  raise RuntimeError.new unless resources.count_where(&expression) > 0
128
140
 
129
- res=remove_resource! &expression
141
+ res=remove_resource! expression
130
142
 
131
143
  fire_triggers!
132
144
 
@@ -135,7 +147,7 @@ class Pool < ResourcefulNode
135
147
  end
136
148
 
137
149
  def to_s
138
- "Pool '#{@name}': #{resources} "
150
+ "Pool '#{@name}': #{resources} "
139
151
  end
140
152
 
141
153
  # TODO this smells. where is this used? can i do without it?
@@ -156,25 +168,6 @@ class Pool < ResourcefulNode
156
168
 
157
169
  end
158
170
 
159
- # TODO document this or else refactor it out
160
- def get_types(initial_value, given_types)
161
- inv { !self.instance_variable_defined?(:@types) }
162
-
163
- if initial_value.is_a?(Fixnum) && given_types.empty?
164
- # nothing to do
165
- elsif initial_value == 0 && !given_types.empty?
166
- # nothing to do
167
- elsif initial_value.is_a?(Hash)
168
- initial_value.each_key { |type| given_types.push(type) }
169
- else
170
- raise ArgumentError.new
171
- end
172
-
173
- given_types.uniq
174
-
175
- end
176
-
177
-
178
171
  def types
179
172
  @types
180
173
  end
@@ -183,16 +176,28 @@ class Pool < ResourcefulNode
183
176
 
184
177
  attr_reader :resources
185
178
 
186
- def remove_resource!(&expression)
179
+ # Tries to remove a Resource that matches given expression from this node.
180
+ # @param [Proc] expression the expression to match against Resources
181
+ # @raise [RuntimeError] In case it was not possible to remove a Resource
182
+ def remove_resource!(expression)
187
183
 
188
184
  # client doesn't need to know about locked vs unlocked resources
189
185
  unlocked_expression = Proc.new { |r| r.unlocked? }
190
186
 
191
- res=resources.get_where { |r| unlocked_expression.call(r) && expression.call(r) }
187
+ begin
188
+ # the original expression plus the expression that specifies that only unlocked
189
+ # resources may be retrieved
190
+ res=resources.get_where { |r| unlocked_expression.call(r) && expression.call(r) }
191
+ rescue ArgumentError
192
+ raise RuntimeError, 'wrong arguments'
193
+ rescue NoElementsMatchingConditionError
194
+ raise RuntimeError, 'no elements matching'
195
+ else
196
+ @resources_removed[res.class] += 1
197
+ res
198
+ end
192
199
 
193
- @resources_removed[res.class] += 1
194
200
 
195
- res
196
201
  end
197
202
 
198
203
  def add_resource!(res)
@@ -201,43 +206,22 @@ class Pool < ResourcefulNode
201
206
 
202
207
  end
203
208
 
204
- def options
205
- [:conditions, :name, :activation, :mode, :types, :initial_value, :diagram]
206
- end
207
-
208
- def defaults
209
- {
210
- activation: :passive,
211
- mode: :pull_any,
212
- types: [],
213
- initial_value: 0
214
- }
215
- end
216
-
217
- def aliases
218
- {:initial_values => :initial_value}
219
- end
220
-
221
209
  def push_any!
222
210
 
223
211
  outgoing_edges.shuffle.each do |edge|
224
- begin
225
- blk = edge.push_expression
226
- rescue => ex
227
- # Could not get a block for one Edge, but this is push_any so I'll go ahead.
228
- next #other edges might still be able to serve me.
229
- end
212
+
213
+ blk = edge.push_expression
230
214
 
231
215
  edge.label.times do
232
216
  begin
233
- res = remove_resource!(&blk)
234
- rescue => ex
235
- # Failed to remove this resource. Let's try another Edge, perhaps?
217
+ res = remove_resource!(blk)
218
+ rescue RuntimeError
219
+ # Failed to remove this resource. Let's try another Edge, perhaps?
236
220
  break
221
+ else
222
+ edge.push!(res)
237
223
  end
238
224
 
239
- edge.push!(res)
240
-
241
225
  end
242
226
 
243
227
  end
@@ -245,26 +229,89 @@ class Pool < ResourcefulNode
245
229
 
246
230
  def pull_any!
247
231
  incoming_edges.shuffle.each do |edge|
248
- begin
249
- blk = edge.pull_expression
250
- rescue RuntimeError => ex
251
- # Could not get a block for one Edge, but this is pull_any so I'll go ahead.
252
- next #other edges might still be able to serve me.
253
- end
232
+
233
+ blk = edge.pull_expression
254
234
 
255
235
  edge.label.times do
256
236
  begin
257
- res = edge.pull!(&blk)
258
- rescue RuntimeError => ex
237
+ res = edge.pull!(blk)
238
+ rescue RuntimeError
259
239
  # Let's try another Edge, perhaps?
260
240
  break
241
+ else
242
+ add_resource!(res.lock!)
261
243
  end
262
244
 
263
- add_resource!(res.lock!)
245
+ end
246
+
247
+ end
248
+ end
249
+
250
+ def pull_all!
251
+
252
+ enabled_incoming_edges = incoming_edges.select { |edge| edge.enabled? }
253
+
254
+ if enabled_incoming_edges.all? { |edge| edge.test_ping? }
255
+
256
+ enabled_incoming_edges.each do |edge|
257
+ blk = edge.pull_expression
258
+
259
+ edge.label.times do
260
+ res = edge.pull!(blk)
261
+
262
+ add_resource!(res.lock!)
263
+
264
+ end
264
265
 
265
266
  end
267
+ fire_triggers!
268
+ end
269
+
270
+ end
271
+
272
+ def push_all!
273
+
274
+ enabled_outgoing_edges = outgoing_edges.select { |edge| edge.enabled? }
275
+
276
+
277
+ if Helper.all_can_push?(edges, require_all: true)
278
+
279
+ enabled_outgoing_edges.each do |edge|
280
+
281
+ expression = edge.push_expression
282
+
283
+ edge.label.times do
284
+
285
+ res = remove_resource!(expression)
286
+
287
+ edge.push!(res)
288
+
289
+ end
266
290
 
291
+ end
292
+ fire_triggers!
267
293
  end
294
+
295
+
296
+ end
297
+
298
+ def options
299
+ [:conditions, :name, :activation, :mode, :types, :initial_value, :diagram]
300
+ end
301
+
302
+ def defaults
303
+ {
304
+ activation: :passive,
305
+ mode: :pull_any,
306
+ types: [],
307
+ initial_value: 0
308
+ }
309
+ end
310
+
311
+ def aliases
312
+ {
313
+ :initial_values => :initial_value
314
+ }
268
315
  end
269
316
 
270
317
  end
@@ -3,7 +3,6 @@ require_relative '../../domain/resources/token'
3
3
  require_relative '../../domain/nodes/node'
4
4
  require_relative '../../domain/modules/common/refiners/proc_convenience_methods'
5
5
 
6
-
7
6
  using ProcConvenienceMethods
8
7
 
9
8
  class ResourcefulNode < Node
@@ -14,4 +14,7 @@ class Sink < Pool
14
14
  # do nothing
15
15
  end
16
16
 
17
+ def to_s
18
+ "Sink '#{@name}'\n\n"
19
+ end
17
20
  end
@@ -28,7 +28,7 @@ class Source < ResourcefulNode
28
28
  end
29
29
 
30
30
  def to_s
31
- "Source '#{@name}': \n"
31
+ "Source '#{@name}'\n\n"
32
32
  end
33
33
 
34
34
  def put_resource!;
@@ -98,7 +98,7 @@ class Source < ResourcefulNode
98
98
 
99
99
  #we'll need to change this if source starts accepting
100
100
  # more than a single type
101
- inv { types.size === 1 }
101
+ inv("Sources can only have a single type") { types.size === 1 }
102
102
 
103
103
  if type.nil?
104
104
  res = Token.new
@@ -144,6 +144,7 @@ class Source < ResourcefulNode
144
144
  end
145
145
 
146
146
  end
147
+ fire_triggers!
147
148
  end
148
149
 
149
150
  def options
@@ -82,16 +82,15 @@ class ResourceBag
82
82
  unlocked = count_where{|r| (r.is_type? klass) && (r.unlocked?) }
83
83
  locked = count_where{|r| (r.is_type? klass) && (r.locked?) }
84
84
 
85
- out += "\n #{name} -> #{unlocked} (#{locked}) \n\n"
85
+ out += "#{name} -> #{unlocked} (#{locked}) \n"
86
86
  end
87
87
 
88
88
  if classes.empty?
89
- "\n Empty\n\n"
89
+ "Empty\n\n"
90
90
  else
91
- out
91
+ out+"\n"
92
92
  end
93
93
 
94
-
95
94
  end
96
95
 
97
96
  # created so that I don't have to call count everytime just to see whether there's at least one element matching said condition
@@ -0,0 +1,2 @@
1
+ class BadDSL < RuntimeError
2
+ end
@@ -0,0 +1,59 @@
1
+ require_relative '../../../lib/rachinations/domain/diagrams/diagram'
2
+ require_relative 'diagram_shorthand_methods'
3
+ require_relative 'bad_dsl'
4
+ require_relative 'helpers/parser'
5
+
6
+ # Bootstraping a diagram using the DiagramShorthandMethods
7
+ module DSL
8
+ module Bootstrap
9
+
10
+ def diagram(name='new_diagram', mode: :silent, &blk)
11
+
12
+ # cant verbose be a simple boolean instead?
13
+ if mode == :silent || mode == 'silent'
14
+ dia= Diagram.new(Parser.validate_name!(name))
15
+ elsif mode == :verbose || mode == 'verbose'
16
+ dia = VerboseDiagram.new(Parser.validate_name!(name))
17
+ else
18
+ raise BadDSL, "Unknown diagram mode: #{mode.to_s}"
19
+ end
20
+
21
+ # methods in the block get run as if they were called on
22
+ # the diagram (augmented by the DiagramShorthandMethods module) itself
23
+ dia.instance_eval(&blk)
24
+
25
+ dia
26
+
27
+ end
28
+
29
+
30
+ def non_deterministic_diagram(name, verbose=:silent, &blk)
31
+
32
+ dia=NonDeterministicDiagram.new(Parser.validate_name!(name))
33
+
34
+ # cant verbose be a simple boolean instead?
35
+ if verbose === :verbose
36
+ dia.extend(Verbose)
37
+ end
38
+
39
+ dia.instance_eval &blk
40
+
41
+ dia
42
+
43
+ end
44
+
45
+ # This is just a convenience method to create a proc in a way that's more
46
+ # intuitive for ends users.
47
+ # @example Create a proc, equivalent to proc{|x| x+1 }
48
+ # expr{|x| x+1 }
49
+ def expr(&blk)
50
+ if !block_given?
51
+ raise ArgumentError, "expected a block, but none was given"
52
+ else
53
+ Proc.new(&blk)
54
+ end
55
+ end
56
+
57
+ end
58
+
59
+ end
@@ -0,0 +1,107 @@
1
+ require_relative '../domain/diagrams/diagram'
2
+ require_relative '../domain/diagrams/verbose_diagram'
3
+ require_relative '../domain/diagrams/non_deterministic_diagram'
4
+ require_relative '../domain/modules/diagrams/verbose'
5
+ require_relative '../domain/modules/common/refiners/proc_convenience_methods'
6
+ require_relative './bad_dsl'
7
+ require_relative '../utils/string_helper'
8
+ require_relative 'helpers/parser'
9
+
10
+ module DSL
11
+
12
+ module DiagramShorthandMethods
13
+
14
+ using ProcConvenienceMethods
15
+
16
+ # if you can turn this into a refiner and still keep all tests passing,
17
+ # send a PR for me :smile:
18
+ class ::Diagram
19
+
20
+ alias_method :run, :run!
21
+
22
+ def pool(*args)
23
+
24
+ hash = Parser.parse_arguments(args)
25
+
26
+ add_node! Pool, hash
27
+
28
+ end
29
+
30
+ def source(*args)
31
+
32
+ hash = Parser.parse_arguments(args)
33
+
34
+ add_node! Source, hash
35
+
36
+ end
37
+
38
+ def sink(*args)
39
+
40
+ hash = Parser.parse_arguments(args)
41
+
42
+ add_node! Sink, hash
43
+
44
+ end
45
+
46
+ def converter(*args)
47
+
48
+ hash = Parser.parse_arguments(args)
49
+
50
+ add_node! Converter, hash
51
+
52
+ end
53
+
54
+ def trader(*args)
55
+
56
+ hash = Parser.parse_arguments(args)
57
+
58
+ add_node! Trader, hash
59
+
60
+ end
61
+
62
+ def gate(*args)
63
+ # gate is different because it doesn't take some arguments
64
+ hash = Parser.parse_gate_arguments(args)
65
+
66
+ add_node! Gate, hash
67
+
68
+ end
69
+
70
+ # methods to create edges
71
+ def edge(*args)
72
+
73
+ hash = Parser.parse_edge_arguments(args)
74
+
75
+ add_edge! Edge, hash
76
+
77
+ end
78
+
79
+
80
+ # so that I can easily access elements which have been given a name
81
+ # (mostly nodes and maybe edges too)
82
+ def method_missing(method_sym, *args, &block)
83
+ super if method_sym.to_s == 'anonymous' #these aren't actual node names
84
+
85
+ begin
86
+ #does a node with that name exist?
87
+ node=get_node(method_sym.to_s)
88
+ rescue RuntimeError => err_node
89
+ #what about an edge?
90
+ begin
91
+ edge = get_edge(method_sym.to_s)
92
+ rescue RuntimeError => err_edge
93
+ #no luck, sorry
94
+ super
95
+ else
96
+ edge
97
+ end
98
+ else
99
+ node
100
+ end
101
+ end
102
+
103
+ end
104
+
105
+ end
106
+
107
+ end