rachinations 0.0.5 → 0.0.6
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 +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +1 -25
- data/Rakefile +4 -4
- data/lib/rachinations/domain/diagrams/diagram.rb +12 -2
- data/lib/rachinations/domain/edges/edge.rb +9 -1
- data/lib/rachinations/domain/exceptions/bad_config.rb +4 -0
- data/lib/rachinations/domain/modules/common/hash_init.rb +1 -2
- data/lib/rachinations/domain/modules/common/refiners/number_modifiers.rb +1 -1
- data/lib/rachinations/domain/nodes/pool.rb +3 -1
- data/lib/rachinations/domain/nodes/source.rb +7 -3
- data/lib/rachinations/dsl/bootstrap.rb +0 -3
- data/lib/rachinations/dsl/helpers/parser.rb +50 -41
- data/lib/rachinations/version.rb +1 -1
- data/lib/rachinations.rb +6 -4
- data/testing/spec/non_deterministic_diagram_spec.rb +2 -2
- data/testing/spec/release1/dsl_spec.rb +36 -2
- data/testing/spec/xexeo_spec.rb +4 -4
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7cdd3c499e1f1791ce742a6a2cc6485fce449c53
|
4
|
+
data.tar.gz: b39dd99ffa4514366b7047be022fb69323a953d8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ac6c02f660108180d6f7d48e048c7ec30ce90a5a1f3f476d19f21e0b0e390073433766bcf868f0a856f3018c2ee33f892e0bdccbed1fff5e1a656f26bfb26be2
|
7
|
+
data.tar.gz: 196440e524df7fa67b43fa13aac1726378a83d578c221769d0ad95ab4f73ecc60ea0c2ee9b74e51b60e3bc2ca50e3ed3c800b85b7e73071f7645ebda8fa8d2f0
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -15,28 +15,4 @@ It provides a Ruby-based DSL to enable game designers to create and also test te
|
|
15
15
|
|
16
16
|
- Classes to model the domain
|
17
17
|
- Tests
|
18
|
-
- A simple DSL (Domain-specific language) whose objective is to enable anyone to write Machinations diagrams, run them, obtain metrics, compose subdiagrams and so on.
|
19
|
-
|
20
|
-
### DSL Usage
|
21
|
-
- Simplest possible usage:
|
22
|
-
- Install the `rachinations` [gem](http://rubygems.org/gems/rachinations)
|
23
|
-
|
24
|
-
```
|
25
|
-
$ gem install rachinations
|
26
|
-
```
|
27
|
-
- Require it into your code and start designing diagrams:
|
28
|
-
|
29
|
-
```ruby
|
30
|
-
require 'rachinations'
|
31
|
-
|
32
|
-
n=diagram 'my diagram' do
|
33
|
-
node 's1',Source
|
34
|
-
node 'p1', Pool
|
35
|
-
edge 'e1', Edge, 's1','p1'
|
36
|
-
end
|
37
|
-
|
38
|
-
n.run!(5)
|
39
|
-
|
40
|
-
p n.get_node("p1").resource_count
|
41
|
-
#prints 5
|
42
|
-
```
|
18
|
+
- A simple DSL (Domain-specific language) whose objective is to enable anyone to write Machinations diagrams, run them, obtain metrics, compose subdiagrams and so on.
|
data/Rakefile
CHANGED
@@ -5,12 +5,12 @@ require 'bundler/gem_tasks'
|
|
5
5
|
|
6
6
|
task :default => [:spec]
|
7
7
|
|
8
|
-
Rake::TestTask.new do |t|
|
9
|
-
t.pattern = 'testing/**/*_test.rb'
|
10
|
-
end
|
8
|
+
#Rake::TestTask.new do |t|
|
9
|
+
# t.pattern = 'testing/**/*_test.rb'
|
10
|
+
#end
|
11
11
|
|
12
12
|
RSpec::Core::RakeTask.new do |t|
|
13
|
-
t.rspec_opts= ['--default-path testing/spec','--color']
|
13
|
+
t.rspec_opts= ['--default-path testing/spec','--color','--pattern **/*_spec.rb']
|
14
14
|
end
|
15
15
|
|
16
16
|
|
@@ -41,12 +41,16 @@ class Diagram
|
|
41
41
|
|
42
42
|
params.store(:diagram, self)
|
43
43
|
|
44
|
-
#if there's a condition, return it, otherwise return default condition
|
44
|
+
# if there's a condition, return it, otherwise return default condition
|
45
45
|
condition = params.delete(:condition) { lambda { true } }
|
46
46
|
|
47
|
-
#similarly, if nodes are supposed to be triggered by another node
|
47
|
+
# similarly, if nodes are supposed to be triggered by another node
|
48
48
|
triggered_by = params.delete(:triggered_by) { nil }
|
49
49
|
|
50
|
+
# akin to :triggered_by, but it's defined in the triggerER
|
51
|
+
# rather than in the trigerrEE
|
52
|
+
triggers = params.delete(:triggers) { nil }
|
53
|
+
|
50
54
|
node = node_klass.new(params)
|
51
55
|
|
52
56
|
node.attach_condition &condition
|
@@ -57,6 +61,12 @@ class Diagram
|
|
57
61
|
triggerer.attach_trigger(node)
|
58
62
|
end
|
59
63
|
|
64
|
+
if !triggers.nil?
|
65
|
+
# ask the current class (diagram) to evaluate what node it is
|
66
|
+
triggeree = self.send(triggers.to_sym)
|
67
|
+
node.attach_trigger(triggeree)
|
68
|
+
end
|
69
|
+
|
60
70
|
nodes.push(node)
|
61
71
|
|
62
72
|
self
|
@@ -8,9 +8,17 @@ class Edge
|
|
8
8
|
using NumberModifiers
|
9
9
|
|
10
10
|
|
11
|
-
attr_reader :from, :to, :name, :
|
11
|
+
attr_reader :from, :to, :name, :types
|
12
12
|
|
13
13
|
|
14
|
+
def label
|
15
|
+
if @label.is_a?(Proc)
|
16
|
+
@label.call
|
17
|
+
else
|
18
|
+
@label
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
14
22
|
def initialize(hsh)
|
15
23
|
|
16
24
|
check_options!(hsh)
|
@@ -3,6 +3,7 @@ require_relative '../../domain/nodes/node'
|
|
3
3
|
require_relative '../../domain/resources/token'
|
4
4
|
require_relative '../resource_bag'
|
5
5
|
require_relative '../../domain/exceptions/no_elements_matching_condition_error'
|
6
|
+
require_relative '../../domain/exceptions/bad_config'
|
6
7
|
require_relative '../../domain/modules/common/refiners/proc_convenience_methods'
|
7
8
|
require_relative '../../../../lib/rachinations/helpers/edge_helper'
|
8
9
|
|
@@ -59,8 +60,9 @@ class Pool < ResourcefulNode
|
|
59
60
|
pull_all!
|
60
61
|
|
61
62
|
else
|
62
|
-
|
63
|
+
raise BadConfig, "Invalid config for this node's mode"
|
63
64
|
end
|
65
|
+
fire_triggers!
|
64
66
|
end
|
65
67
|
end
|
66
68
|
|
@@ -2,7 +2,6 @@ require_relative '../../domain/nodes/pool'
|
|
2
2
|
|
3
3
|
class Source < ResourcefulNode
|
4
4
|
|
5
|
-
|
6
5
|
def initialize(hsh={})
|
7
6
|
|
8
7
|
check_options!(hsh)
|
@@ -65,12 +64,17 @@ class Source < ResourcefulNode
|
|
65
64
|
|
66
65
|
push_any!
|
67
66
|
|
68
|
-
elsif
|
67
|
+
elsif push? && all?
|
68
|
+
|
69
|
+
push_all!
|
69
70
|
|
70
|
-
|
71
|
+
else
|
72
|
+
raise BadConfig, 'Invalid mode for Source'
|
71
73
|
|
72
74
|
end
|
73
75
|
|
76
|
+
fire_triggers!
|
77
|
+
|
74
78
|
end
|
75
79
|
end
|
76
80
|
|
@@ -9,20 +9,19 @@ module DSL
|
|
9
9
|
|
10
10
|
ConstantHash = ::Extras::ConstantHash
|
11
11
|
|
12
|
-
# these patterns
|
12
|
+
# these patterns define what each argument should look like
|
13
13
|
|
14
|
-
|
14
|
+
IDENTIFIER = proc { |arg| arg.is_a?(String) && valid_name?(arg) }
|
15
15
|
|
16
|
-
|
16
|
+
INITIAL_VALUE = proc { |arg| arg.is_a? Fixnum }
|
17
17
|
|
18
|
-
|
18
|
+
MODE = proc { |arg| [:pull_any, :pull_all, :push_any, :push_all].include? arg }
|
19
19
|
|
20
|
-
|
20
|
+
ACTIVATION= proc { |arg| [:automatic, :passive, :start].include? arg }
|
21
21
|
|
22
|
-
|
22
|
+
PROC = proc { |arg| arg.is_a? Proc }
|
23
23
|
|
24
|
-
|
25
|
-
LABEL_EXPR = proc { |arg| arg.is_a? Numeric }
|
24
|
+
LABEL = proc { |arg| arg.is_a?(Numeric) || arg.is_a?(Proc) }
|
26
25
|
|
27
26
|
# Parse an arbitrary list of arguments and returns a well-formed
|
28
27
|
# Hash which can then be used as argument to method add_node!
|
@@ -31,57 +30,66 @@ module DSL
|
|
31
30
|
def self.parse_arguments(arguments)
|
32
31
|
arguments.inject(ConstantHash.new) do |accumulator, arg|
|
33
32
|
|
34
|
-
# named parameters are expressed
|
33
|
+
# named parameters are expressed as hashes
|
35
34
|
# and all arguments can (also) be passed as named parameters
|
36
35
|
if arg.is_a? Hash
|
36
|
+
|
37
|
+
if arg.has_key? :activation
|
38
|
+
if ACTIVATION.match? arg[:activation]
|
39
|
+
accumulator[:activation] = arg[:activation]
|
40
|
+
else
|
41
|
+
raise BadDSL.new
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
37
45
|
if arg.has_key? :condition
|
38
|
-
if
|
46
|
+
if PROC.match? arg[:condition]
|
39
47
|
accumulator[:condition] = arg[:condition]
|
40
48
|
else
|
41
49
|
raise BadDSL.new
|
42
50
|
end
|
43
51
|
end
|
44
52
|
|
45
|
-
if arg.has_key? :
|
46
|
-
if
|
47
|
-
accumulator[:
|
53
|
+
if arg.has_key? :initial_value
|
54
|
+
if INITIAL_VALUE.match? arg[:initial_value]
|
55
|
+
accumulator[:initial_value] = arg[:initial_value]
|
48
56
|
else
|
49
57
|
raise BadDSL.new
|
50
58
|
end
|
51
59
|
end
|
52
60
|
|
53
|
-
if arg.has_key? :
|
54
|
-
if
|
55
|
-
accumulator[:
|
61
|
+
if arg.has_key? :mode
|
62
|
+
if MODE.match? arg[:mode]
|
63
|
+
accumulator[:mode] = arg[:mode]
|
56
64
|
else
|
57
65
|
raise BadDSL.new
|
58
66
|
end
|
59
67
|
end
|
60
68
|
|
61
|
-
if arg.has_key? :
|
62
|
-
if
|
63
|
-
accumulator[:
|
69
|
+
if arg.has_key? :triggered_by
|
70
|
+
if IDENTIFIER.match? arg[:triggered_by]
|
71
|
+
accumulator[:triggered_by] = arg[:triggered_by]
|
64
72
|
else
|
65
73
|
raise BadDSL.new
|
66
74
|
end
|
67
75
|
end
|
68
76
|
|
69
|
-
if arg.has_key? :
|
70
|
-
if
|
71
|
-
accumulator[:
|
77
|
+
if arg.has_key? :triggers
|
78
|
+
if IDENTIFIER.match? arg[:triggers]
|
79
|
+
accumulator[:triggers] = arg[:triggers]
|
72
80
|
else
|
73
81
|
raise BadDSL.new
|
74
82
|
end
|
75
83
|
end
|
76
84
|
|
77
85
|
else
|
78
|
-
if
|
86
|
+
if IDENTIFIER.match?(arg) # a node's name, if present, is always the first argument
|
79
87
|
accumulator[:name] = arg
|
80
|
-
elsif
|
88
|
+
elsif INITIAL_VALUE.match?(arg)
|
81
89
|
accumulator[:initial_value] = arg
|
82
|
-
elsif
|
90
|
+
elsif MODE.match?(arg)
|
83
91
|
accumulator[:mode] = arg
|
84
|
-
elsif
|
92
|
+
elsif ACTIVATION.match?(arg)
|
85
93
|
accumulator[:activation] = arg
|
86
94
|
else
|
87
95
|
raise BadDSL, "Argument #{arg} doesn't fit any known signature"
|
@@ -99,16 +107,16 @@ module DSL
|
|
99
107
|
arguments.inject(ConstantHash.new) do |accumulator, arg|
|
100
108
|
if arg.is_a? Hash
|
101
109
|
if arg.has_key? :condition
|
102
|
-
accumulator[:condition] = arg[:condition] if
|
110
|
+
accumulator[:condition] = arg[:condition] if PROC.match?(arg[:condition])
|
103
111
|
elsif arg.has_key? :triggered_by
|
104
|
-
accumulator[:triggered_by] = arg[:triggered_by] if
|
112
|
+
accumulator[:triggered_by] = arg[:triggered_by] if IDENTIFIER.match?(arg[:triggered_by])
|
105
113
|
else
|
106
|
-
|
114
|
+
raise BadDSL, "Named argument doesn't fit any known signature"
|
107
115
|
end
|
108
116
|
else
|
109
|
-
if
|
117
|
+
if IDENTIFIER.match?(arg)
|
110
118
|
accumulator[:name] = arg
|
111
|
-
elsif
|
119
|
+
elsif ACTIVATION.match?(arg)
|
112
120
|
accumulator[:activation] = arg
|
113
121
|
else
|
114
122
|
raise BadDSL, "Argument #{arg} doesn't fit any known signature"
|
@@ -122,23 +130,24 @@ module DSL
|
|
122
130
|
def self.parse_edge_arguments(arguments)
|
123
131
|
|
124
132
|
arguments.inject(ConstantHash.new) do |accumulator, arg|
|
125
|
-
if
|
126
|
-
accumulator[:name] = arg
|
127
|
-
elsif LABEL_EXPR.match?(arg)
|
128
|
-
accumulator[:label]=arg
|
129
|
-
elsif arg.is_a? Hash
|
130
|
-
|
133
|
+
if arg.is_a? Hash
|
131
134
|
if arg.has_key? :from
|
132
|
-
accumulator[:from] = arg[:from]
|
135
|
+
accumulator[:from] = arg[:from] if IDENTIFIER.match? arg[:from]
|
133
136
|
end
|
134
137
|
if arg.has_key? :to
|
135
|
-
accumulator[:to] = arg[:to]
|
138
|
+
accumulator[:to] = arg[:to] if IDENTIFIER.match? arg[:to]
|
136
139
|
end
|
137
140
|
if arg.has_key? :label
|
138
|
-
accumulator[:label] = arg[:label]
|
141
|
+
accumulator[:label] = arg[:label] if LABEL.match? arg[:label]
|
139
142
|
end
|
140
143
|
else
|
141
|
-
|
144
|
+
if IDENTIFIER.match?(arg)
|
145
|
+
accumulator[:name] = arg
|
146
|
+
elsif LABEL.match?(arg)
|
147
|
+
accumulator[:label]=arg
|
148
|
+
else
|
149
|
+
raise BadDSL, "Argument #{arg} doesn't fit any known signature."
|
150
|
+
end
|
142
151
|
end
|
143
152
|
accumulator
|
144
153
|
end
|
data/lib/rachinations/version.rb
CHANGED
data/lib/rachinations.rb
CHANGED
@@ -18,6 +18,7 @@ require 'rachinations/domain/edges/edge'
|
|
18
18
|
require 'rachinations/domain/exceptions/no_elements_of_given_type'
|
19
19
|
require 'rachinations/domain/exceptions/unsupported_type_error'
|
20
20
|
require 'rachinations/domain/exceptions/bad_options'
|
21
|
+
require 'rachinations/domain/exceptions/bad_config'
|
21
22
|
require 'rachinations/domain/exceptions/no_elements_matching_condition_error'
|
22
23
|
require 'rachinations/domain/exceptions/no_elements_found'
|
23
24
|
require 'rachinations/dsl/bad_dsl'
|
@@ -36,9 +37,10 @@ require 'rachinations/domain/node_collection'
|
|
36
37
|
require 'rachinations/domain/resource_bag'
|
37
38
|
|
38
39
|
|
39
|
-
# users can call .percent on integers
|
40
|
-
using NumberModifiers
|
41
|
-
|
42
40
|
# users can use the dsl to create diagrams
|
43
41
|
include DSL::Bootstrap
|
44
|
-
|
42
|
+
|
43
|
+
# users can call .percent on numbers
|
44
|
+
include NumberModifiers
|
45
|
+
|
46
|
+
|
@@ -11,13 +11,13 @@ describe NonDeterministicDiagram do
|
|
11
11
|
name: 'g1',
|
12
12
|
activation: :automatic,
|
13
13
|
initial_value: 5,
|
14
|
-
mode: :
|
14
|
+
mode: :push_any
|
15
15
|
}
|
16
16
|
|
17
17
|
generator.add_node! Pool, {
|
18
18
|
name: 'g2',
|
19
19
|
activation: :automatic,
|
20
|
-
mode: :
|
20
|
+
mode: :push_any
|
21
21
|
}
|
22
22
|
|
23
23
|
generator.add_node! Pool, {
|
@@ -2,8 +2,6 @@ require_relative '../spec_helper'
|
|
2
2
|
|
3
3
|
describe Diagram do
|
4
4
|
|
5
|
-
using NumberModifiers
|
6
|
-
|
7
5
|
context 'diagram tests using the dsl' do
|
8
6
|
|
9
7
|
it 'runs a simple example diagram' do
|
@@ -185,6 +183,42 @@ describe Diagram do
|
|
185
183
|
|
186
184
|
end
|
187
185
|
|
186
|
+
it "accepts procs for edge labels" do
|
187
|
+
|
188
|
+
d = diagram do
|
189
|
+
source 's'
|
190
|
+
pool 'p'
|
191
|
+
edge from: 's', to: 'p', label: expr { rand(10) }
|
192
|
+
end
|
193
|
+
|
194
|
+
d.run 2
|
195
|
+
|
196
|
+
# this is clearly not an exhaustive test but itll do for now
|
197
|
+
|
198
|
+
expect(d.p.resource_count).to be <= 20
|
199
|
+
expect(d.p.resource_count).to be >= 0
|
200
|
+
|
201
|
+
end
|
202
|
+
|
203
|
+
it 'accepts :triggers' do
|
204
|
+
|
205
|
+
# see how it gets confusing when you to turn your logic
|
206
|
+
# around in your head and define stuff in the wrong order
|
207
|
+
|
208
|
+
d = diagram do
|
209
|
+
pool 'p2'
|
210
|
+
pool 'p1', :push_any, initial_value: 7
|
211
|
+
source 's', triggers: 'p1'
|
212
|
+
edge from: 'p1', to: 'p2'
|
213
|
+
end
|
214
|
+
|
215
|
+
d.run 10
|
216
|
+
|
217
|
+
expect(d.p2.resource_count).to eq 7
|
218
|
+
|
219
|
+
end
|
220
|
+
|
221
|
+
|
188
222
|
# it "forward-referencing of non existing nodes" do
|
189
223
|
#
|
190
224
|
# expect do
|
data/testing/spec/xexeo_spec.rb
CHANGED
@@ -26,13 +26,13 @@ describe Diagram do
|
|
26
26
|
:name => 'g1',
|
27
27
|
:activation => :automatic,
|
28
28
|
:initial_value => 5,
|
29
|
-
mode: :
|
29
|
+
mode: :push_any
|
30
30
|
}
|
31
31
|
|
32
32
|
generator.add_node! Pool, {
|
33
33
|
:name => 'g2',
|
34
34
|
:activation => :automatic,
|
35
|
-
mode: :
|
35
|
+
mode: :push_any
|
36
36
|
}
|
37
37
|
|
38
38
|
generator.add_node! Pool, {
|
@@ -68,13 +68,13 @@ describe Diagram do
|
|
68
68
|
name: 'g1',
|
69
69
|
activation: :automatic,
|
70
70
|
initial_value: 5,
|
71
|
-
mode: :
|
71
|
+
mode: :push_any
|
72
72
|
}
|
73
73
|
|
74
74
|
generator.add_node! Pool, {
|
75
75
|
name: 'g2',
|
76
76
|
activation: :automatic,
|
77
|
-
mode: :
|
77
|
+
mode: :push_any
|
78
78
|
}
|
79
79
|
|
80
80
|
generator.add_node! Pool, {
|
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.
|
4
|
+
version: 0.0.6
|
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-
|
11
|
+
date: 2015-01-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -160,6 +160,7 @@ files:
|
|
160
160
|
- lib/rachinations/domain/diagrams/verbose_diagram.rb
|
161
161
|
- lib/rachinations/domain/edge_collection.rb
|
162
162
|
- lib/rachinations/domain/edges/edge.rb
|
163
|
+
- lib/rachinations/domain/exceptions/bad_config.rb
|
163
164
|
- lib/rachinations/domain/exceptions/bad_options.rb
|
164
165
|
- lib/rachinations/domain/exceptions/no_elements_found.rb
|
165
166
|
- lib/rachinations/domain/exceptions/no_elements_matching_condition_error.rb
|