porolog 0.0.8 → 1.0.0

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.
@@ -608,6 +608,42 @@ describe 'Porolog' do
608
608
  assert_equal [value1], instantiation1.values_for(variable3)
609
609
  end
610
610
 
611
+ it 'should return the value of variable1 given the instantiation of the flathead of variable1' do
612
+ value1 = goal1.value([1,2,3,4])
613
+
614
+ instantiation1 = variable1.instantiate variable2, nil, :flathead
615
+ variable2.instantiate value1
616
+
617
+ assert_equal [[1,2,3,4,UNKNOWN_TAIL]], instantiation1.values_for(variable1)
618
+ end
619
+
620
+ it 'should return the value of variable1 given the instantiation of the flathead of variable2' do
621
+ value1 = goal1.value([1,2,3,4])
622
+
623
+ instantiation1 = variable2.instantiate variable1, :flathead
624
+ variable2.instantiate value1
625
+
626
+ assert_equal [[1,2,3,4,UNKNOWN_TAIL]], instantiation1.values_for(variable1)
627
+ end
628
+
629
+ it 'should return the value of variable1 given the instantiation of the flattail of variable1' do
630
+ value1 = goal1.value([1,2,3,4])
631
+
632
+ instantiation1 = variable1.instantiate variable2, nil, :flattail
633
+ variable2.instantiate value1
634
+
635
+ assert_equal [[UNKNOWN_TAIL,1,2,3,4]], instantiation1.values_for(variable1)
636
+ end
637
+
638
+ it 'should return the value of variable1 given the instantiation of the flattail of variable2' do
639
+ value1 = goal1.value([1,2,3,4])
640
+
641
+ instantiation1 = variable2.instantiate variable1, :flattail
642
+ variable2.instantiate value1
643
+
644
+ assert_equal [[UNKNOWN_TAIL,1,2,3,4]], instantiation1.values_for(variable1)
645
+ end
646
+
611
647
  end
612
648
 
613
649
  describe '#value_at_index' do
@@ -13,10 +13,24 @@ describe 'Porolog' do
13
13
  reset
14
14
  end
15
15
 
16
- describe 'UNKNOWN_TAIL#inspect' do
16
+ describe 'UNKNOWN_TAIL' do
17
17
 
18
- it 'should return distinctive notation' do
19
- assert_equal '...', UNKNOWN_TAIL.inspect
18
+ describe '#inspect' do
19
+
20
+ it 'should return distinctive notation' do
21
+ assert_equal '...', UNKNOWN_TAIL.inspect
22
+ end
23
+
24
+ end
25
+
26
+ describe '#tail' do
27
+
28
+ it 'should return itself' do
29
+ assert_equal UNKNOWN_TAIL, UNKNOWN_TAIL.tail
30
+ assert_equal UNKNOWN_TAIL, UNKNOWN_TAIL.tail(1)
31
+ assert_equal UNKNOWN_TAIL, UNKNOWN_TAIL.tail(5)
32
+ end
33
+
20
34
  end
21
35
 
22
36
  end
@@ -73,6 +87,42 @@ describe 'Porolog' do
73
87
  assert_Arguments upsilon([]), :upsilon, [[]]
74
88
  end
75
89
 
90
+ it 'should define a method in a base class as an instance method and a class method' do
91
+ class Base1 ; end
92
+
93
+ refute_includes Base1.methods, :localised_predicate
94
+ refute_includes Base1.instance_methods, :localised_predicate
95
+
96
+ class Base1
97
+
98
+ builtin :between, class_base: self
99
+ predicate :localised_predicate, class_base: self
100
+
101
+ localised_predicate(:X) << [
102
+ between(:X, 1, 5)
103
+ ]
104
+
105
+ def process
106
+ localised_predicate(:X).solve_for(:X)
107
+ end
108
+ end
109
+
110
+ assert_includes Base1.methods, :localised_predicate
111
+ assert_includes Base1.instance_methods, :localised_predicate
112
+
113
+ refute_includes methods, :localised_predicate
114
+
115
+ assert_solutions Base1.localised_predicate(:X), [
116
+ { X: 1 },
117
+ { X: 2 },
118
+ { X: 3 },
119
+ { X: 4 },
120
+ { X: 5 },
121
+ ]
122
+
123
+ assert_equal [1,2,3,4,5], Base1.new.process
124
+ end
125
+
76
126
  end
77
127
 
78
128
  describe '#unify_goals' do
@@ -267,7 +317,7 @@ describe 'Porolog' do
267
317
  end
268
318
 
269
319
  after do
270
- assert_equal 1, @spy.calls.size
320
+ assert_equal 1, @spy.calls.size, "expected unify_arrays to be called once for #{name}"
271
321
  end
272
322
 
273
323
  it 'should unify empty arrays' do
@@ -367,9 +417,43 @@ describe 'Porolog' do
367
417
  assert_nil unify(:draw, :word, goal), name
368
418
 
369
419
  expected_log = [
370
- 'Cannot unify because Goal1."picturing" != Goal1."something" (variable != variable)'
420
+ 'Cannot unify because "picturing" != "something" (variable != variable)'
421
+ ]
422
+
423
+ assert_equal expected_log, goal.log
424
+ end
425
+
426
+ it 'should unify the unknown array with a variable' do
427
+ goal.instantiate :X, UNKNOWN_ARRAY
428
+ goal.instantiate :Y, [1,2,3,4]
429
+
430
+ unifications = unify(goal[:X], goal[:Y], goal)
431
+
432
+ expected_unifications = [
433
+ [goal[:X], goal[:Y], goal, goal]
434
+ ]
435
+
436
+ assert_equal expected_unifications, unifications
437
+
438
+ expected_log = []
439
+
440
+ assert_equal expected_log, goal.log
441
+ end
442
+
443
+ it 'should unify the unknown array with an array' do
444
+ goal.instantiate :X, [1,2,3,4]
445
+ goal.instantiate :Y, UNKNOWN_ARRAY
446
+
447
+ unifications = unify(goal[:X], goal[:Y], goal)
448
+
449
+ expected_unifications = [
450
+ [goal[:X], goal[:Y], goal, goal]
371
451
  ]
372
452
 
453
+ assert_equal expected_unifications, unifications
454
+
455
+ expected_log = []
456
+
373
457
  assert_equal expected_log, goal.log
374
458
  end
375
459
 
@@ -470,7 +554,7 @@ describe 'Porolog' do
470
554
  assert_nil unify([7,11,13], 'word', goal), name
471
555
 
472
556
  expected_log = [
473
- 'Cannot unify [7, 11, 13] with "word"',
557
+ 'Cannot unify [7, 11, 13] with "word" (array != atomic)',
474
558
  ]
475
559
 
476
560
  assert_equal expected_log, goal.log
@@ -480,7 +564,59 @@ describe 'Porolog' do
480
564
  assert_nil unify('word', [7,11,13], goal), name
481
565
 
482
566
  expected_log = [
483
- 'Cannot unify "word" with [7, 11, 13]',
567
+ 'Cannot unify "word" with [7, 11, 13] (atomic != array)',
568
+ ]
569
+
570
+ assert_equal expected_log, goal.log
571
+ end
572
+
573
+ end
574
+
575
+ describe 'when [:array, :tail]' do
576
+
577
+ let(:goal) { new_goal :p, :x, :y }
578
+
579
+ it 'should unify an array and a tail' do
580
+ assert unify([7,11,13], Tail.new([[7,11,goal[:P]]]), goal), name
581
+
582
+ expected_log = []
583
+
584
+ assert_equal expected_log, goal.log
585
+ end
586
+
587
+ it 'should not unify an array and tail when they cannot be unified' do
588
+ refute unify([7,11,13], Tail.new([[7,11,14]]), goal), name
589
+
590
+ expected_log = [
591
+ 'Cannot unify incompatible values: 13 with 14',
592
+ 'Cannot unify: [7, 11, 13] with [7, 11, 14]',
593
+ 'Cannot unify because [7, 11, 13] != *[[7, 11, 14]] (array != tail)'
594
+ ]
595
+
596
+ assert_equal expected_log, goal.log
597
+ end
598
+
599
+ end
600
+
601
+ describe 'when [:tail, :array]' do
602
+
603
+ let(:goal) { new_goal :p, :x, :y }
604
+
605
+ it 'should unify a tail and an array' do
606
+ assert unify(Tail.new([[7,11,13]]), [7,11,goal[:P]], goal), name
607
+
608
+ expected_log = []
609
+
610
+ assert_equal expected_log, goal.log
611
+ end
612
+
613
+ it 'should not unify a tail and an array when they cannot be unified' do
614
+ refute unify(Tail.new([[7,11,13]]), [7,11,14], goal), name
615
+
616
+ expected_log = [
617
+ 'Cannot unify incompatible values: 13 with 14',
618
+ 'Cannot unify: [7, 11, 13] with [7, 11, 14]',
619
+ 'Cannot unify because *[[7, 11, 13]] != [7, 11, 14] (tail != array)'
484
620
  ]
485
621
 
486
622
  assert_equal expected_log, goal.log
@@ -488,6 +624,22 @@ describe 'Porolog' do
488
624
 
489
625
  end
490
626
 
627
+ describe 'when [:tail, :tail]' do
628
+
629
+ it 'something' do
630
+ expected_unifications = [
631
+ [goal[:B], [goal[:H]]/:T, goal, goal],
632
+ [goal[:C], [goal[:H]]/:NT, goal, goal]
633
+ ]
634
+ assert_equal expected_unifications, unify(
635
+ [:A, :B, :C],
636
+ [:A, [:H]/:T, [:H]/:NT],
637
+ goal
638
+ )
639
+ end
640
+
641
+ end
642
+
491
643
  end
492
644
 
493
645
  describe '#unify_arrays' do
@@ -1094,7 +1246,7 @@ describe 'Porolog' do
1094
1246
 
1095
1247
  merged, unifications = unify_arrays_with_no_tails(arrays, arrays_goals, [])
1096
1248
 
1097
- expected_merged = [1, 2, nil, 4, nil]
1249
+ expected_merged = [1, 2, nil, 4, g3[:z]]
1098
1250
  expected_unifications = [
1099
1251
  [g2[:j], g1[1], g2, g1],
1100
1252
  [g2[:n], g1[2], g2, g1],
@@ -1197,21 +1349,6 @@ describe 'Porolog' do
1197
1349
  ], g3.log
1198
1350
  end
1199
1351
 
1200
- it 'should raise an exception when an array has no associated goal' do # NOT DONE: need to expose the call to unify_arrays_with_no_tails
1201
-
1202
- error = assert_raises Porolog::NoGoalError do
1203
- variable1 = Variable.new :x, g1
1204
- value = Value.new [7,11,13,23,29], g2
1205
-
1206
- variable1.values << [7,11,13,23,29]
1207
- variable1.values << [7,12,13,23,29]
1208
-
1209
- variable1.instantiate value
1210
- end
1211
-
1212
- assert_equal 'Array [7, 11, 13, 23, 29] has no goal for unification', error.message
1213
- end
1214
-
1215
1352
  end
1216
1353
 
1217
1354
  describe '#unify_arrays_with_some_tails' do
@@ -1307,7 +1444,7 @@ describe 'Porolog' do
1307
1444
 
1308
1445
  merged, unifications = unify_arrays_with_some_tails(arrays, arrays_goals, [])
1309
1446
 
1310
- expected_merged = [1, 2, nil, 4, nil]
1447
+ expected_merged = [1, 2, nil, 4, g3[:z]]
1311
1448
  expected_unifications = [
1312
1449
  [g2.variable(:j), g1.value(1), g2, g1],
1313
1450
  [g3.variable(:x), g1.value(1), g3, g1],
@@ -1466,7 +1603,7 @@ describe 'Porolog' do
1466
1603
 
1467
1604
  end
1468
1605
 
1469
- describe '#unify_arrays_with_all_tails' do # NOT DONE: coverage
1606
+ describe '#unify_arrays_with_all_tails' do
1470
1607
 
1471
1608
  let(:g1) { new_goal(:p, :x, :y) }
1472
1609
  let(:g2) { new_goal(:q, :a, :b) }
@@ -1527,6 +1664,7 @@ describe 'Porolog' do
1527
1664
  [g3[:x], g2[2], g3, g2],
1528
1665
  [g2[:y], g1[5], g2, g1],
1529
1666
  [g1[:z], g3[6], g1, g3],
1667
+ [g1[:z], g1[6], g1, g1],
1530
1668
  ]
1531
1669
 
1532
1670
  assert_equal expected_merged, merged
@@ -1879,11 +2017,11 @@ describe 'Porolog' do
1879
2017
  assert_nil unify_headtail_with_tail(arrays, arrays_goals, []), name
1880
2018
 
1881
2019
  assert_equal [
1882
- 'Cannot unify because Goal1.1 != Goal2.2 (variable != variable)',
2020
+ 'Cannot unify because 1 != 2 (variable != variable)',
1883
2021
  'Cannot unify heads: Goal1.:h with Goal2.:h',
1884
2022
  ], g1.log
1885
2023
  assert_equal [
1886
- 'Cannot unify because Goal1.1 != Goal2.2 (variable != variable)',
2024
+ 'Cannot unify because 1 != 2 (variable != variable)',
1887
2025
  'Cannot unify heads: Goal1.:h with Goal2.:h',
1888
2026
  ], g2.log
1889
2027
  assert_equal [
@@ -1911,12 +2049,12 @@ describe 'Porolog' do
1911
2049
  assert_nil unify_headtail_with_tail(arrays, arrays_goals, []), name
1912
2050
 
1913
2051
  assert_equal [
1914
- 'Cannot unify because Goal1.[2, 3] != Goal2.[2, 4] (variable != variable)',
2052
+ 'Cannot unify because [2, 3] != [2, 4] (variable != variable)',
1915
2053
  'Cannot unify headtail tails: Goal1.:t with Goal2.:t',
1916
2054
  'Could not unify headtail arrays: [Goal1.:h, Goal1.2, Goal1.3] with [Goal2.:h, Goal2.2, Goal2.4] with [Goal4.:h, *Goal4.:t]',
1917
2055
  ], g1.log
1918
2056
  assert_equal [
1919
- 'Cannot unify because Goal1.[2, 3] != Goal2.[2, 4] (variable != variable)',
2057
+ 'Cannot unify because [2, 3] != [2, 4] (variable != variable)',
1920
2058
  'Cannot unify headtail tails: Goal1.:t with Goal2.:t',
1921
2059
  'Could not unify headtail arrays: [Goal1.:h, Goal1.2, Goal1.3] with [Goal2.:h, Goal2.2, Goal2.4] with [Goal4.:h, *Goal4.:t]',
1922
2060
  ], g2.log
@@ -1980,7 +2118,6 @@ describe 'Porolog' do
1980
2118
  assert_equal [
1981
2119
  'Cannot unify incompatible values: 3 with 4',
1982
2120
  'Cannot unify: [3] with [4]',
1983
- #'Cannot unify: Goal2.3 with Goal3.4',
1984
2121
  ], g2.log
1985
2122
  assert_equal [
1986
2123
  'Cannot unify incompatible values: 3 with 4',
@@ -2172,4 +2309,122 @@ describe 'Porolog' do
2172
2309
 
2173
2310
  end
2174
2311
 
2312
+ describe '#builtin' do
2313
+
2314
+ it 'should create a Predicate' do
2315
+ # -- Precondition Baseline --
2316
+ assert_equal 0, Scope[:default].predicates.size
2317
+
2318
+ # -- Test --
2319
+ single_predicate = builtin :member
2320
+
2321
+ # -- Compare Result Against Baseline --
2322
+ assert_equal 1, Scope[:default].predicates.size
2323
+ assert_equal :member, Scope[:default].predicates.first.name
2324
+ assert_Predicate single_predicate, :member, []
2325
+ end
2326
+
2327
+ it 'should define a method to create Arguments for solving' do
2328
+ Object.class_eval{
2329
+ remove_method(:member) if public_method_defined?(:member)
2330
+ }
2331
+
2332
+ refute respond_to?(:member)
2333
+
2334
+ builtin :member
2335
+
2336
+ assert respond_to?(:member)
2337
+ assert_Arguments member(:X, ['left','right']), :member, [:X, ['left','right']]
2338
+
2339
+ assert_includes methods, :member
2340
+ end
2341
+
2342
+ it 'should create multiple Predicates' do
2343
+ assert_equal 0, Scope[:default].predicates.size
2344
+
2345
+ multiple_predicates = builtin :member, :append, :is
2346
+
2347
+ assert_equal 3, Scope[:default].predicates.size
2348
+ assert_equal :member, Scope[:default].predicates[0].name
2349
+ assert_equal :append, Scope[:default].predicates[1].name
2350
+ assert_equal :is, Scope[:default].predicates[2].name
2351
+ assert_instance_of Array, multiple_predicates
2352
+ assert_equal 3, multiple_predicates.size
2353
+ assert_Predicate multiple_predicates[0], :member, []
2354
+ assert_Predicate multiple_predicates[1], :append, []
2355
+ assert_Predicate multiple_predicates[2], :is, []
2356
+ end
2357
+
2358
+ it 'should define multiple methods to create Arguments for solving' do
2359
+ Object.class_eval{
2360
+ remove_method(:member) if public_method_defined?(:member)
2361
+ remove_method(:append) if public_method_defined?(:append)
2362
+ }
2363
+
2364
+ refute respond_to?(:member)
2365
+ refute respond_to?(:append)
2366
+
2367
+ builtin :member, :append
2368
+
2369
+ assert respond_to?(:member)
2370
+ assert respond_to?(:append)
2371
+ assert_Arguments member(:X, :L), :member, [:X, :L]
2372
+ assert_Arguments append(:A, :B, :AB), :append, [:A, :B, :AB]
2373
+ end
2374
+
2375
+ it 'should define a method in a base class as an instance method and a class method' do
2376
+ Object.class_eval{
2377
+ remove_method(:member) if public_method_defined?(:member)
2378
+ }
2379
+
2380
+ class Base2 ; end
2381
+
2382
+ refute_includes Base2.methods, :member
2383
+ refute_includes Base2.instance_methods, :member
2384
+
2385
+ builtin :member, class_base: Base2
2386
+
2387
+ assert_includes Base2.methods, :member
2388
+ assert_includes Base2.instance_methods, :member
2389
+
2390
+ refute_includes methods, :member
2391
+
2392
+ class Base2
2393
+ def process
2394
+ member(:X, [4,5,6]).solve_for(:X)
2395
+ end
2396
+ end
2397
+
2398
+ assert_solutions Base2.member(:X, [1,2,3]), [
2399
+ { X: 1 },
2400
+ { X: 2 },
2401
+ { X: 3 },
2402
+ ]
2403
+
2404
+ assert_equal [4,5,6], Base2.new.process
2405
+ end
2406
+
2407
+ end
2408
+
2409
+ describe '#_' do
2410
+
2411
+ let(:goal) { new_goal :p, :x, :y }
2412
+
2413
+ it 'should return a different variable on each call' do
2414
+ # _ is overridden by MiniTest
2415
+ variable1 = Porolog._
2416
+ variable2 = Porolog._
2417
+ variable3 = Porolog._
2418
+
2419
+ assert_equal :_a, variable1
2420
+ assert_equal :_b, variable2
2421
+ assert_equal :_c, variable3
2422
+
2423
+ refute_equal variable1, variable2
2424
+ refute_equal variable2, variable3
2425
+ refute_equal variable3, variable1
2426
+ end
2427
+
2428
+ end
2429
+
2175
2430
  end