dmn 0.0.3 → 0.0.4

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: 83ab9c509d78447fc0dcf11d993e79c9105baf97904af53e932e16ae7eaee2df
4
- data.tar.gz: be469b68cdeab12f0ffee64e6a1c884ee9b67d10e2d9b899f1f3ecfa7905a975
3
+ metadata.gz: 99f8ad17d713e6ce95941ee100f3c4046a2ffc93155ea6629a6761bb3745e1ca
4
+ data.tar.gz: ad53db39e8b2e96884644d177486b8cf1d65a8d608d5b09c136ee37b0d3daad5
5
5
  SHA512:
6
- metadata.gz: a5b1b6a24a4c6d2f305d41e94ac83bcb951f1dbfe8fc4ddccc6d5675ee5f3af70529778f288db5c7dea989a5ef7af685250ad6b7abd5dea7b80bef1afe20d019
7
- data.tar.gz: 62e2cecb612379245854e09684e1632ae6fb670d0618577685d00e92c944aaf44c9e8a5e59173372280a5887879a190603bd1ec47e07f34bebb9e533f91d9a3b
6
+ metadata.gz: 8e8009211631110c50467c8ff2f8b857095ca497409171590d44135c2bd25ee5ced0d7d99c676f48a0137c3b7083c00e349f0853cca2cbfae0e45baa316b612e
7
+ data.tar.gz: bf0a15e9f42f288505314de24eec35a70fdc621238e6944bd46d69b72e82de83cddab12cc891e6f2542bf5a99c7b5c32aa17a216ba4c00ef9482692abac3289a
data/README.md CHANGED
@@ -1,69 +1,11 @@
1
- # Spot Feel
1
+ # DMN
2
2
 
3
- A light-weight DMN FEEL expression evaluator and business rule engine in Ruby.
3
+ A light-weight DMN (Decision Model and Notation) business rule ruby gem.
4
4
 
5
- This gem implements a subset of FEEL (Friendly Enough Expression Language) as defined in the [DMN 1.3 specification](https://www.omg.org/spec/DMN/1.3/PDF) with some additional extensions.
6
-
7
- FEEL expressions are parsed into an abstract syntax tree (AST) and then evaluated in a context. The context is a hash of variables and functions to be resolved inside the expression.
8
-
9
- Expressions are safe, side-effect free, and deterministic. They are ideal for capturing business logic for storage in a database or embedded in DMN, BPMN, or Form documents for execution in a workflow engine like [Spot Flow](https://github.com/connectedbits/spot-flow).
10
-
11
- This project was inspired by these excellent libraries:
12
-
13
- - [feelin](https://github.com/nikku/feelin)
14
- - [dmn-eval-js](https://github.com/mineko-io/dmn-eval-js)
5
+ This gem depends on the [FEEL](https://github.com/connectedbits/bpmn/tree/main/feel) gem to evaluate DMN decision tables and expressions.
15
6
 
16
7
  ## Usage
17
8
 
18
- To evaluate an expression:
19
-
20
- ```ruby
21
- DMN.evaluate('"👋 Hello " + name', variables: { name: "World" })
22
- # => "👋 Hello World"
23
- ```
24
-
25
- A slightly more complex example:
26
-
27
- ```ruby
28
- variables = {
29
- person: {
30
- name: "Eric",
31
- age: 59,
32
- }
33
- }
34
- DMN.evaluate('if person.age >= 18 then "adult" else "minor"', variables:)
35
- # => "adult"
36
- ```
37
-
38
- Calling a built-in function:
39
-
40
- ```ruby
41
- DMN.evaluate('sum([1, 2, 3])')
42
- # => 6
43
- ```
44
-
45
- Calling a user-defined function:
46
-
47
- ```ruby
48
- DMN.config.functions = {
49
- "reverse": ->(s) { s.reverse }
50
- }
51
- DMN.evaluate('reverse("Hello World!")', functions:)
52
- # => "!dlroW olleH"
53
- ```
54
-
55
- To evaluate a unary tests:
56
-
57
- ```ruby
58
- DMN.test(3, '<= 10, > 50'))
59
- # => true
60
- ```
61
-
62
- ```ruby
63
- DMN.test("Eric", '"Bob", "Holly", "Eric"')
64
- # => true
65
- ```
66
-
67
9
  ![Decision Table](docs/media/decision_table.png)
68
10
 
69
11
  To evaluate a DMN decision table:
@@ -80,71 +22,8 @@ result = DMN.decide('fine_decision', definitions_xml: fixture_source("fine.dmn")
80
22
  # => { "amount" => 1000, "points" => 7 })
81
23
  ```
82
24
 
83
- To get a list of variables or functions used in an expression:
84
-
85
- ```ruby
86
- LiteralExpression.new(text: 'person.first_name + " " + person.last_name').variable_names
87
- # => ["person.age, person.last_name"]
88
- ```
89
-
90
- ```ruby
91
- LiteralExpression.new(text: 'sum([1, 2, 3])').function_names
92
- # => ["sum"]
93
- ```
94
-
95
- ```ruby
96
- UnaryTests.new(text: '> speed - speed_limit').variable_names
97
- # => ["speed, speed_limit"]
98
- ```
99
-
100
25
  ## Supported Features
101
26
 
102
- ### Data Types
103
-
104
- - [x] Boolean (true, false)
105
- - [x] Number (integer, decimal)
106
- - [x] String (single and double quoted)
107
- - [x] Date, Time, Duration (ISO 8601)
108
- - [x] List (array)
109
- - [x] Context (hash)
110
-
111
- ### Expressions
112
-
113
- - [x] Literal
114
- - [x] Path
115
- - [x] Arithmetic
116
- - [x] Comparison
117
- - [x] Function Invocation
118
- - [x] Positional Parameters
119
- - [x] If Expression
120
- - [ ] For Expression
121
- - [ ] Quantified Expression
122
- - [ ] Filter Expression
123
- - [ ] Disjunction
124
- - [ ] Conjuction
125
- - [ ] Instance Of
126
- - [ ] Function Definition
127
-
128
- ### Unary Tests
129
-
130
- - [x] Comparison
131
- - [x] Interval/Range (inclusive and exclusive)
132
- - [x] Disjunction
133
- - [x] Negation
134
- - [ ] Expression
135
-
136
- ### Built-in Functions
137
-
138
- - [x] Conversion: `string`, `number`
139
- - [x] Boolean: `not`, `is defined`, `get or else`
140
- - [x] String: `substring`, `substring before`, `substring after`, `string length`, `upper case`, `lower case`, `contains`, `starts with`, `ends with`, `matches`, `replace`, `split`, `strip`, `extract`
141
- - [x] Numeric: `decimal`, `floor`, `ceiling`, `round`, `abs`, `modulo`, `sqrt`, `log`, `exp`, `odd`, `even`, `random number`
142
- - [x] List: `list contains`, `count`, `min`, `max`, `sum`, `product`, `mean`, `median`, `stddev`, `mode`, `all`, `any`, `sublist`, `append`, `concatenate`, `insert before`, `remove`, `reverse`, `index of`, `union`, `distinct values`, `duplicate values`, `flatten`, `sort`, `string join`
143
- - [x] Context: `get entries`, `get value`, `get keys`
144
- - [x] Temporal: `now`, `today`, `day of week`, `day of year`, `month of year`, `week of year`
145
-
146
- ### DMN
147
-
148
27
  - [x] Parse DMN XML documents
149
28
  - [x] Evaluate DMN Decision Tables
150
29
  - [x] Evaluate dependent DMN Decision Tables
@@ -172,10 +51,6 @@ $ bin/setup
172
51
  $ bin/guard
173
52
  ```
174
53
 
175
- ## Development
176
-
177
- [Treetop Doumentation](https://cjheath.github.io/treetop/syntactic_recognition.html) is a good place to start learning about Treetop.
178
-
179
54
  ## License
180
55
 
181
56
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/lib/dmn/decision.rb CHANGED
@@ -7,7 +7,7 @@ module DMN
7
7
  def self.from_json(json)
8
8
  information_requirements = Array.wrap(json[:information_requirement]).map { |ir| InformationRequirement.from_json(ir) } if json[:information_requirement]
9
9
  decision_table = DecisionTable.from_json(json[:decision_table]) if json[:decision_table]
10
- literal_expression = LiteralExpression.from_json(json[:literal_expression]) if json[:literal_expression]
10
+ literal_expression = FEEL::LiteralExpression.from_json(json[:literal_expression]) if json[:literal_expression]
11
11
  variable = Variable.from_json(json[:variable]) if json[:variable]
12
12
  Decision.new(id: json[:id], name: json[:name], decision_table:, variable:, literal_expression:, information_requirements:)
13
13
  end
data/lib/dmn/input.rb CHANGED
@@ -5,7 +5,8 @@ module DMN
5
5
  attr_reader :id, :label, :input_expression
6
6
 
7
7
  def self.from_json(json)
8
- input_expression = LiteralExpression.from_json(json[:input_expression]) if json[:input_expression]
8
+ input_expression = FEEL::
9
+ LiteralExpression.from_json(json[:input_expression]) if json[:input_expression]
9
10
  Input.new(id: json[:id], label: json[:label], input_expression:)
10
11
  end
11
12
 
data/lib/dmn/rule.rb CHANGED
@@ -5,8 +5,8 @@ module DMN
5
5
  attr_accessor :id, :input_entries, :output_entries, :description
6
6
 
7
7
  def self.from_json(json)
8
- input_entries = Array.wrap(json[:input_entry]).map { |input_entry| UnaryTests.from_json(input_entry) }
9
- output_entries = Array.wrap(json[:output_entry]).map { |output_entry| LiteralExpression.from_json(output_entry) }
8
+ input_entries = Array.wrap(json[:input_entry]).map { |input_entry| FEEL::UnaryTests.from_json(input_entry) }
9
+ output_entries = Array.wrap(json[:output_entry]).map { |output_entry| FEEL::LiteralExpression.from_json(output_entry) }
10
10
  Rule.new(id: json[:id], input_entries:, output_entries:, description: json[:description])
11
11
  end
12
12
 
data/lib/dmn/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DMN
4
- VERSION = "0.0.3"
4
+ VERSION = "0.0.4"
5
5
  end
data/lib/dmn.rb CHANGED
@@ -6,16 +6,13 @@ require "active_support"
6
6
  require "active_support/time"
7
7
  require "active_support/core_ext/hash"
8
8
 
9
- require "treetop"
9
+ require "feel"
10
+
10
11
  require "xmlhasher"
11
12
 
12
13
  require "dmn/configuration"
13
- require "dmn/nodes"
14
- require "dmn/parser"
15
14
 
16
15
  require "dmn/variable"
17
- require "dmn/literal_expression"
18
- require "dmn/unary_tests"
19
16
  require "dmn/input"
20
17
  require "dmn/output"
21
18
  require "dmn/rule"
@@ -30,13 +27,13 @@ module DMN
30
27
  class EvaluationError < StandardError; end
31
28
 
32
29
  def self.evaluate(expression_text, variables: {})
33
- literal_expression = DMN::LiteralExpression.new(text: expression_text)
30
+ literal_expression = FEEL::LiteralExpression.new(text: expression_text)
34
31
  raise SyntaxError, "Expression is not valid" unless literal_expression.valid?
35
32
  literal_expression.evaluate(variables)
36
33
  end
37
34
 
38
35
  def self.test(input, unary_tests_text, variables: {})
39
- unary_tests = DMN::UnaryTests.new(text: unary_tests_text)
36
+ unary_tests = FEEL::UnaryTests.new(text: unary_tests_text)
40
37
  raise SyntaxError, "Unary tests are not valid" unless unary_tests.valid?
41
38
  unary_tests.test(input, variables)
42
39
  end
metadata CHANGED
@@ -1,14 +1,28 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dmn
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Connected Bits
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-03-03 00:00:00.000000000 Z
10
+ date: 2025-04-02 00:00:00.000000000 Z
11
11
  dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: feel
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: 0.0.4
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: 0.0.4
12
26
  - !ruby/object:Gem::Dependency
13
27
  name: activemodel
14
28
  requirement: !ruby/object:Gem::Requirement
@@ -275,15 +289,10 @@ files:
275
289
  - lib/dmn/decision.rb
276
290
  - lib/dmn/decision_table.rb
277
291
  - lib/dmn/definitions.rb
278
- - lib/dmn/dmn.treetop
279
292
  - lib/dmn/information_requirement.rb
280
293
  - lib/dmn/input.rb
281
- - lib/dmn/literal_expression.rb
282
- - lib/dmn/nodes.rb
283
294
  - lib/dmn/output.rb
284
- - lib/dmn/parser.rb
285
295
  - lib/dmn/rule.rb
286
- - lib/dmn/unary_tests.rb
287
296
  - lib/dmn/variable.rb
288
297
  - lib/dmn/version.rb
289
298
  homepage: https://www.connectedbits.com