Coder Social home page Coder Social logo

grool's Introduction

grool's People

Contributors

newm4n avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

grool's Issues

Add support for nested structs functions in rules

Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
This rule not work

rule UserTestRule4 "test 3"  salience 10{
					when
					  User.Auth.GetEmail() == "[email protected]"
					then
					  User.Name = "FromRuleScope4";
 					  Retract("UserTestRule4");
				}

returns error

Failed testing condition for rule : UserTestRule4. Got error error while fetching function GetEmail() parameter types. Got function GetEmail not found

Describe the solution you'd like
Add possibility to use nested struct funcs

Funcs called in "then" section, that return nothing not work

Describe the bug
Function called in "then" section not work

To Reproduce
Steps to reproduce the behavior:
use this rule

rule UserTestRule3 "test 3"  salience 10{
					when
					  User.GetName() == "Watson"
					then
					  User.SetName("FromRuleScope3");
 					  Retract("UserTestRule3");
				}

and this object

type User struct {
	Name string
}

func (u *User) GetName() string {
	return u.Name
}

func (u *User) SetName(name string) {
	u.Name = name
}

returns

level=error msg="Failed execution rule : UserTestRule3. Got error no assignment or function call to evaluate"

Expected behavior
Success call function in "then" section

Additional content
It only works if func return any value, like this

func (u *User) SetName(name string)string {
	u.Name = name
	return name
}

and rule then looks like this

rule UserTestRule3 "test 3"  salience 10{
					when
					  User.GetName() == "Watson"
					then
					  Log(User.SetName("FromRuleScope3"));
 					  Retract("UserTestRule3");
				}

Panic if use func that return interface in "where" clause

Describe the bug
Panic if use func that return interface in "where" clause

To Reproduce

package examples

import (
	"github.com/newm4n/grool/builder"
	"github.com/newm4n/grool/context"
	"github.com/newm4n/grool/engine"
	"github.com/newm4n/grool/model"
	"github.com/newm4n/grool/pkg"
	"testing"
)

const (
	Rule81 = `
rule UserTestRule8 "test 8"  salience 10{
	when
	  User.GetParam() == "string_param"
	then
	  User.SetName("FromRule");
	  Retract("UserTestRule8");
}
`
	Rule82 = `
rule UserTestRule8 "test 8"  salience 10{
	when
	  User.GetParam() == 42
	then
	  User.SetName("FromRule");
	  Retract("UserTestRule8");
}
`
)

type AUserIssue8 struct {
	Name  string
	Param interface{}
	Age   int
}

func (u *AUserIssue8) GetName() string {
	return u.Name
}

func (u *AUserIssue8) GetParam() interface{} {
	return u.Param
}

func (u *AUserIssue8) SetName(name interface{}) {
	u.Name = name.(string)
}

func TestMethodCall_Issue8_1(t *testing.T) {
	user := &AUserIssue8{
		Name: "Watson",
		Age:  7,
		Param: "string_param",
	}

	dataContext := context.NewDataContext()
	err := dataContext.Add("User", user)
	if err != nil {
		t.Fatal(err)
	}

	knowledgeBase := model.NewKnowledgeBase()
	ruleBuilder := builder.NewRuleBuilder(knowledgeBase)

	err = ruleBuilder.BuildRuleFromResource(pkg.NewBytesResource([]byte(Rule81)))
	if err != nil {
		t.Log(err)
	} else {
		eng1 := &engine.Grool{MaxCycle: 5}
		err := eng1.Execute(dataContext, knowledgeBase)
		if err != nil {
			t.Fatal(err)
		}
		if user.GetName() != "FromRule" {
			t.Errorf("User should be FromRule but %s", user.GetName())
		}
	}
}

func TestMethodCall_Issue8_2(t *testing.T) {
	user := &AUserIssue8{
		Name: "Watson",
		Age:  7,
		Param: 42,
	}

	dataContext := context.NewDataContext()
	err := dataContext.Add("User", user)
	if err != nil {
		t.Fatal(err)
	}

	knowledgeBase := model.NewKnowledgeBase()
	ruleBuilder := builder.NewRuleBuilder(knowledgeBase)

	err = ruleBuilder.BuildRuleFromResource(pkg.NewBytesResource([]byte(Rule82)))
	if err != nil {
		t.Log(err)
	} else {
		eng1 := &engine.Grool{MaxCycle: 5}
		err := eng1.Execute(dataContext, knowledgeBase)
		if err != nil {
			t.Fatal(err)
		}
		if user.GetName() != "FromRule" {
			t.Errorf("User should be FromRule but %s", user.GetName())
		}
	}
}

=== RUN   TestMethodCall_Issue8
--- FAIL: TestMethodCall_Issue8 (0.00s)
panic: reflect: call of reflect.Value.Type on zero Value [recovered]
	panic: reflect: call of reflect.Value.Type on zero Value

goroutine 19 [running]:
testing.tRunner.func1(0xc0000e4a00)
	/usr/local/go/src/testing/testing.go:874 +0x3a3
panic(0x866820, 0xc00023fa80)
	/usr/local/go/src/runtime/panic.go:679 +0x1b2
reflect.Value.Type(0x0, 0x0, 0x0, 0x98, 0x0)
	/usr/local/go/src/reflect/value.go:1877 +0x166
github.com/newm4n/grool/model.(*Predicate).Evaluate(0xc0001f7600, 0xc00011d920, 0x1, 0x0, 0xc0002281b0, 0xc000195c60)
	/home/id/hdd/go-nogopath/src/github.com/newm4n/grool/model/Predicate.go:104 +0x1845
github.com/newm4n/grool/model.(*Expression).Evaluate(0xc0001f75c0, 0x0, 0xd11df0, 0x861760, 0xc000256008, 0xc00011d950)
	/home/id/hdd/go-nogopath/src/github.com/newm4n/grool/model/Expression.go:53 +0x460
github.com/newm4n/grool/model.(*WhenScope).ExecuteWhen(0xc00023f760, 0x410763, 0xc000195e60, 0xd11df0)
	/home/id/hdd/go-nogopath/src/github.com/newm4n/grool/model/WhenScope.go:41 +0x32
github.com/newm4n/grool/model.(*RuleEntry).CanExecute(0xc0000a7e60, 0xc00011d950, 0xc000195e60, 0xd11df0)
	/home/id/hdd/go-nogopath/src/github.com/newm4n/grool/model/RuleEntry.go:48 +0x39
github.com/newm4n/grool/engine.(*Grool).Execute(0xc000195f08, 0xc00011d920, 0xc0000a5650, 0x0, 0x0)
	/home/id/hdd/go-nogopath/src/github.com/newm4n/grool/engine/GroolEngine.go:58 +0x1c6
github.com/newm4n/grool/examples.TestMethodCall_Issue8(0xc0000e4a00)
	/home/id/hdd/go-nogopath/src/github.com/newm4n/grool/examples/Issue8_test.go:63 +0x337
testing.tRunner(0xc0000e4a00, 0x918a08)
	/usr/local/go/src/testing/testing.go:909 +0xc9
created by testing.(*T).Run
	/usr/local/go/src/testing/testing.go:960 +0x350

Process finished with exit code 1

Expected behavior
Rule works correctly

Can not set string value, if func receives interface

Describe the bug
Can not set string value, if func receives interface

To Reproduce
use rule like that

rule UserCheckSuccess "test"  salience 10{
    when
      User.Age == 1
    then
      User.SetName("FromRule");
}

use struct

type User struct {
	Id      int
	Name    string
}

func (u *User) SetName(name interface{}) {
	u.Name = name.(string)
}

Expected behavior
Func exec normally, and set param to object

Additional context

time="2019-11-01T15:10:38+03:00" level=error msg="Failed execution rule : UserCheckSuccess. Got error invalid argument types for function SetName(). argument #0, require interface but string"

when call Custom function, runtime err: invalid memory address or nil pointer dereference

code:

package main

import (
	"fmt"
	"github.com/newm4n/grool/builder"
	"github.com/newm4n/grool/context"
	"github.com/newm4n/grool/engine"
	"github.com/newm4n/grool/model"
	"github.com/newm4n/grool/pkg"
	"testing"
)


const (rule2  = `
rule AgeNameCheck "test" {
    when
		Pogo.GetStringLength("9999") > 0 
    then
		Log(User.Name);
}
`
)

type MyPoGo struct {
}

func (p *MyPoGo) GetStringLength(sarg string) int {
	return len(sarg)
}

type User struct {
	Name string
	Age int
	Male bool
}

func testMyRule(t *testing.T){
	user := &User{
		Name: "Calo",
		Age:  0,
		Male: true,
	}

	dataContext := context.NewDataContext()
	dataContext.Add("User", user)
	dataContext.Add("Pogo", &MyPoGo{})

	//εˆε§‹εŒ–θ§„εˆ™εΌ•ζ“Ž
	knowledgeBase := model.NewKnowledgeBase()
	ruleBuilder := builder.NewRuleBuilder(knowledgeBase)

	err := ruleBuilder.BuildRuleFromResource(pkg.NewBytesResource([]byte(rule2)))
	if err != nil{
		fmt.Println(err)
	}else{

		eng1 := &engine.Grool{MaxCycle:1}
		eng1.Execute(dataContext,knowledgeBase)
		if err !=nil{
			fmt.Println("err:",err)
		}else {
			fmt.Println(user)
		}
	}
}

func main()  {

	t := &testing.T{}
	testMyRule(t)
}
ERROR:
GOROOT=/Users/renyunyi/sdk/go1.13 #gosetup
GOPATH=/Users/renyunyi/go #gosetup
/Users/renyunyi/sdk/go1.13/bin/go build -o /private/var/folders/k2/3y7zc6yx7nvbxp4xsbbdrknc0000gn/T/___go_build_main_go /Users/renyunyi/go/src/blive-risk/main.go #gosetup
/private/var/folders/k2/3y7zc6yx7nvbxp4xsbbdrknc0000gn/T/___go_build_main_go #gosetup
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x20 pc=0x13baec9]

goroutine 1 [running]:
github.com/newm4n/grool/model.(*ExpressionAtom).Evaluate(0x0, 0x400, 0x1b13900, 0x20300000000000, 0x1cfffff, 0xc0001b38c0)
        /Users/renyunyi/go/src/github.com/newm4n/grool/model/ExpressionAtom.go:25 +0x29
github.com/newm4n/grool/model.(*ExpressionAtom).Evaluate(0xc0000c7b00, 0x400, 0x400, 0x1b13900, 0x1cfffff, 0xc0001b3900)
        /Users/renyunyi/go/src/github.com/newm4n/grool/model/ExpressionAtom.go:32 +0x60
github.com/newm4n/grool/model.(*Predicate).Evaluate(0xc000242700, 0xc000141380, 0x1, 0x0, 0xc0002521e8, 0xc0001b3b50)
        /Users/renyunyi/go/src/github.com/newm4n/grool/model/Predicate.go:53 +0x51
github.com/newm4n/grool/model.(*Expression).Evaluate(0xc0002426c0, 0x0, 0x18b8200, 0x14302e0, 0xc0000caea8, 0xc0001432c0)
        /Users/renyunyi/go/src/github.com/newm4n/grool/model/Expression.go:53 +0x460
github.com/newm4n/grool/model.(*WhenScope).ExecuteWhen(0xc00025cb80, 0x10106f3, 0xc0001b3d28, 0x18b8200)
        /Users/renyunyi/go/src/github.com/newm4n/grool/model/WhenScope.go:41 +0x32
github.com/newm4n/grool/model.(*RuleEntry).CanExecute(0xc000268410, 0xc0001432c0, 0xc0001b3d28, 0x18b8200)
        /Users/renyunyi/go/src/github.com/newm4n/grool/model/RuleEntry.go:43 +0x2f
github.com/newm4n/grool/engine.(*Grool).Execute(0xc0001b3dd8, 0xc000141380, 0xc0000c55c0, 0x0, 0x0)
        /Users/renyunyi/go/src/github.com/newm4n/grool/engine/GroolEngine.go:54 +0x1ad
main.testMyRule(0xc000060e50)
        /Users/renyunyi/go/src/blive-risk/main.go:58 +0x2f6
main.main()
        /Users/renyunyi/go/src/blive-risk/main.go:70 +0x6f

Process finished with exit code 2

Can you help me? My email is [email protected]

String Liternal includes the Quotes in the string it self

Describe the bug
When passing string literals as constants or as function argument. The string Value actually contains the entire literal including the double quotes that encloses the string. This makes string comparison become invalid.

To Reproduce
Steps to reproduce the behavior:

  1. Create a rule that executes a function with string arguments.
  2. Make the function to log out the string argument. The resulting log will contains the enclosing quotes.

Expected behavior
String value should not contains the enclosed quotes.

Error if "when" condition contains field name "Id"

Describe the bug
Error appears if field used in "when" section but not in "then"

Got error Grool successfully selected rule candidate for execution after 2 cycles, this could possibly caused by rule entry(s) that keep added into execution pool but when executed it does not change any data in context. Please evaluate your rule entries "When" and "Then" scope. You can adjust the maximum cycle using Grool.MaxCycle variable.

To Reproduce
Just run UserSuccess and UserFail

ppackage examples

import (
	"github.com/newm4n/grool/builder"
	"github.com/newm4n/grool/context"
	"github.com/newm4n/grool/engine"
	"github.com/newm4n/grool/model"
	"github.com/newm4n/grool/pkg"
	"github.com/stretchr/testify/assert"
	"testing"
)

func Run(name string, i interface{}, rule []byte, t *testing.T) {

	dataContext := context.NewDataContext()
	dataContext.Add(name, i)

	knowledgeBase := model.NewKnowledgeBase()
	ruleBuilder := builder.NewRuleBuilder(knowledgeBase)

	err := ruleBuilder.BuildRuleFromResource(pkg.NewBytesResource(rule))
	if err != nil {
		t.Log(err)
	} else {
		eng1 := &engine.Grool{MaxCycle: 2}

		err := eng1.Execute(dataContext, knowledgeBase)
		if err != nil {
			t.Logf("Got error %v", err)
			t.FailNow()
		} else {
			t.Logf("updated object: %+v\n", i)
		}
	}
}

const ruleUserWork = `
rule UserCheckSuccess "test"  salience 10{
    when
      User.Age == 0  
    then
      User.Name = "FromRule";
      User.Age = 3;
}
`

const ruleUserFail = `
rule UserCheckFail "test"  salience 10{
    when
      User.Id == 1  
    then
      User.Name = "FromRule";
      User.Age = 3;
}
`

type User struct {
	Id   int
	Name string
	Age  int
	Male bool
}

func getUser() *User {
	return &User{
		Id:   1,
		Name: "Calo",
		Age:  0,
		Male: true,
	}
}

func TestUserSuccess(t *testing.T) {
	user := getUser()

	Run("User", user, []byte(ruleUserWork), t)
	assert.Equal(t, "FromRule", user.Name)
	assert.Equal(t, 3, user.Age)
}

func TestUserFail(t *testing.T) {
	user := getUser()
	Run("User", user, []byte(ruleUserFail), t)
	assert.Equal(t, "FromRule", user.Name)
	assert.Equal(t, 3, user.Age)
}

Expected behavior
I expected that "Id" field will be processing as other fields

Desktop (please complete the following information):

  • OS: Linux Debian

Additional context

> go test  examples/AgeCheckSample_test.go -v
=== RUN   TestUserSuccess
time="2019-10-08T12:10:35+03:00" level=info msg="Executing rule : UserCheckSuccess. Salience 10"
time="2019-10-08T12:10:35+03:00" level=info msg="Finished Rules execution. Total #2 cycles."
--- PASS: TestUserSuccess (0.00s)
    AgeCheckSample_test.go:32: updated object: &{Id:1 Name:FromRule Age:3 Male:true}
=== RUN   TestUserFail
time="2019-10-08T12:10:35+03:00" level=info msg="Executing rule : UserCheckFail. Salience 10"
time="2019-10-08T12:10:35+03:00" level=info msg="Executing rule : UserCheckFail. Salience 10"
--- FAIL: TestUserFail (0.00s)
    AgeCheckSample_test.go:29: Got error Grool successfully selected rule candidate for execution after 2 cycles, this could possibly caused by rule entry(s) that keep added into execution pool but when executed it does not change any data in context. Please evaluate your rule entries "When" and "Then" scope. You can adjust the maximum cycle using Grool.MaxCycle variable.
FAIL
FAIL    command-line-arguments  0.004s
FAIL

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.