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
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
-