ruleby 0.9.b4 → 0.9.b7

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 (48) hide show
  1. data/.gitignore +5 -0
  2. data/GPL.txt +341 -0
  3. data/LICENSE.txt +52 -0
  4. data/README.markdown +22 -0
  5. data/benchmarks/basic_rules.rb +61 -0
  6. data/benchmarks/joined_rules.rb +66 -0
  7. data/benchmarks/miss_manners/data.rb +146 -0
  8. data/benchmarks/miss_manners/miss_manners.rb +33 -0
  9. data/benchmarks/miss_manners/model.rb +193 -0
  10. data/benchmarks/miss_manners/rules.rb +105 -0
  11. data/benchmarks/model.rb +36 -0
  12. data/examples/diagnosis.rb +129 -0
  13. data/examples/fibonacci_example1.rb +44 -0
  14. data/examples/fibonacci_example2.rb +40 -0
  15. data/examples/fibonacci_example3.rb +78 -0
  16. data/examples/fibonacci_rulebook.rb +84 -0
  17. data/examples/hello.rb +45 -0
  18. data/examples/ticket.rb +113 -0
  19. data/examples/wordgame.rb +107 -0
  20. data/lib/core/engine.rb +26 -24
  21. data/lib/core/nodes.rb +77 -35
  22. data/lib/ruleby.rb +0 -37
  23. data/ruleby.gemspec +17 -0
  24. data/spec/and_or_spec.rb +252 -0
  25. data/spec/coercion_spec.rb +5 -0
  26. data/spec/collect_spec.rb +1021 -0
  27. data/spec/errors_spec.rb +148 -0
  28. data/spec/ferrari_spec.rb +39 -0
  29. data/spec/function_spec.rb +199 -0
  30. data/spec/hello_spec.rb +34 -0
  31. data/spec/node_sharing_spec.rb +53 -0
  32. data/spec/property_spec.rb +69 -0
  33. data/spec/spec.opts +4 -0
  34. data/spec/spec_helper.rb +9 -0
  35. data/tasks/documentation.rake +32 -0
  36. data/tasks/rspec.rake +21 -0
  37. data/tasks/test.rake +9 -0
  38. data/tests/assert_facts.rb +130 -0
  39. data/tests/common.rb +29 -0
  40. data/tests/duck_type.rb +79 -0
  41. data/tests/gets.rb +48 -0
  42. data/tests/join_nodes.rb +63 -0
  43. data/tests/nil.rb +72 -0
  44. data/tests/not_patterns.rb +91 -0
  45. data/tests/or_patterns.rb +154 -0
  46. data/tests/regex.rb +47 -0
  47. data/tests/self_reference.rb +54 -0
  48. metadata +81 -49
@@ -0,0 +1,36 @@
1
+ # This file is part of the Ruleby project (http://ruleby.org)
2
+ #
3
+ # This application is free software; you can redistribute it and/or
4
+ # modify it under the terms of the Ruby license defined in the
5
+ # LICENSE.txt file.
6
+ #
7
+ # Copyright (c) 2007 Joe Kutner and Matt Smith. All rights reserved.
8
+ #
9
+ # * Authors: Joe Kutner, Matt Smith
10
+ #
11
+
12
+ class Account
13
+ def initialize(status, title, account_id)
14
+ @status = status
15
+ @title = title
16
+ @account_id = account_id
17
+ end
18
+
19
+ attr :status, true
20
+ attr :title, true
21
+ attr :account_id, true
22
+ end
23
+
24
+ class Address
25
+ def initialize(addr_id, city, state, zip)
26
+ @addr_id = addr_id
27
+ @city = city
28
+ @state = state
29
+ @zip = zip
30
+ end
31
+
32
+ attr :addr_id, true
33
+ attr :city, true
34
+ attr :state, true
35
+ attr :zip, true
36
+ end
@@ -0,0 +1,129 @@
1
+ # This file is part of the Ruleby project (http://ruleby.org)
2
+ #
3
+ # This application is free software; you can redistribute it and/or
4
+ # modify it under the terms of the Ruby license defined in the
5
+ # LICENSE.txt file.
6
+ #
7
+ # Copyright (c) 2007 Joe Kutner and Matt Smith. All rights reserved.
8
+ #
9
+ # * Authors: Joe Kutner, Matt Smith
10
+ #
11
+
12
+ $LOAD_PATH << File.join(File.dirname(__FILE__), '../lib/')
13
+ require 'ruleby'
14
+
15
+ class Patient
16
+ def initialize(name,fever,spots,rash,sore_throat,innoculated)
17
+ @name = name
18
+ @fever = fever
19
+ @spots= spots
20
+ @rash = rash
21
+ @sore_throat = sore_throat
22
+ @innoculated = innoculated
23
+ end
24
+ attr:name, true
25
+ attr:fever, true
26
+ attr:spots, true
27
+ attr:rash, true
28
+ attr:sore_throat, true
29
+ attr:innoculated, true
30
+ end
31
+
32
+ class Diagnosis
33
+ def initialize(name,diagnosis)
34
+ @name=name
35
+ @diagnosis=diagnosis
36
+ end
37
+ attr:name,true
38
+ attr:diagnosis,true
39
+ end
40
+
41
+ class Treatment
42
+ def initialize(name,treatment)
43
+ @name=name
44
+ @treatment=treatment
45
+ end
46
+ attr:name,true
47
+ attr:treatment,true
48
+ end
49
+
50
+ class DiagnosisRulebook < Ruleby::Rulebook
51
+ def rules
52
+ rule :Measles, {:priority => 100},
53
+ [Patient,:p,{m.name=>:n},m.fever==:high,m.spots==true,m.innoculated==true] do |v|
54
+ name = v[:n]
55
+ assert Diagnosis.new(name, :measles)
56
+ puts "Measles diagnosed for #{name}"
57
+ end
58
+
59
+ rule :Allergy1,
60
+ [Patient,:p, {m.name=>:n}, m.spots==true],
61
+ [:not, Diagnosis, m.name==b(:n), m.diagnosis==:measles] do |v|
62
+ name = v[:n]
63
+ assert Diagnosis.new(name, :allergy)
64
+ puts "Allergy diagnosed for #{name} from spots and lack of measles"
65
+ end
66
+
67
+ rule :Allergy2,
68
+ [Patient,:p, {m.name=>:n}, m.rash==true] do |v|
69
+ name = v[:n]
70
+ assert Diagnosis.new(name, :allergy)
71
+ puts "Allergy diagnosed from rash for #{name}"
72
+ end
73
+
74
+ rule :Flu,
75
+ [Patient,:p, {m.name=>:n}, m.sore_throat==true, m.fever(&c{|f| f==:mild || f==:high})] do |v|
76
+ name = v[:n]
77
+ assert Diagnosis.new(name, :flu)
78
+ puts "Flu diagnosed for #{name}"
79
+ end
80
+
81
+ rule :Penicillin,
82
+ [Diagnosis, :d, {m.name => :n}, m.diagnosis==:measles] do |v|
83
+ name = v[:n]
84
+ assert Treatment.new(name, :penicillin)
85
+ puts "Penicillin prescribed for #{name}"
86
+ end
87
+
88
+ rule :Allergy_pills,
89
+ [Diagnosis, :d, {m.name => :n}, m.diagnosis==:allergy] do |v|
90
+ name = v[:n]
91
+ assert Treatment.new(name, :allergy_shot)
92
+ puts "Allergy shot prescribed for #{name}"
93
+ end
94
+
95
+ rule :Bed_rest,
96
+ [Diagnosis, :d, {m.name => :n}, m.diagnosis==:flu] do |v|
97
+ name = v[:n]
98
+ assert Treatment.new(name, :bed_rest)
99
+ puts "Bed rest prescribed for #{name}"
100
+ end
101
+ end
102
+ end
103
+
104
+ include Ruleby
105
+
106
+ engine :engine do |e|
107
+
108
+ DiagnosisRulebook.new e do |r|
109
+ r.rules
110
+ end
111
+
112
+ e.assert Patient.new('Fred',:none,true,false,false,false)
113
+ e.assert Patient.new('Joe',:high,false,false,true,false)
114
+ e.assert Patient.new('Bob',:high,true,false,false,true)
115
+ e.assert Patient.new('Tom',:none,false,true,false,false)
116
+
117
+ e.match
118
+
119
+ # expect this output:
120
+ # Measles diagnosed for Bob
121
+ # Penicillin prescribed for Bob
122
+ # Allergy diagnosed from rash for Tom
123
+ # Allergy shot prescribed for Tom
124
+ # Flu diagnosed for Joe
125
+ # Bed rest prescribed for Joe
126
+ # Allergy diagnosed for Fred from spots and lack of measles
127
+ # Allergy shot prescribed for Fred
128
+
129
+ end
@@ -0,0 +1,44 @@
1
+ # This file is part of the Ruleby project (http://ruleby.org)
2
+ #
3
+ # This application is free software; you can redistribute it and/or
4
+ # modify it under the terms of the Ruby license defined in the
5
+ # LICENSE.txt file.
6
+ #
7
+ # Copyright (c) 2007 Joe Kutner and Matt Smith. All rights reserved.
8
+ #
9
+ # * Authors: Joe Kutner, Matt Smith
10
+ #
11
+
12
+ $LOAD_PATH << File.join(File.dirname(__FILE__), '../lib/')
13
+ require 'ruleby'
14
+ require 'fibonacci_rulebook'
15
+ class Fibonacci
16
+ def initialize(sequence,value=-1)
17
+ @sequence = sequence
18
+ @value = value
19
+ end
20
+
21
+ attr_reader :sequence
22
+ attr :value, true
23
+
24
+ def to_s
25
+ return '['+super + " sequence=" + @sequence.to_s + ",value=" + @value.to_s + ']'
26
+ end
27
+ end
28
+
29
+ include Ruleby
30
+
31
+ # This example is borrowed from the JBoss-Rule project.
32
+
33
+ # FACTS
34
+ fib1 = Fibonacci.new(150)
35
+
36
+ t1 = Time.new
37
+ engine :engine do |e|
38
+ FibonacciRulebookFerrari.new(e).rules
39
+ e.assert fib1
40
+ e.match
41
+ end
42
+ t2 = Time.new
43
+ diff = t2.to_f - t1.to_f
44
+ puts diff.to_s
@@ -0,0 +1,40 @@
1
+ # This file is part of the Ruleby project (http://ruleby.org)
2
+ #
3
+ # This application is free software; you can redistribute it and/or
4
+ # modify it under the terms of the Ruby license defined in the
5
+ # LICENSE.txt file.
6
+ #
7
+ # Copyright (c) 2007 Joe Kutner and Matt Smith. All rights reserved.
8
+ #
9
+ # * Authors: Joe Kutner, Matt Smith
10
+ #
11
+
12
+ $LOAD_PATH << File.join(File.dirname(__FILE__), '../lib/')
13
+ require 'ruleby'
14
+ require 'fibonacci_rulebook'
15
+ class Fibonacci
16
+ def initialize(sequence,value=-1)
17
+ @sequence = sequence
18
+ @value = value
19
+ end
20
+
21
+ attr_reader :sequence
22
+ attr :value, true
23
+
24
+ def to_s
25
+ return super + "::sequence=" + @sequence.to_s + ",value=" + @value.to_s
26
+ end
27
+ end
28
+
29
+ include Ruleby
30
+
31
+ # FACTS
32
+ fib1 = Fibonacci.new(1,1)
33
+ fib2 = Fibonacci.new(2,1)
34
+
35
+ engine :engine do |e|
36
+ FibonacciRulebook2.new(e).rules
37
+ e.assert fib1
38
+ e.assert fib2
39
+ e.match
40
+ end
@@ -0,0 +1,78 @@
1
+ # This file is part of the Ruleby project (http://ruleby.org)
2
+ #
3
+ # This application is free software; you can redistribute it and/or
4
+ # modify it under the terms of the Ruby license defined in the
5
+ # LICENSE.txt file.
6
+ #
7
+ # Copyright (c) 2007 Joe Kutner and Matt Smith. All rights reserved.
8
+ #
9
+ # * Authors: Joe Kutner, Matt Smith
10
+ #
11
+
12
+ $LOAD_PATH << File.join(File.dirname(__FILE__), '../lib/')
13
+ require 'ruleby'
14
+ require 'rule_helper'
15
+ class Fibonacci
16
+ def initialize(sequence,value=-1)
17
+ @sequence = sequence
18
+ @value = value
19
+ end
20
+
21
+ attr_reader :sequence
22
+ attr :value, true
23
+
24
+ def to_s
25
+ return super + "::sequence=" + @sequence.to_s + ",value=" + @value.to_s
26
+ end
27
+ end
28
+
29
+ include Ruleby::RuleHelper
30
+ #RULES
31
+ rules = []
32
+ # Bootstrap1
33
+ rules += rule :Bootstrap1, {:priority => 4},
34
+ [Fibonacci, :f, m.value == -1, m.sequence == 1 ] do |vars, engine|
35
+ vars[:f].value = 1
36
+ engine.modify vars[:f]
37
+ puts vars[:f].sequence.to_s + ' == ' + vars[:f].value.to_s
38
+ end
39
+
40
+ # Recurse
41
+ rules += rule :Recurse, {:priority => 3},
42
+ [Fibonacci, :f, m.value == -1] do |vars, engine|
43
+ f2 = Fibonacci.new(vars[:f].sequence - 1)
44
+ engine.assert f2
45
+ puts 'recurse for ' + f2.sequence.to_s
46
+ end
47
+
48
+ # Bootstrap2
49
+ rules += rule :Bootstrap2,
50
+ [Fibonacci, :f, m.value == -1 , m.sequence == 2] do |vars, engine|
51
+ vars[:f].value = 1
52
+ engine.modify vars[:f]
53
+ puts vars[:f].sequence.to_s + ' == ' + vars[:f].value.to_s
54
+ end
55
+
56
+ # Calculate
57
+ rules += rule :Calculate,
58
+ [Fibonacci,:f1, m.value.not== -1, {m.sequence => :s1}],
59
+ [Fibonacci,:f2, m.value.not== -1, {m.sequence( :s1, &c{ |s2,s1| s2 == s1 + 1 } ) => :s2}],
60
+ [Fibonacci,:f3, m.value == -1, m.sequence(:s2, &c{ |s3,s2| s3 == s2 + 1 }) ] do |vars, engine|
61
+ vars[:f3].value = vars[:f1].value + vars[:f2].value
62
+ engine.modify vars[:f3]
63
+ engine.retract vars[:f1]
64
+ puts vars[:f3].sequence.to_s + ' == ' + vars[:f3].value.to_s
65
+ end
66
+
67
+ # FACTS
68
+ fib1 = Fibonacci.new(150)
69
+
70
+ include Ruleby
71
+
72
+ engine :engine do |e|
73
+ rules.each do |r|
74
+ e.assert_rule r
75
+ end
76
+ e.assert fib1
77
+ e.match
78
+ end
@@ -0,0 +1,84 @@
1
+ # This file is part of the Ruleby project (http://ruleby.org)
2
+ #
3
+ # This application is free software; you can redistribute it and/or
4
+ # modify it under the terms of the Ruby license defined in the
5
+ # LICENSE.txt file.
6
+ #
7
+ # Copyright (c) 2007 Joe Kutner and Matt Smith. All rights reserved.
8
+ #
9
+ # * Authors: Joe Kutner, Matt Smith
10
+ #
11
+
12
+ require 'ruleby'
13
+
14
+ include Ruleby
15
+
16
+ # NOTE this example uses the LeTigre DSL syntax. In addition, its semantics are
17
+ # different from the other classes.
18
+ class FibonacciRulebook2 < Rulebook
19
+ MAX_SEQUENCE = 100
20
+ def rules
21
+ rule :Calculate, {:priority => 2 },
22
+ 'Fibonacci as :f1 where #value != -1 #&& #sequence as :s1',
23
+ 'Fibonacci as :f2 where #value != -1 #&& #sequence == #:s1 + 1 as :s2',
24
+ 'Fibonacci as :f3 where #value == -1 #&& #sequence == #:s2 + 1' do |vars|
25
+ retract vars[:f1]
26
+ retract vars[:f3]
27
+ if(vars[:f2].sequence == MAX_SEQUENCE)
28
+ retract vars[:f2]
29
+ else
30
+ f3 = Fibonacci.new(vars[:f2].sequence + 1, vars[:f1].value + vars[:f2].value)
31
+ assert f3
32
+ puts "#{f3.sequence} == #{f3.value}"
33
+ end
34
+ end
35
+
36
+ rule :Build, {:priority => 1},
37
+ 'Fibonacci as :f1 where #value != -1 #&& #sequence as :s1',
38
+ 'Fibonacci as :f2 where #value != -1 #&& #sequence == #:s1 + 1' do |vars|
39
+ f3 = Fibonacci.new(vars[:f2].sequence + 1, -1)
40
+ assert f3
41
+ end
42
+ end
43
+ end
44
+
45
+ # NOTE
46
+ # In this class we demonstrate the Ferrari DSL syntax.
47
+ class FibonacciRulebookFerrari < Rulebook
48
+ def rules
49
+ # Bootstrap1
50
+ rule :Bootstrap1, {:priority => 4},
51
+ [Fibonacci, :f, m.value == -1, m.sequence == 1 ] do |vars|
52
+ vars[:f].value = 1
53
+ modify vars[:f]
54
+ puts vars[:f].sequence.to_s + ' == ' + vars[:f].value.to_s
55
+ end
56
+
57
+ # Recurse
58
+ rule :Recurse, {:priority => 3},
59
+ [Fibonacci, :f, m.value == -1] do |vars|
60
+ f2 = Fibonacci.new(vars[:f].sequence - 1)
61
+ assert f2
62
+ puts 'recurse for ' + f2.sequence.to_s
63
+ end
64
+
65
+ # Bootstrap2
66
+ rule :Bootstrap2,
67
+ [Fibonacci, :f, m.value == -1 , m.sequence == 2] do |vars|
68
+ vars[:f].value = 1
69
+ modify vars[:f]
70
+ puts vars[:f].sequence.to_s + ' == ' + vars[:f].value.to_s
71
+ end
72
+
73
+ # Calculate
74
+ rule :Calculate,
75
+ [Fibonacci,:f1, m.value.not== -1, {m.sequence => :s1}],
76
+ [Fibonacci,:f2, m.value.not== -1, {m.sequence( :s1, &c{ |s2,s1| s2 == s1 + 1 } ) => :s2}],
77
+ [Fibonacci,:f3, m.value == -1, m.sequence(:s2, &c{ |s3,s2| s3 == s2 + 1 }) ] do |vars|
78
+ vars[:f3].value = vars[:f1].value + vars[:f2].value
79
+ modify vars[:f3]
80
+ retract vars[:f1]
81
+ puts vars[:f3].sequence.to_s + ' == ' + vars[:f3].value.to_s
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,45 @@
1
+ # This file is part of the Ruleby project (http://ruleby.org)
2
+ #
3
+ # This application is free software; you can redistribute it and/or
4
+ # modify it under the terms of the Ruby license defined in the
5
+ # LICENSE.txt file.
6
+ #
7
+ # Copyright (c) 2007 Joe Kutner and Matt Smith. All rights reserved.
8
+ #
9
+ # * Authors: Joe Kutner, Matt Smith
10
+ #
11
+
12
+ $LOAD_PATH << File.join(File.dirname(__FILE__), '../lib/')
13
+ require 'ruleby'
14
+
15
+ include Ruleby
16
+
17
+ class Message
18
+ def initialize(status,message)
19
+ @status = status
20
+ @message = message
21
+ end
22
+ attr :status, true
23
+ attr :message, true
24
+ end
25
+
26
+ class HelloWorldRulebook < Rulebook
27
+ def rules
28
+ rule [Message, :m, m.status == :HELLO] do |v|
29
+ puts v[:m].message
30
+ v[:m].message = "Goodbye world"
31
+ v[:m].status = :GOODBYE
32
+ modify v[:m]
33
+ end
34
+
35
+ rule [Message, :m, m.status == :GOODBYE] do |v|
36
+ puts v[:m].message
37
+ end
38
+ end
39
+ end
40
+
41
+ engine :engine do |e|
42
+ HelloWorldRulebook.new(e).rules
43
+ e.assert Message.new(:HELLO, 'Hello World')
44
+ e.match
45
+ end