rules

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 20, 2023 License: MIT Imports: 5 Imported by: 0

README

rules

The rules package provides a set of types and functions for creating, parsing, and evaluating boolean expressions in the form of rules. These rules can be used to define conditions or criteria that determine the outcome or behavior of a program or system.

Installation

To install the rules package, use go get:

go get github.com/IAmRadek/rules

Usage

Import the rules package in your Go code:

import "github.com/IAmRadek/rules"

Variables

The rules package provides two types of variables: Attribute and Variable.

Attribute

Represents a boolean value that can be used in a rule expression. You can create an attribute using the NewAttribute function.

var attr = rules.NewAttribute("attr1")
Variable

Represents a dynamic value that can be changed during runtime and used in a rule expression. You can create a variable using the NewVariable function.

var var1 = rules.NewVariable[float64]("var1")
var var2 = rules.NewVariable[string]("var2")

Rules

The rules package defines a Rule interface that represents a single boolean expression. You can create a rule using the Parse function, which parses a rule expression and returns a Rule instance. The expression can contain operators such as AND, OR, XOR, NOT, EQ, NEQ, GT, LT, GTE, and LTE.

rule, err := rules.Parse("myRule", "var1 AND var2 OR NOT attr1")
if err != nil {
    // handle error
}

You can then evaluate a rule using the Evaluate method, which takes a RuleContext as input and returns a boolean value and an error indicating whether the rule is true or false.

RuleContext

The RuleContext type holds the values of variables and attributes during the evaluation of rules. You can create a RuleContext using the NewContext function, passing in the initial values of variables and attributes as arguments.

globalContext := rules.NewContext(var1(10), var2("global"), attr1(true))
userContext := rules.NewContext(var1(12), var2("user")).MergeWith(globalContext)

You can also merge multiple RuleContext instances together using the MergeWith method to update the values of variables and attributes during the evaluation process.

RuleSet

The RuleSet type represents a collection of rules and rule overrides that can be evaluated together as a group. You can create a RuleSet using the NewRuleSet function, passing in the rules and rule overrides as arguments.

ruleSet := rules.NewRuleSet(rule1, rule2, rule3, rule4, rule5, rule6)

You can then evaluate the RuleSet using the Evaluate method, which takes a RuleContext as input and returns a boolean value and an error indicating whether the rules in the RuleSet are true or false.

RuleOverride

The RuleOverride type represents a rule that overrides the behavior of another rule. You can pass rule to the AddOverride method of a RuleSet to override the behavior of the rule.

ruleSet.AddOverride(rule1)
Contributing

If you find any issues or have suggestions for improvements, please feel free to open an issue or submit a pull request on GitHub at https://github.com/IAmRadek/rules/issues.

Documentation

Overview

Package rules provides a set of tools for parsing, evaluating, and working with boolean expressions in the form of rules. It includes support for variables, attributes, and rule sets.

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// ErrInvalidRule is an error indicating that a rule is invalid.
	ErrInvalidRule = fmt.Errorf("invalid rule")
	// ErrMissingDataInContext is an error indicating that there is a lack of data in the rule context.
	ErrMissingDataInContext = fmt.Errorf("missing data in context")
	// ErrMismatchedParentheses is an error indicating that there are mismatched parentheses in a rule expression.
	ErrMismatchedParentheses = errors.New("mismatched parentheses")
	// ErrEmptyExpression is an error indicating that the rule expression is empty.
	ErrEmptyExpression = errors.New("empty expression")
	// ErrInvalidExpression is an error indicating that the rule expression is invalid.
	ErrInvalidExpression = errors.New("invalid expression")
)

Functions

func NewVariable

func NewVariable[T ordered](name string) variableFunc[T]

Types

type Attribute

type Attribute interface {
	RuleElement
	// contains filtered or unexported methods
}

Attribute represents a boolean value that can be used in a rule.

type AttributeDescriptor

type AttributeDescriptor func(value bool) Attribute

func NewAttribute

func NewAttribute(name string) AttributeDescriptor

type Rule

type Rule interface {
	Name() string
	Evaluate(ctx RuleContext) (bool, error)
}

Rule is an interface that represents a rule. It includes methods for getting the name of the rule and evaluating the rule with a given rule context to determine its boolean result.

func MustParse

func MustParse(name, expr string) Rule

func Parse

func Parse(name, expr string) (Rule, error)

Parse parses a rule expression and returns a Rule. The expression is a string that contains a boolean expression. The expression can contain the following operators:

  • AND, OR, XOR, NOT, EQ, NEQ, GT, LT, GTE, LTE
Example
package main

import (
	"fmt"

	"github.com/IAmRadek/rules"
)

var isPassengerEconomy = rules.NewAttribute("passengerIsEconomy")
var isPassengerGoldCardHolder = rules.NewAttribute("passengerIsGoldCardHolder")
var isPassengerSilverCardHolder = rules.NewAttribute("passengerIsSilverCardHolder")
var isPassengerDressSmart = rules.NewAttribute("passengerDressIsSmart")

var baggageWeight = rules.NewVariable[float64]("passengerCarryOnBaggageWeightKg")
var baggageAllowance = rules.NewVariable[float64]("carryOnBaggageAllowanceKg")
var suitableForUpgrade = rules.MustParse(
	"suitableForUpgrade",
	`passengerIsEconomy 
			AND (passengerIsGoldCardHolder OR passengerIsSilverCardHolder) 
			AND (passengerCarryOnBaggageWeightKg LTE carryOnBaggageAllowanceKg) 
			AND passengerDressIsSmart`,
)

func main() {
	passengerContext := rules.NewContext(
		isPassengerEconomy(true),
		isPassengerGoldCardHolder(true),
		isPassengerSilverCardHolder(false),
		isPassengerDressSmart(true),
		baggageWeight(4.6),
		baggageAllowance(7),
	)

	result, err := suitableForUpgrade.Evaluate(passengerContext)
	if err != nil {
		panic(err)
	}

	fmt.Println(result)

}
Output:

true

type RuleContext

type RuleContext interface {
	MergeWith(ctx RuleContext) RuleContext
	// contains filtered or unexported methods
}

RuleContext is an interface that represents a rule context, which is a collection of rule elements. It includes methods for merging two rule contexts.

func NewContext

func NewContext(elems ...RuleElement) RuleContext
Example
package main

import (
	"fmt"

	"github.com/IAmRadek/rules"
)

var isPassengerEconomy = rules.NewAttribute("passengerIsEconomy")
var isPassengerGoldCardHolder = rules.NewAttribute("passengerIsGoldCardHolder")
var isPassengerSilverCardHolder = rules.NewAttribute("passengerIsSilverCardHolder")
var isPassengerDressSmart = rules.NewAttribute("passengerDressIsSmart")
var isPassengerDressCasual = rules.NewAttribute("passengerDressIsCasual")
var baggageWeight = rules.NewVariable[float64]("passengerCarryOnBaggageWeightKg")
var baggageAllowance = rules.NewVariable[float64]("carryOnBaggageAllowanceKg")
var suitableForUpgrade = rules.MustParse(
	"suitableForUpgrade",
	`passengerIsEconomy 
			AND (passengerIsGoldCardHolder OR passengerIsSilverCardHolder) 
			AND (passengerCarryOnBaggageWeightKg LTE carryOnBaggageAllowanceKg) 
			AND passengerDressIsSmart`,
)

func main() {
	globalContext := rules.NewContext(
		baggageAllowance(3),
		isPassengerDressCasual(true),
	)

	passengerContext := rules.NewContext(
		isPassengerEconomy(true),
		isPassengerGoldCardHolder(true),
		isPassengerSilverCardHolder(false),
		isPassengerDressSmart(true),
		baggageWeight(4.6),
		baggageAllowance(7),
	).MergeWith(globalContext)

	fmt.Println(passengerContext)

	result, err := suitableForUpgrade.Evaluate(passengerContext)
	if err != nil {
		panic(err)
	}

	fmt.Println(result)

}
Output:

passengerIsEconomy(true), passengerIsGoldCardHolder(true), passengerIsSilverCardHolder(false), passengerDressIsSmart(true), passengerCarryOnBaggageWeightKg(4.6), carryOnBaggageAllowanceKg(7), passengerDressIsCasual(true)
true

type RuleElement

type RuleElement interface {
	// contains filtered or unexported methods
}

RuleElement is an interface that represents a rule element, which can be an attribute, a variable, or any other element of a rule.

type RuleOverride

type RuleOverride interface {
	Name() string
}

type RuleSet

type RuleSet interface {
	AddRule(rule Rule)
	AddOverride(override RuleOverride)
	Evaluate(ctx RuleContext) (bool, error)
}
Example
package main

import (
	"fmt"

	"github.com/IAmRadek/rules"
)

var isPassengerEconomy = rules.NewAttribute("passengerIsEconomy")
var isPassengerGoldCardHolder = rules.NewAttribute("passengerIsGoldCardHolder")
var isPassengerSilverCardHolder = rules.NewAttribute("passengerIsSilverCardHolder")
var isPassengerDressSmart = rules.NewAttribute("passengerDressIsSmart")

var baggageWeight = rules.NewVariable[float64]("passengerCarryOnBaggageWeightKg")
var baggageAllowance = rules.NewVariable[float64]("carryOnBaggageAllowanceKg")
var suitableForUpgrade = rules.MustParse(
	"suitableForUpgrade",
	`passengerIsEconomy 
			AND (passengerIsGoldCardHolder OR passengerIsSilverCardHolder) 
			AND (passengerCarryOnBaggageWeightKg LTE carryOnBaggageAllowanceKg) 
			AND passengerDressIsSmart`,
)
var canHaveAdditionalBaggage = rules.MustParse(
	"canHaveAdditionalBaggage",
	`passengerIsEconomy
			AND passengerIsGoldCardHolder
			AND (passengerCarryOnBaggageWeightKg LTE carryOnBaggageAllowanceKg)
			AND passengerDressIsSmart`,
)

func main() {
	ruleSet := rules.NewRuleSet(suitableForUpgrade, canHaveAdditionalBaggage)
	ruleSet.AddOverride(canHaveAdditionalBaggage)

	// Create a context for a passenger
	passengerContext := rules.NewContext(
		isPassengerEconomy(true),
		isPassengerGoldCardHolder(false),
		isPassengerSilverCardHolder(true),
		isPassengerDressSmart(true),
		baggageWeight(4.6),
		baggageAllowance(7),
	)

	// Evaluate the rule set
	result, err := ruleSet.Evaluate(passengerContext)
	if err != nil {
		panic(err)
	}

	fmt.Println(result)

}
Output:

true

func NewRuleSet

func NewRuleSet(rules ...Rule) RuleSet

type Variable

type Variable interface {
	RuleElement
	// contains filtered or unexported methods
}

Variable represents a value that can be used in a rule.

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL