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
data/spec/rubylog_spec.rb DELETED
@@ -1,914 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
-
3
- RSpec::Matchers.define :stand do
4
- match do |actual|
5
- actual.true?
6
- end
7
- end
8
-
9
-
10
- class << Rubylog.theory
11
- Symbol.rubylog_functor \
12
- :likes, :is_happy, :in, :has, :we_have,
13
- :brother, :father, :uncle, :neq, :happy, :%
14
- Integer.rubylog_functor :divides, :queens
15
- Rubylog::Clause.rubylog_functor :-
16
-
17
- describe Rubylog do
18
- before do
19
- Rubylog.theory.clear
20
- end
21
-
22
-
23
-
24
- describe "facts" do
25
- it "can be asserted with assert" do
26
- Rubylog.theory.assert(:john.is_happy)
27
- Rubylog.theory.database[:is_happy][1].should include(Rubylog::Clause.new :-, :john.is_happy, :true)
28
- Rubylog.theory.assert(:john.likes :beer)
29
- Rubylog.theory.database[:likes][2].should include(Rubylog::Clause.new :-, :john.likes(:beer), :true)
30
- Rubylog.theory.assert(:john.likes :drinking.in :bar)
31
- Rubylog.theory.database[:likes][2].should include(:john.likes(:drinking.in :bar) - :true)
32
- end
33
-
34
- it "can be asserted with a bang, and it returns the zeroth arg" do
35
- :john.is_happy!.should == :john
36
- Rubylog.theory.database[:is_happy][1].should include(:john.is_happy.-:true)
37
- :john.likes!(:beer).should == :john
38
- Rubylog.theory.database[:likes][2].should include(:john.likes(:beer).-:true)
39
- :john.likes!(:drinking.in :bar).should == :john
40
- Rubylog.theory.database[:likes][2].should include(:john.likes(:drinking.in :bar).-:true)
41
- end
42
-
43
-
44
- end
45
-
46
- describe "compilation" do
47
-
48
- it "makes eql variables be equal" do
49
- a = A; b = A
50
- c = (a.likes b)
51
- c[0].should be_equal a; c[1].should be_equal b
52
- c[0].should_not be_equal c[1]
53
- c = c.rubylog_compile_variables
54
- c[0].should be_equal c[1]
55
- end
56
-
57
- it "makes non-eql variables be non-equal" do
58
- a = A; b = B
59
- c = (a.likes b)
60
- c[0].should be_equal a; c[1].should be_equal b
61
- c[0].should_not be_equal c[1]
62
- c = c.rubylog_compile_variables
63
- c[0].should_not be_equal c[1]
64
- end
65
-
66
- it "makes dont-care variables be non-equal" do
67
- a = ANY; b = ANY
68
- c = (a.likes b)
69
- c[0].should be_equal a; c[1].should be_equal b
70
- c[0].should_not be_equal c[1]
71
- c = c.rubylog_compile_variables
72
- c[0].should_not be_equal c[1]
73
- end
74
-
75
- it "creates new variables" do
76
- a = A; b = B
77
- c = (a.likes b)
78
- c[0].should be_equal a; c[1].should be_equal b
79
- c = c.rubylog_compile_variables
80
- c[0].should_not be_equal a
81
- c[1].should_not be_equal a
82
- c[0].should_not be_equal b
83
- c[1].should_not be_equal b
84
- end
85
-
86
- it "makes variables available" do
87
- a = A; a1 = A; a2 = A; b = B; b1 = B; c = C;
88
- (a.likes b).rubylog_compile_variables.rubylog_variables.should == [a, b]
89
- (a.likes a1).rubylog_compile_variables.rubylog_variables.should == [a]
90
- (a.likes a1.in b).rubylog_compile_variables.rubylog_variables.should == [a, b]
91
- (a.likes a1,b,b1,a2,c).rubylog_compile_variables.rubylog_variables.should == [a, b, c]
92
- end
93
-
94
- it "does not make dont-care variables available" do
95
- a = ANY; a1 = ANYTHING; a2 = ANYTHING; b = B; b1 = B; c = C;
96
- (a.likes b).rubylog_compile_variables.rubylog_variables.should == [b]
97
- (a.likes a1).rubylog_compile_variables.rubylog_variables.should == []
98
- (a.likes a1.in b).rubylog_compile_variables.
99
- rubylog_variables.should == [b]
100
- (a.likes a1,b,b1,a2,c).rubylog_compile_variables.
101
- rubylog_variables.should == [b, c]
102
- end
103
-
104
-
105
- end
106
-
107
- describe "unification" do
108
- it "works for variables" do
109
- result = false
110
- A.rubylog_unify(12) { result = true }
111
- result.should == true
112
- end
113
- it "works for used classes" do
114
- result = false
115
- :john.rubylog_unify(A) { result = true }
116
- result.should == true
117
- end
118
- it "works for constants" do
119
- result = false
120
- :john.rubylog_unify(:john) { result = true }
121
- result.should == true
122
- end
123
- it "fails for different constants" do
124
- result = false
125
- :john.rubylog_unify(:mary) { result = true }
126
- result.should == false
127
- end
128
- it "works on clauses" do
129
- result = false
130
- (:john.likes :beer).rubylog_unify(A.likes B) { result = true }
131
- result.should == true
132
- end
133
- it "works on clauses with equal values" do
134
- result = false
135
- (:john.likes :beer).rubylog_unify(:john.likes :beer) { result = true }
136
- result.should == true
137
- end
138
- it "works on clauses with different values" do
139
- result = false
140
- (:john.likes :beer).rubylog_unify(:john.likes :milk) { result = true }
141
- result.should == false
142
- end
143
- it "works on clauses with variables and equal values" do
144
- result = false
145
- (:john.likes :beer).rubylog_unify(X.likes :beer) { result = true }
146
- result.should == true
147
- end
148
- it "works on clauses with variables and equal values #2" do
149
- result = false
150
- (:john.likes :beer).rubylog_unify(:john.likes DRINK) { result = true }
151
- result.should == true
152
- end
153
- it "works on clauses with variables and different values" do
154
- result = false
155
- (:john.likes :beer).rubylog_unify(X.likes :milk) { result = true }
156
- result.should == false
157
- end
158
- it "works on clauses with variables and different values #2" do
159
- result = false
160
- (:john.likes :beer).rubylog_unify(:jane.likes D) { result = true }
161
- result.should == false
162
- end
163
-
164
- it "works on clauses with repeated variables #1" do
165
- result = false
166
- (A.likes A).rubylog_compile_variables.rubylog_unify(:john.likes :jane) { result = true }
167
- result.should == false
168
- (A.likes A).rubylog_compile_variables.rubylog_unify(:john.likes :john) { result = true }
169
- result.should == true
170
- end
171
- it "works on clauses with repeated variables #1" do
172
- result = false
173
- (:john.likes :jane).rubylog_unify(A.likes(A).rubylog_compile_variables) { result = true }
174
- result.should == false
175
- (:john.likes :john).rubylog_unify(A.likes(A).rubylog_compile_variables) { result = true }
176
- result.should == true
177
- end
178
-
179
- it "works for second-order variables" do
180
- result = false
181
- (:john.likes :beer).rubylog_unify(A) { result = true }
182
- result.should == true
183
- end
184
-
185
- end
186
-
187
- describe "queries" do
188
- it "can be run with true?" do
189
- lambda {Rubylog.theory.true?(:john.likes :beer)}.should raise_error(Rubylog::ExistenceError)
190
- :john.likes! :beer
191
- Rubylog.theory.true?(:john.likes :beer).should be_true
192
- Rubylog.theory.true?(:john.likes :milk).should be_false
193
- end
194
-
195
- it "can be run with question mark" do
196
- lambda {Rubylog.theory.true?(:john.likes :beer)}.should raise_error(Rubylog::ExistenceError)
197
- :john.likes! :beer
198
- :john.likes?(:beer).should be_true
199
- end
200
-
201
- it "can be run with true?" do
202
- lambda {Rubylog.theory.true?(:john.likes :beer)}.should raise_error(Rubylog::ExistenceError)
203
- :john.likes! :beer
204
- (:john.likes(:beer)).true?.should be_true
205
- end
206
-
207
- it "work with variables" do
208
- lambda {Rubylog.theory.true?(:john.likes X)}.should raise_error(Rubylog::ExistenceError)
209
- :john.likes! :water
210
- :john.likes?(X).should be_true
211
- end
212
-
213
- it "yield all solutions" do
214
- :john.likes! :beer
215
- :john.likes! :milk
216
-
217
- k=[]
218
- (:john.likes X).each{|x|k << x}
219
- k.should == [:beer, :milk]
220
- end
221
-
222
- it "yield all solutions with solve" do
223
- :john.likes! :beer
224
- :john.likes! :milk
225
-
226
- k=[]
227
- (:john.likes X).solve{|x|k << x}
228
- k.should == [:beer, :milk]
229
- end
230
-
231
- it "yield all solutions with solve and multiple vars and multiple block parameters" do
232
- :john.likes! :beer
233
- :jane.likes! :milk
234
- :jane.likes! :water
235
-
236
- k=[]
237
- (X.likes Y).solve{|a,b|k << [a,b]}
238
- k.should == [[:john, :beer], [:jane, :milk], [:jane, :water]]
239
- end
240
-
241
- it "ignore don't-care variables" do
242
- :john.likes! :beer
243
-
244
- k=[]
245
- ANYONE.likes(X).each{|x|k << x}
246
- k.should == [:beer]
247
-
248
- k=[]
249
- X.likes(ANYTHING).each{|x|k << x}
250
- k.should == [:john]
251
- end
252
-
253
- it "makes sure all variables are instantiated" do
254
- res = []
255
- A.likes(B).if {|a,b| res << a << b }
256
- A.likes? :beer
257
- res.should == [nil,:beer]
258
- end
259
-
260
- it "substitutes deeper variables" do
261
- res = []
262
- A.likes(B).if {|a,b| res << a << b }
263
- (A.is(:john).and B.is(:swimming.in C).and
264
- C.is(:sea).and A.likes B).to_a.should == [[:john,:swimming.in(:sea),:sea]]
265
- res.should == [:john, :swimming.in(:sea)]
266
- end
267
-
268
-
269
- describe "support Enumerable" do
270
- before do
271
- :john.likes! :beer
272
- :john.likes! :milk
273
- end
274
-
275
- it "#all?, #any? and #none?" do
276
- (:john.likes A).all?{|a| Symbol===a}.should be_true
277
- (:john.likes A).all?{|a| a == :beer}.should be_false
278
- (:john.likes A).all?{|a| a == :beer or a == :milk}.should be_true
279
- (:john.likes A).any?{|a| a == :beer}.should be_true
280
- (:john.likes A).any?{|a| a == :milk}.should be_true
281
- (:john.likes A).any?{|a| a == :water}.should be_false
282
- (:john.likes A).none?{|a| a == :water}.should be_true
283
- (:john.likes A).none?{|a| a == :beer}.should be_false
284
- end
285
-
286
- it "#to_a" do
287
- (:john.likes A).to_a.should == [:beer, :milk]
288
- (X.likes A).to_a.should == [[:john, :beer], [:john, :milk]]
289
- (ANYONE.likes A).to_a.should == [:beer, :milk]
290
- end
291
-
292
- it "#first" do
293
- (:john.likes A).first.should == :beer
294
- end
295
-
296
- it "#map" do
297
- (:john.likes A).map{|a|a.to_s}.should == ['beer', 'milk']
298
- end
299
-
300
- it "#include? and #member?" do
301
- (:john.likes B).member?(:beer).should be_true
302
- (:john.likes B).include?(:beer).should be_true
303
- (:john.likes B).member?(:milk).should be_true
304
- (:john.likes B).include?(:milk).should be_true
305
- (:john.likes B).member?(:water).should be_false
306
- (:john.likes B).include?(:water).should be_false
307
- end
308
-
309
- end
310
-
311
- it "can yield solutions with vars substituted" do
312
- :john.likes! :beer
313
- :john.likes! :milk
314
- :jane.likes! :milk
315
-
316
- (A.likes B).solutions.should == [
317
- :john.likes(:beer),
318
- :john.likes(:milk),
319
- :jane.likes(:milk)
320
- ]
321
- (A.likes(B).and A.is :john).solutions.should == [
322
- :john.likes(:beer).and(:john.is :john),
323
- :john.likes(:milk).and(:john.is :john)
324
- ]
325
- (:john.likes(B)).solutions.should == [
326
- :john.likes(:beer),
327
- :john.likes(:milk)
328
- ]
329
- (A.likes(:milk)).solutions.should == [
330
- :john.likes(:milk),
331
- :jane.likes(:milk)
332
- ]
333
- end
334
-
335
- end
336
-
337
- describe "using ruby code in clauses" do
338
- it "works" do
339
- (:true.and? {false}).should be_false
340
- (:true.and? {true}).should be_true
341
- (:false.and? {false}).should be_false
342
- (:false.and? {true}).should be_false
343
- (:true.or? {false}).should be_true
344
- (:true.or? {true}).should be_true
345
- (:false.or? {false}).should be_false
346
- (:false.or? {true}).should be_true
347
-
348
- (:fail.or? {false}).should be_false
349
- (:fail.or? {true}).should be_true
350
- end
351
- it "runs the query once at every evaluation" do
352
- count = 0
353
- :john.is_happy.if :true.and { count += 1 }
354
- count.should == 0
355
- :john.is_happy?
356
- count.should == 1
357
- :john.is_happy?
358
- count.should == 2
359
- (:false.or? {count+=1}).should be_true
360
- count.should == 3
361
- end
362
-
363
- describe "bindings" do
364
- it "works for rule bodies" do
365
- result = nil;
366
- (A.likes(B).if {|*args| result = args})
367
- (:john.likes(:beer)).solve{}
368
- result.should == [:john,:beer]
369
- end
370
-
371
- it "works for rules" do
372
- result = nil
373
- (A.likes(B).if B.is(4).and A.is(2).and C.is(5).and {|*args| result = args})
374
- (A.likes(B)).solve{}
375
- result.should == [2,4,5]
376
- end
377
-
378
- it "works for inline terms" do
379
- result = nil
380
- (A.is(1).and B.is(2).and {|*args| result = args}).solve{}
381
- result.should == [1,2]
382
- end
383
-
384
-
385
-
386
- end
387
- end
388
-
389
- describe "rules" do
390
- describe "with prolog body" do
391
- it "cannot be asserted in a builtin's desc" do
392
- lambda {
393
- :john.likes(:beer).and! :jane.likes(:milk)
394
- }.should raise_error(Rubylog::BuiltinPredicateError)
395
- end
396
-
397
- it "can be asserted with if" do
398
- Rubylog.theory.predicate [:we_have, 2]
399
- :john.is_happy.if :-@.we_have(:beer)
400
- :john.is_happy?.should be_false
401
- :-@.we_have!(:beer)
402
- :john.is_happy?.should be_true
403
- end
404
-
405
- it "can be asserted with unless" do
406
- Rubylog.theory.predicate [:we_have, 2]
407
- :john.is_happy.unless :-@.we_have(:problem)
408
- :john.is_happy?.should be_true
409
- :-@.we_have!(:problem)
410
- :john.is_happy?.should be_false
411
- end
412
-
413
- it "can do simple general implications" do
414
- Rubylog.theory.predicate [:is_happy,1], [:has,2]
415
- Rubylog.theory.discontinuous [:likes,2]
416
- X.is_happy.if X.likes(Y).and X.has(Y)
417
- :john.likes! :milk
418
- :john.is_happy?.should be_false
419
- :john.has! :beer
420
- :john.is_happy?.should be_false
421
- :john.likes! :beer
422
- :john.is_happy?.should be_true
423
- end
424
-
425
- it "can yield implied solutions" do
426
- X.brother(Y).if X.father(Z).and Y.father(Z).and X.neq(Y)
427
- X.uncle(Y).if X.father(Z).and Z.brother(Y)
428
- X.neq(Y).if proc {|x,y|x != y}
429
-
430
- :john.father! :dad
431
- :jack.father! :dad
432
- :dad.father! :grandpa
433
- :jim.father! :grandpa
434
-
435
- (:john.brother X).to_a.should == [:jack]
436
- (:john.father X).to_a.should == [:dad]
437
- (X.father :dad).to_a.should == [:john, :jack]
438
- (ANY.father X).to_a.should == [:dad, :dad, :grandpa, :grandpa]
439
- (:john.uncle X).to_a.should == [:jim]
440
- end
441
- end
442
-
443
- describe "with ruby body" do
444
- it "can be asserted (true)" do
445
- :john.is_happy.if proc{ true }
446
- :john.is_happy?.should be_true
447
- end
448
- it "can be asserted (false)" do
449
- :john.is_happy.if proc{ false }
450
- :john.is_happy?.should be_false
451
- end
452
-
453
- it "can be asserted implicitly (true)" do
454
- :john.is_happy.if { true }
455
- :john.is_happy?.should be_true
456
- end
457
-
458
- it "can be asserted implicitly (false)" do
459
- :john.is_happy.if { false }
460
- :john.is_happy?.should be_false
461
- end
462
-
463
- it "run the body during every query" do
464
- count = 0
465
- :john.is_happy.if proc{ count += 1 }
466
- count.should == 0
467
- :john.is_happy?
468
- count.should == 1
469
- :john.is_happy?
470
- count.should == 2
471
- end
472
-
473
- it "can take arguments" do
474
- (A.divides B).if proc{|a,b| b % a == 0}
475
- (4.divides? 16).should be_true
476
- (4.divides? 17).should be_false
477
- (4.divides? 18).should be_false
478
- (3.divides? 3).should be_true
479
- (3.divides? 4).should be_false
480
- (3.divides? 5).should be_false
481
- (3.divides? 6).should be_true
482
- end
483
- end
484
- end
485
-
486
- describe "custom classes" do
487
- before do
488
- class User
489
- rubylog_functor :girl, :boy
490
- include Rubylog::DSL::Constants
491
-
492
- attr_reader :name
493
- def initialize name
494
- @name = name
495
- end
496
-
497
- U.girl.if {|u| u.name =~ /[aeiouh]$/ }
498
- U.boy.unless U.girl
499
- end
500
- end
501
-
502
- it "can have ruby predicates" do
503
- john = User.new "John"
504
- john.girl?.should be_false
505
- john.boy?.should be_true
506
- jane = User.new "Jane"
507
- jane.girl?.should be_true
508
- jane.boy?.should be_false
509
- end
510
-
511
- it "can be used in assertions" do
512
- pete = User.new "Pete"
513
- pete.boy?.should be_false
514
- pete.boy!
515
- pete.boy?.should be_true
516
-
517
- Rubylog.theory[:girl][1].discontinuous!
518
- janet = User.new "Janet"
519
- janet.girl?.should be_false
520
- janet.girl!
521
- janet.girl?.should be_true
522
- end
523
-
524
-
525
-
526
-
527
- end
528
-
529
-
530
- describe "builtin" do
531
- it "true" do
532
- :john.happy.if :true
533
- :john.should be_happy
534
- end
535
-
536
- it "fail" do
537
- :john.happy.if :fail
538
- :john.should_not be_happy
539
- end
540
-
541
- it "false" do
542
- :john.happy.if :false
543
- :john.should_not be_happy
544
- end
545
-
546
- describe "branch or" do
547
- it "works 1" do
548
- :john.happy.if :fail
549
- :john.happy.if :true
550
- :john.should be_happy
551
- end
552
-
553
- it "works 2" do
554
- :john.happy.if :true
555
- :john.happy.if :fail
556
- :john.should be_happy
557
- end
558
-
559
- it "works 3" do
560
- :john.happy.if :fail
561
- :john.happy.if :fail
562
- :john.should_not be_happy
563
- end
564
-
565
- it "works 4" do
566
- :john.happy.if :true
567
- :john.happy.if :true
568
- :john.should be_happy
569
- end
570
- end
571
-
572
- describe "or" do
573
- it "works 1" do
574
- :john.happy.if :fail.or :true
575
- :john.should be_happy
576
- end
577
-
578
- it "works 2" do
579
- :john.happy.if :true.or :fail
580
- :john.should be_happy
581
- end
582
-
583
- it "works 3" do
584
- :john.happy.if :fail.or :fail
585
- :john.should_not be_happy
586
- end
587
-
588
- it "works 4" do
589
- :john.happy.if :true.or :true
590
- :john.should be_happy
591
- end
592
- end
593
-
594
- describe "and" do
595
- it "works 1" do
596
- :john.happy.if :fail.and :true
597
- :john.should_not be_happy
598
- end
599
-
600
- it "works 2" do
601
- :john.happy.if :true.and :fail
602
- :john.should_not be_happy
603
- end
604
-
605
- it "works 3" do
606
- :john.happy.if :fail.and :fail
607
- :john.should_not be_happy
608
- end
609
-
610
- it "works 4" do
611
- :john.happy.if :true.and :true
612
- :john.should be_happy
613
- end
614
- end
615
-
616
- describe "then" do
617
- it "works 1" do
618
- :john.happy.if :fail.then :true
619
- :john.should_not be_happy
620
- end
621
-
622
- it "works 2" do
623
- :john.happy.if :true.then :fail
624
- :john.should_not be_happy
625
- end
626
-
627
- it "works 3" do
628
- :john.happy.if :fail.then :fail
629
- :john.should_not be_happy
630
- end
631
-
632
- it "works 4" do
633
- :john.happy.if :true.then :true
634
- :john.should be_happy
635
- end
636
-
637
- it "works 5" do
638
- :john.happy.if :true.then :true
639
- :john.should be_happy
640
- end
641
- end
642
-
643
- describe "cut" do
644
- it "works with branch or" do
645
- :john.happy.if :true.and :cut.and :fail
646
- :john.happy.if :true
647
- :john.should_not be_happy
648
- end
649
- it "works with branch or (control)" do
650
- :john.happy.if :true.and :fail
651
- :john.happy.if :true
652
- :john.should be_happy
653
- end
654
-
655
- it "works with or" do
656
- :john.happy.if((:true.and :cut.and :fail).or :true)
657
- :john.should_not be_happy
658
- end
659
-
660
- it "works with or (control)" do
661
- :john.happy.if((:true.and :fail).or :true)
662
- :john.should be_happy
663
- end
664
-
665
- it "returns true with branch or" do
666
- :john.happy.if :true.and :cut.and :true
667
- :john.happy.if :true
668
- :john.should be_happy
669
- end
670
- it "returns true with branch or (control)" do
671
- :john.happy.if :true.and :true
672
- :john.happy.if :true
673
- :john.should be_happy
674
- end
675
-
676
- it "returns true with or" do
677
- :john.happy.if((:true.and :cut.and :true).or :true)
678
- :john.should be_happy
679
- end
680
-
681
- it "returns true with or (control)" do
682
- :john.happy.if((:true.and :true).or :true)
683
- :john.should be_happy
684
- end
685
- end
686
-
687
- describe "is_false" do
688
- it "works 5" do
689
- :john.happy.if :true.is_false
690
- :john.should_not be_happy
691
- end
692
-
693
- it "works 5" do
694
- :john.happy.if :fail.is_false
695
- :john.should be_happy
696
- end
697
- end
698
-
699
- describe "is" do
700
- before do
701
- :john.likes! :beer
702
- :jane.likes! :milk
703
- end
704
-
705
- it "works for variables" do
706
- (A.likes(B).and(B.is :milk)).to_a.should == [[:jane, :milk]]
707
- (A.likes(B).and(:milk.is B)).to_a.should == [[:jane, :milk]]
708
- end
709
-
710
- it "works as calculation" do
711
- (A.is {|| 4+4}).to_a.should == [8]
712
- (A.is {4+4}).to_a.should == [8]
713
- (A.is(4).and A.is{2*2}).to_a.should == [4]
714
- (A.is(4).and A.is{2*3}).to_a.should == []
715
- end
716
-
717
- it "works as calculation with vars" do
718
- (A.is(4).and B.is{|a|a*4}).to_a.should == [[4,16]]
719
- (A.is(4).and A.is{|a|a*1}).to_a.should == [4]
720
- (A.is(4).and A.is{|a|a*2}).to_a.should == []
721
- end
722
-
723
- end
724
-
725
- describe "matches" do
726
- before do
727
- :john.likes! "Beer"
728
- :jane.likes! "Water"
729
- end
730
-
731
- it "works for variables" do
732
- (A.likes(B).and(B.matches /e/)).to_a.should == [[:john, "Beer"], [:jane, "Water"]]
733
- (A.likes(B).and(B.matches /ee/)).to_a.should == [[:john, "Beer"]]
734
- (A.likes(B).and(B.matches /w/i)).to_a.should == [[:jane, "Water"]]
735
- end
736
-
737
- it "works as calculation" do
738
- (A.likes(B).and(B.matches {|a,b|/e/})).to_a.should == [[:john, "Beer"], [:jane, "Water"]]
739
- (A.likes(B).and(B.matches {|a,b|/ee/})).to_a.should == [[:john, "Beer"]]
740
- (A.likes(B).and(B.matches {|a,b|/w/i})).to_a.should == [[:jane, "Water"]]
741
- (A.likes(B).and(B.matches {|a,b|b})).to_a.should == [[:john, "Beer"], [:jane, "Water"]]
742
- (A.likes(B).and(B.matches {|a,b|a})).to_a.should == []
743
- end
744
-
745
-
746
- end
747
-
748
- describe "in" do
749
- before do
750
- :john.likes! :beer
751
- :jane.likes! :milk
752
- end
753
-
754
- it "works for variables" do
755
- (A.likes(B).and(B.in [])).to_a.should == []
756
- (A.likes(B).and(B.in [:milk])).to_a.should == [[:jane, :milk]]
757
- (A.likes(B).and(B.in [:beer])).to_a.should == [[:john, :beer]]
758
- (A.likes(B).and(B.in [:milk, :beer])).to_a.should == [[:john, :beer], [:jane, :milk]]
759
- end
760
-
761
- it "works with blocks" do
762
- (A.likes(B).and(B.in {[]})).to_a.should == []
763
- (A.likes(B).and(B.in {|a|[a,:milk]})).to_a.should == [[:jane, :milk]]
764
- (A.likes(B).and(B.in {|a,b|[:beer]})).to_a.should == [[:john, :beer]]
765
- (A.likes(B).and(B.in {|a,b|[b]})).to_a.should == [[:john, :beer], [:jane, :milk]]
766
- end
767
-
768
- it "works as iterator" do
769
- (A.in{[1,3,4]}).to_a.should == [1,3,4]
770
- (A.in [1,3,4]).to_a.should == [1,3,4]
771
- end
772
-
773
- it "works as search" do
774
- (1.in{[1,3,4]}).to_a.should == [nil]
775
- (2.in{[1,3,4]}).to_a.should == []
776
- (1.in [1,3,4]).to_a.should == [nil]
777
- (2.in [1,3,4]).to_a.should == []
778
- end
779
-
780
- it "works with clauses" do
781
- (A.likes(B).and B.in{:john.likes(X)}).to_a.should == [[:john, :beer]]
782
- end
783
-
784
- end
785
-
786
- describe "all,any,one,none" do
787
- before do
788
- :john.likes! :water
789
- :john.likes! :beer
790
-
791
- :jane.likes! :water
792
- :jane.likes! :milk
793
- :jane.likes! :beer
794
-
795
- :jeff.likes! :water
796
- :jeff.likes! :absinth
797
-
798
- :todd.likes! :milk
799
-
800
- @predicates = [:all, :any, :one, :none]
801
- @names = :john, :jane, :jeff, :todd
802
- @good =
803
- [
804
- [[1,1,0,0], [0,1,0,0], [0,0,1,0], [0,1,0,1]], # all
805
- [[1,1,1,0], [1,1,1,1], [1,1,1,0], [0,1,0,1]], # any
806
- [[0,0,1,0], [0,0,1,1], [1,1,0,0], [0,1,0,1]], # one
807
- [[0,0,0,1], [0,0,0,0], [0,0,0,1], [1,0,1,0]] # none
808
- ]
809
- end
810
-
811
- it "work" do
812
- @predicates.map{|p| @names.map{|n| @names.map{|m|
813
- (n.likes(K).send p, m.likes(K)).true? ? 1 : 0
814
- }}}.should == @good
815
- end
816
-
817
- it "mimic well enumerators' predicates" do
818
- @predicates.map{|p| @names.map{|n| @names.map{|m|
819
- n.likes(K).to_a.send(:"#{p}?"){|x| m.likes?(x) } ? 1 : 0
820
- }}}.should == @good
821
- end
822
-
823
-
824
-
825
- it "all works" do
826
- (:john.likes(X).all(:john.likes(X))).should stand
827
- (:john.likes(X).all(:jane.likes(X))).should stand
828
- (:john.likes(X).all(:jeff.likes(X))).should_not stand
829
- (:john.likes(X).all(:todd.likes(X))).should_not stand
830
-
831
- (:jane.likes(X).all(:john.likes(X))).should_not stand
832
- (:jane.likes(X).all(:jane.likes(X))).should stand
833
- (:jane.likes(X).all(:jeff.likes(X))).should_not stand
834
- (:jane.likes(X).all(:todd.likes(X))).should_not stand
835
-
836
- (:jeff.likes(X).all(:john.likes(X))).should_not stand
837
- (:jeff.likes(X).all(:jane.likes(X))).should_not stand
838
- (:jeff.likes(X).all(:jeff.likes(X))).should stand
839
- (:jeff.likes(X).all(:todd.likes(X))).should_not stand
840
-
841
- (:todd.likes(X).all(:john.likes(X))).should_not stand
842
- (:todd.likes(X).all(:jane.likes(X))).should stand
843
- (:todd.likes(X).all(:jeff.likes(X))).should_not stand
844
- (:todd.likes(X).all(:todd.likes(X))).should stand
845
- end
846
-
847
- it "can be called with global functor syntax" do
848
- extend Rubylog::DSL::GlobalFunctors
849
- all(:john.likes(X), :jane.likes(X)).should stand
850
- all(:jane.likes(X), :john.likes(X)).should_not stand
851
- any(:jane.likes(X), :todd.likes(X)).should stand
852
- any(:john.likes(X), :todd.likes(X)).should_not stand
853
- end
854
-
855
- it "can be called unarily" do
856
- extend Rubylog::DSL::GlobalFunctors
857
- one(:john.likes(X)).should_not stand
858
- one(:jane.likes(X)).should_not stand
859
- one(:jeff.likes(X)).should_not stand
860
- one(:todd.likes(X)).should stand
861
- one(:jim.likes(X)).should_not stand
862
-
863
- any(:john.likes(X)).should stand
864
- any(:jane.likes(X)).should stand
865
- any(:jeff.likes(X)).should stand
866
- any(:todd.likes(X)).should stand
867
- any(:jim.likes(X)).should_not stand
868
-
869
- all(:john.likes(X)).should stand
870
- all(:jane.likes(X)).should stand
871
- all(:jeff.likes(X)).should stand
872
- all(:todd.likes(X)).should stand
873
- all(:jim.likes(X)).should stand
874
-
875
- none(:john.likes(X)).should_not stand
876
- none(:jane.likes(X)).should_not stand
877
- none(:jeff.likes(X)).should_not stand
878
- none(:todd.likes(X)).should_not stand
879
- none(:jim.likes(X)).should stand
880
- end
881
- end
882
-
883
- end
884
-
885
- describe "Array" do
886
- it "can be unified" do
887
- result = false
888
- [A,B].rubylog_unify(12) { result = true }
889
- result.should == false
890
-
891
- result = false
892
- [A,B].rubylog_unify([12,13]) { result = true }
893
- result.should == true
894
-
895
- result = false
896
- [14,B].rubylog_unify([12,13]) { result = true }
897
- result.should == false
898
- end
899
- end
900
-
901
-
902
-
903
-
904
- end
905
-
906
-
907
- end
908
-
909
-
910
-
911
-
912
-
913
-
914
-