rubylog 0.0.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (122) hide show
  1. data/Gemfile +1 -1
  2. data/README.hu.rb +58 -0
  3. data/README.rdoc +248 -89
  4. data/Rakefile +6 -1
  5. data/VERSION +1 -1
  6. data/bin/rubylog +18 -0
  7. data/examples/dcg.rb +35 -0
  8. data/examples/dcg2.rb +42 -0
  9. data/examples/enumerators.rb +30 -0
  10. data/examples/factorial.rb +9 -8
  11. data/examples/hanoi.rb +24 -0
  12. data/examples/hello.rb +11 -5
  13. data/examples/parsing.rb +27 -0
  14. data/examples/primitives.rb +24 -0
  15. data/examples/theory.rb +22 -10
  16. data/lib/rubylog/builtins/default.rb +10 -0
  17. data/lib/rubylog/builtins/file_system.rb +15 -0
  18. data/lib/rubylog/builtins/logic.rb +109 -0
  19. data/lib/rubylog/builtins/reflection.rb +94 -0
  20. data/lib/rubylog/builtins/term.rb +47 -0
  21. data/lib/rubylog/dsl/array_splat.rb +25 -0
  22. data/lib/rubylog/dsl/primitives.rb +17 -0
  23. data/lib/rubylog/dsl/thats.rb +22 -0
  24. data/lib/rubylog/dsl/variables.rb +30 -0
  25. data/lib/rubylog/dsl.rb +35 -17
  26. data/lib/rubylog/errors.rb +19 -1
  27. data/lib/rubylog/interfaces/assertable.rb +16 -0
  28. data/lib/rubylog/interfaces/callable.rb +18 -0
  29. data/lib/rubylog/interfaces/composite_term.rb +47 -0
  30. data/lib/rubylog/interfaces/predicate.rb +8 -0
  31. data/lib/rubylog/interfaces/procedure.rb +60 -0
  32. data/lib/rubylog/interfaces/term.rb +41 -0
  33. data/lib/rubylog/mixins/array.rb +118 -0
  34. data/lib/{class.rb → rubylog/mixins/class.rb} +2 -2
  35. data/lib/rubylog/mixins/hash.rb +8 -0
  36. data/lib/rubylog/mixins/kernel.rb +5 -0
  37. data/lib/rubylog/mixins/method.rb +3 -0
  38. data/lib/rubylog/mixins/object.rb +8 -0
  39. data/lib/rubylog/mixins/proc.rb +37 -0
  40. data/lib/rubylog/mixins/string.rb +104 -0
  41. data/lib/rubylog/mixins/symbol.rb +44 -0
  42. data/lib/rubylog/simple_procedure.rb +8 -0
  43. data/lib/rubylog/{clause.rb → structure.rb} +32 -31
  44. data/lib/rubylog/theory.rb +368 -79
  45. data/lib/rubylog/variable.rb +102 -23
  46. data/lib/rubylog.rb +33 -25
  47. data/logic/builtins/file_system_logic.rb +23 -0
  48. data/logic/builtins/reflection_logic.rb +40 -0
  49. data/logic/dereference_logic.rb +23 -0
  50. data/logic/directory_structure_logic.rb +19 -0
  51. data/logic/dsl_logic.rb +29 -0
  52. data/logic/errors_logic.rb +9 -0
  53. data/logic/guard_logic.rb +115 -0
  54. data/logic/list_logic.rb +55 -0
  55. data/logic/map_logic.rb +15 -0
  56. data/logic/multitheory.rb +23 -0
  57. data/logic/recursion_logic.rb +12 -0
  58. data/logic/string_logic.rb +41 -0
  59. data/logic/thats_logic.rb +51 -0
  60. data/logic/variable_logic.rb +24 -0
  61. data/rubylog.gemspec +85 -46
  62. data/spec/bartak_guide_spec.rb +57 -62
  63. data/spec/builtins/all_spec.rb +99 -0
  64. data/spec/builtins/and_spec.rb +22 -0
  65. data/spec/builtins/array_spec.rb +16 -0
  66. data/spec/builtins/branch_or_spec.rb +27 -0
  67. data/spec/builtins/cut_spec.rb +44 -0
  68. data/spec/builtins/fail_spec.rb +5 -0
  69. data/spec/builtins/false_spec.rb +5 -0
  70. data/spec/builtins/in_spec.rb +38 -0
  71. data/spec/builtins/is_false_spec.rb +12 -0
  72. data/spec/builtins/is_spec.rb +26 -0
  73. data/spec/builtins/matches_spec.rb +23 -0
  74. data/spec/builtins/or_spec.rb +22 -0
  75. data/spec/{rubylog/builtins → builtins}/splits_to.rb +0 -0
  76. data/spec/builtins/then_spec.rb +27 -0
  77. data/spec/builtins/true_spec.rb +5 -0
  78. data/spec/clause_spec.rb +82 -0
  79. data/spec/compilation_spec.rb +61 -0
  80. data/spec/custom_classes_spec.rb +43 -0
  81. data/spec/dereference.rb +10 -0
  82. data/spec/{inriasuite.rb → inriasuite_spec.rb} +2 -9
  83. data/spec/queries_spec.rb +150 -0
  84. data/spec/recursion_spec.rb +4 -4
  85. data/spec/ruby_code_spec.rb +52 -0
  86. data/spec/rules_spec.rb +97 -0
  87. data/spec/spec_helper.rb +6 -2
  88. data/spec/theory_spec.rb +28 -0
  89. data/spec/unification_spec.rb +84 -0
  90. data/spec/variable_spec.rb +26 -0
  91. metadata +153 -180
  92. data/examples/4queens.rb +0 -10
  93. data/examples/calculation.rb +0 -12
  94. data/examples/concepts.rb +0 -46
  95. data/examples/fp.rb +0 -56
  96. data/examples/historia_de_espana.rb +0 -31
  97. data/examples/idea.rb +0 -143
  98. data/examples/lists.rb +0 -5
  99. data/examples/mechanika.rb +0 -409
  100. data/examples/parse.rb +0 -15
  101. data/lib/array.rb +0 -24
  102. data/lib/method.rb +0 -4
  103. data/lib/object.rb +0 -5
  104. data/lib/proc.rb +0 -4
  105. data/lib/rubylog/builtins.rb +0 -193
  106. data/lib/rubylog/callable.rb +0 -20
  107. data/lib/rubylog/composite_term.rb +0 -38
  108. data/lib/rubylog/dsl/constants.rb +0 -15
  109. data/lib/rubylog/dsl/first_order_functors.rb +0 -9
  110. data/lib/rubylog/dsl/global_functors.rb +0 -3
  111. data/lib/rubylog/dsl/second_order_functors.rb +0 -8
  112. data/lib/rubylog/internal_helpers.rb +0 -16
  113. data/lib/rubylog/predicate.rb +0 -34
  114. data/lib/rubylog/proc_method_additions.rb +0 -69
  115. data/lib/rubylog/term.rb +0 -20
  116. data/lib/rubylog/unifiable.rb +0 -19
  117. data/lib/symbol.rb +0 -35
  118. data/script/inriasuite2spec +0 -0
  119. data/script/inriasuite2spec.pl +0 -22
  120. data/spec/rubylog/clause_spec.rb +0 -81
  121. data/spec/rubylog/variable_spec.rb +0 -25
  122. 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
@@ -0,0 +1,5 @@
1
+
2
+ it "true" do
3
+ :john.happy.if :true
4
+ :john.should be_happy
5
+ end
@@ -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
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Dereference" do
4
+ specify do
5
+ t = theory do
6
+ Rubylog::Variable.should === A
7
+
8
+ end
9
+ end
10
+ end
@@ -1,20 +1,13 @@
1
- describe "abolish" do
2
-
3
- end
4
-
5
1
  describe "and" do
6
- it {
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
@@ -1,10 +1,10 @@
1
1
 
2
2
  require 'rubylog'
3
3
 
4
- class << Rubylog.theory
5
- describe "recursion" do
6
- specify "factorial" do
7
- Integer.rubylog_functor :factorial
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
@@ -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
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
- $LOAD_PATH.unshift(File.dirname(__FILE__))
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