or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

context-management.mdcore-operations.mderror-handling.mdindex.mdtype-system.md

core-operations.mddocs/

0

# Core Rule Operations

1

2

The fundamental rule evaluation system that provides rule creation, matching, filtering, and expression evaluation capabilities. These operations form the foundation of the rule engine's functionality.

3

4

## Capabilities

5

6

### Rule Creation

7

8

Create rule objects from text expressions with optional context for type safety and custom symbol resolution.

9

10

```python { .api }

11

class Rule:

12

def __init__(self, rule_text: str, context: Context = None):

13

"""

14

Create a new rule from a text expression.

15

16

Args:

17

rule_text (str): The rule expression text to parse

18

context (Context, optional): Context for symbol resolution and type checking

19

20

Raises:

21

RuleSyntaxError: If the rule text contains syntax errors

22

EvaluationError: If type checking fails during parsing

23

"""

24

```

25

26

**Usage Example:**

27

28

```python

29

import rule_engine

30

31

# Basic rule creation

32

rule = rule_engine.Rule('age > 18 and status == "active"')

33

34

# Rule with typed context

35

context = rule_engine.Context(

36

type_resolver=rule_engine.type_resolver_from_dict({

37

'age': rule_engine.DataType.FLOAT,

38

'status': rule_engine.DataType.STRING

39

})

40

)

41

typed_rule = rule_engine.Rule('age > 18', context=context)

42

```

43

44

### Boolean Matching

45

46

Evaluate rules against data to determine if they match the specified conditions.

47

48

```python { .api }

49

def matches(self, thing, **kwargs) -> bool:

50

"""

51

Test if the rule matches the provided object.

52

53

Args:

54

thing: The object to evaluate against the rule

55

**kwargs: Additional keyword arguments passed to the evaluation context

56

57

Returns:

58

bool: True if the rule matches, False otherwise

59

60

Raises:

61

EvaluationError: If evaluation fails due to type errors or other issues

62

SymbolResolutionError: If symbols cannot be resolved

63

AttributeResolutionError: If attributes cannot be accessed

64

"""

65

```

66

67

**Usage Example:**

68

69

```python

70

rule = rule_engine.Rule('name == "John" and age >= 21')

71

72

person1 = {'name': 'John', 'age': 25}

73

person2 = {'name': 'Jane', 'age': 19}

74

75

print(rule.matches(person1)) # True

76

print(rule.matches(person2)) # False

77

78

# Using object attributes instead of dictionary

79

class Person:

80

def __init__(self, name, age):

81

self.name = name

82

self.age = age

83

84

john = Person('John', 25)

85

print(rule.matches(john)) # True

86

```

87

88

### Collection Filtering

89

90

Filter collections of objects using rule expressions, returning only matching items.

91

92

```python { .api }

93

def filter(self, things, **kwargs):

94

"""

95

Filter an iterable of objects, yielding only those that match the rule.

96

97

Args:

98

things: Iterable of objects to filter

99

**kwargs: Additional keyword arguments passed to the evaluation context

100

101

Yields:

102

Objects from the iterable that match the rule

103

104

Raises:

105

EvaluationError: If evaluation fails for any item

106

SymbolResolutionError: If symbols cannot be resolved

107

AttributeResolutionError: If attributes cannot be accessed

108

"""

109

```

110

111

**Usage Example:**

112

113

```python

114

rule = rule_engine.Rule('age >= 18 and department == "engineering"')

115

116

employees = [

117

{'name': 'Alice', 'age': 25, 'department': 'engineering'},

118

{'name': 'Bob', 'age': 17, 'department': 'engineering'},

119

{'name': 'Charlie', 'age': 30, 'department': 'marketing'},

120

{'name': 'Diana', 'age': 28, 'department': 'engineering'}

121

]

122

123

# Filter returns a generator

124

eligible_employees = list(rule.filter(employees))

125

print(f"Found {len(eligible_employees)} eligible employees")

126

127

# Can be used in loops

128

for employee in rule.filter(employees):

129

print(f"{employee['name']} is eligible")

130

```

131

132

### Expression Evaluation

133

134

Evaluate rule expressions to compute and return values rather than just boolean results.

135

136

```python { .api }

137

def evaluate(self, thing, **kwargs):

138

"""

139

Evaluate the rule expression and return the computed result.

140

141

Args:

142

thing: The object to evaluate against

143

**kwargs: Additional keyword arguments passed to the evaluation context

144

145

Returns:

146

The computed result of the expression evaluation

147

148

Raises:

149

EvaluationError: If evaluation fails due to type errors or other issues

150

SymbolResolutionError: If symbols cannot be resolved

151

AttributeResolutionError: If attributes cannot be accessed

152

"""

153

```

154

155

**Usage Example:**

156

157

```python

158

# Arithmetic expressions

159

calc_rule = rule_engine.Rule('price * quantity * (1 + tax_rate)')

160

order = {'price': 10.50, 'quantity': 3, 'tax_rate': 0.08}

161

total = calc_rule.evaluate(order)

162

print(f"Total: ${total:.2f}")

163

164

# String concatenation

165

name_rule = rule_engine.Rule('first_name + " " + last_name')

166

person = {'first_name': 'John', 'last_name': 'Doe'}

167

full_name = name_rule.evaluate(person)

168

print(full_name) # "John Doe"

169

170

# Complex expressions with built-in functions

171

data_rule = rule_engine.Rule('filter(lambda x: x > 10, numbers)')

172

data = {'numbers': [5, 15, 8, 20, 12]}

173

filtered = data_rule.evaluate(data)

174

print(list(filtered)) # [15, 20, 12]

175

```

176

177

### Rule Validation

178

179

Validate rule syntax without creating a full rule object.

180

181

```python { .api }

182

@classmethod

183

def is_valid(cls, text: str, context: Context = None) -> bool:

184

"""

185

Test whether a rule is syntactically correct.

186

187

Args:

188

text (str): The rule expression text to validate

189

context (Context, optional): Context for type checking validation

190

191

Returns:

192

bool: True if the rule is well-formed and valid

193

"""

194

```

195

196

**Usage Example:**

197

198

```python

199

import rule_engine

200

201

# Validate syntax before creating rule

202

if rule_engine.Rule.is_valid('age > 18 and status == "active"'):

203

rule = rule_engine.Rule('age > 18 and status == "active"')

204

print("Rule is valid")

205

else:

206

print("Invalid rule syntax")

207

208

# Validate with context for type checking

209

context = rule_engine.Context(

210

type_resolver=rule_engine.type_resolver_from_dict({

211

'age': rule_engine.DataType.FLOAT,

212

'status': rule_engine.DataType.STRING

213

})

214

)

215

216

if rule_engine.Rule.is_valid('age + status', context): # Will be False - type error

217

print("Valid")

218

else:

219

print("Invalid - type error")

220

```

221

222

### AST Visualization

223

224

Generate GraphViz diagrams of parsed rule abstract syntax trees for debugging.

225

226

```python { .api }

227

def to_graphviz(self):

228

"""

229

Generate a GraphViz diagram of the rule's AST.

230

231

Returns:

232

graphviz.Digraph: The rule diagram

233

234

Raises:

235

ImportError: If graphviz package is not installed

236

"""

237

```

238

239

**Usage Example:**

240

241

```python

242

import rule_engine

243

244

rule = rule_engine.Rule('age > 18 and (status == "active" or priority >= 5)')

245

digraph = rule.to_graphviz()

246

247

# Save the diagram to a file

248

digraph.render('rule_ast', format='png', cleanup=True)

249

250

# Or view the source

251

print(digraph.source)

252

```

253

254

### Rule Properties

255

256

Access rule metadata and configuration information.

257

258

```python { .api }

259

@property

260

def text(self) -> str:

261

"""The original rule text string."""

262

263

@property

264

def context(self) -> Context:

265

"""The context object associated with this rule."""

266

```

267

268

**Usage Example:**

269

270

```python

271

rule = rule_engine.Rule('age > 18')

272

print(f"Rule text: {rule.text}")

273

print(f"Has context: {rule.context is not None}")

274

275

# Accessing context properties

276

context = rule_engine.Context(default_value="unknown")

277

typed_rule = rule_engine.Rule('name', context=context)

278

print(f"Default value: {typed_rule.context.default_value}")

279

```

280

281

## Advanced Features

282

283

### Custom Keyword Arguments

284

285

Rules support custom keyword arguments that can be used in expressions or passed to custom resolvers.

286

287

```python

288

rule = rule_engine.Rule('threshold > min_value')

289

result = rule.matches({'threshold': 15}, min_value=10) # True

290

```

291

292

### Regex Matching

293

294

Use regular expression operators for string pattern matching.

295

296

```python

297

email_rule = rule_engine.Rule('email =~ ".*@company\\.com$"')

298

user = {'email': 'john.doe@company.com'}

299

print(email_rule.matches(user)) # True

300

```

301

302

### Datetime Operations

303

304

Work with datetime objects and operations.

305

306

```python

307

rule = rule_engine.Rule('created_date > parse_datetime("2023-01-01")')

308

record = {'created_date': datetime.datetime(2023, 6, 15)}

309

print(rule.matches(record)) # True

310

```

311

312

## Error Handling

313

314

All core operations can raise various exceptions that should be handled appropriately:

315

316

```python

317

import rule_engine

318

319

try:

320

rule = rule_engine.Rule('invalid syntax ===')

321

except rule_engine.RuleSyntaxError as e:

322

print(f"Syntax error: {e.message}")

323

324

try:

325

rule = rule_engine.Rule('unknown_field == "value"')

326

rule.matches({'known_field': 'value'})

327

except rule_engine.SymbolResolutionError as e:

328

print(f"Symbol error: {e.message}")

329

if e.suggestion:

330

print(f"Did you mean: {e.suggestion}")

331

```