hecks 1.3.0 → 1.4.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 +7 -7
- data/lib/hecks/adapters/driven/d1.rb +187 -23
- data/lib/hecks/adapters/driven/folder.rb +10 -10
- data/lib/hecks/adapters/driven/google_authentication.rb +8 -8
- data/lib/hecks/adapters/driven/governance_authorization.rb +31 -13
- data/lib/hecks/adapters/driven/heki/journal.rb +5 -4
- data/lib/hecks/adapters/driven/heki/saga_store.rb +5 -5
- data/lib/hecks/adapters/driven/heki.rb +13 -7
- data/lib/hecks/adapters/driven/identity_registry.rb +2 -2
- data/lib/hecks/adapters/driven/in_memory_ordering.rb +3 -3
- data/lib/hecks/adapters/driven/lambda/client.rb +34 -9
- data/lib/hecks/adapters/driven/lambda.rb +39 -33
- data/lib/hecks/adapters/driven/local_storage.rb +17 -10
- data/lib/hecks/adapters/driven/memory.rb +205 -9
- data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +1 -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 +4 -4
- 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.rb +4 -4
- data/lib/hecks/adapters/driving/github_webhook.rb +18 -18
- data/lib/hecks/behaviors/dsl.rb +2 -2
- data/lib/hecks/behaviors/expectations.rb +23 -23
- data/lib/hecks/behaviors/ir.rb +1 -1
- data/lib/hecks/behaviors/rspec.rb +1 -1
- data/lib/hecks/behaviors/runner.rb +2 -2
- data/lib/hecks/behaviors.rb +1 -1
- data/lib/hecks/bluebook/aggregate.rb +13 -13
- data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +10 -10
- data/lib/hecks/bluebook/assembly/build.rb +1 -1
- data/lib/hecks/bluebook/assembly/contract.rb +39 -16
- data/lib/hecks/bluebook/assembly/contracts.rb +40 -38
- data/lib/hecks/bluebook/assembly/marks.rb +18 -18
- data/lib/hecks/bluebook/assembly/specializer.rb +19 -21
- data/lib/hecks/bluebook/assembly.rb +9 -9
- data/lib/hecks/bluebook/attribute.rb +9 -9
- data/lib/hecks/bluebook/behaviour/aggregate.rb +11 -11
- data/lib/hecks/bluebook/behaviour/attribute.rb +5 -5
- data/lib/hecks/bluebook/behaviour/chapter.rb +23 -5
- data/lib/hecks/bluebook/behaviour/command.rb +23 -23
- data/lib/hecks/bluebook/behaviour/domain_port.rb +7 -7
- data/lib/hecks/bluebook/behaviour/entity.rb +8 -8
- data/lib/hecks/bluebook/behaviour/hexagon.rb +4 -4
- data/lib/hecks/bluebook/behaviour/lifecycle.rb +5 -5
- data/lib/hecks/bluebook/behaviour/policy.rb +12 -12
- data/lib/hecks/bluebook/behaviour/process_manager.rb +7 -7
- data/lib/hecks/bluebook/behaviour/query.rb +1 -1
- data/lib/hecks/bluebook/behaviour/read_model.rb +8 -8
- data/lib/hecks/bluebook/behaviour/traits.rb +12 -12
- data/lib/hecks/bluebook/behaviour/value_object.rb +6 -6
- data/lib/hecks/bluebook/capabilities.rb +27 -0
- data/lib/hecks/bluebook/chapter.rb +28 -9
- data/lib/hecks/bluebook/command.rb +12 -12
- data/lib/hecks/bluebook/domain_port.rb +9 -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 +96 -96
- data/lib/hecks/bluebook/dsl/attribute_collector.rb +41 -41
- data/lib/hecks/bluebook/dsl/binding_proxy.rb +22 -2
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +111 -74
- data/lib/hecks/bluebook/dsl/bluebook_builder.rb +48 -30
- data/lib/hecks/bluebook/dsl/bootstrap_table.rb +116 -0
- data/lib/hecks/bluebook/dsl/command_builder.rb +103 -103
- 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 +56 -56
- data/lib/hecks/bluebook/dsl/generic_dispatch.rb +148 -132
- data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +89 -30
- data/lib/hecks/bluebook/dsl/identity_declaration.rb +17 -17
- data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +27 -4
- data/lib/hecks/bluebook/dsl/policy_builder.rb +30 -21
- 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 +35 -35
- data/lib/hecks/bluebook/dsl/query_builder.rb +5 -5
- data/lib/hecks/bluebook/dsl/read_model_builder.rb +34 -34
- data/lib/hecks/bluebook/dsl/rule_reference.rb +41 -39
- data/lib/hecks/bluebook/dsl/translation_builder.rb +9 -9
- data/lib/hecks/bluebook/dsl/value_object_builder.rb +16 -16
- 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 +11 -11
- data/lib/hecks/bluebook/expression/ast_json.rb +20 -20
- data/lib/hecks/bluebook/expression/ast_reader.rb +3 -3
- data/lib/hecks/bluebook/expression/canonical_form.rb +9 -9
- data/lib/hecks/bluebook/expression/evaluator.rb +18 -18
- data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +18 -18
- data/lib/hecks/bluebook/expression/resolver.rb +60 -62
- data/lib/hecks/bluebook/hexagon.rb +1 -1
- data/lib/hecks/bluebook/lifecycle.rb +1 -1
- data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +1 -1
- data/lib/hecks/bluebook/meta_validator/judge.rb +101 -87
- data/lib/hecks/bluebook/meta_validator/plan.rb +39 -39
- data/lib/hecks/bluebook/meta_validator/port_judge.rb +2 -2
- data/lib/hecks/bluebook/meta_validator/readings.rb +43 -43
- data/lib/hecks/bluebook/meta_validator/reconstruction.rb +44 -37
- data/lib/hecks/bluebook/meta_validator/shapes.rb +25 -21
- data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +145 -31
- data/lib/hecks/bluebook/meta_validator/translation_judge.rb +6 -6
- data/lib/hecks/bluebook/meta_validator/world_judge.rb +5 -5
- data/lib/hecks/bluebook/meta_validator.rb +70 -70
- data/lib/hecks/bluebook/model_check.rb +170 -84
- data/lib/hecks/bluebook/pattern_subset.rb +9 -9
- data/lib/hecks/bluebook/policy.rb +15 -13
- data/lib/hecks/bluebook/process_manager.rb +14 -14
- data/lib/hecks/bluebook/project_register.rb +6 -6
- data/lib/hecks/bluebook/query.rb +4 -4
- data/lib/hecks/bluebook/read_model.rb +14 -14
- data/lib/hecks/bluebook/reference.rb +8 -8
- data/lib/hecks/bluebook/smoke_test.rb +19 -19
- data/lib/hecks/bluebook/synthesizer.rb +12 -12
- data/lib/hecks/bluebook/translation.rb +4 -4
- data/lib/hecks/bluebook/value_object.rb +6 -6
- data/lib/hecks/bluebook.rb +2 -2
- data/lib/hecks/codemod/legacy_dispatch_args.rb +299 -0
- data/lib/hecks/codemod/legacy_dispatch_recorder.rb +186 -0
- data/lib/hecks/codemod.rb +36 -35
- data/lib/hecks/construct.rb +6 -6
- data/lib/hecks/corpus.rb +317 -0
- data/lib/hecks/deprecation.rb +95 -0
- data/lib/hecks/doc/reference.rb +19 -19
- data/lib/hecks/embryonaut_bluebook.rb +11 -11
- 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 +79 -32
- data/lib/hecks/facade/json_door.rb +106 -25
- data/lib/hecks/facade/surface/aggregate_door.rb +42 -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 +180 -19
- data/lib/hecks/forms/html.rb +51 -7
- data/lib/hecks/forms/index_renderer.rb +14 -2
- data/lib/hecks/forms/params.rb +120 -23
- data/lib/hecks/forms/port_argument.rb +2 -2
- data/lib/hecks/forms/query_form_renderer.rb +2 -2
- data/lib/hecks/forms/record_renderer.rb +2 -2
- data/lib/hecks/forms/record_table.rb +1 -1
- data/lib/hecks/forms/value_object_shape.rb +3 -3
- data/lib/hecks/forms.rb +24 -4
- data/lib/hecks/fqn.rb +1 -1
- data/lib/hecks/framework/bluebook/governance.bluebook +9 -0
- data/lib/hecks/framework.rb +48 -17
- data/lib/hecks/freezer.rb +11 -11
- data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +90 -90
- data/lib/hecks/fuzzing/combination_miner.rb +119 -0
- data/lib/hecks/fuzzing/concurrent_dispatch.rb +140 -45
- data/lib/hecks/fuzzing/coverage_campaign.rb +118 -0
- data/lib/hecks/fuzzing/differential.rb +158 -0
- data/lib/hecks/fuzzing/domain_generator.rb +694 -0
- data/lib/hecks/fuzzing/era_boundary.rb +37 -18
- data/lib/hecks/fuzzing/form_census.rb +35 -20
- data/lib/hecks/fuzzing/generated_domain_check.rb +95 -0
- data/lib/hecks/fuzzing/invalid_value_generator.rb +6 -6
- data/lib/hecks/fuzzing/isolated_boot.rb +62 -62
- data/lib/hecks/fuzzing/nondeterministic.rb +67 -0
- data/lib/hecks/fuzzing/persistence_parity.rb +19 -21
- data/lib/hecks/fuzzing/properties/corrections.rb +9 -9
- data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +154 -49
- data/lib/hecks/fuzzing/properties/guards.rb +42 -42
- data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +32 -32
- data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +22 -35
- data/lib/hecks/fuzzing/properties/outbox.rb +24 -24
- data/lib/hecks/fuzzing/properties/querying.rb +17 -17
- data/lib/hecks/fuzzing/properties.rb +64 -40
- data/lib/hecks/fuzzing/qa_settings.rb +152 -0
- data/lib/hecks/fuzzing/replay.rb +114 -114
- data/lib/hecks/fuzzing/rotation_priority.rb +10 -10
- data/lib/hecks/fuzzing/rust_gap_manifest.rb +113 -0
- data/lib/hecks/fuzzing/self_consistency.rb +141 -112
- data/lib/hecks/fuzzing/sequence_generator/adversary.rb +35 -35
- 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 +58 -31
- data/lib/hecks/fuzzing/sequence_generator.rb +111 -23
- data/lib/hecks/fuzzing/shrinker.rb +197 -0
- data/lib/hecks/fuzzing/structural_skips.rb +23 -130
- data/lib/hecks/fuzzing/sweep_depth.rb +4 -4
- data/lib/hecks/fuzzing/target_capabilities.rb +49 -18
- data/lib/hecks/fuzzing/value_generator.rb +14 -14
- data/lib/hecks/fuzzing.rb +5 -0
- data/lib/hecks/grammar/evolve.rb +10 -10
- data/lib/hecks/grammar.rb +7 -7
- data/lib/hecks/ir.rb +13 -13
- 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/oidc.json +5 -0
- data/lib/hecks/literal.rb +9 -9
- data/lib/hecks/naming.rb +25 -25
- data/lib/hecks/ports/access_control.rb +58 -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 +53 -11
- data/lib/hecks/ports/clock.rb +42 -23
- data/lib/hecks/ports/extraction.rb +16 -0
- data/lib/hecks/ports/identity_assignment.rb +24 -2
- data/lib/hecks/ports/identity_generation.rb +17 -3
- data/lib/hecks/ports/identity_resolution.rb +18 -1
- 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 +28 -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 +57 -4
- 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 +42 -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 +18 -19
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +5 -5
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +1 -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 +3 -3
- data/lib/hecks/ports/query/ordering.rb +6 -6
- data/lib/hecks/ports/query.rb +35 -0
- data/lib/hecks/projections/bootstrap_table.rb +112 -0
- data/lib/hecks/projections/diagrams.rb +75 -75
- data/lib/hecks/projections/glossary/html.rb +3 -3
- data/lib/hecks/projections/glossary/markdown.rb +3 -3
- data/lib/hecks/projections/glossary/mermaid.rb +1 -1
- data/lib/hecks/projections/glossary/sections.rb +1 -1
- data/lib/hecks/projections/glossary/sentences.rb +5 -5
- data/lib/hecks/projections/glossary.rb +15 -15
- data/lib/hecks/projections/ir.rb +1 -1
- data/lib/hecks/projections/model/deviations.rb +18 -17
- data/lib/hecks/projections/model.rb +25 -21
- data/lib/hecks/projections/oidc.rb +7 -7
- data/lib/hecks/projections/parser_table.rb +5 -5
- data/lib/hecks/projections/reference.rb +3 -3
- data/lib/hecks/projections/rust_vocabulary.rb +443 -0
- data/lib/hecks/projections/shape.rb +2 -2
- data/lib/hecks/projections/statements.rb +11 -11
- data/lib/hecks/projections/vocabulary.rb +9 -9
- data/lib/hecks/projections.rb +5 -3
- data/lib/hecks/projector/cli_projector.rb +29 -29
- data/lib/hecks/projector/docs_projector.rb +13 -13
- data/lib/hecks/projector/exporter.rb +42 -21
- data/lib/hecks/projector/ir_projector.rb +1 -1
- data/lib/hecks/projector/narrate_projector.rb +11 -11
- data/lib/hecks/projector/target.rb +13 -13
- data/lib/hecks/projector.rb +15 -15
- data/lib/hecks/query_ir.rb +47 -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 +57 -13
- 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 +3 -3
- data/lib/hecks/router/namespace_installer.rb +3 -3
- data/lib/hecks/router.rb +1 -1
- data/lib/hecks/runtime/aggregate_lock.rb +11 -11
- data/lib/hecks/runtime/boot_gates.rb +3 -3
- data/lib/hecks/runtime/caller.rb +8 -8
- data/lib/hecks/runtime/capability_graph.rb +2 -2
- data/lib/hecks/runtime/command_interpreter/argument_gate.rb +22 -25
- data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +42 -63
- data/lib/hecks/runtime/command_interpreter.rb +159 -102
- data/lib/hecks/runtime/command_rules/admissibility.rb +69 -69
- data/lib/hecks/runtime/command_rules/arithmetic.rb +137 -91
- 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 +35 -35
- data/lib/hecks/runtime/command_rules.rb +3 -0
- data/lib/hecks/runtime/dependency_planning.rb +11 -11
- data/lib/hecks/runtime/dispatcher.rb +283 -90
- data/lib/hecks/runtime/entity_element.rb +151 -67
- data/lib/hecks/runtime/entity_interpreter.rb +108 -82
- data/lib/hecks/runtime/errors.rb +19 -19
- data/lib/hecks/runtime/event.rb +6 -6
- data/lib/hecks/runtime/identity.rb +22 -22
- data/lib/hecks/runtime/instance.rb +39 -14
- data/lib/hecks/runtime/interpreting.rb +12 -12
- data/lib/hecks/runtime/invocation.rb +276 -0
- data/lib/hecks/runtime/loader.rb +14 -14
- data/lib/hecks/runtime/outbox.rb +23 -23
- data/lib/hecks/runtime/policy_interpreter.rb +54 -54
- data/lib/hecks/runtime/port_operation_interpreter.rb +22 -19
- data/lib/hecks/runtime/query_interpreter.rb +55 -64
- data/lib/hecks/runtime/reaction_invocation.rb +20 -20
- data/lib/hecks/runtime/read_model_interpreter.rb +40 -40
- data/lib/hecks/runtime/rebuild_sweep.rb +4 -4
- data/lib/hecks/runtime/reference_hop.rb +6 -6
- data/lib/hecks/runtime/refusal_wording.rb +92 -115
- data/lib/hecks/runtime/registry/saga_persistence.rb +21 -21
- data/lib/hecks/runtime/registry/verification.rb +36 -26
- data/lib/hecks/runtime/registry.rb +45 -28
- data/lib/hecks/runtime/remote_dispatcher.rb +38 -23
- data/lib/hecks/runtime/routing.rb +10 -153
- data/lib/hecks/runtime/saga_interpreter/correlation.rb +17 -17
- data/lib/hecks/runtime/saga_interpreter.rb +64 -64
- data/lib/hecks/runtime/saga_pending_dispatch.rb +12 -12
- data/lib/hecks/runtime/tenant_check.rb +9 -9
- data/lib/hecks/runtime/tenant_scope.rb +5 -5
- data/lib/hecks/runtime/value/admission.rb +75 -30
- data/lib/hecks/runtime/value/coercion.rb +318 -127
- data/lib/hecks/runtime/value/entity_list_coercion.rb +34 -34
- data/lib/hecks/runtime/value.rb +21 -21
- data/lib/hecks/runtime.rb +7 -7
- data/lib/hecks/storehouse.rb +64 -64
- data/lib/hecks/version.rb +3 -3
- data/lib/hecks/vocabulary.rb +205 -4
- data/lib/hecks.rb +13 -11
- data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +11 -11
- data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +14 -12
- data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +11 -11
- metadata +22 -2
|
@@ -1,25 +1,29 @@
|
|
|
1
|
+
require_relative "bootstrap_table"
|
|
2
|
+
|
|
1
3
|
module Hecks
|
|
2
4
|
module Bluebook
|
|
3
5
|
module DSL
|
|
4
|
-
#
|
|
6
|
+
# Item #13's full metaprogrammed dispatch — slices 1-2 of 4, whole-
|
|
5
7
|
# project table-unification survey. WordGate (the first slice,
|
|
6
|
-
# already shipped) only
|
|
7
|
-
#
|
|
8
|
-
#
|
|
8
|
+
# already shipped) only checks a word's admissibility; this module
|
|
9
|
+
# executes the safe, mechanical subset of what a word actually
|
|
10
|
+
# does, read live off the same self-hosted grammar table — so a
|
|
9
11
|
# builder method for one of these words no longer needs to be
|
|
10
12
|
# hand-written at all. Called from `WordGate#method_missing`'s own
|
|
11
13
|
# "admitted here, no builder method for it yet" branch, so it only
|
|
12
14
|
# ever sees a word whose (context, word) pair the grammar already
|
|
13
15
|
# admits.
|
|
14
16
|
#
|
|
15
|
-
#
|
|
17
|
+
# ## What is covered
|
|
18
|
+
#
|
|
19
|
+
# Scope, deliberately narrow and verified word-by-word — a full
|
|
16
20
|
# audit read every real Ruby builder method's own source before
|
|
17
21
|
# any of this was written, not inferred from the table's shape
|
|
18
22
|
# alone (which fooled a first pass: `ReadModelBuilder#group_by`/
|
|
19
|
-
# `#include`
|
|
23
|
+
# `#include` look like plain fills from `kind`/`fills` alone, but
|
|
20
24
|
# actually wrap their arguments in a Hash/tuple). What's covered:
|
|
21
25
|
#
|
|
22
|
-
# - a
|
|
26
|
+
# - a single, non-variadic, positional Argument row whose value
|
|
23
27
|
# is stored with nothing beyond a uniform, kind-driven
|
|
24
28
|
# coercion (`COERCE_BY_KIND`) — or, for `kind: "text"`, no
|
|
25
29
|
# coercion at all when the row's own `coerce: "false"` says so
|
|
@@ -27,43 +31,45 @@ module Hecks
|
|
|
27
31
|
# is a same-object no-op for every real corpus use, but a
|
|
28
32
|
# genuine behavior change for a direct Ruby API call passing
|
|
29
33
|
# something else)
|
|
30
|
-
# - a scalar
|
|
34
|
+
# - a scalar assign (`@ivar = value`) or list append (`@ivar <<
|
|
31
35
|
# value`), chosen by whether the ivar `fills:` names is
|
|
32
|
-
#
|
|
36
|
+
# already an Array at call time (every candidate's own
|
|
33
37
|
# `initialize` pre-populates its accumulating ivars as `[]` —
|
|
34
38
|
# read live, not assumed)
|
|
35
|
-
# - a
|
|
36
|
-
# Keyword rows in the
|
|
37
|
-
# target — derives its own stored value from
|
|
39
|
+
# - a zero-argument word, either (a) one of several sibling
|
|
40
|
+
# Keyword rows in the same context sharing the same `fills:`
|
|
41
|
+
# target — derives its own stored value from its own word
|
|
38
42
|
# name as a symbol (`core`/`generic`/`supporting` all fill
|
|
39
|
-
# `classification`), or (b) the
|
|
43
|
+
# `classification`), or (b) the only Keyword row filling its
|
|
40
44
|
# own `fills:` target — a bare marker, stores literal `true`
|
|
41
45
|
# (`ReadModel#count`)
|
|
42
46
|
# - an OPENS_BLOCK word named in `SAFE_OPENS_BLOCK` below,
|
|
43
|
-
# verified to do
|
|
47
|
+
# verified to do nothing beyond "build the child, instance_
|
|
44
48
|
# eval the block against it, append the result" — see that
|
|
45
49
|
# constant's own comment
|
|
46
50
|
# - (slice 2) a single-fill word whose row also names a `blank_
|
|
47
|
-
# message:` — raises that
|
|
51
|
+
# message:` — raises that exact Malformed text if the coerced
|
|
48
52
|
# value is blank, before storing it, matching a real hand-
|
|
49
53
|
# written guard exactly (`Translation#retired`/
|
|
50
54
|
# `TranslationAggregate#drop`, the only two words in the whole
|
|
51
55
|
# grammar with this precise shape — `required: "true"` alone
|
|
52
56
|
# only gates Ruby's own arity, never a present-but-blank
|
|
53
|
-
# value, and most `required: "true"` words do
|
|
57
|
+
# value, and most `required: "true"` words do not raise on
|
|
54
58
|
# blank, so this needed a real per-row signal, not an
|
|
55
59
|
# assumption from `required:` alone)
|
|
56
60
|
#
|
|
57
|
-
#
|
|
61
|
+
# ## What stays hand-written
|
|
62
|
+
#
|
|
63
|
+
# Explicitly out of this slice (found live, during the audit, not
|
|
58
64
|
# assumed) — stays hand-written, unaffected, until a later slice's
|
|
59
65
|
# own new table columns (`gated_by:`/`calls:`) can name
|
|
60
66
|
# what it really does: variadic accumulation with a real transform
|
|
61
67
|
# (`attaches_to`); source-block extraction (`ensures`, `where`);
|
|
62
68
|
# Struct/Hash-wrapping (`limit`, `group_by`, `rekey`); a guard
|
|
63
|
-
# clause
|
|
64
|
-
# if
|
|
69
|
+
# clause not reducible to a plain blank-check (`role`'s own "raise
|
|
70
|
+
# if already set" uniqueness gate — a genuinely different shape
|
|
65
71
|
# from `retired`/`drop`'s own blank-check, needing its own
|
|
66
|
-
# design); a dynamically-
|
|
72
|
+
# design); a dynamically-built refusal message rather than one
|
|
67
73
|
# fixed string (`TranslationAggregateBuilder#unresolved` — real
|
|
68
74
|
# branching logic choosing between several message shapes, not a
|
|
69
75
|
# simple "always refuses" flag; belongs with `calls:`, slice 4,
|
|
@@ -74,7 +80,7 @@ module Hecks
|
|
|
74
80
|
# `Bluebook#aggregate`, `Translation#aggregate`) or doing anything
|
|
75
81
|
# beyond a bare fold after building (`Aggregate#policy`'s stamp,
|
|
76
82
|
# `Aggregate#value_object`'s flatten, `Hecksagon#port`'s resolver-
|
|
77
|
-
# swap-and-branch); the
|
|
83
|
+
# swap-and-branch); the deferred-build queue pattern (`Aggregate`/
|
|
78
84
|
# `Entity`'s own `command`/`entity`/`query`); the shadow_parsing?-
|
|
79
85
|
# gated words (`has_many`/`has_one`/`belongs_to`/`then_set`/
|
|
80
86
|
# `trigger`/`dispatch`/`one_of` — each delegates to its own
|
|
@@ -84,18 +90,20 @@ module Hecks
|
|
|
84
90
|
# `File`-context word (routes through `Runtime.current_registry`,
|
|
85
91
|
# a side effect this module has no business performing).
|
|
86
92
|
#
|
|
87
|
-
#
|
|
93
|
+
# ## Words that look table-safe and are not
|
|
94
|
+
#
|
|
95
|
+
# Two further, different reasons a word can look table-safe and
|
|
88
96
|
# still be excluded, both found live rather than assumed:
|
|
89
|
-
# -
|
|
97
|
+
# - Bootstrap reachability. `WordGate`'s own gate steps aside
|
|
90
98
|
# entirely while `MetaValidator.bootstrapping?` (the meta-
|
|
91
99
|
# domain's own circularity — its grammar table doesn't exist
|
|
92
|
-
# yet to read), and `load_grammar_into` loads
|
|
93
|
-
# `.adapter` files, plus every core `.bluebook` chapter,
|
|
100
|
+
# yet to read), and `load_grammar_into` loads real `.port`/
|
|
101
|
+
# `.adapter` files, plus every core `.bluebook` chapter, during
|
|
94
102
|
# that exact window. Any word those files actually call (found
|
|
95
103
|
# to be nearly every common one — `vision`/`core`/`generic`/
|
|
96
104
|
# `supporting`/`description`/`goal`/`emits`/`role`/`identified_
|
|
97
105
|
# by` describe literally every self-hosted aggregate/command)
|
|
98
|
-
# has
|
|
106
|
+
# has no working method to fall back on if its hand-written
|
|
99
107
|
# `def` is removed — `super` from `WordGate#method_missing`
|
|
100
108
|
# just raises `NoMethodError`. `PortBuilder`/`AdapterBuilder`/
|
|
101
109
|
# `BluebookBuilder` turned out to be entirely off-limits to
|
|
@@ -103,13 +111,13 @@ module Hecks
|
|
|
103
111
|
# booting `MetaValidator.grammar_registry` after each
|
|
104
112
|
# candidate removal, not assumed safe from reading the table
|
|
105
113
|
# alone.
|
|
106
|
-
# - A
|
|
107
|
-
# and `HecksagonBuilder` each define their
|
|
114
|
+
# - A conflicting hand-written `method_missing`. `WorldBuilder`
|
|
115
|
+
# and `HecksagonBuilder` each define their own `method_missing`
|
|
108
116
|
# directly on the class (for genuinely open-ended settings/
|
|
109
117
|
# collector verbs) — a method defined directly on a class always
|
|
110
118
|
# wins over one from an included module in Ruby's own method
|
|
111
119
|
# resolution, so `WordGate`'s (and this module's) own
|
|
112
|
-
# `method_missing` never runs for
|
|
120
|
+
# `method_missing` never runs for their builders at all. Their
|
|
113
121
|
# own candidate words (`realm`/`latest`, `subscribe`) stay
|
|
114
122
|
# hand-written for this structural reason, independent of
|
|
115
123
|
# whether their own behavior would otherwise qualify.
|
|
@@ -119,10 +127,10 @@ module Hecks
|
|
|
119
127
|
COERCE_BY_KIND = { "text" => :to_s, "symbol" => :to_sym }.freeze
|
|
120
128
|
|
|
121
129
|
# (context, word) OPENS_BLOCK pairs verified, by reading every
|
|
122
|
-
# real Ruby method, to do
|
|
130
|
+
# real Ruby method, to do nothing beyond building the child and
|
|
123
131
|
# appending it — see this file's own header for the full account
|
|
124
132
|
# of what was excluded and why. Value: the ivar the built child
|
|
125
|
-
# is appended into.
|
|
133
|
+
# is appended into. Not derivable from `fills:` — every one of
|
|
126
134
|
# these Keyword rows carries `fills: ""`; the append target is
|
|
127
135
|
# implicit in the hand-written code today, never named by the
|
|
128
136
|
# table at all, so this is the one place slice 1 hand-names a
|
|
@@ -134,122 +142,72 @@ module Hecks
|
|
|
134
142
|
%w[Bluebook read_model] => :read_models
|
|
135
143
|
}.freeze
|
|
136
144
|
|
|
137
|
-
# `WordGate#method_missing`'s
|
|
138
|
-
# consulted
|
|
145
|
+
# `WordGate#method_missing`'s own bootstrap-window fallback,
|
|
146
|
+
# consulted only while `MetaValidator.bootstrapping?` (the real
|
|
139
147
|
# table doesn't exist yet to read `keyword[:calls]` from). Names
|
|
140
|
-
# the
|
|
141
|
-
# `calls:` column carries
|
|
142
|
-
#
|
|
143
|
-
#
|
|
144
|
-
#
|
|
145
|
-
#
|
|
146
|
-
#
|
|
147
|
-
#
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
%w[Query attribute] => :attribute_impl,
|
|
154
|
-
%w[PortOperation attribute] => :attribute_impl,
|
|
155
|
-
%w[Command role] => :role_impl,
|
|
156
|
-
# given/invariant/reference_to — slice 4b. Each is a SEPARATE
|
|
157
|
-
# per-builder implementation (not a shared mixin like
|
|
158
|
-
# attribute_impl), so every (context, word) pair below names
|
|
159
|
-
# its OWN builder's own method, even where several share a
|
|
160
|
-
# name.
|
|
161
|
-
%w[Aggregate given] => :given_impl,
|
|
162
|
-
%w[Entity given] => :given_impl,
|
|
163
|
-
%w[Command given] => :given_impl,
|
|
164
|
-
%w[Aggregate invariant] => :invariant_impl,
|
|
165
|
-
%w[Entity invariant] => :invariant_impl,
|
|
166
|
-
%w[ValueObject invariant] => :invariant_impl,
|
|
167
|
-
%w[Aggregate reference_to] => :reference_to_impl,
|
|
168
|
-
%w[Entity reference_to] => :reference_to_impl,
|
|
169
|
-
%w[Command reference_to] => :reference_to_impl,
|
|
170
|
-
%w[Query reference_to] => :reference_to_impl,
|
|
171
|
-
%w[ReadModel reference_to] => :reference_to_impl,
|
|
172
|
-
%w[PortOperation reference_to] => :reference_to_impl,
|
|
173
|
-
# `belongs_to` — genuinely NEW bootstrap-reachability, post-dating
|
|
174
|
-
# the "not bootstrap-reachable" determination above: has_many/
|
|
175
|
-
# has_one/belongs_to were retired everywhere when that check was
|
|
176
|
-
# made, so nothing core/attached used one to describe itself.
|
|
177
|
-
# Wave 6 (identity-and-relationships arc) un-deprecates all three
|
|
178
|
-
# for real, and syntax.bluebook's own Bluebook.Declare relationship
|
|
179
|
-
# (`belongs_to Bluebook`) now uses one describing itself — checked
|
|
180
|
-
# directly (only `belongs_to`, not `has_many`/`has_one`, is
|
|
181
|
-
# actually used this way by any core/attached chapter today).
|
|
182
|
-
%w[Aggregate belongs_to] => :belongs_to_impl,
|
|
183
|
-
# slice 4c — the remaining hand-written words a fresh survey
|
|
184
|
-
# found still un-migrated across every builder. Each checked
|
|
185
|
-
# for bootstrap-reachability individually (grepped directly
|
|
186
|
-
# against every core/attached chapter, not assumed); only the
|
|
187
|
-
# ones below actually are.
|
|
188
|
-
%w[Bluebook aggregate] => :aggregate_impl,
|
|
189
|
-
%w[Aggregate provenance] => :provenance_impl,
|
|
190
|
-
%w[Aggregate identified_by] => :identified_by_impl,
|
|
191
|
-
%w[Aggregate lifecycle] => :lifecycle_impl,
|
|
192
|
-
%w[Aggregate entity] => :entity_impl,
|
|
193
|
-
%w[Aggregate query] => :query_impl,
|
|
194
|
-
%w[Aggregate policy] => :policy_impl,
|
|
195
|
-
%w[Aggregate command] => :command_impl,
|
|
196
|
-
%w[Aggregate projects] => :projects_impl,
|
|
197
|
-
%w[Entity identified_by] => :identified_by_impl,
|
|
198
|
-
%w[Entity command] => :command_impl,
|
|
199
|
-
%w[Entity query] => :query_impl,
|
|
200
|
-
%w[Entity lifecycle] => :lifecycle_impl,
|
|
201
|
-
%w[Command provenance] => :provenance_impl,
|
|
202
|
-
%w[Command sets] => :sets_impl,
|
|
203
|
-
%w[Lifecycle transition] => :transition_impl,
|
|
204
|
-
%w[ReadModel where] => :where_impl,
|
|
205
|
-
%w[ReadModel order_by] => :order_by_impl,
|
|
206
|
-
%w[ReadModel include] => :include_impl,
|
|
207
|
-
%w[Query where] => :where_impl,
|
|
208
|
-
%w[Query order_by] => :order_by_impl,
|
|
209
|
-
%w[Entity entity] => :entity_impl,
|
|
210
|
-
%w[ValueObject member] => :member_impl,
|
|
211
|
-
# slice 5. `port`/`realm`/`latest` — real, closed-set words
|
|
212
|
-
# that sat unreachable behind Hecksagon/World's own class-level
|
|
213
|
-
# `method_missing` (see WordGate#word_gate_dispatch's own
|
|
214
|
-
# header), not bootstrap circularity as such, but the SAME
|
|
215
|
-
# fallback table serves them: this hash is looked up before
|
|
216
|
-
# `word_gate_dispatch` even runs, keyed by whichever context
|
|
217
|
-
# the caller's own class reports.
|
|
218
|
-
%w[Hecksagon port] => :port_impl,
|
|
219
|
-
%w[World realm] => :realm_impl,
|
|
220
|
-
%w[World latest] => :latest_impl,
|
|
221
|
-
# `["Type", word]` — ONE entry each covers `list_of`/`one_of`
|
|
222
|
-
# for EVERY calling context (Aggregate/Entity/Command/Query/
|
|
223
|
-
# PortOperation/ValueObject all use them in an attribute's own
|
|
224
|
-
# type position, and `self.class::GRAMMAR_CONTEXT` can never
|
|
225
|
-
# actually equal "Type" — see `word_gate_dispatch`'s own
|
|
226
|
-
# header). The bootstrap branch checks this key directly, the
|
|
227
|
-
# same way the ordinary `word_gate_dispatch` path's own
|
|
228
|
-
# "Type"-context fallback does.
|
|
229
|
-
%w[Type list_of] => :list_of_impl,
|
|
230
|
-
%w[Type one_of] => :one_of_impl
|
|
231
|
-
}.freeze
|
|
148
|
+
# the same (context, word) -> method pairs the real table's own
|
|
149
|
+
# `calls:` column carries — every live row, projected ahead of
|
|
150
|
+
# time into the committed lib/hecks/bluebook/dsl/bootstrap_table.rb
|
|
151
|
+
# (bin/project_bootstrap_table, pinned by spec/bootstrap_table_spec.rb).
|
|
152
|
+
#
|
|
153
|
+
# Every row is carried, rather than a hand-kept subset checked for
|
|
154
|
+
# bootstrap-reachability by grepping the core chapters. Carrying
|
|
155
|
+
# all of them costs nothing: a builder with its own `def` never
|
|
156
|
+
# reaches `method_missing`, and one without gains the same dispatch
|
|
157
|
+
# it gets once bootstrapping ends. `["Type", word]` rows still cover
|
|
158
|
+
# `list_of`/`one_of` in an attribute's type position for every
|
|
159
|
+
# calling context (see `word_gate_dispatch`'s own header).
|
|
160
|
+
BOOTSTRAP_CALLS_FALLBACK = BootstrapTable::CALLS
|
|
232
161
|
|
|
233
162
|
module_function
|
|
234
163
|
|
|
235
|
-
#
|
|
236
|
-
#
|
|
164
|
+
# Reports whether `try` would execute a (context, word) pair, without executing anything.
|
|
165
|
+
#
|
|
166
|
+
# **The static predicate** — does this (context, word) pair fall
|
|
167
|
+
# within this slice's own verified scope, without executing
|
|
237
168
|
# anything? The same row-shape checks `try` itself runs before
|
|
238
169
|
# ever touching a real argument, shared so a conformance spec
|
|
239
170
|
# (which has no real call, no real builder instance) can ask the
|
|
240
|
-
#
|
|
171
|
+
# same question `method_missing` answers live.
|
|
172
|
+
#
|
|
173
|
+
# @param context [String] the grammar context, a builder's `GRAMMAR_CONTEXT` such as
|
|
174
|
+
# `"Aggregate"`, or `"Type"`
|
|
175
|
+
# @param word [String] the DSL word; a Symbol never matches a row
|
|
176
|
+
# @param rows [Hash{Symbol => Array<Hash{Symbol => String}>}] the grammar table, with
|
|
177
|
+
# `:keywords` and `:arguments` row lists; defaults to the live self-hosted table
|
|
178
|
+
# @return [Boolean] true when `try` would execute the word rather than answer `NOT_HANDLED`
|
|
241
179
|
def handles?(context, word, rows: MetaValidator::SyntaxBoot.call)
|
|
242
180
|
!shape_for(context, word, rows).nil?
|
|
243
181
|
end
|
|
244
182
|
|
|
183
|
+
# Executes a grammar-admitted word straight off the table when its row shape is one of
|
|
184
|
+
# the four verified safe ones.
|
|
185
|
+
#
|
|
245
186
|
# `NOT_HANDLED` for anything outside this slice's own verified
|
|
246
187
|
# scope — the caller (`WordGate#method_missing`) falls through
|
|
247
|
-
# to its own existing "not yet implemented" refusal,
|
|
188
|
+
# to its own existing "not yet implemented" refusal, unchanged,
|
|
248
189
|
# the exact same message a word not yet migrated to any slice
|
|
249
190
|
# already gets today. A real `ArgumentError` — matching what a
|
|
250
191
|
# hand-written method of the same arity would raise — for a
|
|
251
|
-
# call whose
|
|
192
|
+
# call whose shape the grammar admits but whose actual argument
|
|
252
193
|
# count doesn't match; never a silent wrong answer.
|
|
194
|
+
#
|
|
195
|
+
# @param builder [Bluebook::DSL::WordGate] the builder instance the word was called on
|
|
196
|
+
# @param context [String] the grammar context the word was admitted under
|
|
197
|
+
# @param word [String] the DSL word being executed
|
|
198
|
+
# @param args [Array<Object>] the call's positional arguments
|
|
199
|
+
# @param kwargs [Hash{Symbol => Object}] the call's keyword arguments
|
|
200
|
+
# @param block [Proc, nil] the block given to the word, if any
|
|
201
|
+
# @param rows [Hash{Symbol => Array<Hash{Symbol => String}>}] the grammar table, with
|
|
202
|
+
# `:keywords` and `:arguments` row lists
|
|
203
|
+
# @return [Object] what executing the word produced — the target method's own result
|
|
204
|
+
# for a `calls:` row, otherwise the stored value or the list appended to — or
|
|
205
|
+
# `NOT_HANDLED` when the word is outside the verified scope
|
|
206
|
+
# @raise [ArgumentError] if the word is table-executed and the positional argument count
|
|
207
|
+
# does not match what its row admits
|
|
208
|
+
# @raise [Bluebook::DSL::Malformed] if a single-fill row names a `blank_message:` and the
|
|
209
|
+
# value is blank, or the `calls:` target itself refuses the declaration
|
|
210
|
+
# @raise [Runtime::WiringError] if `shape_for` names a kind this method has no arm for
|
|
253
211
|
def try(builder, context, word, args, kwargs, block, rows)
|
|
254
212
|
shape = shape_for(context, word, rows)
|
|
255
213
|
return NOT_HANDLED unless shape
|
|
@@ -274,7 +232,9 @@ module Hecks
|
|
|
274
232
|
end
|
|
275
233
|
end
|
|
276
234
|
|
|
277
|
-
#
|
|
235
|
+
# Classifies a (context, word) pair into the table-executable shape its rows describe.
|
|
236
|
+
#
|
|
237
|
+
# The one place row shape is judged — returns a small Hash naming
|
|
278
238
|
# which of the four safe shapes (context, word) is, or `nil` if
|
|
279
239
|
# it falls outside this slice's own verified scope. No argument
|
|
280
240
|
# values are read here; this only ever looks at the table.
|
|
@@ -284,6 +244,14 @@ module Hecks
|
|
|
284
244
|
# checks before it. Splitting per shape would mean re-deriving or
|
|
285
245
|
# threading those locals across method boundaries for a
|
|
286
246
|
# classification that is only ever read top-to-bottom once, here.
|
|
247
|
+
#
|
|
248
|
+
# @param context [String] the grammar context to look the word up under
|
|
249
|
+
# @param word [String] the DSL word; retired rows never match
|
|
250
|
+
# @param rows [Hash{Symbol => Array<Hash{Symbol => String}>}] the grammar table, with
|
|
251
|
+
# `:keywords` and `:arguments` row lists
|
|
252
|
+
# @return [Hash{Symbol => Object}, nil] `:kind` is `:calls_through` (with `:calls`, the
|
|
253
|
+
# target method name), `:opens_block` or `:zero_arg` (with `:keyword`, the row), or
|
|
254
|
+
# `:single_fill` (with `:fills` and `:argument`); nil when the word is out of scope
|
|
287
255
|
# rubocop:disable-next Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
288
256
|
def shape_for(context, word, rows)
|
|
289
257
|
keyword = rows[:keywords].find { |k| k[:context] == context && k[:word] == word && k[:status] != "retired" }
|
|
@@ -309,19 +277,44 @@ module Hecks
|
|
|
309
277
|
{ kind: :single_fill, fills: fills, argument: arg }
|
|
310
278
|
end
|
|
311
279
|
|
|
280
|
+
# Forwards a word's whole call to the builder method its row's `calls:` column names.
|
|
281
|
+
#
|
|
312
282
|
# `keyword[:calls]` names a real Ruby method whose whole call —
|
|
313
283
|
# every positional, every kwarg, the block, all of it — forwards
|
|
314
|
-
# here
|
|
284
|
+
# here unchanged. No argument-shape interpretation at all,
|
|
315
285
|
# deliberately: the target method (`AttributeCollector#
|
|
316
286
|
# attribute_impl`, etc.) already does its own, real, hand-
|
|
317
287
|
# written argument handling; this is a pure, transparent `send`,
|
|
318
288
|
# the lowest-risk possible shape for a word whose own logic is
|
|
319
289
|
# too complex to re-derive from the table (type-quoting refusal,
|
|
320
290
|
# closed-set synthesis, pattern validation, ...).
|
|
291
|
+
#
|
|
292
|
+
# @param builder [Bluebook::DSL::WordGate] the builder instance to send the call to
|
|
293
|
+
# @param calls [String, Symbol] the target method's name, such as `"attribute_impl"`
|
|
294
|
+
# @param args [Array<Object>] positional arguments, forwarded unchanged
|
|
295
|
+
# @param kwargs [Hash{Symbol => Object}] keyword arguments, forwarded unchanged
|
|
296
|
+
# @param block [Proc, nil] the block, forwarded unchanged
|
|
297
|
+
# @return [Object] whatever the target method returns
|
|
298
|
+
# @raise [Bluebook::DSL::Malformed] if the target method refuses the declaration
|
|
321
299
|
def try_calls_through(builder, calls, args, kwargs, block)
|
|
322
300
|
builder.send(calls, *args, **kwargs, &block)
|
|
323
301
|
end
|
|
324
302
|
|
|
303
|
+
# Builds a child construct from a block-opening word and appends it to the builder's list.
|
|
304
|
+
#
|
|
305
|
+
# @param builder [Bluebook::DSL::WordGate] the builder whose list receives the child
|
|
306
|
+
# @param keyword [Hash{Symbol => String}] the word's Keyword row; `:opens` names the
|
|
307
|
+
# child builder class without its `Builder` suffix, and the pair of `:context` and
|
|
308
|
+
# `:word` must be a `SAFE_OPENS_BLOCK` key
|
|
309
|
+
# @param args [Array<Object>] the call's positional arguments; exactly one, the child's
|
|
310
|
+
# name
|
|
311
|
+
# @param kwargs [Hash{Symbol => Object}] the call's keyword arguments
|
|
312
|
+
# @param block [Proc, nil] the child's body, evaluated against the child builder
|
|
313
|
+
# @return [Array<Object>, Object] the builder's list with the built child appended, or
|
|
314
|
+
# `NOT_HANDLED` when any keyword argument was given
|
|
315
|
+
# @raise [ArgumentError] if the call does not carry exactly one positional argument
|
|
316
|
+
# @raise [KeyError] if the row's context and word are not in `SAFE_OPENS_BLOCK`
|
|
317
|
+
# @raise [Bluebook::DSL::Malformed] if the child builder refuses its own body
|
|
325
318
|
def try_opens_block(builder, keyword, args, kwargs, block)
|
|
326
319
|
return NOT_HANDLED unless kwargs.empty?
|
|
327
320
|
|
|
@@ -337,6 +330,15 @@ module Hecks
|
|
|
337
330
|
list << child
|
|
338
331
|
end
|
|
339
332
|
|
|
333
|
+
# Stores a zero-argument word's value into the instance variable its row's `fills:` names.
|
|
334
|
+
#
|
|
335
|
+
# @param builder [Bluebook::DSL::WordGate] the builder whose instance variable is set
|
|
336
|
+
# @param keyword [Hash{Symbol => String}] the word's Keyword row, read for `:context`,
|
|
337
|
+
# `:fills` and `:word`
|
|
338
|
+
# @param args [Array<Object>] the call's positional arguments, which must be empty
|
|
339
|
+
# @return [Symbol, true] the stored value: the word itself as a Symbol when sibling words
|
|
340
|
+
# share the same `fills:` target (`core`/`generic`/`supporting`), otherwise `true`
|
|
341
|
+
# @raise [ArgumentError] if any positional argument was given
|
|
340
342
|
def try_zero_arg(builder, keyword, args)
|
|
341
343
|
raise ArgumentError, "wrong number of arguments (given #{args.size}, expected 0)" unless args.empty?
|
|
342
344
|
|
|
@@ -349,6 +351,20 @@ module Hecks
|
|
|
349
351
|
builder.instance_variable_set(:"@#{keyword[:fills]}", value)
|
|
350
352
|
end
|
|
351
353
|
|
|
354
|
+
# Coerces a word's one positional argument and stores it, appending when the target
|
|
355
|
+
# instance variable already holds an Array and assigning otherwise.
|
|
356
|
+
#
|
|
357
|
+
# @param builder [Bluebook::DSL::WordGate] the builder whose instance variable is filled
|
|
358
|
+
# @param fills [String] the instance variable's name, without the `@`
|
|
359
|
+
# @param arg [Hash{Symbol => String}] the word's single Argument row, read for `:kind`,
|
|
360
|
+
# `:coerce` and `:blank_message`
|
|
361
|
+
# @param args [Array<Object>] the call's positional arguments; exactly one
|
|
362
|
+
# @param kwargs [Hash{Symbol => Object}] the call's keyword arguments
|
|
363
|
+
# @return [Object] the stored value, or the Array it was appended to, or `NOT_HANDLED`
|
|
364
|
+
# when any keyword argument was given
|
|
365
|
+
# @raise [ArgumentError] if the call does not carry exactly one positional argument
|
|
366
|
+
# @raise [Bluebook::DSL::Malformed] if the row names a `blank_message:` and the coerced
|
|
367
|
+
# value is blank
|
|
352
368
|
def try_single_fill(builder, fills, arg, args, kwargs)
|
|
353
369
|
return NOT_HANDLED unless kwargs.empty?
|
|
354
370
|
|