mini_kraken 0.2.02 → 0.3.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/.rubocop.yml +378 -333
- data/CHANGELOG.md +52 -0
- data/README.md +19 -19
- data/lib/mini_kraken.rb +0 -1
- data/lib/mini_kraken/atomic/all_atomic.rb +5 -0
- data/lib/mini_kraken/atomic/atomic_term.rb +96 -0
- data/lib/mini_kraken/atomic/k_boolean.rb +42 -0
- data/lib/mini_kraken/{core → atomic}/k_integer.rb +2 -5
- data/lib/mini_kraken/atomic/k_string.rb +17 -0
- data/lib/mini_kraken/{core → atomic}/k_symbol.rb +4 -8
- data/lib/mini_kraken/composite/all_composite.rb +4 -0
- data/lib/mini_kraken/composite/composite_term.rb +27 -0
- data/lib/mini_kraken/composite/cons_cell.rb +299 -0
- data/lib/mini_kraken/composite/cons_cell_visitor.rb +50 -0
- data/lib/mini_kraken/composite/list.rb +32 -0
- data/lib/mini_kraken/core/all_core.rb +8 -0
- data/lib/mini_kraken/core/any_value.rb +31 -7
- data/lib/mini_kraken/core/arity.rb +69 -0
- data/lib/mini_kraken/core/association.rb +29 -4
- data/lib/mini_kraken/core/association_copy.rb +50 -0
- data/lib/mini_kraken/core/base_term.rb +13 -0
- data/lib/mini_kraken/core/blackboard.rb +315 -0
- data/lib/mini_kraken/core/bookmark.rb +46 -0
- data/lib/mini_kraken/core/context.rb +492 -0
- data/lib/mini_kraken/core/duck_fiber.rb +21 -19
- data/lib/mini_kraken/core/entry.rb +40 -0
- data/lib/mini_kraken/core/fail.rb +20 -18
- data/lib/mini_kraken/core/fusion.rb +29 -0
- data/lib/mini_kraken/core/goal.rb +20 -29
- data/lib/mini_kraken/core/log_var.rb +22 -0
- data/lib/mini_kraken/core/log_var_ref.rb +108 -0
- data/lib/mini_kraken/core/nullary_relation.rb +2 -9
- data/lib/mini_kraken/core/parametrized_term.rb +61 -0
- data/lib/mini_kraken/core/relation.rb +14 -28
- data/lib/mini_kraken/core/scope.rb +67 -0
- data/lib/mini_kraken/core/solver_adapter.rb +58 -0
- data/lib/mini_kraken/core/specification.rb +48 -0
- data/lib/mini_kraken/core/succeed.rb +21 -17
- data/lib/mini_kraken/core/symbol_table.rb +137 -0
- data/lib/mini_kraken/core/term.rb +15 -4
- data/lib/mini_kraken/glue/dsl.rb +45 -81
- data/lib/mini_kraken/glue/run_star_expression.rb +28 -30
- data/lib/mini_kraken/rela/all_rela.rb +8 -0
- data/lib/mini_kraken/rela/binary_relation.rb +30 -0
- data/lib/mini_kraken/rela/conde.rb +143 -0
- data/lib/mini_kraken/rela/conj2.rb +65 -0
- data/lib/mini_kraken/rela/def_relation.rb +93 -0
- data/lib/mini_kraken/rela/disj2.rb +70 -0
- data/lib/mini_kraken/rela/fresh.rb +98 -0
- data/lib/mini_kraken/{core → rela}/goal_relation.rb +7 -9
- data/lib/mini_kraken/rela/unify.rb +258 -0
- data/lib/mini_kraken/version.rb +1 -1
- data/mini_kraken.gemspec +2 -2
- data/spec/.rubocop.yml +1 -1
- data/spec/atomic/atomic_term_spec.rb +98 -0
- data/spec/{core → atomic}/k_boolean_spec.rb +19 -34
- data/spec/{core → atomic}/k_symbol_spec.rb +3 -16
- data/spec/composite/cons_cell_spec.rb +225 -0
- data/spec/composite/cons_cell_visitor_spec.rb +158 -0
- data/spec/composite/list_spec.rb +50 -0
- data/spec/core/any_value_spec.rb +52 -0
- data/spec/core/arity_spec.rb +92 -0
- data/spec/core/association_copy_spec.rb +69 -0
- data/spec/core/association_spec.rb +31 -4
- data/spec/core/blackboard_spec.rb +287 -0
- data/spec/core/bookmark_spec.rb +40 -0
- data/spec/core/context_spec.rb +245 -0
- data/spec/core/core_spec.rb +40 -0
- data/spec/core/duck_fiber_spec.rb +16 -46
- data/spec/core/fail_spec.rb +5 -6
- data/spec/core/goal_spec.rb +24 -14
- data/spec/core/log_var_ref_spec.rb +105 -0
- data/spec/core/log_var_spec.rb +64 -0
- data/spec/core/nullary_relation_spec.rb +33 -0
- data/spec/core/parametrized_tem_spec.rb +39 -0
- data/spec/core/relation_spec.rb +33 -0
- data/spec/core/scope_spec.rb +73 -0
- data/spec/core/solver_adapter_spec.rb +70 -0
- data/spec/core/specification_spec.rb +43 -0
- data/spec/core/succeed_spec.rb +5 -5
- data/spec/core/symbol_table_spec.rb +142 -0
- data/spec/glue/dsl_chap1_spec.rb +96 -144
- data/spec/glue/dsl_chap2_spec.rb +350 -0
- data/spec/glue/run_star_expression_spec.rb +82 -906
- data/spec/rela/conde_spec.rb +153 -0
- data/spec/rela/conj2_spec.rb +123 -0
- data/spec/rela/def_relation_spec.rb +119 -0
- data/spec/rela/disj2_spec.rb +117 -0
- data/spec/rela/fresh_spec.rb +147 -0
- data/spec/rela/unify_spec.rb +369 -0
- data/spec/support/factory_atomic.rb +29 -0
- data/spec/support/factory_composite.rb +21 -0
- data/spec/support/factory_methods.rb +11 -26
- metadata +100 -64
- data/lib/mini_kraken/core/association_walker.rb +0 -183
- data/lib/mini_kraken/core/atomic_term.rb +0 -67
- data/lib/mini_kraken/core/base_arg.rb +0 -10
- data/lib/mini_kraken/core/binary_relation.rb +0 -63
- data/lib/mini_kraken/core/composite_goal.rb +0 -46
- data/lib/mini_kraken/core/composite_term.rb +0 -41
- data/lib/mini_kraken/core/conde.rb +0 -143
- data/lib/mini_kraken/core/conj2.rb +0 -79
- data/lib/mini_kraken/core/cons_cell.rb +0 -82
- data/lib/mini_kraken/core/def_relation.rb +0 -50
- data/lib/mini_kraken/core/designation.rb +0 -55
- data/lib/mini_kraken/core/disj2.rb +0 -72
- data/lib/mini_kraken/core/environment.rb +0 -73
- data/lib/mini_kraken/core/equals.rb +0 -156
- data/lib/mini_kraken/core/formal_arg.rb +0 -22
- data/lib/mini_kraken/core/formal_ref.rb +0 -25
- data/lib/mini_kraken/core/freshness.rb +0 -45
- data/lib/mini_kraken/core/goal_arg.rb +0 -12
- data/lib/mini_kraken/core/goal_template.rb +0 -62
- data/lib/mini_kraken/core/k_boolean.rb +0 -35
- data/lib/mini_kraken/core/outcome.rb +0 -53
- data/lib/mini_kraken/core/variable.rb +0 -41
- data/lib/mini_kraken/core/variable_ref.rb +0 -78
- data/lib/mini_kraken/core/vocabulary.rb +0 -442
- data/lib/mini_kraken/glue/fresh_env.rb +0 -75
- data/spec/core/association_walker_spec.rb +0 -192
- data/spec/core/conde_spec.rb +0 -147
- data/spec/core/conj2_spec.rb +0 -114
- data/spec/core/cons_cell_spec.rb +0 -107
- data/spec/core/def_relation_spec.rb +0 -96
- data/spec/core/disj2_spec.rb +0 -99
- data/spec/core/environment_spec.rb +0 -142
- data/spec/core/equals_spec.rb +0 -304
- data/spec/core/goal_template_spec.rb +0 -74
- data/spec/core/outcome_spec.rb +0 -48
- data/spec/core/variable_ref_spec.rb +0 -27
- data/spec/core/variable_spec.rb +0 -35
- data/spec/core/vocabulary_spec.rb +0 -219
- data/spec/glue/fresh_env_spec.rb +0 -62
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../spec_helper' # Use the RSpec framework
|
4
|
+
|
5
|
+
# Load the class under test
|
6
|
+
require_relative '../../lib/mini_kraken/core/bookmark'
|
7
|
+
|
8
|
+
module MiniKraken
|
9
|
+
module Core
|
10
|
+
describe Bookmark do
|
11
|
+
let(:one_ser_num) { 42 }
|
12
|
+
let(:a_kind) { :scope }
|
13
|
+
subject { Bookmark.new(a_kind, one_ser_num) }
|
14
|
+
|
15
|
+
context 'Initialization:' do
|
16
|
+
it 'should be initialized with a Symbol and an Integer' do
|
17
|
+
expect { Bookmark.new(a_kind, one_ser_num) }.not_to raise_error
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should know its kind' do
|
21
|
+
expect(subject.kind).to eq(a_kind)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should know its serial number' do
|
25
|
+
expect(subject.ser_num).to eq(one_ser_num)
|
26
|
+
end
|
27
|
+
end # context
|
28
|
+
|
29
|
+
context 'Provided services:' do
|
30
|
+
it 'should compare to another instance' do
|
31
|
+
same = Bookmark.new(a_kind, one_ser_num)
|
32
|
+
expect(subject).to eq(same)
|
33
|
+
|
34
|
+
distinct = Bookmark.new(a_kind, 3)
|
35
|
+
expect(subject).not_to eq(distinct)
|
36
|
+
end
|
37
|
+
end # context
|
38
|
+
end # describe
|
39
|
+
end # module
|
40
|
+
end # module
|
@@ -0,0 +1,245 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../spec_helper' # Use the RSpec framework
|
4
|
+
require_relative '../../lib/mini_kraken/core/association'
|
5
|
+
require_relative '../../lib/mini_kraken/core/log_var'
|
6
|
+
require_relative '../../lib/mini_kraken/composite/all_composite'
|
7
|
+
|
8
|
+
require_relative '../support/factory_atomic'
|
9
|
+
require_relative '../support/factory_methods'
|
10
|
+
|
11
|
+
# Load the class under test
|
12
|
+
require_relative '../../lib/mini_kraken/core/context'
|
13
|
+
|
14
|
+
module MiniKraken
|
15
|
+
module Core
|
16
|
+
describe Context do
|
17
|
+
include MiniKraken::FactoryAtomic # Use mix-in module
|
18
|
+
subject { Context.new }
|
19
|
+
|
20
|
+
context 'Initialization:' do
|
21
|
+
it 'should be initialized without argument' do
|
22
|
+
expect { Context.new }.not_to raise_error
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should have an empty symbol table' do
|
26
|
+
expect(subject.symbol_table).to be_empty
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should have an empty blackboard' do
|
30
|
+
expect(subject.blackboard).to be_empty
|
31
|
+
end
|
32
|
+
end # context
|
33
|
+
|
34
|
+
context 'Provided services:' do
|
35
|
+
def var(aName)
|
36
|
+
LogVar.new(aName)
|
37
|
+
end
|
38
|
+
|
39
|
+
def cons(term1, term2 = nil)
|
40
|
+
Composite::ConsCell.new(term1, term2)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should accept the addition of an entry in symbol table' do
|
44
|
+
subject.insert(var('x'))
|
45
|
+
expect(subject.symbol_table).not_to be_empty
|
46
|
+
expect(subject.symbol_table.current_scope.defns['x']).to be_kind_of(LogVar)
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should create one or more variables from name(s)' do
|
50
|
+
# Case: single name
|
51
|
+
subject.add_vars('x')
|
52
|
+
expect(subject.symbol_table).not_to be_empty
|
53
|
+
expect(subject.symbol_table.current_scope.defns['x']).to be_kind_of(LogVar)
|
54
|
+
|
55
|
+
# Case: multiple names
|
56
|
+
subject.add_vars(%w[y z])
|
57
|
+
expect(subject.symbol_table.current_scope.defns['y']).to be_kind_of(LogVar)
|
58
|
+
expect(subject.symbol_table.current_scope.defns['z']).to be_kind_of(LogVar)
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'should accept the addition of an association to a given i_name' do
|
62
|
+
i_name_x = subject.insert(var('x'))
|
63
|
+
i_name_y = subject.insert(var('y'))
|
64
|
+
|
65
|
+
expect(subject.associations_for('x')).to be_empty
|
66
|
+
something = double('something')
|
67
|
+
assoc_x = subject.associate('x', something)
|
68
|
+
expect(subject.associations_for('x')).to eq([assoc_x])
|
69
|
+
|
70
|
+
thing = double('thing')
|
71
|
+
assoc_y = Association.new(i_name_y, thing)
|
72
|
+
subject.enqueue_association(assoc_y)
|
73
|
+
expect(subject.associations_for('y')).to eq([assoc_y])
|
74
|
+
|
75
|
+
blob = double('blob')
|
76
|
+
assoc2_x = Association.new(i_name_x, blob)
|
77
|
+
subject.enqueue_association(assoc2_x)
|
78
|
+
expect(subject.associations_for('x')).to eq([assoc_x, assoc2_x])
|
79
|
+
|
80
|
+
var_y = subject.lookup('y')
|
81
|
+
foo = double('bar')
|
82
|
+
assoc2_y = subject.associate(var_y, foo)
|
83
|
+
expect(subject.associations_for('y')).to eq([assoc_y, assoc2_y])
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'should allow the fusion of two variables' do
|
87
|
+
symb_tbl = subject.symbol_table
|
88
|
+
i_name_q = subject.insert(var('q'))
|
89
|
+
symb_tbl.enter_scope(Core::Scope.new)
|
90
|
+
i_name_x = subject.insert(var('x'))
|
91
|
+
|
92
|
+
expect(subject.associations_for('q')).to be_empty
|
93
|
+
something = double('something')
|
94
|
+
assoc_x = subject.associate('x', something)
|
95
|
+
expect(subject.associations_for('x')).to eq([assoc_x])
|
96
|
+
pre_queue_size = subject.blackboard.move_queue.size
|
97
|
+
fusion = subject.fuse(%w[q x])
|
98
|
+
|
99
|
+
expect(fusion).to be_kind_of(Fusion)
|
100
|
+
expect(fusion.elements).to eq(%w[q x].map { |e| subject.lookup(e).i_name })
|
101
|
+
expect(subject.blackboard.move_queue.size).to eq(pre_queue_size + 2)
|
102
|
+
expect(subject.cv2vars).to be_include(fusion.i_name)
|
103
|
+
expect(subject.cv2vars[fusion.i_name]).to eq(fusion.elements)
|
104
|
+
expect(subject.blackboard.vars2cv[i_name_q]).to eq(fusion.i_name)
|
105
|
+
expect(subject.blackboard.vars2cv[i_name_x]).to eq(fusion.i_name)
|
106
|
+
expect(subject.associations_for('q')).not_to be_empty
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'should allow the search of an entry based on its name' do
|
110
|
+
symb_tbl = subject.symbol_table
|
111
|
+
subject.add_vars(%w[q x])
|
112
|
+
symb_tbl.enter_scope(Core::Scope.new)
|
113
|
+
subject.add_vars(%w[q y])
|
114
|
+
|
115
|
+
# Search for unknown name
|
116
|
+
expect(subject.lookup('z')).to be_nil
|
117
|
+
|
118
|
+
# Search for existing unique names
|
119
|
+
expect(subject.lookup('y')).to eq(symb_tbl.current_scope.defns['y'])
|
120
|
+
expect(subject.lookup('x')).to eq(symb_tbl.root.defns['x'])
|
121
|
+
|
122
|
+
# Search for redefined name
|
123
|
+
expect(subject.lookup('q')).to eq(symb_tbl.current_scope.defns['q'])
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'should determine the ranks of fresh variables' do
|
127
|
+
subject.add_vars(%w[x y z])
|
128
|
+
|
129
|
+
ref_y = LogVarRef.new('y')
|
130
|
+
subject.associate('x', ref_y)
|
131
|
+
subject.send(:calc_ranking)
|
132
|
+
expect(subject.ranking.size).to eq(2)
|
133
|
+
i_name_y = subject.lookup('y').i_name
|
134
|
+
expect(subject.ranking[i_name_y]).to eq(0)
|
135
|
+
i_name_z = subject.lookup('z').i_name
|
136
|
+
expect(subject.ranking[i_name_z]).to eq(1)
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'should allow entering in a new scope' do
|
140
|
+
new_scope = Scope.new
|
141
|
+
expect { subject.enter_scope(new_scope) }.not_to raise_error
|
142
|
+
expect(subject.symbol_table.current_scope).to eq(new_scope)
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'should allow leaving out current scope' do
|
146
|
+
subject.add_vars(%w[q x])
|
147
|
+
x_val = k_symbol(:foo)
|
148
|
+
assoc_x = subject.associate('x', x_val) # x => :foo
|
149
|
+
expect(subject.blackboard.move_queue.size).to eq(1)
|
150
|
+
new_scope = Scope.new
|
151
|
+
subject.enter_scope(new_scope) # Adds one bookmark
|
152
|
+
expect(subject.blackboard.move_queue.size).to eq(2)
|
153
|
+
subject.add_vars(%w[w x y z])
|
154
|
+
|
155
|
+
q_val = LogVarRef.new('x')
|
156
|
+
assoc_q = subject.associate('q', q_val)
|
157
|
+
w_val = k_symbol(:bar)
|
158
|
+
subject.associate('w', w_val)
|
159
|
+
x2_val = LogVarRef.new('z')
|
160
|
+
assoc2_x = subject.associate('x', x2_val)
|
161
|
+
y_val = k_symbol(:foobar)
|
162
|
+
subject.associate('y', y_val)
|
163
|
+
# x => :foo
|
164
|
+
# ------
|
165
|
+
# q => x
|
166
|
+
# w => :bar
|
167
|
+
# x => z
|
168
|
+
# y => :foobar
|
169
|
+
expect(subject.blackboard.i_name2moves.keys.size).to eq(5)
|
170
|
+
expect(subject.blackboard.move_queue.size).to eq(6)
|
171
|
+
# require 'debug'
|
172
|
+
expect { subject.leave_scope }.not_to raise_error
|
173
|
+
# Expected state:
|
174
|
+
# x => :foo
|
175
|
+
# q => x'
|
176
|
+
# x' => z
|
177
|
+
expect(subject.blackboard.move_queue.size).to eq(3)
|
178
|
+
symb_table = subject.symbol_table
|
179
|
+
expect(symb_table.current_scope).to eq(symb_table.root)
|
180
|
+
expect(subject.blackboard.i_name2moves.keys.size).to eq(3)
|
181
|
+
expect(subject.blackboard.move_queue).to eq([assoc_x, assoc_q, assoc2_x])
|
182
|
+
end
|
183
|
+
|
184
|
+
it 'should substitute values of associations (if needed)' do
|
185
|
+
subject.add_vars(%w[q x y z])
|
186
|
+
|
187
|
+
x_ref = LogVarRef.new('x')
|
188
|
+
foobar = Composite::ConsCell.new(k_symbol(:foo), k_symbol(:bar))
|
189
|
+
q_val = Composite::ConsCell.new(x_ref, foobar)
|
190
|
+
assoc_q = subject.associate('q', q_val)
|
191
|
+
subject.send(:calc_ranking)
|
192
|
+
|
193
|
+
expect(subject.send(:substitute, assoc_q).to_s).to eq('(_0 :foo . :bar)')
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'should build a solution (atomic terms)' do
|
197
|
+
subject.add_vars(%w[x y z])
|
198
|
+
|
199
|
+
subject.succeeded!
|
200
|
+
sol = subject.build_solution
|
201
|
+
expect(sol.size).to eq(3)
|
202
|
+
expect(sol['x']).to eq(:_0)
|
203
|
+
expect(sol['y']).to eq(:_1)
|
204
|
+
expect(sol['z']).to eq(:_2)
|
205
|
+
|
206
|
+
foo = k_symbol(:foo)
|
207
|
+
subject.associate('x', foo)
|
208
|
+
sol = subject.build_solution
|
209
|
+
expect(sol.size).to eq(3)
|
210
|
+
expect(sol['x']).to eq(foo)
|
211
|
+
expect(sol['y']).to eq(:_0)
|
212
|
+
expect(sol['z']).to eq(:_1)
|
213
|
+
|
214
|
+
bar = k_symbol(:bar)
|
215
|
+
subject.associate('y', bar)
|
216
|
+
sol = subject.build_solution
|
217
|
+
expect(sol.size).to eq(3)
|
218
|
+
expect(sol['x']).to eq(foo)
|
219
|
+
expect(sol['y']).to eq(bar)
|
220
|
+
expect(sol['z']).to eq(:_0)
|
221
|
+
end
|
222
|
+
|
223
|
+
it 'should build a solution (composite terms)' do
|
224
|
+
subject.add_vars(['l'])
|
225
|
+
new_scope = Scope.new
|
226
|
+
subject.enter_scope(new_scope)
|
227
|
+
a = k_symbol(:a)
|
228
|
+
b = k_symbol(:b)
|
229
|
+
c = k_symbol(:c)
|
230
|
+
subject.add_vars(['d'])
|
231
|
+
d_ref = LogVarRef.new('d')
|
232
|
+
subject.associate('l', cons(cons(a, cons(b)), d_ref))
|
233
|
+
subject.associate('d', cons(c))
|
234
|
+
|
235
|
+
subject.succeeded!
|
236
|
+
sol = subject.build_solution
|
237
|
+
expect(sol.size).to eq(1)
|
238
|
+
|
239
|
+
# TODO: fix next line. Actual is: ((a :c))
|
240
|
+
expect(sol['l'].to_s).to eq('((:a :b) :c)')
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end # describe
|
244
|
+
end # module
|
245
|
+
end # module
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../spec_helper' # Use the RSpec framework
|
4
|
+
|
5
|
+
require_relative '../../lib/mini_kraken/core/all_core'
|
6
|
+
|
7
|
+
module MiniKraken
|
8
|
+
module Core
|
9
|
+
# Integration-in-the-small testing
|
10
|
+
describe 'Core Classes' do
|
11
|
+
let(:ctx) { Context.new }
|
12
|
+
|
13
|
+
context 'Executing nullary goals:' do
|
14
|
+
def var(aName)
|
15
|
+
LogVar.new(aName)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should execute nullary fail goal' do
|
19
|
+
# Equivalent to frame 1:7
|
20
|
+
goal = Goal.new(Fail.instance, [])
|
21
|
+
ctx.insert(var('q'))
|
22
|
+
result = goal.achieve(ctx)
|
23
|
+
expect(result.resume).to eq(ctx)
|
24
|
+
expect(ctx).to be_failure
|
25
|
+
expect(ctx.associations_for('q')).to be_empty
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should execute nullary succeed goal' do
|
29
|
+
# Equivalent to frame 1:17
|
30
|
+
goal = Goal.new(Succeed.instance, [])
|
31
|
+
ctx.insert(var('q'))
|
32
|
+
result = goal.achieve(ctx)
|
33
|
+
expect(result.resume).to eq(ctx)
|
34
|
+
expect(ctx).to be_success
|
35
|
+
expect(ctx.associations_for('q')).to be_empty # RS: (_0)
|
36
|
+
end
|
37
|
+
end # context
|
38
|
+
end # describe
|
39
|
+
end # module
|
40
|
+
end # module
|
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative '../spec_helper' # Use the RSpec framework
|
4
|
-
require_relative '../../lib/mini_kraken/core/environment'
|
5
4
|
|
6
5
|
# Load the class under test
|
7
6
|
require_relative '../../lib/mini_kraken/core/duck_fiber'
|
@@ -9,62 +8,33 @@ require_relative '../../lib/mini_kraken/core/duck_fiber'
|
|
9
8
|
module MiniKraken
|
10
9
|
module Core
|
11
10
|
describe DuckFiber do
|
12
|
-
|
11
|
+
let(:ctx) { Core::Context.new }
|
12
|
+
let(:callable) { -> { ctx.failed! } }
|
13
|
+
subject { DuckFiber.new(callable) }
|
13
14
|
|
14
15
|
context 'Initialization:' do
|
15
|
-
it '
|
16
|
-
expect { DuckFiber.new(
|
16
|
+
it 'could be initialized with a Proc' do
|
17
|
+
expect { DuckFiber.new(-> { ctx.failed }) }.not_to raise_error
|
18
|
+
end
|
17
19
|
|
18
|
-
|
20
|
+
it "could be initialized with an object that responds to 'call'" do
|
21
|
+
expect { DuckFiber.new(callable) }.not_to raise_error
|
19
22
|
end
|
20
23
|
|
21
|
-
it 'should know its
|
22
|
-
expect(subject.
|
24
|
+
it 'should know its callable object' do
|
25
|
+
expect(subject.callable).to eq(callable)
|
23
26
|
end
|
24
27
|
end # context
|
25
28
|
|
26
29
|
context 'Provided services:' do
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
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 be_successful
|
44
|
-
expect(outcome.parent).to be_nil
|
45
|
-
|
46
|
-
# Only one result should be yielded
|
47
|
-
expect(succeeding.resume).to be_nil
|
48
|
-
end
|
49
|
-
|
50
|
-
it 'should yield a distinct success object' do
|
51
|
-
instance1 = DuckFiber.new(:success)
|
52
|
-
outcome1 = instance1.resume
|
53
|
-
|
54
|
-
instance2 = DuckFiber.new(:success)
|
55
|
-
outcome2 = instance2.resume
|
56
|
-
|
57
|
-
expect(outcome1).not_to be_equal(outcome2)
|
58
|
-
end
|
59
|
-
|
60
|
-
it 'should behave like a Fiber yielding a custom outcome' do
|
61
|
-
tailored = DuckFiber.new(:custom) { Outcome.new(:"#s", parent) }
|
62
|
-
outcome = nil
|
63
|
-
expect { outcome = tailored.resume }.not_to raise_error
|
64
|
-
expect(outcome).to eq(Outcome.new(:"#s", parent))
|
30
|
+
it 'should behave like a Fiber yielding the given Context' do
|
31
|
+
result = nil
|
32
|
+
expect { result = subject.resume }.not_to raise_error
|
33
|
+
expect(result).to eq(ctx)
|
34
|
+
expect(ctx).to be_failure
|
65
35
|
|
66
36
|
# Only one result should be yielded
|
67
|
-
expect(
|
37
|
+
expect(subject.resume).to be_nil
|
68
38
|
end
|
69
39
|
end # context
|
70
40
|
end # describe
|
data/spec/core/fail_spec.rb
CHANGED
@@ -21,17 +21,16 @@ module MiniKraken
|
|
21
21
|
end # context
|
22
22
|
|
23
23
|
context 'Provided services:' do
|
24
|
-
|
25
|
-
args = double('fake-args')
|
26
|
-
env = double('fake-env')
|
24
|
+
let(:ctx) { Context.new }
|
27
25
|
|
26
|
+
it 'should unconditionally return a failure result' do
|
28
27
|
solver = nil
|
29
|
-
expect { solver = subject.solver_for(
|
28
|
+
expect { solver = subject.solver_for([], ctx) }.not_to raise_error
|
30
29
|
|
31
|
-
# Solver
|
30
|
+
# Solver quacks like a Fiber
|
32
31
|
dummy_arg = double('dummy-stuff')
|
33
32
|
result = solver.resume(dummy_arg)
|
34
|
-
expect(result).to
|
33
|
+
expect(result).to be_failure
|
35
34
|
|
36
35
|
# Only one "solution", next 'resume' call should return nil
|
37
36
|
result = solver.resume(dummy_arg)
|
data/spec/core/goal_spec.rb
CHANGED
@@ -1,22 +1,31 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative '../spec_helper' # Use the RSpec framework
|
4
|
-
require_relative '../../lib/mini_kraken/core/environment'
|
5
|
-
require_relative '../../lib/mini_kraken/core/equals'
|
6
4
|
require_relative '../../lib/mini_kraken/core/fail'
|
7
|
-
require_relative '../../lib/mini_kraken/
|
5
|
+
require_relative '../../lib/mini_kraken/atomic/k_symbol'
|
6
|
+
|
8
7
|
|
9
8
|
# Load the class under test
|
10
9
|
require_relative '../../lib/mini_kraken/core/goal'
|
11
10
|
|
12
11
|
module MiniKraken
|
13
12
|
module Core
|
13
|
+
class DummyRelation < Relation
|
14
|
+
def initialize
|
15
|
+
super('dummy', 2)
|
16
|
+
end
|
17
|
+
|
18
|
+
def solver_for(_actuals, ctx)
|
19
|
+
DuckFiber.new(-> { ctx.succeeded! })
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
14
23
|
describe Goal do
|
15
24
|
let(:nullary_relation) { Fail.instance }
|
16
|
-
|
17
|
-
let(:
|
18
|
-
let(:
|
19
|
-
subject { Goal.new(binary_relation,
|
25
|
+
let(:binary_relation) { DummyRelation.new }
|
26
|
+
let(:ctx) { Context.new }
|
27
|
+
let(:actuals) { [Atomic::KSymbol.new(:pea), Atomic::KSymbol.new(:pod)] }
|
28
|
+
subject { Goal.new(binary_relation, actuals) }
|
20
29
|
|
21
30
|
context 'Initialization:' do
|
22
31
|
it 'should accept one nullary relation and empty argument array' do
|
@@ -24,7 +33,7 @@ module MiniKraken
|
|
24
33
|
end
|
25
34
|
|
26
35
|
it 'should accept one binary relation and 2-elements array' do
|
27
|
-
expect { Goal.new(binary_relation, [
|
36
|
+
expect { Goal.new(binary_relation, [Term.new, Term.new]) }.not_to raise_error
|
28
37
|
end
|
29
38
|
|
30
39
|
it 'should know its relation' do
|
@@ -32,25 +41,26 @@ module MiniKraken
|
|
32
41
|
end
|
33
42
|
|
34
43
|
it 'should know its actual arguments' do
|
35
|
-
expectations = [KSymbol.new(:pea), KSymbol.new(:pod)]
|
44
|
+
expectations = [Atomic::KSymbol.new(:pea), Atomic::KSymbol.new(:pod)]
|
36
45
|
expect(subject.actuals).to eq(expectations)
|
37
46
|
end
|
38
47
|
end # context
|
39
48
|
|
40
49
|
context 'Provided services:' do
|
41
50
|
it 'should fail if relation does not succeed' do
|
42
|
-
|
43
|
-
|
51
|
+
instance = Goal.new(nullary_relation, [])
|
52
|
+
solver = instance.achieve(ctx)
|
53
|
+
expect(solver.resume).not_to be_success
|
44
54
|
|
45
55
|
# No more solution...
|
46
56
|
expect(solver.resume).to be_nil
|
47
57
|
end
|
48
58
|
|
49
59
|
it 'should succeed if relation succeeds' do
|
50
|
-
instance = Goal.new(binary_relation,
|
60
|
+
instance = Goal.new(binary_relation, actuals)
|
51
61
|
|
52
|
-
solver = instance.
|
53
|
-
expect(solver.resume).to
|
62
|
+
solver = instance.achieve(ctx)
|
63
|
+
expect(solver.resume).to be_success
|
54
64
|
|
55
65
|
# No more solution...
|
56
66
|
expect(solver.resume).to be_nil
|