rubylog 2.0.1 → 2.1.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.
- data/Gemfile +2 -0
- data/Gemfile.lock +10 -0
- data/README.rdoc +1 -1
- data/RELEASE_NOTES.rdoc +7 -4
- data/VERSION +1 -1
- data/{examples → benchmark}/benchmark.rb +1 -0
- data/{examples → benchmark}/benchmark/compiled_not_indexed.rb +0 -0
- data/{examples → benchmark}/benchmark/compiled_sequence_indexed.rb +0 -0
- data/{examples → benchmark}/benchmark/indexed_procedure.rb +0 -0
- data/{examples → benchmark}/benchmark/prolog.rb +0 -0
- data/benchmark/benchmark/pure.rb +28 -0
- data/bin/rubylog +14 -0
- data/examples/a_plus_b.rb +2 -2
- data/examples/dcg.rb +22 -26
- data/examples/dcg2.rb +25 -30
- data/examples/divisors.rb +1 -3
- data/examples/factorial.rb +8 -15
- data/examples/file_search.rb +14 -13
- data/examples/hanoi.rb +1 -3
- data/examples/hu/csaladfa.rb +0 -4
- data/examples/n_queens.rb +17 -22
- data/examples/palindrome_detection.rb +1 -2
- data/examples/parsing.rb +19 -23
- data/examples/permutation.rb +1 -3
- data/examples/primality_by_division.rb +2 -2
- data/examples/sieve_of_eratosthenes.rb +2 -2
- data/examples/string_interpolation.rb +0 -3
- data/examples/tracing.rb +0 -4
- data/lib/rubylog/builtins/assumption.rb +2 -1
- data/lib/rubylog/builtins/file_system.rb +1 -1
- data/lib/rubylog/default_context.rb +3 -5
- data/lib/rubylog/mixins/kernel.rb +9 -1
- data/lib/rubylog/rubylog_files.rb +7 -0
- data/rubylog.gemspec +17 -22
- data/spec/inriasuite_spec.rb +851 -847
- data/spec/integration/dsl_spec.rb +32 -29
- data/spec/rspec/rubylog_spec.rb +46 -52
- data/spec/rubylog/assertable_spec.rb +92 -90
- data/spec/rubylog/builtins/arithmetics_spec.rb +92 -90
- data/spec/rubylog/builtins/assumption_spec.rb +59 -57
- data/spec/rubylog/builtins/ensure_spec.rb +6 -4
- data/spec/rubylog/builtins/file_system_spec.rb +41 -39
- data/spec/rubylog/builtins/logic_spec.rb +308 -306
- data/spec/rubylog/builtins/reflection_spec.rb +31 -29
- data/spec/rubylog/builtins/term_spec.rb +62 -60
- data/spec/rubylog/context_modules/demonstration_spec.rb +108 -106
- data/spec/rubylog/context_modules/predicates_spec.rb +29 -27
- data/spec/rubylog/context_modules/thats_spec.rb +77 -75
- data/spec/rubylog/dsl/array_splat_spec.rb +11 -9
- data/spec/rubylog/dsl/indicators_spec.rb +23 -21
- data/spec/rubylog/dsl/primitives_spec.rb +30 -28
- data/spec/rubylog/errors_spec.rb +13 -11
- data/spec/rubylog/interfaces/term_spec.rb +78 -76
- data/spec/rubylog/mixins/array_spec.rb +60 -58
- data/spec/rubylog/mixins/composite_term_spec.rb +55 -53
- data/spec/rubylog/mixins/proc_spec.rb +48 -46
- data/spec/rubylog/mixins/string_spec.rb +45 -43
- data/spec/rubylog/mixins/symbol_spec.rb +7 -5
- data/spec/rubylog/procedure_spec.rb +8 -6
- data/spec/rubylog/rule_spec.rb +10 -8
- data/spec/rubylog/structure_spec.rb +73 -71
- data/spec/rubylog/term_spec.rb +5 -3
- data/spec/rubylog/tracing_spec.rb +35 -33
- data/spec/rubylog/variable_spec.rb +249 -247
- data/spec/spec_helper.rb +4 -0
- metadata +54 -43
- data/examples/benchmark/pure.rb +0 -26
- data/examples/checkmate.rb +0 -88
- data/examples/combination.rb +0 -17
- data/examples/directory_structure_logic.rb +0 -17
- data/examples/dirlist.rb +0 -4
- data/examples/enumerators.rb +0 -30
- data/examples/hello.rb +0 -17
- data/examples/mice.rb +0 -92
- data/examples/mice2.rb +0 -37
- data/examples/object_oriented.rb +0 -14
- data/examples/prefix.rb +0 -13
- data/examples/primitives.rb +0 -26
- data/examples/sudoku.rb +0 -17
- data/spec/integration/theory_as_module_spec.rb +0 -20
- data/spec/integration/theory_as_module_with_include_spec.rb +0 -14
@@ -1,80 +1,82 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
3
|
+
module RubylogSpec
|
4
|
+
describe Array, :rubylog=>true do
|
5
|
+
|
6
|
+
describe "unification" do
|
7
|
+
def can_unify a, b
|
8
|
+
result = false
|
9
|
+
a.rubylog_unify(b) { result = true; yield if block_given? }
|
10
|
+
result.should == true
|
11
|
+
end
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
13
|
+
def cannot_unify a, b
|
14
|
+
result = false
|
15
|
+
a.rubylog_unify(b) { result = true }
|
16
|
+
result.should == false
|
17
|
+
end
|
17
18
|
|
18
|
-
|
19
|
-
|
20
|
-
|
19
|
+
it "does not unify with non-array" do
|
20
|
+
cannot_unify [A,B], 12
|
21
|
+
end
|
21
22
|
|
22
|
-
|
23
|
-
|
24
|
-
|
23
|
+
it "unifies empty arrays" do
|
24
|
+
can_unify [], []
|
25
|
+
end
|
25
26
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
27
|
+
it "unifies empty array with splat" do
|
28
|
+
a = A
|
29
|
+
can_unify [], [*a] do
|
30
|
+
a.value.should == []
|
31
|
+
end
|
30
32
|
end
|
31
|
-
end
|
32
33
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
34
|
+
it "unifies two splats" do
|
35
|
+
a = A
|
36
|
+
b = B
|
37
|
+
can_unify [*a], [*b] do
|
38
|
+
a.value.should equal b
|
39
|
+
end
|
38
40
|
end
|
39
|
-
end
|
40
41
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
42
|
+
it "unifies two arrays with splats at the first element" do
|
43
|
+
a = A
|
44
|
+
b = B
|
45
|
+
can_unify [*a], [*b,5] do
|
46
|
+
a.value.should eql [*b,5]
|
47
|
+
end
|
46
48
|
end
|
47
|
-
end
|
48
49
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
50
|
+
it "unifies a splat with empty array" do
|
51
|
+
a = A
|
52
|
+
can_unify [*a], [] do
|
53
|
+
a.value.should eql []
|
54
|
+
end
|
53
55
|
end
|
54
|
-
end
|
55
56
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
57
|
+
it "unififes splats at first elements" do
|
58
|
+
A.is([1,2,3]).and([*A,4].is([*B,*ANY])).map{B}.should ==
|
59
|
+
[[],[1],[1,2],[1,2,3],[1,2,3,4]]
|
60
|
+
end
|
60
61
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
62
|
+
it "unififes first splat with first non-splat" do
|
63
|
+
A.is([1,2,3]).and([*A,4].is([X,*C])).map{[X,C]}.should ==
|
64
|
+
[[1,[2,3,4]]]
|
65
|
+
end
|
65
66
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
67
|
+
it "unififes first empty splat with first non-splat" do
|
68
|
+
A.is([]).and([*A,4].is([X,*C])).map{[X,C]}.should ==
|
69
|
+
[[4,[]]]
|
70
|
+
end
|
70
71
|
|
71
72
|
|
72
|
-
|
73
|
+
end
|
73
74
|
|
74
|
-
|
75
|
-
|
76
|
-
|
75
|
+
describe "#rubylog_deep_dereference" do
|
76
|
+
it "does keeps unbound splats" do
|
77
|
+
[*A].rubylog_deep_dereference.should eql [*A]
|
78
|
+
end
|
77
79
|
end
|
78
|
-
end
|
79
80
|
|
81
|
+
end
|
80
82
|
end
|
@@ -1,66 +1,68 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
module RubylogSpec
|
4
|
+
describe Rubylog::CompoundTerm, :rubylog=>true do
|
5
|
+
predicate_for Symbol, ".likes()"
|
5
6
|
|
6
|
-
|
7
|
+
describe "compilation" do
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
9
|
+
it "makes eql variables be equal" do
|
10
|
+
a = A; b = A
|
11
|
+
c = (a.likes b)
|
12
|
+
c[0].should be_equal a; c[1].should be_equal b
|
13
|
+
c[0].should_not be_equal c[1]
|
14
|
+
c = c.rubylog_match_variables
|
15
|
+
c[0].should be_equal c[1]
|
16
|
+
end
|
16
17
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
18
|
+
it "makes non-eql variables be non-equal" do
|
19
|
+
a = A; b = B
|
20
|
+
c = (a.likes b)
|
21
|
+
c[0].should be_equal a; c[1].should be_equal b
|
22
|
+
c[0].should_not be_equal c[1]
|
23
|
+
c = c.rubylog_match_variables
|
24
|
+
c[0].should_not be_equal c[1]
|
25
|
+
end
|
25
26
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
27
|
+
it "makes dont-care variables be non-equal" do
|
28
|
+
a = ANY; b = ANY
|
29
|
+
c = (a.likes b)
|
30
|
+
c[0].should be_equal a; c[1].should be_equal b
|
31
|
+
c[0].should_not be_equal c[1]
|
32
|
+
c = c.rubylog_match_variables
|
33
|
+
c[0].should_not be_equal c[1]
|
34
|
+
end
|
34
35
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
36
|
+
it "creates new variables" do
|
37
|
+
a = A; b = B
|
38
|
+
c = (a.likes b)
|
39
|
+
c[0].should be_equal a; c[1].should be_equal b
|
40
|
+
c = c.rubylog_match_variables
|
41
|
+
c[0].should_not be_equal a
|
42
|
+
c[1].should_not be_equal a
|
43
|
+
c[0].should_not be_equal b
|
44
|
+
c[1].should_not be_equal b
|
45
|
+
end
|
45
46
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
47
|
+
it "makes variables available" do
|
48
|
+
a = A; a1 = A; a2 = A; b = B; b1 = B; c = C;
|
49
|
+
(a.likes b).rubylog_match_variables.rubylog_variables.should == [a, b]
|
50
|
+
(a.likes a1).rubylog_match_variables.rubylog_variables.should == [a]
|
51
|
+
(a.likes a1.in b).rubylog_match_variables.rubylog_variables.should == [a, b]
|
52
|
+
(a.likes a1,b,b1,a2,c).rubylog_match_variables.rubylog_variables.should == [a, b, c]
|
53
|
+
end
|
53
54
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
55
|
+
it "does not make dont-care variables available" do
|
56
|
+
a = ANY; a1 = ANYTHING; a2 = ANYTHING; b = B; b1 = B; c = C;
|
57
|
+
(a.likes b).rubylog_match_variables.rubylog_variables.should == [b]
|
58
|
+
(a.likes a1).rubylog_match_variables.rubylog_variables.should == []
|
59
|
+
(a.likes a1.in b).rubylog_match_variables.
|
60
|
+
rubylog_variables.should == [b]
|
61
|
+
(a.likes a1,b,b1,a2,c).rubylog_match_variables.
|
62
|
+
rubylog_variables.should == [b, c]
|
63
|
+
end
|
63
64
|
|
64
65
|
|
66
|
+
end
|
65
67
|
end
|
66
68
|
end
|
@@ -1,59 +1,61 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
describe "using ruby code in clauses" do
|
9
|
-
it "works" do
|
10
|
-
(:true.and? {false}).should be_false
|
11
|
-
(:true.and? {true}).should be_true
|
12
|
-
(:fail.and? {false}).should be_false
|
13
|
-
(:fail.and? {true}).should be_false
|
14
|
-
(:true.or? {false}).should be_true
|
15
|
-
(:true.or? {true}).should be_true
|
16
|
-
(:fail.or? {false}).should be_false
|
17
|
-
(:fail.or? {true}).should be_true
|
18
|
-
|
19
|
-
(:fail.or? {false}).should be_false
|
20
|
-
(:fail.or? {true}).should be_true
|
21
|
-
end
|
22
|
-
it "runs the query once at every evaluation" do
|
23
|
-
count = 0
|
24
|
-
:john.is_happy.if :true.and { count += 1 }
|
25
|
-
count.should == 0
|
26
|
-
:john.is_happy?
|
27
|
-
count.should == 1
|
28
|
-
:john.is_happy?
|
29
|
-
count.should == 2
|
30
|
-
(:fail.or? {count+=1}).should be_true
|
31
|
-
count.should == 3
|
3
|
+
module RubylogSpec
|
4
|
+
describe Proc, :rubylog=>true do
|
5
|
+
before do
|
6
|
+
predicate_for Symbol, ".is_happy .likes()"
|
32
7
|
end
|
33
8
|
|
34
|
-
describe "
|
35
|
-
it "works
|
36
|
-
|
37
|
-
(
|
38
|
-
(:
|
39
|
-
|
9
|
+
describe "using ruby code in clauses" do
|
10
|
+
it "works" do
|
11
|
+
(:true.and? {false}).should be_false
|
12
|
+
(:true.and? {true}).should be_true
|
13
|
+
(:fail.and? {false}).should be_false
|
14
|
+
(:fail.and? {true}).should be_false
|
15
|
+
(:true.or? {false}).should be_true
|
16
|
+
(:true.or? {true}).should be_true
|
17
|
+
(:fail.or? {false}).should be_false
|
18
|
+
(:fail.or? {true}).should be_true
|
19
|
+
|
20
|
+
(:fail.or? {false}).should be_false
|
21
|
+
(:fail.or? {true}).should be_true
|
40
22
|
end
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
23
|
+
it "runs the query once at every evaluation" do
|
24
|
+
count = 0
|
25
|
+
:john.is_happy.if :true.and { count += 1 }
|
26
|
+
count.should == 0
|
27
|
+
:john.is_happy?
|
28
|
+
count.should == 1
|
29
|
+
:john.is_happy?
|
30
|
+
count.should == 2
|
31
|
+
(:fail.or? {count+=1}).should be_true
|
32
|
+
count.should == 3
|
47
33
|
end
|
48
34
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
35
|
+
describe "bindings" do
|
36
|
+
it "works for rule bodies" do
|
37
|
+
result = nil;
|
38
|
+
(A.likes(B).if {result = [A,B]})
|
39
|
+
(:john.likes(:beer)).solve{}
|
40
|
+
result.should == [:john,:beer]
|
41
|
+
end
|
42
|
+
|
43
|
+
it "works for rules" do
|
44
|
+
result = nil
|
45
|
+
(A.likes(B).if B.is(4).and A.is(2).and C.is(5).and {result = [A,B,C]})
|
46
|
+
(A.likes(B)).solve{}
|
47
|
+
result.should == [2,4,5]
|
48
|
+
end
|
54
49
|
|
50
|
+
it "works for inline terms" do
|
51
|
+
result = nil
|
52
|
+
(A.is(1).and B.is(2).and {result = [A,B]}).solve{}
|
53
|
+
result.should == [1,2]
|
54
|
+
end
|
55
55
|
|
56
56
|
|
57
|
+
|
58
|
+
end
|
57
59
|
end
|
58
60
|
end
|
59
61
|
end
|
@@ -1,48 +1,50 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
|
-
|
4
|
-
describe
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
3
|
+
module RubylogSpec
|
4
|
+
describe String, :rubylog=>true do
|
5
|
+
describe "unification" do
|
6
|
+
check "asdf".is "asdf"
|
7
|
+
check { "abc#{S}def" =~ /abc.S\[\].def/ }
|
8
|
+
check { "abc#{S[length: 1]}def" =~ /abc.S\[\d+\].def/ }
|
9
|
+
check { "h#{S}o".is("hello").map{S} == ["ell"] }
|
10
|
+
check { "#{Base}.#{Ext}".is("hello.rb").map{Base} == ["hello"] }
|
11
|
+
check { "#{Base}.#{Ext}".is("hello.rb").map{Ext} == ["rb"] }
|
12
|
+
check { "h#{S}o".is("auto").map{S} == [] }
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "backtracked matches" do
|
16
|
+
check { "abc".is("#{A}#{B}").map{"#{A}:#{B}"} == [":abc","a:bc","ab:c","abc:"] }
|
17
|
+
check { "www.google.com".is("#{A}.#{B}").map{[A,B]} == [["www", "google.com"],["www.google", "com"]] }
|
18
|
+
check { "a".is("#{A}#{B}#{C}").map{"#{A}:#{B}:#{C}"} == ["::a",":a:","a::"] }
|
19
|
+
check { "ab".is("#{A}#{B}#{C}").map{"#{A}:#{B}:#{C}"} == %w(::ab :a:b :ab: a::b a:b: ab::) }
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "guards" do
|
23
|
+
check { "abc".is("#{A[/\A.\z/]}#{B}").map{"#{A}:#{B}"} == ["a:bc"] }
|
24
|
+
check { "abc".is("#{A[length: 1]}#{B}").map{"#{A}:#{B}"} == ["a:bc"] }
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
describe "palindromes" do
|
29
|
+
predicate_for String, ".palindrome"
|
30
|
+
|
31
|
+
S[empty?: true].palindrome!
|
32
|
+
S[length: 1].palindrome!
|
33
|
+
S[lambda{|s|s.length > 1}].palindrome.if S.is("#{A[length: 1]}#{B}#{A}").and B.palindrome
|
34
|
+
|
35
|
+
check "".palindrome
|
36
|
+
check "dd".palindrome
|
37
|
+
check "aba".palindrome
|
38
|
+
check "faaf".palindrome
|
39
|
+
check "ffaaff".palindrome
|
40
|
+
check "rererer".palindrome
|
41
|
+
check "lol".palindrome
|
42
|
+
check "ji".palindrome.false
|
43
|
+
check "doo".palindrome.false
|
44
|
+
check "taaaz".palindrome.false
|
45
|
+
check "faad".palindrome.false
|
46
|
+
check "rerere".palindrome.false
|
47
|
+
end
|
20
48
|
|
21
|
-
describe "guards" do
|
22
|
-
check { "abc".is("#{A[/\A.\z/]}#{B}").map{"#{A}:#{B}"} == ["a:bc"] }
|
23
|
-
check { "abc".is("#{A[length: 1]}#{B}").map{"#{A}:#{B}"} == ["a:bc"] }
|
24
49
|
end
|
25
|
-
|
26
|
-
|
27
|
-
describe "palindromes" do
|
28
|
-
predicate_for String, ".palindrome"
|
29
|
-
|
30
|
-
S[empty?: true].palindrome!
|
31
|
-
S[length: 1].palindrome!
|
32
|
-
S[lambda{|s|s.length > 1}].palindrome.if S.is("#{A[length: 1]}#{B}#{A}").and B.palindrome
|
33
|
-
|
34
|
-
check "".palindrome
|
35
|
-
check "dd".palindrome
|
36
|
-
check "aba".palindrome
|
37
|
-
check "faaf".palindrome
|
38
|
-
check "ffaaff".palindrome
|
39
|
-
check "rererer".palindrome
|
40
|
-
check "lol".palindrome
|
41
|
-
check "ji".palindrome.false
|
42
|
-
check "doo".palindrome.false
|
43
|
-
check "taaaz".palindrome.false
|
44
|
-
check "faad".palindrome.false
|
45
|
-
check "rerere".palindrome.false
|
46
|
-
end
|
47
|
-
|
48
50
|
end
|