rachinations 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7cdd3c499e1f1791ce742a6a2cc6485fce449c53
4
- data.tar.gz: b39dd99ffa4514366b7047be022fb69323a953d8
3
+ metadata.gz: f121ae6b88636bb8f2d61ce349052e5eaaab765a
4
+ data.tar.gz: 80b8154cb68f75059ed98c866043b052c1271ac0
5
5
  SHA512:
6
- metadata.gz: ac6c02f660108180d6f7d48e048c7ec30ce90a5a1f3f476d19f21e0b0e390073433766bcf868f0a856f3018c2ee33f892e0bdccbed1fff5e1a656f26bfb26be2
7
- data.tar.gz: 196440e524df7fa67b43fa13aac1726378a83d578c221769d0ad95ab4f73ecc60ea0c2ee9b74e51b60e3bc2ca50e3ed3c800b85b7e73071f7645ebda8fa8d2f0
6
+ metadata.gz: 555791bf758a0458b7cfc3b1c71287c33b54ce296d957878f4c4d236fb0186a8b1aaf036529119b5a85bd40eeeeacf152e7bf2df87590040f75a89330c52e067
7
+ data.tar.gz: 1443bdad6609c32eb441b22e686c46b04c531808f190301ed0de56d309730ff2b94cd7b47dc4244e252594188fe9b2939caad027c72168a3f9512cd0a9a2fd9b
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rachinations (0.0.5)
4
+ rachinations (0.0.6)
5
5
  activesupport (= 3.0.0)
6
6
  i18n (= 0.6.11)
7
7
  weighted_distribution (= 1.0.0)
data/lib/rachinations.rb CHANGED
@@ -4,6 +4,8 @@ require 'rachinations/version'
4
4
 
5
5
  require 'rachinations/domain/modules/common/refiners/proc_convenience_methods'
6
6
  require 'rachinations/domain/modules/common/refiners/number_modifiers'
7
+ require 'rachinations/domain/modules/common/schedulable_tasks'
8
+
7
9
 
8
10
  require 'rachinations/extras/fifo'
9
11
 
@@ -1,10 +1,12 @@
1
1
  require_relative '../../domain/modules/common/invariant'
2
+ require_relative '../../domain/modules/common/schedulable_tasks'
2
3
  require_relative '../edge_collection'
3
4
  require_relative '../node_collection'
4
5
 
5
6
  class Diagram
6
7
 
7
8
  include Invariant
9
+ include SchedulableTasks
8
10
 
9
11
  attr_accessor :name, :max_iterations, :nodes, :edges
10
12
 
@@ -56,14 +58,15 @@ class Diagram
56
58
  node.attach_condition &condition
57
59
 
58
60
  if !triggered_by.nil?
61
+
59
62
  # ask the current class (diagram) to evaluate what node it is
60
- triggerer = self.send(triggered_by.to_sym)
63
+ triggerer = get_node(triggered_by)
61
64
  triggerer.attach_trigger(node)
62
65
  end
63
66
 
64
67
  if !triggers.nil?
65
- # ask the current class (diagram) to evaluate what node it is
66
- triggeree = self.send(triggers.to_sym)
68
+ # ask the diagram to evaluate what node it is
69
+ triggeree = get_node(triggers)
67
70
  node.attach_trigger(triggeree)
68
71
  end
69
72
 
@@ -77,17 +80,16 @@ class Diagram
77
80
 
78
81
  params.store(:diagram, self)
79
82
 
80
- #we need to send the actual nodes, not their names
81
- from = get_node(params.delete(:from))
82
- to = get_node(params.delete(:to))
83
-
84
- params.store(:from, from)
85
- params.store(:to, to)
83
+ # replace node names in params with the actual nodes
84
+ node_from = get_node(params.delete(:from))
85
+ params.store(:from, node_from)
86
+ node_to = get_node(params.delete(:to))
87
+ params.store(:to, node_to)
86
88
 
87
89
  edge = edge_klass.new(params)
88
90
 
89
- from.attach_edge!(edge)
90
- to.attach_edge!(edge)
91
+ node_from.attach_edge!(edge)
92
+ node_to.attach_edge!(edge)
91
93
 
92
94
  edges.push(edge)
93
95
 
@@ -4,6 +4,6 @@ class VerboseDiagram < Diagram
4
4
 
5
5
  #useful to see round-to-round changes, to help debugging for instance.
6
6
 
7
- include Verbose
7
+ include ::Verbose
8
8
 
9
9
  end
@@ -5,11 +5,12 @@ require_relative '../../../../lib/rachinations/domain/modules/common/refiners/nu
5
5
 
6
6
  class Edge
7
7
  include HashInit
8
- using NumberModifiers
9
8
 
9
+ using NumberModifiers
10
10
 
11
11
  attr_reader :from, :to, :name, :types
12
12
 
13
+ attr_writer :from, :to
13
14
 
14
15
  def label
15
16
  if @label.is_a?(Proc)
@@ -27,14 +28,14 @@ class Edge
27
28
 
28
29
  @name = params.fetch(:name, 'anonymous')
29
30
 
30
- @from = params.fetch(:from)
31
-
32
- @to = params.fetch(:to)
33
-
34
31
  @label = params.fetch(:label)
35
32
 
36
33
  @types = params.fetch(:types)
37
34
 
35
+ @from = params.fetch(:from) if params.has_key?(:from)
36
+
37
+ @to = params.fetch(:to) if params.has_key?(:to)
38
+
38
39
  end
39
40
 
40
41
  # Simulates a ping!, but no resources get actually
@@ -46,7 +47,7 @@ class Edge
46
47
  #
47
48
  # @return [Boolean] true in case a ping! on this Edge
48
49
  # would return true. False otherwise.
49
- def test_ping?(require_all:false)
50
+ def test_ping?(require_all: false)
50
51
  return false if from.disabled? || to.disabled?
51
52
 
52
53
  condition = strategy.condition
@@ -123,10 +124,13 @@ class Edge
123
124
  # end of this Edge.
124
125
  #
125
126
  # @raise [RuntimeError] in case the receiving node or this Edge
126
- # won't accept the resource sent.
127
+ # won't accept the resource sent.
128
+ # @raise [RuntimeError] if this edge hasn't defined :from and :to
129
+ # instance variables
127
130
  # @param res [Token] the resource to send.
128
131
  def push!(res)
129
- raise RuntimeError, "This Edge does not support type: #{res.type}" unless supports?(res.type)
132
+ raise RuntimeError, "Edge does not support type: #{res.type}" unless supports?(res.type)
133
+ raise RuntimeError, "Please define instance variables :from and :to" unless instance_variable_defined?(:@from) && instance_variable_defined?(:@to)
130
134
 
131
135
  begin
132
136
  to.put_resource!(res, self)
@@ -136,16 +140,20 @@ class Edge
136
140
  end
137
141
 
138
142
  # Tries to take a resource matching given block
139
- # from the node at the other end.
143
+ # from the node at the other end.
140
144
  #
141
145
  # @param [Proc] blk block that will define what resource the other node
142
- # should send.
146
+ # should send.
143
147
  # @raise [RuntimeError] in case the other node could provide no resources
144
- # that satisfy this condition block.
148
+ # that satisfy this condition block.
149
+ # @raise [RuntimeError] if this edge hasn't defined :from and :to
150
+ # instance variables
145
151
  # @return [Token,nil] a Resource that satisfies the given block or nil,
146
- # if the pull was not performed for some reason (e.g. it's probabilistic)
152
+ # if the pull was not performed for some reason (e.g. it's probabilistic)
147
153
  def pull!(blk)
148
154
 
155
+ raise RuntimeError, "Please define instance variables :from and :to" unless instance_variable_defined?(:@from) && instance_variable_defined?(:@to)
156
+
149
157
  begin
150
158
  res=from.take_resource!(blk)
151
159
  rescue => e
@@ -175,7 +183,7 @@ class Edge
175
183
  end
176
184
 
177
185
  def options
178
- [:name,:label,:types,:from,:to,:diagram]
186
+ [:name, :label, :types, :diagram, :from, :to]
179
187
  end
180
188
 
181
189
  end
@@ -0,0 +1,27 @@
1
+
2
+ module SchedulableTasks
3
+ def schedule_task(method, *params)
4
+ task = Hash.new
5
+ task[:method] = method
6
+ task[:params] = params
7
+
8
+ @scheduled_tasks ||= Array.new
9
+ @scheduled_tasks << task
10
+ end
11
+
12
+ def scheduled_tasks
13
+ @scheduled_tasks ||= Array.new
14
+ end
15
+
16
+ def run_scheduled_tasks
17
+ scheduled_tasks.each do |task|
18
+
19
+ method = task[:method]
20
+ params = task[:params]
21
+
22
+
23
+ method.call(*params)
24
+ end
25
+ end
26
+
27
+ end
@@ -18,24 +18,95 @@ module DSL
18
18
  raise BadDSL, "Unknown diagram mode: #{mode.to_s}"
19
19
  end
20
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)
21
+ # This is a modified version of Diagram#add_edge!. It defers some method
22
+ # calls that involve other nodes until after the end of the block that
23
+ # builds the diagram. this is done because, when these options are set,
24
+ # the nodes may not have been created yet.
25
+ # @param [Class] the edge class. probably Edge
26
+ # @param [Hash] params params to be passed to the constructor of given class
27
+ def dia.add_edge!(edge_klass, params)
24
28
 
25
- dia
29
+ params.store(:diagram, self)
26
30
 
27
- end
31
+ from_node_name = params.fetch(:from)
32
+ to_node_name = params.fetch(:to)
28
33
 
29
- def non_deterministic_diagram(name, verbose=:silent, &blk)
34
+ edge = edge_klass.new(params)
30
35
 
31
- dia=NonDeterministicDiagram.new(Parser.validate_name!(name))
36
+ # this method may contain nodes that may not yet exist
37
+ edge_attach_from = lambda do |edge, node_name, diagram|
38
+ # ask the diagram to evaluate what node it is
39
+ node = diagram.get_node(node_name)
40
+ node.attach_edge!(edge)
41
+ edge.from = node
42
+ end
43
+
44
+ # this method may contain nodes that may not yet exist
45
+ edge_attach_to = lambda do |edge, node_name, diagram|
46
+ # ask the diagram to evaluate what node it is
47
+ node = diagram.get_node(node_name)
48
+ node.attach_edge!(edge)
49
+ edge.to = node
50
+ end
51
+
52
+ # so they need to be scheduled and run later
53
+ schedule_task(edge_attach_from, edge, from_node_name, self)
54
+ schedule_task(edge_attach_to, edge, to_node_name, self)
55
+
56
+ edges.push(edge)
57
+
58
+ self
59
+
60
+ end
61
+
62
+ def dia.add_node!(node_klass, params)
63
+
64
+ params.store(:diagram, self)
65
+
66
+ # if there's a condition, return it, otherwise return default condition
67
+ condition = params.delete(:condition) { lambda { true } }
68
+
69
+ # similarly, if nodes are supposed to be triggered by another node
70
+ triggered_by = params.delete(:triggered_by) { nil }
71
+
72
+ # akin to :triggered_by, but it's defined in the triggerER
73
+ # rather than in the trigerrEE
74
+ triggers = params.delete(:triggers) { nil }
75
+
76
+ node = node_klass.new(params)
77
+
78
+ node.attach_condition &condition
79
+
80
+ if !triggered_by.nil?
81
+
82
+ attach_trigger_task = lambda do |triggeree, triggerer_name, diagram|
83
+ # ask the diagram to evaluate what node it is
84
+ triggerer = diagram.get_node(triggerer_name)
85
+ triggerer.attach_trigger(triggeree)
86
+ end
87
+ schedule_task(attach_trigger_task, node, triggered_by, self)
88
+
89
+ end
90
+
91
+ if !triggers.nil?
92
+
93
+ attach_trigger_task = lambda do |triggerer, triggeree_name, diagram|
94
+ # ask the diagram to evaluate what node it is
95
+ triggeree = diagram.send(triggeree_name.to_sym)
96
+ triggerer.attach_trigger(triggeree)
97
+ end
98
+ schedule_task(attach_trigger_task, node, triggers, self)
99
+
100
+ end
101
+
102
+ nodes.push(node)
103
+
104
+ self
32
105
 
33
- # cant verbose be a simple boolean instead?
34
- if verbose === :verbose
35
- dia.extend(Verbose)
36
106
  end
37
107
 
38
- dia.instance_eval &blk
108
+ dia.instance_eval(&blk)
109
+ dia.run_scheduled_tasks
39
110
 
40
111
  dia
41
112
 
@@ -76,7 +76,6 @@ module DSL
76
76
 
77
77
  end
78
78
 
79
-
80
79
  # so that I can easily access elements which have been given a name
81
80
  # (mostly nodes and maybe edges too)
82
81
  def method_missing(method_sym, *args, &block)
@@ -1,3 +1,3 @@
1
1
  module Rachinations
2
- VERSION = "0.0.6"
2
+ VERSION = "0.0.7"
3
3
  end
@@ -219,20 +219,52 @@ describe Diagram do
219
219
  end
220
220
 
221
221
 
222
- # it "forward-referencing of non existing nodes" do
223
- #
224
- # expect do
225
- #
226
- # d = diagram do
227
- # pool 'p2', initial_value: 7 # this will be triggered 10 times
228
- # edge from: 'p2', to: 'p3'
229
- # pool 'p3'
230
- # end
231
- #
232
- # end.not_to raise_error
233
- #
234
- # end
222
+ it "accepts declaring forward-referencing of non existing nodes" do
235
223
 
224
+ expect do
225
+ # triggered_by forward referencing a node
226
+ diagram do
227
+ pool 'p2', 7, triggered_by: 'p3'
228
+ pool 'p3'
229
+ end
230
+ end.not_to raise_error
231
+
232
+ expect do
233
+ # edge forward referencing its connected nodes
234
+ d = diagram do
235
+ pool 'p2', initial_value: 7 # this will be triggered 10 times
236
+ edge from: 'p2', to: 'p3'
237
+ pool 'p3'
238
+ end
239
+
240
+ end.not_to raise_error
241
+
242
+ end
243
+
244
+ it 'runs diagrams using forward-referencing' do
245
+
246
+ d = diagram do
247
+ pool 'p2',:automatic, :push_any, initial_value: 7 # this will be triggered 10 times
248
+ edge from: 'p2', to: 'p3'
249
+ pool 'p3'
250
+ end
251
+
252
+ d.run 10
253
+
254
+ expect(d.p3.resource_count).to eq 7
255
+
256
+ d2 = diagram do
257
+ pool :automatic, triggers: 'p2'
258
+ pool 'p2', :push_any, initial_value: 10
259
+ pool 'p3'
260
+ edge from: 'p2', to: 'p3'
261
+ end
262
+
263
+ d2.run 10
264
+ expect(d2.p3.resource_count).to eq 10
265
+ expect(d2.p2.resource_count).to eq 0
266
+
267
+ end
236
268
 
237
269
  end
238
270
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rachinations
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Felipe Almeida
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-20 00:00:00.000000000 Z
11
+ date: 2015-01-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -170,6 +170,7 @@ files:
170
170
  - lib/rachinations/domain/modules/common/invariant.rb
171
171
  - lib/rachinations/domain/modules/common/refiners/number_modifiers.rb
172
172
  - lib/rachinations/domain/modules/common/refiners/proc_convenience_methods.rb
173
+ - lib/rachinations/domain/modules/common/schedulable_tasks.rb
173
174
  - lib/rachinations/domain/modules/diagrams/verbose.rb
174
175
  - lib/rachinations/domain/node_collection.rb
175
176
  - lib/rachinations/domain/nodes/converter.rb