A tiny rule engine.
Ruli is the tiny rule engine behind the Android library Integrated Rating Request - a polite way to ask for ratings.
Ruli is available on Maven jCenter.
If you are using Maven for compilation you can declare the library as a dependency.
<dependency>
<groupId>net.mediavrog</groupId>
<artifactId>ruli</artifactId>
<version>1.1.0</version>
</dependency>
compile 'net.mediavrog:ruli:1.1.0'
Ruli is a tiny rule engine for the evaluation of simple rules. If consists of a couple of classes to describe and evaluate rules and sets of rules:
Rule
: Abstract rule withevaluate
interface to provide arbitrary results.RuleSet
: Evaluate groups of rules with logical AND or OR. Implements theRule
interface to allow nesting.RuleEngine
: A slightly enhancedRuleSet
, which saves the last result and can notify a listener upon result availability.Value
: Boxed value to support dynamic generation e.g. by querying a persistence layer. UseValue.as
shorthand to box a simple variable.SimpleRule
: A simple left-right hand comparison. TakesValue
s as arguments and aSimpleRule.Comparator
.SimpleRule.Comparator
: An enum for common comparison types:EQ
- equalNEQ
- not equalGT
- greater thanGT_EQ
- greater than or equalLT
- lesser thanLT_EQ
- lesser than or equal
Ruli promotes immutability to support thread-safety. It doesn't make assumptions about your system, so use Threads when necessary if you expect your custom rules to take long time to evaluate.
Ruli is open to PR's. Please add tests for any code provided. Thanks!
SimpleRule trueRule1 = new SimpleRule<Boolean>(true, SimpleRule.Comparator.EQ, true);
SimpleRule trueRule2 = new SimpleRule<Boolean>(true, SimpleRule.Comparator.EQ, true);
SimpleRule falseRule1 = new SimpleRule<Boolean>(true, SimpleRule.Comparator.EQ, false);
RuleSet set = new RuleSet.Builder(RuleSet.Mode.OR)
.addRule(falseRule1)
.addRule(trueRule1)
.addRule(trueRule2)
.build();
assertTrue(set.evaluate());
SimpleRule trueRule1 = new SimpleRule<Boolean>(true, SimpleRule.Comparator.EQ, true);
SimpleRule trueRule2 = new SimpleRule<Boolean>(true, SimpleRule.Comparator.EQ, true);
SimpleRule falseRule1 = new SimpleRule<Boolean>(true, SimpleRule.Comparator.EQ, false);
RuleSet set = new RuleSet.Builder(RuleSet.Mode.AND)
.addRule(trueRule1)
.addRule(falseRule1)
.addRule(trueRule2)
.build();
assertFalse(set.evaluate());
SimpleRule trueRule1 = new SimpleRule<Boolean>(true, SimpleRule.Comparator.EQ, true);
SimpleRule trueRule2 = new SimpleRule<Boolean>(true, SimpleRule.Comparator.EQ, true);
SimpleRule falseRule1 = new SimpleRule<Boolean>(true, SimpleRule.Comparator.EQ, false);
RuleSet trueSet = new RuleSet.Builder(RuleSet.Mode.OR)
.addRule(falseRule1)
.addRule(trueRule1)
.addRule(trueRule2)
.build();
SimpleRule falseRule2 = new SimpleRule<Boolean>(true, SimpleRule.Comparator.EQ, false);
RuleSet set = new RuleSet.Builder(RuleSet.Mode.AND)
.addRule(trueSet)
.addRule(falseRule2)
.build();
assertFalse(set.evaluate());
// fake data setup
class WeatherApi {
public float getTemp() {
return 30.4f;
}
}
Integer iceEatenToday = 2;
final Calendar cal = Calendar.getInstance();
cal.set(Calendar.DAY_OF_WEEK, Calendar.SATURDAY);
// the rules
RuleSet eatingIceTime = new RuleSet.Builder()
// simple int comparison
.addRule(new SimpleRule<Integer>(iceEatenToday, SimpleRule.Comparator.LT, 5))
// float compared with return value of other object
.addRule(new SimpleRule<Float>(new Value<Float>() {
@Override
public Float get() {
return new WeatherApi().getTemp();
}
}, SimpleRule.Comparator.GT_EQ, 30f))
// custom evaluation logic
.addRule(new Rule() {
@Override
public boolean evaluate() {
int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
return dayOfWeek == Calendar.SATURDAY || dayOfWeek == Calendar.SUNDAY;
}
})
.build();
assertTrue("Eh? But I'm still hungry!", eatingIceTime.evaluate()); // *yum* moar!