deliveredtechnologies / rulebook

100% Java, Lambda Enabled, Lightweight Rules Engine with a Simple and Intuitive DSL
http://www.deliveredtechnologies.com
Apache License 2.0
721 stars 124 forks source link

When condition seems not working. A very easy question regarding with going through the example on the toturial #56

Closed sammr2 closed 7 years ago

sammr2 commented 7 years ago

Hi, I tried to do the simple Hello World example to see how the library generally work, but the result is a little bit funky. Here is the code I wrote: import com.deliveredtechnologies.rulebook.FactMap; import com.deliveredtechnologies.rulebook.NameValueReferableMap; import com.deliveredtechnologies.rulebook.Result; import com.deliveredtechnologies.rulebook.lang.RuleBookBuilder; import com.deliveredtechnologies.rulebook.model.RuleBook; import com.deliveredtechnologies.rulebook.lang.RuleBuilder; import com.deliveredtechnologies.rulebook.Rule;

import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.util.*; import java.lang.String;

class ruletest{ public static void main(String [] arg){ NameValueReferableMap factMap = new FactMap(); factMap.setValue("hello", "Hello"); factMap.setValue("world", " World"); RuleBook ruleBook = RuleBookBuilder.create().withResultType(Integer.class) .addRule(rule -> rule.withFactType(FactMap.class) .when(f -> f.containsKey("hello") ) .using("hello").then(t -> System.out.println(1) )) .addRule(rule -> rule.withFactType(FactMap.class) .when(f -> !f.containsKey("hello_2")) .then(t -> System.out.println(2) )) .build();

    ruleBook.run(factMap); //return 2. However it should be 1
    System.out.println(factMap.containsKey("hello")); //Return true
}

}

When I run the code, it seems that it is not working. the expected result should be 1 instead of 2. Thank you for the help. Wish you have a good day

Clayton7510 commented 7 years ago

I see what your issue is. By specifying FactMap as the fact type for each rule, you are telling each rule that only facts of type FactMap are to be made available to your rules. So, the first when() condition evaluates to false since there are no facts of type FactMap named "hello". If you specified the factType as String then the condition on the first rule would evaluate to true.

I have modified your example below to show how this would work.

class RuleTest {
  public static void main(String [] arg){
    NameValueReferableMap factMap = new FactMap();
    factMap.setValue("hello", "Hello");
    factMap.setValue("world", " World");
    RuleBook ruleBook = RuleBookBuilder.create().withResultType(Integer.class)
        .addRule(rule -> rule.withFactType(String.class) //you want facts of type String available here
            .when(f -> f.containsKey("hello") )
            .using("hello")
            .then(t -> System.out.println(1) ))
        .addRule(rule -> rule.withFactType(String.class) //you probably want facts of type String available here too
            .when(f -> !f.containsKey("hello_2"))
            .then(t -> System.out.println(2) ))
        .build();

    ruleBook.run(factMap); //this will print 1 followed by 2 since conditions on both rules will evaluate to true
    System.out.println(factMap.containsKey("hello")); //Return true
  }
}

To further illustrate how this works, I added another rule that only works with Integer facts.

class RuleTest{
  public static void main(String [] arg){
    NameValueReferableMap factMap = new FactMap();
    factMap.setValue("hello", "Hello");
    factMap.setValue("world", " World");
    factMap.setValue("magic number", 128);
    RuleBook ruleBook = RuleBookBuilder.create().withResultType(Integer.class)
        .addRule(rule -> rule.withFactType(String.class) //you want facts of type String available here
            .when(f -> f.containsKey("hello") )
            .using("hello")
            .then(t -> System.out.println(1) ))
        .addRule(rule -> rule.withFactType(String.class) //you probably want facts of type String available here too
            .when(f -> !f.containsKey("hello_2"))
            .then(t -> System.out.println(2) ))
        .addRule(rule -> rule.withFactType(Integer.class) //there's only one Integer fact, so only one fact is available to this rule
            //condition defaults to true if none exists
            .then(f -> System.out.println(f.getOne()))) //the value of the facts is the value of the single fact when only one exists
        .build();

    ruleBook.run(factMap); //this will print 1 followed by 2 followed by the value of magic number since conditions on both rules will evaluate to true
    System.out.println(factMap.containsKey("hello")); //Return true
  }
}

Of course, you could always make all facts available to a rule as I did with the last rule in this example.

class RuleTest{
  public static void main(String [] arg){
    NameValueReferableMap factMap = new FactMap();
    factMap.setValue("hello", "Hello");
    factMap.setValue("world", " World");
    factMap.setValue("magic number", 128);
    RuleBook ruleBook = RuleBookBuilder.create().withResultType(Integer.class)
        .addRule(rule -> rule.withFactType(String.class) //you want facts of type String available here
            .when(f -> f.containsKey("hello") )
            .using("hello")
            .then(t -> System.out.println(1) ))
        .addRule(rule -> rule.withFactType(String.class) //you probably want facts of type String available here too
            .when(f -> !f.containsKey("hello_2"))
            .then(t -> System.out.println(2) ))
        .addRule(rule -> rule.withNoSpecifiedFactType() //make all facts available to the rule
            //condition defaults to true if none exists
            .using("magic number") //restrict the facts available to the then() method to "magic number"
            .then(f -> System.out.println(f.getOne()))) //the value of the facts is the value of the single fact when only one exists
        .build();

    ruleBook.run(factMap); //this will print 1 followed by 2 followed by the value of magic number since conditions on both rules will evaluate to true
    System.out.println(factMap.containsKey("hello")); //Return true
  }
}
sammr2 commented 7 years ago

Thats very very clear, thank you for your help and time!!!!

Clayton7510 commented 7 years ago

Issue resolved in comment per OP.