kumi 0.0.6 → 0.0.7
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/CLAUDE.md +33 -176
- data/README.md +33 -2
- data/docs/SYNTAX.md +2 -7
- data/docs/features/array-broadcasting.md +1 -1
- data/docs/schema_metadata/broadcasts.md +53 -0
- data/docs/schema_metadata/cascades.md +45 -0
- data/docs/schema_metadata/declarations.md +54 -0
- data/docs/schema_metadata/dependencies.md +57 -0
- data/docs/schema_metadata/evaluation_order.md +29 -0
- data/docs/schema_metadata/examples.md +95 -0
- data/docs/schema_metadata/inferred_types.md +46 -0
- data/docs/schema_metadata/inputs.md +86 -0
- data/docs/schema_metadata.md +108 -0
- data/lib/kumi/analyzer/passes/broadcast_detector.rb +52 -57
- data/lib/kumi/analyzer/passes/dependency_resolver.rb +8 -8
- data/lib/kumi/analyzer/passes/input_collector.rb +2 -2
- data/lib/kumi/analyzer/passes/name_indexer.rb +2 -2
- data/lib/kumi/analyzer/passes/semantic_constraint_validator.rb +15 -16
- data/lib/kumi/analyzer/passes/toposorter.rb +23 -23
- data/lib/kumi/analyzer/passes/type_checker.rb +7 -9
- data/lib/kumi/analyzer/passes/type_consistency_checker.rb +2 -2
- data/lib/kumi/analyzer/passes/type_inferencer.rb +24 -24
- data/lib/kumi/analyzer/passes/unsat_detector.rb +11 -13
- data/lib/kumi/analyzer.rb +5 -5
- data/lib/kumi/compiler.rb +39 -45
- data/lib/kumi/error_reporting.rb +1 -1
- data/lib/kumi/explain.rb +12 -0
- data/lib/kumi/export/node_registry.rb +2 -2
- data/lib/kumi/json_schema/generator.rb +63 -0
- data/lib/kumi/json_schema/validator.rb +25 -0
- data/lib/kumi/json_schema.rb +14 -0
- data/lib/kumi/{parser → ruby_parser}/build_context.rb +1 -1
- data/lib/kumi/{parser → ruby_parser}/declaration_reference_proxy.rb +3 -3
- data/lib/kumi/{parser → ruby_parser}/dsl.rb +1 -1
- data/lib/kumi/{parser → ruby_parser}/dsl_cascade_builder.rb +2 -2
- data/lib/kumi/{parser → ruby_parser}/expression_converter.rb +14 -14
- data/lib/kumi/{parser → ruby_parser}/guard_rails.rb +1 -1
- data/lib/kumi/{parser → ruby_parser}/input_builder.rb +1 -1
- data/lib/kumi/{parser → ruby_parser}/input_field_proxy.rb +4 -4
- data/lib/kumi/{parser → ruby_parser}/input_proxy.rb +1 -1
- data/lib/kumi/{parser → ruby_parser}/nested_input.rb +1 -1
- data/lib/kumi/{parser → ruby_parser}/parser.rb +11 -10
- data/lib/kumi/{parser → ruby_parser}/schema_builder.rb +1 -1
- data/lib/kumi/{parser → ruby_parser}/sugar.rb +1 -1
- data/lib/kumi/ruby_parser.rb +10 -0
- data/lib/kumi/schema.rb +10 -4
- data/lib/kumi/schema_instance.rb +6 -6
- data/lib/kumi/schema_metadata.rb +524 -0
- data/lib/kumi/vectorization_metadata.rb +4 -4
- data/lib/kumi/version.rb +1 -1
- data/lib/kumi.rb +14 -0
- metadata +28 -15
- data/lib/generators/trait_engine/templates/schema_spec.rb.erb +0 -27
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ec2c56684edac64e9818bbf85de98e9855c3d50df80c490c8f868b3e9b701dab
|
4
|
+
data.tar.gz: d5246f98e10b0365b47f6a67fed5c3a4cbc77d5ad15905d93b046251965135f5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f71ba6867b72145247b5c1ea4c3b197f831996bf078798c6a9decdb4e047f83859e062e6a6411e2311d279f8a8cc03ca7e16ac194c9a27b84f8a55b67faa3fcb
|
7
|
+
data.tar.gz: 70c4dab6bf036da2d507f89c2d8e9d65a24da2685412d3e517a2b3c1696d200c294c512786c85bfccf9feca301e90e70a26999f5ed1528221331b55f77175c8d
|
data/CLAUDE.md
CHANGED
@@ -5,11 +5,9 @@
|
|
5
5
|
!! Do not care about linter or coverage unless asked to do so.
|
6
6
|
!! IMPORTANT: Communication style - Write direct, factual statements. Avoid promotional language, unnecessary claims, or marketing speak. State what the system does, not what benefits it provides. Use TODOs for missing information rather than placeholder claims.
|
7
7
|
|
8
|
-
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
9
|
-
|
10
8
|
## Project Overview
|
11
9
|
|
12
|
-
Kumi is a
|
10
|
+
Kumi is a Declarative logic and rules engine framework with static analysis for Ruby.
|
13
11
|
|
14
12
|
## Development Commands
|
15
13
|
|
@@ -18,29 +16,11 @@ Kumi is a declarative decision-modeling compiler for Ruby that transforms comple
|
|
18
16
|
- `bundle exec rspec spec/path/to/specific_spec.rb` - Run specific test file
|
19
17
|
- `bundle exec rspec spec/path/to/specific_spec.rb:123` - Run specific test at line
|
20
18
|
|
21
|
-
### Linting & Code Quality
|
22
|
-
- `bundle exec rubocop` - Run RuboCop linter
|
23
|
-
- `bundle exec rubocop -a` - Auto-fix RuboCop issues where possible
|
24
|
-
- `rake` - Run default task (includes rspec and rubocop)
|
25
|
-
|
26
19
|
### Gem Management
|
27
20
|
- `bundle install` - Install dependencies
|
28
21
|
- `gem build kumi.gemspec` - Build the gem
|
29
22
|
- `gem install ./kumi-*.gem` - Install locally built gem
|
30
23
|
|
31
|
-
### Kumi CLI
|
32
|
-
- `./bin/kumi -i` - Start interactive REPL mode for rapid schema testing
|
33
|
-
- `./bin/kumi -f schema.rb -d data.json` - Execute schema file with input data
|
34
|
-
- `./bin/kumi -f schema.rb -k key1,key2` - Extract specific keys from schema
|
35
|
-
- `./bin/kumi -f schema.rb -e key_name` - Explain how a key is computed
|
36
|
-
- `./bin/kumi -f schema.rb -d data.json -o json` - Output results in JSON format
|
37
|
-
|
38
|
-
**CLI Features**:
|
39
|
-
- Interactive REPL with schema loading, data manipulation, and live evaluation
|
40
|
-
- File-based schema execution with JSON/YAML input data support
|
41
|
-
- Selective key extraction and explain functionality for debugging
|
42
|
-
- Multiple output formats (pretty, JSON, YAML) for integration
|
43
|
-
|
44
24
|
## Architecture Overview
|
45
25
|
|
46
26
|
### Core Components
|
@@ -50,13 +30,7 @@ Kumi is a declarative decision-modeling compiler for Ruby that transforms comple
|
|
50
30
|
- Provides the `schema(&block)` DSL method that builds the syntax tree, runs analysis, and compiles to executable form
|
51
31
|
- Generates a `Runner` instance for executing queries against input data
|
52
32
|
|
53
|
-
**Parser** (`lib/kumi/
|
54
|
-
- `dsl.rb` - Main DSL parser that converts Ruby block syntax into AST nodes
|
55
|
-
- `dsl_builder_context.rb` - Context for building DSL elements with input/value/trait methods
|
56
|
-
- `dsl_cascade_builder.rb` - Specialized builder for cascade expressions
|
57
|
-
- `dsl_proxy.rb` - Proxy object for method delegation during parsing
|
58
|
-
- `input_dsl_proxy.rb` - Proxy for input block DSL supporting both `key` method and type-specific DSL methods
|
59
|
-
- `input_proxy.rb` - Proxy for `input.field_name` references in expressions
|
33
|
+
**Parser** (`lib/kumi/ruby_parser{/*,.rb}`):
|
60
34
|
|
61
35
|
**Syntax Tree** (`lib/kumi/syntax/`):
|
62
36
|
- `node.rb` - Base node class with location tracking
|
@@ -66,12 +40,13 @@ Kumi is a declarative decision-modeling compiler for Ruby that transforms comple
|
|
66
40
|
- `input_declaration.rb` - Input field declaration nodes (formerly FieldDecl)
|
67
41
|
- `call_expression.rb` - Function call expression nodes
|
68
42
|
- `array_expression.rb` - Array expression nodes (formerly ListExpression)
|
69
|
-
- `hash_expression.rb` - Hash expression nodes (for future hash literals)
|
43
|
+
- `hash_expression.rb` - Hash expression nodes (for future hash literals) (currently not used)
|
70
44
|
- `cascade_expression.rb` - Cascade expression nodes (conditional values)
|
71
45
|
- `case_expression.rb` - Case expression nodes (formerly WhenCaseExpression)
|
72
46
|
- `literal.rb` - Literal value nodes
|
73
|
-
- `input_reference.rb` - Input field reference nodes (formerly FieldRef)
|
74
|
-
- `
|
47
|
+
- `input_reference.rb` - Input field reference nodes (formerly FieldRef)
|
48
|
+
- `input_element_reference.rb` - Reference to nested input field (array -> obj.field)
|
49
|
+
- `declaration_reference.rb` - Declaration reference value or trait nodes
|
75
50
|
|
76
51
|
**Analyzer** (`lib/kumi/analyzer.rb`):
|
77
52
|
- Multi-pass analysis system that validates schemas and builds dependency graphs
|
@@ -135,10 +110,7 @@ end
|
|
135
110
|
```
|
136
111
|
|
137
112
|
**Function Call Syntax**:
|
138
|
-
- **Symbol style**: `fn(:function_name, arg1, arg2)` -
|
139
|
-
- **Method style**: `fn.function_name(arg1, arg2)` - Also works, more readable
|
140
|
-
- **Incorrect**: `fn()` - Empty function calls cause parse errors
|
141
|
-
- **Incorrect**: `fn.function_name()` - Empty method calls cause parse errors
|
113
|
+
- **Symbol style**: `fn(:function_name, arg1, arg2, ...)` - The only supported function call syntax
|
142
114
|
|
143
115
|
**Arithmetic Operations**:
|
144
116
|
- **Sugar Syntax**: `input.field1 + input.field2` - Works for input fields and value references
|
@@ -147,26 +119,13 @@ end
|
|
147
119
|
|
148
120
|
**Cascade Condition Syntax**:
|
149
121
|
```ruby
|
150
|
-
# CORRECT - use symbols for trait references in cascades
|
151
122
|
value :status do
|
152
123
|
on trait_name, "Result"
|
153
124
|
base "Default"
|
154
125
|
end
|
155
|
-
|
156
|
-
# INCORRECT - bare identifiers don't work in cascade conditions
|
157
|
-
value :status do
|
158
|
-
on trait_name, "Result" # This will fail
|
159
|
-
base "Default"
|
160
|
-
end
|
161
126
|
```
|
162
127
|
|
163
|
-
**UnsatDetector Considerations**:
|
164
|
-
- Cascades with mutually exclusive conditions are valid (e.g., `amount < 100` vs `amount >= 100`)
|
165
|
-
- Values that depend on such cascades are also valid (fixed in recent update)
|
166
|
-
- Use clear, non-contradictory trait names to avoid confusion
|
167
|
-
|
168
128
|
### Key Patterns
|
169
|
-
|
170
129
|
**DSL Structure**:
|
171
130
|
```ruby
|
172
131
|
schema do
|
@@ -177,6 +136,14 @@ schema do
|
|
177
136
|
array :scores, elem: { type: :float }
|
178
137
|
hash :metadata, key: { type: :string }, val: { type: :any }
|
179
138
|
|
139
|
+
array :line_items do
|
140
|
+
float :price
|
141
|
+
integer :quantity
|
142
|
+
string :category
|
143
|
+
end
|
144
|
+
|
145
|
+
|
146
|
+
|
180
147
|
# Fields with no declared type
|
181
148
|
any :misc_field
|
182
149
|
end
|
@@ -191,20 +158,13 @@ end
|
|
191
158
|
```
|
192
159
|
|
193
160
|
**IMPORTANT CASCADE CONDITION SYNTAX:**
|
194
|
-
In cascade expressions (`value :name do ... end`), trait references use
|
161
|
+
In cascade expressions (`value :name do ... end`), trait references use bare identifiers:
|
195
162
|
```ruby
|
196
163
|
value :status do
|
197
|
-
on adult, "Adult Status"
|
164
|
+
on adult, "Adult Status"
|
198
165
|
on verified, "Verified User"
|
199
166
|
base "Unverified"
|
200
167
|
end
|
201
|
-
|
202
|
-
# NOT this:
|
203
|
-
value :status do
|
204
|
-
on adult, "Adult Status" # ❌ Wrong - don't use bare identifier in cascade
|
205
|
-
on verified, "Verified User" # ❌ Wrong
|
206
|
-
base "Unverified"
|
207
|
-
end
|
208
168
|
```
|
209
169
|
|
210
170
|
**Input Block System**:
|
@@ -260,72 +220,26 @@ The `examples/` directory contains comprehensive examples showing Kumi usage pat
|
|
260
220
|
- `spec/fixtures/` - Test fixtures and sample schemas
|
261
221
|
- `spec/support/` - Test helpers (`ast_factory.rb`, `schema_generator.rb`)
|
262
222
|
|
263
|
-
##
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
3. `lib/kumi/analyzer.rb` - Core analysis pipeline with multi-pass system
|
268
|
-
4. `lib/kumi/types.rb` - Static type system implementation
|
269
|
-
5. `lib/kumi/function_registry.rb` - Available functions and extension patterns
|
270
|
-
6. `lib/kumi/analyzer/passes/type_inferencer.rb` - Type inference algorithm
|
271
|
-
7. `lib/kumi/analyzer/passes/type_checker.rb` - Type validation with enhanced error messages
|
272
|
-
8. `spec/kumi/input_block_spec.rb` - Input block syntax and behavior
|
273
|
-
9. `spec/integration/compiler_integration_spec.rb` - End-to-end test examples
|
274
|
-
10. `docs/DSL.md` - Concise DSL syntax reference
|
275
|
-
11. `docs/AST.md` - AST node types and structure reference
|
276
|
-
12. `docs/SYNTAX.md` - Comprehensive sugar vs sugar-free syntax comparison with examples
|
277
|
-
13. `lib/kumi/cli.rb` - CLI implementation with REPL and file execution
|
278
|
-
14. `examples/simple_tax_schema.rb` - CLI-compatible schema example
|
279
|
-
15. `docs/features/analysis-cascade-mutual-exclusion.md` - Cascade mutual exclusion detection feature documentation
|
280
|
-
16. `docs/features/array-broadcasting.md` - Array broadcasting and vectorization system documentation
|
281
|
-
|
282
|
-
## CLI Usage and Best Practices
|
283
|
-
|
284
|
-
### Schema File Requirements
|
285
|
-
- **Must use module structure**: `module SchemaName; extend Kumi::Schema; schema do ... end; end`
|
286
|
-
- **Must have proper require**: `require_relative "../lib/kumi"` at the top
|
287
|
-
- **Must have input block**: Even empty `input {}` blocks are required
|
288
|
-
- **Avoid inline definitions**: Don't define schemas directly in methods or blocks
|
289
|
-
|
290
|
-
### CLI Development Workflow
|
291
|
-
1. **Start with REPL**: Use `./bin/kumi -i` for rapid prototyping and testing
|
292
|
-
2. **Test with files**: Create `.rb` schema files and `.json/.yaml` data files
|
293
|
-
3. **Iterate quickly**: Use `-k key1,key2` to focus on specific outputs
|
294
|
-
4. **Debug with explain**: Use `-e key_name` to understand computation flow
|
295
|
-
5. **Validate with different data**: Test edge cases with varied input data
|
296
|
-
|
297
|
-
### Common CLI Patterns
|
298
|
-
```bash
|
299
|
-
# Interactive development
|
300
|
-
./bin/kumi -i
|
301
|
-
kumi> schema examples/my_schema.rb
|
302
|
-
kumi> data test_data.json
|
303
|
-
kumi> get result
|
304
|
-
|
305
|
-
# File-based execution
|
306
|
-
./bin/kumi -f examples/tax_schema.rb -d examples/tax_data.json -k total_tax,effective_rate
|
307
|
-
|
308
|
-
# Debugging computations
|
309
|
-
./bin/kumi -f examples/complex_schema.rb -d examples/data.json -e complex_calculation
|
310
|
-
|
311
|
-
# Output formats for integration
|
312
|
-
./bin/kumi -f schema.rb -d data.json -k results -o json | jq '.results'
|
313
|
-
```
|
223
|
+
## Files for Understanding
|
224
|
+
|
225
|
+
. `docs/*` - Documents about Kumi, its features, DSL syntax, ...
|
226
|
+
- `examples/*` Random examples of very diverse contexts.
|
314
227
|
|
315
228
|
### Troubleshooting Schema Issues
|
316
229
|
- **Parse Errors**: Check function syntax (avoid empty `fn()` calls)
|
317
|
-
- **Module Not Found**: Ensure proper module structure and naming
|
318
|
-
- **UnsatDetector Errors**: Review trait logic for contradictions
|
319
|
-
- **Type Errors**: Check input block type declarations match usage
|
320
|
-
- **Runtime Errors**: Use explain to trace computation dependencies
|
230
|
+
- **Module Not Found**: Ensure proper module structure and naming, see examples
|
231
|
+
- **UnsatDetector Errors**: Review trait logic for contradictions, add debugs!
|
232
|
+
- **Type Errors**: Check input block type declarations match usage, add debugs!
|
233
|
+
- **Runtime Errors**: Use explain to trace computation dependencies, add debugs!
|
321
234
|
|
322
235
|
## Input Block System Details
|
323
236
|
|
324
237
|
### Required Input Blocks
|
325
|
-
- **All schemas must have an input block** -
|
238
|
+
- **All schemas must have an input block** -
|
326
239
|
- Input blocks declare expected fields with optional type and domain constraints
|
327
|
-
- **Empty input blocks are allowed**
|
328
|
-
- Fields are accessed via `input.field_name`
|
240
|
+
- **Empty input blocks are allowed** -`input {}` Even if its not very useful.
|
241
|
+
- Fields are accessed via `input.field_name` or `input.field.nested_field.nested_nested_field` which
|
242
|
+
works for referencing nested array input declarations.
|
329
243
|
|
330
244
|
### Type System Integration
|
331
245
|
- **Declared Types**: Explicit type declarations in input blocks (e.g. `integer :field`, `string :name`, `any :field`)
|
@@ -335,26 +249,21 @@ kumi> get result
|
|
335
249
|
- **Helper Functions**: Use `array(:type)` and `hash(:key_type, :value_type)` for complex types
|
336
250
|
|
337
251
|
### Parser Components
|
338
|
-
|
339
|
-
- `input_proxy.rb` - Handles `input.field_name` references in expressions
|
340
|
-
- `input_collector.rb` - Collects and validates field metadata consistency
|
252
|
+
See `lib/kumi/ruby_parser/parser.rb`
|
341
253
|
|
342
254
|
### Domain Constraints
|
343
255
|
- Can be declared: `integer :age, domain: 18..65`
|
344
|
-
- **Implemented**: Domain validation is active and enforced at runtime
|
345
256
|
- Supports Range domains (`18..65`), Array domains (`%w[active inactive]`), and Proc domains for custom validation
|
346
|
-
-
|
347
|
-
|
257
|
+
- Analyzer do some limited domain UNSAT detection, and its used to validated against input at Runtime
|
348
258
|
### Type Examples
|
349
259
|
```ruby
|
350
260
|
input do
|
351
|
-
# New type-specific DSL methods (recommended)
|
352
261
|
string :name
|
353
262
|
integer :age, domain: 18..65
|
354
263
|
hash :metadata, key: { type: :string }, val: { type: :any }
|
355
264
|
|
356
|
-
#
|
357
|
-
any :misc
|
265
|
+
#generic type
|
266
|
+
any :misc # this will make Kumi lose most of its analyze/inference power
|
358
267
|
end
|
359
268
|
```
|
360
269
|
|
@@ -437,59 +346,20 @@ trait :qualified, input.age, :>=, 21, input.score # OLD - shows deprecation war
|
|
437
346
|
3. Add pass to `PASSES` array in `lib/kumi/analyzer.rb` in correct order
|
438
347
|
4. Consider dependencies on other passes (e.g., TypeChecker needs TypeInferencer)
|
439
348
|
|
440
|
-
### Working with AST Nodes
|
441
|
-
- All nodes include `Node` module for location tracking
|
442
|
-
- Use `spec/support/ast_factory.rb` helpers in tests
|
443
|
-
- Field declarations use `FieldDecl` nodes with name, domain, and type
|
444
|
-
- Field references use `FieldRef` nodes (from `input.field_name`) with operator methods
|
445
|
-
- FieldRef operator methods (>=, <=, >, <, ==, !=) create CallExpression nodes
|
446
|
-
- CallExpression `&` method enables logical AND chaining
|
447
|
-
|
448
|
-
### Testing Input Block Features
|
449
|
-
- See `spec/kumi/input_block_spec.rb` for comprehensive input block tests
|
450
|
-
- Use `schema_generator.rb` helper for creating test schemas
|
451
|
-
- All integration tests now require input blocks
|
452
|
-
|
453
349
|
## Architecture Design Principles
|
454
350
|
|
455
351
|
- **Multi-pass Analysis**: Each analysis pass has a single responsibility and builds on previous passes
|
456
352
|
- **Immutable Syntax Tree**: AST nodes are immutable; analysis results stored separately in analyzer state
|
457
353
|
- **Dependency-driven Evaluation**: All computation follows dependency graph to ensure correct order
|
458
354
|
- **Type Safety**: Optional but comprehensive type checking without breaking existing schemas
|
459
|
-
- **Backward Compatibility**: New features maintain compatibility with existing DSL and APIs
|
460
355
|
- **Ruby Integration**: Leverages Ruby's metaprogramming while providing structured analysis
|
461
|
-
- **Separation of Concerns**: Input metadata (types, domains) separated from business logic
|
462
|
-
- **Class Decomposition**: Large classes split into focused, single-responsibility components following RuboCop guidelines
|
463
|
-
- **Delegation Pattern**: Complex operations delegated to specialized analyzer and formatter classes
|
464
356
|
- **Unified Error Reporting**: Consistent, localized error messages throughout the system with clear interface patterns
|
465
357
|
|
466
358
|
## Code Organization Patterns
|
467
359
|
|
468
|
-
### Modular Validation Architecture
|
469
|
-
- **Coordinator Classes**: Main classes like `Input::Validator` and `Domain::Validator` coordinate but delegate complex logic
|
470
|
-
- **Specialized Analyzers**: Domain-specific classes like `RangeAnalyzer` and `EnumAnalyzer` handle specific constraint types
|
471
|
-
- **Formatter Classes**: Dedicated classes like `ViolationFormatter` handle message formatting with consistent patterns
|
472
|
-
- **Creator Classes**: Classes like `ViolationCreator` centralize object creation with standardized structure
|
473
|
-
|
474
360
|
### Testing Best Practices
|
475
361
|
- **Spec Organization**: Tests organized by component with clear separation between unit and integration tests
|
476
362
|
- **Error Variable Extraction**: RSpec patterns avoid multiline block chains by extracting error variables for assertion
|
477
|
-
- **Shared Contexts**: Use `schema_generator` and other shared contexts for consistent test setup
|
478
|
-
|
479
|
-
### RuboCop Compliance
|
480
|
-
- **Method Length**: Keep methods under 10 lines through extraction and delegation
|
481
|
-
- **Class Length**: Break classes over 100 lines into focused components
|
482
|
-
- **Complexity Metrics**: Reduce cyclomatic and ABC complexity through single-responsibility design
|
483
|
-
- **Style Consistency**: Follow Ruby style guidelines for readability and maintainability
|
484
|
-
|
485
|
-
### Error Reporting Architecture
|
486
|
-
- **Unified Interface**: Use `ErrorReporter` module and `ErrorReporting` mixin for consistent error handling
|
487
|
-
- **Location Information**: All errors must include proper file:line:column location data
|
488
|
-
- **Precise Location Tracking**: Error objects preserve location data in `.location` attribute for programmatic access
|
489
|
-
- **User Code Location**: Errors point to actual user DSL code, not internal library files
|
490
|
-
- **Backward Compatibility**: Support both legacy `[location, message]` and new `ErrorEntry` formats
|
491
|
-
- **Type Categorization**: Errors categorized as `:syntax`, `:semantic`, `:type`, `:runtime`
|
492
|
-
- **Enhanced Messaging**: Support for error suggestions, context, and similar name detection
|
493
363
|
|
494
364
|
## Development Guides and Standards
|
495
365
|
|
@@ -522,18 +392,5 @@ end
|
|
522
392
|
- Use `spec/integration/dsl_breakage_spec.rb` patterns for comprehensive error testing
|
523
393
|
- Use `spec/integration/potential_breakage_spec.rb` for edge cases break
|
524
394
|
- Use `spec/fixtures/location_tracking_test_schema.rb` fixture for testing different syntax error types
|
525
|
-
- Test backward compatibility with existing analyzer pass specs
|
526
|
-
|
527
|
-
### Key Development Files
|
528
|
-
12. `lib/kumi/error_reporter.rb` - Central error reporting functionality
|
529
|
-
13. `lib/kumi/error_reporting.rb` - Mixin for consistent error interfaces
|
530
|
-
14. `spec/integration/location_tracking_spec.rb` - Comprehensive tests for error location accuracy
|
531
|
-
15. `spec/fixtures/location_tracking_test_schema.rb` - Fixture with intentional syntax errors for location testing
|
532
|
-
16. `ERROR_REPORTING_INTERFACE.md` - Detailed error reporting implementation guide
|
533
|
-
17. `ON_ERRORS.md` - Comprehensive analysis of DSL breakage scenarios and error quality
|
534
|
-
18. `spec/integration/dsl_breakage_spec.rb` - Integration tests for all DSL breakage scenarios
|
535
|
-
19. `spec/integration/potential_breakage_spec.rb` - Edge cases that should break but might not
|
536
|
-
20. `docs/development/README.md` - Development guides directory index
|
537
|
-
21. `docs/development/error-reporting.md` - Comprehensive error reporting standards and patterns
|
538
395
|
|
539
396
|
#
|
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 Declarative logic framework with static analysis for Ruby.
|
6
|
+
Kumi is a Declarative logic and rules engine framework with static analysis for Ruby.
|
7
7
|
|
8
8
|
It is well-suited for scenarios with complex, interdependent calculations, enforcing validation and consistency across your business rules while maintaining performance.
|
9
9
|
|
@@ -330,6 +330,37 @@ Kumi::Explain.call(FederalTax2024, :fed_tax, inputs: {income: 100_000, filing_st
|
|
330
330
|
|
331
331
|
</details>
|
332
332
|
|
333
|
+
<details>
|
334
|
+
<summary><strong>📋 Schema Metadata</strong> - Extract structured information for tooling</summary>
|
335
|
+
|
336
|
+
### Schema Metadata
|
337
|
+
|
338
|
+
Access structured metadata for building tools like form generators and dependency analyzers:
|
339
|
+
|
340
|
+
```ruby
|
341
|
+
metadata = FederalTax2024.schema_metadata
|
342
|
+
|
343
|
+
# Processed metadata (tool-friendly)
|
344
|
+
metadata.inputs # Input field types and domains
|
345
|
+
metadata.values # Value declarations with dependencies
|
346
|
+
metadata.traits # Trait conditions and metadata
|
347
|
+
metadata.functions # Function registry information
|
348
|
+
|
349
|
+
# Raw analyzer state (advanced usage)
|
350
|
+
metadata.dependencies # Dependency graph between declarations
|
351
|
+
metadata.evaluation_order # Topologically sorted computation order
|
352
|
+
metadata.inferred_types # Type inference results
|
353
|
+
metadata.declarations # Raw AST declaration nodes
|
354
|
+
|
355
|
+
# Export formats
|
356
|
+
metadata.to_h # Serializable hash for JSON/APIs
|
357
|
+
metadata.to_json_schema # JSON Schema for input validation
|
358
|
+
```
|
359
|
+
|
360
|
+
The SchemaMetadata interface provides both processed metadata for tool development and raw analyzer state for advanced use cases. Complete documentation available in the SchemaMetadata class and [docs/schema_metadata.md](docs/schema_metadata.md).
|
361
|
+
|
362
|
+
</details>
|
363
|
+
|
333
364
|
## Usage
|
334
365
|
|
335
366
|
**Suitable for:**
|
@@ -364,4 +395,4 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/amuta/
|
|
364
395
|
|
365
396
|
## License
|
366
397
|
|
367
|
-
MIT License. See [LICENSE](LICENSE).
|
398
|
+
MIT License. See [LICENSE](LICENSE).
|
data/docs/SYNTAX.md
CHANGED
@@ -131,13 +131,8 @@ trait :needs_review, fn(:and, needs_improvement, fn(:>, input.attempts, 2))
|
|
131
131
|
### String Operations
|
132
132
|
|
133
133
|
```ruby
|
134
|
-
#
|
135
|
-
trait :long_name, input.name
|
136
|
-
trait :starts_with_a, input.name.start_with?("A")
|
137
|
-
trait :contains_space, input.name.include?(" ")
|
138
|
-
|
139
|
-
# Sugar-Free
|
140
|
-
trait :long_name, fn(:>, fn(:string_length, input.name), 20)
|
134
|
+
# All string operations use function syntax
|
135
|
+
trait :long_name, fn(:string_length, input.name) > 20
|
141
136
|
trait :starts_with_a, fn(:start_with?, input.name, "A")
|
142
137
|
trait :contains_space, fn(:contains?, input.name, " ")
|
143
138
|
```
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# Broadcasts Metadata
|
2
|
+
|
3
|
+
Array broadcasting operation analysis for vectorized computations.
|
4
|
+
|
5
|
+
## Structure
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
state[:broadcasts] = {
|
9
|
+
array_fields: Hash,
|
10
|
+
vectorized_operations: Hash,
|
11
|
+
reduction_operations: Hash
|
12
|
+
}
|
13
|
+
```
|
14
|
+
|
15
|
+
## Array Fields
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
array_fields: {
|
19
|
+
:line_items => {
|
20
|
+
element_fields: [:price, :quantity, :name],
|
21
|
+
element_types: { price: :float, quantity: :integer, name: :string }
|
22
|
+
}
|
23
|
+
}
|
24
|
+
```
|
25
|
+
|
26
|
+
## Vectorized Operations
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
vectorized_operations: {
|
30
|
+
:item_totals => {
|
31
|
+
operation: :multiply,
|
32
|
+
vectorized_args: { 0 => true, 1 => true }
|
33
|
+
}
|
34
|
+
}
|
35
|
+
```
|
36
|
+
|
37
|
+
## Reduction Operations
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
reduction_operations: {
|
41
|
+
:total_amount => {
|
42
|
+
function: :sum,
|
43
|
+
source: :array_field
|
44
|
+
}
|
45
|
+
}
|
46
|
+
```
|
47
|
+
|
48
|
+
## Usage
|
49
|
+
|
50
|
+
- Compiler optimizations
|
51
|
+
- Parallel execution
|
52
|
+
- Type inference
|
53
|
+
- Performance analysis
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# Cascades Metadata
|
2
|
+
|
3
|
+
Cascade mutual exclusion analysis for safe conditional cycles.
|
4
|
+
|
5
|
+
## Structure
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
state[:cascades] = {
|
9
|
+
cascade_name => {
|
10
|
+
condition_traits: Array,
|
11
|
+
condition_count: Integer,
|
12
|
+
all_mutually_exclusive: Boolean,
|
13
|
+
exclusive_pairs: Integer,
|
14
|
+
total_pairs: Integer
|
15
|
+
}
|
16
|
+
}
|
17
|
+
```
|
18
|
+
|
19
|
+
## Example
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
{
|
23
|
+
:tax_rate => {
|
24
|
+
condition_traits: [:single, :married],
|
25
|
+
condition_count: 2,
|
26
|
+
all_mutually_exclusive: true,
|
27
|
+
exclusive_pairs: 1,
|
28
|
+
total_pairs: 1
|
29
|
+
}
|
30
|
+
}
|
31
|
+
```
|
32
|
+
|
33
|
+
## Fields
|
34
|
+
|
35
|
+
- `condition_traits`: Trait names used in cascade conditions
|
36
|
+
- `all_mutually_exclusive`: Whether all condition pairs are exclusive
|
37
|
+
- `exclusive_pairs`: Count of mutually exclusive pairs
|
38
|
+
- `total_pairs`: Total possible pairs
|
39
|
+
|
40
|
+
## Usage
|
41
|
+
|
42
|
+
- Cycle safety analysis
|
43
|
+
- Topological sorting
|
44
|
+
- Optimization detection
|
45
|
+
- Dependency validation
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# Declarations Metadata
|
2
|
+
|
3
|
+
Processed declaration metadata for all schema declarations (traits and values) with clean, serializable information.
|
4
|
+
|
5
|
+
## Access
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
metadata = MySchema.schema_metadata
|
9
|
+
declarations = metadata.declarations
|
10
|
+
```
|
11
|
+
|
12
|
+
## Structure
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
# Returns Hash<Symbol, Hash>
|
16
|
+
{
|
17
|
+
declaration_name => {
|
18
|
+
type: :trait | :value, # Declaration type
|
19
|
+
expression: String # Human-readable expression
|
20
|
+
}
|
21
|
+
}
|
22
|
+
```
|
23
|
+
|
24
|
+
## Example
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
metadata.declarations
|
28
|
+
# => {
|
29
|
+
# :adult => { type: :trait, expression: ">=(input.age, 18)" },
|
30
|
+
# :tax_amount => { type: :value, expression: "multiply(input.income, tax_rate)" },
|
31
|
+
# :status => { type: :value, expression: "cascade" }
|
32
|
+
# }
|
33
|
+
```
|
34
|
+
|
35
|
+
## Raw AST Access
|
36
|
+
|
37
|
+
For advanced use cases requiring direct AST manipulation:
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
raw_declarations = metadata.analyzer_state[:declarations]
|
41
|
+
# => { :adult => #<TraitDeclaration...>, :tax_amount => #<ValueDeclaration...> }
|
42
|
+
```
|
43
|
+
|
44
|
+
## AST Node Types
|
45
|
+
|
46
|
+
- **TraitDeclaration**: Boolean conditions
|
47
|
+
- **ValueDeclaration**: Computed values or cascades
|
48
|
+
|
49
|
+
## Usage
|
50
|
+
|
51
|
+
- Dependency analysis
|
52
|
+
- Code generation
|
53
|
+
- AST traversal
|
54
|
+
- Type inference
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# Dependencies Metadata
|
2
|
+
|
3
|
+
Processed dependency information showing relationships between declarations with clean, serializable data.
|
4
|
+
|
5
|
+
## Access
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
metadata = MySchema.schema_metadata
|
9
|
+
dependencies = metadata.dependencies
|
10
|
+
```
|
11
|
+
|
12
|
+
## Structure
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
# Returns Hash<Symbol, Array<Hash>>
|
16
|
+
{
|
17
|
+
declaration_name => [
|
18
|
+
{
|
19
|
+
to: Symbol, # Target declaration name
|
20
|
+
conditional: Boolean, # True if dependency is conditional (cascade branch)
|
21
|
+
cascade_owner: Symbol # Optional: cascade that owns this conditional edge
|
22
|
+
}
|
23
|
+
]
|
24
|
+
}
|
25
|
+
```
|
26
|
+
|
27
|
+
## Example
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
metadata.dependencies
|
31
|
+
# => {
|
32
|
+
# :tax_amount => [
|
33
|
+
# { to: :income, conditional: false },
|
34
|
+
# { to: :deductions, conditional: false }
|
35
|
+
# ],
|
36
|
+
# :status => [
|
37
|
+
# { to: :adult, conditional: true, cascade_owner: :status },
|
38
|
+
# { to: :verified, conditional: true, cascade_owner: :status }
|
39
|
+
# ]
|
40
|
+
# }
|
41
|
+
```
|
42
|
+
|
43
|
+
## Raw Edge Objects
|
44
|
+
|
45
|
+
For advanced use cases requiring direct Edge object access:
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
raw_dependencies = metadata.analyzer_state[:dependencies]
|
49
|
+
# => { :tax_amount => [#<Edge to: :income>, #<Edge to: :deductions>] }
|
50
|
+
```
|
51
|
+
|
52
|
+
## Usage
|
53
|
+
|
54
|
+
- Topological sorting
|
55
|
+
- Cycle detection
|
56
|
+
- Evaluation planning
|
57
|
+
- Dependency visualization
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# Evaluation Order Metadata
|
2
|
+
|
3
|
+
Topologically sorted order for safe declaration evaluation.
|
4
|
+
|
5
|
+
## Structure
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
state[:evaluation_order] = [:name1, :name2, :name3, ...]
|
9
|
+
```
|
10
|
+
|
11
|
+
## Example
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
[:income, :deductions, :taxable_income, :tax_rate, :tax_amount, :adult, :status]
|
15
|
+
```
|
16
|
+
|
17
|
+
## Properties
|
18
|
+
|
19
|
+
- Dependencies appear before dependents
|
20
|
+
- Handles conditional cycles in cascades
|
21
|
+
- Deterministic ordering
|
22
|
+
- Leaf nodes typically appear first
|
23
|
+
|
24
|
+
## Usage
|
25
|
+
|
26
|
+
- Compilation order
|
27
|
+
- Evaluation sequencing
|
28
|
+
- Optimization planning
|
29
|
+
- Parallel execution grouping
|