rachinations 0.0.6 → 0.0.7

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