stellwerk-ruby 0.1.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 +7 -0
- data/CHANGELOG.md +27 -0
- data/LICENSE.txt +21 -0
- data/README.md +164 -0
- data/lib/stellwerk/errors.rb +18 -0
- data/lib/stellwerk/evaluator.rb +748 -0
- data/lib/stellwerk/flow.rb +88 -0
- data/lib/stellwerk/functions.rb +318 -0
- data/lib/stellwerk/result.rb +35 -0
- data/lib/stellwerk/version.rb +5 -0
- data/lib/stellwerk.rb +60 -0
- metadata +115 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 796b4095b7fea502bbfacb3e03aa62ab11fd85234c69e5ee2ebd867e82b1586b
|
|
4
|
+
data.tar.gz: ef32afa830843674ef9e83175538181c087910be20fd7b9406a927ee192f1bd7
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 882b4adabe5be8af497114eefbd7e0454c145de3b98235de44e77db01e40e588fb56ffc21bc2741ba307cf4b2987a8b5ad6d4d6525ef6c394e1813f7cedb2c70
|
|
7
|
+
data.tar.gz: 9ed76a0cfc751cb41fcc46c02d2a2fb97e48dcc0ac24ed8570bbe5bb5cbfddf8fdb762d125356db014e5ba963e9f35f442e0b6b7b24f43eac2aaf2f1f0fbb55d
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.1.0] - 2026-01-31
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Initial release of stellwerk-ruby gem
|
|
13
|
+
- Flow evaluation engine for pre-compiled Stellwerk JSON
|
|
14
|
+
- Support for all core node types:
|
|
15
|
+
- `start` - Entry point with input validation
|
|
16
|
+
- `calculate` - Formula evaluation using Dentaku
|
|
17
|
+
- `condition` - Boolean branching (true/false)
|
|
18
|
+
- `switch` - Multi-case branching
|
|
19
|
+
- `merge` - Joins multiple branches
|
|
20
|
+
- `map` - Array iteration with sub-flow execution
|
|
21
|
+
- `end` - Output template processing
|
|
22
|
+
- Built-in collection functions:
|
|
23
|
+
- Aggregation: `SUM`, `COUNT`, `MIN`, `MAX`, `AVERAGE`/`AVG`
|
|
24
|
+
- Array operations: `FIRST`, `LAST`, `TAKE`, `DISTINCT`, `PROJECT`
|
|
25
|
+
- Higher-order: `MAP`, `FILTER`, `REDUCE`, `SUMIF`, `COUNTIF`
|
|
26
|
+
- Configuration system with optional logging
|
|
27
|
+
- Result object with success/failure states, outputs, and execution context
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Roadwerk
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# Stellwerk
|
|
2
|
+
|
|
3
|
+
A standalone Ruby gem for evaluating pre-compiled Stellwerk flows without any Rails or ActiveRecord dependencies.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Add this line to your application's Gemfile:
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
gem 'stellwerk-ruby'
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
And then execute:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
bundle install
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Or install it yourself as:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
gem install stellwerk-ruby
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Usage
|
|
26
|
+
|
|
27
|
+
### Simple Usage
|
|
28
|
+
|
|
29
|
+
```ruby
|
|
30
|
+
require 'stellwerk'
|
|
31
|
+
|
|
32
|
+
# Load a compiled flow from a JSON file
|
|
33
|
+
flow = Stellwerk::Flow.load('pricing.compiled.json')
|
|
34
|
+
|
|
35
|
+
# Execute with input parameters
|
|
36
|
+
result = flow.execute(quantity: 10, price: 25.00)
|
|
37
|
+
|
|
38
|
+
if result.success?
|
|
39
|
+
puts result.outputs[:total]
|
|
40
|
+
else
|
|
41
|
+
puts result.errors
|
|
42
|
+
end
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Direct Evaluator Usage
|
|
46
|
+
|
|
47
|
+
For more control, you can use the evaluator directly:
|
|
48
|
+
|
|
49
|
+
```ruby
|
|
50
|
+
require 'stellwerk'
|
|
51
|
+
require 'json'
|
|
52
|
+
|
|
53
|
+
json = JSON.parse(File.read('flow.json'))
|
|
54
|
+
result = Stellwerk::Evaluator.call(
|
|
55
|
+
compiled_json: json,
|
|
56
|
+
params: { x: 10, y: 20 }
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
puts result.outputs
|
|
60
|
+
puts result.context
|
|
61
|
+
puts result.applied_nodes
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Configuration
|
|
65
|
+
|
|
66
|
+
```ruby
|
|
67
|
+
require 'logger'
|
|
68
|
+
|
|
69
|
+
Stellwerk.configure do |config|
|
|
70
|
+
config.logger = Logger.new(STDOUT)
|
|
71
|
+
end
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Compiled JSON Format
|
|
75
|
+
|
|
76
|
+
The gem expects compiled flow JSON in this structure:
|
|
77
|
+
|
|
78
|
+
```json
|
|
79
|
+
{
|
|
80
|
+
"version": "1.0",
|
|
81
|
+
"compiled_at": "2026-01-31T12:00:00Z",
|
|
82
|
+
"entry_node_ids": ["node-1"],
|
|
83
|
+
"nodes": {
|
|
84
|
+
"node-1": {
|
|
85
|
+
"id": "node-1",
|
|
86
|
+
"name": "Start",
|
|
87
|
+
"type": "start",
|
|
88
|
+
"config": { "inputs": [...] }
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
"adjacency": {
|
|
92
|
+
"node-1": [{ "to": "node-2", "branch": null }]
|
|
93
|
+
},
|
|
94
|
+
"reverse_adjacency": {
|
|
95
|
+
"node-2": ["node-1"]
|
|
96
|
+
},
|
|
97
|
+
"sub_flows": {
|
|
98
|
+
"flow-uuid": { ... embedded sub-flow ... }
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Node Types
|
|
104
|
+
|
|
105
|
+
The evaluator supports the following node types:
|
|
106
|
+
|
|
107
|
+
- **start**: Entry point with input validation
|
|
108
|
+
- **calculate**: Formula evaluation using Dentaku
|
|
109
|
+
- **condition**: Boolean branching (true/false)
|
|
110
|
+
- **switch**: Multi-case branching
|
|
111
|
+
- **merge**: Joins multiple branches
|
|
112
|
+
- **map**: Iterates over arrays with sub-flow execution
|
|
113
|
+
- **end**: Output template processing
|
|
114
|
+
|
|
115
|
+
## Built-in Functions
|
|
116
|
+
|
|
117
|
+
The gem includes collection functions for use in formulas:
|
|
118
|
+
|
|
119
|
+
### Aggregation
|
|
120
|
+
- `SUM(array)` or `SUM(a, b, c)`
|
|
121
|
+
- `COUNT(array)`
|
|
122
|
+
- `MIN(array)` / `MAX(array)`
|
|
123
|
+
- `AVERAGE(array)` or `AVG(array)`
|
|
124
|
+
|
|
125
|
+
### Array Operations
|
|
126
|
+
- `FIRST(array)` / `LAST(array)`
|
|
127
|
+
- `TAKE(array, n)`
|
|
128
|
+
- `DISTINCT(array)`
|
|
129
|
+
- `PROJECT(array, "field")` - Extract field from array of hashes
|
|
130
|
+
|
|
131
|
+
### Higher-Order Functions
|
|
132
|
+
- `MAP(array, "expression")` - Transform elements
|
|
133
|
+
- `FILTER(array, "predicate")` - Filter elements
|
|
134
|
+
- `REDUCE(array, initial, "expression")` - Reduce to single value
|
|
135
|
+
- `SUMIF(array, "predicate", "projection")` - Conditional sum
|
|
136
|
+
- `COUNTIF(array, "predicate")` - Conditional count
|
|
137
|
+
|
|
138
|
+
## Result Object
|
|
139
|
+
|
|
140
|
+
Execution returns a `Stellwerk::Result` object:
|
|
141
|
+
|
|
142
|
+
```ruby
|
|
143
|
+
result = flow.execute(params)
|
|
144
|
+
|
|
145
|
+
result.success? # => true/false
|
|
146
|
+
result.failure? # => true/false
|
|
147
|
+
result.outputs # => Hash of output values
|
|
148
|
+
result.errors # => Array of error messages/hashes
|
|
149
|
+
result.applied_nodes # => Array of executed nodes
|
|
150
|
+
result.context # => Full execution context
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Development
|
|
154
|
+
|
|
155
|
+
After checking out the repo, run:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
bundle install
|
|
159
|
+
bundle exec rspec
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## License
|
|
163
|
+
|
|
164
|
+
The gem is available as open source under the terms of the [MIT License](LICENSE.txt).
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Stellwerk
|
|
4
|
+
# Base error class for all Stellwerk errors
|
|
5
|
+
class Error < StandardError; end
|
|
6
|
+
|
|
7
|
+
# Raised when the compiled JSON is invalid or malformed
|
|
8
|
+
class InvalidFlowError < Error; end
|
|
9
|
+
|
|
10
|
+
# Raised when flow evaluation encounters an error
|
|
11
|
+
class EvaluationError < Error; end
|
|
12
|
+
|
|
13
|
+
# Raised when a required sub-flow is not found
|
|
14
|
+
class SubFlowNotFoundError < Error; end
|
|
15
|
+
|
|
16
|
+
# Raised when a required input is missing
|
|
17
|
+
class MissingInputError < Error; end
|
|
18
|
+
end
|