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 +4 -4
- data/README.md +3 -128
- data/lib/dmn/decision.rb +1 -1
- data/lib/dmn/input.rb +2 -1
- data/lib/dmn/rule.rb +2 -2
- data/lib/dmn/version.rb +1 -1
- data/lib/dmn.rb +4 -7
- metadata +16 -7
- data/lib/dmn/dmn.treetop +0 -654
- data/lib/dmn/literal_expression.rb +0 -372
- data/lib/dmn/nodes.rb +0 -682
- data/lib/dmn/parser.rb +0 -29
- data/lib/dmn/unary_tests.rb +0 -25
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 99f8ad17d713e6ce95941ee100f3c4046a2ffc93155ea6629a6761bb3745e1ca
         | 
| 4 | 
            +
              data.tar.gz: ad53db39e8b2e96884644d177486b8cf1d65a8d608d5b09c136ee37b0d3daad5
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 8e8009211631110c50467c8ff2f8b857095ca497409171590d44135c2bd25ee5ced0d7d99c676f48a0137c3b7083c00e349f0853cca2cbfae0e45baa316b612e
         | 
| 7 | 
            +
              data.tar.gz: bf0a15e9f42f288505314de24eec35a70fdc621238e6944bd46d69b72e82de83cddab12cc891e6f2542bf5a99c7b5c32aa17a216ba4c00ef9482692abac3289a
         | 
    
        data/README.md
    CHANGED
    
    | @@ -1,69 +1,11 @@ | |
| 1 | 
            -
            #  | 
| 1 | 
            +
            # DMN
         | 
| 2 2 |  | 
| 3 | 
            -
            A light-weight DMN  | 
| 3 | 
            +
            A light-weight DMN (Decision Model and Notation) business rule ruby gem.
         | 
| 4 4 |  | 
| 5 | 
            -
            This gem  | 
| 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 | 
             
            
         | 
| 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 =  | 
| 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
    
    
    
        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 " | 
| 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 =  | 
| 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 =  | 
| 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. | 
| 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- | 
| 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
         |