kumi 0.0.10 → 0.0.12
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/.rubocop.yml +1 -1
- data/CHANGELOG.md +23 -0
- data/CLAUDE.md +7 -231
- data/README.md +5 -5
- data/docs/SYNTAX.md +66 -0
- data/docs/VECTOR_SEMANTICS.md +286 -0
- data/docs/features/hierarchical-broadcasting.md +67 -1
- data/docs/features/input-declaration-system.md +16 -0
- data/docs/features/s-expression-printer.md +2 -2
- data/lib/kumi/analyzer.rb +34 -12
- data/lib/kumi/compiler.rb +2 -12
- data/lib/kumi/core/analyzer/passes/broadcast_detector.rb +157 -64
- data/lib/kumi/core/analyzer/passes/dependency_resolver.rb +1 -1
- data/lib/kumi/core/analyzer/passes/input_access_planner_pass.rb +47 -0
- data/lib/kumi/core/analyzer/passes/input_collector.rb +123 -101
- data/lib/kumi/core/analyzer/passes/join_reduce_planning_pass.rb +293 -0
- data/lib/kumi/core/analyzer/passes/lower_to_ir_pass.rb +993 -0
- data/lib/kumi/core/analyzer/passes/pass_base.rb +2 -2
- data/lib/kumi/core/analyzer/passes/scope_resolution_pass.rb +346 -0
- data/lib/kumi/core/analyzer/passes/semantic_constraint_validator.rb +2 -1
- data/lib/kumi/core/analyzer/passes/toposorter.rb +9 -3
- data/lib/kumi/core/analyzer/passes/type_checker.rb +3 -3
- data/lib/kumi/core/analyzer/passes/type_consistency_checker.rb +2 -2
- data/lib/kumi/core/analyzer/passes/{type_inferencer.rb → type_inferencer_pass.rb} +4 -4
- data/lib/kumi/core/analyzer/passes/unsat_detector.rb +2 -2
- data/lib/kumi/core/analyzer/plans.rb +52 -0
- data/lib/kumi/core/analyzer/structs/access_plan.rb +20 -0
- data/lib/kumi/core/analyzer/structs/input_meta.rb +29 -0
- data/lib/kumi/core/compiler/access_builder.rb +36 -0
- data/lib/kumi/core/compiler/access_planner.rb +219 -0
- data/lib/kumi/core/compiler/accessors/base.rb +69 -0
- data/lib/kumi/core/compiler/accessors/each_indexed_accessor.rb +84 -0
- data/lib/kumi/core/compiler/accessors/materialize_accessor.rb +55 -0
- data/lib/kumi/core/compiler/accessors/ravel_accessor.rb +73 -0
- data/lib/kumi/core/compiler/accessors/read_accessor.rb +41 -0
- data/lib/kumi/core/compiler_base.rb +2 -2
- data/lib/kumi/core/error_reporter.rb +6 -5
- data/lib/kumi/core/errors.rb +4 -0
- data/lib/kumi/core/explain.rb +157 -205
- data/lib/kumi/core/export/node_builders.rb +2 -2
- data/lib/kumi/core/export/node_serializers.rb +1 -1
- data/lib/kumi/core/function_registry/collection_functions.rb +21 -10
- data/lib/kumi/core/function_registry/conditional_functions.rb +14 -4
- data/lib/kumi/core/function_registry/function_builder.rb +142 -55
- data/lib/kumi/core/function_registry/logical_functions.rb +5 -5
- data/lib/kumi/core/function_registry/stat_functions.rb +2 -2
- data/lib/kumi/core/function_registry.rb +126 -108
- data/lib/kumi/core/input/validator.rb +1 -1
- data/lib/kumi/core/ir/execution_engine/combinators.rb +117 -0
- data/lib/kumi/core/ir/execution_engine/interpreter.rb +336 -0
- data/lib/kumi/core/ir/execution_engine/values.rb +46 -0
- data/lib/kumi/core/ir/execution_engine.rb +50 -0
- data/lib/kumi/core/ir.rb +58 -0
- data/lib/kumi/core/ruby_parser/build_context.rb +2 -2
- data/lib/kumi/core/ruby_parser/declaration_reference_proxy.rb +0 -12
- data/lib/kumi/core/ruby_parser/dsl_cascade_builder.rb +36 -15
- data/lib/kumi/core/ruby_parser/input_builder.rb +30 -9
- data/lib/kumi/core/ruby_parser/parser.rb +1 -1
- data/lib/kumi/core/ruby_parser/schema_builder.rb +2 -2
- data/lib/kumi/core/ruby_parser/sugar.rb +7 -0
- data/lib/kumi/core/types/validator.rb +1 -1
- data/lib/kumi/registry.rb +14 -79
- data/lib/kumi/runtime/executable.rb +213 -0
- data/lib/kumi/schema.rb +14 -3
- data/lib/kumi/schema_metadata.rb +2 -2
- data/lib/kumi/support/ir_dump.rb +491 -0
- data/lib/kumi/support/s_expression_printer.rb +1 -1
- data/lib/kumi/syntax/location.rb +5 -0
- data/lib/kumi/syntax/node.rb +0 -1
- data/lib/kumi/syntax/root.rb +2 -2
- data/lib/kumi/version.rb +1 -1
- data/lib/kumi.rb +6 -15
- metadata +37 -19
- data/lib/kumi/core/cascade_executor_builder.rb +0 -132
- data/lib/kumi/core/compiled_schema.rb +0 -43
- data/lib/kumi/core/compiler/expression_compiler.rb +0 -146
- data/lib/kumi/core/compiler/function_invoker.rb +0 -55
- data/lib/kumi/core/compiler/path_traversal_compiler.rb +0 -158
- data/lib/kumi/core/compiler/reference_compiler.rb +0 -46
- data/lib/kumi/core/evaluation_wrapper.rb +0 -40
- data/lib/kumi/core/nested_structure_utils.rb +0 -78
- data/lib/kumi/core/schema_instance.rb +0 -115
- data/lib/kumi/core/vectorized_function_builder.rb +0 -88
- data/lib/kumi/js/compiler.rb +0 -878
- data/lib/kumi/js/function_registry.rb +0 -333
- data/migrate_to_core_iterative.rb +0 -938
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dc6d1a550925563fbffcc0f4f96e6609d70734dfff031d9e6e2bfd405ecf45f8
|
4
|
+
data.tar.gz: '090999f0550fcd66a79cb3f683b8f27680b5921166267bbdf57dd8c593d3c6fd'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9c18d000d924168fbef1abcc6a19f59f18af8a82fae6d4d7bb14e475ce5b34032f031a14ae3d20faa8deadf96f7e1da9bb2190fca0251da74d629c38f637c139
|
7
|
+
data.tar.gz: 37f124928afe975bb7138c2856093849b6c15fb23694d77a7a0d1628b2c67f7e262576cb734a522105b8f83253fe112f6cbacc00895ad2daba4212eb7a337384
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
## [0.0.12] – 2025-08-14
|
2
|
+
### Added
|
3
|
+
- Hash objects input declarations with `hash :field do ... end` syntax
|
4
|
+
- Complete hash object integration with arrays, nesting, and broadcasting
|
5
|
+
|
6
|
+
## [0.0.11] – 2025-08-13
|
7
|
+
### Added
|
8
|
+
- Intermediate Representation (IR) and slot-based VM interpreter.
|
9
|
+
- Scope-aware vector semantics (alignment, lift, hierarchical indices).
|
10
|
+
- Debug tooling: IR dump, VM/lowering traces via DEBUG_* flags.
|
11
|
+
|
12
|
+
### Changed
|
13
|
+
- Analyzer now lowers to IR via `LowerToIRPass`.
|
14
|
+
- Access modes: `:read`, `:ravel`, `:each_indexed`, `:materialize`.
|
15
|
+
|
16
|
+
### Removed (BREAKING)
|
17
|
+
- JavaScript transpiler (legacy compiler).
|
18
|
+
|
19
|
+
### Requirements
|
20
|
+
- Ruby >= 3.1 (Was >= 3.0)
|
21
|
+
|
22
|
+
### Notes
|
23
|
+
- No expected DSL changes for typical schemas; report regressions.
|
data/CLAUDE.md
CHANGED
@@ -18,11 +18,6 @@ Kumi is a Declarative logic and rules engine framework with static analysis for
|
|
18
18
|
- `bundle exec rspec spec/path/to/specific_spec.rb` - Run specific test file
|
19
19
|
- `bundle exec rspec spec/path/to/specific_spec.rb:123` - Run specific test at line
|
20
20
|
|
21
|
-
### Gem Management
|
22
|
-
- `bundle install` - Install dependencies
|
23
|
-
- `gem build kumi.gemspec` - Build the gem
|
24
|
-
- `gem install ./kumi-*.gem` - Install locally built gem
|
25
|
-
|
26
21
|
## Architecture Overview
|
27
22
|
|
28
23
|
### Core Components
|
@@ -72,50 +67,8 @@ Kumi is a Declarative logic and rules engine framework with static analysis for
|
|
72
67
|
- Supports custom function registration with type metadata
|
73
68
|
- Each function includes param_types, return_type, arity, and description
|
74
69
|
- Core functions include: `==`, `>`, `<`, `add`, `multiply`, `and`, `or`, `clamp`, etc.
|
75
|
-
- Maintains backward compatibility with legacy type checking system
|
76
70
|
- Function documents are generated by the script ./scripts/generate_function_docs.rb
|
77
71
|
|
78
|
-
**Input Validation System** (`lib/kumi/input/` and `lib/kumi/domain/`):
|
79
|
-
- `input/validator.rb` - Main validation coordinator for type and domain checking
|
80
|
-
- `input/type_matcher.rb` - Type validation logic for primitive and complex types
|
81
|
-
- `input/violation_creator.rb` - Creates standardized violation objects with detailed messages
|
82
|
-
- `domain/validator.rb` - Domain constraint validation (ranges, arrays, procs)
|
83
|
-
- `domain/range_analyzer.rb` - Range domain analysis and validation
|
84
|
-
- `domain/enum_analyzer.rb` - Enumeration domain analysis and validation
|
85
|
-
- `domain/violation_formatter.rb` - Formats domain violation error messages
|
86
|
-
|
87
|
-
## DSL Syntax Requirements
|
88
|
-
|
89
|
-
### Critical Syntax Rules
|
90
|
-
|
91
|
-
**Module Definition Structure**
|
92
|
-
```ruby
|
93
|
-
# CORRECT - CLI can find and load this
|
94
|
-
module SchemaName
|
95
|
-
extend Kumi::Schema
|
96
|
-
|
97
|
-
schema do
|
98
|
-
# schema definition here
|
99
|
-
end
|
100
|
-
end
|
101
|
-
```
|
102
|
-
|
103
|
-
**Function Call Syntax**:
|
104
|
-
- **Symbol style**: `fn(:function_name, arg1, arg2, ...)` - The only supported function call syntax
|
105
|
-
|
106
|
-
**Arithmetic Operations**:
|
107
|
-
- **Sugar Syntax**: `input.field1 + input.field2` - Works for input fields and value references
|
108
|
-
- **Function Syntax**: `fn(:add, input.field1, input.field2)` - Always works, more explicit
|
109
|
-
- **Mixed**: Sugar syntax for basic operations, function syntax for complex ones
|
110
|
-
|
111
|
-
**Cascade Condition Syntax**:
|
112
|
-
```ruby
|
113
|
-
value :status do
|
114
|
-
on trait_name, "Result"
|
115
|
-
base "Default"
|
116
|
-
end
|
117
|
-
```
|
118
|
-
|
119
72
|
### Key Patterns
|
120
73
|
**DSL Structure**:
|
121
74
|
```ruby
|
@@ -133,17 +86,15 @@ schema do
|
|
133
86
|
string :category
|
134
87
|
end
|
135
88
|
|
136
|
-
|
137
|
-
|
138
89
|
# Fields with no declared type
|
139
90
|
any :misc_field
|
140
91
|
end
|
141
92
|
|
142
|
-
trait :name, (expression) # Boolean conditions
|
93
|
+
trait :name, (expression) # Boolean conditions
|
143
94
|
value :name, expression # Computed values
|
144
95
|
value :name do # Conditional logic
|
145
|
-
on condition, result
|
146
|
-
base default_result
|
96
|
+
on condition, result # on <trait> ?,<trait> , <expr>
|
97
|
+
base default_result # base <expr>
|
147
98
|
end
|
148
99
|
end
|
149
100
|
```
|
@@ -151,13 +102,6 @@ end
|
|
151
102
|
**IMPORTANT CASCADE CONDITION SYNTAX:**
|
152
103
|
In cascade expressions (`value :name do ... end`), trait references use bare identifiers:
|
153
104
|
|
154
|
-
**Input Block System**:
|
155
|
-
- **Required**: All schemas must have an `input` block declaring expected fields
|
156
|
-
- **Type Declarations**: Preferred via type-specific methods (e.g. `integer :field`, `string :name`, `any :field` for untyped fields)
|
157
|
-
- **Complex Types**: Use helper functions: `array(:element_type)` and `hash(:key_type, :value_type)`
|
158
|
-
- **Domain Constraints**: Fields can have domains: `integer :age, domain: 18..65` (validated at runtime)
|
159
|
-
- **Field Access**: Use `input.field_name` to reference input fields in expressions
|
160
|
-
- **Separation**: Input metadata (types, domains) is separate from business logic
|
161
105
|
|
162
106
|
**Expression Types**:
|
163
107
|
- `input.field_name` - Access input data with operator methods (>=, <=, >, <, ==, !=)
|
@@ -179,30 +123,6 @@ In cascade expressions (`value :name do ... end`), trait references use bare ide
|
|
179
123
|
- Type inference for all declarations based on expression analysis
|
180
124
|
- Type primitives: `:string`, `:integer`, `:float`, `:boolean`, `:any`, `:symbol`, `:regexp`, `:time`, `:date`, `:datetime`
|
181
125
|
- Collection types: `array(:element_type)` and `hash(:key_type, :value_type)` helper functions
|
182
|
-
- Type compatibility checking and unification algorithms for numeric types
|
183
|
-
- Enhanced error messages showing type provenance (declared vs inferred)
|
184
|
-
- Legacy compatibility constants maintained for backward compatibility
|
185
|
-
|
186
|
-
### Examples Directory
|
187
|
-
|
188
|
-
The `examples/` directory contains examples showing Kumi usage patterns:
|
189
|
-
- `cascade_demonstration.rb` - Demonstrates cascade logic with UnsatDetector fixes (working)
|
190
|
-
- `working_comprehensive_schema.rb` - Feature showcase (current best practices, working)
|
191
|
-
- Mathematical predicate examples - Safe mutual recursion patterns using cascade mutual exclusion
|
192
|
-
- `federal_tax_calculator_2024.rb` - Real-world tax calculation example (working)
|
193
|
-
- `tax_2024.rb` - Tax example with explain functionality (working)
|
194
|
-
- `wide_schema_compilation_and_evaluation_benchmark.rb` - Benchmark for wide schemas (compilation and evaluation)
|
195
|
-
- `deep_schema_compilation_and_evaluation_benchmark.rb` - Performance benchmark for deep dependency chains (stack-safe evaluation)
|
196
|
-
- `comprehensive_god_schema.rb` - Complex example (currently has UnsatDetector semantic errors)
|
197
|
-
|
198
|
-
*Note: Some examples may use deprecated syntax and should be updated to use the new input block system.*
|
199
|
-
|
200
|
-
## Test Structure
|
201
|
-
|
202
|
-
- `spec/kumi/` - Unit tests for core components
|
203
|
-
- `spec/integration/` - Integration tests for full workflows
|
204
|
-
- `spec/fixtures/` - Test fixtures and sample schemas
|
205
|
-
- `spec/support/` - Test helpers (`ast_factory.rb`, `schema_generator.rb`)
|
206
126
|
|
207
127
|
## Files for Understanding
|
208
128
|
|
@@ -210,46 +130,8 @@ The `examples/` directory contains examples showing Kumi usage patterns:
|
|
210
130
|
- `examples/*` Random examples of diverse contexts.
|
211
131
|
|
212
132
|
### Troubleshooting Schema Issues
|
213
|
-
|
214
|
-
- **Module Not Found**: Check module structure and naming, see examples
|
215
|
-
- **UnsatDetector Errors**: Review trait logic for contradictions, add debugs!
|
216
|
-
- **Type Errors**: Check input block type declarations match usage, add debugs!
|
217
|
-
- **Runtime Errors**: Use explain to trace computation dependencies, add debugs!
|
133
|
+
DEBUG, DEBUG. DEBUG LOGS!
|
218
134
|
|
219
|
-
## Input Block System Details
|
220
|
-
|
221
|
-
### Required Input Blocks
|
222
|
-
- **All schemas must have an input block** -
|
223
|
-
- Input blocks declare expected fields with optional type and domain constraints
|
224
|
-
- **Empty input blocks are allowed** -`input {}` Even if not useful.
|
225
|
-
- Fields are accessed via `input.field_name` or `input.field.nested_field.nested_nested_field` which
|
226
|
-
works for referencing nested array input declarations.
|
227
|
-
|
228
|
-
### Type System Integration
|
229
|
-
- **Declared Types**: Explicit type declarations in input blocks (e.g. `integer :field`, `string :name`, `any :field`)
|
230
|
-
- **Inferred Types**: Types automatically inferred from expression analysis
|
231
|
-
- **Type Checking**: Validates compatibility between declared and inferred types
|
232
|
-
- **Enhanced Errors**: Error messages show type provenance (declared vs inferred)
|
233
|
-
- **Helper Functions**: Use `array(:type)` and `hash(:key_type, :value_type)` for complex types
|
234
|
-
|
235
|
-
### Parser Components
|
236
|
-
See `lib/kumi/ruby_parser/parser.rb`
|
237
|
-
|
238
|
-
### Domain Constraints
|
239
|
-
- Can be declared: `integer :age, domain: 18..65`
|
240
|
-
- Supports Range domains (`18..65`), Array domains (`%w[active inactive]`), and Proc domains for custom validation
|
241
|
-
- Analyzer do some limited domain UNSAT detection, and its used to validated against input at Runtime
|
242
|
-
### Type Examples
|
243
|
-
```ruby
|
244
|
-
input do
|
245
|
-
string :name
|
246
|
-
integer :age, domain: 18..65
|
247
|
-
hash :metadata, key: { type: :string }, val: { type: :any }
|
248
|
-
|
249
|
-
#generic type
|
250
|
-
any :misc # this reduces Kumi's analyze/inference capabilities
|
251
|
-
end
|
252
|
-
```
|
253
135
|
|
254
136
|
### Array Broadcasting System
|
255
137
|
|
@@ -262,6 +144,9 @@ input do
|
|
262
144
|
float :price
|
263
145
|
integer :quantity
|
264
146
|
string :category
|
147
|
+
array :prices do
|
148
|
+
element :integer, :val
|
149
|
+
end
|
265
150
|
end
|
266
151
|
end
|
267
152
|
|
@@ -269,112 +154,3 @@ end
|
|
269
154
|
value :subtotals, input.line_items.price * input.line_items.quantity
|
270
155
|
trait :is_taxable, (input.line_items.category != "digital")
|
271
156
|
```
|
272
|
-
|
273
|
-
**Aggregation Operations**: Functions consuming arrays are detected:
|
274
|
-
```ruby
|
275
|
-
value :total_subtotal, fn(:sum, subtotals)
|
276
|
-
value :avg_price, fn(:avg, input.line_items.price)
|
277
|
-
value :max_quantity, fn(:max, input.line_items.quantity)
|
278
|
-
```
|
279
|
-
|
280
|
-
**Implementation Components**:
|
281
|
-
- **InputElementReference** AST nodes for nested field access paths
|
282
|
-
- **BroadcastDetector** analyzer pass identifies vectorized vs scalar operations
|
283
|
-
- **Compiler** generates appropriate map/reduce functions based on usage context
|
284
|
-
- **Type Inference** infers types for array element operations
|
285
|
-
- Supports arbitrary depth field access with nested arrays and hashes
|
286
|
-
|
287
|
-
### Trait Syntax Evolution
|
288
|
-
|
289
|
-
**Current Syntax** (recommended):
|
290
|
-
```ruby
|
291
|
-
trait :adult, (input.age >= 18)
|
292
|
-
trait :qualified, (input.age >= 21) & (input.score > 80) & (input.verified == true)
|
293
|
-
```
|
294
|
-
|
295
|
-
**Composite Trait Syntax** (NEW - bare identifier references):
|
296
|
-
```ruby
|
297
|
-
# Base traits
|
298
|
-
trait :adult, (input.age >= 18)
|
299
|
-
trait :verified, (input.verified == true)
|
300
|
-
trait :high_score, (input.score > 80)
|
301
|
-
|
302
|
-
# Composite traits using bare identifier syntax
|
303
|
-
trait :eligible, adult & verified & high_score
|
304
|
-
trait :mixed, adult & (input.income > 50_000) & verified
|
305
|
-
|
306
|
-
# Backward compatibility - both syntaxes work together
|
307
|
-
trait :legacy_mix, adult & ref(:verified) & (input.score > 90)
|
308
|
-
```
|
309
|
-
|
310
|
-
**Deprecated Syntax** (with warnings):
|
311
|
-
```ruby
|
312
|
-
trait :adult, input.age, :>=, 18 # OLD - shows deprecation warning
|
313
|
-
trait :qualified, input.age, :>=, 21, input.score # OLD - shows deprecation warning
|
314
|
-
```
|
315
|
-
|
316
|
-
**Key Changes**:
|
317
|
-
- **NEW**: Bare identifier syntax for direct trait reference: `adult` instead of `ref(:adult)`
|
318
|
-
- New syntax uses parenthesized expressions: `trait :name, (expression)`
|
319
|
-
- FieldRef nodes have operator methods that create CallExpression nodes
|
320
|
-
- Logical AND chaining via `&` operator (Ruby limitation prevents `&&`)
|
321
|
-
- Only AND operations supported to maintain constraint satisfaction system
|
322
|
-
- **Backward Compatible**: Both `trait_name` and `ref(:trait_name)` work together
|
323
|
-
- Old syntax maintained with deprecation warnings for backward compatibility
|
324
|
-
|
325
|
-
## Common Development Tasks
|
326
|
-
|
327
|
-
### Adding New Analyzer Passes
|
328
|
-
1. Create pass class inheriting from `PassBase` in `lib/kumi/analyzer/passes/`
|
329
|
-
2. Implement `run(errors)` method that calls `set_state(key, value)` to store results
|
330
|
-
3. Add pass to `PASSES` array in `lib/kumi/analyzer.rb` in correct order
|
331
|
-
4. Consider dependencies on other passes (e.g., TypeChecker needs TypeInferencer)
|
332
|
-
|
333
|
-
## Architecture Design Principles
|
334
|
-
|
335
|
-
- **Multi-pass Analysis**: Each analysis pass has a single responsibility and builds on previous passes
|
336
|
-
- **Immutable Syntax Tree**: AST nodes are immutable; analysis results stored separately in analyzer state
|
337
|
-
- **Dependency-driven Evaluation**: All computation follows dependency graph for correct order
|
338
|
-
- **Type Safety**: Optional type checking without breaking existing schemas
|
339
|
-
- **Ruby Integration**: Leverages Ruby's metaprogramming with structured analysis
|
340
|
-
- **Unified Error Reporting**: Consistent, localized error messages throughout the system with clear interface patterns
|
341
|
-
|
342
|
-
## Code Organization Patterns
|
343
|
-
|
344
|
-
### Testing Best Practices
|
345
|
-
- **Spec Organization**: Tests organized by component with clear separation between unit and integration tests
|
346
|
-
- **Error Variable Extraction**: RSpec patterns avoid multiline block chains by extracting error variables for assertion
|
347
|
-
|
348
|
-
## Development Guides and Standards
|
349
|
-
|
350
|
-
### Error Reporting Standards
|
351
|
-
**For Parser Classes**:
|
352
|
-
```ruby
|
353
|
-
class MyParser
|
354
|
-
include ErrorReporting
|
355
|
-
|
356
|
-
def parse_something
|
357
|
-
# Error raising
|
358
|
-
raise_syntax_error("Invalid syntax", location: current_location)
|
359
|
-
end
|
360
|
-
end
|
361
|
-
```
|
362
|
-
|
363
|
-
**For Analyzer Passes**:
|
364
|
-
```ruby
|
365
|
-
class MyAnalyzerPass < PassBase
|
366
|
-
def run(errors)
|
367
|
-
# Error accumulation with enhanced location
|
368
|
-
report_error(errors, "semantic error", location: node.loc, type: :semantic)
|
369
|
-
|
370
|
-
# Backward compatible method
|
371
|
-
add_error(errors, node.loc, "legacy format error")
|
372
|
-
end
|
373
|
-
end
|
374
|
-
```
|
375
|
-
### Testing Error Scenarios
|
376
|
-
- Use `spec/integration/dsl_breakage_spec.rb` patterns for error testing
|
377
|
-
- Use `spec/integration/potential_breakage_spec.rb` for edge cases break
|
378
|
-
- Use `spec/fixtures/location_tracking_test_schema.rb` fixture for testing different syntax error types
|
379
|
-
|
380
|
-
#
|
data/README.md
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
[](https://github.com/amuta/kumi/actions)
|
4
4
|
[](https://badge.fury.io/rb/kumi)
|
5
5
|
|
6
|
-
Kumi is a
|
6
|
+
**Kumi** is a declarative rules-and-calculation DSL for Ruby. It compiles business logic into a **typed, analyzable dependency graph** with **vector semantics** over nested data, performs **static checks** at definition time, **lowers to a compact IR**, and executes **deterministically**.
|
7
7
|
|
8
8
|
It handles complex, interdependent calculations with validation and consistency checking.
|
9
9
|
|
@@ -66,7 +66,7 @@ Validation happens during schema definition.
|
|
66
66
|
## Installation
|
67
67
|
|
68
68
|
```bash
|
69
|
-
# Requires Ruby 3.
|
69
|
+
# Requires Ruby 3.1+
|
70
70
|
# No external dependencies
|
71
71
|
gem install kumi
|
72
72
|
```
|
@@ -436,8 +436,8 @@ runner[:after_tax] # => 196,844.80 (cached)
|
|
436
436
|
- Sequential procedural workflows
|
437
437
|
- High-frequency processing
|
438
438
|
|
439
|
-
## JavaScript Transpiler
|
440
|
-
|
439
|
+
## JavaScript Transpiler (V 0.0.10)
|
440
|
+
Note: On the current 0.0.11 this is disabled but will be back in later versions. reason: IR/Interpreter update.
|
441
441
|
Transpiles compiled schemas to standalone JavaScript code. See [docs/features/javascript-transpiler.md](docs/features/javascript-transpiler.md) for details.
|
442
442
|
|
443
443
|
```ruby
|
@@ -465,7 +465,7 @@ See [docs/features/performance.md](docs/features/performance.md) for detailed be
|
|
465
465
|
|
466
466
|
## What Kumi does not guarantee
|
467
467
|
|
468
|
-
Lambdas (e.g. -> inside the schema), external IO, floating-point vs bignum,
|
468
|
+
Lambdas (e.g. -> inside the schema), external IO, floating-point vs bignum, time-zone math differences, etc.
|
469
469
|
|
470
470
|
## Learn More
|
471
471
|
|
data/docs/SYNTAX.md
CHANGED
@@ -214,12 +214,14 @@ Array broadcasting enables element-wise operations on array fields with automati
|
|
214
214
|
|
215
215
|
```ruby
|
216
216
|
input do
|
217
|
+
# Structured array with defined fields
|
217
218
|
array :line_items do
|
218
219
|
float :price
|
219
220
|
integer :quantity
|
220
221
|
string :category
|
221
222
|
end
|
222
223
|
|
224
|
+
# Nested arrays with hash objects
|
223
225
|
array :orders do
|
224
226
|
array :items do
|
225
227
|
hash :product do
|
@@ -229,6 +231,15 @@ input do
|
|
229
231
|
integer :quantity
|
230
232
|
end
|
231
233
|
end
|
234
|
+
|
235
|
+
# Dynamic arrays with flexible element types
|
236
|
+
array :api_responses do
|
237
|
+
element :any, :response_data # For dynamic/unknown hash structures
|
238
|
+
end
|
239
|
+
|
240
|
+
array :measurements do
|
241
|
+
element :float, :value # For simple scalar arrays
|
242
|
+
end
|
232
243
|
end
|
233
244
|
```
|
234
245
|
|
@@ -290,6 +301,61 @@ value :avg_line_total, fn(:avg, line_totals)
|
|
290
301
|
trait :has_expensive, fn(:any?, expensive_items)
|
291
302
|
```
|
292
303
|
|
304
|
+
### Dynamic Hash Elements with `element :any`
|
305
|
+
|
306
|
+
For arrays containing hash data with unknown or flexible structure, use `element :any` instead of defining explicit hash objects:
|
307
|
+
|
308
|
+
```ruby
|
309
|
+
input do
|
310
|
+
array :api_responses do
|
311
|
+
element :any, :response_data
|
312
|
+
end
|
313
|
+
|
314
|
+
array :user_profiles do
|
315
|
+
element :any, :profile_info
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
# Access hash data using fn(:fetch)
|
320
|
+
value :response_codes, fn(:fetch, input.api_responses.response_data, "status")
|
321
|
+
value :user_names, fn(:fetch, input.user_profiles.profile_info, "name")
|
322
|
+
value :user_ages, fn(:fetch, input.user_profiles.profile_info, "age")
|
323
|
+
|
324
|
+
# Mathematical operations on extracted values
|
325
|
+
value :avg_response_time, fn(:mean, fn(:fetch, input.api_responses.response_data, "response_time"))
|
326
|
+
value :total_users, fn(:size, input.user_profiles.profile_info)
|
327
|
+
|
328
|
+
# Traits using dynamic data
|
329
|
+
trait :success_responses, fn(:any?, fn(:fetch, input.api_responses.response_data, "status") == 200)
|
330
|
+
trait :adult_users, fn(:any?, fn(:fetch, input.user_profiles.profile_info, "age") >= 18)
|
331
|
+
```
|
332
|
+
|
333
|
+
**Use Cases for `element :any`:**
|
334
|
+
- API responses with varying schemas
|
335
|
+
- Configuration data with flexible structure
|
336
|
+
- Dynamic hash structures (unknown keys at schema definition time)
|
337
|
+
- Legacy data where hash structure may vary
|
338
|
+
- When you need maximum flexibility without type constraints
|
339
|
+
|
340
|
+
**Comparison: `element :any` vs Hash Objects**
|
341
|
+
|
342
|
+
```ruby
|
343
|
+
# element :any approach (flexible, dynamic)
|
344
|
+
array :users do
|
345
|
+
element :any, :data
|
346
|
+
end
|
347
|
+
value :names, fn(:fetch, input.users.data, "name")
|
348
|
+
|
349
|
+
# hash object approach (typed, structured)
|
350
|
+
array :users do
|
351
|
+
hash :data do
|
352
|
+
string :name
|
353
|
+
integer :age
|
354
|
+
end
|
355
|
+
end
|
356
|
+
value :names, input.users.data.name
|
357
|
+
```
|
358
|
+
|
293
359
|
### Broadcasting Type Inference
|
294
360
|
|
295
361
|
The type system automatically infers appropriate types:
|