rubylog 0.0.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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