hecks 1.3.0 → 1.5.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 +4 -4
- data/lib/hecks/adapters/driven/claude_code.rb +72 -7
- data/lib/hecks/adapters/driven/d1.rb +187 -23
- data/lib/hecks/adapters/driven/folder.rb +83 -10
- data/lib/hecks/adapters/driven/google_authentication.rb +33 -12
- data/lib/hecks/adapters/driven/governance_authorization.rb +87 -18
- data/lib/hecks/adapters/driven/heki/journal.rb +13 -4
- data/lib/hecks/adapters/driven/heki/saga_store.rb +56 -10
- data/lib/hecks/adapters/driven/heki/snapshot.rb +1 -1
- data/lib/hecks/adapters/driven/heki.rb +106 -9
- data/lib/hecks/adapters/driven/identity_registry.rb +12 -2
- data/lib/hecks/adapters/driven/in_memory_ordering.rb +25 -3
- data/lib/hecks/adapters/driven/in_process_key_vault.adapter +3 -0
- data/lib/hecks/adapters/driven/in_process_key_vault.rb +53 -0
- data/lib/hecks/adapters/driven/lambda/client.rb +67 -14
- data/lib/hecks/adapters/driven/lambda.rb +82 -35
- data/lib/hecks/adapters/driven/local_storage.rb +83 -10
- data/lib/hecks/adapters/driven/memory.rb +205 -9
- data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +21 -1
- data/lib/hecks/adapters/driven/postgres/codec.rb +27 -11
- data/lib/hecks/adapters/driven/postgres/outbox.rb +40 -2
- data/lib/hecks/adapters/driven/postgres/reconnect.rb +23 -7
- data/lib/hecks/adapters/driven/postgres/schema_builder.rb +14 -14
- data/lib/hecks/adapters/driven/postgres.rb +175 -28
- data/lib/hecks/adapters/driven/prism.rb +50 -11
- data/lib/hecks/adapters/driven/secure_random_identity.rb +3 -0
- data/lib/hecks/adapters/driven/sql_query_builder.rb +34 -22
- data/lib/hecks/adapters/driven/sqlite/codec.rb +38 -10
- data/lib/hecks/adapters/driven/sqlite/projection.rb +60 -32
- data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +12 -12
- data/lib/hecks/adapters/driven/sqlite.rb +181 -21
- data/lib/hecks/adapters/driven/system_clock.rb +3 -0
- data/lib/hecks/adapters/driven/tenant_provisioner.adapter +3 -0
- data/lib/hecks/adapters/driven/tenant_provisioner.rb +66 -0
- data/lib/hecks/adapters/driven.rb +6 -4
- data/lib/hecks/adapters/driving/github_webhook.rb +31 -18
- data/lib/hecks/behaviors/dsl.rb +60 -2
- data/lib/hecks/behaviors/expectations.rb +190 -29
- data/lib/hecks/behaviors/ir.rb +12 -1
- data/lib/hecks/behaviors/rspec.rb +9 -1
- data/lib/hecks/behaviors/runner.rb +21 -2
- data/lib/hecks/behaviors.rb +9 -1
- data/lib/hecks/bluebook/aggregate.rb +43 -13
- data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +17 -10
- data/lib/hecks/bluebook/assembly/build.rb +26 -5
- data/lib/hecks/bluebook/assembly/contract.rb +98 -23
- data/lib/hecks/bluebook/assembly/contracts.rb +59 -52
- data/lib/hecks/bluebook/assembly/marks.rb +159 -30
- data/lib/hecks/bluebook/assembly/specializer.rb +38 -21
- data/lib/hecks/bluebook/assembly.rb +32 -14
- data/lib/hecks/bluebook/attribute.rb +26 -12
- data/lib/hecks/bluebook/behaviour/aggregate.rb +43 -11
- data/lib/hecks/bluebook/behaviour/attribute.rb +18 -5
- data/lib/hecks/bluebook/behaviour/chapter.rb +76 -5
- data/lib/hecks/bluebook/behaviour/command.rb +55 -25
- data/lib/hecks/bluebook/behaviour/domain_port.rb +27 -7
- data/lib/hecks/bluebook/behaviour/entity.rb +20 -8
- data/lib/hecks/bluebook/behaviour/hexagon.rb +30 -4
- data/lib/hecks/bluebook/behaviour/lifecycle.rb +27 -6
- data/lib/hecks/bluebook/behaviour/policy.rb +42 -17
- data/lib/hecks/bluebook/behaviour/process_manager.rb +39 -8
- data/lib/hecks/bluebook/behaviour/query.rb +6 -1
- data/lib/hecks/bluebook/behaviour/read_model.rb +29 -8
- data/lib/hecks/bluebook/behaviour/traits.rb +48 -12
- data/lib/hecks/bluebook/behaviour/value_object.rb +21 -9
- data/lib/hecks/bluebook/capabilities.rb +27 -0
- data/lib/hecks/bluebook/chapter.rb +51 -9
- data/lib/hecks/bluebook/command.rb +62 -17
- data/lib/hecks/bluebook/domain_port.rb +34 -9
- data/lib/hecks/bluebook/dsl/adapter_builder.rb +24 -0
- data/lib/hecks/bluebook/dsl/aggregate_builder/sealing.rb +49 -49
- data/lib/hecks/bluebook/dsl/aggregate_builder.rb +282 -123
- data/lib/hecks/bluebook/dsl/attribute_collector.rb +112 -75
- data/lib/hecks/bluebook/dsl/binding_proxy.rb +81 -2
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +486 -117
- data/lib/hecks/bluebook/dsl/bluebook_builder.rb +179 -47
- data/lib/hecks/bluebook/dsl/bootstrap_table.rb +116 -0
- data/lib/hecks/bluebook/dsl/command_builder.rb +284 -122
- data/lib/hecks/bluebook/dsl/const_shim.rb +46 -15
- data/lib/hecks/bluebook/dsl/domain_port_builder.rb +90 -25
- data/lib/hecks/bluebook/dsl/entity_builder.rb +191 -61
- data/lib/hecks/bluebook/dsl/generic_dispatch.rb +148 -132
- data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +130 -30
- data/lib/hecks/bluebook/dsl/identity_declaration.rb +38 -21
- data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +27 -4
- data/lib/hecks/bluebook/dsl/policy_builder.rb +86 -36
- data/lib/hecks/bluebook/dsl/port_builder.rb +38 -7
- data/lib/hecks/bluebook/dsl/port_operation_builder.rb +56 -22
- data/lib/hecks/bluebook/dsl/process_manager_builder.rb +111 -47
- data/lib/hecks/bluebook/dsl/query_builder.rb +37 -8
- data/lib/hecks/bluebook/dsl/read_model_builder.rb +127 -52
- data/lib/hecks/bluebook/dsl/rule_reference.rb +97 -43
- data/lib/hecks/bluebook/dsl/translation_builder.rb +150 -44
- data/lib/hecks/bluebook/dsl/value_object_builder.rb +68 -20
- data/lib/hecks/bluebook/dsl/word_gate.rb +59 -53
- data/lib/hecks/bluebook/dsl/world_builder.rb +51 -8
- data/lib/hecks/bluebook/entity.rb +40 -11
- data/lib/hecks/bluebook/expression/ast_json.rb +128 -36
- data/lib/hecks/bluebook/expression/ast_reader.rb +32 -3
- data/lib/hecks/bluebook/expression/canonical_form.rb +55 -16
- data/lib/hecks/bluebook/expression/evaluator.rb +221 -43
- data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +54 -18
- data/lib/hecks/bluebook/expression/resolver.rb +369 -128
- data/lib/hecks/bluebook/hexagon.rb +35 -1
- data/lib/hecks/bluebook/lifecycle.rb +12 -1
- data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +2 -1
- data/lib/hecks/bluebook/meta_validator/judge.rb +126 -108
- data/lib/hecks/bluebook/meta_validator/plan.rb +81 -46
- data/lib/hecks/bluebook/meta_validator/port_judge.rb +3 -2
- data/lib/hecks/bluebook/meta_validator/readings.rb +200 -50
- data/lib/hecks/bluebook/meta_validator/reconstruction.rb +68 -41
- data/lib/hecks/bluebook/meta_validator/shapes.rb +166 -21
- data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +286 -46
- data/lib/hecks/bluebook/meta_validator/translation_judge.rb +11 -10
- data/lib/hecks/bluebook/meta_validator/world_judge.rb +6 -5
- data/lib/hecks/bluebook/meta_validator.rb +235 -139
- data/lib/hecks/bluebook/model_check.rb +434 -104
- data/lib/hecks/bluebook/pattern_subset.rb +32 -10
- data/lib/hecks/bluebook/policy.rb +15 -13
- data/lib/hecks/bluebook/process_manager.rb +27 -14
- data/lib/hecks/bluebook/project_discovery.rb +5 -0
- data/lib/hecks/bluebook/project_loader.rb +40 -0
- data/lib/hecks/bluebook/project_register.rb +50 -6
- data/lib/hecks/bluebook/query.rb +31 -4
- data/lib/hecks/bluebook/read_model.rb +35 -15
- data/lib/hecks/bluebook/reference.rb +26 -13
- data/lib/hecks/bluebook/smoke_test.rb +46 -23
- data/lib/hecks/bluebook/synthesizer.rb +46 -12
- data/lib/hecks/bluebook/translation.rb +34 -5
- data/lib/hecks/bluebook/value_object.rb +29 -11
- data/lib/hecks/bluebook.rb +5 -6
- data/lib/hecks/codemod.rb +138 -50
- data/lib/hecks/construct.rb +21 -7
- data/lib/hecks/corpus.rb +438 -0
- data/lib/hecks/deploy/bluebook/deploy.hecksagon +19 -0
- data/lib/hecks/doc/reference.rb +200 -31
- data/lib/hecks/embryonaut_bluebook.rb +38 -15
- data/lib/hecks/facade/cli_door.rb +69 -10
- data/lib/hecks/facade/cli_runner.rb +105 -24
- data/lib/hecks/facade/command_request.rb +23 -0
- data/lib/hecks/facade/handle.rb +155 -35
- data/lib/hecks/facade/json_door.rb +106 -25
- data/lib/hecks/facade/surface/aggregate_door.rb +50 -27
- data/lib/hecks/facade/surface/chapter.rb +26 -17
- data/lib/hecks/facade/surface.rb +16 -3
- data/lib/hecks/facade.rb +15 -4
- data/lib/hecks/forms/app.rb +46 -30
- data/lib/hecks/forms/command_form_renderer.rb +70 -9
- data/lib/hecks/forms/field_renderer.rb +142 -6
- data/lib/hecks/forms/field_shape.rb +183 -19
- data/lib/hecks/forms/html.rb +51 -7
- data/lib/hecks/forms/index_renderer.rb +14 -2
- data/lib/hecks/forms/page.rb +14 -0
- data/lib/hecks/forms/params.rb +120 -23
- data/lib/hecks/forms/port_argument.rb +14 -2
- data/lib/hecks/forms/query_form_renderer.rb +65 -2
- data/lib/hecks/forms/record_renderer.rb +60 -2
- data/lib/hecks/forms/record_table.rb +28 -1
- data/lib/hecks/forms/reference_options.rb +24 -0
- data/lib/hecks/forms/value_object_shape.rb +13 -3
- data/lib/hecks/forms.rb +24 -4
- data/lib/hecks/fqn.rb +59 -1
- data/lib/hecks/framework/bluebook/governance.bluebook +9 -0
- data/lib/hecks/framework/bluebook/privacy.bluebook +155 -0
- data/lib/hecks/framework/oidc.json +15 -0
- data/lib/hecks/framework.rb +79 -25
- data/lib/hecks/freezer.rb +27 -11
- data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +241 -106
- data/lib/hecks/fuzzing/combination_miner.rb +178 -0
- data/lib/hecks/fuzzing/concurrent_dispatch.rb +241 -45
- data/lib/hecks/fuzzing/coverage_campaign.rb +161 -0
- data/lib/hecks/fuzzing/differential.rb +192 -0
- data/lib/hecks/fuzzing/domain_generator.rb +871 -0
- data/lib/hecks/fuzzing/era_boundary.rb +68 -19
- data/lib/hecks/fuzzing/form_census.rb +121 -20
- data/lib/hecks/fuzzing/generated_domain_check.rb +171 -0
- data/lib/hecks/fuzzing/invalid_value_generator.rb +45 -6
- data/lib/hecks/fuzzing/isolated_boot.rb +137 -80
- data/lib/hecks/fuzzing/nondeterministic.rb +79 -0
- data/lib/hecks/fuzzing/persistence_parity.rb +111 -21
- data/lib/hecks/fuzzing/properties/corrections.rb +34 -9
- data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +300 -51
- data/lib/hecks/fuzzing/properties/guards.rb +86 -42
- data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +80 -32
- data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +40 -35
- data/lib/hecks/fuzzing/properties/outbox.rb +70 -32
- data/lib/hecks/fuzzing/properties/querying.rb +82 -28
- data/lib/hecks/fuzzing/properties.rb +84 -51
- data/lib/hecks/fuzzing/qa_settings.rb +164 -0
- data/lib/hecks/fuzzing/replay.rb +241 -133
- data/lib/hecks/fuzzing/rotation_priority.rb +48 -28
- data/lib/hecks/fuzzing/rust_gap_manifest.rb +139 -0
- data/lib/hecks/fuzzing/self_consistency.rb +315 -137
- data/lib/hecks/fuzzing/sequence_generator/adversary.rb +46 -40
- data/lib/hecks/fuzzing/sequence_generator/catalog.rb +18 -11
- data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +13 -12
- data/lib/hecks/fuzzing/sequence_generator/picker.rb +21 -12
- data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +59 -32
- data/lib/hecks/fuzzing/sequence_generator.rb +158 -23
- data/lib/hecks/fuzzing/shrinker.rb +309 -0
- data/lib/hecks/fuzzing/structural_skips.rb +37 -130
- data/lib/hecks/fuzzing/sweep_depth.rb +12 -4
- data/lib/hecks/fuzzing/target_capabilities.rb +107 -29
- data/lib/hecks/fuzzing/value_generator.rb +110 -22
- data/lib/hecks/fuzzing.rb +5 -0
- data/lib/hecks/grammar/evolve.rb +188 -12
- data/lib/hecks/grammar.rb +53 -7
- data/lib/hecks/ir.rb +51 -20
- data/lib/hecks/language/bluebook/bluebook.bluebook +41 -0
- data/lib/hecks/language/bluebook/policy.bluebook +11 -1
- data/lib/hecks/language/bluebook/vocabulary.bluebook +348 -13
- data/lib/hecks/language/hecksagon/hecksagon.bluebook +11 -0
- data/lib/hecks/language/oidc.json +5 -0
- data/lib/hecks/literal.rb +41 -9
- data/lib/hecks/naming.rb +112 -31
- data/lib/hecks/ports/access_control.rb +53 -2
- data/lib/hecks/ports/agent/answers.rb +83 -6
- data/lib/hecks/ports/agent.rb +119 -35
- data/lib/hecks/ports/authentication.rb +44 -4
- data/lib/hecks/ports/authorization.rb +50 -11
- data/lib/hecks/ports/clock.rb +42 -23
- data/lib/hecks/ports/extraction.rb +16 -0
- data/lib/hecks/ports/identity_assignment.rb +23 -2
- data/lib/hecks/ports/identity_generation.rb +17 -3
- data/lib/hecks/ports/identity_resolution.rb +17 -1
- data/lib/hecks/ports/key_vault.port +6 -0
- data/lib/hecks/ports/key_vault.rb +58 -0
- data/lib/hecks/ports/loading.rb +4 -0
- data/lib/hecks/ports/persistence/append_only.rb +172 -8
- data/lib/hecks/ports/persistence/binding_policy.rb +34 -0
- data/lib/hecks/ports/persistence/codec_boundary.rb +178 -0
- data/lib/hecks/ports/persistence/execution.rb +4 -0
- data/lib/hecks/ports/persistence/null_saga_store.rb +12 -1
- data/lib/hecks/ports/persistence/plugin.rb +42 -4
- data/lib/hecks/ports/persistence/plugins/era/era_check.rb +218 -25
- data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +77 -9
- data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +81 -24
- data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +29 -18
- data/lib/hecks/ports/persistence/plugins/era/lineage.rb +144 -60
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +103 -8
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +98 -23
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +282 -109
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +63 -25
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +118 -66
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +51 -28
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +34 -5
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +25 -12
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +129 -34
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +51 -6
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +33 -9
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +16 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +95 -6
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +25 -2
- data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +314 -90
- data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +68 -10
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +9 -3
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +9 -2
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +48 -8
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +16 -1
- data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +36 -5
- data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +23 -3
- data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +58 -19
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +96 -5
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/renderer.rb +15 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +9 -1
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +2 -2
- data/lib/hecks/ports/persistence/plugins/era.rb +12 -2
- data/lib/hecks/ports/persistence/remote_runtime.rb +9 -2
- data/lib/hecks/ports/persistence/repository_factory.rb +23 -3
- data/lib/hecks/ports/persistence/state_codec.rb +319 -0
- data/lib/hecks/ports/persistence.rb +36 -1
- data/lib/hecks/ports/projection.rb +61 -7
- data/lib/hecks/ports/query/in_memory.rb +41 -8
- data/lib/hecks/ports/query/ordering.rb +21 -6
- data/lib/hecks/ports/query.rb +35 -0
- data/lib/hecks/ports.rb +1 -0
- data/lib/hecks/projections/bootstrap_table.rb +147 -0
- data/lib/hecks/projections/diagrams.rb +315 -79
- data/lib/hecks/projections/glossary/html.rb +91 -3
- data/lib/hecks/projections/glossary/markdown.rb +50 -3
- data/lib/hecks/projections/glossary/mermaid.rb +49 -1
- data/lib/hecks/projections/glossary/sections.rb +1 -1
- data/lib/hecks/projections/glossary/sentences.rb +110 -5
- data/lib/hecks/projections/glossary.rb +173 -31
- data/lib/hecks/projections/ir.rb +1 -1
- data/lib/hecks/projections/model/deviations.rb +62 -17
- data/lib/hecks/projections/model.rb +75 -21
- data/lib/hecks/projections/oidc.rb +45 -8
- data/lib/hecks/projections/parser_table.rb +53 -12
- data/lib/hecks/projections/reference.rb +15 -3
- data/lib/hecks/projections/rust_vocabulary.rb +646 -0
- data/lib/hecks/projections/shape.rb +10 -2
- data/lib/hecks/projections/statements.rb +69 -22
- data/lib/hecks/projections/vocabulary.rb +26 -9
- data/lib/hecks/projections.rb +5 -3
- data/lib/hecks/projector/cli_projector.rb +245 -37
- data/lib/hecks/projector/docs_projector.rb +154 -28
- data/lib/hecks/projector/exporter.rb +104 -29
- data/lib/hecks/projector/ir_projector.rb +7 -1
- data/lib/hecks/projector/narrate_projector.rb +144 -23
- data/lib/hecks/projector/target.rb +42 -18
- data/lib/hecks/projector.rb +86 -18
- data/lib/hecks/query_ir.rb +94 -47
- data/lib/hecks/query_specification/common/comparators.rb +19 -3
- data/lib/hecks/query_specification/common/comparison.rb +109 -27
- data/lib/hecks/query_specification/common/dsl.rb +65 -9
- data/lib/hecks/query_specification/common/null_policy.rb +61 -15
- data/lib/hecks/query_specification/common/null_semantics.rb +4 -0
- data/lib/hecks/query_specification/common/options.rb +25 -0
- data/lib/hecks/query_specification/field_path.rb +69 -15
- data/lib/hecks/query_specification/hop_path.rb +57 -20
- data/lib/hecks/query_specification/read_model/specification.rb +4 -0
- data/lib/hecks/rendering.rb +9 -3
- data/lib/hecks/router/namespace_installer.rb +16 -3
- data/lib/hecks/router.rb +56 -1
- data/lib/hecks/runtime/aggregate_lock.rb +20 -11
- data/lib/hecks/runtime/boot_gates.rb +21 -3
- data/lib/hecks/runtime/caller.rb +40 -8
- data/lib/hecks/runtime/capability_graph.rb +13 -2
- data/lib/hecks/runtime/command_interpreter/argument_gate.rb +40 -41
- data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +45 -67
- data/lib/hecks/runtime/command_interpreter.rb +195 -113
- data/lib/hecks/runtime/command_rules/admissibility.rb +231 -80
- data/lib/hecks/runtime/command_rules/arithmetic.rb +154 -96
- data/lib/hecks/runtime/command_rules/authorization.rb +38 -17
- data/lib/hecks/runtime/command_rules/emission.rb +18 -1
- data/lib/hecks/runtime/command_rules/references.rb +145 -55
- data/lib/hecks/runtime/command_rules.rb +3 -0
- data/lib/hecks/runtime/dependency_planning.rb +56 -11
- data/lib/hecks/runtime/dispatcher.rb +263 -92
- data/lib/hecks/runtime/entity_element.rb +304 -67
- data/lib/hecks/runtime/entity_interpreter.rb +149 -88
- data/lib/hecks/runtime/errors.rb +37 -23
- data/lib/hecks/runtime/event.rb +15 -10
- data/lib/hecks/runtime/identity.rb +91 -23
- data/lib/hecks/runtime/instance.rb +103 -18
- data/lib/hecks/runtime/interpreting.rb +24 -16
- data/lib/hecks/runtime/invocation.rb +358 -0
- data/lib/hecks/runtime/loader.rb +105 -19
- data/lib/hecks/runtime/outbox.rb +164 -26
- data/lib/hecks/runtime/policy_interpreter.rb +73 -60
- data/lib/hecks/runtime/port_operation_interpreter.rb +42 -19
- data/lib/hecks/runtime/query_interpreter.rb +93 -74
- data/lib/hecks/runtime/reaction_invocation.rb +73 -28
- data/lib/hecks/runtime/read_model_interpreter.rb +60 -44
- data/lib/hecks/runtime/rebuild_sweep.rb +32 -4
- data/lib/hecks/runtime/reference_hop.rb +48 -6
- data/lib/hecks/runtime/refusal_wording.rb +142 -115
- data/lib/hecks/runtime/registry/saga_persistence.rb +32 -21
- data/lib/hecks/runtime/registry/verification.rb +153 -28
- data/lib/hecks/runtime/registry.rb +202 -32
- data/lib/hecks/runtime/remote_dispatcher.rb +125 -24
- data/lib/hecks/runtime/routing.rb +36 -154
- data/lib/hecks/runtime/saga_interpreter/correlation.rb +25 -27
- data/lib/hecks/runtime/saga_interpreter.rb +90 -76
- data/lib/hecks/runtime/saga_pending_dispatch.rb +12 -12
- data/lib/hecks/runtime/tenant_check.rb +33 -13
- data/lib/hecks/runtime/tenant_scope.rb +23 -5
- data/lib/hecks/runtime/value/admission.rb +75 -30
- data/lib/hecks/runtime/value/coercion.rb +555 -142
- data/lib/hecks/runtime/value/entity_list_coercion.rb +132 -60
- data/lib/hecks/runtime/value.rb +71 -21
- data/lib/hecks/runtime.rb +39 -7
- data/lib/hecks/storehouse.rb +368 -72
- data/lib/hecks/tenancy/bluebook/tenancy.bluebook +130 -0
- data/lib/hecks/tenancy/bluebook/tenancy.hecksagon +32 -0
- data/lib/hecks/version.rb +3 -3
- data/lib/hecks/vocabulary.rb +205 -4
- data/lib/hecks.rb +91 -11
- data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +19 -11
- data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +24 -12
- data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +38 -14
- metadata +28 -2
|
@@ -14,6 +14,14 @@ module Hecks
|
|
|
14
14
|
module Shapes
|
|
15
15
|
# The type came in as the id of what it names, so it goes back out as the
|
|
16
16
|
# name — or, for another aggregate's head, as the encoding the IR spells.
|
|
17
|
+
#
|
|
18
|
+
# @param field [Hash{Symbol => Object}] one dispatched attribute row
|
|
19
|
+
# @param aggregate_id [String] the owning aggregate's own id, to
|
|
20
|
+
# strip from an owned value-object type
|
|
21
|
+
# @return [Hash{Symbol => Object}] `:name` (`Symbol`, `nil`),
|
|
22
|
+
# `:type` (`String`), `:list`/`:optional` (`Boolean`), `:default`
|
|
23
|
+
# (decoded literal, `nil` when absent), `:pattern`/`:admits`/
|
|
24
|
+
# `:relationship` (`String`, `nil` when absent)
|
|
17
25
|
def attribute(field, aggregate_id)
|
|
18
26
|
type = text(field[:type]).to_s
|
|
19
27
|
|
|
@@ -27,8 +35,8 @@ module Hecks
|
|
|
27
35
|
# bluebook that no longer says what it said.
|
|
28
36
|
optional: text(field[:optional]).to_s == "true",
|
|
29
37
|
pattern: presence(text(field[:pattern])),
|
|
30
|
-
#
|
|
31
|
-
#
|
|
38
|
+
# The round trip is the only way in. The grammar registry keeps the
|
|
39
|
+
# assembled graph — the language as its own judge read it back — so a
|
|
32
40
|
# fact dropped here is a fact no downstream projection ever sees, no
|
|
33
41
|
# matter how plainly the .bluebook file declares it.
|
|
34
42
|
admits: presence(text(field[:admits])),
|
|
@@ -36,9 +44,15 @@ module Hecks
|
|
|
36
44
|
}
|
|
37
45
|
end
|
|
38
46
|
|
|
39
|
-
# A
|
|
40
|
-
# Prefixed with the owner and the identity join, because that
|
|
47
|
+
# A type this aggregate owns, offered as its id and read back as its name.
|
|
48
|
+
# Prefixed with the owner and the identity join, because that is the value
|
|
41
49
|
# object's identity — the aggregate it belongs to, then its name.
|
|
50
|
+
#
|
|
51
|
+
# @param type [String] the attribute's own dispatched `type` cell
|
|
52
|
+
# @param aggregate_id [String] the owning aggregate's own id
|
|
53
|
+
# @return [String, nil] `type` with the owner's own identity prefix
|
|
54
|
+
# stripped, or `nil` if `type` does not carry that prefix (an
|
|
55
|
+
# ordinary type name, or a cross-aggregate reference)
|
|
42
56
|
def owned_type(type, aggregate_id)
|
|
43
57
|
prefix = Naming.identity([aggregate_id, ""])
|
|
44
58
|
return nil unless type.start_with?(prefix)
|
|
@@ -46,15 +60,18 @@ module Hecks
|
|
|
46
60
|
type.delete_prefix(prefix)
|
|
47
61
|
end
|
|
48
62
|
|
|
49
|
-
#
|
|
63
|
+
# One part of an identity, read back as the path it went in as. The inverse
|
|
50
64
|
# of `Marks#identity_path`, and named the same so the two directions read
|
|
51
65
|
# as one table.
|
|
66
|
+
#
|
|
67
|
+
# @param part [Hash{Symbol => Object}] one dispatched identity-part row
|
|
68
|
+
# @return [String] the identity part's own path text
|
|
52
69
|
def identity_path(part) = text(part[:value]).to_s
|
|
53
70
|
|
|
54
71
|
# An argument, a parameter, a piece's attribute — the three places an
|
|
55
72
|
# attribute is written that carry no owner id to strip... except a
|
|
56
73
|
# piece's own attribute now does : an entity is its own root (repeating
|
|
57
|
-
# the aggregate's whole shape one level down), so
|
|
74
|
+
# the aggregate's whole shape one level down), so its attributes name a
|
|
58
75
|
# value object exactly the way an aggregate's own do (`Judge#cell`'s own
|
|
59
76
|
# comment), and reconstruction has to undo the same owned-vs-reference
|
|
60
77
|
# split `attribute`, below, already undoes for an aggregate — not the
|
|
@@ -66,16 +83,25 @@ module Hecks
|
|
|
66
83
|
# argument or a parameter carries no value-object type at all — see
|
|
67
84
|
# entity.bluebook's/command.bluebook's own comments on why — so the
|
|
68
85
|
# generic reader path calls this with one argument and gets the
|
|
69
|
-
#
|
|
86
|
+
# old reading unchanged), is the piece's owning aggregate — the same
|
|
70
87
|
# one its own attribute types were resolved against on the way in
|
|
71
88
|
# (`Judge#owning_aggregate_ref`).
|
|
72
89
|
#
|
|
73
|
-
# A
|
|
90
|
+
# A reference among the other two came in as the head's ID, because
|
|
74
91
|
# that is what Command/Query.Reference offer, so it goes back out as
|
|
75
92
|
# the encoding the IR spells. A qualified name is the tell : an
|
|
76
93
|
# ordinary type names something declared beside it (`Money`,
|
|
77
94
|
# `AccountNumber`) and never carries a chapter, while a head's id
|
|
78
95
|
# always does.
|
|
96
|
+
#
|
|
97
|
+
# @param field [Hash{Symbol => Object}] one dispatched attribute,
|
|
98
|
+
# argument, or parameter row
|
|
99
|
+
# @param aggregate_id [String, nil] the piece's own owning
|
|
100
|
+
# aggregate id, passed only for a piece's own attribute
|
|
101
|
+
# @return [Hash{Symbol => Object}] `:name` (`Symbol`, `nil`),
|
|
102
|
+
# `:type` (`String`), `:list`/`:optional` (`Boolean`), `:default`
|
|
103
|
+
# (decoded literal, `nil` when absent), `:pattern`/`:admits`/
|
|
104
|
+
# `:relationship` (`String`, `nil` when absent)
|
|
79
105
|
def shape_field(field, aggregate_id = nil)
|
|
80
106
|
return attribute(field, aggregate_id) if aggregate_id
|
|
81
107
|
|
|
@@ -83,7 +109,7 @@ module Hecks
|
|
|
83
109
|
|
|
84
110
|
{
|
|
85
111
|
name: text(field[:name])&.to_sym,
|
|
86
|
-
# A
|
|
112
|
+
# A qualified name is the tell : an ordinary type names something
|
|
87
113
|
# declared beside it (`Money`, `AccountNumber`) and carries no join at
|
|
88
114
|
# all, where a head's id always does (chapter + name, joined the way
|
|
89
115
|
# every derived id is).
|
|
@@ -97,11 +123,16 @@ module Hecks
|
|
|
97
123
|
}
|
|
98
124
|
end
|
|
99
125
|
|
|
100
|
-
# An
|
|
126
|
+
# An absent pattern is nil, not "". The language holds every field as
|
|
101
127
|
# text, so a field nobody set comes back as the empty string — and ""
|
|
102
128
|
# is a real regex (it matches everything), so keeping it would turn
|
|
103
129
|
# "no pattern" into "a pattern that always passes" and quietly cost the
|
|
104
130
|
# IR its round trip.
|
|
131
|
+
#
|
|
132
|
+
# @param text [String, nil] a dispatched cell's own already-unwrapped
|
|
133
|
+
# text
|
|
134
|
+
# @return [String, nil] `text`, or `nil` when `text` is `nil` or
|
|
135
|
+
# empty
|
|
105
136
|
def presence(text)
|
|
106
137
|
value = text.to_s
|
|
107
138
|
value.empty? ? nil : value
|
|
@@ -113,13 +144,29 @@ module Hecks
|
|
|
113
144
|
# String, Integer, Float, TrueClass, FalseClass — plus a symbol, and an
|
|
114
145
|
# object literal, which is what `to: { value: "good" }` is: a value object's
|
|
115
146
|
# fields written inline.
|
|
147
|
+
#
|
|
148
|
+
# @param text [String, nil] the self-describing wire spelling
|
|
149
|
+
# `Readings#encode_literal` wrote
|
|
150
|
+
# @return [Object] `nil`, `true`, `false`, `Integer`, `Float`,
|
|
151
|
+
# `Symbol`, `Hecks::StateRef`, `String`, `Hash`, or `Array` — or
|
|
152
|
+
# `text` itself, stripped, when it matches no known spelling
|
|
116
153
|
def decode_literal(text) = Literal.read(text)
|
|
117
154
|
|
|
155
|
+
# Reads a rule's plain description/canonical pair, for a
|
|
156
|
+
# `given`/`invariant`/`ensures`.
|
|
157
|
+
#
|
|
158
|
+
# @param row [Hash{Symbol => Object}] one dispatched rule row
|
|
159
|
+
# @return [Hash{Symbol => String}] `:description` and `:canonical`
|
|
118
160
|
def rule(row) = { description: text(row[:description]), canonical: text(row[:canonical]) }
|
|
119
161
|
|
|
120
162
|
# S12, ADR 0025 — `projects :name, from: :"reference.remote_field"`,
|
|
121
163
|
# read back the same three plain identifiers `rule` above reads
|
|
122
164
|
# description/canonical as.
|
|
165
|
+
#
|
|
166
|
+
# @param row [Hash{Symbol => Object}] one dispatched projected-field
|
|
167
|
+
# row
|
|
168
|
+
# @return [Hash{Symbol => String}] `:name`, `:reference`, and
|
|
169
|
+
# `:remote_field`
|
|
123
170
|
def projected_field(row)
|
|
124
171
|
{ name: text(row[:name]), reference: text(row[:reference]), remote_field: text(row[:remote_field]) }
|
|
125
172
|
end
|
|
@@ -128,26 +175,57 @@ module Hecks
|
|
|
128
175
|
# does — an object literal, self-describing via Hecks::Literal — one
|
|
129
176
|
# level up: a whole keyword's argument rather than an attribute's
|
|
130
177
|
# `default:`.
|
|
178
|
+
#
|
|
179
|
+
# @param row [Hash{Symbol => Object}] a dispatched row carrying a
|
|
180
|
+
# `:provenance` cell
|
|
181
|
+
# @return [Object] the decoded `from:` object literal, or `nil` when
|
|
182
|
+
# absent
|
|
131
183
|
def provenance(row) = decode_literal(text(row[:provenance]))
|
|
132
184
|
|
|
133
|
-
# `command "Debit", from: "open"` — the
|
|
185
|
+
# `command "Debit", from: "open"` — the same literal encoding
|
|
134
186
|
# `provenance`/`default:` already ride (S10, ADR 0025), one
|
|
135
187
|
# state or an array of them, or nil for a command with no
|
|
136
188
|
# lifecycle guard.
|
|
189
|
+
#
|
|
190
|
+
# @param row [Hash{Symbol => Object}] a dispatched row carrying a
|
|
191
|
+
# `:from` cell
|
|
192
|
+
# @return [String, Array<String>, nil] the decoded lifecycle guard
|
|
193
|
+
# state(s), or `nil` for a command with no lifecycle guard
|
|
137
194
|
def from(row) = decode_literal(text(row[:from]))
|
|
138
195
|
|
|
139
|
-
#
|
|
196
|
+
# A flag is held as text ("true"/"false") and emitted as a boolean —
|
|
197
|
+
# `Policy#expect_undelivered` on the wire.
|
|
198
|
+
#
|
|
199
|
+
# @param row [Hash{Symbol => Object}] a dispatched row carrying an
|
|
200
|
+
# `:expect_undelivered` cell
|
|
201
|
+
# @return [Boolean] whether the flag reads `"true"`
|
|
202
|
+
def expect_undelivered?(row) = text(row[:expect_undelivered]).to_s == "true"
|
|
203
|
+
|
|
204
|
+
# The option rows, gathered back into the shapes `extra_options_to_h` spells.
|
|
140
205
|
#
|
|
141
206
|
# One row per part, so a compound option is several rows and a repeated one is
|
|
142
207
|
# several groups told apart by `at`. Grouping by option name and then by `at`
|
|
143
208
|
# rebuilds both without either knowing which options exist — the whole point
|
|
144
209
|
# of holding them as an open map.
|
|
210
|
+
#
|
|
211
|
+
# @param row [Hash{Symbol => Object}] a dispatched row carrying an
|
|
212
|
+
# `:options` list
|
|
213
|
+
# @return [Hash{Symbol => Object}] one entry per option name; each
|
|
214
|
+
# value is `gathered`'s own return for that option's own parts
|
|
145
215
|
def options_of(row)
|
|
146
216
|
Array(row[:options])
|
|
147
217
|
.group_by { |part| text(part[:option]) }
|
|
148
218
|
.to_h { |option, parts| [option.to_sym, gathered(parts)] }
|
|
149
219
|
end
|
|
150
220
|
|
|
221
|
+
# Groups one option's own dispatched parts back into a single
|
|
222
|
+
# binding, or several `at`-keyed groups for a repeated option.
|
|
223
|
+
#
|
|
224
|
+
# @param parts [Array<Hash{Symbol => Object}>] one option's own
|
|
225
|
+
# dispatched key/value/at rows
|
|
226
|
+
# @return [Hash{Symbol => String}, Array<Hash{Symbol => String}>]
|
|
227
|
+
# a single `key => value` hash when no part carries `at`;
|
|
228
|
+
# otherwise an array of such hashes, one per distinct `at`
|
|
151
229
|
def gathered(parts)
|
|
152
230
|
repeated, single = parts.partition { |part| !text(part[:at]).to_s.empty? }
|
|
153
231
|
return single.to_h { |part| [text(part[:key]).to_sym, text(part[:value])] } if repeated.empty?
|
|
@@ -157,8 +235,8 @@ module Hecks
|
|
|
157
235
|
.map { |group| group.to_h { |part| [text(part[:key]).to_sym, text(part[:value])] } }
|
|
158
236
|
end
|
|
159
237
|
|
|
160
|
-
# The IR keeps a where's field as a
|
|
161
|
-
# out, never called. The value stays
|
|
238
|
+
# The IR keeps a where's field as a string, not a symbol — it is read back
|
|
239
|
+
# out, never called. The value stays raw text here on purpose : this
|
|
162
240
|
# feeds the declaration hash Assembly::Marks#where_clause decodes
|
|
163
241
|
# from (via `read`), and decoding twice is worse than once — a
|
|
164
242
|
# kwarg reference (":ceiling") decoded here into the Symbol :ceiling
|
|
@@ -166,11 +244,20 @@ module Hecks
|
|
|
166
244
|
# back out as the plain string "ceiling", indistinguishable from a
|
|
167
245
|
# literal of the same name. One decode, at the one place that builds
|
|
168
246
|
# the object every comparator actually reads.
|
|
247
|
+
#
|
|
248
|
+
# @param row [Hash{Symbol => Object}] one dispatched where-clause row
|
|
249
|
+
# @return [Hash{Symbol => String}] `:field`, `:op`, and `:value`
|
|
250
|
+
# (raw text, undecoded)
|
|
169
251
|
def where_clause(row)
|
|
170
252
|
{ field: text(row[:field]), op: text(row[:op]), value: text(row[:value]) }
|
|
171
253
|
end
|
|
172
254
|
|
|
173
255
|
# One object in the IR, two fields in the language.
|
|
256
|
+
#
|
|
257
|
+
# @param row [Hash{Symbol => Object}] a dispatched row carrying
|
|
258
|
+
# `:order_field`/`:order_way` cells
|
|
259
|
+
# @return [Hash{Symbol => String}, nil] `:field` and `:direction`,
|
|
260
|
+
# or `nil` when no `order_field` was declared
|
|
174
261
|
def order_by(row)
|
|
175
262
|
field = text(row[:order_field])
|
|
176
263
|
return nil if field.to_s.empty?
|
|
@@ -178,6 +265,12 @@ module Hecks
|
|
|
178
265
|
{ field: field, direction: text(row[:order_way]) }
|
|
179
266
|
end
|
|
180
267
|
|
|
268
|
+
# Reads a read model's own declared row limit.
|
|
269
|
+
#
|
|
270
|
+
# @param row [Hash{Symbol => Object}] a dispatched row carrying a
|
|
271
|
+
# `:limit` cell
|
|
272
|
+
# @return [Hash{Symbol => String}, nil] `{value: ceiling}`, or `nil`
|
|
273
|
+
# when no limit was declared
|
|
181
274
|
def limit(row)
|
|
182
275
|
ceiling = text(row[:limit])
|
|
183
276
|
return nil if ceiling.to_s.empty?
|
|
@@ -185,6 +278,12 @@ module Hecks
|
|
|
185
278
|
{ value: ceiling }
|
|
186
279
|
end
|
|
187
280
|
|
|
281
|
+
# Reads one lifecycle transition row.
|
|
282
|
+
#
|
|
283
|
+
# @param row [Hash{Symbol => Object}] one dispatched lifecycle
|
|
284
|
+
# transition row
|
|
285
|
+
# @return [Hash{Symbol => String}] `:command`, `:from_state`, and
|
|
286
|
+
# `:to_state`
|
|
188
287
|
def transition(row)
|
|
189
288
|
{
|
|
190
289
|
command: text(row[:command]),
|
|
@@ -193,6 +292,13 @@ module Hecks
|
|
|
193
292
|
}
|
|
194
293
|
end
|
|
195
294
|
|
|
295
|
+
# Reads one reference head — a process manager handler's own
|
|
296
|
+
# aggregate binding.
|
|
297
|
+
#
|
|
298
|
+
# @param row [Hash{Symbol => Object}] one dispatched reference-head
|
|
299
|
+
# row
|
|
300
|
+
# @return [Hash{Symbol => Object}] `:aggregate`/`:as` (`String`) and
|
|
301
|
+
# `:many` (`Boolean`)
|
|
196
302
|
def head(row)
|
|
197
303
|
{
|
|
198
304
|
aggregate: text(row[:aggregate]),
|
|
@@ -203,33 +309,48 @@ module Hecks
|
|
|
203
309
|
}
|
|
204
310
|
end
|
|
205
311
|
|
|
312
|
+
# Reads a read model's own `group_by` field name.
|
|
313
|
+
#
|
|
314
|
+
# @param row [Hash{Symbol => Object}] a dispatched row carrying a
|
|
315
|
+
# `:field` cell
|
|
316
|
+
# @return [Hash{Symbol => String}] `{field: ...}`
|
|
206
317
|
def group_by_field(row) = { field: text(row[:field]) }
|
|
207
318
|
|
|
208
|
-
# `count`'s own boolean, read back the
|
|
319
|
+
# `count`'s own boolean, read back the same way `head`'s own
|
|
209
320
|
# `many` is (`text(row[:many]).to_s == "true"`) — except a
|
|
210
|
-
# `ReadModel.Count` command is dispatched
|
|
321
|
+
# `ReadModel.Count` command is dispatched at all only when
|
|
211
322
|
# `@count` was truthy (`MetaValidator::Judge#setters` skips a
|
|
212
323
|
# setter whose every source is absent), so an undeclared read
|
|
213
324
|
# model's own `count` field never gets written and comes back
|
|
214
325
|
# `nil` here, never `"false"` — matching `ReadModel#to_h`'s own
|
|
215
326
|
# `true`/`nil` pair (never `false`) exactly, rather than the
|
|
216
327
|
# unconditional `true`/`false` `head`'s own `many` needs (every
|
|
217
|
-
# head
|
|
328
|
+
# head does get a `Gather` dispatch, declared or derived).
|
|
329
|
+
#
|
|
330
|
+
# @param row [Hash{Symbol => Object}] a dispatched row carrying a
|
|
331
|
+
# `:count` cell
|
|
332
|
+
# @return [Boolean, nil] `true` when the flag reads `"true"`, `nil`
|
|
333
|
+
# for an undeclared read model's own `count`
|
|
218
334
|
def read_model_count(row) = (true if text(row[:count]).to_s == "true")
|
|
219
335
|
|
|
220
|
-
#
|
|
336
|
+
# The append flattening, in reverse.
|
|
221
337
|
#
|
|
222
338
|
# An append binds several fields at once and the language's Change holds one
|
|
223
|
-
# field/kind/source triple, so the walk offers an append once
|
|
339
|
+
# field/kind/source triple, so the walk offers an append once per binding.
|
|
224
340
|
# Rebuilding groups those rows back into the single mutation the IR keeps —
|
|
225
341
|
# the only place here that undoes something rather than simply reading it.
|
|
342
|
+
#
|
|
343
|
+
# @param row [Hash{Symbol => Object}] a dispatched row carrying a
|
|
344
|
+
# `:mutations` list
|
|
345
|
+
# @return [Array<Hash{Symbol => Object}>] one hash per distinct
|
|
346
|
+
# `target`/`op` pair, each `mutation`'s own return
|
|
226
347
|
def mutations(row)
|
|
227
348
|
Array(row[:mutations])
|
|
228
349
|
.group_by { |change| [text(change[:target]), text(change[:op])] }
|
|
229
350
|
.map { |(target, op), bindings| mutation(target, op, bindings) }
|
|
230
351
|
end
|
|
231
352
|
|
|
232
|
-
# `sign:` — read the
|
|
353
|
+
# `sign:` — read the same way the declared side computes it
|
|
233
354
|
# (`Bluebook::Mutation.sign_for`, item #5 of the whole-project
|
|
234
355
|
# table-unification survey), not stored on any row here — the
|
|
235
356
|
# meta-domain's own Change entity carries no `sign` field of its
|
|
@@ -238,20 +359,44 @@ module Hecks
|
|
|
238
359
|
# Mutation's own `to_h` lambda does, rather than leaving the key
|
|
239
360
|
# silently absent (spec/round_trip_spec's whole point: a field the
|
|
240
361
|
# language does not hold is a named gap, not a byte-for-byte one).
|
|
362
|
+
#
|
|
363
|
+
# @param target [String] the mutated field's own name
|
|
364
|
+
# @param oper [String] the mutation's operation name, such as
|
|
365
|
+
# `"set"`, `"append"`, `"delegate"`, or `"corrects"`
|
|
366
|
+
# @param bindings [Array<Hash{Symbol => Object}>] this target/op
|
|
367
|
+
# pair's own dispatched binding rows
|
|
368
|
+
# @return [Hash{Symbol => Object}] `:target`/`:op` (`Symbol`),
|
|
369
|
+
# `:sign` (`String`), plus `:fields` (`appended`'s own return) for
|
|
370
|
+
# `"append"`/`"delegate"`/`"corrects"`, or `:source`
|
|
371
|
+
# (`classified`'s own return) for anything else
|
|
241
372
|
def mutation(target, oper, bindings)
|
|
242
373
|
base = { target: target.to_sym, op: oper.to_sym, sign: Hecks::Bluebook::Mutation.sign_for(oper) }
|
|
243
374
|
# `:delegate`/`:corrects` (CommandBuilder#delegates_to's and
|
|
244
|
-
# #corrects_impl's own comments) ride the
|
|
375
|
+
# #corrects_impl's own comments) ride the same multi-binding
|
|
245
376
|
# shape `:append` does.
|
|
246
377
|
return base.merge(fields: appended(bindings)) if ["append", "delegate", "corrects"].include?(oper)
|
|
247
378
|
|
|
248
379
|
base.merge(source: classified(bindings.first))
|
|
249
380
|
end
|
|
250
381
|
|
|
382
|
+
# Rebuilds an append's own field -> source map from its flattened
|
|
383
|
+
# per-binding rows.
|
|
384
|
+
#
|
|
385
|
+
# @param bindings [Array<Hash{Symbol => Object}>] one append's own
|
|
386
|
+
# dispatched binding rows
|
|
387
|
+
# @return [Hash{Symbol => String}] each bound field name mapped to
|
|
388
|
+
# its own source text
|
|
251
389
|
def appended(bindings)
|
|
252
390
|
bindings.to_h { |binding| [text(binding[:field]).to_sym, text(binding[:source])] }
|
|
253
391
|
end
|
|
254
392
|
|
|
393
|
+
# Classifies a single-binding mutation's own source.
|
|
394
|
+
#
|
|
395
|
+
# @param binding [Hash{Symbol => Object}] one dispatched binding row
|
|
396
|
+
# @return [Hash{Symbol => Object}] `{kind: "argument"|"state",
|
|
397
|
+
# name: String}` for an argument or state reference, or
|
|
398
|
+
# `{kind: "literal", value: Object}` (the decoded literal) for
|
|
399
|
+
# anything else
|
|
255
400
|
def classified(binding)
|
|
256
401
|
kind = text(binding[:kind])
|
|
257
402
|
value = text(binding[:source])
|