rubylog 1.0.0 → 2.0pre1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +3 -12
- data/Gemfile.lock +22 -48
- data/README.rdoc +38 -38
- data/README.rdoc.orig +284 -0
- data/RELEASE_NOTES.rdoc +51 -0
- data/Rakefile +14 -18
- data/TODO.txt +0 -0
- data/VERSION +1 -1
- data/examples/a_plus_b.rb +6 -0
- data/examples/checkmate.rb +88 -0
- data/examples/combination.rb +17 -0
- data/examples/dcg.rb +3 -2
- data/examples/dcg2.rb +2 -2
- data/{logic → examples}/directory_structure_logic.rb +3 -5
- data/examples/dirlist.rb +4 -0
- data/examples/divisors.rb +6 -0
- data/examples/enumerators.rb +3 -3
- data/examples/factorial.rb +2 -3
- data/examples/file_search.rb +14 -0
- data/examples/hanoi.rb +4 -5
- data/examples/hello.rb +6 -4
- data/examples/mice.rb +92 -0
- data/examples/mice2.rb +19 -0
- data/examples/n_queens.rb +32 -0
- data/examples/object_oriented.rb +14 -0
- data/examples/palindrome_detection.rb +18 -0
- data/examples/parsing.rb +6 -4
- data/examples/permutation.rb +12 -0
- data/examples/prefix.rb +13 -0
- data/examples/primality_by_division.rb +22 -0
- data/examples/primitives.rb +10 -8
- data/examples/sieve_of_eratosthenes.rb +14 -0
- data/examples/string_interpolation.rb +4 -0
- data/examples/sudoku.rb +52 -0
- data/examples/tracing.rb +19 -0
- data/lib/rspec/rubylog.rb +29 -0
- data/lib/rubylog/assertable.rb +24 -0
- data/lib/rubylog/builtins/arithmetics.rb +63 -0
- data/lib/rubylog/builtins/assumption.rb +71 -0
- data/lib/rubylog/builtins/ensure.rb +13 -0
- data/lib/rubylog/builtins/file_system.rb +30 -8
- data/lib/rubylog/builtins/logic.rb +69 -38
- data/lib/rubylog/builtins/reflection.rb +35 -50
- data/lib/rubylog/builtins/term.rb +15 -17
- data/lib/rubylog/builtins.rb +11 -0
- data/lib/rubylog/clause.rb +19 -0
- data/lib/rubylog/{interfaces/composite_term.rb → compound_term.rb} +3 -3
- data/lib/rubylog/context.rb +24 -0
- data/lib/rubylog/context_creation.rb +71 -0
- data/lib/rubylog/context_modules/checks.rb +35 -0
- data/lib/rubylog/context_modules/demonstration.rb +16 -0
- data/lib/rubylog/context_modules/predicates.rb +86 -0
- data/lib/rubylog/context_modules/primitives.rb +18 -0
- data/lib/rubylog/context_modules/thats.rb +13 -0
- data/lib/rubylog/default_context.rb +9 -0
- data/lib/rubylog/dsl/array_splat.rb +11 -3
- data/lib/rubylog/dsl/primitives.rb +24 -12
- data/lib/rubylog/dsl/thats.rb +6 -0
- data/lib/rubylog/dsl/variables.rb +56 -21
- data/lib/rubylog/errors.rb +26 -15
- data/lib/rubylog/mixins/array.rb +95 -62
- data/lib/rubylog/mixins/kernel.rb +3 -2
- data/lib/rubylog/mixins/method.rb +0 -1
- data/lib/rubylog/mixins/object.rb +2 -1
- data/lib/rubylog/mixins/proc.rb +9 -12
- data/lib/rubylog/mixins/string.rb +15 -23
- data/lib/rubylog/mixins/symbol.rb +7 -24
- data/lib/rubylog/nullary_predicates.rb +3 -0
- data/lib/rubylog/predicate.rb +53 -0
- data/lib/rubylog/primitive.rb +15 -0
- data/lib/rubylog/procedure.rb +42 -0
- data/lib/rubylog/rule.rb +24 -0
- data/lib/rubylog/structure.rb +19 -38
- data/lib/rubylog/{interfaces/term.rb → term.rb} +2 -7
- data/lib/rubylog/tracing.rb +75 -0
- data/lib/rubylog/variable.rb +31 -12
- data/lib/rubylog.rb +36 -32
- data/rubylog.gemspec +92 -84
- data/spec/inriasuite_spec.rb +906 -9
- data/spec/integration/custom_classes_spec.rb +61 -0
- data/spec/integration/dsl_spec.rb +38 -0
- data/spec/integration/recursion_spec.rb +14 -0
- data/spec/integration/theory_as_module_spec.rb +20 -0
- data/spec/integration/theory_as_module_with_include_spec.rb +14 -0
- data/spec/rspec/rubylog_spec.rb +75 -0
- data/spec/rubylog/assertable_spec.rb +111 -0
- data/spec/rubylog/builtins/arithmetics_spec.rb +94 -0
- data/spec/rubylog/builtins/assumption_spec.rb +70 -0
- data/spec/rubylog/builtins/ensure_spec.rb +8 -0
- data/spec/rubylog/builtins/file_system_spec.rb +40 -0
- data/spec/rubylog/builtins/logic_spec.rb +340 -0
- data/spec/rubylog/builtins/reflection_spec.rb +43 -0
- data/spec/rubylog/builtins/term_spec.rb +85 -0
- data/spec/rubylog/context_modules/demonstration_spec.rb +132 -0
- data/spec/rubylog/context_modules/predicates_spec.rb +57 -0
- data/spec/rubylog/context_modules/thats_spec.rb +94 -0
- data/spec/rubylog/dsl/array_splat_spec.rb +15 -0
- data/spec/rubylog/dsl/primitives_spec.rb +43 -0
- data/spec/rubylog/errors_spec.rb +18 -0
- data/spec/{unification_spec.rb → rubylog/interfaces/term_spec.rb} +8 -9
- data/spec/rubylog/mixins/array_spec.rb +80 -0
- data/spec/rubylog/mixins/composite_term_spec.rb +66 -0
- data/spec/rubylog/mixins/proc_spec.rb +59 -0
- data/spec/rubylog/mixins/string_spec.rb +48 -0
- data/spec/rubylog/mixins/symbol_spec.rb +9 -0
- data/spec/{clause_spec.rb → rubylog/structure_spec.rb} +16 -15
- data/spec/rubylog/term_spec.rb +7 -0
- data/spec/rubylog/tracing_spec.input +27 -0
- data/spec/rubylog/tracing_spec.rb +44 -0
- data/spec/rubylog/variable_spec.rb +279 -0
- data/spec/spec_helper.rb +1 -0
- data/vimrc +11 -0
- metadata +103 -123
- data/README.hu.rb +0 -58
- data/bin/rubylog +0 -18
- data/examples/theory.rb +0 -32
- data/lib/rubylog/builtins/default.rb +0 -10
- data/lib/rubylog/dsl.rb +0 -70
- data/lib/rubylog/interfaces/assertable.rb +0 -16
- data/lib/rubylog/interfaces/callable.rb +0 -18
- data/lib/rubylog/interfaces/predicate.rb +0 -8
- data/lib/rubylog/interfaces/procedure.rb +0 -60
- data/lib/rubylog/mixins/class.rb +0 -11
- data/lib/rubylog/simple_procedure.rb +0 -8
- data/lib/rubylog/theory.rb +0 -422
- data/logic/builtins/file_system_logic.rb +0 -23
- data/logic/builtins/reflection_logic.rb +0 -40
- data/logic/dereference_logic.rb +0 -23
- data/logic/dsl_logic.rb +0 -29
- data/logic/errors_logic.rb +0 -9
- data/logic/guard_logic.rb +0 -115
- data/logic/list_logic.rb +0 -55
- data/logic/map_logic.rb +0 -15
- data/logic/multitheory.rb +0 -23
- data/logic/recursion_logic.rb +0 -12
- data/logic/string_logic.rb +0 -41
- data/logic/thats_logic.rb +0 -51
- data/logic/variable_logic.rb +0 -24
- data/spec/bartak_guide_spec.rb +0 -86
- data/spec/builtins/all_spec.rb +0 -99
- data/spec/builtins/and_spec.rb +0 -22
- data/spec/builtins/array_spec.rb +0 -16
- data/spec/builtins/branch_or_spec.rb +0 -27
- data/spec/builtins/cut_spec.rb +0 -44
- data/spec/builtins/fail_spec.rb +0 -5
- data/spec/builtins/false_spec.rb +0 -5
- data/spec/builtins/in_spec.rb +0 -38
- data/spec/builtins/is_false_spec.rb +0 -12
- data/spec/builtins/is_spec.rb +0 -26
- data/spec/builtins/matches_spec.rb +0 -23
- data/spec/builtins/or_spec.rb +0 -22
- data/spec/builtins/splits_to.rb +0 -18
- data/spec/builtins/then_spec.rb +0 -27
- data/spec/builtins/true_spec.rb +0 -5
- data/spec/compilation_spec.rb +0 -61
- data/spec/custom_classes_spec.rb +0 -43
- data/spec/dereference.rb +0 -10
- data/spec/queries_spec.rb +0 -150
- data/spec/recursion_spec.rb +0 -18
- data/spec/ruby_code_spec.rb +0 -52
- data/spec/rules_spec.rb +0 -97
- data/spec/theory_spec.rb +0 -29
- data/spec/variable_spec.rb +0 -26
@@ -0,0 +1,94 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "rubylog/builtins/file_system"
|
3
|
+
|
4
|
+
describe "thats", :rubylog=>true do
|
5
|
+
describe "one level" do
|
6
|
+
check 4.is(ANY[Integer,thats < 10])
|
7
|
+
check 4.is(ANY[Integer,thats < 5])
|
8
|
+
check 4.is(ANY[Integer,thats < 4]).false
|
9
|
+
check 4.is(ANY[Integer,thats < 2]).false
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "question mark" do
|
13
|
+
check "".is(ANY[thats.empty?])
|
14
|
+
check "a".is(ANY[thats.empty?]).false
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "two levels" do
|
18
|
+
check "hello".is(ANYTHING[thats.reverse == "olleh"])
|
19
|
+
check "hello".is(ANYTHING[thats.reverse == "olle"]).false
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "four levels" do
|
23
|
+
check "hello".is(ANY[thats.upcase.partition("E")[0] == "H"])
|
24
|
+
check "hello".is(ANY[thats.upcase.partition("E")[1] == "E"])
|
25
|
+
check "hello".is(ANY[thats.upcase.partition("E")[2] == "LLO"])
|
26
|
+
check "hello".is(ANY[thats.upcase.partition("E")[1] == "H"]).false
|
27
|
+
check "hello".is(ANY[thats.upcase.partition("E")[0] == "h"]).false
|
28
|
+
check "hello".is(ANY[thats.upcase.partition("L")[0] == "H"]).false
|
29
|
+
check "hello".is(ANY[thats.upcase.partition("e")[0] == "H"]).false
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "files" do
|
33
|
+
check { "#{S[String, thats.start_with?(".")]}".filename_in(".").map{S}.include? ".gitignore" }
|
34
|
+
check { not "#{S[String, thats.start_with?(".")]}". dirname_in(".").map{S}.include? "lib" }
|
35
|
+
check { "#{S[/\A(.*)\.rb/]}".filename_in("lib").map{S} == ["rubylog.rb"] }
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "factorial" do
|
39
|
+
predicate_for Integer, ".factorial()"
|
40
|
+
0.factorial! 1
|
41
|
+
K[thats > 0].factorial(N).if K0.is{K-1}.and K0.factorial(N0).and N.is{N0*K}
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "palindrome" do
|
45
|
+
predicate_for String, ".palindrome"
|
46
|
+
S[String, thats.length <= 1].palindrome!
|
47
|
+
"#{A[thats.length == 1]}#{B}#{A}".palindrome.if B.palindrome
|
48
|
+
|
49
|
+
check "a".palindrome
|
50
|
+
check "aa".palindrome
|
51
|
+
check "aga".palindrome
|
52
|
+
check "aaa".palindrome
|
53
|
+
check "avava".palindrome
|
54
|
+
check "ab".palindrome.false
|
55
|
+
check "abb".palindrome.false
|
56
|
+
check "abab".palindrome.false
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
describe "thats_not", :rubylog=>true do
|
62
|
+
describe "one level" do
|
63
|
+
check 4.is(ANY[Integer,thats_not < 10]).false
|
64
|
+
check 4.is(ANY[Integer,thats_not < 5]).false
|
65
|
+
check 4.is(ANY[Integer,thats_not < 4])
|
66
|
+
check 4.is(ANY[Integer,thats_not < 2])
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "question mark" do
|
70
|
+
check "".is(ANY[thats_not.empty?]).false
|
71
|
+
check "a".is(ANY[thats_not.empty?])
|
72
|
+
end
|
73
|
+
|
74
|
+
describe "two levels" do
|
75
|
+
check "hello".is(ANYTHING[thats_not.reverse == "olleh"]).false
|
76
|
+
check "hello".is(ANYTHING[thats_not.reverse == "olle"])
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "four levels" do
|
80
|
+
check "hello".is(ANY[thats_not.upcase.partition("E")[0] == "H"]).false
|
81
|
+
check "hello".is(ANY[thats_not.upcase.partition("E")[1] == "E"]).false
|
82
|
+
check "hello".is(ANY[thats_not.upcase.partition("E")[2] == "LLO"]).false
|
83
|
+
check "hello".is(ANY[thats_not.upcase.partition("E")[1] == "H"])
|
84
|
+
check "hello".is(ANY[thats_not.upcase.partition("E")[0] == "h"])
|
85
|
+
check "hello".is(ANY[thats_not.upcase.partition("L")[0] == "H"])
|
86
|
+
check "hello".is(ANY[thats_not.upcase.partition("e")[0] == "H"])
|
87
|
+
end
|
88
|
+
|
89
|
+
describe "files" do
|
90
|
+
check { not "#{S[String, thats_not.start_with?(".")]}".filename_in(".").map{S}.include? ".gitignore" }
|
91
|
+
check { "#{S[String, thats_not.start_with?(".")]}". dirname_in(".").map{S}.include? "lib" }
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Rubylog::DSL::ArraySplat, :rubylog=>true do
|
4
|
+
describe "#inspect" do
|
5
|
+
[*A].inspect.should == "[*A]"
|
6
|
+
end
|
7
|
+
|
8
|
+
specify "#==" do
|
9
|
+
[*A].should == [*A]
|
10
|
+
end
|
11
|
+
|
12
|
+
specify "#eql?" do
|
13
|
+
[*A].should eql [*A]
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Rubylog::DSL::Primitives, :rubylog=>true do
|
4
|
+
describe "#primitives" do
|
5
|
+
before do
|
6
|
+
String.instance_methods.should_not include :looong
|
7
|
+
end
|
8
|
+
|
9
|
+
it "defines functors on default subject" do
|
10
|
+
self.default_subject = String
|
11
|
+
class << primitives
|
12
|
+
def looong s
|
13
|
+
end
|
14
|
+
end
|
15
|
+
String.instance_methods.should include :looong
|
16
|
+
String.instance_methods.should include :looong!
|
17
|
+
String.instance_methods.should include :looong?
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "#primitives_for" do
|
22
|
+
before do
|
23
|
+
Integer.instance_methods.should_not include :large
|
24
|
+
end
|
25
|
+
|
26
|
+
it "defines functors on the given subject" do
|
27
|
+
class << primitives_for(Integer)
|
28
|
+
def large s
|
29
|
+
end
|
30
|
+
end
|
31
|
+
Integer.instance_methods.should include :large
|
32
|
+
Integer.instance_methods.should include :large!
|
33
|
+
Integer.instance_methods.should include :large?
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "Primitives#inspect" do
|
38
|
+
specify do
|
39
|
+
primitives_for(Integer).inspect.should =~ /\Aprimitives_for\(.*\)\z/
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Rubylog errors", :rubylog=>true do
|
4
|
+
|
5
|
+
describe "syntax error" do
|
6
|
+
predicate_for String, ".happy"
|
7
|
+
|
8
|
+
specify { proc{ "John".happy.if }.should raise_error Rubylog::SyntaxError }
|
9
|
+
specify { proc{ "John".happy.if! }.should raise_error Rubylog::SyntaxError }
|
10
|
+
specify { proc{ "John".happy.unless }.should raise_error Rubylog::SyntaxError }
|
11
|
+
end
|
12
|
+
|
13
|
+
describe Rubylog::InstantiationError do
|
14
|
+
specify { proc { A.true? }.should raise_error(Rubylog::InstantiationError, "Instantiation error in A") }
|
15
|
+
specify { proc { A.sum_of(B,1).true? }.should raise_error(Rubylog::InstantiationError, "Instantiation error in A.sum_of(B, 1)") }
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -1,9 +1,8 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "unification", :rubylog=>true do
|
4
|
+
predicate_for Symbol, ".likes"
|
5
5
|
|
6
|
-
describe "unification" do
|
7
6
|
it "works for variables" do
|
8
7
|
result = false
|
9
8
|
A.rubylog_unify(12) { result = true }
|
@@ -62,16 +61,16 @@ describe "unification" do
|
|
62
61
|
|
63
62
|
it "works on clauses with repeated variables #1" do
|
64
63
|
result = false
|
65
|
-
(A.likes A).
|
64
|
+
(A.likes A).rubylog_match_variables.rubylog_unify(:john.likes :jane) { result = true }
|
66
65
|
result.should == false
|
67
|
-
(A.likes A).
|
66
|
+
(A.likes A).rubylog_match_variables.rubylog_unify(:john.likes :john) { result = true }
|
68
67
|
result.should == true
|
69
68
|
end
|
70
69
|
it "works on clauses with repeated variables #1" do
|
71
70
|
result = false
|
72
|
-
(:john.likes :jane).rubylog_unify(A.likes(A).
|
71
|
+
(:john.likes :jane).rubylog_unify(A.likes(A).rubylog_match_variables) { result = true }
|
73
72
|
result.should == false
|
74
|
-
(:john.likes :john).rubylog_unify(A.likes(A).
|
73
|
+
(:john.likes :john).rubylog_unify(A.likes(A).rubylog_match_variables) { result = true }
|
75
74
|
result.should == true
|
76
75
|
end
|
77
76
|
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Array, :rubylog=>true do
|
4
|
+
|
5
|
+
describe "unification" do
|
6
|
+
def can_unify a, b
|
7
|
+
result = false
|
8
|
+
a.rubylog_unify(b) { result = true; yield if block_given? }
|
9
|
+
result.should == true
|
10
|
+
end
|
11
|
+
|
12
|
+
def cannot_unify a, b
|
13
|
+
result = false
|
14
|
+
a.rubylog_unify(b) { result = true }
|
15
|
+
result.should == false
|
16
|
+
end
|
17
|
+
|
18
|
+
it "does not unify with non-array" do
|
19
|
+
cannot_unify [A,B], 12
|
20
|
+
end
|
21
|
+
|
22
|
+
it "unifies empty arrays" do
|
23
|
+
can_unify [], []
|
24
|
+
end
|
25
|
+
|
26
|
+
it "unifies empty array with splat" do
|
27
|
+
a = A
|
28
|
+
can_unify [], [*a] do
|
29
|
+
a.value.should == []
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
it "unifies two splats" do
|
34
|
+
a = A
|
35
|
+
b = B
|
36
|
+
can_unify [*a], [*b] do
|
37
|
+
b.value.should equal a
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
it "unifies two arrays with splats at the first element" do
|
42
|
+
a = A
|
43
|
+
b = B
|
44
|
+
can_unify [*a], [*b,5] do
|
45
|
+
a.value.should eql [*b,5]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
it "unifies a splat with empty array" do
|
50
|
+
a = A
|
51
|
+
can_unify [*a], [] do
|
52
|
+
a.value.should eql []
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
it "unififes splats at first elements" do
|
57
|
+
A.is([1,2,3]).and([*A,4].is([*B,*ANY])).map{B}.should ==
|
58
|
+
[[],[1],[1,2],[1,2,3],[1,2,3,4]]
|
59
|
+
end
|
60
|
+
|
61
|
+
it "unififes first splat with first non-splat" do
|
62
|
+
A.is([1,2,3]).and([*A,4].is([X,*C])).map{[X,C]}.should ==
|
63
|
+
[[1,[2,3,4]]]
|
64
|
+
end
|
65
|
+
|
66
|
+
it "unififes first empty splat with first non-splat" do
|
67
|
+
A.is([]).and([*A,4].is([X,*C])).map{[X,C]}.should ==
|
68
|
+
[[4,[]]]
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
describe "#rubylog_deep_dereference" do
|
75
|
+
it "does keeps unbound splats" do
|
76
|
+
[*A].rubylog_deep_dereference.should eql [*A]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Rubylog::CompoundTerm, :rubylog=>true do
|
4
|
+
predicate_for Symbol, ".likes()"
|
5
|
+
|
6
|
+
describe "compilation" do
|
7
|
+
|
8
|
+
it "makes eql variables be equal" do
|
9
|
+
a = A; b = A
|
10
|
+
c = (a.likes b)
|
11
|
+
c[0].should be_equal a; c[1].should be_equal b
|
12
|
+
c[0].should_not be_equal c[1]
|
13
|
+
c = c.rubylog_match_variables
|
14
|
+
c[0].should be_equal c[1]
|
15
|
+
end
|
16
|
+
|
17
|
+
it "makes non-eql variables be non-equal" do
|
18
|
+
a = A; b = B
|
19
|
+
c = (a.likes b)
|
20
|
+
c[0].should be_equal a; c[1].should be_equal b
|
21
|
+
c[0].should_not be_equal c[1]
|
22
|
+
c = c.rubylog_match_variables
|
23
|
+
c[0].should_not be_equal c[1]
|
24
|
+
end
|
25
|
+
|
26
|
+
it "makes dont-care variables be non-equal" do
|
27
|
+
a = ANY; b = ANY
|
28
|
+
c = (a.likes b)
|
29
|
+
c[0].should be_equal a; c[1].should be_equal b
|
30
|
+
c[0].should_not be_equal c[1]
|
31
|
+
c = c.rubylog_match_variables
|
32
|
+
c[0].should_not be_equal c[1]
|
33
|
+
end
|
34
|
+
|
35
|
+
it "creates new variables" do
|
36
|
+
a = A; b = B
|
37
|
+
c = (a.likes b)
|
38
|
+
c[0].should be_equal a; c[1].should be_equal b
|
39
|
+
c = c.rubylog_match_variables
|
40
|
+
c[0].should_not be_equal a
|
41
|
+
c[1].should_not be_equal a
|
42
|
+
c[0].should_not be_equal b
|
43
|
+
c[1].should_not be_equal b
|
44
|
+
end
|
45
|
+
|
46
|
+
it "makes variables available" do
|
47
|
+
a = A; a1 = A; a2 = A; b = B; b1 = B; c = C;
|
48
|
+
(a.likes b).rubylog_match_variables.rubylog_variables.should == [a, b]
|
49
|
+
(a.likes a1).rubylog_match_variables.rubylog_variables.should == [a]
|
50
|
+
(a.likes a1.in b).rubylog_match_variables.rubylog_variables.should == [a, b]
|
51
|
+
(a.likes a1,b,b1,a2,c).rubylog_match_variables.rubylog_variables.should == [a, b, c]
|
52
|
+
end
|
53
|
+
|
54
|
+
it "does not make dont-care variables available" do
|
55
|
+
a = ANY; a1 = ANYTHING; a2 = ANYTHING; b = B; b1 = B; c = C;
|
56
|
+
(a.likes b).rubylog_match_variables.rubylog_variables.should == [b]
|
57
|
+
(a.likes a1).rubylog_match_variables.rubylog_variables.should == []
|
58
|
+
(a.likes a1.in b).rubylog_match_variables.
|
59
|
+
rubylog_variables.should == [b]
|
60
|
+
(a.likes a1,b,b1,a2,c).rubylog_match_variables.
|
61
|
+
rubylog_variables.should == [b, c]
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Proc, :rubylog=>true do
|
4
|
+
before do
|
5
|
+
predicate_for Symbol, ".is_happy .likes()"
|
6
|
+
end
|
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
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "bindings" do
|
35
|
+
it "works for rule bodies" do
|
36
|
+
result = nil;
|
37
|
+
(A.likes(B).if {result = [A,B]})
|
38
|
+
(:john.likes(:beer)).solve{}
|
39
|
+
result.should == [:john,:beer]
|
40
|
+
end
|
41
|
+
|
42
|
+
it "works for rules" do
|
43
|
+
result = nil
|
44
|
+
(A.likes(B).if B.is(4).and A.is(2).and C.is(5).and {result = [A,B,C]})
|
45
|
+
(A.likes(B)).solve{}
|
46
|
+
result.should == [2,4,5]
|
47
|
+
end
|
48
|
+
|
49
|
+
it "works for inline terms" do
|
50
|
+
result = nil
|
51
|
+
(A.is(1).and B.is(2).and {result = [A,B]}).solve{}
|
52
|
+
result.should == [1,2]
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe String, :rubylog=>true do
|
4
|
+
describe "unification" do
|
5
|
+
check "asdf".is "asdf"
|
6
|
+
check { "abc#{S}def" =~ /abc.S\[\].def/ }
|
7
|
+
check { "abc#{S[length: 1]}def" =~ /abc.S\[\d+\].def/ }
|
8
|
+
check { "h#{S}o".is("hello").map{S} == ["ell"] }
|
9
|
+
check { "#{Base}.#{Ext}".is("hello.rb").map{Base} == ["hello"] }
|
10
|
+
check { "#{Base}.#{Ext}".is("hello.rb").map{Ext} == ["rb"] }
|
11
|
+
check { "h#{S}o".is("auto").map{S} == [] }
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "backtracked matches" do
|
15
|
+
check { "abc".is("#{A}#{B}").map{"#{A}:#{B}"} == [":abc","a:bc","ab:c","abc:"] }
|
16
|
+
check { "www.google.com".is("#{A}.#{B}").map{[A,B]} == [["www", "google.com"],["www.google", "com"]] }
|
17
|
+
check { "a".is("#{A}#{B}#{C}").map{"#{A}:#{B}:#{C}"} == ["::a",":a:","a::"] }
|
18
|
+
check { "ab".is("#{A}#{B}#{C}").map{"#{A}:#{B}:#{C}"} == %w(::ab :a:b :ab: a::b a:b: ab::) }
|
19
|
+
end
|
20
|
+
|
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
|
+
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
|
+
end
|
@@ -1,9 +1,9 @@
|
|
1
|
-
require '
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
describe Rubylog::Structure, :rubylog=>true do
|
4
|
+
|
5
|
+
predicate_for Symbol, ".is_happy .likes()"
|
5
6
|
|
6
|
-
describe "clauses" do
|
7
7
|
it "can be created" do
|
8
8
|
(:john.is_happy).should be_kind_of Rubylog::Term
|
9
9
|
(:john.likes :beer).should be_kind_of Rubylog::Term
|
@@ -11,19 +11,16 @@ describe "clauses" do
|
|
11
11
|
(:john.likes Drink).should be_kind_of Rubylog::Term
|
12
12
|
(:john.likes :drinking.in :bar).should be_kind_of Rubylog::Term
|
13
13
|
end
|
14
|
+
|
14
15
|
it "forbids non-declared names" do
|
15
16
|
lambda { :john.something_else }.should raise_error(NoMethodError)
|
16
17
|
end
|
17
|
-
|
18
|
-
(:is_happy%1).should be_kind_of Rubylog::Term
|
19
|
-
(A%B).should be_kind_of Rubylog::Term
|
20
|
-
end
|
18
|
+
|
21
19
|
it "can be asked for their functor" do
|
22
20
|
(:john.is_happy).functor.should == :is_happy
|
23
|
-
(:is_happy%1).functor.should == :%
|
24
|
-
(A%1).functor.should == :%
|
25
21
|
(:john.likes :drinking.in :bar).functor.should == :likes
|
26
22
|
end
|
23
|
+
|
27
24
|
it "can be indexed" do
|
28
25
|
(:john.is_happy)[0].should == :john
|
29
26
|
(:john.likes :beer)[0].should == :john
|
@@ -32,6 +29,7 @@ describe "clauses" do
|
|
32
29
|
(:john.likes(:cold, :beer))[1..2].should == [:cold,:beer]
|
33
30
|
(:john.likes :drinking.in :bar)[1].should == (:drinking.in :bar)
|
34
31
|
end
|
32
|
+
|
35
33
|
it "can be asked for their args" do
|
36
34
|
(:john.is_happy).args.should == [:john]
|
37
35
|
(:john.likes :beer).args.should == [:john, :beer]
|
@@ -72,11 +70,14 @@ describe "clauses" do
|
|
72
70
|
(:john.likes :drinking,:beer).arity.should == 3
|
73
71
|
(:john.likes :drinking.in :bar).arity.should == 2
|
74
72
|
end
|
75
|
-
|
76
|
-
|
77
|
-
(:john.
|
78
|
-
(:john.likes :
|
79
|
-
(:john.likes :drinking
|
73
|
+
|
74
|
+
it "can tell their indicator" do
|
75
|
+
(:john.is_happy).indicator.should == [:is_happy,1]
|
76
|
+
(:john.likes :beer).indicator.should == [:likes,2]
|
77
|
+
(:john.likes :drinking,:beer).indicator.should == [:likes,3]
|
78
|
+
(:john.likes :drinking.in :bar).indicator.should == [:likes,2]
|
80
79
|
end
|
80
|
+
|
81
|
+
|
81
82
|
end
|
82
83
|
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Rubylog::Tracing, :rubylog=>true do
|
4
|
+
before do
|
5
|
+
@old_argv = ARGV.dup
|
6
|
+
ARGV.replace ["spec/rubylog/tracing_spec.input"]
|
7
|
+
@old_stdout = $stdout
|
8
|
+
$stdout = @output = StringIO.new
|
9
|
+
end
|
10
|
+
|
11
|
+
after do
|
12
|
+
Rubylog.trace?.should == false
|
13
|
+
$stdout = @old_stdout
|
14
|
+
ARGV.replace @old_argv
|
15
|
+
end
|
16
|
+
|
17
|
+
it "can be called with true/false" do
|
18
|
+
Rubylog.trace true
|
19
|
+
1.is(A).solve
|
20
|
+
Rubylog.trace false
|
21
|
+
@output.string.should include "1.is(A).prove()"
|
22
|
+
end
|
23
|
+
|
24
|
+
it "can be called without true" do
|
25
|
+
Rubylog.trace
|
26
|
+
1.is(A).solve
|
27
|
+
Rubylog.trace false
|
28
|
+
@output.string.should include "1.is(A).prove()"
|
29
|
+
end
|
30
|
+
|
31
|
+
it "can be called with a block" do
|
32
|
+
Rubylog.trace do
|
33
|
+
1.is(A).solve
|
34
|
+
end
|
35
|
+
@output.string.should include "1.is(A).prove()"
|
36
|
+
end
|
37
|
+
|
38
|
+
it "traces unifications" do
|
39
|
+
Rubylog.trace do
|
40
|
+
1.is(A).solve
|
41
|
+
end
|
42
|
+
@output.string.should include "A.bind_to(1)"
|
43
|
+
end
|
44
|
+
end
|