mini_kraken 0.2.03 → 0.3.03
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 +48 -0
- data/README.md +29 -21
- 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 +301 -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 +68 -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 +44 -88
- 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 +265 -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/{core → composite}/cons_cell_visitor_spec.rb +36 -20
- 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 +22 -12
- 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 +88 -144
- data/spec/glue/dsl_chap2_spec.rb +454 -19
- data/spec/glue/run_star_expression_spec.rb +81 -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 +98 -70
- 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/cons_cell_visitor.rb +0 -102
- data/lib/mini_kraken/core/def_relation.rb +0 -53
- 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 -193
- 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 -102
- data/lib/mini_kraken/core/k_boolean.rb +0 -35
- data/lib/mini_kraken/core/outcome.rb +0 -63
- data/lib/mini_kraken/core/variable.rb +0 -41
- data/lib/mini_kraken/core/variable_ref.rb +0 -84
- data/lib/mini_kraken/core/vocabulary.rb +0 -446
- data/lib/mini_kraken/glue/fresh_env.rb +0 -103
- data/lib/mini_kraken/glue/fresh_env_factory.rb +0 -83
- 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 -97
- data/spec/core/disj2_spec.rb +0 -99
- data/spec/core/environment_spec.rb +0 -142
- data/spec/core/equals_spec.rb +0 -317
- data/spec/core/goal_template_spec.rb +0 -74
- data/spec/core/outcome_spec.rb +0 -56
- data/spec/core/variable_ref_spec.rb +0 -30
- data/spec/core/variable_spec.rb +0 -35
- data/spec/core/vocabulary_spec.rb +0 -219
- data/spec/glue/fresh_env_factory_spec.rb +0 -97
- data/spec/glue/fresh_env_spec.rb +0 -62
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../spec_helper' # Use the RSpec framework
|
4
|
+
require_relative '../support/factory_atomic'
|
5
|
+
|
6
|
+
# Load the class under test
|
7
|
+
require_relative '../../lib/mini_kraken/composite/list'
|
8
|
+
|
9
|
+
module MiniKraken
|
10
|
+
module Composite
|
11
|
+
describe List do
|
12
|
+
include MiniKraken::FactoryAtomic # Use mix-in module
|
13
|
+
|
14
|
+
let(:pea) { k_symbol(:pea) }
|
15
|
+
let(:pod) { k_symbol(:pod) }
|
16
|
+
let(:corn) { k_symbol(:corn) }
|
17
|
+
|
18
|
+
context 'Module as a factory:' do
|
19
|
+
subject { List }
|
20
|
+
|
21
|
+
it 'builds a pair wiht one argument (= one element proper list)' do
|
22
|
+
pair = subject.cons(pea)
|
23
|
+
expect(pair.car).to eq(pea)
|
24
|
+
expect(pair.cdr).to be_nil
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'builds a pair with two explicit arguments' do
|
28
|
+
pair = subject.cons(pea, pod)
|
29
|
+
expect(pair.car).to eq(pea)
|
30
|
+
expect(pair.cdr).to eq(pod)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'builds a null list from an empty array' do
|
34
|
+
l = subject.make_list([])
|
35
|
+
expect(l).to be_kind_of(ConsCell)
|
36
|
+
expect(l).to be_null
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'builds a proper list from an non-empty array' do
|
40
|
+
l = subject.make_list([pea, pod, corn])
|
41
|
+
|
42
|
+
expect(l.car).to eq(pea)
|
43
|
+
expect(l.cdr.car).to eq(pod)
|
44
|
+
expect(l.cdr.cdr.car).to eq(corn)
|
45
|
+
expect(l.cdr.cdr.cdr).to be_nil
|
46
|
+
end
|
47
|
+
end # context
|
48
|
+
end # describz
|
49
|
+
end # module
|
50
|
+
end # module
|
@@ -0,0 +1,52 @@
|
|
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/any_value'
|
7
|
+
|
8
|
+
|
9
|
+
module MiniKraken
|
10
|
+
module Core
|
11
|
+
describe AnyValue do
|
12
|
+
let(:some_rank) { 2 }
|
13
|
+
subject { AnyValue.new(some_rank) }
|
14
|
+
|
15
|
+
context 'Initialization:' do
|
16
|
+
it "should be initialized with a variable's rank" do
|
17
|
+
expect { AnyValue.new(0) }.not_to raise_error
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should know its rank' do
|
21
|
+
expect(subject.rank).to eq(some_rank)
|
22
|
+
end
|
23
|
+
end # context
|
24
|
+
|
25
|
+
context 'Provided services:' do
|
26
|
+
it 'should compare itself to another instance' do
|
27
|
+
expect(subject == AnyValue.new(some_rank)).to be_truthy
|
28
|
+
expect(subject == AnyValue.new(1)).to be_falsey
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should compare itself to an integer' do
|
32
|
+
expect(subject == some_rank).to be_truthy
|
33
|
+
expect(subject == 1).to be_falsey
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should compare itself to a symbol' do
|
37
|
+
expect(subject == :_2).to be_truthy
|
38
|
+
expect(subject == :_1).to be_falsey
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should know its text representation' do
|
42
|
+
expect(subject.to_s).to eq('_2')
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should know that it represents a non-pinned variable' do
|
46
|
+
ctx = double('dummy-context')
|
47
|
+
expect(subject).not_to be_pinned(ctx)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end # describe
|
51
|
+
end # module
|
52
|
+
end # module
|
@@ -0,0 +1,92 @@
|
|
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/arity'
|
7
|
+
|
8
|
+
module MiniKraken
|
9
|
+
module Core
|
10
|
+
describe Arity do
|
11
|
+
subject { Arity.new(0, 1) }
|
12
|
+
|
13
|
+
context 'Initialization:' do
|
14
|
+
it 'should be initialized with two integers' do
|
15
|
+
expect { Arity.new(0, 1) }.not_to raise_error
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should know its lower bound' do
|
19
|
+
expect(subject.low).to eq(0)
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should know its upper bound' do
|
23
|
+
expect(subject.high).to eq(1)
|
24
|
+
end
|
25
|
+
end # context
|
26
|
+
|
27
|
+
context 'Initialization:' do
|
28
|
+
it 'should know whether is is nullary' do
|
29
|
+
expect(subject).not_to be_nullary
|
30
|
+
|
31
|
+
instance = Arity.new(0, '*')
|
32
|
+
expect(instance).not_to be_nullary
|
33
|
+
|
34
|
+
instance = Arity.new(0, 0)
|
35
|
+
expect(instance).to be_nullary
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should know whether is is unary' do
|
39
|
+
expect(subject).not_to be_unary
|
40
|
+
|
41
|
+
instance = Arity.new(1, 2)
|
42
|
+
expect(instance).not_to be_unary
|
43
|
+
|
44
|
+
instance = Arity.new(1, 1)
|
45
|
+
expect(instance).to be_unary
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should know whether is is binary' do
|
49
|
+
expect(subject).not_to be_binary
|
50
|
+
|
51
|
+
instance = Arity.new(1, 2)
|
52
|
+
expect(instance).not_to be_binary
|
53
|
+
|
54
|
+
instance = Arity.new(2, 2)
|
55
|
+
expect(instance).to be_binary
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'should know whether is is variadic' do
|
59
|
+
expect(subject).not_to be_variadic
|
60
|
+
|
61
|
+
instance = Arity.new(1, '*')
|
62
|
+
expect(instance).to be_variadic
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'should know whether an integer fits the arity range' do
|
66
|
+
expect(subject.match?(0)).to be_truthy
|
67
|
+
expect(subject.match?(1)).to be_truthy
|
68
|
+
expect(subject.match?(2)).to be_falsey
|
69
|
+
|
70
|
+
instance = Arity.new(2, '*')
|
71
|
+
expect(instance.match?(1)).to be_falsey
|
72
|
+
expect(instance.match?(2)).to be_truthy
|
73
|
+
expect(instance.match?(42)).to be_truthy
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'should know whether is equal to another arity' do
|
77
|
+
itself = subject # Renaming as workaround to Rubocop complaint
|
78
|
+
expect(subject == itself).to be_truthy
|
79
|
+
|
80
|
+
same = Arity.new(0, 1)
|
81
|
+
expect(subject == same).to be_truthy
|
82
|
+
|
83
|
+
same_low = Arity.new(0, 2)
|
84
|
+
expect(subject == same_low).to be_falsey
|
85
|
+
|
86
|
+
same_high = Arity.new(1, 1)
|
87
|
+
expect(subject == same_high).to be_falsey
|
88
|
+
end
|
89
|
+
end # context
|
90
|
+
end # describe
|
91
|
+
end # module
|
92
|
+
end # module
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../spec_helper' # Use the RSpec framework
|
4
|
+
require_relative '../support/factory_atomic'
|
5
|
+
require_relative '../../lib/mini_kraken/core/context'
|
6
|
+
require_relative '../../lib/mini_kraken/core/log_var'
|
7
|
+
require_relative '../../lib/mini_kraken/core/log_var_ref'
|
8
|
+
|
9
|
+
# Load the class under test
|
10
|
+
require_relative '../../lib/mini_kraken/core/association_copy'
|
11
|
+
|
12
|
+
module MiniKraken
|
13
|
+
module Core
|
14
|
+
describe AssociationCopy do
|
15
|
+
include MiniKraken::FactoryAtomic # Use mix-in module
|
16
|
+
|
17
|
+
let(:pea) { k_symbol(:pea) }
|
18
|
+
let(:q_assoc) { Association.new('q', pea) }
|
19
|
+
subject { AssociationCopy.new('q_x', q_assoc) }
|
20
|
+
|
21
|
+
context 'Initialization:' do
|
22
|
+
it 'should be initialized with a name and an association' do
|
23
|
+
expect { AssociationCopy.new('q_x', q_assoc) }.not_to raise_error
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should be initialized with a variable and an association' do
|
27
|
+
q_x_var = LogVar.new('q_x')
|
28
|
+
expect { AssociationCopy.new(q_x_var, q_assoc) }.not_to raise_error
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should know the internal variable name' do
|
32
|
+
expect(subject.i_name).to eq('q_x')
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should know the associated value' do
|
36
|
+
expect(subject.value).to eq(pea)
|
37
|
+
end
|
38
|
+
end # context
|
39
|
+
|
40
|
+
context 'Provided services:' do
|
41
|
+
let(:ctx) { Context.new }
|
42
|
+
|
43
|
+
it 'should tell whether the associated value is pinned' do
|
44
|
+
ctx.add_vars(%w[q x q_x])
|
45
|
+
expect(subject).to be_pinned(ctx)
|
46
|
+
|
47
|
+
a = Association.new(ctx.lookup('q'), LogVarRef.new('x'))
|
48
|
+
instance = AssociationCopy.new(ctx.lookup('q_x'), a)
|
49
|
+
expect(instance).not_to be_pinned(ctx)
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should tell whether the associated value is floating' do
|
53
|
+
ctx.add_vars(%w[q x q_x])
|
54
|
+
|
55
|
+
expect(subject).not_to be_floating(ctx)
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'should retrieve the dependencies in its value' do
|
59
|
+
expect(subject.dependencies(ctx)).to be_empty
|
60
|
+
|
61
|
+
ctx.add_vars(%w[q x q_x])
|
62
|
+
a = Association.new(ctx.lookup('q'), LogVarRef.new('x'))
|
63
|
+
instance = AssociationCopy.new(ctx.lookup('q_x'), a)
|
64
|
+
expect(instance.dependencies(ctx).size).to eq(1)
|
65
|
+
end
|
66
|
+
end # context
|
67
|
+
end # describe
|
68
|
+
end # module
|
69
|
+
end # module
|
@@ -1,8 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative '../spec_helper' # Use the RSpec framework
|
4
|
-
require_relative '
|
5
|
-
require_relative '../../lib/mini_kraken/core/
|
4
|
+
require_relative '../support/factory_atomic'
|
5
|
+
require_relative '../../lib/mini_kraken/core/context'
|
6
|
+
require_relative '../../lib/mini_kraken/core/log_var'
|
7
|
+
require_relative '../../lib/mini_kraken/core/log_var_ref'
|
6
8
|
|
7
9
|
# Load the class under test
|
8
10
|
require_relative '../../lib/mini_kraken/core/association'
|
@@ -10,7 +12,9 @@ require_relative '../../lib/mini_kraken/core/association'
|
|
10
12
|
module MiniKraken
|
11
13
|
module Core
|
12
14
|
describe Association do
|
13
|
-
|
15
|
+
include MiniKraken::FactoryAtomic # Use mix-in module
|
16
|
+
|
17
|
+
let(:pea) { k_symbol(:pea) }
|
14
18
|
subject { Association.new('q', pea) }
|
15
19
|
|
16
20
|
context 'Initialization:' do
|
@@ -19,7 +23,7 @@ module MiniKraken
|
|
19
23
|
end
|
20
24
|
|
21
25
|
it 'should be initialized with a variable and a value' do
|
22
|
-
expect { Association.new(
|
26
|
+
expect { Association.new(LogVar.new('p'), pea) }.not_to raise_error
|
23
27
|
end
|
24
28
|
|
25
29
|
it 'should know the variable name' do
|
@@ -32,6 +36,29 @@ module MiniKraken
|
|
32
36
|
end # context
|
33
37
|
|
34
38
|
context 'Provided services:' do
|
39
|
+
let(:ctx) { Context.new }
|
40
|
+
|
41
|
+
it 'should tell whether the associated value is pinned' do
|
42
|
+
ctx.add_vars(%w[q x])
|
43
|
+
|
44
|
+
expect(subject).to be_pinned(ctx)
|
45
|
+
instance = Association.new(ctx.lookup('q'), LogVarRef.new('x'))
|
46
|
+
expect(instance).not_to be_pinned(ctx)
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should tell whether the associated value is floating' do
|
50
|
+
ctx.add_vars(%w[q x])
|
51
|
+
|
52
|
+
expect(subject).not_to be_floating(ctx)
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should retrieve the dependencies in its value' do
|
56
|
+
expect(subject.dependencies(ctx)).to be_empty
|
57
|
+
|
58
|
+
ctx.add_vars(%w[q x])
|
59
|
+
instance = Association.new(ctx.lookup('q'), LogVarRef.new('x'))
|
60
|
+
expect(instance.dependencies(ctx).size).to eq(1)
|
61
|
+
end
|
35
62
|
end # context
|
36
63
|
end # describe
|
37
64
|
end # module
|
@@ -0,0 +1,287 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../spec_helper' # Use the RSpec framework
|
4
|
+
require_relative '../support/factory_atomic'
|
5
|
+
require_relative '../../lib/mini_kraken/core/log_var_ref'
|
6
|
+
require_relative '../../lib/mini_kraken/core/scope'
|
7
|
+
require_relative '../../lib/mini_kraken/composite/cons_cell'
|
8
|
+
|
9
|
+
# Load the class under test
|
10
|
+
require_relative '../../lib/mini_kraken/core/blackboard'
|
11
|
+
|
12
|
+
module MiniKraken
|
13
|
+
module Core
|
14
|
+
describe Blackboard do
|
15
|
+
include MiniKraken::FactoryAtomic # Use mix-in module
|
16
|
+
subject { Blackboard.new }
|
17
|
+
|
18
|
+
context 'Initialization:' do
|
19
|
+
it 'should be initialized without argument' do
|
20
|
+
expect { Blackboard.new }.not_to raise_error
|
21
|
+
end
|
22
|
+
|
23
|
+
it "shouldn't have internal name entry at initialization" do
|
24
|
+
expect(subject.i_name2moves).to be_empty
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should have an empty association queue at initialization' do
|
28
|
+
expect(subject.move_queue).to be_empty
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should be empty at initialization' do
|
32
|
+
expect(subject).to be_empty
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should be ready to assign a serial number' do
|
36
|
+
expect(subject.next_serial_num).to be_zero
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should have its resultant attribute un-initialized' do
|
40
|
+
expect(subject.resultant).to be_nil
|
41
|
+
end
|
42
|
+
end # context
|
43
|
+
|
44
|
+
context 'Provided services:' do
|
45
|
+
let(:a_ser_num) { 42 }
|
46
|
+
let(:pea) { k_symbol(:pea) }
|
47
|
+
let(:pod) { k_symbol(:pod) }
|
48
|
+
let(:x_assoc) { Core::Association.new('x', pea) }
|
49
|
+
let(:y_assoc) { Core::Association.new('y', pod) }
|
50
|
+
let(:z_assoc) { Core::Association.new('z', pea) }
|
51
|
+
|
52
|
+
def var_ref(aName)
|
53
|
+
LogVarRef.new(aName)
|
54
|
+
end
|
55
|
+
|
56
|
+
def cons(car, cdr = nil)
|
57
|
+
Composite::ConsCell.new(car, cdr)
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'should allow the enqueuing of one association' do
|
61
|
+
expect { subject.enqueue_association(x_assoc) }.not_to raise_error
|
62
|
+
expect(subject.i_name2moves).not_to be_empty
|
63
|
+
expect(subject.move_queue).not_to be_empty
|
64
|
+
expect(subject.i_name2moves['x']).to be_kind_of(Array)
|
65
|
+
expect(subject.i_name2moves['x'].first).to eq(0)
|
66
|
+
expect(subject.last_move).to eq(x_assoc)
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'should allow the enqueuing of multiple associations' do
|
70
|
+
expect(subject.enqueue_association(x_assoc)).to eq(x_assoc)
|
71
|
+
expect { subject.enqueue_association(y_assoc) }.not_to raise_error
|
72
|
+
expect(subject.i_name2moves.size).to eq(2)
|
73
|
+
expect(subject.move_queue.size).to eq(2)
|
74
|
+
expect(subject.i_name2moves['y']).to be_kind_of(Array)
|
75
|
+
expect(subject.i_name2moves['y'].first).to eq(1)
|
76
|
+
expect(subject.last_move).to eq(y_assoc)
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'should allow the enqueuing of multiple associations for same i_name' do
|
80
|
+
subject.enqueue_association(x_assoc)
|
81
|
+
|
82
|
+
x_assoc_b = Core::Association.new('x', double('something'))
|
83
|
+
expect { subject.enqueue_association(x_assoc_b) }.not_to raise_error
|
84
|
+
expect(subject.i_name2moves.size).to eq(1)
|
85
|
+
expect(subject.move_queue.size).to eq(2)
|
86
|
+
expect(subject.i_name2moves['x']).to be_kind_of(Array)
|
87
|
+
expect(subject.i_name2moves['x'].size).to eq(2)
|
88
|
+
expect(subject.i_name2moves['x'].last).to eq(1)
|
89
|
+
expect(subject.move_queue.pop).to eq(x_assoc_b)
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'should allow the removal of the association at TOS position' do
|
93
|
+
subject.enqueue_association(x_assoc)
|
94
|
+
x_assoc_b = Core::Association.new('x', double('something'))
|
95
|
+
subject.enqueue_association(x_assoc_b)
|
96
|
+
expect(subject.move_queue.size).to eq(2)
|
97
|
+
expect(subject.i_name2moves.size).to eq(1)
|
98
|
+
|
99
|
+
expect { subject.send(:dequeue_item) }.not_to raise_error
|
100
|
+
expect(subject.move_queue.size).to eq(1)
|
101
|
+
expect(subject.i_name2moves.size).to eq(1)
|
102
|
+
|
103
|
+
subject.send(:dequeue_item)
|
104
|
+
expect(subject.move_queue).to be_empty
|
105
|
+
expect(subject.i_name2moves).to be_empty
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'should allow the enqueuing of a backtrack bookmark' do
|
109
|
+
subject.enqueue_association(x_assoc)
|
110
|
+
|
111
|
+
expect { subject.place_bt_point }.not_to raise_error
|
112
|
+
expect(subject.i_name2moves.size).to eq(1)
|
113
|
+
expect(subject.move_queue.size).to eq(2)
|
114
|
+
expect(subject.i_name2moves['x']).to be_kind_of(Array)
|
115
|
+
expect(subject.i_name2moves['x'].size).to eq(1)
|
116
|
+
expect(subject.last_move).to be_kind_of(Bookmark)
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'should allow the enqueuing of a scope bookmark' do
|
120
|
+
subject.enqueue_association(x_assoc)
|
121
|
+
|
122
|
+
expect { subject.enter_scope }.not_to raise_error
|
123
|
+
expect(subject.i_name2moves.size).to eq(1)
|
124
|
+
expect(subject.move_queue.size).to eq(2)
|
125
|
+
expect(subject.i_name2moves['x']).to be_kind_of(Array)
|
126
|
+
expect(subject.i_name2moves['x'].size).to eq(1)
|
127
|
+
expect(subject.last_move).to be_kind_of(Bookmark)
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'should allow the fusion of two unbound variables' do
|
131
|
+
q_var = LogVar.new('q')
|
132
|
+
x_var = LogVar.new('x')
|
133
|
+
q_x_var = LogVar.new('q_x')
|
134
|
+
fusion = Fusion.new(q_x_var.i_name, [q_var.i_name, x_var.i_name])
|
135
|
+
pre_size = subject.move_queue.size
|
136
|
+
subject.enqueue_fusion(fusion)
|
137
|
+
|
138
|
+
expect(subject.move_queue.size).to eq(pre_size + 1)
|
139
|
+
expect(subject.i_name2moves).to be_include(q_x_var.i_name)
|
140
|
+
expect(subject.vars2cv[q_var.i_name]).to eq(q_x_var.i_name)
|
141
|
+
expect(subject.vars2cv[x_var.i_name]).to eq(q_x_var.i_name)
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'should allow the fusion of one unbound and one floating variable' do
|
145
|
+
q_var = LogVar.new('q')
|
146
|
+
x_var = LogVar.new('x')
|
147
|
+
assoc_x = Association.new('x', cons(LogVarRef.new('y'), pea))
|
148
|
+
subject.enqueue_association(assoc_x)
|
149
|
+
q_x_var = LogVar.new('q_x')
|
150
|
+
fusion = Fusion.new(q_x_var.i_name, [q_var.i_name, x_var.i_name])
|
151
|
+
pre_size = subject.move_queue.size
|
152
|
+
|
153
|
+
subject.enqueue_fusion(fusion)
|
154
|
+
expect(subject.move_queue.size).to eq(pre_size + 2)
|
155
|
+
expect(subject.i_name2moves).to be_include(q_x_var.i_name)
|
156
|
+
indices = subject.i_name2moves[q_x_var.i_name]
|
157
|
+
expect(indices.size).to eq(2) # 2 = 1 Fusion + 1 AssocCopy
|
158
|
+
new_assoc = subject.move_queue[indices.last]
|
159
|
+
expect(new_assoc.value).to eq(assoc_x.value)
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'should allow the fusion of two floating variables' do
|
163
|
+
q_var = LogVar.new('q')
|
164
|
+
x_var = LogVar.new('x')
|
165
|
+
assoc_q = Association.new('x', cons(pod, var_ref('z')))
|
166
|
+
subject.enqueue_association(assoc_q)
|
167
|
+
assoc_x = Association.new('x', cons(var_ref('y'), pea))
|
168
|
+
subject.enqueue_association(assoc_x)
|
169
|
+
q_x_var = LogVar.new('q_x')
|
170
|
+
fusion = Fusion.new(q_x_var.i_name, [q_var.i_name, x_var.i_name])
|
171
|
+
pre_size = subject.move_queue.size
|
172
|
+
|
173
|
+
subject.enqueue_fusion(fusion)
|
174
|
+
expect(subject.move_queue.size).to eq(pre_size + 3)
|
175
|
+
expect(subject.i_name2moves).to be_include(q_x_var.i_name)
|
176
|
+
indices = subject.i_name2moves[q_x_var.i_name]
|
177
|
+
expect(indices.size).to eq(3)
|
178
|
+
new_move1 = subject.move_queue[indices[0]]
|
179
|
+
expect(new_move1).to be_kind_of(Core::Fusion)
|
180
|
+
new_move2 = subject.move_queue[indices[1]]
|
181
|
+
expect(new_move2.value).to eq(assoc_q.value)
|
182
|
+
new_move3 = subject.move_queue[indices[2]]
|
183
|
+
expect(new_move3.value).to eq(assoc_x.value)
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'should allow the removal of a fusion object at TOS position' do
|
187
|
+
q_var = LogVar.new('q')
|
188
|
+
x_var = LogVar.new('x')
|
189
|
+
q_x_var = LogVar.new('q_x')
|
190
|
+
fusion = Fusion.new(q_x_var.i_name, [q_var.i_name, x_var.i_name])
|
191
|
+
pre_size = subject.move_queue.size
|
192
|
+
subject.enqueue_fusion(fusion)
|
193
|
+
|
194
|
+
expect(subject.move_queue.size).to eq(pre_size + 1)
|
195
|
+
expect(subject.i_name2moves).to be_include(q_x_var.i_name)
|
196
|
+
expect(subject.vars2cv[q_var.i_name]).to eq(q_x_var.i_name)
|
197
|
+
expect(subject.vars2cv[x_var.i_name]).to eq(q_x_var.i_name)
|
198
|
+
|
199
|
+
expect { subject.send(:dequeue_item) }.not_to raise_error
|
200
|
+
expect(subject.move_queue.size).to eq(pre_size)
|
201
|
+
expect(subject.i_name2moves).not_to be_include(q_x_var.i_name)
|
202
|
+
expect(subject.vars2cv[q_var.i_name]).to be_nil
|
203
|
+
expect(subject.vars2cv[x_var.i_name]).to be_nil
|
204
|
+
end
|
205
|
+
|
206
|
+
it 'should retrieve association for a given i_name (0 fusion)' do
|
207
|
+
subject.enqueue_association(x_assoc)
|
208
|
+
subject.enqueue_association(y_assoc)
|
209
|
+
|
210
|
+
x_assoc_b = Core::Association.new('x', double('something'))
|
211
|
+
subject.enqueue_association(x_assoc_b)
|
212
|
+
expect(subject.associations_for('z')).to be_empty
|
213
|
+
expect(subject.associations_for('y').size).to eq(1)
|
214
|
+
expect(subject.associations_for('x').size).to eq(2)
|
215
|
+
expect(subject.associations_for('x').last).to eq(x_assoc_b)
|
216
|
+
end
|
217
|
+
|
218
|
+
it 'should retrieve association for a given i_name (1 fusion)' do
|
219
|
+
subject.enqueue_association(x_assoc)
|
220
|
+
expect(subject.associations_for('x').size).to eq(1)
|
221
|
+
expect(subject.associations_for('z').size).to eq(0)
|
222
|
+
expect(subject.associations_for('z', true).size).to eq(0)
|
223
|
+
|
224
|
+
x_z_var = LogVar.new('x_z')
|
225
|
+
fusion = Fusion.new(x_z_var.i_name, %w[x z])
|
226
|
+
subject.enqueue_fusion(fusion)
|
227
|
+
expect(subject.associations_for('z', true).size).to eq(1)
|
228
|
+
x_z_assoc = Core::Association.new(x_z_var.i_name, var_ref('y'))
|
229
|
+
subject.enqueue_association(x_z_assoc)
|
230
|
+
expect(subject.associations_for('z', false).size).to eq(0)
|
231
|
+
expect(subject.associations_for('z', true).size).to eq(2)
|
232
|
+
expect(subject.associations_for('x', false).size).to eq(1)
|
233
|
+
expect(subject.associations_for('x', true).size).to eq(2)
|
234
|
+
end
|
235
|
+
|
236
|
+
it 'should accept the succeeded notification' do
|
237
|
+
subject.enqueue_association(x_assoc)
|
238
|
+
subject.enqueue_association(y_assoc)
|
239
|
+
subject.succeeded!
|
240
|
+
expect(subject).to be_success
|
241
|
+
expect(subject.move_queue.size).to eq(2)
|
242
|
+
end
|
243
|
+
|
244
|
+
it 'should accept the failed notification in absence of bookmarks' do
|
245
|
+
subject.enqueue_association(x_assoc)
|
246
|
+
subject.enqueue_association(y_assoc)
|
247
|
+
subject.failed!
|
248
|
+
expect(subject).to be_failure
|
249
|
+
expect(subject.move_queue).to be_empty
|
250
|
+
expect(subject.i_name2moves).to be_empty
|
251
|
+
end
|
252
|
+
|
253
|
+
it 'should accept the failed notification with backtrack' do
|
254
|
+
x_assoc2 = Core::Association.new('x', pea)
|
255
|
+
|
256
|
+
subject.enqueue_association(x_assoc)
|
257
|
+
subject.enqueue_association(y_assoc)
|
258
|
+
subject.place_bt_point
|
259
|
+
subject.enqueue_association(z_assoc)
|
260
|
+
subject.enqueue_association(x_assoc2)
|
261
|
+
expect(subject.i_name2moves['x'].size).to eq(2)
|
262
|
+
|
263
|
+
subject.failed!
|
264
|
+
expect(subject.resultant).to eq(:"#u")
|
265
|
+
expect(subject.last_move).to be_kind_of(Core::Bookmark)
|
266
|
+
expect(subject.i_name2moves.include?('z')).to be_falsey
|
267
|
+
expect(subject.i_name2moves['x'].size).to eq(1)
|
268
|
+
end
|
269
|
+
|
270
|
+
it 'should accept the failed notification on a bookmark' do
|
271
|
+
subject.enqueue_association(x_assoc)
|
272
|
+
subject.enqueue_association(y_assoc)
|
273
|
+
subject.place_bt_point # Backtrack point bookmark added...
|
274
|
+
|
275
|
+
subject.enqueue_association(z_assoc)
|
276
|
+
subject.enter_scope # Scope bookmark
|
277
|
+
|
278
|
+
expect(subject.move_queue.size).to eq(5)
|
279
|
+
|
280
|
+
subject.failed!
|
281
|
+
expect(subject.resultant).to eq(:"#u")
|
282
|
+
expect(subject.move_queue.size).to eq(3) # 3 = 2 assocs + 1 bookmark
|
283
|
+
end
|
284
|
+
end # context
|
285
|
+
end # describe
|
286
|
+
end # module
|
287
|
+
end # module
|