ruler 1.0.0 → 1.2.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.
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/bin/example.rb +1 -1
- data/lib/ruler.rb +23 -8
- data/spec/ruler_spec.rb +44 -0
- metadata +4 -4
data/Rakefile
CHANGED
@@ -16,7 +16,7 @@ Jeweler::Tasks.new do |gem|
|
|
16
16
|
gem.homepage = "http://github.com/BlueFrogGaming/ruler"
|
17
17
|
gem.license = "MIT"
|
18
18
|
gem.summary = %Q{Ruby DSL to help with rules and facts}
|
19
|
-
gem.description = %Q{
|
19
|
+
gem.description = %Q{Ruler module implements a DSL that makes it easy to write a set of facts and rules. If you have some tricky conditional logic, Ruler can help clear it up.}
|
20
20
|
gem.email = "kognate@gmail.com"
|
21
21
|
gem.authors = ["Joshua Smith"]
|
22
22
|
# Include your dependencies below. Runtime dependencies are required when using your gem,
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.2.0
|
data/bin/example.rb
CHANGED
data/lib/ruler.rb
CHANGED
@@ -8,7 +8,13 @@
|
|
8
8
|
# Copyright:: (c) 2011 Blue Frog Gaming, All Rights Reserved
|
9
9
|
# License:: This file has no public license.
|
10
10
|
|
11
|
-
class
|
11
|
+
class RulerError < StandardError
|
12
|
+
end
|
13
|
+
|
14
|
+
class BadDefaultRule < RulerError
|
15
|
+
end
|
16
|
+
|
17
|
+
class BadNotCall < RulerError
|
12
18
|
end
|
13
19
|
|
14
20
|
module Ruler
|
@@ -73,19 +79,28 @@ module Ruler
|
|
73
79
|
# will never be used.
|
74
80
|
def fact name, dval = nil, &blk
|
75
81
|
if dval.nil?
|
76
|
-
Thread.current[:working_memory][name] = yield
|
82
|
+
Thread.current[:working_memory][name] = {:value => yield }
|
77
83
|
else
|
78
|
-
Thread.current[:working_memory][name] = dval
|
84
|
+
Thread.current[:working_memory][name] = {:value => dval }
|
79
85
|
end
|
80
86
|
end
|
81
87
|
|
88
|
+
# a dynamic_fact is evaulated every time the fact is checked. Unlike a normal fact, which
|
89
|
+
# is only evaluated once, dynamic facts are evaluated once for each rule they appear in
|
90
|
+
def dynamic_fact name, &blk
|
91
|
+
Thread.current[:working_memory][name] = {:transient => true, :block => blk }
|
92
|
+
end
|
82
93
|
|
83
|
-
# allows for a fact to be NOT another fact.
|
94
|
+
# allows for a fact to be NOT another fact. notf cannot be used with a dynamic_fact
|
84
95
|
# for example:
|
85
96
|
# fact :one, 10 == 10
|
86
97
|
# fact :notfone, not(:one)
|
87
98
|
def notf name
|
88
|
-
|
99
|
+
if Thread.current[:working_memory][name][:transient]
|
100
|
+
raise BadNotCall.new("Cannot call notf on dynamic fact")
|
101
|
+
else
|
102
|
+
not(Thread.current[:working_memory][name][:value])
|
103
|
+
end
|
89
104
|
end
|
90
105
|
|
91
106
|
# a rule takes a list of fact names and a block. Rules are evaluated in the order
|
@@ -101,7 +116,7 @@ module Ruler
|
|
101
116
|
# there is no check to see if fact names are valid, and facts can be (re)defined
|
102
117
|
#inside of rules. Fact names are false if they are not defined.
|
103
118
|
def rule vlist,docstr = nil,&blk
|
104
|
-
dbg = lambda {|va| puts "|=-\t#{va} = #{Thread.current[:working_memory][va]}" }
|
119
|
+
dbg = lambda {|va| puts Thread.current[:working_memory][va][:transient].nil? ? "|=-\t#{va} = #{Thread.current[:working_memory][va][:value]}" : "|=-\t#{va} = #{Thread.current[:working_memory][va][:block].call()}" }
|
105
120
|
if @DEBUG
|
106
121
|
puts "---------------------------------------"
|
107
122
|
puts vlist.join(" & ")
|
@@ -112,8 +127,8 @@ module Ruler
|
|
112
127
|
if Thread.current[:singletary] && Thread.current[:rulematched]
|
113
128
|
Thread.current[:rulematched]
|
114
129
|
else
|
115
|
-
|
116
|
-
Thread.current[:rulematched] = if vlist.inject(true) {|k,v| k ? k &&
|
130
|
+
conditional_call = lambda {|n| Thread.current[:working_memory][n][:transient].nil? ? Thread.current[:working_memory][n][:value] : Thread.current[:working_memory][n][:block].call() }
|
131
|
+
Thread.current[:rulematched] = if vlist.inject(true) {|k,v| k ? k && conditional_call.call(v) : false }
|
117
132
|
yield
|
118
133
|
end
|
119
134
|
end
|
data/spec/ruler_spec.rb
CHANGED
@@ -137,6 +137,39 @@ I think.
|
|
137
137
|
end
|
138
138
|
end
|
139
139
|
end
|
140
|
+
|
141
|
+
def test_ten
|
142
|
+
#@DEBUG = true
|
143
|
+
ruleset do
|
144
|
+
dynamic_fact :one do
|
145
|
+
self.checking_method
|
146
|
+
end
|
147
|
+
|
148
|
+
fact :wrong, false
|
149
|
+
|
150
|
+
rule [:one, :wrong] do
|
151
|
+
false
|
152
|
+
end
|
153
|
+
|
154
|
+
rule [:one, :one, :wrong] do
|
155
|
+
false
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def test_eleven
|
161
|
+
ruleset do
|
162
|
+
dynamic_fact :one do
|
163
|
+
true
|
164
|
+
end
|
165
|
+
|
166
|
+
fact :two, notf(:one)
|
167
|
+
|
168
|
+
default_rule do
|
169
|
+
true
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
140
173
|
end
|
141
174
|
|
142
175
|
describe Rules do
|
@@ -187,5 +220,16 @@ describe Rules do
|
|
187
220
|
lambda { r.test_nine.should}.should raise_error
|
188
221
|
end
|
189
222
|
|
223
|
+
it "should call dynamic rules each time they are evaluated" do
|
224
|
+
r = Rules.new
|
225
|
+
r.expects(:checking_method).times(3).returns(true)
|
226
|
+
r.test_ten.should be(nil)
|
227
|
+
end
|
228
|
+
|
229
|
+
it "should throw an exception if a dyanmic fact is declared in a notf" do
|
230
|
+
r = Rules.new
|
231
|
+
lambda { r.test_eleven }.should raise_error
|
232
|
+
end
|
233
|
+
|
190
234
|
end
|
191
235
|
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruler
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 31
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 1
|
8
|
+
- 2
|
8
9
|
- 0
|
9
|
-
|
10
|
-
version: 1.0.0
|
10
|
+
version: 1.2.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Joshua Smith
|
@@ -94,7 +94,7 @@ dependencies:
|
|
94
94
|
name: mocha
|
95
95
|
requirement: *id005
|
96
96
|
type: :development
|
97
|
-
description:
|
97
|
+
description: Ruler module implements a DSL that makes it easy to write a set of facts and rules. If you have some tricky conditional logic, Ruler can help clear it up.
|
98
98
|
email: kognate@gmail.com
|
99
99
|
executables:
|
100
100
|
- example.rb
|