philiprehberger-rule_engine 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/README.md +41 -8
- data/lib/philiprehberger/rule_engine/engine.rb +38 -0
- data/lib/philiprehberger/rule_engine/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b150f5bc67b381f5f5a1c88032c5241c4bc83f952c565ceaf5d66baa852d4f65
|
|
4
|
+
data.tar.gz: 0fc2ae7a0e84089dcfddee3b80d917201924522c249c320bc80dd6bbc317e9f2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 99ab211d1ba3beefd989c2c32444fcc40386d72fdaa90963cbb2ae845021db06ebe4b882843ff8eea76f9773879610f47f71fec26044065b165530ae8d387767
|
|
7
|
+
data.tar.gz: 0b3ab9ec81247acaab0f07b7c44add184aa0437cf650f66c760d99666f3797d3049d4730c788e9a280ef4352a7333546878a0105289fa64933d5b76787c83af1
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.3.0] - 2026-04-01
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- `#dry_run(facts)` for evaluating rules without executing actions
|
|
14
|
+
- `#detect_conflicts` for finding potentially overlapping rule pairs
|
|
15
|
+
- `#validate_rules` for checking rule completeness
|
|
16
|
+
|
|
17
|
+
## [0.2.1] - 2026-03-31
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
- Standardize README badges, support section, and license format
|
|
21
|
+
|
|
10
22
|
## [0.2.0] - 2026-03-28
|
|
11
23
|
|
|
12
24
|
### Added
|
data/README.md
CHANGED
|
@@ -2,12 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://github.com/philiprehberger/rb-rule-engine/actions/workflows/ci.yml)
|
|
4
4
|
[](https://rubygems.org/gems/philiprehberger-rule_engine)
|
|
5
|
-
[](https://github.com/philiprehberger/rb-rule-engine/releases)
|
|
6
5
|
[](https://github.com/philiprehberger/rb-rule-engine/commits/main)
|
|
7
|
-
[](LICENSE)
|
|
8
|
-
[](https://github.com/philiprehberger/rb-rule-engine/issues?q=is%3Aissue+is%3Aopen+label%3Abug)
|
|
9
|
-
[](https://github.com/philiprehberger/rb-rule-engine/issues?q=is%3Aissue+is%3Aopen+label%3Aenhancement)
|
|
10
|
-
[](https://github.com/sponsors/philiprehberger)
|
|
11
6
|
|
|
12
7
|
Lightweight rule engine with declarative conditions and actions
|
|
13
8
|
|
|
@@ -163,6 +158,29 @@ engine.stats
|
|
|
163
158
|
engine.reset_stats!
|
|
164
159
|
```
|
|
165
160
|
|
|
161
|
+
### Dry Run
|
|
162
|
+
|
|
163
|
+
Evaluate without executing actions:
|
|
164
|
+
|
|
165
|
+
```ruby
|
|
166
|
+
matched = engine.dry_run(facts)
|
|
167
|
+
# => [{ name: "discount", priority: 10 }]
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Conflict Detection
|
|
171
|
+
|
|
172
|
+
```ruby
|
|
173
|
+
engine.detect_conflicts
|
|
174
|
+
# => [{ rules: ["rule_a", "rule_b"], priorities: [10, 5] }]
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Rule Validation
|
|
178
|
+
|
|
179
|
+
```ruby
|
|
180
|
+
engine.validate_rules
|
|
181
|
+
# => { valid: false, issues: ["Rule 'x' has no action"] }
|
|
182
|
+
```
|
|
183
|
+
|
|
166
184
|
### Serialization
|
|
167
185
|
|
|
168
186
|
```ruby
|
|
@@ -203,6 +221,9 @@ end
|
|
|
203
221
|
| `#chain(*rule_names)` | Execute rules sequentially as a pipeline |
|
|
204
222
|
| `#stats` | Per-rule execution statistics |
|
|
205
223
|
| `#reset_stats!` | Clear all execution statistics |
|
|
224
|
+
| `#dry_run(facts)` | Evaluate rules without executing actions |
|
|
225
|
+
| `#detect_conflicts` | Find rule pairs that could both match |
|
|
226
|
+
| `#validate_rules` | Check all rules have conditions and actions |
|
|
206
227
|
|
|
207
228
|
### Rule DSL
|
|
208
229
|
|
|
@@ -230,9 +251,21 @@ bundle exec rubocop
|
|
|
230
251
|
|
|
231
252
|
## Support
|
|
232
253
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
254
|
+
If you find this project useful:
|
|
255
|
+
|
|
256
|
+
⭐ [Star the repo](https://github.com/philiprehberger/rb-rule-engine)
|
|
257
|
+
|
|
258
|
+
🐛 [Report issues](https://github.com/philiprehberger/rb-rule-engine/issues?q=is%3Aissue+is%3Aopen+label%3Abug)
|
|
259
|
+
|
|
260
|
+
💡 [Suggest features](https://github.com/philiprehberger/rb-rule-engine/issues?q=is%3Aissue+is%3Aopen+label%3Aenhancement)
|
|
261
|
+
|
|
262
|
+
❤️ [Sponsor development](https://github.com/sponsors/philiprehberger)
|
|
263
|
+
|
|
264
|
+
🌐 [All Open Source Projects](https://philiprehberger.com/open-source-packages)
|
|
265
|
+
|
|
266
|
+
💻 [GitHub Profile](https://github.com/philiprehberger)
|
|
267
|
+
|
|
268
|
+
🔗 [LinkedIn Profile](https://www.linkedin.com/in/philiprehberger)
|
|
236
269
|
|
|
237
270
|
## License
|
|
238
271
|
|
|
@@ -135,6 +135,40 @@ module Philiprehberger
|
|
|
135
135
|
@stats.each_key { |k| @stats[k] = new_stat_entry }
|
|
136
136
|
end
|
|
137
137
|
|
|
138
|
+
# Evaluate rules without executing actions, return matched rule info
|
|
139
|
+
#
|
|
140
|
+
# @param facts [Hash] the facts to evaluate
|
|
141
|
+
# @return [Array<Hash>] matched rules with name and priority
|
|
142
|
+
def dry_run(facts)
|
|
143
|
+
matched = enabled_rules_sorted.select { |rule| rule.matches?(facts) }
|
|
144
|
+
matched = [matched.first].compact if @mode == :first
|
|
145
|
+
matched.map { |rule| { name: rule.name, priority: rule.priority } }
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Find rules with potentially overlapping conditions
|
|
149
|
+
#
|
|
150
|
+
# @return [Array<Hash>] pairs of rule names that could both match
|
|
151
|
+
def detect_conflicts
|
|
152
|
+
pairs = []
|
|
153
|
+
sorted = enabled_rules_sorted
|
|
154
|
+
sorted.combination(2) do |a, b|
|
|
155
|
+
pairs << { rules: [a.name, b.name], priorities: [a.priority, b.priority] }
|
|
156
|
+
end
|
|
157
|
+
pairs
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# Validate all rules have conditions and actions defined
|
|
161
|
+
#
|
|
162
|
+
# @return [Hash] { valid: Boolean, issues: Array<String> }
|
|
163
|
+
def validate_rules
|
|
164
|
+
issues = []
|
|
165
|
+
@rules.each do |rule|
|
|
166
|
+
issues << "Rule '#{rule.name}' has no condition" unless rule.instance_variable_get(:@condition)
|
|
167
|
+
issues << "Rule '#{rule.name}' has no action" unless rule.instance_variable_get(:@action)
|
|
168
|
+
end
|
|
169
|
+
{ valid: issues.empty?, issues: issues }
|
|
170
|
+
end
|
|
171
|
+
|
|
138
172
|
# Serialize the engine configuration to a hash.
|
|
139
173
|
#
|
|
140
174
|
# @return [Hash] engine metadata including mode and rules
|
|
@@ -169,6 +203,10 @@ module Philiprehberger
|
|
|
169
203
|
|
|
170
204
|
private
|
|
171
205
|
|
|
206
|
+
def enabled_rules_sorted
|
|
207
|
+
@rules.select(&:enabled).sort_by(&:priority)
|
|
208
|
+
end
|
|
209
|
+
|
|
172
210
|
def new_stat_entry
|
|
173
211
|
{
|
|
174
212
|
evaluations: 0,
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: philiprehberger-rule_engine
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Philip Rehberger
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-04-02 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: A lightweight rule engine with a declarative DSL for defining conditions
|
|
14
14
|
and actions. Supports priority-based ordering, first-match and all-match evaluation
|
|
@@ -27,11 +27,11 @@ files:
|
|
|
27
27
|
- lib/philiprehberger/rule_engine/helpers.rb
|
|
28
28
|
- lib/philiprehberger/rule_engine/rule.rb
|
|
29
29
|
- lib/philiprehberger/rule_engine/version.rb
|
|
30
|
-
homepage: https://
|
|
30
|
+
homepage: https://philiprehberger.com/open-source-packages/ruby/philiprehberger-rule_engine
|
|
31
31
|
licenses:
|
|
32
32
|
- MIT
|
|
33
33
|
metadata:
|
|
34
|
-
homepage_uri: https://
|
|
34
|
+
homepage_uri: https://philiprehberger.com/open-source-packages/ruby/philiprehberger-rule_engine
|
|
35
35
|
source_code_uri: https://github.com/philiprehberger/rb-rule-engine
|
|
36
36
|
changelog_uri: https://github.com/philiprehberger/rb-rule-engine/blob/main/CHANGELOG.md
|
|
37
37
|
bug_tracker_uri: https://github.com/philiprehberger/rb-rule-engine/issues
|