mini_kraken 0.1.01 → 0.1.02
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/CHANGELOG.md +3 -0
- data/README.md +0 -3
- data/lib/mini_kraken/core/any_value.rb +29 -0
- data/lib/mini_kraken/core/association.rb +21 -0
- data/lib/mini_kraken/core/association_walker.rb +179 -0
- data/lib/mini_kraken/core/atomic_term.rb +64 -0
- data/lib/mini_kraken/core/binary_relation.rb +61 -0
- data/lib/mini_kraken/core/composite_term.rb +54 -0
- data/lib/mini_kraken/core/cons_cell.rb +44 -0
- data/lib/mini_kraken/core/duck_fiber.rb +44 -0
- data/lib/mini_kraken/core/environment.rb +59 -0
- data/lib/mini_kraken/core/equals.rb +216 -0
- data/lib/mini_kraken/core/fail.rb +8 -5
- data/lib/mini_kraken/core/freshness.rb +42 -0
- data/lib/mini_kraken/core/goal.rb +31 -6
- data/lib/mini_kraken/core/k_integer.rb +15 -0
- data/lib/mini_kraken/core/k_symbol.rb +15 -0
- data/lib/mini_kraken/core/nullary_relation.rb +11 -3
- data/lib/mini_kraken/core/outcome.rb +35 -0
- data/lib/mini_kraken/core/relation.rb +31 -4
- data/lib/mini_kraken/core/succeed.rb +13 -1
- data/lib/mini_kraken/core/term.rb +7 -0
- data/lib/mini_kraken/core/variable.rb +45 -3
- data/lib/mini_kraken/core/variable_ref.rb +76 -0
- data/lib/mini_kraken/core/vocabulary.rb +161 -0
- data/lib/mini_kraken/glue/fresh_env.rb +31 -0
- data/lib/mini_kraken/glue/run_star_expression.rb +43 -0
- data/lib/mini_kraken/version.rb +1 -1
- data/spec/core/association_spec.rb +38 -0
- data/spec/core/association_walker_spec.rb +191 -0
- data/spec/core/cons_cell_spec.rb +63 -0
- data/spec/core/duck_fiber_spec.rb +62 -0
- data/spec/core/environment_spec.rb +154 -0
- data/spec/core/equals_spec.rb +289 -0
- data/spec/core/fail_spec.rb +16 -0
- data/spec/core/goal_spec.rb +36 -10
- data/spec/core/k_symbol_spec.rb +72 -0
- data/spec/core/succeed_spec.rb +43 -0
- data/spec/core/variable_ref_spec.rb +31 -0
- data/spec/core/variable_spec.rb +11 -3
- data/spec/core/vocabulary_spec.rb +188 -0
- data/spec/glue/fresh_env_spec.rb +36 -0
- data/spec/glue/run_star_expression_spec.rb +247 -0
- data/spec/support/factory_methods.rb +54 -0
- metadata +46 -13
- data/lib/mini_kraken/core/facade.rb +0 -45
- data/lib/mini_kraken/core/formal_arg.rb +0 -6
- data/lib/mini_kraken/core/publisher.rb +0 -27
- data/lib/mini_kraken/core/run_star_expression.rb +0 -34
- data/lib/mini_kraken/dsl/kraken_dsl.rb +0 -12
- data/spec/core/facade_spec.rb +0 -38
- data/spec/core/run_star_expression_spec.rb +0 -43
- data/spec/dsl/kraken_dsl_spec.rb +0 -31
@@ -0,0 +1,31 @@
|
|
1
|
+
require_relative '../core/environment'
|
2
|
+
require_relative '../core/variable'
|
3
|
+
|
4
|
+
module MiniKraken
|
5
|
+
module Glue
|
6
|
+
# (fresh (x) (== 'pea q))
|
7
|
+
# Introduces the new variable 'x'
|
8
|
+
# Takes a list of names and a goal-like object
|
9
|
+
# Must respond to message attain(aPublisher, vars) and must return an Outcome
|
10
|
+
class FreshEnv < Core::Environment
|
11
|
+
# @return [Goal]
|
12
|
+
attr_reader :goal
|
13
|
+
|
14
|
+
# @param theNames [Array<String>]
|
15
|
+
# @param aGoal [Goal]
|
16
|
+
def initialize(theNames, aGoal)
|
17
|
+
super()
|
18
|
+
@goal = aGoal
|
19
|
+
theNames.each { |nm| add_var(Core::Variable.new(nm)) }
|
20
|
+
end
|
21
|
+
|
22
|
+
# Attempt to achieve the goal given this environment
|
23
|
+
# @param aParent [Environment]
|
24
|
+
# @return [Fiber<Outcome>] A Fiber object that will generate the results.
|
25
|
+
def attain(aParent)
|
26
|
+
self.parent = aParent
|
27
|
+
goal.attain(self)
|
28
|
+
end
|
29
|
+
end # class
|
30
|
+
end # module
|
31
|
+
end # module
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require_relative '../core/any_value'
|
2
|
+
require_relative '../core/cons_cell'
|
3
|
+
require_relative 'fresh_env'
|
4
|
+
|
5
|
+
module MiniKraken
|
6
|
+
module Glue
|
7
|
+
class RunStarExpression
|
8
|
+
attr_reader :env
|
9
|
+
|
10
|
+
# @param var_name [String]
|
11
|
+
# @param goal [Core::Goal]
|
12
|
+
def initialize(var_name, goal)
|
13
|
+
@env = FreshEnv.new([var_name], goal)
|
14
|
+
end
|
15
|
+
|
16
|
+
def var
|
17
|
+
env.vars.values.first
|
18
|
+
end
|
19
|
+
|
20
|
+
def run
|
21
|
+
result = nil
|
22
|
+
solver = env.goal.attain(env)
|
23
|
+
# require 'debug'
|
24
|
+
loop do
|
25
|
+
outcome = solver.resume
|
26
|
+
break if outcome.nil?
|
27
|
+
env.clear
|
28
|
+
if result # ... more than one result...
|
29
|
+
else
|
30
|
+
if outcome.successful?
|
31
|
+
env.propagate(outcome)
|
32
|
+
result = Core::ConsCell.new(var.quote(outcome))
|
33
|
+
else
|
34
|
+
result = Core::NullList
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
result
|
40
|
+
end
|
41
|
+
end # class
|
42
|
+
end # module
|
43
|
+
end # module
|
data/lib/mini_kraken/version.rb
CHANGED
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../spec_helper' # Use the RSpec framework
|
4
|
+
require_relative '../../lib/mini_kraken/core/k_symbol'
|
5
|
+
require_relative '../../lib/mini_kraken/core/variable'
|
6
|
+
|
7
|
+
# Load the class under test
|
8
|
+
require_relative '../../lib/mini_kraken/core/association'
|
9
|
+
|
10
|
+
module MiniKraken
|
11
|
+
module Core
|
12
|
+
describe Association do
|
13
|
+
let(:pea) {KSymbol.new(:pea) }
|
14
|
+
subject { Association.new('q', pea) }
|
15
|
+
|
16
|
+
context 'Initialization:' do
|
17
|
+
it 'should be initialized with a name and a value' do
|
18
|
+
expect { Association.new('q', pea) }.not_to raise_error
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should be initialized with a variable and a value' do
|
22
|
+
expect { Association.new(Variable.new('p'), pea) }.not_to raise_error
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should know the variable name' do
|
26
|
+
expect(subject.var_name).to eq('q')
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should know the associated value' do
|
30
|
+
expect(subject.value).to eq(pea)
|
31
|
+
end
|
32
|
+
end # context
|
33
|
+
|
34
|
+
context 'Provided services:' do
|
35
|
+
end # context
|
36
|
+
end # describe
|
37
|
+
end # module
|
38
|
+
end # module
|
@@ -0,0 +1,191 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../spec_helper' # Use the RSpec framework
|
4
|
+
require_relative '../../lib/mini_kraken/core/environment'
|
5
|
+
require_relative '../support/factory_methods'
|
6
|
+
|
7
|
+
# Load the class under test
|
8
|
+
require_relative '../../lib/mini_kraken/core/association_walker'
|
9
|
+
|
10
|
+
|
11
|
+
module MiniKraken
|
12
|
+
module Core
|
13
|
+
describe AssociationWalker do
|
14
|
+
include FactoryMethods
|
15
|
+
|
16
|
+
subject { AssociationWalker.new }
|
17
|
+
|
18
|
+
context 'Initialization:' do
|
19
|
+
it 'should be initialized without argument' do
|
20
|
+
expect { AssociationWalker.new }.not_to raise_error
|
21
|
+
end
|
22
|
+
|
23
|
+
it "shouldn't have any visitee at initialization" do
|
24
|
+
expect(subject.visitees.size).to eq(0)
|
25
|
+
end
|
26
|
+
end # context
|
27
|
+
|
28
|
+
context 'Provided services:' do
|
29
|
+
let(:pea) { KSymbol.new(:pea) }
|
30
|
+
let(:pod) { KSymbol.new(:pod) }
|
31
|
+
let(:var_q) { Variable.new('q') }
|
32
|
+
let(:ref_q) { VariableRef.new('q') }
|
33
|
+
let(:var_x) { Variable.new('x') }
|
34
|
+
let(:ref_x) { VariableRef.new('x') }
|
35
|
+
let(:env) { Environment.new }
|
36
|
+
|
37
|
+
it 'should return composite when it has only atomic term(s)' do
|
38
|
+
expr1 = cons(pea)
|
39
|
+
expect(subject.walk_value(expr1, env)).to eq(expr1)
|
40
|
+
|
41
|
+
expr2 = cons(pea, pod)
|
42
|
+
expect(subject.walk_value(expr2, env)).to eq(expr2)
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should return composite when it has ground composite term(s)' do
|
46
|
+
expr1 = cons(pea, cons(pod))
|
47
|
+
expect(subject.walk_value(expr1, env)).to eq(expr1)
|
48
|
+
|
49
|
+
expr2 = cons(pea, cons(pod, cons(pea, cons(pod))))
|
50
|
+
expect(subject.walk_value(expr2, env)).to eq(expr2)
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should return nil when there is one fresh variable' do
|
54
|
+
env.add_var(var_q)
|
55
|
+
expr1 = cons(pea, cons(pod, ref_q))
|
56
|
+
expect(subject.walk_value(expr1, env)).to be_nil
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should return composite when it has ground composite term(s)' do
|
60
|
+
env.add_var(var_q)
|
61
|
+
env.add_assoc(Association.new('q', pea))
|
62
|
+
expr1 = cons(pea, cons(pod, cons(ref_q)))
|
63
|
+
expect(subject.walk_value(expr1, env)).to eq(expr1)
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'should return nil when no assocation exists' do
|
67
|
+
env.add_var(var_q)
|
68
|
+
env.add_assoc(Association.new('q', pea))
|
69
|
+
env.add_var(var_x)
|
70
|
+
|
71
|
+
expect(subject.find_ground(var_x.name, env)).to be_nil
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'should find an atomic term directly associated' do
|
75
|
+
env.add_var(var_q)
|
76
|
+
env.add_assoc(Association.new('q', pea))
|
77
|
+
|
78
|
+
result = subject.find_ground(var_q.name, env)
|
79
|
+
expect(result).to eq(pea)
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'should find an atomic term directly associated' do
|
83
|
+
env.add_var(var_q)
|
84
|
+
env.add_var(var_x)
|
85
|
+
env.add_assoc(Association.new('q', ref_x))
|
86
|
+
env.add_assoc(Association.new('x', pea))
|
87
|
+
expect(env['x']).not_to be_nil
|
88
|
+
|
89
|
+
result = subject.find_ground(var_q.name, env)
|
90
|
+
expect(result).to eq(pea)
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'should cope with cyclic structures' do
|
94
|
+
env.add_var(var_q)
|
95
|
+
env.add_var(var_x)
|
96
|
+
env.add_assoc(Association.new('q', ref_x))
|
97
|
+
env.add_assoc(Association.new('x', pea))
|
98
|
+
env.add_assoc(Association.new('x', ref_q))
|
99
|
+
|
100
|
+
result = subject.find_ground(var_q.name, env)
|
101
|
+
expect(result).to eq(pea)
|
102
|
+
|
103
|
+
result = subject.find_ground(var_x.name, env)
|
104
|
+
expect(result).to eq(pea)
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'should cope with a composite with atomic terms only' do
|
108
|
+
env.add_var(var_q)
|
109
|
+
expr = cons(pea, cons(pod, cons(pea)))
|
110
|
+
env.add_assoc(Association.new('q', expr))
|
111
|
+
|
112
|
+
result = subject.find_ground(var_q.name, env)
|
113
|
+
expect(result).to eq(expr)
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'should cope with a composite with one fresh variable' do
|
117
|
+
env.add_var(var_q)
|
118
|
+
env.add_var(var_x)
|
119
|
+
expr = cons(pea, cons(pod, cons(ref_x)))
|
120
|
+
env.add_assoc(Association.new('q', expr))
|
121
|
+
|
122
|
+
result = subject.find_ground(var_q.name, env)
|
123
|
+
expect(result).to be_nil
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'should cope with a composite with one ground variable' do
|
127
|
+
env.add_var(var_q)
|
128
|
+
env.add_var(var_x)
|
129
|
+
expr = cons(pea, cons(pod, cons(ref_x)))
|
130
|
+
env.add_assoc(Association.new('q', expr))
|
131
|
+
env.add_assoc(Association.new('x', pod))
|
132
|
+
|
133
|
+
result = subject.find_ground(var_q.name, env)
|
134
|
+
expect(result).to eq(expr)
|
135
|
+
end
|
136
|
+
=begin
|
137
|
+
=end
|
138
|
+
it 'should categorize a variable without association as free' do
|
139
|
+
env.add_var(var_q)
|
140
|
+
result = subject.determine_freshness(ref_q, env)
|
141
|
+
expect(result).to be_fresh
|
142
|
+
expect(result.associated).to be_nil
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'should categorize a variable related to fresh variable as bound' do
|
146
|
+
env.add_var(var_q)
|
147
|
+
env.add_var(var_x)
|
148
|
+
env.add_assoc(Association.new('q', ref_x))
|
149
|
+
|
150
|
+
result = subject.determine_freshness(ref_q, env)
|
151
|
+
expect(result).to be_bound
|
152
|
+
expect(result.associated).to eq(ref_x)
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'should categorize a variable even in presence of cycle(s)' do
|
156
|
+
env.add_var(var_q)
|
157
|
+
env.add_var(var_x)
|
158
|
+
env.add_assoc(Association.new('q', ref_x))
|
159
|
+
env.add_assoc(Association.new('x', ref_q))
|
160
|
+
|
161
|
+
result = subject.determine_freshness(ref_q, env)
|
162
|
+
expect(result).to be_bound
|
163
|
+
expect(result.associated).to eq(ref_x)
|
164
|
+
end
|
165
|
+
|
166
|
+
it 'should categorize an atomic term as ground term' do
|
167
|
+
result = subject.determine_freshness(pea, env)
|
168
|
+
expect(result).to be_ground
|
169
|
+
expect(result.associated).to eq(pea)
|
170
|
+
end
|
171
|
+
|
172
|
+
it 'should categorize a composite term as ground term' do
|
173
|
+
# Ground composite: a composite where all members are ground
|
174
|
+
composite = cons(pea, cons(pod))
|
175
|
+
result = subject.determine_freshness(composite, env)
|
176
|
+
expect(result).to be_ground
|
177
|
+
expect(result.associated).to eq(composite)
|
178
|
+
end
|
179
|
+
|
180
|
+
it 'should categorize a composite term as bound term' do
|
181
|
+
# Bound composite: a composite where at least one member is fresh
|
182
|
+
env.add_var(var_q)
|
183
|
+
composite = cons(pea, cons(ref_q))
|
184
|
+
result = subject.determine_freshness(composite, env)
|
185
|
+
expect(result).to be_bound
|
186
|
+
expect(result.associated).to eq(composite)
|
187
|
+
end
|
188
|
+
end # context
|
189
|
+
end # describe
|
190
|
+
end # module
|
191
|
+
end # module
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../spec_helper' # Use the RSpec framework
|
4
|
+
require_relative '../../lib/mini_kraken/core/k_symbol'
|
5
|
+
|
6
|
+
# Load the class under test
|
7
|
+
require_relative '../../lib/mini_kraken/core/cons_cell'
|
8
|
+
|
9
|
+
module MiniKraken
|
10
|
+
module Core
|
11
|
+
describe ConsCell do
|
12
|
+
let(:pea) {KSymbol.new(:pea) }
|
13
|
+
let(:pod) {KSymbol.new(:pod) }
|
14
|
+
subject { ConsCell.new(pea, pod) }
|
15
|
+
|
16
|
+
context 'Initialization:' do
|
17
|
+
it 'could be initialized with one argument' do
|
18
|
+
expect { ConsCell.new(pea) }.not_to raise_error
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'could be initialized with a second optional argument' do
|
22
|
+
expect { ConsCell.new(pea, pod) }.not_to raise_error
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should know its car child' do
|
26
|
+
expect(subject.car).to eq(pea)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should know its cdr child' do
|
30
|
+
expect(subject.cdr).to eq(pod)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should know its children' do
|
34
|
+
expect(subject.children).to eq([pea, pod])
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should know if it is empty (null)' do
|
38
|
+
expect(subject).not_to be_null
|
39
|
+
expect(ConsCell.new(nil, nil)).to be_null
|
40
|
+
expect(NullList).to be_null
|
41
|
+
end
|
42
|
+
end # context
|
43
|
+
|
44
|
+
context 'Provided services:' do
|
45
|
+
it 'should compare to itself' do
|
46
|
+
expect(subject.eql?(subject)).to be_truthy
|
47
|
+
expect(subject == subject).to be_truthy
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should compare to another instance' do
|
51
|
+
same = ConsCell.new(pea, pod)
|
52
|
+
expect(subject.eql?(same)).to be_truthy
|
53
|
+
|
54
|
+
different = ConsCell.new(pod, pea)
|
55
|
+
expect(subject.eql?(different)).to be_falsey
|
56
|
+
|
57
|
+
different = ConsCell.new(pea)
|
58
|
+
expect(subject.eql?(different)).to be_falsey
|
59
|
+
end
|
60
|
+
end # context
|
61
|
+
end # describe
|
62
|
+
end # module
|
63
|
+
end # module
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../spec_helper' # Use the RSpec framework
|
4
|
+
require_relative '../../lib/mini_kraken/core/environment'
|
5
|
+
|
6
|
+
# Load the class under test
|
7
|
+
require_relative '../../lib/mini_kraken/core/duck_fiber'
|
8
|
+
|
9
|
+
module MiniKraken
|
10
|
+
module Core
|
11
|
+
describe DuckFiber do
|
12
|
+
subject { DuckFiber.new(:failure) }
|
13
|
+
|
14
|
+
context 'Initialization:' do
|
15
|
+
it 'should be initialized with a symbol and an optional block' do
|
16
|
+
expect { DuckFiber.new(:failure) }.not_to raise_error
|
17
|
+
|
18
|
+
expect { DuckFiber.new(:custom) { Outcome.new(:"#s") } }.not_to raise_error
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should know its outcome' do
|
22
|
+
expect(subject.outcome).to eq(Failure)
|
23
|
+
end
|
24
|
+
end # context
|
25
|
+
|
26
|
+
context 'Provided services:' do
|
27
|
+
let(:parent) { Environment.new }
|
28
|
+
|
29
|
+
it 'should behave like a Fiber yielding a failure' do
|
30
|
+
failing = DuckFiber.new(:failure)
|
31
|
+
outcome = nil
|
32
|
+
expect { outcome = failing.resume }.not_to raise_error
|
33
|
+
expect(outcome).to eq(Failure)
|
34
|
+
|
35
|
+
# Only one result should be yielded
|
36
|
+
expect(failing.resume).to be_nil
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should behave like a Fiber yielding a basic success' do
|
40
|
+
succeeding = DuckFiber.new(:success)
|
41
|
+
outcome = nil
|
42
|
+
expect { outcome = succeeding.resume }.not_to raise_error
|
43
|
+
expect(outcome).to eq(BasicSuccess)
|
44
|
+
|
45
|
+
# Only one result should be yielded
|
46
|
+
expect(succeeding.resume).to be_nil
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should behave like a Fiber yielding a custom outcome' do
|
50
|
+
|
51
|
+
tailored = DuckFiber.new(:custom) { Outcome.new(:"#s", parent) }
|
52
|
+
outcome = nil
|
53
|
+
expect { outcome = tailored.resume }.not_to raise_error
|
54
|
+
expect(outcome).to eq(Outcome.new(:"#s", parent))
|
55
|
+
|
56
|
+
# Only one result should be yielded
|
57
|
+
expect(tailored.resume).to be_nil
|
58
|
+
end
|
59
|
+
end # context
|
60
|
+
end # describe
|
61
|
+
end # module
|
62
|
+
end # module
|
@@ -0,0 +1,154 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../spec_helper' # Use the RSpec framework
|
4
|
+
require_relative '../../lib/mini_kraken/core/k_symbol'
|
5
|
+
require_relative '../../lib/mini_kraken/core/variable'
|
6
|
+
require_relative '../../lib/mini_kraken/core/variable_ref'
|
7
|
+
require_relative '../../lib/mini_kraken/core/association'
|
8
|
+
require_relative '../../lib/mini_kraken/core/outcome'
|
9
|
+
|
10
|
+
# Load the class under test
|
11
|
+
require_relative '../../lib/mini_kraken/core/environment'
|
12
|
+
|
13
|
+
module MiniKraken
|
14
|
+
module Core
|
15
|
+
describe Environment do
|
16
|
+
subject { Environment.new }
|
17
|
+
|
18
|
+
context 'Initialization:' do
|
19
|
+
it 'should be initialized with an optional parent' do
|
20
|
+
expect { Environment.new }.not_to raise_error
|
21
|
+
parent = Environment.new
|
22
|
+
expect { Environment.new(parent) }.not_to raise_error
|
23
|
+
end
|
24
|
+
|
25
|
+
it "shouldn't have variable by default" do
|
26
|
+
expect(subject.vars).to be_empty
|
27
|
+
end
|
28
|
+
|
29
|
+
it "shouldn't have associations by default" do
|
30
|
+
expect(subject.associations).to be_empty
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'shold know its parent (if any)' do
|
34
|
+
# Case: no parent
|
35
|
+
expect(subject.parent).to be_nil
|
36
|
+
|
37
|
+
# Case: there is a parent
|
38
|
+
child = Environment.new(subject)
|
39
|
+
expect(child.parent).to eq(subject)
|
40
|
+
end
|
41
|
+
|
42
|
+
end # context
|
43
|
+
|
44
|
+
context 'Provided services:' do
|
45
|
+
let(:var_a) { Variable.new('a') }
|
46
|
+
let(:var_b) { Variable.new('b') }
|
47
|
+
let(:var_c) { Variable.new('c') }
|
48
|
+
let(:var_c_bis) { Variable.new('c') }
|
49
|
+
let(:pea) { KSymbol.new(:pea) }
|
50
|
+
let(:pod) { KSymbol.new(:pod) }
|
51
|
+
let(:pad) { KSymbol.new(:pad) }
|
52
|
+
|
53
|
+
it 'should accept the addition of a variable' do
|
54
|
+
subject.add_var(var_a)
|
55
|
+
expect(subject.vars).not_to be_empty
|
56
|
+
expect(subject.vars['a']).to eq(var_a)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should accept the addition of multiple variables' do
|
60
|
+
subject.add_var(var_a)
|
61
|
+
expect(subject.vars).not_to be_empty
|
62
|
+
subject.add_var(var_b)
|
63
|
+
expect(subject.vars['a']).to eq(var_a)
|
64
|
+
expect(subject.vars['b']).to eq(var_b)
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'should accept the addition of an association' do
|
68
|
+
subject.add_var(var_a)
|
69
|
+
assoc = Association.new('a', pea)
|
70
|
+
subject.add_assoc(assoc)
|
71
|
+
expect(subject.associations.size).to eq(1)
|
72
|
+
expect(subject.associations['a']).to eq([assoc])
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'should tell that a newborn variable is fresh' do
|
76
|
+
subject.add_var(var_a)
|
77
|
+
|
78
|
+
# By default, a variable is fresh...
|
79
|
+
expect(subject.fresh?(var_a)).to be_truthy
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should tell variable associated with a literal value isn't fresh" do
|
83
|
+
subject.add_var(var_a)
|
84
|
+
|
85
|
+
# Let's associate an atomic term...
|
86
|
+
assoc = Association.new('a', pea)
|
87
|
+
subject.add_assoc(assoc)
|
88
|
+
|
89
|
+
expect(subject.fresh?(var_a)).to be_falsey
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should cope with a variable associated with another variable" do
|
93
|
+
subject.add_var(var_a)
|
94
|
+
subject.add_var(var_b)
|
95
|
+
|
96
|
+
# Let's associate a with (fresh) b
|
97
|
+
assoc = Association.new(var_a, var_b)
|
98
|
+
subject.add_assoc(assoc)
|
99
|
+
|
100
|
+
expect(subject.fresh?(var_a)).to be_truthy
|
101
|
+
|
102
|
+
# Now associate b with something ground...
|
103
|
+
assoc_b = Association.new(var_b, pea)
|
104
|
+
subject.add_assoc(assoc_b)
|
105
|
+
|
106
|
+
# b is no more fresh, so is ... a
|
107
|
+
expect(subject.fresh?(var_b)).to be_falsey
|
108
|
+
expect(subject.fresh?(var_a)).to be_falsey
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'should remove all associations' do
|
112
|
+
subject.add_var(var_a)
|
113
|
+
assoc = Association.new(var_a, pea)
|
114
|
+
subject.add_assoc(assoc)
|
115
|
+
|
116
|
+
subject.add_var(var_b)
|
117
|
+
assoc = Association.new(var_b, pod)
|
118
|
+
subject.add_assoc(assoc)
|
119
|
+
|
120
|
+
subject.clear
|
121
|
+
expect(subject.fresh?(var_a)).to be_truthy
|
122
|
+
expect(subject.fresh?(var_a)).to be_truthy
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'should propagate associations up in the environment hierarchy' do
|
126
|
+
parent = Environment.new
|
127
|
+
parent.add_var(var_a)
|
128
|
+
# parent.add_var(var_c)
|
129
|
+
instance = Environment.new(parent)
|
130
|
+
instance.add_var(var_b)
|
131
|
+
# instance.add_var(var_c_bis) # Should shadow parent's c variable
|
132
|
+
|
133
|
+
outcome = Outcome.new(:"#s", instance)
|
134
|
+
outcome.add_assoc(Association.new(var_a, pea))
|
135
|
+
outcome.add_assoc(Association.new(var_b, pod))
|
136
|
+
# outcome.add_assoc(Association.new(var_c_bis, pad))
|
137
|
+
expect(outcome.associations.size).to eq(2)
|
138
|
+
|
139
|
+
# Propagate: outcome -> .. -> instance
|
140
|
+
instance.propagate(outcome)
|
141
|
+
expect(outcome.associations.size).to eq(1)
|
142
|
+
expect(instance.associations[var_b.name]).not_to be_nil
|
143
|
+
expect(parent.associations[var_a.name]).to be_nil
|
144
|
+
|
145
|
+
# Propagate: outcome -> .. -> parent
|
146
|
+
parent.propagate(outcome)
|
147
|
+
expect(outcome.associations).to be_empty
|
148
|
+
expect(parent.associations[var_b.name]).to be_nil
|
149
|
+
expect(parent.associations[var_a.name]).not_to be_nil
|
150
|
+
end
|
151
|
+
end # context
|
152
|
+
end # describe
|
153
|
+
end # module
|
154
|
+
end # module
|