ruleby 0.9.b4 → 0.9.b7

Sign up to get free protection for your applications and to get access to all the features.
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,148 @@
1
+ require 'spec_helper'
2
+
3
+ class A
4
+ attr :value, true
5
+ def initialize(v=nil); @value = v; end
6
+ end
7
+
8
+ include Ruleby
9
+
10
+ class ErrorsRulebook < Rulebook
11
+ def rules_with_method_that_doesnt_exist
12
+ rule [A, :a, m.foobar == 'quack'] do |v|
13
+ assert Success.new
14
+ end
15
+ end
16
+
17
+ def rules_that_raise_errors
18
+ rule [A, :a, m.value(&c{|v| raise ":(" if v == 42; true})] do |v|
19
+ assert Success.new
20
+ end
21
+ end
22
+
23
+ end
24
+
25
+ describe Ruleby::Core::Engine do
26
+
27
+ describe "#errors" do
28
+ context "rules_with_method_that_doesnt_exist" do
29
+ subject do
30
+ engine :engine do |e|
31
+ ErrorsRulebook.new(e).rules_with_method_that_doesnt_exist
32
+ end
33
+ end
34
+
35
+ context "with one A" do
36
+ before do
37
+ subject.assert A.new
38
+ subject.match
39
+ end
40
+
41
+ it "should accumulate an error" do
42
+ r = subject.retrieve Success
43
+ r.size.should == 0
44
+
45
+ errors = subject.errors
46
+ errors.should_not be_nil
47
+ errors.size.should == 1
48
+ errors[0].type.should == :no_method
49
+ errors[0].details[:method].should == :foobar
50
+ errors[0].details[:object].should match /#<A:(.+)>/
51
+ subject.clear_errors
52
+
53
+ subject.errors.should == []
54
+ end
55
+ end
56
+
57
+ context "with one A that quacks" do
58
+ before do
59
+ a = A.new
60
+
61
+ # define a method on the instance (not on the class)
62
+ def a.foobar
63
+ "quack"
64
+ end
65
+
66
+ subject.assert a
67
+ subject.assert A.new
68
+ subject.match
69
+ end
70
+
71
+ it "should accumulate one error" do
72
+ r = subject.retrieve Success
73
+ r.size.should == 1
74
+
75
+ errors = subject.errors
76
+ errors.should_not be_nil
77
+ errors.size.should == 1
78
+ errors[0].type.should == :no_method
79
+ errors[0].details[:method].should == :foobar
80
+ errors[0].details[:object].should match /#<A:(.+)>/
81
+ subject.clear_errors
82
+ end
83
+ end
84
+ end
85
+
86
+
87
+ context "rules_that_raise_errors" do
88
+ subject do
89
+ engine :engine do |e|
90
+ ErrorsRulebook.new(e).rules_that_raise_errors
91
+ end
92
+ end
93
+
94
+ context "with one A where value==42" do
95
+ before do
96
+ a = A.new
97
+ a.value = 42
98
+ subject.assert a
99
+ subject.match
100
+ end
101
+
102
+ it "should accumulate an error" do
103
+ r = subject.retrieve Success
104
+ r.size.should == 0
105
+
106
+ errors = subject.errors
107
+ errors.should_not be_nil
108
+ errors.size.should == 1
109
+ errors[0].type.should == :proc_call
110
+ errors[0].details[:message].should == ':('
111
+ errors[0].details[:object].should match /#<A:(.+)>/
112
+ errors[0].details[:method].should == :value
113
+ errors[0].details[:value].should == "42"
114
+ subject.clear_errors
115
+ end
116
+ end
117
+
118
+ context "with one A where value==42, and one A where value==0" do
119
+ before do
120
+ a1 = A.new
121
+ a1.value = 42
122
+
123
+ a2 = A.new
124
+ a2.value = 0
125
+
126
+ subject.assert a1
127
+ subject.assert a2
128
+ subject.match
129
+ end
130
+
131
+ it "should accumulate one error" do
132
+ r = subject.retrieve Success
133
+ r.size.should == 1
134
+
135
+ errors = subject.errors
136
+ errors.should_not be_nil
137
+ errors.size.should == 1
138
+ errors[0].type.should == :proc_call
139
+ errors[0].details[:message].should == ':('
140
+ errors[0].details[:object].should match /#<A:(.+)>/
141
+ errors[0].details[:method].should == :value
142
+ errors[0].details[:value].should == "42"
143
+ subject.clear_errors
144
+ end
145
+ end
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ class A
4
+
5
+ end
6
+
7
+ include Ruleby
8
+
9
+ class FerrariRulebook < Rulebook
10
+ def rules
11
+ rule [A] do |v|
12
+ assert Success.new
13
+ end
14
+ end
15
+ end
16
+
17
+ describe Ruleby::Core::Engine do
18
+
19
+ subject do
20
+ engine :engine do |e|
21
+ FerrariRulebook.new(e).rules
22
+ end
23
+ end
24
+
25
+ describe "simple case" do
26
+ context "with one A" do
27
+ before do
28
+ subject.assert A.new
29
+ subject.match
30
+ end
31
+
32
+ it "should retrieve Success" do
33
+ s = subject.retrieve Success
34
+ s.should_not be_nil
35
+ s.size.should == 1
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,199 @@
1
+ require 'spec_helper'
2
+
3
+ class FuncFact
4
+ attr :value, true
5
+ attr :times, true
6
+ def initialize(v=nil); @value = v; @times = 0; end
7
+ end
8
+
9
+ include Ruleby
10
+
11
+ class FunctionsRulebook < Rulebook
12
+ def rules_with_simple_function
13
+ rule [FuncFact, :a, f("b", c{|a, b| b == "b"})] do |v|
14
+ assert Success.new
15
+ end
16
+ end
17
+
18
+ def rules_with_function_testing_self(arg)
19
+ rule [FuncFact, :a, f(arg, c{|a, b| a.value == b})] do |v|
20
+ assert Success.new
21
+ end
22
+ end
23
+
24
+ def rules_that_share_a_function
25
+ func = c{|a, b| a.times += 1; b == "foobar"}
26
+
27
+ rule [FuncFact, :a, m.value > 1, f("foobar", func)] do |v|
28
+ assert Success.new
29
+ end
30
+
31
+ rule [FuncFact, :a, m.value > 2, f("foobar", func)] do |v|
32
+ assert Success.new
33
+ end
34
+ end
35
+
36
+ def rules_with_many_args_function
37
+ rule [FuncFact, :a, f([1, 2, 3, 4], c{|a, b, c, d, e| b < e})] do |v|
38
+ assert Success.new
39
+ end
40
+ end
41
+
42
+ def rules_with_no_args_function
43
+ rule [FuncFact, :a, f(c{|a| !a.nil?})] do |v|
44
+ assert Success.new
45
+ end
46
+ end
47
+ end
48
+
49
+ describe Ruleby::Rulebook do
50
+
51
+ describe "#f" do
52
+ context "rules_with_simple_function" do
53
+ subject do
54
+ engine :engine do |e|
55
+ FunctionsRulebook.new(e).rules_with_simple_function
56
+ end
57
+ end
58
+
59
+ context "with one FuncFact" do
60
+ before do
61
+ subject.assert FuncFact.new
62
+ subject.match
63
+ end
64
+
65
+ it "should match once" do
66
+ r = subject.retrieve Success
67
+ r.size.should == 1
68
+ subject.errors.should == []
69
+ end
70
+ end
71
+ end
72
+
73
+ context "rules_with_function_testing_self(:foo)" do
74
+ subject do
75
+ engine :engine do |e|
76
+ FunctionsRulebook.new(e).rules_with_function_testing_self(:foo)
77
+ end
78
+ end
79
+
80
+ context "with one FuncFact" do
81
+ before do
82
+ subject.assert FuncFact.new(:foo)
83
+ subject.match
84
+ end
85
+
86
+ it "should match once" do
87
+ r = subject.retrieve Success
88
+ r.size.should == 1
89
+ subject.errors.should == []
90
+ end
91
+ end
92
+ end
93
+
94
+ context "rules_with_function_testing_self(:bar)" do
95
+ subject do
96
+ engine :engine do |e|
97
+ FunctionsRulebook.new(e).rules_with_function_testing_self(:bar)
98
+ end
99
+ end
100
+
101
+ context "with one FuncFact" do
102
+ before do
103
+ subject.assert FuncFact.new(:foo)
104
+ subject.match
105
+ end
106
+
107
+ it "should not match " do
108
+ r = subject.retrieve Success
109
+ r.size.should == 0
110
+ subject.errors.should == []
111
+ end
112
+ end
113
+ end
114
+
115
+ context "rules_that_share_a_function" do
116
+ subject do
117
+ engine :engine do |e|
118
+ FunctionsRulebook.new(e).rules_that_share_a_function
119
+ end
120
+ end
121
+
122
+ context "with one FuncFact" do
123
+ before do
124
+ @f = FuncFact.new(3)
125
+ subject.assert @f
126
+ subject.match
127
+ end
128
+
129
+ it "should match, node should be shared, function should be evaled once" do
130
+ r = subject.retrieve Success
131
+ r.size.should == 2
132
+ subject.errors.should == []
133
+
134
+ @f.times.should == 1
135
+
136
+ subject.retract r[0]
137
+ subject.retract r[1]
138
+ subject.retract @f
139
+ subject.match
140
+
141
+ r = subject.retrieve Success
142
+ r.size.should == 0
143
+ subject.errors.should == []
144
+
145
+ subject.assert @f
146
+ subject.match
147
+
148
+ r = subject.retrieve Success
149
+ r.size.should == 2
150
+ subject.errors.should == []
151
+
152
+ @f.times.should == 2
153
+ end
154
+ end
155
+ end
156
+
157
+ context "rules_with_many_args_function" do
158
+ subject do
159
+ engine :engine do |e|
160
+ FunctionsRulebook.new(e).rules_with_many_args_function
161
+ end
162
+ end
163
+
164
+ context "with one FuncFact" do
165
+ before do
166
+ subject.assert FuncFact.new
167
+ subject.match
168
+ end
169
+
170
+ it "should match once" do
171
+ r = subject.retrieve Success
172
+ r.size.should == 1
173
+ subject.errors.should == []
174
+ end
175
+ end
176
+ end
177
+
178
+ context "rules_with_no_args_function" do
179
+ subject do
180
+ engine :engine do |e|
181
+ FunctionsRulebook.new(e).rules_with_no_args_function
182
+ end
183
+ end
184
+
185
+ context "with one FuncFact" do
186
+ before do
187
+ subject.assert FuncFact.new
188
+ subject.match
189
+ end
190
+
191
+ it "should match once" do
192
+ r = subject.retrieve Success
193
+ r.size.should == 1
194
+ subject.errors.should == []
195
+ end
196
+ end
197
+ end
198
+ end
199
+ end
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+
3
+ class HelloFact
4
+ attr :value, true
5
+ def initialize(v=nil); @value = v; end
6
+ end
7
+
8
+ include Ruleby
9
+
10
+ class HelloRulebook < Rulebook
11
+ def rules
12
+ rule [HelloFact, :h] do
13
+ assert Success.new
14
+ end
15
+ end
16
+ end
17
+
18
+ describe Ruleby::Core::Engine do
19
+ subject do
20
+ engine :engine do |e|
21
+ HelloRulebook.new(e).rules
22
+ end
23
+ end
24
+
25
+ before do
26
+ subject.assert HelloFact.new
27
+ subject.match
28
+ end
29
+
30
+ it "should have matched" do
31
+ subject.errors.should == []
32
+ subject.retrieve(Success).size.should == 1
33
+ end
34
+ end
@@ -0,0 +1,53 @@
1
+ require 'spec_helper'
2
+
3
+ class NodeShareFact
4
+ attr_reader :times
5
+
6
+ def initialize(v=nil); @value = v; @times = 0; end
7
+
8
+ def value
9
+ @times += 1
10
+ @value
11
+ end
12
+ end
13
+
14
+ include Ruleby
15
+
16
+ class NodeShareRulebook < Rulebook
17
+ def rules
18
+ rule [NodeShareFact, :n, m.value == 5] do
19
+ assert Success.new
20
+ end
21
+
22
+ rule [NodeShareFact, :n, m.value == 5] do
23
+ assert Success.new
24
+ end
25
+
26
+ rule [NodeShareFact, :n, m.value == 6] do
27
+ assert Success.new
28
+ end
29
+ end
30
+ end
31
+
32
+ describe Ruleby::Core::Engine do
33
+
34
+ describe "node sharing" do
35
+ subject do
36
+ engine :engine do |e|
37
+ NodeShareRulebook.new(e).rules
38
+ end
39
+ end
40
+
41
+ before do
42
+ @f = NodeShareFact.new(5)
43
+ subject.assert @f
44
+ subject.match
45
+ end
46
+
47
+ it "should have matched" do
48
+ @f.times.should == 1
49
+ subject.errors.should == []
50
+ subject.retrieve(Success).size.should == 2
51
+ end
52
+ end
53
+ end