rubylog 1.0.0 → 2.0pre1
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 +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
|