rubylog 0.0.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -1
- data/README.hu.rb +58 -0
- data/README.rdoc +248 -89
- data/Rakefile +6 -1
- data/VERSION +1 -1
- data/bin/rubylog +18 -0
- data/examples/dcg.rb +35 -0
- data/examples/dcg2.rb +42 -0
- data/examples/enumerators.rb +30 -0
- data/examples/factorial.rb +9 -8
- data/examples/hanoi.rb +24 -0
- data/examples/hello.rb +11 -5
- data/examples/parsing.rb +27 -0
- data/examples/primitives.rb +24 -0
- data/examples/theory.rb +22 -10
- data/lib/rubylog/builtins/default.rb +10 -0
- data/lib/rubylog/builtins/file_system.rb +15 -0
- data/lib/rubylog/builtins/logic.rb +109 -0
- data/lib/rubylog/builtins/reflection.rb +94 -0
- data/lib/rubylog/builtins/term.rb +47 -0
- data/lib/rubylog/dsl/array_splat.rb +25 -0
- data/lib/rubylog/dsl/primitives.rb +17 -0
- data/lib/rubylog/dsl/thats.rb +22 -0
- data/lib/rubylog/dsl/variables.rb +30 -0
- data/lib/rubylog/dsl.rb +35 -17
- data/lib/rubylog/errors.rb +19 -1
- data/lib/rubylog/interfaces/assertable.rb +16 -0
- data/lib/rubylog/interfaces/callable.rb +18 -0
- data/lib/rubylog/interfaces/composite_term.rb +47 -0
- data/lib/rubylog/interfaces/predicate.rb +8 -0
- data/lib/rubylog/interfaces/procedure.rb +60 -0
- data/lib/rubylog/interfaces/term.rb +41 -0
- data/lib/rubylog/mixins/array.rb +118 -0
- data/lib/{class.rb → rubylog/mixins/class.rb} +2 -2
- data/lib/rubylog/mixins/hash.rb +8 -0
- data/lib/rubylog/mixins/kernel.rb +5 -0
- data/lib/rubylog/mixins/method.rb +3 -0
- data/lib/rubylog/mixins/object.rb +8 -0
- data/lib/rubylog/mixins/proc.rb +37 -0
- data/lib/rubylog/mixins/string.rb +104 -0
- data/lib/rubylog/mixins/symbol.rb +44 -0
- data/lib/rubylog/simple_procedure.rb +8 -0
- data/lib/rubylog/{clause.rb → structure.rb} +32 -31
- data/lib/rubylog/theory.rb +368 -79
- data/lib/rubylog/variable.rb +102 -23
- data/lib/rubylog.rb +33 -25
- data/logic/builtins/file_system_logic.rb +23 -0
- data/logic/builtins/reflection_logic.rb +40 -0
- data/logic/dereference_logic.rb +23 -0
- data/logic/directory_structure_logic.rb +19 -0
- data/logic/dsl_logic.rb +29 -0
- data/logic/errors_logic.rb +9 -0
- data/logic/guard_logic.rb +115 -0
- data/logic/list_logic.rb +55 -0
- data/logic/map_logic.rb +15 -0
- data/logic/multitheory.rb +23 -0
- data/logic/recursion_logic.rb +12 -0
- data/logic/string_logic.rb +41 -0
- data/logic/thats_logic.rb +51 -0
- data/logic/variable_logic.rb +24 -0
- data/rubylog.gemspec +85 -46
- data/spec/bartak_guide_spec.rb +57 -62
- data/spec/builtins/all_spec.rb +99 -0
- data/spec/builtins/and_spec.rb +22 -0
- data/spec/builtins/array_spec.rb +16 -0
- data/spec/builtins/branch_or_spec.rb +27 -0
- data/spec/builtins/cut_spec.rb +44 -0
- data/spec/builtins/fail_spec.rb +5 -0
- data/spec/builtins/false_spec.rb +5 -0
- data/spec/builtins/in_spec.rb +38 -0
- data/spec/builtins/is_false_spec.rb +12 -0
- data/spec/builtins/is_spec.rb +26 -0
- data/spec/builtins/matches_spec.rb +23 -0
- data/spec/builtins/or_spec.rb +22 -0
- data/spec/{rubylog/builtins → builtins}/splits_to.rb +0 -0
- data/spec/builtins/then_spec.rb +27 -0
- data/spec/builtins/true_spec.rb +5 -0
- data/spec/clause_spec.rb +82 -0
- data/spec/compilation_spec.rb +61 -0
- data/spec/custom_classes_spec.rb +43 -0
- data/spec/dereference.rb +10 -0
- data/spec/{inriasuite.rb → inriasuite_spec.rb} +2 -9
- data/spec/queries_spec.rb +150 -0
- data/spec/recursion_spec.rb +4 -4
- data/spec/ruby_code_spec.rb +52 -0
- data/spec/rules_spec.rb +97 -0
- data/spec/spec_helper.rb +6 -2
- data/spec/theory_spec.rb +28 -0
- data/spec/unification_spec.rb +84 -0
- data/spec/variable_spec.rb +26 -0
- metadata +153 -180
- data/examples/4queens.rb +0 -10
- data/examples/calculation.rb +0 -12
- data/examples/concepts.rb +0 -46
- data/examples/fp.rb +0 -56
- data/examples/historia_de_espana.rb +0 -31
- data/examples/idea.rb +0 -143
- data/examples/lists.rb +0 -5
- data/examples/mechanika.rb +0 -409
- data/examples/parse.rb +0 -15
- data/lib/array.rb +0 -24
- data/lib/method.rb +0 -4
- data/lib/object.rb +0 -5
- data/lib/proc.rb +0 -4
- data/lib/rubylog/builtins.rb +0 -193
- data/lib/rubylog/callable.rb +0 -20
- data/lib/rubylog/composite_term.rb +0 -38
- data/lib/rubylog/dsl/constants.rb +0 -15
- data/lib/rubylog/dsl/first_order_functors.rb +0 -9
- data/lib/rubylog/dsl/global_functors.rb +0 -3
- data/lib/rubylog/dsl/second_order_functors.rb +0 -8
- data/lib/rubylog/internal_helpers.rb +0 -16
- data/lib/rubylog/predicate.rb +0 -34
- data/lib/rubylog/proc_method_additions.rb +0 -69
- data/lib/rubylog/term.rb +0 -20
- data/lib/rubylog/unifiable.rb +0 -19
- data/lib/symbol.rb +0 -35
- data/script/inriasuite2spec +0 -0
- data/script/inriasuite2spec.pl +0 -22
- data/spec/rubylog/clause_spec.rb +0 -81
- data/spec/rubylog/variable_spec.rb +0 -25
- data/spec/rubylog_spec.rb +0 -914
@@ -0,0 +1,27 @@
|
|
1
|
+
|
2
|
+
describe "then" do
|
3
|
+
it "works 1" do
|
4
|
+
:john.happy.if :fail.then :true
|
5
|
+
:john.should_not be_happy
|
6
|
+
end
|
7
|
+
|
8
|
+
it "works 2" do
|
9
|
+
:john.happy.if :true.then :fail
|
10
|
+
:john.should_not be_happy
|
11
|
+
end
|
12
|
+
|
13
|
+
it "works 3" do
|
14
|
+
:john.happy.if :fail.then :fail
|
15
|
+
:john.should_not be_happy
|
16
|
+
end
|
17
|
+
|
18
|
+
it "works 4" do
|
19
|
+
:john.happy.if :true.then :true
|
20
|
+
:john.should be_happy
|
21
|
+
end
|
22
|
+
|
23
|
+
it "works 5" do
|
24
|
+
:john.happy.if :true.then :true
|
25
|
+
:john.should be_happy
|
26
|
+
end
|
27
|
+
end
|
data/spec/clause_spec.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'rubylog'
|
2
|
+
|
3
|
+
theory "Vars" do
|
4
|
+
end
|
5
|
+
|
6
|
+
describe "clauses" do
|
7
|
+
it "can be created" do
|
8
|
+
(:john.is_happy).should be_kind_of Rubylog::Term
|
9
|
+
(:john.likes :beer).should be_kind_of Rubylog::Term
|
10
|
+
(A.likes :beer).should be_kind_of Rubylog::Term
|
11
|
+
(:john.likes Drink).should be_kind_of Rubylog::Term
|
12
|
+
(:john.likes :drinking.in :bar).should be_kind_of Rubylog::Term
|
13
|
+
end
|
14
|
+
it "forbids non-declared names" do
|
15
|
+
lambda { :john.something_else }.should raise_error(NoMethodError)
|
16
|
+
end
|
17
|
+
it "also work with operators" do
|
18
|
+
(:is_happy%1).should be_kind_of Rubylog::Term
|
19
|
+
(A%B).should be_kind_of Rubylog::Term
|
20
|
+
end
|
21
|
+
it "can be asked for their functor" do
|
22
|
+
(:john.is_happy).functor.should == :is_happy
|
23
|
+
(:is_happy%1).functor.should == :%
|
24
|
+
(A%1).functor.should == :%
|
25
|
+
(:john.likes :drinking.in :bar).functor.should == :likes
|
26
|
+
end
|
27
|
+
it "can be indexed" do
|
28
|
+
(:john.is_happy)[0].should == :john
|
29
|
+
(:john.likes :beer)[0].should == :john
|
30
|
+
(:john.likes :beer)[1].should == :beer
|
31
|
+
(:john.likes(:cold, :beer))[2].should == :beer
|
32
|
+
(:john.likes(:cold, :beer))[1..2].should == [:cold,:beer]
|
33
|
+
(:john.likes :drinking.in :bar)[1].should == (:drinking.in :bar)
|
34
|
+
end
|
35
|
+
it "can be asked for their args" do
|
36
|
+
(:john.is_happy).args.should == [:john]
|
37
|
+
(:john.likes :beer).args.should == [:john, :beer]
|
38
|
+
(:john.likes(:cold, :beer)).args.should == [:john, :cold, :beer]
|
39
|
+
(:john.likes :drinking.in :bar).args.should == [:john, :drinking.in(:bar)]
|
40
|
+
end
|
41
|
+
it "support ==" do
|
42
|
+
(:john.is_happy).should == (:john.is_happy)
|
43
|
+
(:john.is_happy).should_not be_equal(:john.is_happy)
|
44
|
+
(:john.is_happy).should_not == nil
|
45
|
+
(:john.is_happy).should_not == 9
|
46
|
+
(:john.is_happy).should_not == :john
|
47
|
+
(:john.is_happy).should_not == Rubylog
|
48
|
+
(:john.likes :drinking.in :bar).should == (:john.likes :drinking.in :bar)
|
49
|
+
end
|
50
|
+
it "support eql?" do
|
51
|
+
(:john.is_happy).should be_eql(:john.is_happy)
|
52
|
+
(:john.is_happy).should_not be_eql nil
|
53
|
+
(:john.is_happy).should_not be_eql 9
|
54
|
+
(:john.is_happy).should_not be_eql :john
|
55
|
+
(:john.is_happy).should_not be_eql Rubylog
|
56
|
+
(:john.likes :drinking.in :bar).should be_eql(:john.likes :drinking.in :bar)
|
57
|
+
end
|
58
|
+
it "support hash" do
|
59
|
+
(:john.is_happy).hash.should == (:john.is_happy).hash
|
60
|
+
(:john.likes :drinking.in :bar).hash.should ==
|
61
|
+
(:john.likes :drinking.in :bar).hash
|
62
|
+
end
|
63
|
+
it "support inspect" do
|
64
|
+
(:john.is_happy).inspect.should == ":john.is_happy"
|
65
|
+
(:john.likes :beer).inspect.should == ":john.likes(:beer)"
|
66
|
+
(:john.likes :drinking,:beer).inspect.should == ":john.likes(:drinking, :beer)"
|
67
|
+
(:john.likes :drinking.in :bar).inspect.should == ":john.likes(:drinking.in(:bar))"
|
68
|
+
end
|
69
|
+
it "can tell their arity" do
|
70
|
+
(:john.is_happy).arity.should == 1
|
71
|
+
(:john.likes :beer).arity.should == 2
|
72
|
+
(:john.likes :drinking,:beer).arity.should == 3
|
73
|
+
(:john.likes :drinking.in :bar).arity.should == 2
|
74
|
+
end
|
75
|
+
it "can tell their descriptor" do
|
76
|
+
(:john.is_happy).desc.should == [:is_happy,1]
|
77
|
+
(:john.likes :beer).desc.should == [:likes,2]
|
78
|
+
(:john.likes :drinking,:beer).desc.should == [:likes,3]
|
79
|
+
(:john.likes :drinking.in :bar).desc.should == [:likes,2]
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
@@ -0,0 +1,61 @@
|
|
1
|
+
|
2
|
+
describe "compilation" do
|
3
|
+
|
4
|
+
it "makes eql variables be equal" do
|
5
|
+
a = A; b = A
|
6
|
+
c = (a.likes b)
|
7
|
+
c[0].should be_equal a; c[1].should be_equal b
|
8
|
+
c[0].should_not be_equal c[1]
|
9
|
+
c = c.rubylog_compile_variables
|
10
|
+
c[0].should be_equal c[1]
|
11
|
+
end
|
12
|
+
|
13
|
+
it "makes non-eql variables be non-equal" do
|
14
|
+
a = A; b = B
|
15
|
+
c = (a.likes b)
|
16
|
+
c[0].should be_equal a; c[1].should be_equal b
|
17
|
+
c[0].should_not be_equal c[1]
|
18
|
+
c = c.rubylog_compile_variables
|
19
|
+
c[0].should_not be_equal c[1]
|
20
|
+
end
|
21
|
+
|
22
|
+
it "makes dont-care variables be non-equal" do
|
23
|
+
a = ANY; b = ANY
|
24
|
+
c = (a.likes b)
|
25
|
+
c[0].should be_equal a; c[1].should be_equal b
|
26
|
+
c[0].should_not be_equal c[1]
|
27
|
+
c = c.rubylog_compile_variables
|
28
|
+
c[0].should_not be_equal c[1]
|
29
|
+
end
|
30
|
+
|
31
|
+
it "creates new variables" do
|
32
|
+
a = A; b = B
|
33
|
+
c = (a.likes b)
|
34
|
+
c[0].should be_equal a; c[1].should be_equal b
|
35
|
+
c = c.rubylog_compile_variables
|
36
|
+
c[0].should_not be_equal a
|
37
|
+
c[1].should_not be_equal a
|
38
|
+
c[0].should_not be_equal b
|
39
|
+
c[1].should_not be_equal b
|
40
|
+
end
|
41
|
+
|
42
|
+
it "makes variables available" do
|
43
|
+
a = A; a1 = A; a2 = A; b = B; b1 = B; c = C;
|
44
|
+
(a.likes b).rubylog_compile_variables.rubylog_variables.should == [a, b]
|
45
|
+
(a.likes a1).rubylog_compile_variables.rubylog_variables.should == [a]
|
46
|
+
(a.likes a1.in b).rubylog_compile_variables.rubylog_variables.should == [a, b]
|
47
|
+
(a.likes a1,b,b1,a2,c).rubylog_compile_variables.rubylog_variables.should == [a, b, c]
|
48
|
+
end
|
49
|
+
|
50
|
+
it "does not make dont-care variables available" do
|
51
|
+
a = ANY; a1 = ANYTHING; a2 = ANYTHING; b = B; b1 = B; c = C;
|
52
|
+
(a.likes b).rubylog_compile_variables.rubylog_variables.should == [b]
|
53
|
+
(a.likes a1).rubylog_compile_variables.rubylog_variables.should == []
|
54
|
+
(a.likes a1.in b).rubylog_compile_variables.
|
55
|
+
rubylog_variables.should == [b]
|
56
|
+
(a.likes a1,b,b1,a2,c).rubylog_compile_variables.
|
57
|
+
rubylog_variables.should == [b, c]
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
|
2
|
+
describe "custom classes" do
|
3
|
+
before do
|
4
|
+
class User
|
5
|
+
rubylog_functor :girl, :boy
|
6
|
+
include Rubylog::DSL::Constants
|
7
|
+
|
8
|
+
attr_reader :name
|
9
|
+
def initialize name
|
10
|
+
@name = name
|
11
|
+
end
|
12
|
+
|
13
|
+
U.girl.if {|u| u.name =~ /[aeiouh]$/ }
|
14
|
+
U.boy.unless U.girl
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
it "can have ruby predicates" do
|
19
|
+
john = User.new "John"
|
20
|
+
john.girl?.should be_false
|
21
|
+
john.boy?.should be_true
|
22
|
+
jane = User.new "Jane"
|
23
|
+
jane.girl?.should be_true
|
24
|
+
jane.boy?.should be_false
|
25
|
+
end
|
26
|
+
|
27
|
+
it "can be used in assertions" do
|
28
|
+
pete = User.new "Pete"
|
29
|
+
pete.boy?.should be_false
|
30
|
+
pete.boy!
|
31
|
+
pete.boy?.should be_true
|
32
|
+
|
33
|
+
Rubylog.theory[:girl][1].discontinuous!
|
34
|
+
janet = User.new "Janet"
|
35
|
+
janet.girl?.should be_false
|
36
|
+
janet.girl!
|
37
|
+
janet.girl?.should be_true
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
|
42
|
+
|
43
|
+
end
|
data/spec/dereference.rb
ADDED
@@ -1,20 +1,13 @@
|
|
1
|
-
describe "abolish" do
|
2
|
-
|
3
|
-
end
|
4
|
-
|
5
1
|
describe "and" do
|
6
|
-
|
2
|
+
specify do
|
7
3
|
(X.is(1).and X.var).to_a.should == []
|
8
4
|
(X.var.and X.is(1)).to_a.should == [1]
|
9
5
|
(:fail.and :call[3]).to_a.should == []
|
10
6
|
lambda { (:nofoo[X].and X.call).to_a }.
|
11
7
|
should raise_error ExistenceError
|
12
8
|
(X.is(:true).and X.call).should == [:true]
|
13
|
-
|
9
|
+
end
|
14
10
|
end
|
15
11
|
|
16
12
|
|
17
|
-
describe "arg" do
|
18
|
-
|
19
|
-
end
|
20
13
|
|
@@ -0,0 +1,150 @@
|
|
1
|
+
|
2
|
+
describe "queries" do
|
3
|
+
it "can be run with true?" do
|
4
|
+
lambda {Rubylog.theory.true?(:john.likes :beer)}.should raise_error(Rubylog::ExistenceError)
|
5
|
+
:john.likes! :beer
|
6
|
+
Rubylog.theory.true?(:john.likes :beer).should be_true
|
7
|
+
Rubylog.theory.true?(:john.likes :milk).should be_false
|
8
|
+
end
|
9
|
+
|
10
|
+
it "can be run with question mark" do
|
11
|
+
lambda {Rubylog.theory.true?(:john.likes :beer)}.should raise_error(Rubylog::ExistenceError)
|
12
|
+
:john.likes! :beer
|
13
|
+
:john.likes?(:beer).should be_true
|
14
|
+
end
|
15
|
+
|
16
|
+
it "can be run with true?" do
|
17
|
+
lambda {Rubylog.theory.true?(:john.likes :beer)}.should raise_error(Rubylog::ExistenceError)
|
18
|
+
:john.likes! :beer
|
19
|
+
(:john.likes(:beer)).true?.should be_true
|
20
|
+
end
|
21
|
+
|
22
|
+
it "work with variables" do
|
23
|
+
lambda {Rubylog.theory.true?(:john.likes X)}.should raise_error(Rubylog::ExistenceError)
|
24
|
+
:john.likes! :water
|
25
|
+
:john.likes?(X).should be_true
|
26
|
+
end
|
27
|
+
|
28
|
+
it "yield all solutions" do
|
29
|
+
:john.likes! :beer
|
30
|
+
:john.likes! :milk
|
31
|
+
|
32
|
+
k=[]
|
33
|
+
(:john.likes X).each{|x|k << x}
|
34
|
+
k.should == [:beer, :milk]
|
35
|
+
end
|
36
|
+
|
37
|
+
it "yield all solutions with solve" do
|
38
|
+
:john.likes! :beer
|
39
|
+
:john.likes! :milk
|
40
|
+
|
41
|
+
k=[]
|
42
|
+
(:john.likes X).solve{|x|k << x}
|
43
|
+
k.should == [:beer, :milk]
|
44
|
+
end
|
45
|
+
|
46
|
+
it "yield all solutions with solve and multiple vars and multiple block parameters" do
|
47
|
+
:john.likes! :beer
|
48
|
+
:jane.likes! :milk
|
49
|
+
:jane.likes! :water
|
50
|
+
|
51
|
+
k=[]
|
52
|
+
(X.likes Y).solve{|a,b|k << [a,b]}
|
53
|
+
k.should == [[:john, :beer], [:jane, :milk], [:jane, :water]]
|
54
|
+
end
|
55
|
+
|
56
|
+
it "ignore don't-care variables" do
|
57
|
+
:john.likes! :beer
|
58
|
+
|
59
|
+
k=[]
|
60
|
+
ANYONE.likes(X).each{|x|k << x}
|
61
|
+
k.should == [:beer]
|
62
|
+
|
63
|
+
k=[]
|
64
|
+
X.likes(ANYTHING).each{|x|k << x}
|
65
|
+
k.should == [:john]
|
66
|
+
end
|
67
|
+
|
68
|
+
it "makes sure all variables are instantiated" do
|
69
|
+
res = []
|
70
|
+
A.likes(B).if {|a,b| res << a << b }
|
71
|
+
A.likes? :beer
|
72
|
+
res.should == [nil,:beer]
|
73
|
+
end
|
74
|
+
|
75
|
+
it "substitutes deeper variables" do
|
76
|
+
res = []
|
77
|
+
A.likes(B).if {|a,b| res << a << b }
|
78
|
+
(A.is(:john).and B.is(:swimming.in C).and
|
79
|
+
C.is(:sea).and A.likes B).to_a.should == [[:john,:swimming.in(:sea),:sea]]
|
80
|
+
res.should == [:john, :swimming.in(:sea)]
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
describe "support Enumerable" do
|
85
|
+
before do
|
86
|
+
:john.likes! :beer
|
87
|
+
:john.likes! :milk
|
88
|
+
end
|
89
|
+
|
90
|
+
it "#all?, #any? and #none?" do
|
91
|
+
(:john.likes A).all?{|a| Symbol===a}.should be_true
|
92
|
+
(:john.likes A).all?{|a| a == :beer}.should be_false
|
93
|
+
(:john.likes A).all?{|a| a == :beer or a == :milk}.should be_true
|
94
|
+
(:john.likes A).any?{|a| a == :beer}.should be_true
|
95
|
+
(:john.likes A).any?{|a| a == :milk}.should be_true
|
96
|
+
(:john.likes A).any?{|a| a == :water}.should be_false
|
97
|
+
(:john.likes A).none?{|a| a == :water}.should be_true
|
98
|
+
(:john.likes A).none?{|a| a == :beer}.should be_false
|
99
|
+
end
|
100
|
+
|
101
|
+
it "#to_a" do
|
102
|
+
(:john.likes A).to_a.should == [:beer, :milk]
|
103
|
+
(X.likes A).to_a.should == [[:john, :beer], [:john, :milk]]
|
104
|
+
(ANYONE.likes A).to_a.should == [:beer, :milk]
|
105
|
+
end
|
106
|
+
|
107
|
+
it "#first" do
|
108
|
+
(:john.likes A).first.should == :beer
|
109
|
+
end
|
110
|
+
|
111
|
+
it "#map" do
|
112
|
+
(:john.likes A).map{|a|a.to_s}.should == ['beer', 'milk']
|
113
|
+
end
|
114
|
+
|
115
|
+
it "#include? and #member?" do
|
116
|
+
(:john.likes B).member?(:beer).should be_true
|
117
|
+
(:john.likes B).include?(:beer).should be_true
|
118
|
+
(:john.likes B).member?(:milk).should be_true
|
119
|
+
(:john.likes B).include?(:milk).should be_true
|
120
|
+
(:john.likes B).member?(:water).should be_false
|
121
|
+
(:john.likes B).include?(:water).should be_false
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
it "can yield solutions with vars substituted" do
|
127
|
+
:john.likes! :beer
|
128
|
+
:john.likes! :milk
|
129
|
+
:jane.likes! :milk
|
130
|
+
|
131
|
+
(A.likes B).solutions.should == [
|
132
|
+
:john.likes(:beer),
|
133
|
+
:john.likes(:milk),
|
134
|
+
:jane.likes(:milk)
|
135
|
+
]
|
136
|
+
(A.likes(B).and A.is :john).solutions.should == [
|
137
|
+
:john.likes(:beer).and(:john.is :john),
|
138
|
+
:john.likes(:milk).and(:john.is :john)
|
139
|
+
]
|
140
|
+
(:john.likes(B)).solutions.should == [
|
141
|
+
:john.likes(:beer),
|
142
|
+
:john.likes(:milk)
|
143
|
+
]
|
144
|
+
(A.likes(:milk)).solutions.should == [
|
145
|
+
:john.likes(:milk),
|
146
|
+
:jane.likes(:milk)
|
147
|
+
]
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
data/spec/recursion_spec.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
|
2
2
|
require 'rubylog'
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
Integer
|
4
|
+
describe "recursion" do
|
5
|
+
specify "factorial" do
|
6
|
+
theory "Recursion" do
|
7
|
+
functor_for Integer, :factorial
|
8
8
|
0.factorial! 1
|
9
9
|
N.factorial(K).if lambda{|n|n>0}.and N1.is{|n|n-1}.and N1.factorial(K1).and K.is{|n,_,_,k1|k1*n}
|
10
10
|
|
@@ -0,0 +1,52 @@
|
|
1
|
+
|
2
|
+
describe "using ruby code in clauses" do
|
3
|
+
it "works" do
|
4
|
+
(:true.and? {false}).should be_false
|
5
|
+
(:true.and? {true}).should be_true
|
6
|
+
(:false.and? {false}).should be_false
|
7
|
+
(:false.and? {true}).should be_false
|
8
|
+
(:true.or? {false}).should be_true
|
9
|
+
(:true.or? {true}).should be_true
|
10
|
+
(:false.or? {false}).should be_false
|
11
|
+
(:false.or? {true}).should be_true
|
12
|
+
|
13
|
+
(:fail.or? {false}).should be_false
|
14
|
+
(:fail.or? {true}).should be_true
|
15
|
+
end
|
16
|
+
it "runs the query once at every evaluation" do
|
17
|
+
count = 0
|
18
|
+
:john.is_happy.if :true.and { count += 1 }
|
19
|
+
count.should == 0
|
20
|
+
:john.is_happy?
|
21
|
+
count.should == 1
|
22
|
+
:john.is_happy?
|
23
|
+
count.should == 2
|
24
|
+
(:false.or? {count+=1}).should be_true
|
25
|
+
count.should == 3
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "bindings" do
|
29
|
+
it "works for rule bodies" do
|
30
|
+
result = nil;
|
31
|
+
(A.likes(B).if {|*args| result = args})
|
32
|
+
(:john.likes(:beer)).solve{}
|
33
|
+
result.should == [:john,:beer]
|
34
|
+
end
|
35
|
+
|
36
|
+
it "works for rules" do
|
37
|
+
result = nil
|
38
|
+
(A.likes(B).if B.is(4).and A.is(2).and C.is(5).and {|*args| result = args})
|
39
|
+
(A.likes(B)).solve{}
|
40
|
+
result.should == [2,4,5]
|
41
|
+
end
|
42
|
+
|
43
|
+
it "works for inline terms" do
|
44
|
+
result = nil
|
45
|
+
(A.is(1).and B.is(2).and {|*args| result = args}).solve{}
|
46
|
+
result.should == [1,2]
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
data/spec/rules_spec.rb
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
|
2
|
+
describe "rules" do
|
3
|
+
describe "with prolog body" do
|
4
|
+
it "cannot be asserted in a builtin's desc" do
|
5
|
+
lambda {
|
6
|
+
:john.likes(:beer).and! :jane.likes(:milk)
|
7
|
+
}.should raise_error(Rubylog::BuiltinPredicateError)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "can be asserted with if" do
|
11
|
+
Rubylog.theory.predicate [:we_have, 2]
|
12
|
+
:john.is_happy.if :-@.we_have(:beer)
|
13
|
+
:john.is_happy?.should be_false
|
14
|
+
:-@.we_have!(:beer)
|
15
|
+
:john.is_happy?.should be_true
|
16
|
+
end
|
17
|
+
|
18
|
+
it "can be asserted with unless" do
|
19
|
+
Rubylog.theory.predicate [:we_have, 2]
|
20
|
+
:john.is_happy.unless :-@.we_have(:problem)
|
21
|
+
:john.is_happy?.should be_true
|
22
|
+
:-@.we_have!(:problem)
|
23
|
+
:john.is_happy?.should be_false
|
24
|
+
end
|
25
|
+
|
26
|
+
it "can do simple general implications" do
|
27
|
+
Rubylog.theory.predicate [:is_happy,1], [:has,2]
|
28
|
+
Rubylog.theory.discontinuous [:likes,2]
|
29
|
+
X.is_happy.if X.likes(Y).and X.has(Y)
|
30
|
+
:john.likes! :milk
|
31
|
+
:john.is_happy?.should be_false
|
32
|
+
:john.has! :beer
|
33
|
+
:john.is_happy?.should be_false
|
34
|
+
:john.likes! :beer
|
35
|
+
:john.is_happy?.should be_true
|
36
|
+
end
|
37
|
+
|
38
|
+
it "can yield implied solutions" do
|
39
|
+
X.brother(Y).if X.father(Z).and Y.father(Z).and X.neq(Y)
|
40
|
+
X.uncle(Y).if X.father(Z).and Z.brother(Y)
|
41
|
+
X.neq(Y).if proc {|x,y|x != y}
|
42
|
+
|
43
|
+
:john.father! :dad
|
44
|
+
:jack.father! :dad
|
45
|
+
:dad.father! :grandpa
|
46
|
+
:jim.father! :grandpa
|
47
|
+
|
48
|
+
(:john.brother X).to_a.should == [:jack]
|
49
|
+
(:john.father X).to_a.should == [:dad]
|
50
|
+
(X.father :dad).to_a.should == [:john, :jack]
|
51
|
+
(ANY.father X).to_a.should == [:dad, :dad, :grandpa, :grandpa]
|
52
|
+
(:john.uncle X).to_a.should == [:jim]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "with ruby body" do
|
57
|
+
it "can be asserted (true)" do
|
58
|
+
:john.is_happy.if proc{ true }
|
59
|
+
:john.is_happy?.should be_true
|
60
|
+
end
|
61
|
+
it "can be asserted (false)" do
|
62
|
+
:john.is_happy.if proc{ false }
|
63
|
+
:john.is_happy?.should be_false
|
64
|
+
end
|
65
|
+
|
66
|
+
it "can be asserted implicitly (true)" do
|
67
|
+
:john.is_happy.if { true }
|
68
|
+
:john.is_happy?.should be_true
|
69
|
+
end
|
70
|
+
|
71
|
+
it "can be asserted implicitly (false)" do
|
72
|
+
:john.is_happy.if { false }
|
73
|
+
:john.is_happy?.should be_false
|
74
|
+
end
|
75
|
+
|
76
|
+
it "run the body during every query" do
|
77
|
+
count = 0
|
78
|
+
:john.is_happy.if proc{ count += 1 }
|
79
|
+
count.should == 0
|
80
|
+
:john.is_happy?
|
81
|
+
count.should == 1
|
82
|
+
:john.is_happy?
|
83
|
+
count.should == 2
|
84
|
+
end
|
85
|
+
|
86
|
+
it "can take arguments" do
|
87
|
+
(A.divides B).if proc{|a,b| b % a == 0}
|
88
|
+
(4.divides? 16).should be_true
|
89
|
+
(4.divides? 17).should be_false
|
90
|
+
(4.divides? 18).should be_false
|
91
|
+
(3.divides? 3).should be_true
|
92
|
+
(3.divides? 4).should be_false
|
93
|
+
(3.divides? 5).should be_false
|
94
|
+
(3.divides? 6).should be_true
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,6 +1,10 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
$:.unshift(File.dirname(__FILE__))
|
3
3
|
require 'rspec'
|
4
|
+
|
5
|
+
require 'simplecov'
|
6
|
+
SimpleCov.start
|
7
|
+
|
4
8
|
require 'rubylog'
|
5
9
|
|
6
10
|
# Requires supporting files with custom matchers and macros, etc,
|
data/spec/theory_spec.rb
CHANGED
@@ -1 +1,29 @@
|
|
1
|
+
theory "Th" do
|
2
|
+
subject Symbol
|
3
|
+
functor \
|
4
|
+
:likes, :is_happy, :in, :has, :we_have,
|
5
|
+
:brother, :father, :uncle, :neq, :happy, :%
|
6
|
+
end
|
1
7
|
|
8
|
+
|
9
|
+
describe "facts" do
|
10
|
+
it "can be asserted with assert" do
|
11
|
+
Th.assert(:john.is_happy)
|
12
|
+
Th[[:is_happy,1]].should include(Rubylog::Clause.new :-, :john.is_happy, :true)
|
13
|
+
Th.assert(:john.likes :beer)
|
14
|
+
Th[[:likes,2]].should include(Rubylog::Clause.new :-, :john.likes(:beer), :true)
|
15
|
+
Th.assert(:john.likes :drinking.in :bar)
|
16
|
+
Th[[:likes,2]].should include(:john.likes(:drinking.in :bar) - :true)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "can be asserted with a bang, and it returns the zeroth arg" do
|
20
|
+
:john.is_happy!.should == :john
|
21
|
+
Th[[:is_happy,1]].should include(:john.is_happy.-:true)
|
22
|
+
:john.likes!(:beer).should == :john
|
23
|
+
Th[[:likes,2]].should include(:john.likes(:beer).-:true)
|
24
|
+
:john.likes!(:drinking.in :bar).should == :john
|
25
|
+
Th[[:likes,2]].should include(:john.likes(:drinking.in :bar).-:true)
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
end
|