hecks 0.2.0 → 1.0.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 +5 -5
- data/lib/hecks/adapters/driven/claude_code.adapter +3 -0
- data/lib/hecks/adapters/driven/claude_code.rb +127 -0
- data/lib/hecks/adapters/driven/d1.adapter +12 -0
- data/lib/hecks/adapters/driven/d1.rb +427 -0
- data/lib/hecks/adapters/driven/folder.adapter +3 -0
- data/lib/hecks/adapters/driven/folder.rb +199 -0
- data/lib/hecks/adapters/driven/google_authentication.adapter +3 -0
- data/lib/hecks/adapters/driven/google_authentication.rb +100 -0
- data/lib/hecks/adapters/driven/governance_authorization.adapter +3 -0
- data/lib/hecks/adapters/driven/governance_authorization.rb +101 -0
- data/lib/hecks/adapters/driven/heki/journal.rb +56 -0
- data/lib/hecks/adapters/driven/heki/saga_store.rb +99 -0
- data/lib/hecks/adapters/driven/heki/snapshot.rb +65 -0
- data/lib/hecks/adapters/driven/heki.adapter +4 -0
- data/lib/hecks/adapters/driven/heki.rb +179 -0
- data/lib/hecks/adapters/driven/identity_registry.adapter +3 -0
- data/lib/hecks/adapters/driven/identity_registry.rb +26 -0
- data/lib/hecks/adapters/driven/in_memory_ordering.rb +51 -0
- data/lib/hecks/adapters/driven/lambda/client.rb +63 -0
- data/lib/hecks/adapters/driven/lambda.adapter +4 -0
- data/lib/hecks/adapters/driven/lambda.rb +145 -0
- data/lib/hecks/adapters/driven/memory.adapter +3 -0
- data/lib/hecks/adapters/driven/memory.rb +103 -0
- data/lib/hecks/adapters/driven/mock_stripe_adapter.adapter +3 -0
- data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +28 -0
- data/lib/hecks/adapters/driven/postgres/codec.rb +88 -0
- data/lib/hecks/adapters/driven/postgres/schema_builder.rb +207 -0
- data/lib/hecks/adapters/driven/postgres.adapter +5 -0
- data/lib/hecks/adapters/driven/postgres.rb +438 -0
- data/lib/hecks/adapters/driven/postgres_era.adapter +17 -0
- data/lib/hecks/adapters/driven/prism.adapter +3 -0
- data/lib/hecks/adapters/driven/prism.rb +80 -0
- data/lib/hecks/adapters/driven/secure_random_identity.adapter +3 -0
- data/lib/hecks/adapters/driven/secure_random_identity.rb +14 -0
- data/lib/hecks/adapters/driven/sql_query_builder.rb +221 -0
- data/lib/hecks/adapters/driven/sqlite/codec.rb +80 -0
- data/lib/hecks/adapters/driven/sqlite/projection.rb +172 -0
- data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +192 -0
- data/lib/hecks/adapters/driven/sqlite.adapter +9 -0
- data/lib/hecks/adapters/driven/sqlite.rb +306 -0
- data/lib/hecks/adapters/driven/system_clock.adapter +3 -0
- data/lib/hecks/adapters/driven/system_clock.rb +14 -0
- data/lib/hecks/adapters/driven.rb +54 -0
- data/lib/hecks/adapters.rb +6 -0
- data/lib/hecks/behaviors/dsl.rb +125 -0
- data/lib/hecks/behaviors/expectations.rb +340 -0
- data/lib/hecks/behaviors/ir.rb +31 -0
- data/lib/hecks/behaviors/rspec.rb +42 -0
- data/lib/hecks/behaviors/runner.rb +96 -0
- data/lib/hecks/behaviors.rb +25 -0
- data/lib/hecks/bluebook/aggregate.rb +108 -0
- data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +134 -0
- data/lib/hecks/bluebook/assembly/build.rb +48 -0
- data/lib/hecks/bluebook/assembly/contract.rb +112 -0
- data/lib/hecks/bluebook/assembly/contracts.rb +438 -0
- data/lib/hecks/bluebook/assembly/marks.rb +228 -0
- data/lib/hecks/bluebook/assembly/specializer.rb +70 -0
- data/lib/hecks/bluebook/assembly.rb +91 -0
- data/lib/hecks/bluebook/attribute.rb +96 -0
- data/lib/hecks/bluebook/behaviour/aggregate.rb +83 -0
- data/lib/hecks/bluebook/behaviour/attribute.rb +27 -0
- data/lib/hecks/bluebook/behaviour/chapter.rb +72 -0
- data/lib/hecks/bluebook/behaviour/command.rb +116 -0
- data/lib/hecks/bluebook/behaviour/domain_port.rb +25 -0
- data/lib/hecks/bluebook/behaviour/entity.rb +59 -0
- data/lib/hecks/bluebook/behaviour/hexagon.rb +50 -0
- data/lib/hecks/bluebook/behaviour/lifecycle.rb +68 -0
- data/lib/hecks/bluebook/behaviour/policy.rb +52 -0
- data/lib/hecks/bluebook/behaviour/process_manager.rb +51 -0
- data/lib/hecks/bluebook/behaviour/query.rb +10 -0
- data/lib/hecks/bluebook/behaviour/read_model.rb +29 -0
- data/lib/hecks/bluebook/behaviour/traits.rb +81 -0
- data/lib/hecks/bluebook/behaviour/value_object.rb +33 -0
- data/lib/hecks/bluebook/chapter.rb +78 -0
- data/lib/hecks/bluebook/command.rb +124 -0
- data/lib/hecks/bluebook/domain_port.rb +102 -0
- data/lib/hecks/bluebook/dsl/adapter_builder.rb +34 -0
- data/lib/hecks/bluebook/dsl/aggregate_builder.rb +1018 -0
- data/lib/hecks/bluebook/dsl/attribute_collector.rb +348 -0
- data/lib/hecks/bluebook/dsl/binding_proxy.rb +71 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder.rb +1087 -0
- data/lib/hecks/bluebook/dsl/command_builder.rb +714 -0
- data/lib/hecks/bluebook/dsl/const_shim.rb +81 -0
- data/lib/hecks/bluebook/dsl/domain_port_builder.rb +79 -0
- data/lib/hecks/bluebook/dsl/entity_builder.rb +430 -0
- data/lib/hecks/bluebook/dsl/generic_dispatch.rb +366 -0
- data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +163 -0
- data/lib/hecks/bluebook/dsl/identity_declaration.rb +191 -0
- data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +44 -0
- data/lib/hecks/bluebook/dsl/malformed.rb +7 -0
- data/lib/hecks/bluebook/dsl/policy_builder.rb +135 -0
- data/lib/hecks/bluebook/dsl/port_builder.rb +39 -0
- data/lib/hecks/bluebook/dsl/port_operation_builder.rb +142 -0
- data/lib/hecks/bluebook/dsl/process_manager_builder.rb +306 -0
- data/lib/hecks/bluebook/dsl/query_builder.rb +113 -0
- data/lib/hecks/bluebook/dsl/read_model_builder.rb +233 -0
- data/lib/hecks/bluebook/dsl/rule_reference.rb +173 -0
- data/lib/hecks/bluebook/dsl/translation_builder.rb +243 -0
- data/lib/hecks/bluebook/dsl/value_object_builder.rb +178 -0
- data/lib/hecks/bluebook/dsl/word_gate.rb +228 -0
- data/lib/hecks/bluebook/dsl/world_builder.rb +117 -0
- data/lib/hecks/bluebook/dsl.rb +45 -0
- data/lib/hecks/bluebook/entity.rb +103 -0
- data/lib/hecks/bluebook/expression/canonical_form.rb +123 -0
- data/lib/hecks/bluebook/expression/evaluator.rb +304 -0
- data/lib/hecks/bluebook/expression/projection.json +218 -0
- data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +233 -0
- data/lib/hecks/bluebook/expression/resolver.rb +781 -0
- data/lib/hecks/bluebook/expression.rb +13 -0
- data/lib/hecks/bluebook/hexagon.rb +60 -0
- data/lib/hecks/bluebook/lifecycle.rb +42 -0
- data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +54 -0
- data/lib/hecks/bluebook/meta_validator/judge.rb +621 -0
- data/lib/hecks/bluebook/meta_validator/plan.rb +332 -0
- data/lib/hecks/bluebook/meta_validator/port_judge.rb +51 -0
- data/lib/hecks/bluebook/meta_validator/readings.rb +360 -0
- data/lib/hecks/bluebook/meta_validator/reconstruction.rb +351 -0
- data/lib/hecks/bluebook/meta_validator/shapes.rb +266 -0
- data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +255 -0
- data/lib/hecks/bluebook/meta_validator/translation_judge.rb +138 -0
- data/lib/hecks/bluebook/meta_validator/world_judge.rb +78 -0
- data/lib/hecks/bluebook/meta_validator.rb +542 -0
- data/lib/hecks/bluebook/model_check.rb +445 -0
- data/lib/hecks/bluebook/pattern_subset.rb +184 -0
- data/lib/hecks/bluebook/policy.rb +41 -0
- data/lib/hecks/bluebook/process_manager.rb +128 -0
- data/lib/hecks/bluebook/project_discovery.rb +30 -0
- data/lib/hecks/bluebook/project_loader.rb +40 -0
- data/lib/hecks/bluebook/project_register.rb +82 -0
- data/lib/hecks/bluebook/query.rb +61 -0
- data/lib/hecks/bluebook/read_model.rb +109 -0
- data/lib/hecks/bluebook/reference.rb +74 -0
- data/lib/hecks/bluebook/smoke_test.rb +166 -0
- data/lib/hecks/bluebook/synthesizer.rb +95 -0
- data/lib/hecks/bluebook/translation.rb +92 -0
- data/lib/hecks/bluebook/value_object.rb +66 -0
- data/lib/hecks/bluebook.rb +74 -0
- data/lib/hecks/codemod.rb +342 -0
- data/lib/hecks/construct.rb +71 -0
- data/lib/hecks/deploy/bluebook/deploy.bluebook +219 -0
- data/lib/hecks/deploy/bluebook/deploy.hecksagon +4 -0
- data/lib/hecks/deploy/oidc.json +18 -0
- data/lib/hecks/doc/reference.rb +410 -0
- data/lib/hecks/embryonaut_bluebook.rb +75 -0
- data/lib/hecks/facade/cli_door.rb +119 -0
- data/lib/hecks/facade/cli_runner.rb +190 -0
- data/lib/hecks/facade/command_request.rb +105 -0
- data/lib/hecks/facade/handle.rb +173 -0
- data/lib/hecks/facade/json_door.rb +166 -0
- data/lib/hecks/facade/surface/aggregate_door.rb +185 -0
- data/lib/hecks/facade/surface/chapter.rb +107 -0
- data/lib/hecks/facade/surface.rb +48 -0
- data/lib/hecks/facade.rb +44 -0
- data/lib/hecks/forms/app.rb +341 -0
- data/lib/hecks/forms/command_form_renderer.rb +113 -0
- data/lib/hecks/forms/examples/banking_console.bluebook +3 -0
- data/lib/hecks/forms/field_renderer.rb +177 -0
- data/lib/hecks/forms/field_shape.rb +232 -0
- data/lib/hecks/forms/html.rb +84 -0
- data/lib/hecks/forms/index_renderer.rb +35 -0
- data/lib/hecks/forms/page.rb +157 -0
- data/lib/hecks/forms/params.rb +161 -0
- data/lib/hecks/forms/port_argument.rb +46 -0
- data/lib/hecks/forms/query_form_renderer.rb +114 -0
- data/lib/hecks/forms/record_renderer.rb +119 -0
- data/lib/hecks/forms/record_table.rb +68 -0
- data/lib/hecks/forms/reference_options.rb +30 -0
- data/lib/hecks/forms/value_object_shape.rb +46 -0
- data/lib/hecks/forms.rb +54 -0
- data/lib/hecks/fqn.rb +94 -0
- data/lib/hecks/framework/bluebook/compliance.bluebook +1 -0
- data/lib/hecks/framework/bluebook/console_settings.bluebook +489 -0
- data/lib/hecks/framework/bluebook/framework.hecksagon +32 -0
- data/lib/hecks/framework/bluebook/governance.bluebook +145 -0
- data/lib/hecks/framework/bluebook/identity.bluebook +90 -0
- data/lib/hecks/framework/oidc.json +39 -0
- data/lib/hecks/framework.rb +90 -0
- data/lib/hecks/freezer.rb +67 -0
- data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +527 -0
- data/lib/hecks/fuzzing/invalid_value_generator.rb +86 -0
- data/lib/hecks/fuzzing/isolated_boot.rb +286 -0
- data/lib/hecks/fuzzing/properties.rb +1192 -0
- data/lib/hecks/fuzzing/replay.rb +668 -0
- data/lib/hecks/fuzzing/sequence_generator/catalog.rb +93 -0
- data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +80 -0
- data/lib/hecks/fuzzing/sequence_generator/picker.rb +96 -0
- data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +250 -0
- data/lib/hecks/fuzzing/sequence_generator.rb +131 -0
- data/lib/hecks/fuzzing/value_generator.rb +200 -0
- data/lib/hecks/fuzzing.rb +12 -0
- data/lib/hecks/grammar/evolve.rb +324 -0
- data/lib/hecks/grammar/expression.bluebook +420 -0
- data/lib/hecks/grammar/expression_operators.json +1648 -0
- data/lib/hecks/grammar/grammar.hecksagon +20 -0
- data/lib/hecks/grammar/oidc.json +69 -0
- data/lib/hecks/grammar/translation.bluebook +203 -0
- data/lib/hecks/grammar.rb +178 -0
- data/lib/hecks/ir.rb +126 -0
- data/lib/hecks/language/adapter.bluebook +116 -0
- data/lib/hecks/language/bluebook/aggregate.bluebook +581 -0
- data/lib/hecks/language/bluebook/attaches/paging.bluebook +76 -0
- data/lib/hecks/language/bluebook/bluebook.bluebook +256 -0
- data/lib/hecks/language/bluebook/bluebook.hecksagon +24 -0
- data/lib/hecks/language/bluebook/command.bluebook +471 -0
- data/lib/hecks/language/bluebook/entity.bluebook +392 -0
- data/lib/hecks/language/bluebook/policy.bluebook +189 -0
- data/lib/hecks/language/bluebook/process_manager.bluebook +381 -0
- data/lib/hecks/language/bluebook/projection.bluebook +267 -0
- data/lib/hecks/language/bluebook/query.bluebook +245 -0
- data/lib/hecks/language/bluebook/shape.bluebook +292 -0
- data/lib/hecks/language/bluebook/syntax.bluebook +448 -0
- data/lib/hecks/language/bluebook/vocabulary.bluebook +379 -0
- data/lib/hecks/language/hecksagon/adapter_binding.bluebook +51 -0
- data/lib/hecks/language/hecksagon/domain_port.bluebook +76 -0
- data/lib/hecks/language/hecksagon/hecksagon.bluebook +131 -0
- data/lib/hecks/language/hecksagon/port_operation.bluebook +102 -0
- data/lib/hecks/language/oidc.json +333 -0
- data/lib/hecks/language/port.bluebook +120 -0
- data/lib/hecks/language/translation/translation.bluebook +110 -0
- data/lib/hecks/language/translation/translation_aggregate.bluebook +267 -0
- data/lib/hecks/language/world/wiring.bluebook +62 -0
- data/lib/hecks/language/world/world.bluebook +84 -0
- data/lib/hecks/literal.rb +125 -0
- data/lib/hecks/naming.rb +174 -0
- data/lib/hecks/ports/access_control.port +9 -0
- data/lib/hecks/ports/access_control.rb +62 -0
- data/lib/hecks/ports/agent/answers.rb +104 -0
- data/lib/hecks/ports/agent.port +8 -0
- data/lib/hecks/ports/agent.rb +167 -0
- data/lib/hecks/ports/authentication.port +6 -0
- data/lib/hecks/ports/authentication.rb +50 -0
- data/lib/hecks/ports/authorization.port +7 -0
- data/lib/hecks/ports/authorization.rb +62 -0
- data/lib/hecks/ports/clock.port +5 -0
- data/lib/hecks/ports/clock.rb +62 -0
- data/lib/hecks/ports/extraction.port +5 -0
- data/lib/hecks/ports/extraction.rb +37 -0
- data/lib/hecks/ports/identity_assignment.port +5 -0
- data/lib/hecks/ports/identity_assignment.rb +45 -0
- data/lib/hecks/ports/identity_generation.port +5 -0
- data/lib/hecks/ports/identity_generation.rb +49 -0
- data/lib/hecks/ports/identity_resolution.port +5 -0
- data/lib/hecks/ports/identity_resolution.rb +40 -0
- data/lib/hecks/ports/loading.port +4 -0
- data/lib/hecks/ports/loading.rb +13 -0
- data/lib/hecks/ports/persistence/append_only.rb +138 -0
- data/lib/hecks/ports/persistence/binding_policy.rb +56 -0
- data/lib/hecks/ports/persistence/execution.rb +23 -0
- data/lib/hecks/ports/persistence/null_saga_store.rb +25 -0
- data/lib/hecks/ports/persistence/plugin.rb +54 -0
- data/lib/hecks/ports/persistence/plugins/era/era_check.rb +169 -0
- data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +128 -0
- data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +161 -0
- data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +61 -0
- data/lib/hecks/ports/persistence/plugins/era/lineage.rb +304 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +171 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +190 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +478 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +166 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +314 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +168 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +170 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +134 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +137 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +89 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +85 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +43 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +132 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +74 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +758 -0
- data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +120 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +31 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +46 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +102 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +46 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +70 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +72 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +120 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +183 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/renderer.rb +41 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +28 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +30 -0
- data/lib/hecks/ports/persistence/plugins/era/translation.rb +11 -0
- data/lib/hecks/ports/persistence/plugins/era.rb +48 -0
- data/lib/hecks/ports/persistence/remote_runtime.rb +42 -0
- data/lib/hecks/ports/persistence/repository_factory.rb +30 -0
- data/lib/hecks/ports/persistence.port +4 -0
- data/lib/hecks/ports/persistence.rb +39 -0
- data/lib/hecks/ports/projection.port +4 -0
- data/lib/hecks/ports/projection.rb +96 -0
- data/lib/hecks/ports/query/in_memory.rb +60 -0
- data/lib/hecks/ports/query/ordering.rb +41 -0
- data/lib/hecks/ports/query.rb +36 -0
- data/lib/hecks/ports.rb +27 -0
- data/lib/hecks/projections/diagrams.rb +642 -0
- data/lib/hecks/projections/ir.rb +18 -0
- data/lib/hecks/projections/model/deviations.rb +98 -0
- data/lib/hecks/projections/model.rb +145 -0
- data/lib/hecks/projections/oidc.rb +110 -0
- data/lib/hecks/projections/parser_table.rb +159 -0
- data/lib/hecks/projections/reference.rb +38 -0
- data/lib/hecks/projections/shape.rb +44 -0
- data/lib/hecks/projections/statements.rb +110 -0
- data/lib/hecks/projections/vocabulary.rb +100 -0
- data/lib/hecks/projections.rb +32 -0
- data/lib/hecks/projector/cli_projector.rb +446 -0
- data/lib/hecks/projector/docs_projector.rb +321 -0
- data/lib/hecks/projector/exporter.rb +158 -0
- data/lib/hecks/projector/ir_projector.rb +18 -0
- data/lib/hecks/projector/narrate_projector.rb +243 -0
- data/lib/hecks/projector/target.rb +97 -0
- data/lib/hecks/projector.rb +186 -0
- data/lib/hecks/query_ir.rb +411 -0
- data/lib/hecks/query_specification/common/authorization_spec.rb +9 -0
- data/lib/hecks/query_specification/common/comparators.rb +25 -0
- data/lib/hecks/query_specification/common/comparison.rb +174 -0
- data/lib/hecks/query_specification/common/cursor_spec.rb +9 -0
- data/lib/hecks/query_specification/common/dsl.rb +58 -0
- data/lib/hecks/query_specification/common/inspection_spec.rb +9 -0
- data/lib/hecks/query_specification/common/limit_spec.rb +9 -0
- data/lib/hecks/query_specification/common/null_policy.rb +92 -0
- data/lib/hecks/query_specification/common/null_semantics.rb +11 -0
- data/lib/hecks/query_specification/common/offset_spec.rb +9 -0
- data/lib/hecks/query_specification/common/options.rb +32 -0
- data/lib/hecks/query_specification/common/order_by.rb +9 -0
- data/lib/hecks/query_specification/common/specification.rb +10 -0
- data/lib/hecks/query_specification/common/where_clause.rb +9 -0
- data/lib/hecks/query_specification/field_path.rb +107 -0
- data/lib/hecks/query_specification/hop_path.rb +132 -0
- data/lib/hecks/query_specification/read_model/specification.rb +18 -0
- data/lib/hecks/query_specification.rb +14 -0
- data/lib/hecks/rendering.rb +48 -0
- data/lib/hecks/router/namespace_installer.rb +157 -0
- data/lib/hecks/router.rb +70 -0
- data/lib/hecks/runtime/aggregate_lock.rb +45 -0
- data/lib/hecks/runtime/boot_gates.rb +41 -0
- data/lib/hecks/runtime/caller.rb +66 -0
- data/lib/hecks/runtime/capability_graph.rb +44 -0
- data/lib/hecks/runtime/command_interpreter/argument_gate.rb +135 -0
- data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +260 -0
- data/lib/hecks/runtime/command_interpreter.rb +497 -0
- data/lib/hecks/runtime/command_rules/admissibility.rb +357 -0
- data/lib/hecks/runtime/command_rules/arithmetic.rb +260 -0
- data/lib/hecks/runtime/command_rules/authorization.rb +65 -0
- data/lib/hecks/runtime/command_rules/emission.rb +34 -0
- data/lib/hecks/runtime/command_rules/references.rb +189 -0
- data/lib/hecks/runtime/command_rules.rb +28 -0
- data/lib/hecks/runtime/dependency_planning.rb +245 -0
- data/lib/hecks/runtime/dispatcher.rb +301 -0
- data/lib/hecks/runtime/entity_element.rb +253 -0
- data/lib/hecks/runtime/entity_interpreter.rb +299 -0
- data/lib/hecks/runtime/errors.rb +122 -0
- data/lib/hecks/runtime/event.rb +51 -0
- data/lib/hecks/runtime/identity.rb +156 -0
- data/lib/hecks/runtime/instance.rb +175 -0
- data/lib/hecks/runtime/interpreting.rb +90 -0
- data/lib/hecks/runtime/loader.rb +184 -0
- data/lib/hecks/runtime/policy_interpreter.rb +366 -0
- data/lib/hecks/runtime/port_operation_interpreter.rb +210 -0
- data/lib/hecks/runtime/query_interpreter.rb +286 -0
- data/lib/hecks/runtime/reaction_invocation.rb +253 -0
- data/lib/hecks/runtime/read_model_interpreter.rb +341 -0
- data/lib/hecks/runtime/rebuild_sweep.rb +74 -0
- data/lib/hecks/runtime/reference_hop.rb +99 -0
- data/lib/hecks/runtime/refusal_wording.rb +126 -0
- data/lib/hecks/runtime/registry/saga_persistence.rb +142 -0
- data/lib/hecks/runtime/registry/verification.rb +246 -0
- data/lib/hecks/runtime/registry.rb +279 -0
- data/lib/hecks/runtime/remote_dispatcher.rb +143 -0
- data/lib/hecks/runtime/routing.rb +96 -0
- data/lib/hecks/runtime/saga_interpreter/correlation.rb +97 -0
- data/lib/hecks/runtime/saga_interpreter.rb +503 -0
- data/lib/hecks/runtime/saga_pending_dispatch.rb +45 -0
- data/lib/hecks/runtime/tenant_check.rb +84 -0
- data/lib/hecks/runtime/tenant_scope.rb +55 -0
- data/lib/hecks/runtime/value/admission.rb +130 -0
- data/lib/hecks/runtime/value/coercion.rb +565 -0
- data/lib/hecks/runtime/value/invariant_violation.rb +5 -0
- data/lib/hecks/runtime/value.rb +125 -0
- data/lib/hecks/runtime.rb +107 -0
- data/lib/hecks/storehouse.rb +632 -0
- data/lib/hecks/version.rb +16 -0
- data/lib/hecks/vocabulary.rb +218 -0
- data/lib/hecks.rb +123 -6
- data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +90 -0
- data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +128 -0
- data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +160 -0
- metadata +412 -222
- data/bin/hecks +0 -7
- data/bin/hecks-package +0 -65
- data/bin/hecks_console +0 -12
- data/bin/hecks_serverless +0 -6
- data/lib/cli/build.rb +0 -14
- data/lib/cli/command_runner.rb +0 -28
- data/lib/cli/console.rb +0 -10
- data/lib/cli/generate.rb +0 -37
- data/lib/cli/hecks-cli.rb +0 -27
- data/lib/cli/test.rb +0 -57
- data/lib/console/commands.rb +0 -8
- data/lib/console/hecks-console.rb +0 -1
- data/lib/packager/README.md +0 -0
- data/lib/packager/app_runner.rb +0 -21
- data/lib/packager/args.rb +0 -26
- data/lib/packager/compatibility/fixnum.rb +0 -6
- data/lib/packager/hecks.rb +0 -39
- data/lib/packager/query_runner.rb +0 -21
- data/lib/packager/resources/Dockerfile +0 -11
- data/lib/packager/resources/app_binary +0 -7
- data/lib/packager/resources/bundle_config +0 -3
- data/lib/packager/resources/traveling-ruby-20150715-2.2.2-linux-x86_64.tar.gz +0 -0
- data/lib/packager/resources/traveling-ruby-20150715-2.2.2-osx.tar.gz +0 -0
- data/lib/serverless/Domain +0 -32
- data/lib/serverless/cli.rb +0 -75
- data/lib/serverless/resources/command_name.js +0 -5
- data/lib/serverless/resources/environment.js +0 -7
- data/lib/serverless/resources/handler.js.tt +0 -28
- data/lib/serverless/resources/run_binary.js +0 -22
- data/lib/serverless/resources/serverless.yml +0 -20
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
module Hecks
|
|
2
|
+
module Bluebook
|
|
3
|
+
class Assembly
|
|
4
|
+
# THE FIRST SPECIALIZER — a projection of `contracts.rb`'s `fields:` table,
|
|
5
|
+
# derived from the language's own description of a category instead of
|
|
6
|
+
# hand-written beside it.
|
|
7
|
+
#
|
|
8
|
+
# `Plan` already reads `grammar_registry` to build the judge's walk ; this
|
|
9
|
+
# reads the same chapter to build the OTHER table this arc's own header
|
|
10
|
+
# names as duplication — "SPELLED AS THE IR SPELLS THEM," field for field,
|
|
11
|
+
# for every category simple enough to say so.
|
|
12
|
+
#
|
|
13
|
+
# ONE CASE, PROVEN, NOT THE WHOLE TABLE. A field this can speak for is
|
|
14
|
+
# scalar and not a reference — every other field (a list, a reference, a
|
|
15
|
+
# fold like Lifecycle) is exactly what `contracts.rb`'s `reads:`/`derived:`
|
|
16
|
+
# exist to say, and stays hand-written until a later projection learns to
|
|
17
|
+
# derive readers and folds too. Restricting the claim to what can be
|
|
18
|
+
# PROVEN CORRECT — checked in spec/specializer_spec.rb against two
|
|
19
|
+
# independent categories — is the same discipline `derived:` itself
|
|
20
|
+
# enforces : a claim needs a kind, and this one's kind is "plain, checked."
|
|
21
|
+
module Specializer
|
|
22
|
+
module_function
|
|
23
|
+
|
|
24
|
+
# `position` IS THE FIRST FOLD THIS RUNS INTO, and it is a universal
|
|
25
|
+
# one : every category declares `attribute :position, Position` — for
|
|
26
|
+
# the JUDGE's own walk, `order_by :position` on its `DeclaredIn` ask —
|
|
27
|
+
# but no `*` constructor takes it as an argument. `contracts.rb`
|
|
28
|
+
# already says so, in the language every other derived field speaks :
|
|
29
|
+
# `derived: { position: :walk }`. The language says a category HAS a
|
|
30
|
+
# position ; it does not say a category's OWN constructor is handed
|
|
31
|
+
# one, and that second fact is exactly what `fields:` needs to answer.
|
|
32
|
+
# So this is not silently special-cased — it is the one fold named
|
|
33
|
+
# here because it is the one fold that is not a lucky accident of
|
|
34
|
+
# Policy or Handler, but a fact true of every category this arc will
|
|
35
|
+
# ever reach.
|
|
36
|
+
DERIVED_EVERYWHERE = %i[position].freeze
|
|
37
|
+
|
|
38
|
+
# S17, ADR 0026 — `Handler` is a genuine entity now, nested under
|
|
39
|
+
# `ProcessManager`, so `.aggregate` alone no longer finds it —
|
|
40
|
+
# it hangs off some aggregate's own `.entities` instead
|
|
41
|
+
# (searched recursively, the same reason `Value::Coercion#find_
|
|
42
|
+
# entity` does: a NESTED entity, like `Dispatch` inside
|
|
43
|
+
# `Handler`, is not a direct child of any aggregate either).
|
|
44
|
+
def construct_for(chapter, name)
|
|
45
|
+
chapter.aggregate(name) || chapter.aggregates.filter_map { |a| find_entity(a, name) }.first
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def find_entity(construct, name)
|
|
49
|
+
construct.entities.each do |candidate|
|
|
50
|
+
return candidate if candidate.hecks_name == name
|
|
51
|
+
|
|
52
|
+
found = find_entity(candidate, name)
|
|
53
|
+
return found if found
|
|
54
|
+
end
|
|
55
|
+
nil
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def fields_for(category)
|
|
59
|
+
language = construct_for(MetaValidator.grammar_registry.bluebook("Bluebook"), category.to_s)
|
|
60
|
+
language.attributes.each_with_object({}) do |attribute, fields|
|
|
61
|
+
next if attribute.list? || attribute.reference?
|
|
62
|
+
next if DERIVED_EVERYWHERE.include?(attribute.name)
|
|
63
|
+
|
|
64
|
+
fields[attribute.name] = [attribute.name, :plain]
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
module Hecks
|
|
2
|
+
module Bluebook
|
|
3
|
+
# A GRAPH BUILT FROM DECLARATIONS, rather than from DSL calls.
|
|
4
|
+
#
|
|
5
|
+
# This is the half that lets the language orchestrate. `Reconstruction` reads a
|
|
6
|
+
# chapter back out of the meta-domain, in declaration order, as plain
|
|
7
|
+
# declarations — the same shape `to_h` spells. This turns those declarations
|
|
8
|
+
# into the graph the runtime runs: IR aggregates with their verbs, value
|
|
9
|
+
# objects, entities and asks, owned by the chapter that declares them.
|
|
10
|
+
#
|
|
11
|
+
# It takes a HASH, not a runtime, on purpose. That makes it a pure inverse of
|
|
12
|
+
# `to_h` and testable without the meta-domain in the picture at all:
|
|
13
|
+
#
|
|
14
|
+
# Assembly.call(built.to_h).to_h == built.to_h
|
|
15
|
+
#
|
|
16
|
+
# which is the check `spec/assembly_spec` makes for every chapter in the tree.
|
|
17
|
+
# Feed it the reconstruction instead and the same code assembles what the
|
|
18
|
+
# LANGUAGE holds — the only difference being where the declarations came from.
|
|
19
|
+
#
|
|
20
|
+
# EVERY FIELD IS READ FROM ONE TABLE. There is no method per category here:
|
|
21
|
+
# `Contracts` names what the language cannot say about a construct, `Build`
|
|
22
|
+
# reads it, and the coverage gate holds the table to the language. The first
|
|
23
|
+
# draft of this file did have a method each, which is the shape the judge used
|
|
24
|
+
# to have — and the price of that shape was fourteen verbs the language declared
|
|
25
|
+
# and nothing ever offered.
|
|
26
|
+
#
|
|
27
|
+
# What stays hand-written is the CONTAINMENT: which construct holds which.
|
|
28
|
+
# That is not a field table. (The runtime SURFACE is no longer built here at
|
|
29
|
+
# all — the door is a per-boot projection, facade/surface.rb.)
|
|
30
|
+
class Assembly
|
|
31
|
+
def self.call(declaration) = new(declaration).bluebook
|
|
32
|
+
|
|
33
|
+
def initialize(declaration)
|
|
34
|
+
@declaration = declaration
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def bluebook
|
|
38
|
+
aggregates = Array(@declaration[:aggregates]).map { |row| AggregateAssembly.new(row).aggregate }
|
|
39
|
+
models = Array(@declaration[:read_models]).map { |row| Build.call("ReadModel", row) }
|
|
40
|
+
|
|
41
|
+
chapter = Build.call(
|
|
42
|
+
"Bluebook", @declaration,
|
|
43
|
+
aggregates: aggregates,
|
|
44
|
+
read_models: models,
|
|
45
|
+
policies: reactions(aggregates),
|
|
46
|
+
process_managers: Array(@declaration[:process_managers]).map { |row| process_manager(row) }
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
chapter
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
# Every reaction the chapter holds, and each one also handed back to the head
|
|
55
|
+
# that declared it — the builder keeps a policy in BOTH places, hoisting it onto
|
|
56
|
+
# the chapter where the runtime reads it while the head keeps its own list. The
|
|
57
|
+
# language records which head, so the assembly can put it back.
|
|
58
|
+
def reactions(aggregates)
|
|
59
|
+
Array(@declaration[:policies]).map { |row| Build.call("Policy", row) }.each do |reaction|
|
|
60
|
+
next if reaction.aggregate.to_s.empty?
|
|
61
|
+
|
|
62
|
+
head = aggregates.find { |held| held.hecks_name == reaction.aggregate }
|
|
63
|
+
head&.policies&.push(reaction)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def process_manager(row)
|
|
68
|
+
Build.call("ProcessManager", row,
|
|
69
|
+
handlers: Array(row[:handlers]).map { |leg| handler(leg) })
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def handler(row)
|
|
73
|
+
Build.call("Handler", row,
|
|
74
|
+
dispatches: Array(row[:dispatches]).map { |leg| dispatch(leg) })
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# `compensates` — a PLAIN HASH on the declaration (`Reconstruction#
|
|
78
|
+
# dispatch`'s own comment for why), built into the real
|
|
79
|
+
# `DispatchSpec` its own field actually is by recursing through
|
|
80
|
+
# THIS SAME method, one level in — the identical move `handler`
|
|
81
|
+
# itself takes into `dispatches`, one level up. `nil` when there
|
|
82
|
+
# is nothing to compensate; `Build.call` never sees a
|
|
83
|
+
# `compensates:` key it does not know how to read either way, the
|
|
84
|
+
# same reason `compensates` never joined `Contract#fields` at all.
|
|
85
|
+
def dispatch(row)
|
|
86
|
+
compensates = row[:compensates] && dispatch(row[:compensates])
|
|
87
|
+
Build.call("Dispatch", row, compensates: compensates)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
require_relative "behaviour/attribute"
|
|
2
|
+
require_relative "../ir"
|
|
3
|
+
require_relative "../vocabulary"
|
|
4
|
+
require_relative "../naming"
|
|
5
|
+
|
|
6
|
+
module Hecks
|
|
7
|
+
module Bluebook
|
|
8
|
+
class Attribute
|
|
9
|
+
include Hecks::IR
|
|
10
|
+
include Behaviour::Attribute
|
|
11
|
+
|
|
12
|
+
emits_ir(
|
|
13
|
+
name: :name,
|
|
14
|
+
type: -> { @type.to_s },
|
|
15
|
+
list: :list?,
|
|
16
|
+
default: :default,
|
|
17
|
+
optional: :optional?,
|
|
18
|
+
pattern: :pattern,
|
|
19
|
+
admits: :admits,
|
|
20
|
+
relationship: :relationship
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
attr_reader :name, :type, :default, :pattern, :admits, :relationship
|
|
24
|
+
|
|
25
|
+
# A Reference is kept AS ITSELF. Every other type is still a name, and
|
|
26
|
+
# crosses over as its construct does.
|
|
27
|
+
#
|
|
28
|
+
# `admits` names an ALREADY-DECLARED closed set the value must belong
|
|
29
|
+
# to — `Vocabulary::QueryComparator` — spelled aggregate-qualified
|
|
30
|
+
# because the set is a value object INSIDE an aggregate, and the
|
|
31
|
+
# aggregate is the only thing `reference_to` can reach.
|
|
32
|
+
#
|
|
33
|
+
# ON THE WIRE, because it is a RULE and not only a typing hint.
|
|
34
|
+
#
|
|
35
|
+
# It began as neither. The link existed so a generator could type
|
|
36
|
+
# `WhereClause.op` as `WhereOp` — a typing convenience, not worth
|
|
37
|
+
# moving 710 attribute records across eight goldens for. Then `admits`
|
|
38
|
+
# grew teeth (coercion refuses a non-member) and the argument
|
|
39
|
+
# inverted: a rule the wire does not carry is one a reader of the IR
|
|
40
|
+
# cannot enforce, and a bluebook whose meaning depends on the reader
|
|
41
|
+
# means two things. Proved rather than assumed — the same domain
|
|
42
|
+
# refused "burnt" through one reading and emitted the event through
|
|
43
|
+
# another.
|
|
44
|
+
#
|
|
45
|
+
# The wire carries the NAME, not the members. A reader resolves it
|
|
46
|
+
# against the IR it holds, so the members are declared once and
|
|
47
|
+
# copied nowhere — which is the same reason `admits` exists at all.
|
|
48
|
+
def initialize(name:, type:, list: false, default: nil, optional: false, pattern: nil,
|
|
49
|
+
admits: nil, relationship: nil)
|
|
50
|
+
@name = name.to_sym
|
|
51
|
+
@type = spell(type)
|
|
52
|
+
@list = list
|
|
53
|
+
@default = default
|
|
54
|
+
@optional = optional
|
|
55
|
+
@pattern = pattern
|
|
56
|
+
@admits = admits&.to_s
|
|
57
|
+
@relationship = relationship&.to_s
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# A BARE CONSTANT IN A BLUEBOOK IS A NAME, EVEN WHEN RUBY HAS HEARD OF IT.
|
|
61
|
+
#
|
|
62
|
+
# `BluebookBuilder.build` says exactly this and installs a `const_missing`
|
|
63
|
+
# resolver that hands back the symbol — `attribute :target, Target` becomes
|
|
64
|
+
# the name "Target" and nothing looks Target up. That works only while the
|
|
65
|
+
# lookup FAILS, and `Facade::Surface` installs every aggregate name as a
|
|
66
|
+
# TOP-LEVEL constant (its own comment, and `ConstShim`'s, both say so).
|
|
67
|
+
#
|
|
68
|
+
# So in one process: boot a domain with an aggregate named `Target`, then
|
|
69
|
+
# load a chapter whose own value object is called `Target`, and Ruby
|
|
70
|
+
# resolves the constant before the hook is ever asked. The chapter is then
|
|
71
|
+
# built against somebody else's aggregate — silently, with no refusal —
|
|
72
|
+
# and the attribute stops meaning what the file plainly says.
|
|
73
|
+
#
|
|
74
|
+
# DEMODULISED, so both paths spell it the same: `:Target` and
|
|
75
|
+
# `QualityControl::Target` are both "Target". A plain class stays itself —
|
|
76
|
+
# `String` demodulises to "String" — so the ordinary case is untouched.
|
|
77
|
+
# This does not undo the constant leak; it makes the leak unable to change
|
|
78
|
+
# what a chapter MEANS, which is the part that has to hold.
|
|
79
|
+
def spell(type)
|
|
80
|
+
return type if type.is_a?(Reference)
|
|
81
|
+
return Naming.demodulise(type) if type.is_a?(Module)
|
|
82
|
+
|
|
83
|
+
type.to_s
|
|
84
|
+
end
|
|
85
|
+
private :spell
|
|
86
|
+
|
|
87
|
+
# Held because a declared vocabulary pins it — spec/vocabulary_conformance
|
|
88
|
+
# holds `Primitive`'s members to this list. The `primitive?` predicate that
|
|
89
|
+
# used to read it had no caller anywhere and is gone.
|
|
90
|
+
PRIMITIVES = Hecks::Vocabulary.fetch("Primitive")
|
|
91
|
+
|
|
92
|
+
# `type` is spelled, never handed over. A Reference renders as
|
|
93
|
+
# "Reference<Customer>" here because that is the export's pinned spelling.
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
require_relative "traits"
|
|
2
|
+
|
|
3
|
+
module Hecks
|
|
4
|
+
module Bluebook
|
|
5
|
+
module Behaviour
|
|
6
|
+
# WHAT AN AGGREGATE DOES, as opposed to what it holds.
|
|
7
|
+
#
|
|
8
|
+
# The holding half — the field list, the readers, the emission — is
|
|
9
|
+
# the same list the language already declares in
|
|
10
|
+
# `language/bluebook/aggregate.bluebook`, said a second and third
|
|
11
|
+
# time in Ruby. This half is not: derived identity, the name
|
|
12
|
+
# indexes, the owner stamping and the finders are decisions about
|
|
13
|
+
# HOW the declared shape is used, and no grammar states them.
|
|
14
|
+
#
|
|
15
|
+
# Split so the holding half can be generated from the language
|
|
16
|
+
# without any of this being in the blast radius of a regeneration.
|
|
17
|
+
# Everything here is hand-written and permanent.
|
|
18
|
+
#
|
|
19
|
+
# The three traits are shared with Entity (and, for `Indexed`,
|
|
20
|
+
# with Command and PortOperation) — see behaviour/traits.rb on why
|
|
21
|
+
# they are one module rather than four copies.
|
|
22
|
+
module Aggregate
|
|
23
|
+
include Identified
|
|
24
|
+
include Indexed
|
|
25
|
+
include Owns
|
|
26
|
+
|
|
27
|
+
# An aggregate is a MEMBER of its chapter's namespace — "Pizzas::Pizza" —
|
|
28
|
+
# where everything else is declared ON its owner and joins with ".".
|
|
29
|
+
def hecks_separator = "::"
|
|
30
|
+
|
|
31
|
+
# THE HOOK THE GENERATED CONSTRUCTOR CALLS once every declared
|
|
32
|
+
# field is assigned. Nothing here is derivable from the
|
|
33
|
+
# declaration, which is exactly why it is not generated.
|
|
34
|
+
def settle
|
|
35
|
+
derive_identity
|
|
36
|
+
index_declarations
|
|
37
|
+
# An entity stamps its own commands and queries when it is
|
|
38
|
+
# declared, so the chain closes downward from here.
|
|
39
|
+
stamp(@commands, @value_objects, @entities, @queries)
|
|
40
|
+
self
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def index_declarations
|
|
44
|
+
index_attributes(@attributes)
|
|
45
|
+
@value_objects_by_name = index_by_hecks_name(@value_objects)
|
|
46
|
+
@commands_by_name = index_by_hecks_name(@commands)
|
|
47
|
+
@queries_by_name = index_by_hecks_name(@queries)
|
|
48
|
+
@ports_by_name = @ports.to_h { |port| [port.name, port] }
|
|
49
|
+
# S12, ADR 0025 — keyed by SYMBOL, the same convention
|
|
50
|
+
# `Indexed#attribute` already uses; `GuardState` asks for one
|
|
51
|
+
# by name at every dispatch, the rebuild sweep walks all of
|
|
52
|
+
# them once per pass.
|
|
53
|
+
@projected_fields_by_name = @projected_fields.to_h { |field| [field.name, field] }
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def projected_field(named) = @projected_fields_by_name[named.to_sym]
|
|
57
|
+
|
|
58
|
+
# A value object is a CLASS now, so `name` is Ruby's answer (the constant
|
|
59
|
+
# path) and the declared name is `hecks_name`. This finder is on its way
|
|
60
|
+
# out — once an attribute's type IS the class there is nothing to find —
|
|
61
|
+
# but every consumer still asks by type string, so it stays until they
|
|
62
|
+
# stop.
|
|
63
|
+
def value_object(named) = @value_objects_by_name[named.to_s]
|
|
64
|
+
def port(named) = @ports_by_name[named.to_s]
|
|
65
|
+
|
|
66
|
+
# A PORT IS DECLARED IN THE HECKSAGON, NOT THE BLUEBOOK — the
|
|
67
|
+
# boundary between the domain and its adapters, in hexagonal terms,
|
|
68
|
+
# is exactly what a `.hecksagon` file already IS for every other
|
|
69
|
+
# port (persistence, projection, ...). So this attaches AFTER the
|
|
70
|
+
# aggregate already exists and is registered — `HecksagonBuilder`
|
|
71
|
+
# calls it once per `port` declaration, having already stamped each
|
|
72
|
+
# operation's reference attributes with `declared_in = self`, since
|
|
73
|
+
# nothing upstream of a hecksagon load does that for it.
|
|
74
|
+
def add_port(port)
|
|
75
|
+
@ports << port
|
|
76
|
+
@ports_by_name[port.name] = port
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def storage_name = Naming.snake(@name)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Hecks
|
|
2
|
+
module Bluebook
|
|
3
|
+
module Behaviour
|
|
4
|
+
# WHAT AN ATTRIBUTE DOES. The declared half — name, type, list,
|
|
5
|
+
# default, optional, pattern, admits — is what the language states
|
|
6
|
+
# in `aggregate.bluebook`'s own `Field`. These are the questions
|
|
7
|
+
# readers ask ABOUT that shape, which no declaration states.
|
|
8
|
+
module Attribute
|
|
9
|
+
def list? = @list
|
|
10
|
+
def scalar? = !@list
|
|
11
|
+
def reference? = @type.is_a?(Reference)
|
|
12
|
+
|
|
13
|
+
# MAY THIS FACT BE LEFT OUT?
|
|
14
|
+
#
|
|
15
|
+
# Required is the default and by far the common case — a command takes
|
|
16
|
+
# the arguments it declares, and all of them — so the EXCEPTION is what
|
|
17
|
+
# gets marked. Marking the other way would annotate almost every
|
|
18
|
+
# attribute in the corpus to say nothing.
|
|
19
|
+
#
|
|
20
|
+
# Only a COMMAND enforces this. An aggregate's own attributes are filled
|
|
21
|
+
# by the commands that set them, and a value object's by its
|
|
22
|
+
# constructor ; neither is a payload anyone hands in.
|
|
23
|
+
def optional? = @optional
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
require_relative "traits"
|
|
2
|
+
|
|
3
|
+
module Hecks
|
|
4
|
+
module Bluebook
|
|
5
|
+
module Behaviour
|
|
6
|
+
# WHAT A CHAPTER DOES. The declared half is the roll-call of what a
|
|
7
|
+
# bluebook holds; these are the finders over it, plus `verbs` — the
|
|
8
|
+
# chapter's own list of every dispatchable name, which is derived
|
|
9
|
+
# from the aggregates rather than declared anywhere.
|
|
10
|
+
module Chapter
|
|
11
|
+
include Owns
|
|
12
|
+
|
|
13
|
+
# THE HOOK THE GENERATED CONSTRUCTOR CALLS. Three things a
|
|
14
|
+
# declaration does not state: that a chapter is the ROOT of the
|
|
15
|
+
# owner chain (nothing declares it, it is what having no owner
|
|
16
|
+
# MEANS), the ports table — which a `.hecksagon` fills later, so
|
|
17
|
+
# the bluebook cannot declare it — and stamping its own children,
|
|
18
|
+
# the same act an Aggregate performs one level down.
|
|
19
|
+
def settle
|
|
20
|
+
@hecks_root = true
|
|
21
|
+
@ports = []
|
|
22
|
+
@ports_by_name = {}
|
|
23
|
+
stamp(@aggregates, @read_models)
|
|
24
|
+
self
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def aggregate(named) = @aggregates.find { |a| a.name == named.to_s }
|
|
28
|
+
def read_model(named) = @read_models.find { |model| model.name == named.to_s || model.query_name == named.to_s }
|
|
29
|
+
def port(named) = @ports_by_name[named.to_s]
|
|
30
|
+
|
|
31
|
+
# A PORT IS DECLARED IN THE HECKSAGON, not the bluebook — so it
|
|
32
|
+
# attaches after the chapter already exists, the same way an
|
|
33
|
+
# aggregate's own ports do.
|
|
34
|
+
def add_port(port)
|
|
35
|
+
@ports << port
|
|
36
|
+
@ports_by_name[port.name] = port
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Every dispatchable name this chapter answers to, spelled exactly
|
|
40
|
+
# as Dispatcher#dispatch takes it. Derived from the aggregates,
|
|
41
|
+
# never declared — which is why Projections::OIDC can hold its own
|
|
42
|
+
# scope list equal to this and have that mean something.
|
|
43
|
+
#
|
|
44
|
+
# Recurses into entities, not just an aggregate's own direct
|
|
45
|
+
# commands — `Dispatcher#dispatch` already routes a dotted
|
|
46
|
+
# `Domain::Aggregate.Entity.Command` verb to `EntityInterpreter`
|
|
47
|
+
# (a command_name with a "." in it), so a verb this method left
|
|
48
|
+
# out was never "not a verb," only one this list forgot to name.
|
|
49
|
+
# Ported from the same recursive shape `spec/judge_coverage_spec.rb`
|
|
50
|
+
# already proved out for the meta-domain's own grammar (S17, ADR
|
|
51
|
+
# 0026) — entities nest arbitrarily deep (`Dispatch`, inside
|
|
52
|
+
# `Handler`), so one flat level isn't enough.
|
|
53
|
+
def verbs
|
|
54
|
+
@aggregates.flat_map { |agg| aggregate_verbs(agg) }
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
private
|
|
58
|
+
|
|
59
|
+
def aggregate_verbs(agg)
|
|
60
|
+
agg.commands.map { |cmd| "#{@name}::#{agg.hecks_name}.#{cmd.hecks_name}" } +
|
|
61
|
+
agg.entities.flat_map { |entity| entity_verbs("#{@name}::#{agg.hecks_name}", entity) }
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def entity_verbs(prefix, entity)
|
|
65
|
+
dotted = "#{prefix}.#{entity.hecks_name}"
|
|
66
|
+
entity.commands.map { |cmd| "#{dotted}.#{cmd.hecks_name}" } +
|
|
67
|
+
entity.entities.flat_map { |piece| entity_verbs(dotted, piece) }
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
require_relative "traits"
|
|
2
|
+
|
|
3
|
+
module Hecks
|
|
4
|
+
module Bluebook
|
|
5
|
+
module Behaviour
|
|
6
|
+
# WHAT A COMMAND DOES. EXTENDED, not included — a command is a
|
|
7
|
+
# CLASS, one per declared verb.
|
|
8
|
+
module Command
|
|
9
|
+
include Indexed
|
|
10
|
+
|
|
11
|
+
# Indexed once — attributes are final once absorbed, and every
|
|
12
|
+
# dispatch asks this finder by name.
|
|
13
|
+
def settle
|
|
14
|
+
index_attributes(@attributes)
|
|
15
|
+
self
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# The construct this verb acts upon — the construct itself, not its name.
|
|
19
|
+
#
|
|
20
|
+
# A verb declared on an ENTITY always acts on that piece. It never
|
|
21
|
+
# self-references, because an element is addressed THROUGH its parent —
|
|
22
|
+
# which means `creates?` answers true for every one of them, and reading
|
|
23
|
+
# `acts_on` off `creates?` alone would report that `LedgerEntry.Amend`
|
|
24
|
+
# brings a ledger entry into being. Three of banking's commands were
|
|
25
|
+
# about to say exactly that, and nothing would have contradicted them.
|
|
26
|
+
#
|
|
27
|
+
# On an aggregate, a creating command acts on no existing root, so nil is
|
|
28
|
+
# the truth: there is nothing there yet.
|
|
29
|
+
def acts_on
|
|
30
|
+
# FULLY QUALIFIED, and it has to be: inside `module Behaviour`
|
|
31
|
+
# the bare name `Entity` resolves to Behaviour::Entity — this
|
|
32
|
+
# module's SIBLING — not to the construct. Comparing a Class to
|
|
33
|
+
# a Module answers nil, so the guard silently fell through and
|
|
34
|
+
# every entity verb reported acting on nothing.
|
|
35
|
+
return hecks_owner if hecks_owner.is_a?(Class) && hecks_owner < Bluebook::Entity
|
|
36
|
+
|
|
37
|
+
creates? ? nil : hecks_owner
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def creates? = @references.nil?
|
|
41
|
+
|
|
42
|
+
# EVERY REASON THIS VERB CAN REFUSE ON A RULE — the descriptions of
|
|
43
|
+
# its givens AND its ensures, the exact text the runtime quotes
|
|
44
|
+
# after "refused — " when a guard is not met (see
|
|
45
|
+
# command_rules/admissibility.rb's GivenNotMet/EnsuresNotMet). A
|
|
46
|
+
# property that asks "did the runtime only ever refuse for a rule
|
|
47
|
+
# the language wrote" reads this rather than re-deriving the two
|
|
48
|
+
# collections; `compact` because a rule's description is optional
|
|
49
|
+
# (behavior.bluebook's Rule) and an unnamed one quotes nothing.
|
|
50
|
+
def guard_descriptions = (@givens + @ensures).map(&:description).compact
|
|
51
|
+
|
|
52
|
+
# THE ARGUMENT NAME THAT ADDRESSES an instance of `aggregate_name`
|
|
53
|
+
# for THIS command — the one fact `PolicyInterpreter`'s own
|
|
54
|
+
# `for_each` fan-out needs and, until this reading existed, had
|
|
55
|
+
# to guess at (see git blame: `Behaviour::Policy
|
|
56
|
+
# #fan_out_reference_key`, which hardcoded `<aggregate>_id`
|
|
57
|
+
# unconditionally and refused every dispatch to a self-
|
|
58
|
+
# addressing command as a result — `Account.Freeze`, addressed
|
|
59
|
+
# by `number`/`account`, not `account_id`).
|
|
60
|
+
#
|
|
61
|
+
# TWO SHAPES, the same two `CommandBuilder#reference_to` already
|
|
62
|
+
# tells apart at declare time (command_builder.rb's own comment
|
|
63
|
+
# on `cross_reference` — "`as:` MEANS a named attribute... a
|
|
64
|
+
# command can point at another instance of its OWN kind"):
|
|
65
|
+
#
|
|
66
|
+
# SELF-ADDRESSING — `references == aggregate_name` (this verb
|
|
67
|
+
# is declared ON the very aggregate it acts on, `reference_to
|
|
68
|
+
# Account` on a command Account itself owns). No attribute was
|
|
69
|
+
# minted for it at all; the SAME bare key
|
|
70
|
+
# `CommandInterpreter::ArgumentGate#reference_key` already
|
|
71
|
+
# accepts as "addressing, not describing" is reused here
|
|
72
|
+
# rather than re-derived — one door, not two.
|
|
73
|
+
#
|
|
74
|
+
# CROSS-REFERENCING — a real, declared reference-typed
|
|
75
|
+
# attribute whose OWN target is `aggregate_name` (`customer_id`
|
|
76
|
+
# on `Account.Open`, or whatever `as:` named it). Its NAME is
|
|
77
|
+
# the key, exactly as declared — never re-derived from the
|
|
78
|
+
# target's name, because an `as:` reference's name and its
|
|
79
|
+
# target's snake case can legitimately differ (`Transfer`'s own
|
|
80
|
+
# `source`/`destination`, both `Reference<Account>`).
|
|
81
|
+
#
|
|
82
|
+
# `nil` when neither shape matches — a CREATING command (nothing
|
|
83
|
+
# to address yet) or one that simply never references this
|
|
84
|
+
# aggregate at all. A caller minting a fan-out dispatch is
|
|
85
|
+
# expected to treat `nil` as "this command cannot be addressed by
|
|
86
|
+
# a row of this aggregate," not to fall back on a guess.
|
|
87
|
+
def addressing_key_for(aggregate_name)
|
|
88
|
+
return Naming.reference_key(aggregate_name) if references.to_s == aggregate_name.to_s
|
|
89
|
+
|
|
90
|
+
attributes.find { |attribute| attribute.reference? && attribute.type.target_name.to_s == aggregate_name.to_s }
|
|
91
|
+
&.name
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# A MUTATION'S OWN READINGS. Included (not extended) — Mutation is
|
|
96
|
+
# a Struct, so these are instance methods.
|
|
97
|
+
module Mutation
|
|
98
|
+
# An APPEND binds several fields at once, each from either a command
|
|
99
|
+
# ARGUMENT (a Symbol) or a LITERAL. It used to spell the Symbol bare
|
|
100
|
+
# and inspect the rest, which is the opposite of what a where-clause
|
|
101
|
+
# did with the same two kinds — see Hecks::Literal.
|
|
102
|
+
def appended_fields = source.transform_values { |value| Literal.render(value) }
|
|
103
|
+
|
|
104
|
+
def classified_source
|
|
105
|
+
if source.is_a?(Symbol)
|
|
106
|
+
{ kind: "argument", name: source.to_s }
|
|
107
|
+
elsif source.is_a?(StateRef)
|
|
108
|
+
{ kind: "state", name: source.name.to_s }
|
|
109
|
+
else
|
|
110
|
+
{ kind: "literal", value: source }
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require_relative "traits"
|
|
2
|
+
|
|
3
|
+
module Hecks
|
|
4
|
+
module Bluebook
|
|
5
|
+
module Behaviour
|
|
6
|
+
# WHAT ONE PORT OPERATION DOES.
|
|
7
|
+
module PortOperation
|
|
8
|
+
include Indexed
|
|
9
|
+
|
|
10
|
+
# An operation declares no reference of its own — the OWNER is
|
|
11
|
+
# what it acts for, and `identity_attribute` is how that is found.
|
|
12
|
+
def references = nil
|
|
13
|
+
|
|
14
|
+
def identity_attribute(owner_name)
|
|
15
|
+
@attributes.find { |attribute| attribute.reference? && attribute.type.target_name == owner_name.to_s }
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# WHAT A PORT DOES — one finder over its declared operations.
|
|
20
|
+
module DomainPort
|
|
21
|
+
def operation(named) = @operations.find { |op| op.hecks_name == named.to_s }
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
require_relative "traits"
|
|
2
|
+
|
|
3
|
+
module Hecks
|
|
4
|
+
module Bluebook
|
|
5
|
+
module Behaviour
|
|
6
|
+
# WHAT AN ENTITY DOES. EXTENDED, not included — an entity is a
|
|
7
|
+
# CLASS, so this is singleton behaviour.
|
|
8
|
+
#
|
|
9
|
+
# `settle` is the same seam an Aggregate has, reached from `absorb`
|
|
10
|
+
# rather than from a constructor because a declared entity is built
|
|
11
|
+
# by subclassing rather than by `new`. The traits are the same
|
|
12
|
+
# ones, which is the whole point of them being traits: an entity's
|
|
13
|
+
# identity is derived exactly as an aggregate's is, and was written
|
|
14
|
+
# out twice before anyone could see that.
|
|
15
|
+
module Entity
|
|
16
|
+
include Identified
|
|
17
|
+
include Indexed
|
|
18
|
+
include Owns
|
|
19
|
+
|
|
20
|
+
def settle
|
|
21
|
+
derive_identity
|
|
22
|
+
index_declarations
|
|
23
|
+
self
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def index_declarations
|
|
27
|
+
index_attributes(@attributes)
|
|
28
|
+
@commands_by_name = index_by_hecks_name(@commands)
|
|
29
|
+
@queries_by_name = index_by_hecks_name(@queries)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# S17, ADR 0026 — `@entities`, now genuinely NESTED entities
|
|
33
|
+
# (Dispatch, inside Handler) rather than always `[]`. Kept as a
|
|
34
|
+
# real reader rather than a hardcoded empty list for two
|
|
35
|
+
# reasons at once: `Value::Coercion#for_attribute` calls
|
|
36
|
+
# `.entities` on WHATEVER OWNER it is handed — an aggregate's or
|
|
37
|
+
# an entity's own — the moment it meets ANY `list_of(...)`
|
|
38
|
+
# attribute (entity-typed or not — `hydrate_entity_list`'s own
|
|
39
|
+
# fallback, `return value unless entity`, only runs once
|
|
40
|
+
# `.entities` has already answered) ; and `EntityInterpreter`
|
|
41
|
+
# now walks a DOTTED chain of entities one level at a time
|
|
42
|
+
# (`walk_entity_chain`) exactly the way an aggregate's own
|
|
43
|
+
# `.entities` is walked for its direct children. Entity's own
|
|
44
|
+
# header comment already promises it stays "structurally
|
|
45
|
+
# interchangeable with an aggregate" for exactly this reason.
|
|
46
|
+
def entities = @entities || []
|
|
47
|
+
|
|
48
|
+
# A piece OWNS the verbs declared on it, so they can state an
|
|
49
|
+
# identity — `Banking::Account.Ledger.Deposit` rather than a
|
|
50
|
+
# command that cannot say what it belongs to. Separate from
|
|
51
|
+
# `settle` because `declare` stamps AFTER absorbing, once the
|
|
52
|
+
# subclass that will own them exists. `@entities` too now
|
|
53
|
+
# (S17, ADR 0026) — a nested entity states its own owner chain
|
|
54
|
+
# exactly the way a nested command does.
|
|
55
|
+
def stamp_children = stamp(@commands, @queries, @entities)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|