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.
Files changed (136) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +378 -333
  3. data/CHANGELOG.md +48 -0
  4. data/README.md +29 -21
  5. data/lib/mini_kraken/atomic/all_atomic.rb +5 -0
  6. data/lib/mini_kraken/atomic/atomic_term.rb +96 -0
  7. data/lib/mini_kraken/atomic/k_boolean.rb +42 -0
  8. data/lib/mini_kraken/{core → atomic}/k_integer.rb +2 -5
  9. data/lib/mini_kraken/atomic/k_string.rb +17 -0
  10. data/lib/mini_kraken/{core → atomic}/k_symbol.rb +4 -8
  11. data/lib/mini_kraken/composite/all_composite.rb +4 -0
  12. data/lib/mini_kraken/composite/composite_term.rb +27 -0
  13. data/lib/mini_kraken/composite/cons_cell.rb +301 -0
  14. data/lib/mini_kraken/composite/cons_cell_visitor.rb +50 -0
  15. data/lib/mini_kraken/composite/list.rb +32 -0
  16. data/lib/mini_kraken/core/all_core.rb +8 -0
  17. data/lib/mini_kraken/core/any_value.rb +31 -7
  18. data/lib/mini_kraken/core/arity.rb +69 -0
  19. data/lib/mini_kraken/core/association.rb +29 -4
  20. data/lib/mini_kraken/core/association_copy.rb +50 -0
  21. data/lib/mini_kraken/core/base_term.rb +13 -0
  22. data/lib/mini_kraken/core/blackboard.rb +315 -0
  23. data/lib/mini_kraken/core/bookmark.rb +46 -0
  24. data/lib/mini_kraken/core/context.rb +492 -0
  25. data/lib/mini_kraken/core/duck_fiber.rb +21 -19
  26. data/lib/mini_kraken/core/entry.rb +40 -0
  27. data/lib/mini_kraken/core/fail.rb +20 -18
  28. data/lib/mini_kraken/core/fusion.rb +29 -0
  29. data/lib/mini_kraken/core/goal.rb +20 -29
  30. data/lib/mini_kraken/core/log_var.rb +22 -0
  31. data/lib/mini_kraken/core/log_var_ref.rb +108 -0
  32. data/lib/mini_kraken/core/nullary_relation.rb +2 -9
  33. data/lib/mini_kraken/core/parametrized_term.rb +68 -0
  34. data/lib/mini_kraken/core/relation.rb +14 -28
  35. data/lib/mini_kraken/core/scope.rb +67 -0
  36. data/lib/mini_kraken/core/solver_adapter.rb +58 -0
  37. data/lib/mini_kraken/core/specification.rb +48 -0
  38. data/lib/mini_kraken/core/succeed.rb +21 -17
  39. data/lib/mini_kraken/core/symbol_table.rb +137 -0
  40. data/lib/mini_kraken/core/term.rb +15 -4
  41. data/lib/mini_kraken/glue/dsl.rb +44 -88
  42. data/lib/mini_kraken/glue/run_star_expression.rb +28 -30
  43. data/lib/mini_kraken/rela/all_rela.rb +8 -0
  44. data/lib/mini_kraken/rela/binary_relation.rb +30 -0
  45. data/lib/mini_kraken/rela/conde.rb +143 -0
  46. data/lib/mini_kraken/rela/conj2.rb +65 -0
  47. data/lib/mini_kraken/rela/def_relation.rb +93 -0
  48. data/lib/mini_kraken/rela/disj2.rb +70 -0
  49. data/lib/mini_kraken/rela/fresh.rb +98 -0
  50. data/lib/mini_kraken/{core → rela}/goal_relation.rb +7 -9
  51. data/lib/mini_kraken/rela/unify.rb +265 -0
  52. data/lib/mini_kraken/version.rb +1 -1
  53. data/mini_kraken.gemspec +2 -2
  54. data/spec/.rubocop.yml +1 -1
  55. data/spec/atomic/atomic_term_spec.rb +98 -0
  56. data/spec/{core → atomic}/k_boolean_spec.rb +19 -34
  57. data/spec/{core → atomic}/k_symbol_spec.rb +3 -16
  58. data/spec/composite/cons_cell_spec.rb +225 -0
  59. data/spec/{core → composite}/cons_cell_visitor_spec.rb +36 -20
  60. data/spec/composite/list_spec.rb +50 -0
  61. data/spec/core/any_value_spec.rb +52 -0
  62. data/spec/core/arity_spec.rb +92 -0
  63. data/spec/core/association_copy_spec.rb +69 -0
  64. data/spec/core/association_spec.rb +31 -4
  65. data/spec/core/blackboard_spec.rb +287 -0
  66. data/spec/core/bookmark_spec.rb +40 -0
  67. data/spec/core/context_spec.rb +245 -0
  68. data/spec/core/core_spec.rb +40 -0
  69. data/spec/core/duck_fiber_spec.rb +16 -46
  70. data/spec/core/fail_spec.rb +5 -6
  71. data/spec/core/goal_spec.rb +22 -12
  72. data/spec/core/log_var_ref_spec.rb +105 -0
  73. data/spec/core/log_var_spec.rb +64 -0
  74. data/spec/core/nullary_relation_spec.rb +33 -0
  75. data/spec/core/parametrized_tem_spec.rb +39 -0
  76. data/spec/core/relation_spec.rb +33 -0
  77. data/spec/core/scope_spec.rb +73 -0
  78. data/spec/core/solver_adapter_spec.rb +70 -0
  79. data/spec/core/specification_spec.rb +43 -0
  80. data/spec/core/succeed_spec.rb +5 -5
  81. data/spec/core/symbol_table_spec.rb +142 -0
  82. data/spec/glue/dsl_chap1_spec.rb +88 -144
  83. data/spec/glue/dsl_chap2_spec.rb +454 -19
  84. data/spec/glue/run_star_expression_spec.rb +81 -906
  85. data/spec/rela/conde_spec.rb +153 -0
  86. data/spec/rela/conj2_spec.rb +123 -0
  87. data/spec/rela/def_relation_spec.rb +119 -0
  88. data/spec/rela/disj2_spec.rb +117 -0
  89. data/spec/rela/fresh_spec.rb +147 -0
  90. data/spec/rela/unify_spec.rb +369 -0
  91. data/spec/support/factory_atomic.rb +29 -0
  92. data/spec/support/factory_composite.rb +21 -0
  93. data/spec/support/factory_methods.rb +11 -26
  94. metadata +98 -70
  95. data/lib/mini_kraken/core/association_walker.rb +0 -183
  96. data/lib/mini_kraken/core/atomic_term.rb +0 -67
  97. data/lib/mini_kraken/core/base_arg.rb +0 -10
  98. data/lib/mini_kraken/core/binary_relation.rb +0 -63
  99. data/lib/mini_kraken/core/composite_goal.rb +0 -46
  100. data/lib/mini_kraken/core/composite_term.rb +0 -41
  101. data/lib/mini_kraken/core/conde.rb +0 -143
  102. data/lib/mini_kraken/core/conj2.rb +0 -79
  103. data/lib/mini_kraken/core/cons_cell.rb +0 -82
  104. data/lib/mini_kraken/core/cons_cell_visitor.rb +0 -102
  105. data/lib/mini_kraken/core/def_relation.rb +0 -53
  106. data/lib/mini_kraken/core/designation.rb +0 -55
  107. data/lib/mini_kraken/core/disj2.rb +0 -72
  108. data/lib/mini_kraken/core/environment.rb +0 -73
  109. data/lib/mini_kraken/core/equals.rb +0 -193
  110. data/lib/mini_kraken/core/formal_arg.rb +0 -22
  111. data/lib/mini_kraken/core/formal_ref.rb +0 -25
  112. data/lib/mini_kraken/core/freshness.rb +0 -45
  113. data/lib/mini_kraken/core/goal_arg.rb +0 -12
  114. data/lib/mini_kraken/core/goal_template.rb +0 -102
  115. data/lib/mini_kraken/core/k_boolean.rb +0 -35
  116. data/lib/mini_kraken/core/outcome.rb +0 -63
  117. data/lib/mini_kraken/core/variable.rb +0 -41
  118. data/lib/mini_kraken/core/variable_ref.rb +0 -84
  119. data/lib/mini_kraken/core/vocabulary.rb +0 -446
  120. data/lib/mini_kraken/glue/fresh_env.rb +0 -103
  121. data/lib/mini_kraken/glue/fresh_env_factory.rb +0 -83
  122. data/spec/core/association_walker_spec.rb +0 -192
  123. data/spec/core/conde_spec.rb +0 -147
  124. data/spec/core/conj2_spec.rb +0 -114
  125. data/spec/core/cons_cell_spec.rb +0 -107
  126. data/spec/core/def_relation_spec.rb +0 -97
  127. data/spec/core/disj2_spec.rb +0 -99
  128. data/spec/core/environment_spec.rb +0 -142
  129. data/spec/core/equals_spec.rb +0 -317
  130. data/spec/core/goal_template_spec.rb +0 -74
  131. data/spec/core/outcome_spec.rb +0 -56
  132. data/spec/core/variable_ref_spec.rb +0 -30
  133. data/spec/core/variable_spec.rb +0 -35
  134. data/spec/core/vocabulary_spec.rb +0 -219
  135. data/spec/glue/fresh_env_factory_spec.rb +0 -97
  136. data/spec/glue/fresh_env_spec.rb +0 -62
@@ -1,103 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../core/environment'
4
- require_relative '../core/conj2'
5
- require_relative '../core/goal_template'
6
- require_relative '../core/variable'
7
-
8
- module MiniKraken
9
- module Glue
10
- # A combination of an Environment (= a scope for one or more variables)
11
- # and a goal. It quacks like a Goal object: when receiving the attain message,
12
- # it attempts to achieve its given goal.
13
- # (fresh (x) (== 'pea q))
14
- # Introduces the new variable 'x'
15
- # Takes a list of names and a goal-like object
16
- # Must respond to message attain(aPublisher, vars) and must return an Outcome
17
- class FreshEnv < Core::Environment
18
- # @return [Goal]
19
- attr_reader :goal
20
-
21
- # @return [TrueClass, FalseClass] Do associations persist after goal exec?
22
- attr_reader :persistent
23
-
24
- # @param theNames [Array<String>] The variable names
25
- # @param aGoal [Goal, Array<Goal>] The goal to achieve or the conjunction of them.
26
- def initialize(theNames, aGoal, persistence = true)
27
- super()
28
- @goal = valid_goal(aGoal)
29
- theNames.each do |nm|
30
- var = Core::Variable.new(nm)
31
- add_var(var)
32
- end
33
- @persistent = persistence
34
- end
35
-
36
- # Attempt to achieve the goal given this environment
37
- # @param aParent [Environment]
38
- # @return [Fiber<Outcome>] A Fiber object that will generate the results.
39
- def attain(aParent)
40
- # require 'debug'
41
- self.parent = aParent
42
- goal.attain(self)
43
- end
44
-
45
- # Remove associations of variables of this environment, if
46
- # persistence flag is set to false.
47
- def prune(anOutcome)
48
- return super(anOutcome) if persistent
49
-
50
- vars.each_value do |v|
51
- v_name = v.name
52
- if anOutcome.associations.include?(v_name)
53
- anOutcome.associations.delete(v_name)
54
- end
55
- end
56
-
57
- anOutcome
58
- end
59
-
60
- protected
61
-
62
- def introspect
63
- +", @vars=[#{vars.keys.join(', ')}]"
64
- end
65
-
66
- private
67
-
68
- def valid_goal(aGoal)
69
- result = nil
70
-
71
- case aGoal
72
- when Core::Goal
73
- result = aGoal
74
- when FreshEnv
75
- result = aGoal
76
- when Core::GoalTemplate
77
- result = aGoal
78
- when Array # an Array of Goal?..
79
- goal_array = aGoal
80
- loop do
81
- conjunctions = []
82
- goal_array.each_slice(2) do |uno_duo|
83
- if uno_duo.size == 2
84
- conjunctions << Core::Goal.new(Core::Conj2.instance, uno_duo)
85
- else
86
- conjunctions << uno_duo[0]
87
- end
88
- end
89
- if conjunctions.size == 1
90
- result = conjunctions[0]
91
- break
92
- end
93
- goal_array = conjunctions
94
- end
95
- else
96
- raise StandardError, "Cannot handle argumment type #{aGoal.class}"
97
- end
98
-
99
- result
100
- end
101
- end # class
102
- end # module
103
- end # module
@@ -1,83 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../core/environment'
4
- require_relative '../core/conj2'
5
- require_relative '../core/goal_template'
6
- require_relative '../core/variable'
7
- require_relative 'fresh_env'
8
-
9
- module MiniKraken
10
- module Glue
11
- # A combination of an Environment (= a scope for one or more variables)
12
- # and a goal. It quacks like a Goal template object: when receiving the
13
- # instantiate message, it creates a FreshEnv.
14
- class FreshEnvFactory
15
- # @return [Array<String>] The names of variables to be.
16
- attr_reader :names
17
-
18
- # @return [GoalTemplate] The goal template
19
- attr_reader :goal_template
20
-
21
- # @param theNames [Array<String>] The names of variables to build.
22
- # @param aGoal [GoalTemplate, Array<Goal>] The goal template(s)
23
- def initialize(theNames, aGoalTemplate)
24
- @goal_template = valid_goal_template(aGoalTemplate)
25
- @names = valid_names(theNames)
26
- end
27
-
28
- # Factory method: Create a goal object.
29
- # @param formals [Array<FormalArg>] Array of formal arguments
30
- # @param actuals [Array<GoalArg>] Array of actual arguments
31
- # @return [Goal] instantiate a goal object given the actuals and environment
32
- def instantiate(formals, actuals)
33
- # require 'debug'
34
- goal = goal_template.instantiate(formals, actuals)
35
- FreshEnv.new(names, goal, false)
36
- end
37
-
38
- protected
39
-
40
- def introspect
41
- +", @names=[#{names.join(', ')}]"
42
- end
43
-
44
- private
45
-
46
- def valid_names(theNames)
47
- theNames
48
- end
49
-
50
- def valid_goal_template(aGoalTemplate)
51
- result = nil
52
-
53
- case aGoalTemplate
54
- when FreshEnvFactory
55
- result = aGoalTemplate
56
- when Core::GoalTemplate
57
- result = aGoalTemplate
58
- # when Array # an Array of Goal?..
59
- # goal_array = aGoalTemplate
60
- # loop do
61
- # conjunctions = []
62
- # goal_array.each_slice(2) do |uno_duo|
63
- # if uno_duo.size == 2
64
- # conjunctions << Core::GoalTemplate.new(Core::Conj2.instance, uno_duo)
65
- # else
66
- # conjunctions << uno_duo[0]
67
- # end
68
- # end
69
- # if conjunctions.size == 1
70
- # result = conjunctions[0]
71
- # break
72
- # end
73
- # goal_array = conjunctions
74
- # end
75
- else
76
- raise StandardError, "Cannot handle argumment type #{aGoalTemplate.class}"
77
- end
78
-
79
- result
80
- end
81
- end # class
82
- end # module
83
- end # module
@@ -1,192 +0,0 @@
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('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('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('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('q', ref_x)
86
- env.add_assoc('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('q', ref_x)
97
- env.add_assoc('x', pea)
98
- env.add_assoc('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('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('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('q', expr)
131
- env.add_assoc('x', pod)
132
-
133
- result = subject.find_ground(var_q.name, env)
134
- expect(result).to eq(expr)
135
- end
136
-
137
- it 'should categorize a variable without association as free' do
138
- env.add_var(var_q)
139
- result = subject.determine_freshness(ref_q, env)
140
- expect(result).to be_fresh
141
- expect(result.associated).to be_nil
142
- end
143
-
144
- it 'should categorize a variable related to fresh variable as bound' do
145
- env.add_var(var_q)
146
- env.add_var(var_x)
147
- env.add_assoc('q', ref_x)
148
-
149
- result = subject.determine_freshness(ref_q, env)
150
- expect(result).to be_bound
151
- expect(result.associated).to eq(ref_x)
152
- end
153
-
154
- it 'should categorize a variable even in presence of fused var(s)' do
155
- env.add_var(var_q)
156
- env.add_var(var_x)
157
- env.add_assoc('q', ref_x)
158
- env.add_assoc('x', ref_q)
159
- # q and x are fused...
160
-
161
- result = subject.determine_freshness(ref_q, env)
162
- expect(result).to be_fresh
163
- expect(var_q.i_name).to eq(var_x.i_name)
164
- expect(env.associations).to be_empty
165
- end
166
-
167
- it 'should categorize an atomic term as ground term' do
168
- result = subject.determine_freshness(pea, env)
169
- expect(result).to be_ground
170
- expect(result.associated).to eq(pea)
171
- end
172
-
173
- it 'should categorize a composite term as ground term' do
174
- # Ground composite: a composite where all members are ground
175
- composite = cons(pea, cons(pod))
176
- result = subject.determine_freshness(composite, env)
177
- expect(result).to be_ground
178
- expect(result.associated).to eq(composite)
179
- end
180
-
181
- it 'should categorize a composite term as bound term' do
182
- # Bound composite: a composite where at least one member is fresh
183
- env.add_var(var_q)
184
- composite = cons(pea, cons(ref_q))
185
- result = subject.determine_freshness(composite, env)
186
- expect(result).to be_bound
187
- expect(result.associated).to eq(composite)
188
- end
189
- end # context
190
- end # describe
191
- end # module
192
- end # module
@@ -1,147 +0,0 @@
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/fail'
6
- require_relative '../../lib/mini_kraken/core/succeed'
7
- require_relative '../../lib/mini_kraken/core/equals'
8
- require_relative '../../lib/mini_kraken/core/environment'
9
- require_relative '../../lib/mini_kraken/core/variable'
10
- require_relative '../../lib/mini_kraken/core/variable_ref'
11
-
12
- # Load the class under test
13
- require_relative '../../lib/mini_kraken/core/conde'
14
-
15
- module MiniKraken
16
- module Core
17
- describe Conde do
18
- subject { Conde.instance }
19
-
20
- context 'Initialization:' do
21
- it 'should be initialized without argument' do
22
- expect { Conde.instance }.not_to raise_error
23
- end
24
-
25
- it 'should know its name' do
26
- expect(subject.name).to eq('conde')
27
- end
28
- end # context
29
-
30
- context 'Provided services:' do
31
- let(:bean) { KSymbol.new(:bean) }
32
- let(:corn) { KSymbol.new(:corn) }
33
- let(:meal) { KSymbol.new(:meal) }
34
- let(:oil) { KSymbol.new(:oil) }
35
- let(:olive) { KSymbol.new(:olive) }
36
- let(:pea) { KSymbol.new(:pea) }
37
- let(:red) { KSymbol.new(:red) }
38
- let(:split) { KSymbol.new(:split) }
39
- let(:fails) { Goal.new(Fail.instance, []) }
40
- let(:succeeds) { Goal.new(Succeed.instance, []) }
41
- let(:var_q) { Variable.new('q') }
42
- let(:var_x) { Variable.new('x') }
43
- let(:var_y) { Variable.new('y') }
44
- let(:ref_q) { VariableRef.new('q') }
45
- let(:ref_x) { VariableRef.new('x') }
46
- let(:ref_y) { VariableRef.new('y') }
47
- let(:env) do
48
- e = Environment.new
49
- e.add_var(var_q)
50
- e.add_var(var_x)
51
- e.add_var(var_y)
52
- e
53
- end
54
-
55
- it 'should complain when one of its argument is not a goal' do
56
- err = StandardError
57
- expect { subject.solver_for([succeeds, pea], env) }.to raise_error(err)
58
- expect { subject.solver_for([pea, succeeds], env) }.to raise_error(err)
59
- end
60
-
61
- it 'should fail when all goals fail' do
62
- solver = subject.solver_for([fails, fails, fails], env)
63
- expect(solver.resume).not_to be_success
64
- expect(solver.resume).to be_nil
65
- end
66
-
67
- it 'yield success if first argument succeeds' do
68
- subgoal = Goal.new(Equals.instance, [olive, ref_q])
69
- solver = subject.solver_for([subgoal, fails, fails], env)
70
- outcome = solver.resume
71
- expect(outcome).to be_success
72
- expect(outcome.associations['q'].first.value).to eq(olive)
73
- expect(solver.resume).to be_nil
74
- end
75
-
76
- it 'yield success if second argument succeeds' do
77
- subgoal = Goal.new(Equals.instance, [oil, ref_q])
78
- solver = subject.solver_for([fails, subgoal, fails], env)
79
- outcome = solver.resume
80
- expect(outcome).to be_success
81
- expect(outcome.associations['q'].first.value).to eq(oil)
82
- expect(solver.resume).to be_nil
83
- end
84
-
85
- it 'yield success if third argument succeeds' do
86
- subgoal = Goal.new(Equals.instance, [oil, ref_q])
87
- solver = subject.solver_for([fails, fails, subgoal], env)
88
- outcome = solver.resume
89
- expect(outcome).to be_success
90
- expect(outcome.associations['q'].first.value).to eq(oil)
91
- expect(solver.resume).to be_nil
92
- end
93
-
94
- it 'yields three solutions if three goals succeed' do
95
- # Covers frame 1:58
96
- subgoal1 = Goal.new(Equals.instance, [olive, ref_q])
97
- subgoal2 = Goal.new(Equals.instance, [oil, ref_q])
98
- subgoal3 = Goal.new(Equals.instance, [pea, ref_q])
99
- solver = subject.solver_for([subgoal1, subgoal2, subgoal3, fails], env)
100
-
101
- # First solution
102
- outcome1 = solver.resume
103
- expect(outcome1).to be_success
104
- expect(outcome1.associations['q'].first.value).to eq(olive)
105
-
106
- # Second solution
107
- outcome2 = solver.resume
108
- expect(outcome2).to be_success
109
- expect(outcome2.associations['q'].first.value).to eq(oil)
110
-
111
- # Third solution
112
- outcome3 = solver.resume
113
- expect(outcome3).to be_success
114
- expect(outcome3.associations['q'].first.value).to eq(pea)
115
-
116
- expect(solver.resume).to be_nil
117
- end
118
-
119
- it 'also use conjunctions for nested goals' do
120
- # Covers frame 1:88
121
- subgoal1 = Goal.new(Equals.instance, [split, ref_x])
122
- subgoal2 = Goal.new(Equals.instance, [pea, ref_y])
123
- combo1 = [subgoal1, subgoal2]
124
-
125
- subgoal3 = Goal.new(Equals.instance, [red, ref_x])
126
- subgoal4 = Goal.new(Equals.instance, [bean, ref_y])
127
- combo2 = [subgoal3, subgoal4]
128
- solver = subject.solver_for([combo1, combo2], env)
129
-
130
- # First solution
131
- outcome1 = solver.resume
132
- expect(outcome1).to be_success
133
- expect(outcome1.associations['x'].first.value).to eq(split)
134
- expect(outcome1.associations['y'].first.value).to eq(pea)
135
-
136
- # Second solution
137
- outcome2 = solver.resume
138
- expect(outcome2).to be_success
139
- expect(outcome2.associations['x'].first.value).to eq(red)
140
- expect(outcome2.associations['y'].first.value).to eq(bean)
141
-
142
- expect(solver.resume).to be_nil
143
- end
144
- end # context
145
- end # describe
146
- end # module
147
- end # module