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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 48759336967f009c48193bd19ba3abc3edf2c45712e21f18bbc3382b50ce2c19
4
- data.tar.gz: 2894eca7b2c22440eb52c0920ae3edcb1642ada7193668f3e2d01213c6d0f560
3
+ metadata.gz: b150f5bc67b381f5f5a1c88032c5241c4bc83f952c565ceaf5d66baa852d4f65
4
+ data.tar.gz: 0fc2ae7a0e84089dcfddee3b80d917201924522c249c320bc80dd6bbc317e9f2
5
5
  SHA512:
6
- metadata.gz: 0f1df77fa3a9caa8dc480eeb6cdb9c2010806f2b57108b8c4fde06b60830c853387918d225d48584d56cca89aeb2e790eee245ef0081debe6f9b8af723b3fa47
7
- data.tar.gz: 9cd80a35da5092a44dd170965cd508faed0d3aba1d25a4005a91af5da037dff4a2e41cf9e54cb4995533e7240f4dd47155c5c26259d495d238f0eb41fd8bb9ee
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
  [![Tests](https://github.com/philiprehberger/rb-rule-engine/actions/workflows/ci.yml/badge.svg)](https://github.com/philiprehberger/rb-rule-engine/actions/workflows/ci.yml)
4
4
  [![Gem Version](https://badge.fury.io/rb/philiprehberger-rule_engine.svg)](https://rubygems.org/gems/philiprehberger-rule_engine)
5
- [![GitHub release](https://img.shields.io/github/v/release/philiprehberger/rb-rule-engine)](https://github.com/philiprehberger/rb-rule-engine/releases)
6
5
  [![Last updated](https://img.shields.io/github/last-commit/philiprehberger/rb-rule-engine)](https://github.com/philiprehberger/rb-rule-engine/commits/main)
7
- [![License](https://img.shields.io/github/license/philiprehberger/rb-rule-engine)](LICENSE)
8
- [![Bug Reports](https://img.shields.io/github/issues/philiprehberger/rb-rule-engine/bug)](https://github.com/philiprehberger/rb-rule-engine/issues?q=is%3Aissue+is%3Aopen+label%3Abug)
9
- [![Feature Requests](https://img.shields.io/github/issues/philiprehberger/rb-rule-engine/enhancement)](https://github.com/philiprehberger/rb-rule-engine/issues?q=is%3Aissue+is%3Aopen+label%3Aenhancement)
10
- [![Sponsor](https://img.shields.io/badge/sponsor-GitHub%20Sponsors-ec6cb9)](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
- - [Bug Reports](https://github.com/philiprehberger/rb-rule-engine/issues?q=is%3Aissue+is%3Aopen+label%3Abug)
234
- - [Feature Requests](https://github.com/philiprehberger/rb-rule-engine/issues?q=is%3Aissue+is%3Aopen+label%3Aenhancement)
235
- - [GitHub Sponsors](https://github.com/sponsors/philiprehberger)
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,
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Philiprehberger
4
4
  module RuleEngine
5
- VERSION = '0.2.0'
5
+ VERSION = '0.3.0'
6
6
  end
7
7
  end
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.2.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-03-29 00:00:00.000000000 Z
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://github.com/philiprehberger/rb-rule-engine
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://github.com/philiprehberger/rb-rule-engine
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