A squeaky rule engine
Following on from the weekends simple java rule engine, I thought I'd give a squeak implementation a try. Following a similar API I have two classes: RuleManager and RuleSet, as initially defined as:
The RuleManager contains a dictionary of rules, with a simple wrapper to add a rule:Object subclass: #RuleManager instanceVariableNames: 'ruleMap' classVariableNames: '' poolDictionaries: '' category: 'Talios' Object subclass: #RuleSet instanceVariableNames: 'rules' classVariableNames: '' poolDictionaries: '' category: 'Kernel-Objects'
This is pretty straight forward, so lets move over to the actual RuleSet. Unlike the earlier java implementation which used instances of the Rule interface as assertion definitions, we'll simply use block instances. A simple wrapper method is provided to add these to the rule:at: name put: rule "Store a map under the define named" ruleMap at: name put: rule
Putting these together we can define a rule with:assert: aBlock "A rule is made up with a series of assertions, defined as blocks" rules addLast: aBlock
Here we first create a RuleManager and Ruleset and start adding assertions, finally we add the rule into named slot. Now we want to actually use it...ruleManager := RuleManager new. nameIsMark := RuleSet new. nameIsMark assert: [:x| x = 'mark']. ruleManager at: 'nameIsMark' put: nameIsMark.
Here we have a simplistic message that conditionally executes a block of code if the rule evaluated to true.ruleManager if: 'nameIsMark' with: 'amrk' do: [ Transcript show: 'rule passed'. ]
Now we have the "guts" (if we can call it that) of the rule evaluation loop. RuleManager>>if simply pulls out the named RuleSet, and if it exists, calls RuleSet>>check with the value and block. RuleSet simply iterates over each defined block. If everything returns true, the block is executed. Both this and my earlier java rule system are extremely simplistic, but they'd both be good for general purpose rule checking.RuleManager>>if: name with: value do: aBlock "If the named rule passes all assertions, evaluate the block." (ruleMap at: name) ifNotNilDo: [:rule | (rule check: value) ifTrue: [aBlock value]] RuleSet>>check: value "Run each assertion against the value, if anything returns false, the rule fails." rules do: [:assertion| (assertion value: value) ifFalse: [^false]]. ^true
Thanks Mark - this is a great starting point for a rule system I want to implement in order to model animal behaviour. With Smalltalk, Squeak, the Bots Inc book and your posting I feel I have a great start provided for me. Thanks for blogging - apart from talented you're very generous. Dave (mailto:david.urquhart@hotmail.com)