hecks 2.9.0 → 3.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 +4 -4
- data/exe/hecks +51 -6
- data/lib/hecks/adapters/driven/heki/journal.rb +1 -1
- data/lib/hecks/adapters/driven/lambda/client.rb +1 -1
- data/lib/hecks/adapters/driven/lambda.rb +1 -1
- data/lib/hecks/adapters/driven/memory.rb +16 -3
- data/lib/hecks/adapters/driven/postgres/reconnect.rb +6 -2
- data/lib/hecks/adapters/driven/postgres/shared_connection.rb +180 -0
- data/lib/hecks/adapters/driven/postgres.rb +4 -2
- data/lib/hecks/adapters/driven/prism.rb +41 -8
- data/lib/hecks/adapters/driven/tenant_provisioner.rb +73 -16
- data/lib/hecks/behaviors/expectations.rb +1 -1
- data/lib/hecks/behaviors.rb +1 -1
- data/lib/hecks/bench/cli.rb +62 -0
- data/lib/hecks/bench/environment.rb +71 -0
- data/lib/hecks/bench/postgres_probe.rb +30 -0
- data/lib/hecks/bench/report.rb +76 -0
- data/lib/hecks/bench/ruby_runner.rb +93 -0
- data/lib/hecks/bench/run.rb +55 -0
- data/lib/hecks/bench/rust_runner.rb +101 -0
- data/lib/hecks/bench/stats.rb +46 -0
- data/lib/hecks/bench/suite.rb +98 -0
- data/lib/hecks/bench/workload.rb +89 -0
- data/lib/hecks/bench.rb +17 -0
- data/lib/hecks/bluebook/assembly/contracts.rb +2 -0
- data/lib/hecks/bluebook/attribute.rb +1 -1
- data/lib/hecks/bluebook/behaviour/aggregate.rb +30 -1
- data/lib/hecks/bluebook/behaviour/domain_port.rb +7 -0
- data/lib/hecks/bluebook/chapter.rb +6 -2
- data/lib/hecks/bluebook/domain_port.rb +36 -5
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +10 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder.rb +8 -0
- data/lib/hecks/bluebook/dsl/bootstrap_table.rb +2 -1
- data/lib/hecks/bluebook/dsl/domain_port_builder.rb +31 -3
- data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +122 -3
- data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +1 -1
- data/lib/hecks/bluebook/dsl/query_builder.rb +27 -1
- data/lib/hecks/bluebook/dsl/rule_reference.rb +1 -1
- data/lib/hecks/bluebook/dsl/world_builder.rb +29 -2
- data/lib/hecks/bluebook/expression/canonical_form.rb +1 -1
- data/lib/hecks/bluebook/expression/resolver.rb +3 -2
- data/lib/hecks/bluebook/hexagon.rb +13 -5
- data/lib/hecks/bluebook/meta_validator/reconstruction.rb +1 -0
- data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +4 -1
- data/lib/hecks/bluebook/meta_validator/verdict_cache.rb +246 -0
- data/lib/hecks/bluebook/meta_validator.rb +9 -4
- data/lib/hecks/bluebook/model_check.rb +23 -0
- data/lib/hecks/bluebook/pattern_subset.rb +38 -0
- data/lib/hecks/bluebook/query.rb +20 -5
- data/lib/hecks/bluebook/smoke_test.rb +1 -1
- data/lib/hecks/canonical_json.rb +30 -0
- data/lib/hecks/chapters.rb +102 -0
- data/lib/hecks/cli/behaviors.rb +61 -0
- data/lib/hecks/cli/canonicalise.rb +25 -0
- data/lib/hecks/cli/check_engine_agreement.rb +32 -0
- data/lib/hecks/cli/check_era.rb +88 -0
- data/lib/hecks/cli/console.rb +66 -0
- data/lib/hecks/cli/deploy_template_diff.rb +40 -0
- data/lib/hecks/cli/doc_coverage.rb +32 -0
- data/lib/hecks/cli/document.rb +2 -2
- data/lib/hecks/cli/expression_projection.rb +41 -0
- data/lib/hecks/cli/follow.rb +88 -0
- data/lib/hecks/cli/history.rb +44 -0
- data/lib/hecks/cli/ir.rb +1 -1
- data/lib/hecks/cli/mcp.rb +3 -3
- data/lib/hecks/cli/model_check.rb +7 -4
- data/lib/hecks/cli/pattern_cases.rb +47 -0
- data/lib/hecks/cli/present.rb +39 -0
- data/lib/hecks/cli/project_cli.rb +224 -32
- data/lib/hecks/cli/project_diagrams.rb +4 -3
- data/lib/hecks/cli/project_glossary.rb +44 -0
- data/lib/hecks/cli/reference.rb +46 -0
- data/lib/hecks/cli/refresh_projections.rb +44 -0
- data/lib/hecks/cli/refresh_rspec_runtime_baseline.rb +150 -0
- data/lib/hecks/cli/release.rb +70 -0
- data/lib/hecks/cli/release_gem.rb +59 -0
- data/lib/hecks/cli/rspec_io_parallel_files.rb +137 -0
- data/lib/hecks/cli/rspec_shard_files.rb +66 -0
- data/lib/hecks/cli/run.rb +3 -3
- data/lib/hecks/cli/seed_semantics_corpus.rb +71 -0
- data/lib/hecks/cli/serve_query_ir_mcp.rb +30 -0
- data/lib/hecks/cli/shape.rb +70 -0
- data/lib/hecks/cli/smoke_http.rb +230 -0
- data/lib/hecks/cli/smoke_test.rb +5 -3
- data/lib/hecks/cli/spec_example.rb +27 -0
- data/lib/hecks/cli/statements.rb +32 -0
- data/lib/hecks/cli/stores.rb +4 -5
- data/lib/hecks/cli/stress_concurrency_specs.rb +177 -0
- data/lib/hecks/cli.rb +201 -52
- data/lib/hecks/codemod.rb +324 -0
- data/lib/hecks/corpus.rb +423 -0
- data/lib/hecks/deploy/bluebook/deploy.bluebook +591 -23
- data/lib/hecks/deploy/bluebook/deploy.hecksagon +41 -4
- data/lib/hecks/deploy/oidc.json +82 -2
- data/lib/hecks/doc/reference.rb +351 -0
- data/lib/hecks/doors/cli_door.rb +196 -0
- data/lib/hecks/doors/cli_runner.rb +297 -0
- data/lib/hecks/{facade → doors}/command_request.rb +1 -1
- data/lib/hecks/{facade → doors}/handle.rb +2 -2
- data/lib/hecks/{facade → doors}/json_door.rb +4 -4
- data/lib/hecks/doors/launcher_options.rb +129 -0
- data/lib/hecks/{cli → doors}/mcp_door.rb +7 -7
- data/lib/hecks/doors/mcp_door_scope.rb +97 -0
- data/lib/hecks/{facade/surface → doors/ruby_door}/aggregate_door.rb +8 -3
- data/lib/hecks/{facade/surface → doors/ruby_door}/chapter.rb +3 -3
- data/lib/hecks/{facade/surface.rb → doors/ruby_door.rb} +36 -5
- data/lib/hecks/doors.rb +61 -0
- data/lib/hecks/embryonaut_bluebook/vendor_cli.rb +1 -1
- data/lib/hecks/embryonaut_bluebook.rb +1 -1
- data/lib/hecks/engine_agreement.rb +156 -0
- data/lib/hecks/facade.rb +24 -37
- data/lib/hecks/forms/app.rb +6 -6
- data/lib/hecks/forms/banking_presentation.rb +50 -0
- data/lib/hecks/forms/field_shape.rb +2 -1
- data/lib/hecks/forms/port_argument.rb +1 -1
- data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +393 -0
- data/lib/hecks/fuzzing/combination_miner.rb +86 -0
- data/lib/hecks/fuzzing/concurrent_dispatch.rb +214 -0
- data/lib/hecks/fuzzing/coverage_campaign.rb +143 -0
- data/lib/hecks/fuzzing/differential.rb +156 -0
- data/lib/hecks/fuzzing/domain_generator.rb +615 -0
- data/lib/hecks/fuzzing/era_boundary.rb +71 -0
- data/lib/hecks/fuzzing/form_census.rb +136 -0
- data/lib/hecks/fuzzing/generated_domain_check.rb +93 -0
- data/lib/hecks/fuzzing/invalid_value_generator.rb +64 -0
- data/lib/hecks/fuzzing/isolated_boot.rb +301 -0
- data/lib/hecks/fuzzing/nondeterministic.rb +51 -0
- data/lib/hecks/fuzzing/outside_world.rb +45 -0
- data/lib/hecks/fuzzing/persistence_parity.rb +102 -0
- data/lib/hecks/fuzzing/properties/corrections.rb +88 -0
- data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +314 -0
- data/lib/hecks/fuzzing/properties/guards.rb +190 -0
- data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +300 -0
- data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +93 -0
- data/lib/hecks/fuzzing/properties/outbox.rb +89 -0
- data/lib/hecks/fuzzing/properties/querying.rb +175 -0
- data/lib/hecks/fuzzing/properties.rb +162 -0
- data/lib/hecks/fuzzing/qa_settings.rb +123 -0
- data/lib/hecks/fuzzing/replay.rb +505 -0
- data/lib/hecks/fuzzing/rotation_priority.rb +48 -0
- data/lib/hecks/fuzzing/rust_gap_manifest.rb +108 -0
- data/lib/hecks/fuzzing/self_consistency.rb +339 -0
- data/lib/hecks/fuzzing/sequence_generator/adversary.rb +385 -0
- data/lib/hecks/fuzzing/sequence_generator/catalog.rb +132 -0
- data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +95 -0
- data/lib/hecks/fuzzing/sequence_generator/picker.rb +77 -0
- data/lib/hecks/fuzzing/sequence_generator/query_binding.rb +109 -0
- data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +237 -0
- data/lib/hecks/fuzzing/sequence_generator.rb +189 -0
- data/lib/hecks/fuzzing/shrinker.rb +166 -0
- data/lib/hecks/fuzzing/structural_skips.rb +33 -0
- data/lib/hecks/fuzzing/sweep_depth.rb +43 -0
- data/lib/hecks/fuzzing/target_capabilities.rb +163 -0
- data/lib/hecks/fuzzing/value_generator.rb +216 -0
- data/lib/hecks/fuzzing.rb +23 -0
- data/lib/hecks/grammar/evolve.rb +336 -0
- data/lib/hecks/hecks/adapters/codebase/codemods.rb +45 -0
- data/lib/hecks/hecks/adapters/codebase/conformance.rb +71 -0
- data/lib/hecks/hecks/adapters/codebase/corpus_tasks.rb +202 -0
- data/lib/hecks/hecks/adapters/codebase/gem_registry.rb +80 -0
- data/lib/hecks/hecks/adapters/codebase/kernel_tables.rb +54 -0
- data/lib/hecks/hecks/adapters/codebase/language.rb +240 -0
- data/lib/hecks/hecks/adapters/codebase/npm_registry.rb +102 -0
- data/lib/hecks/hecks/adapters/codebase/publishing.rb +142 -0
- data/lib/hecks/hecks/adapters/codebase/regeneration.rb +67 -0
- data/lib/hecks/hecks/adapters/codebase/release_facts.rb +90 -0
- data/lib/hecks/hecks/adapters/codebase/ruby_child.rb +83 -0
- data/lib/hecks/hecks/adapters/codebase/secret_vault.rb +36 -0
- data/lib/hecks/hecks/adapters/codebase/source_tree.adapter +7 -0
- data/lib/hecks/hecks/adapters/codebase/source_tree.rb +189 -0
- data/lib/hecks/hecks/adapters/codebase/sqlite_fixture.rb +71 -0
- data/lib/hecks/hecks/adapters/codebase/style.rb +171 -0
- data/lib/hecks/hecks/adapters/codebase/test_runner.rb +55 -0
- data/lib/hecks/hecks/adapters/codebase/test_suite.rb +165 -0
- data/lib/hecks/hecks/adapters/codebase/tree.rb +111 -0
- data/lib/hecks/hecks/adapters/console_capture.rb +79 -0
- data/lib/hecks/hecks/adapters/deploy_toolchain.adapter +7 -0
- data/lib/hecks/hecks/adapters/deploy_toolchain.rb +108 -0
- data/lib/hecks/hecks/adapters/git.adapter +7 -0
- data/lib/hecks/hecks/adapters/git.rb +102 -0
- data/lib/hecks/hecks/adapters/host_http.adapter +7 -0
- data/lib/hecks/hecks/adapters/host_http.rb +65 -0
- data/lib/hecks/hecks/adapters/in_process_boot.adapter +7 -0
- data/lib/hecks/hecks/adapters/in_process_boot.rb +197 -0
- data/lib/hecks/hecks/adapters/in_process_operations.rb +202 -0
- data/lib/hecks/hecks/adapters/journal_store/changes.rb +143 -0
- data/lib/hecks/hecks/adapters/journal_store/compaction.rb +145 -0
- data/lib/hecks/hecks/adapters/journal_store/edge_audit.rb +132 -0
- data/lib/hecks/hecks/adapters/journal_store/examination.rb +135 -0
- data/lib/hecks/hecks/adapters/journal_store/held_domain.rb +163 -0
- data/lib/hecks/hecks/adapters/journal_store/readings.rb +187 -0
- data/lib/hecks/hecks/adapters/journal_store.adapter +7 -0
- data/lib/hecks/hecks/adapters/journal_store.rb +64 -0
- data/lib/hecks/hecks/adapters/local_files.adapter +7 -0
- data/lib/hecks/hecks/adapters/local_files.rb +46 -0
- data/lib/hecks/hecks/adapters/pg_admin.adapter +7 -0
- data/lib/hecks/hecks/adapters/pg_admin.rb +245 -0
- data/lib/hecks/hecks/adapters/process_pool.adapter +7 -0
- data/lib/hecks/hecks/adapters/process_pool.rb +119 -0
- data/lib/hecks/hecks/adapters/rust_toolchain.adapter +7 -0
- data/lib/hecks/hecks/adapters/rust_toolchain.rb +179 -0
- data/lib/hecks/hecks/adapters/rust_workspace.rb +150 -0
- data/lib/hecks/hecks/adapters/shell.adapter +7 -0
- data/lib/hecks/hecks/adapters/shell.rb +49 -0
- data/lib/hecks/hecks/adapters/terminal.adapter +7 -0
- data/lib/hecks/hecks/adapters/terminal.rb +74 -0
- data/lib/hecks/hecks/codebase.behaviors +172 -0
- data/lib/hecks/hecks/codebase.bluebook +2453 -0
- data/lib/hecks/hecks/context_map.hecksagon +13 -0
- data/lib/hecks/hecks/custodian.behaviors +179 -0
- data/lib/hecks/hecks/custodian.bluebook +1847 -0
- data/lib/hecks/hecks/deploy.behaviors +74 -0
- data/lib/hecks/hecks/deploy.world +12 -0
- data/lib/hecks/hecks/environments/memory.world +10 -0
- data/lib/hecks/hecks/governance.world +7 -0
- data/lib/hecks/hecks/hecks.behaviors +62 -0
- data/lib/hecks/hecks/hecks.bluebook +124 -0
- data/lib/hecks/hecks/hecks.hecksagon +390 -0
- data/lib/hecks/hecks/hecks.world +42 -0
- data/lib/hecks/kernel_capabilities.rb +194 -0
- data/lib/hecks/language/bluebook/bluebook.bluebook +11 -0
- data/lib/hecks/language/bluebook/query.bluebook +7 -0
- data/lib/hecks/language/bluebook/vocabulary.bluebook +4 -4
- data/lib/hecks/language/hecksagon/domain_port.bluebook +10 -0
- data/lib/hecks/language/hecksagon/hecksagon.bluebook +20 -0
- data/lib/hecks/mcp_stdio_guard.rb +2 -2
- data/lib/hecks/persistence_legacy_fixture/regenerate.rb +161 -0
- data/lib/hecks/persistence_legacy_fixture.rb +113 -0
- data/lib/hecks/ports/persistence/plugins/era/era_check.rb +8 -5
- data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +4 -1
- data/lib/hecks/ports/persistence/plugins/era/expected_era.rb +15 -2
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +1 -1
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +1 -1
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +1 -1
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +32 -15
- data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +6 -3
- data/lib/hecks/ports/persistence/plugins/era/translation/approval_file.rb +227 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +1 -1
- data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +43 -24
- data/lib/hecks/ports/persistence/plugins/era/translation.rb +1 -0
- data/lib/hecks/ports/persistence/state_codec.rb +24 -5
- data/lib/hecks/projection_files.rb +285 -0
- data/lib/hecks/projections/bootstrap_table.rb +1 -1
- data/lib/hecks/projections/deploy/fargate.rb +5 -5
- data/lib/hecks/projections/deploy/lambda.rb +43 -32
- data/lib/hecks/projections/deploy/preview/preview.sh.erb +1 -1
- data/lib/hecks/projections/deploy/preview/template.rb +1 -1
- data/lib/hecks/projections/deploy/scripts/deploy-service.sh.tmpl +1 -1
- data/lib/hecks/projections/deploy/scripts/expected-era.header +1 -1
- data/lib/hecks/projections/deploy/scripts/hosting.mk.tmpl +3 -3
- data/lib/hecks/projections/deploy/scripts/smoke-after-deploy.sh.tmpl +1 -1
- data/lib/hecks/projections/deploy/shared.rb +1 -1
- data/lib/hecks/projections/diagrams.rb +3 -3
- data/lib/hecks/projections/model/deviations.rb +1 -1
- data/lib/hecks/projections/parser_table.rb +4 -4
- data/lib/hecks/projections/reference.rb +2 -3
- data/lib/hecks/projections/rust_vocabulary.rb +1 -1
- data/lib/hecks/projector/cli_projector.rb +106 -37
- data/lib/hecks/projector.rb +1 -1
- data/lib/hecks/quality_control/adapters/agent.adapter +7 -0
- data/lib/hecks/quality_control/adapters/agent.rb +58 -0
- data/lib/hecks/quality_control/adapters/angle_tools.adapter +7 -0
- data/lib/hecks/quality_control/adapters/angle_tools.rb +15 -0
- data/lib/hecks/quality_control/adapters/clearance_recorder.rb +36 -0
- data/lib/hecks/quality_control/adapters/clearance_tools.adapter +7 -0
- data/lib/hecks/quality_control/adapters/clearance_tools.rb +17 -0
- data/lib/hecks/quality_control/adapters/git_pr.adapter +7 -0
- data/lib/hecks/quality_control/adapters/git_pr.rb +226 -0
- data/lib/hecks/quality_control/adapters/github_checks.adapter +9 -0
- data/lib/hecks/quality_control/adapters/github_checks.rb +83 -0
- data/lib/hecks/quality_control/adapters/github_ci_webhook.rb +56 -0
- data/lib/hecks/quality_control/adapters/github_issues.adapter +7 -0
- data/lib/hecks/quality_control/adapters/github_issues.rb +49 -0
- data/lib/hecks/quality_control/adapters/qa_tool.rb +59 -0
- data/lib/hecks/quality_control/adapters/sweep_tools.adapter +7 -0
- data/lib/hecks/quality_control/adapters/sweep_tools.rb +51 -0
- data/lib/hecks/quality_control/adapters/target_tools.adapter +7 -0
- data/lib/hecks/quality_control/adapters/target_tools.rb +43 -0
- data/lib/hecks/quality_control/cli/child.rb +45 -0
- data/lib/hecks/quality_control/cli/qa_concurrency_racer.rb +45 -0
- data/lib/hecks/quality_control/cli/qa_discover_external_domains.rb +248 -0
- data/lib/hecks/quality_control/cli/qa_domain_novelty.rb +163 -0
- data/lib/hecks/quality_control/cli/qa_generated_domains.rb +450 -0
- data/lib/hecks/quality_control/cli/qa_log_bug.rb +195 -0
- data/lib/hecks/quality_control/cli/qa_mine_combinations.rb +220 -0
- data/lib/hecks/quality_control/cli/qa_open_pr.rb +305 -0
- data/lib/hecks/quality_control/cli/qa_postgres_migrate.rb +154 -0
- data/lib/hecks/quality_control/cli/qa_postgres_role.rb +159 -0
- data/lib/hecks/quality_control/cli/qa_pr_check.rb +232 -0
- data/lib/hecks/quality_control/cli/qa_seed_angles.rb +142 -0
- data/lib/hecks/quality_control/cli/qa_seed_targets.rb +69 -0
- data/lib/hecks/quality_control/cli/qa_sweep/all_mode.rb +280 -0
- data/lib/hecks/quality_control/cli/qa_sweep/checks.rb +329 -0
- data/lib/hecks/quality_control/cli/qa_sweep/dials.rb +92 -0
- data/lib/hecks/quality_control/cli/qa_sweep/finding_report.rb +117 -0
- data/lib/hecks/quality_control/cli/qa_sweep/parsing.rb +175 -0
- data/lib/hecks/quality_control/cli/qa_sweep/release_mode.rb +60 -0
- data/lib/hecks/quality_control/cli/qa_sweep.rb +611 -0
- data/lib/hecks/quality_control/cli/qa_tick.rb +274 -0
- data/lib/hecks/quality_control/quality_control.bluebook +2224 -0
- data/lib/hecks/quality_control/quality_control.hecksagon +13 -0
- data/lib/hecks/quality_control/quality_control.ports.hecksagon +54 -0
- data/lib/hecks/query_ir.rb +346 -0
- data/lib/hecks/query_ir_mcp.rb +198 -0
- data/lib/hecks/release/runner/ci_publisher.rb +2 -2
- data/lib/hecks/release/runner/clean_tree.rb +42 -0
- data/lib/hecks/release/runner/console.rb +6 -0
- data/lib/hecks/release/runner/gem_publisher.rb +14 -7
- data/lib/hecks/release/runner/npm_publisher.rb +6 -36
- data/lib/hecks/release/runner/preflight.rb +26 -2
- data/lib/hecks/release/runner/published.rb +8 -26
- data/lib/hecks/release/runner/tagger.rb +30 -15
- data/lib/hecks/release/runner.rb +57 -6
- data/lib/hecks/router/namespace_installer.rb +3 -3
- data/lib/hecks/runtime/adapter_lookup.rb +124 -0
- data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +4 -0
- data/lib/hecks/runtime/dependency_planning.rb +20 -2
- data/lib/hecks/runtime/dispatcher.rb +53 -3
- data/lib/hecks/runtime/interpreting.rb +3 -0
- data/lib/hecks/runtime/loader.rb +65 -12
- data/lib/hecks/runtime/outbox.rb +1 -1
- data/lib/hecks/runtime/policy_interpreter.rb +5 -2
- data/lib/hecks/runtime/port_operation_interpreter.rb +2 -10
- data/lib/hecks/runtime/query_interpreter.rb +77 -0
- data/lib/hecks/runtime/reaction_outcome.rb +89 -0
- data/lib/hecks/runtime/refusal_wording.rb +23 -1
- data/lib/hecks/runtime/registry/verification.rb +163 -4
- data/lib/hecks/runtime/registry.rb +57 -3
- data/lib/hecks/runtime/remote_dispatcher.rb +31 -2
- data/lib/hecks/runtime/value/coercion.rb +23 -135
- data/lib/hecks/runtime/value/field_checks.rb +172 -0
- data/lib/hecks/runtime/value.rb +4 -1
- data/lib/hecks/runtime.rb +20 -6
- data/lib/hecks/rust_build/conformance.rb +158 -0
- data/lib/hecks/rust_build/conformance_fuzz.rb +71 -0
- data/lib/hecks/rust_build/coverage.rb +218 -0
- data/lib/hecks/rust_build/native_build.rb +124 -0
- data/lib/hecks/rust_build/project_rust/root_mod.rb +120 -0
- data/lib/hecks/rust_build/project_rust.rb +332 -0
- data/lib/hecks/rust_build/wasm.rb +105 -0
- data/lib/hecks/rust_build/wasm_browser.rb +113 -0
- data/lib/hecks/rust_build.rb +144 -0
- data/lib/hecks/storehouse.rb +16 -16
- data/lib/hecks/tenancy/bluebook/tenancy.bluebook +2 -2
- data/lib/hecks/tenancy/bluebook/tenancy.hecksagon +1 -1
- data/lib/hecks/three_zero/forms.yml +127 -0
- data/lib/hecks/three_zero.rb +12 -0
- data/lib/hecks/tools/argument_gate_matrix.rb +316 -0
- data/lib/hecks/tools/comment_style.rb +1070 -0
- data/lib/hecks/tools/corpus_report.rb +87 -0
- data/lib/hecks/tools/deploy_recipe.rb +255 -0
- data/lib/hecks/tools/deploy_recipe_lint.rb +282 -0
- data/lib/hecks/tools/drop_implicit_append_fields.rb +95 -0
- data/lib/hecks/tools/era_projection_backfill.rb +94 -0
- data/lib/hecks/tools/era_reattest.rb +146 -0
- data/lib/hecks/tools/evolve_run.rb +189 -0
- data/lib/hecks/tools/fuzz_sweep.rb +373 -0
- data/lib/hecks/tools/heki_compaction.rb +100 -0
- data/lib/hecks/tools/hoist_local_givens.rb +246 -0
- data/lib/hecks/tools/journal_compaction.rb +89 -0
- data/lib/hecks/tools/oidc_manifests.rb +70 -0
- data/lib/hecks/tools/query_ir_run.rb +81 -0
- data/lib/hecks/tools/regeneration_run.rb +166 -0
- data/lib/hecks/tools/rust_comment_style.rb +642 -0
- data/lib/hecks/tools/sequence_script.rb +62 -0
- data/lib/hecks/tools/tail_merge.rb +117 -0
- data/lib/hecks/tools/tenant_provisioning.rb +142 -0
- data/lib/hecks/tools/translation_audit.rb +208 -0
- data/lib/hecks/tools/translation_scaffold.rb +131 -0
- data/lib/hecks/tools.rb +86 -0
- data/lib/hecks/version.rb +1 -1
- data/lib/hecks.rb +32 -15
- data/qa/settings.yml +66 -0
- data/rust/.cargo/config.toml +6 -0
- data/rust/.gitignore +2 -0
- data/rust/Cargo.lock +54 -0
- data/rust/Cargo.toml +61 -0
- data/rust/build/.cargo/config.toml +3 -0
- data/rust/build/.gitignore +1 -0
- data/rust/build/Cargo.lock +7 -0
- data/rust/build/Cargo.toml +19 -0
- data/rust/build/src/build_artifact.rs +47 -0
- data/rust/build/src/cargo_sync.rs +248 -0
- data/rust/build/src/json.rs +421 -0
- data/rust/build/src/lineage_pass.rs +285 -0
- data/rust/build/src/main.rs +51 -0
- data/rust/build/src/optional_pass.rs +150 -0
- data/rust/build/src/pipeline.rs +264 -0
- data/rust/build/src/reserved_names.rs +76 -0
- data/rust/build/src/resolve.rs +124 -0
- data/rust/build/src/root.rs +25 -0
- data/rust/build/src/sidecars.rs +73 -0
- data/rust/build/src/subprocess.rs +51 -0
- data/rust/build/src/tmp.rs +31 -0
- data/rust/codegen/.cargo/config.toml +3 -0
- data/rust/codegen/.gitignore +1 -0
- data/rust/codegen/Cargo.lock +7 -0
- data/rust/codegen/Cargo.toml +20 -0
- data/rust/codegen/src/attr.rs +32 -0
- data/rust/codegen/src/bridging.rs +481 -0
- data/rust/codegen/src/commands.rs +1226 -0
- data/rust/codegen/src/constraints.rs +109 -0
- data/rust/codegen/src/dependency_planning.rs +209 -0
- data/rust/codegen/src/domain_generator.rs +1288 -0
- data/rust/codegen/src/exemplar.rs +230 -0
- data/rust/codegen/src/expr_emitter.rs +87 -0
- data/rust/codegen/src/fielded.rs +192 -0
- data/rust/codegen/src/hecks_naming.rs +33 -0
- data/rust/codegen/src/json.rs +335 -0
- data/rust/codegen/src/json_codec.rs +697 -0
- data/rust/codegen/src/literal.rs +207 -0
- data/rust/codegen/src/main.rs +290 -0
- data/rust/codegen/src/manifest.rs +227 -0
- data/rust/codegen/src/mutations.rs +784 -0
- data/rust/codegen/src/naming.rs +286 -0
- data/rust/codegen/src/ports.rs +208 -0
- data/rust/codegen/src/prelude.rs +116 -0
- data/rust/codegen/src/queries.rs +786 -0
- data/rust/codegen/src/reactions.rs +532 -0
- data/rust/codegen/src/read_models.rs +697 -0
- data/rust/codegen/src/reference_specs.rs +40 -0
- data/rust/codegen/src/registry.rs +966 -0
- data/rust/codegen/src/reserved_names.rs +76 -0
- data/rust/codegen/src/shared.rs +93 -0
- data/rust/codegen/src/skip_reason.rs +25 -0
- data/rust/codegen/src/types.rs +362 -0
- data/rust/host/.cargo/config.toml +3 -0
- data/rust/host/.gitignore +1 -0
- data/rust/host/Cargo.lock +4297 -0
- data/rust/host/Cargo.toml +61 -0
- data/rust/host/HECKS_RELEASE +1 -0
- data/rust/host/rds-ca-bundle.pem +2736 -0
- data/rust/host/src/api.rs +1596 -0
- data/rust/host/src/approval.rs +652 -0
- data/rust/host/src/auth.rs +1287 -0
- data/rust/host/src/bin/expr_harness.rs +46 -0
- data/rust/host/src/bin/lineage_harness.rs +119 -0
- data/rust/host/src/bin/mint_harness.rs +135 -0
- data/rust/host/src/checkout.rs +265 -0
- data/rust/host/src/dispatch.rs +1443 -0
- data/rust/host/src/expr_json.rs +1117 -0
- data/rust/host/src/field_hints.rs +52 -0
- data/rust/host/src/ir.rs +733 -0
- data/rust/host/src/journal.rs +874 -0
- data/rust/host/src/lambda_client.rs +378 -0
- data/rust/host/src/log.rs +147 -0
- data/rust/host/src/main.rs +474 -0
- data/rust/host/src/mint.rs +1865 -0
- data/rust/host/src/payments/keystore.rs +330 -0
- data/rust/host/src/payments/tests.rs +1400 -0
- data/rust/host/src/payments.rs +767 -0
- data/rust/host/src/presentation.rs +698 -0
- data/rust/host/src/presentation_write.rs +1431 -0
- data/rust/host/src/query_step.rs +149 -0
- data/rust/host/src/rate_limit.rs +904 -0
- data/rust/host/src/reference_transform.rs +241 -0
- data/rust/host/src/reference_validate.rs +338 -0
- data/rust/host/src/resend.rs +296 -0
- data/rust/host/src/secrets.rs +106 -0
- data/rust/host/src/server.rs +663 -0
- data/rust/host/src/storage_shape.rs +175 -0
- data/rust/host/src/test_pg.rs +40 -0
- data/rust/host/src/ui_schema.rs +1351 -0
- data/rust/host/src/wasm_runner.rs +191 -0
- data/rust/host/src/web/newsletter/cooldown.rs +126 -0
- data/rust/host/src/web/newsletter/tests.rs +104 -0
- data/rust/host/src/web/newsletter.rs +310 -0
- data/rust/host/src/web/newsletter_send.rs +357 -0
- data/rust/host/src/web/registrations.rs +1505 -0
- data/rust/host/src/web.rs +2937 -0
- data/rust/lsp/.gitignore +1 -0
- data/rust/lsp/Cargo.lock +7 -0
- data/rust/lsp/Cargo.toml +16 -0
- data/rust/lsp/README.md +133 -0
- data/rust/lsp/src/diagnostics.rs +165 -0
- data/rust/lsp/src/json.rs +385 -0
- data/rust/lsp/src/main.rs +399 -0
- data/rust/lsp/src/outline.rs +177 -0
- data/rust/lsp/src/rpc.rs +67 -0
- data/rust/parser/.cargo/config.toml +5 -0
- data/rust/parser/.gitignore +1 -0
- data/rust/parser/Cargo.lock +7 -0
- data/rust/parser/Cargo.toml +21 -0
- data/rust/parser/src/build/closed_sets.rs +27 -0
- data/rust/parser/src/build/identity.rs +276 -0
- data/rust/parser/src/build/mod.rs +12 -0
- data/rust/parser/src/build/naming.rs +141 -0
- data/rust/parser/src/build/pattern_subset.rs +161 -0
- data/rust/parser/src/build/query_derive.rs +72 -0
- data/rust/parser/src/build/query_inference.rs +269 -0
- data/rust/parser/src/build/query_options.rs +100 -0
- data/rust/parser/src/build/read_model.rs +94 -0
- data/rust/parser/src/build/references.rs +32 -0
- data/rust/parser/src/canonical.rs +114 -0
- data/rust/parser/src/diag.rs +55 -0
- data/rust/parser/src/emit.rs +953 -0
- data/rust/parser/src/expr/ast_json.rs +147 -0
- data/rust/parser/src/expr/evaluator.rs +81 -0
- data/rust/parser/src/expr/mod.rs +84 -0
- data/rust/parser/src/expr/resolver.rs +497 -0
- data/rust/parser/src/ir.rs +387 -0
- data/rust/parser/src/keywords.rs +585 -0
- data/rust/parser/src/lex.rs +662 -0
- data/rust/parser/src/main.rs +252 -0
- data/rust/parser/src/parse/aggregate.rs +612 -0
- data/rust/parser/src/parse/chapter.rs +517 -0
- data/rust/parser/src/parse/command.rs +637 -0
- data/rust/parser/src/parse/domain_port.rs +127 -0
- data/rust/parser/src/parse/entity.rs +527 -0
- data/rust/parser/src/parse/file.rs +67 -0
- data/rust/parser/src/parse/hecksagon.rs +231 -0
- data/rust/parser/src/parse/lifecycle.rs +162 -0
- data/rust/parser/src/parse/mod.rs +1262 -0
- data/rust/parser/src/parse/policy.rs +87 -0
- data/rust/parser/src/parse/process_manager.rs +305 -0
- data/rust/parser/src/parse/query.rs +100 -0
- data/rust/parser/src/parse/read_model.rs +214 -0
- data/rust/parser/src/parse/value_object.rs +250 -0
- data/rust/parser/src/ruby_value.rs +422 -0
- data/rust/project/bridging.rb +257 -0
- data/rust/project/commands.rb +877 -0
- data/rust/project/constraints.rb +86 -0
- data/rust/project/dependency_planning.rb +178 -0
- data/rust/project/domain_generator.rb +980 -0
- data/rust/project/exemplar.rb +148 -0
- data/rust/project/expr_emitter.rb +72 -0
- data/rust/project/fielded.rb +141 -0
- data/rust/project/json_codec.rb +641 -0
- data/rust/project/mutations.rb +721 -0
- data/rust/project/naming.rb +205 -0
- data/rust/project/ports.rb +65 -0
- data/rust/project/queries.rb +493 -0
- data/rust/project/reactions.rb +317 -0
- data/rust/project/read_models.rb +690 -0
- data/rust/project/reference_specs.rb +27 -0
- data/rust/project/registry.rb +396 -0
- data/rust/project/skip_reason.rb +29 -0
- data/rust/project/types.rb +225 -0
- data/rust/project/write_if_changed.rb +83 -0
- data/rust/project.rb +30 -0
- data/rust/project_rust_pipeline.rb +383 -0
- data/rust/src/exemplar/commands.rs +279 -0
- data/rust/src/exemplar/constraints.rs +18 -0
- data/rust/src/exemplar/fielded.rs +280 -0
- data/rust/src/exemplar/json.rs +277 -0
- data/rust/src/exemplar/mod.rs +17 -0
- data/rust/src/exemplar/mutations.rs +80 -0
- data/rust/src/exemplar/queries.rs +33 -0
- data/rust/src/exemplar/reactions.rs +88 -0
- data/rust/src/exemplar/read_models.rs +48 -0
- data/rust/src/exemplar/registry.rs +166 -0
- data/rust/src/exemplar/types.rs +44 -0
- data/rust/src/kernel/attribute_shapes/composite.rs +88 -0
- data/rust/src/kernel/attribute_shapes/list.rs +18 -0
- data/rust/src/kernel/attribute_shapes/mod.rs +44 -0
- data/rust/src/kernel/attribute_shapes/optional.rs +9 -0
- data/rust/src/kernel/attribute_shapes/scalar.rs +39 -0
- data/rust/src/kernel/cli.rs +585 -0
- data/rust/src/kernel/dispatch.rs +1090 -0
- data/rust/src/kernel/expr.rs +458 -0
- data/rust/src/kernel/expression_operators/arithmetic.rs +128 -0
- data/rust/src/kernel/expression_operators/comparison.rs +48 -0
- data/rust/src/kernel/expression_operators/enumeration.rs +232 -0
- data/rust/src/kernel/expression_operators/logical.rs +13 -0
- data/rust/src/kernel/expression_operators/membership.rs +18 -0
- data/rust/src/kernel/expression_operators/mod.rs +68 -0
- data/rust/src/kernel/expression_operators/pattern_match.rs +73 -0
- data/rust/src/kernel/expression_operators/positional.rs +126 -0
- data/rust/src/kernel/expression_operators/presence.rs +101 -0
- data/rust/src/kernel/expression_operators/sign_test.rs +16 -0
- data/rust/src/kernel/expression_operators/sized.rs +35 -0
- data/rust/src/kernel/expression_operators/text.rs +79 -0
- data/rust/src/kernel/expression_operators/to_string.rs +18 -0
- data/rust/src/kernel/json.rs +779 -0
- data/rust/src/kernel/mod.rs +133 -0
- data/rust/src/kernel/named_query.rs +219 -0
- data/rust/src/kernel/orchestrate.rs +1810 -0
- data/rust/src/kernel/pattern.rs +307 -0
- data/rust/src/kernel/query_comparators.rs +206 -0
- data/rust/src/kernel/query_ordering.rs +103 -0
- data/rust/src/kernel/read_model.rs +914 -0
- data/rust/src/kernel/reference_lookup.rs +149 -0
- data/rust/src/kernel/repository.rs +468 -0
- data/rust/src/kernel/routing.rs +612 -0
- data/rust/src/kernel/vocab/aggregate_dispatch_order.rs +118 -0
- data/rust/src/kernel/vocab/entity_dispatch_order.rs +114 -0
- data/rust/src/kernel/vocab/field_hint.rs +70 -0
- data/rust/src/kernel/vocab/mod.rs +20 -0
- data/rust/src/kernel/vocab/query_comparator.rs +65 -0
- data/rust/src/kernel/vocab/refusal_template.rs +1592 -0
- data/rust/src/lib.rs +8 -0
- data/rust/src/main.rs +16 -0
- data/rust/web/.gitignore +1 -0
- data/rust/web/Cargo.lock +119 -0
- data/rust/web/Cargo.toml +18 -0
- data/rust/web/src/lib.rs +8 -0
- metadata +477 -12
- data/lib/hecks/facade/cli_door.rb +0 -96
- data/lib/hecks/facade/cli_runner.rb +0 -127
- data/lib/hecks/mcp_door_scope.rb +0 -95
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
|
|
3
|
+
module Hecks
|
|
4
|
+
module Bench
|
|
5
|
+
# A fixed command sequence for one example domain, identical for every runtime.
|
|
6
|
+
# Cycles name their records by `n`, so no command is refused and none times a rejection path.
|
|
7
|
+
class Workload
|
|
8
|
+
Step = Struct.new(:verb, :args) do
|
|
9
|
+
def to_json_line
|
|
10
|
+
JSON.generate("verb" => verb, "args" => args)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def ruby_args
|
|
14
|
+
args.transform_keys(&:to_sym)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# The example domain's directory name, also its Cargo feature.
|
|
19
|
+
attr_reader :name
|
|
20
|
+
|
|
21
|
+
# The absolute path of the example domain directory.
|
|
22
|
+
attr_reader :domain_path
|
|
23
|
+
|
|
24
|
+
# The commands run once, untimed, before any cycle.
|
|
25
|
+
attr_reader :setup
|
|
26
|
+
|
|
27
|
+
def initialize(name:, setup:, cycle:)
|
|
28
|
+
@name = name
|
|
29
|
+
@domain_path = File.expand_path("../../../examples/#{name}", __dir__)
|
|
30
|
+
@setup = setup
|
|
31
|
+
@cycle = cycle
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def cycle(number) = @cycle.call(number)
|
|
35
|
+
|
|
36
|
+
def commands_per_cycle = cycle(0).size
|
|
37
|
+
|
|
38
|
+
def self.all
|
|
39
|
+
{ "pizzas" => pizzas, "banking" => banking }
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def self.fetch(name)
|
|
43
|
+
all.fetch(name) do
|
|
44
|
+
raise ArgumentError, "unknown domain #{name.inspect} — one of #{all.keys.join(', ')}"
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def self.pizzas
|
|
49
|
+
new(name: "pizzas", setup: [], cycle: lambda { |n|
|
|
50
|
+
pizza = "pizza-#{n}"
|
|
51
|
+
[
|
|
52
|
+
Step.new("Pizzas::Order.CreatePizza",
|
|
53
|
+
{ "name" => { "value" => pizza },
|
|
54
|
+
"pizza" => { "price_cents" => { "cents" => 1200 }, "size" => { "value" => "large" } } }),
|
|
55
|
+
Step.new("Pizzas::Order.AddTopping",
|
|
56
|
+
{ "name" => pizza, "topping" => { "value" => "Basil" }, "amount" => { "value" => 3 } }),
|
|
57
|
+
Step.new("Pizzas::Order.AddTopping",
|
|
58
|
+
{ "name" => pizza, "topping" => { "value" => "Olive" }, "amount" => { "value" => 2 } }),
|
|
59
|
+
Step.new("Pizzas::Order.Purchase",
|
|
60
|
+
{ "name" => pizza, "customer_name" => { "value" => "Chris" },
|
|
61
|
+
"amount" => { "cents" => 1200 } })
|
|
62
|
+
]
|
|
63
|
+
})
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def self.banking
|
|
67
|
+
register = Step.new("Banking::Customer.Register",
|
|
68
|
+
{ "reference" => { "value" => "CUST-0001" },
|
|
69
|
+
"name" => { "given" => "Ada", "family" => "Lovelace" },
|
|
70
|
+
"email" => { "address" => "ada@example.com" } })
|
|
71
|
+
new(name: "banking", setup: [register], cycle: lambda { |n|
|
|
72
|
+
number = { "value" => "acct-#{n}" }
|
|
73
|
+
money = ->(cents) { { "cents" => cents, "currency" => "USD" } }
|
|
74
|
+
[
|
|
75
|
+
Step.new("Banking::Account.Open",
|
|
76
|
+
{ "number" => number, "kind" => { "name" => "current" },
|
|
77
|
+
"daily_limit" => { "cents" => 50_000 }, "customer" => "CUST-0001" }),
|
|
78
|
+
Step.new("Banking::Account.Credit",
|
|
79
|
+
{ "number" => number, "amount" => money.call(10_000), "narrative" => { "text" => "Deposit" } }),
|
|
80
|
+
Step.new("Banking::Account.Credit",
|
|
81
|
+
{ "number" => number, "amount" => money.call(5000), "narrative" => { "text" => "Deposit" } }),
|
|
82
|
+
Step.new("Banking::Account.Debit",
|
|
83
|
+
{ "number" => number, "amount" => money.call(2500), "narrative" => { "text" => "Groceries" } })
|
|
84
|
+
]
|
|
85
|
+
})
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
data/lib/hecks/bench.rb
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Hecks
|
|
2
|
+
# Throughput and latency harness behind `hecks bench`; see `docs/benchmarks.md`.
|
|
3
|
+
# Not required by `lib/hecks.rb`: a booted domain never needs it.
|
|
4
|
+
module Bench
|
|
5
|
+
end
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
require_relative "bench/stats"
|
|
9
|
+
require_relative "bench/workload"
|
|
10
|
+
require_relative "bench/environment"
|
|
11
|
+
require_relative "bench/postgres_probe"
|
|
12
|
+
require_relative "bench/run"
|
|
13
|
+
require_relative "bench/ruby_runner"
|
|
14
|
+
require_relative "bench/rust_runner"
|
|
15
|
+
require_relative "bench/suite"
|
|
16
|
+
require_relative "bench/report"
|
|
17
|
+
require_relative "bench/cli"
|
|
@@ -17,6 +17,7 @@ module Hecks
|
|
|
17
17
|
vision: [:vision, :plain],
|
|
18
18
|
classification: [:classification, :plain],
|
|
19
19
|
formerly_known_as: [:formerly_known_as, :plain],
|
|
20
|
+
namespace: [:namespace, :plain],
|
|
20
21
|
attaches_to: [:attaches_to, :plain],
|
|
21
22
|
provides: [:provides, :plain]
|
|
22
23
|
},
|
|
@@ -97,6 +98,7 @@ module Hecks
|
|
|
97
98
|
wheres: [:wheres, [:each, :where_clause]],
|
|
98
99
|
order_by: [:order_by, :order_by],
|
|
99
100
|
limit: [:limit, :limit],
|
|
101
|
+
returns: [:returns, :plain],
|
|
100
102
|
# Held by the language as an open map, so every one of these reads the
|
|
101
103
|
# same way and a ninth option needs no new field on either side.
|
|
102
104
|
offset: [:offset, [:option, :offset]],
|
|
@@ -49,7 +49,7 @@ module Hecks
|
|
|
49
49
|
|
|
50
50
|
# A bare constant in a bluebook is a name, even when Ruby has heard of it.
|
|
51
51
|
#
|
|
52
|
-
# `
|
|
52
|
+
# `Doors::RubyDoor` installs aggregate names as top-level constants, which would win
|
|
53
53
|
# over the `const_missing` resolver and silently rebind the attribute. Demodulising
|
|
54
54
|
# spells `:Target` and `QualityControl::Target` the same.
|
|
55
55
|
def spell(type)
|
|
@@ -64,13 +64,42 @@ module Hecks
|
|
|
64
64
|
# none is attached under that name
|
|
65
65
|
def port(named) = @ports_by_name[named.to_s]
|
|
66
66
|
|
|
67
|
+
# Finds every port whose adapter answers a query.
|
|
68
|
+
#
|
|
69
|
+
# @param named [String, Symbol] the query's declared name
|
|
70
|
+
# @return [Array<Bluebook::DomainPort>] the ports the hecksagon binds to the query; empty
|
|
71
|
+
# when the query is answered from the aggregate's records
|
|
72
|
+
def query_bindings(named) = @ports.select { |port| port.answer_for(named) }
|
|
73
|
+
|
|
74
|
+
# Finds the port whose adapter answers a query.
|
|
75
|
+
#
|
|
76
|
+
# @param named [String, Symbol] the query's declared name
|
|
77
|
+
# @return [Bluebook::DomainPort, nil] the first port bound to the query, or `nil` if
|
|
78
|
+
# the hecksagon binds none
|
|
79
|
+
def query_binding(named) = query_bindings(named).first
|
|
80
|
+
|
|
67
81
|
# Attaches a port declared in the hecksagon, after the aggregate exists.
|
|
68
82
|
# `HecksagonBuilder` stamps each operation's reference attributes with
|
|
69
|
-
# `declared_in = self` before calling it.
|
|
83
|
+
# `declared_in = self` before calling it. A port declared again under a name the
|
|
84
|
+
# aggregate already holds merges into it, so an overlay repeating a base
|
|
85
|
+
# declaration adds nothing twice; two different names stay two ports.
|
|
70
86
|
#
|
|
71
87
|
# @param port [Bluebook::DomainPort] the aggregate-scoped port to attach
|
|
72
88
|
# @return [void]
|
|
73
89
|
def add_port(port)
|
|
90
|
+
held = @ports_by_name[port.name]
|
|
91
|
+
return attach_port(port) unless held
|
|
92
|
+
|
|
93
|
+
operations = held.operations + port.operations.reject { |op| held.operation(op.hecks_name) }
|
|
94
|
+
answers = held.answered_queries + port.answered_queries.reject { |a| held.answer_for(a.name) }
|
|
95
|
+
merged = Bluebook::DomainPort.new(name: held.name, operations: operations, answered_queries: answers)
|
|
96
|
+
@ports[@ports.index(held)] = merged
|
|
97
|
+
@ports_by_name[merged.name] = merged
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# @param port [Bluebook::DomainPort] a port under a name the aggregate does not hold
|
|
101
|
+
# @return [void]
|
|
102
|
+
def attach_port(port)
|
|
74
103
|
@ports << port
|
|
75
104
|
@ports_by_name[port.name] = port
|
|
76
105
|
end
|
|
@@ -47,6 +47,13 @@ module Hecks
|
|
|
47
47
|
# @return [Bluebook::PortOperation, nil] the operation, or `nil` if none is
|
|
48
48
|
# declared by that name
|
|
49
49
|
def operation(named) = @operations.find { |op| op.hecks_name == named.to_s }
|
|
50
|
+
|
|
51
|
+
# Finds the binding this port gives a query, if it answers that query.
|
|
52
|
+
#
|
|
53
|
+
# @param named [String, Symbol] the query's declared name
|
|
54
|
+
# @return [Bluebook::QueryAnswer, nil] the binding, or `nil` if this port does not
|
|
55
|
+
# answer that query
|
|
56
|
+
def answer_for(named) = @answered_queries.find { |answer| answer.name == named.to_s }
|
|
50
57
|
end
|
|
51
58
|
end
|
|
52
59
|
end
|
|
@@ -24,6 +24,9 @@ module Hecks
|
|
|
24
24
|
# differing only by their old name can't hash identically at the
|
|
25
25
|
# meta-validator's cache key (`SHA256(JSON(bluebook.to_h))`).
|
|
26
26
|
formerly_known_as: :formerly_known_as,
|
|
27
|
+
# The Ruby module the chapter's constants install under, when it is not the chapter's
|
|
28
|
+
# own name (the Hecks domain nests under `Hecks::Domain`); nil for every other chapter.
|
|
29
|
+
namespace: :namespace,
|
|
27
30
|
aggregates: many(:aggregates),
|
|
28
31
|
read_models: many(:read_models),
|
|
29
32
|
policies: many(:policies),
|
|
@@ -53,7 +56,7 @@ module Hecks
|
|
|
53
56
|
end
|
|
54
57
|
|
|
55
58
|
attr_reader :name, :version, :vision, :aggregates, :policies, :process_managers,
|
|
56
|
-
:classification, :read_models, :ports, :formerly_known_as, :attaches_to, :provides
|
|
59
|
+
:classification, :read_models, :ports, :formerly_known_as, :namespace, :attaches_to, :provides
|
|
57
60
|
|
|
58
61
|
# @param policies [Array<Bluebook::Policy>] every reaction declared across the
|
|
59
62
|
# chapter's own aggregates, hoisted here
|
|
@@ -61,7 +64,7 @@ module Hecks
|
|
|
61
64
|
# its project's own domain model, or `nil` if undeclared
|
|
62
65
|
def initialize(name:, version: nil, vision: nil, aggregates: [], policies: [],
|
|
63
66
|
process_managers: [], classification: nil, read_models: [], formerly_known_as: nil,
|
|
64
|
-
attaches_to: [], provides: [])
|
|
67
|
+
namespace: nil, attaches_to: [], provides: [])
|
|
65
68
|
@policies = policies
|
|
66
69
|
@process_managers = process_managers
|
|
67
70
|
@name = name.to_s
|
|
@@ -73,6 +76,7 @@ module Hecks
|
|
|
73
76
|
@read_models = read_models
|
|
74
77
|
@classification = classification&.to_s
|
|
75
78
|
@formerly_known_as = formerly_known_as&.to_s
|
|
79
|
+
@namespace = namespace&.to_s
|
|
76
80
|
@attaches_to = Array(attaches_to).map(&:to_s)
|
|
77
81
|
@provides = Array(provides).map { |row| Provision.from(row) }
|
|
78
82
|
settle
|
|
@@ -58,20 +58,51 @@ module Hecks
|
|
|
58
58
|
end
|
|
59
59
|
end
|
|
60
60
|
|
|
61
|
-
# A
|
|
61
|
+
# A query the hecksagon binds to a port's adapter: the bluebook declares the question and the
|
|
62
|
+
# value object its answer takes (`returns`), and this declares that something outside the
|
|
63
|
+
# domain answers it.
|
|
64
|
+
class QueryAnswer
|
|
65
|
+
include Hecks::IR
|
|
66
|
+
|
|
67
|
+
emits_ir(name: :name)
|
|
68
|
+
|
|
69
|
+
attr_reader :name
|
|
70
|
+
|
|
71
|
+
# @param name [String, Symbol] the bound query's declared name
|
|
72
|
+
def initialize(name:)
|
|
73
|
+
@name = name.to_s
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# A named group of operations an aggregate exposes to whatever adapter calls in, plus the
|
|
78
|
+
# queries its adapter answers.
|
|
62
79
|
class DomainPort
|
|
63
80
|
include Hecks::IR
|
|
64
81
|
include Behaviour::DomainPort
|
|
65
82
|
|
|
66
83
|
emits_ir(name: :name, operations: many(:operations))
|
|
67
84
|
|
|
68
|
-
attr_reader :name, :operations
|
|
85
|
+
attr_reader :name, :operations, :answered_queries
|
|
69
86
|
|
|
70
87
|
# @param name [String, Symbol] the port's declared name
|
|
71
88
|
# @param operations [Array<Bluebook::PortOperation>] the port's declared operations
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
89
|
+
# @param answered_queries [Array<Bluebook::QueryAnswer>] the queries this port's adapter
|
|
90
|
+
# answers instead of the aggregate's stored records
|
|
91
|
+
def initialize(name:, operations: [], answered_queries: [])
|
|
92
|
+
@name = name.to_s
|
|
93
|
+
@operations = operations
|
|
94
|
+
@answered_queries = answered_queries
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# `answered_queries` is merged in only when there are some, so a port that binds no query
|
|
98
|
+
# emits the shape it always did.
|
|
99
|
+
#
|
|
100
|
+
# @return [Hash] the port's IR
|
|
101
|
+
def to_h
|
|
102
|
+
shape = super
|
|
103
|
+
return shape if @answered_queries.empty?
|
|
104
|
+
|
|
105
|
+
shape.merge(answered_queries: @answered_queries.map(&:to_h))
|
|
75
106
|
end
|
|
76
107
|
end
|
|
77
108
|
end
|
|
@@ -14,6 +14,7 @@ module Hecks
|
|
|
14
14
|
# @raise [Bluebook::DSL::ProcessManagerBuilder::InvalidProcessManager] if a
|
|
15
15
|
# `correlates_by` resolves to something other than a scalar field
|
|
16
16
|
def validate_assembled!(bluebook)
|
|
17
|
+
validate_not_the_gem_module!(bluebook)
|
|
17
18
|
# an attribute type references its Shape, so an undeclared value object
|
|
18
19
|
# fails resolution
|
|
19
20
|
validate_reference_value_objects!(bluebook.aggregates)
|
|
@@ -289,6 +290,15 @@ module Hecks
|
|
|
289
290
|
# chapter level because seeing a cycle needs every end declared (ADR 0025). Catches
|
|
290
291
|
# any ring length; self-reference stays legal, and a cross-chapter target is a
|
|
291
292
|
# dangling name, not an edge.
|
|
293
|
+
# A chapter's constants install under its name, or its `namespace`; landing in the
|
|
294
|
+
# gem's own `Hecks` module would shadow the gem's modules (ADR 0080), so it refuses.
|
|
295
|
+
def validate_not_the_gem_module!(bluebook)
|
|
296
|
+
return unless (bluebook.namespace || bluebook.name) == "Hecks"
|
|
297
|
+
|
|
298
|
+
raise Malformed, "#{bluebook.name}'s constants would install in the gem's own Hecks module — " \
|
|
299
|
+
"declare a namespace, such as namespace \"Hecks::Domain\", or rename the chapter"
|
|
300
|
+
end
|
|
301
|
+
|
|
292
302
|
def validate_no_bidirectional_references!(aggregates)
|
|
293
303
|
edges = aggregates.to_h do |aggregate|
|
|
294
304
|
[aggregate.hecks_name, aggregate.reference_targets.uniq.reject { |target| target == aggregate.hecks_name }]
|
|
@@ -65,6 +65,13 @@ module Hecks
|
|
|
65
65
|
# @return [String] `value`, stringified, as stored
|
|
66
66
|
def formerly_known_as(value) = @formerly_known_as = value.to_s
|
|
67
67
|
|
|
68
|
+
# Names the Ruby module the chapter's constants install under instead of its own name,
|
|
69
|
+
# such as `namespace "Hecks::Domain"` for a chapter that would otherwise collide.
|
|
70
|
+
#
|
|
71
|
+
# @param value [String] a constant path, such as `"Hecks::Domain"`
|
|
72
|
+
# @return [String] `value`, stringified, as stored
|
|
73
|
+
def namespace(value) = @namespace = value.to_s
|
|
74
|
+
|
|
68
75
|
# Names a core grammar context this chapter's sub-language extends (ADR 0026).
|
|
69
76
|
# Variadic and accumulates across calls, like `identified_by`/`group_by`.
|
|
70
77
|
#
|
|
@@ -197,6 +204,7 @@ module Hecks
|
|
|
197
204
|
process_managers: @process_managers,
|
|
198
205
|
classification: @classification,
|
|
199
206
|
formerly_known_as: @formerly_known_as,
|
|
207
|
+
namespace: @namespace,
|
|
200
208
|
attaches_to: @attaches_to || [],
|
|
201
209
|
provides: @provides || [])
|
|
202
210
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
# KeywordSeed under lib/hecks/language/).
|
|
4
4
|
#
|
|
5
5
|
# Do not edit. spec/bootstrap_table_spec.rb re-projects this in memory
|
|
6
|
-
# and refuses a diff — run
|
|
6
|
+
# and refuses a diff — run hecks project_bootstrap_table instead.
|
|
7
7
|
#
|
|
8
8
|
# Plain data, no requires: this is read while the grammar table it was
|
|
9
9
|
# projected from is still being built (`MetaValidator.bootstrapping?`).
|
|
@@ -88,6 +88,7 @@ module Hecks
|
|
|
88
88
|
["DomainPort", "operation"] => :tells_impl,
|
|
89
89
|
["DomainPort", "tells"] => :tells_impl,
|
|
90
90
|
["DomainPort", "asks"] => :asks_impl,
|
|
91
|
+
["DomainPort", "answers_query"] => :answers_query_impl,
|
|
91
92
|
["Hecksagon", "port"] => :port_impl,
|
|
92
93
|
["PortOperation", "reference_to"] => :reference_to_impl,
|
|
93
94
|
["PortOperation", "attribute"] => :attribute_impl,
|
|
@@ -23,6 +23,7 @@ module Hecks
|
|
|
23
23
|
@operations = []
|
|
24
24
|
@signal = :reply
|
|
25
25
|
@answers = []
|
|
26
|
+
@answered_queries = []
|
|
26
27
|
@legacy_bare_port = legacy_bare_port
|
|
27
28
|
end
|
|
28
29
|
|
|
@@ -58,6 +59,30 @@ module Hecks
|
|
|
58
59
|
@operations << PortOperationBuilder.build(name, to: to, owner: @owner, direction: :outbound, &)
|
|
59
60
|
end
|
|
60
61
|
|
|
62
|
+
# Declares that this port's adapter answers one of the owning aggregate's queries.
|
|
63
|
+
#
|
|
64
|
+
# The bluebook declares the question and the shape of its answer (`returns`) and never
|
|
65
|
+
# says who answers it; this binds it. The adapter is asked by the query's snake-cased
|
|
66
|
+
# name with its arguments. The aggregate's stored records are never read.
|
|
67
|
+
#
|
|
68
|
+
# @param name [String] the query's name, as the aggregate declares it
|
|
69
|
+
# @param removed [Hash] any keyword at all; the binding takes only the name
|
|
70
|
+
# @return [Array<Bluebook::QueryAnswer>] every binding declared so far, this one last
|
|
71
|
+
# @raise [Bluebook::DSL::Malformed] if a keyword such as `shape:` is written, or the query
|
|
72
|
+
# is already bound on this port
|
|
73
|
+
def answers_query_impl(name, **removed)
|
|
74
|
+
unless removed.empty?
|
|
75
|
+
raise Malformed, "answers_query #{name.inspect} takes only the query's name — the shape " \
|
|
76
|
+
"of its answer is the query's own `returns`, declared in the bluebook " \
|
|
77
|
+
"(#{removed.keys.join(', ')} is not a word here)"
|
|
78
|
+
end
|
|
79
|
+
if @answered_queries.any? { |answer| answer.name == name.to_s }
|
|
80
|
+
raise Malformed, "#{@name} binds #{name} twice — a query has one answer"
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
@answered_queries << QueryAnswer.new(name: name)
|
|
84
|
+
end
|
|
85
|
+
|
|
61
86
|
# Names the verb aggregates call this port by, making it a driven `Port` rather than a
|
|
62
87
|
# `DomainPort` of operations. A port is one shape or the other, never both.
|
|
63
88
|
#
|
|
@@ -83,10 +108,11 @@ module Hecks
|
|
|
83
108
|
#
|
|
84
109
|
# @return [Bluebook::Port, Bluebook::DomainPort] a `Port` when the body named a `verb`
|
|
85
110
|
# (or was empty under `legacy_bare_port:`), otherwise a `DomainPort` of its operations
|
|
111
|
+
# and answered queries
|
|
86
112
|
# @raise [Bluebook::DSL::Malformed] if the body declares both a verb and operations,
|
|
87
113
|
# declares neither without `legacy_bare_port:`, or the port language refuses the `Port`
|
|
88
114
|
def build
|
|
89
|
-
if @verb &&
|
|
115
|
+
if @verb && !(@operations.empty? && @answered_queries.empty?)
|
|
90
116
|
raise Malformed,
|
|
91
117
|
"#{@name} declares both a verb and operations — a port is one or the other, not both"
|
|
92
118
|
end
|
|
@@ -96,9 +122,11 @@ module Hecks
|
|
|
96
122
|
answers: @answers))
|
|
97
123
|
end
|
|
98
124
|
|
|
99
|
-
|
|
125
|
+
if @operations.empty? && @answered_queries.empty?
|
|
126
|
+
raise Malformed, "#{@name} declares no verb and no operations, and answers no query"
|
|
127
|
+
end
|
|
100
128
|
|
|
101
|
-
DomainPort.new(name: @name, operations: @operations)
|
|
129
|
+
DomainPort.new(name: @name, operations: @operations, answered_queries: @answered_queries)
|
|
102
130
|
end
|
|
103
131
|
|
|
104
132
|
# Evaluates a `port` block against a fresh builder and returns whichever shape it declared.
|
|
@@ -10,10 +10,54 @@ module Hecks
|
|
|
10
10
|
include WordGate
|
|
11
11
|
|
|
12
12
|
class << self
|
|
13
|
-
|
|
13
|
+
# The bind collector of the build running on this thread; thread-local, so a build
|
|
14
|
+
# on another thread never sees it.
|
|
15
|
+
#
|
|
16
|
+
# @return [Array, nil] the binds the running build collects into
|
|
17
|
+
def collector = Thread.current.thread_variable_get(:hecks_hecksagon_collector)
|
|
18
|
+
|
|
19
|
+
# @param value [Array, nil] the binds the running build collects into
|
|
20
|
+
def collector=(value)
|
|
21
|
+
Thread.current.thread_variable_set(:hecks_hecksagon_collector, value)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# @return [String, nil] the name of the chapter whose hecksagon is being built
|
|
25
|
+
def building = Thread.current.thread_variable_get(:hecks_hecksagon_building)
|
|
26
|
+
|
|
27
|
+
# @param value [String, nil] the name of the chapter whose hecksagon is being built
|
|
28
|
+
def building=(value)
|
|
29
|
+
Thread.current.thread_variable_set(:hecks_hecksagon_building, value)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# @return [Hash, nil] the modules this thread's build has taken off `Hecks`
|
|
33
|
+
def hidden_modules = Thread.current.thread_variable_get(:hecks_hecksagon_hidden)
|
|
34
|
+
|
|
35
|
+
# @param value [Hash, nil] the modules this thread's build has taken off `Hecks`
|
|
36
|
+
def hidden_modules=(value)
|
|
37
|
+
Thread.current.thread_variable_set(:hecks_hecksagon_hidden, value)
|
|
38
|
+
end
|
|
14
39
|
end
|
|
15
40
|
|
|
16
|
-
|
|
41
|
+
# Lets the Hecks chapter's own hecksagon spell its aggregates `Hecks::Operation`.
|
|
42
|
+
#
|
|
43
|
+
# While the chapter named Hecks builds its hecksagon, a missing constant on `Hecks` is
|
|
44
|
+
# one of that chapter's aggregates; at any other time it is the ordinary `NameError`.
|
|
45
|
+
#
|
|
46
|
+
# A real module of the same name (`Hecks::Release`) would answer first, so
|
|
47
|
+
# `HecksagonBuilder.build` takes each off `Hecks` while the block runs (see `shadowed`).
|
|
48
|
+
# `attaches` loads whole chapters inside the block; the shadow lifts around each load
|
|
49
|
+
# (see `with_real_modules`), so loaded code sees the real modules.
|
|
50
|
+
module ChapterConstants
|
|
51
|
+
# @param name [Symbol] the missing constant
|
|
52
|
+
# @return [Bluebook::DSL::BindingProxy] a proxy for that aggregate while building
|
|
53
|
+
def const_missing(name)
|
|
54
|
+
return super unless HecksagonBuilder.building == "Hecks" && HecksagonBuilder.collector
|
|
55
|
+
|
|
56
|
+
BindingProxy.new("Hecks::#{name}", HecksagonBuilder.collector)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
attr_reader :binds, :subscriptions, :framework_members, :vendored_bluebooks, :attached_chapters
|
|
17
61
|
|
|
18
62
|
def initialize(domain)
|
|
19
63
|
@domain = domain
|
|
@@ -21,6 +65,7 @@ module Hecks
|
|
|
21
65
|
@subscriptions = []
|
|
22
66
|
@framework_members = []
|
|
23
67
|
@vendored_bluebooks = []
|
|
68
|
+
@attached_chapters = []
|
|
24
69
|
@bounded = false
|
|
25
70
|
@translates = []
|
|
26
71
|
end
|
|
@@ -54,6 +99,17 @@ module Hecks
|
|
|
54
99
|
Hecks.current_registry&.mark_bounded(Hecks::Naming.pascal(name.to_s))
|
|
55
100
|
end
|
|
56
101
|
|
|
102
|
+
# Attaches a chapter the gem carries (the language, Expression, Tenancy, Deploy,
|
|
103
|
+
# QualityControl) by name and loads its files into the registry, with the ports and
|
|
104
|
+
# adapters it ships. Marked bounded like a framework member, since this hecksagon is its
|
|
105
|
+
# anti-corruption layer.
|
|
106
|
+
def attaches(name)
|
|
107
|
+
require_relative "../../chapters"
|
|
108
|
+
@attached_chapters << name.to_s
|
|
109
|
+
self.class.with_real_modules { Hecks::Chapters.load!(name) }
|
|
110
|
+
Hecks.current_registry&.mark_bounded(name.to_s)
|
|
111
|
+
end
|
|
112
|
+
|
|
57
113
|
# Declares a port at the hecksagon's root — the chapter as a whole, not one aggregate.
|
|
58
114
|
def port_impl(name, &block)
|
|
59
115
|
bluebook_ir = Hecks.current_registry.bluebook(@domain) or
|
|
@@ -90,7 +146,7 @@ module Hecks
|
|
|
90
146
|
def build
|
|
91
147
|
Hecksagon.new(domain: @domain, binds: @binds, subscriptions: @subscriptions,
|
|
92
148
|
framework_members: @framework_members, vendored_bluebooks: @vendored_bluebooks,
|
|
93
|
-
bounded: @bounded, translates: @translates)
|
|
149
|
+
attached_chapters: @attached_chapters, bounded: @bounded, translates: @translates)
|
|
94
150
|
end
|
|
95
151
|
|
|
96
152
|
# Records any verb the grammar doesn't own as a domain-wide default bind, e.g. bare
|
|
@@ -117,16 +173,79 @@ module Hecks
|
|
|
117
173
|
resolver = ->(name) { BindingProxy.namespace(name, builder.binds) }
|
|
118
174
|
|
|
119
175
|
previous = collector
|
|
176
|
+
previous_name = building
|
|
120
177
|
self.collector = builder.binds
|
|
178
|
+
self.building = domain.to_s
|
|
179
|
+
previous_hidden = hidden_modules
|
|
180
|
+
hidden = previous_name == "Hecks" ? {} : shadowed(domain)
|
|
181
|
+
self.hidden_modules = hidden.empty? ? previous_hidden : hidden
|
|
121
182
|
begin
|
|
122
183
|
ConstShim.with(resolver) { builder.instance_eval(&block) } if block
|
|
123
184
|
ensure
|
|
185
|
+
restore_shadowed(hidden)
|
|
186
|
+
self.hidden_modules = previous_hidden
|
|
124
187
|
self.collector = previous
|
|
188
|
+
self.building = previous_name
|
|
125
189
|
end
|
|
126
190
|
|
|
127
191
|
builder.build
|
|
128
192
|
end
|
|
193
|
+
|
|
194
|
+
# Takes off `Hecks` each real module a chapter aggregate shares its name with, so the
|
|
195
|
+
# name reaches `ChapterConstants#const_missing`. Only the chapter named Hecks has this
|
|
196
|
+
# collision; a nested build of it leaves the outer build's shadows in place.
|
|
197
|
+
#
|
|
198
|
+
# @param domain [String, Symbol] the chapter whose hecksagon is being built
|
|
199
|
+
# @return [Hash{Symbol => Object}] what was taken off, by name: the module, or the
|
|
200
|
+
# autoload path when the constant had not loaded yet
|
|
201
|
+
def self.shadowed(domain)
|
|
202
|
+
return {} unless domain.to_s == "Hecks"
|
|
203
|
+
|
|
204
|
+
chapter = Hecks.current_registry&.bluebook("Hecks")
|
|
205
|
+
names = chapter ? chapter.aggregates.map { |aggregate| aggregate.hecks_name.to_sym } : []
|
|
206
|
+
names.select { |name| Hecks.const_defined?(name, false) }.to_h do |name|
|
|
207
|
+
pending = Hecks.autoload?(name)
|
|
208
|
+
held = pending ? [:autoload, pending] : [:module, Hecks.const_get(name, false)]
|
|
209
|
+
Hecks.send(:remove_const, name)
|
|
210
|
+
[name, held]
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# Runs the block with every module the running build shadowed back on `Hecks`, and a
|
|
215
|
+
# missing `Hecks::X` an ordinary `NameError`, then shadows them again. A chapter loaded
|
|
216
|
+
# from inside the hecksagon block is ordinary code, not the hecksagon's own vocabulary.
|
|
217
|
+
# A no-op when nothing is shadowed.
|
|
218
|
+
#
|
|
219
|
+
# @yield the code that must see `Hecks`'s real modules
|
|
220
|
+
# @return [Object] the block's result
|
|
221
|
+
def self.with_real_modules
|
|
222
|
+
hidden = hidden_modules
|
|
223
|
+
return yield if hidden.nil? || hidden.empty?
|
|
224
|
+
|
|
225
|
+
name = building
|
|
226
|
+
restore_shadowed(hidden)
|
|
227
|
+
self.building = nil
|
|
228
|
+
begin
|
|
229
|
+
yield
|
|
230
|
+
ensure
|
|
231
|
+
self.building = name
|
|
232
|
+
hidden.replace(shadowed(name))
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
# Puts back what `shadowed` took off.
|
|
237
|
+
#
|
|
238
|
+
# @param hidden [Hash{Symbol => Array}] `shadowed`'s answer
|
|
239
|
+
# @return [void]
|
|
240
|
+
def self.restore_shadowed(hidden)
|
|
241
|
+
hidden.each do |name, (kind, held)|
|
|
242
|
+
Hecks.send(:remove_const, name) if Hecks.const_defined?(name, false)
|
|
243
|
+
kind == :autoload ? Hecks.autoload(name, held) : Hecks.const_set(name, held)
|
|
244
|
+
end
|
|
245
|
+
end
|
|
129
246
|
end
|
|
130
247
|
end
|
|
131
248
|
end
|
|
132
249
|
end
|
|
250
|
+
|
|
251
|
+
Hecks.singleton_class.prepend(Hecks::Bluebook::DSL::HecksagonBuilder::ChapterConstants)
|
|
@@ -64,7 +64,7 @@ module Hecks
|
|
|
64
64
|
|
|
65
65
|
# C5.3 (docs/semantics/bluebook-semantics.md): overlapping `from:` sets for one command
|
|
66
66
|
# are refused. Disjoint sets are legitimate. An undeclared `from:` state is left to
|
|
67
|
-
# `
|
|
67
|
+
# `hecks model_check`.
|
|
68
68
|
def refuse_ambiguity!
|
|
69
69
|
return if MetaValidator.shadow_parsing? # frozen era text is exempt
|
|
70
70
|
|
|
@@ -27,6 +27,31 @@ module Hecks
|
|
|
27
27
|
# @return [String] the description as stored
|
|
28
28
|
def description(value) = @description = value
|
|
29
29
|
|
|
30
|
+
# Names the value object of the owning aggregate that shapes this query's answer.
|
|
31
|
+
#
|
|
32
|
+
# The bluebook owns the meaning of an answer: a query that returns a value object is
|
|
33
|
+
# answered by something outside the domain (the hecksagon binds it), and each row of
|
|
34
|
+
# that answer is built as the value object, so a wrong-shaped answer is refused before
|
|
35
|
+
# it enters the domain. A query that returns nothing answers with the aggregate's own row.
|
|
36
|
+
#
|
|
37
|
+
# @param type [Module, AttributeCollector::ListOf] a bare value-object constant, or
|
|
38
|
+
# `list_of(Constant)` when the answer is many rows
|
|
39
|
+
# @return [String] the return type as stored: `"Name"` or `"list_of(Name)"`
|
|
40
|
+
# @raise [Bluebook::DSL::Malformed] if the query already returns, or the type is quoted text
|
|
41
|
+
def returns(type)
|
|
42
|
+
raise Malformed, "#{@name} declares returns twice — a query answers in one shape" if @returns
|
|
43
|
+
|
|
44
|
+
list = type.is_a?(AttributeCollector::ListOf)
|
|
45
|
+
inner = list ? type.type : type
|
|
46
|
+
if inner.is_a?(::String)
|
|
47
|
+
raise Malformed, "#{@name}'s returns #{inner.inspect} is quoted text — give the bare " \
|
|
48
|
+
"constant (#{inner}) instead"
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
name = Naming.demodulise(inner)
|
|
52
|
+
@returns = list ? "list_of(#{name})" : name.to_s
|
|
53
|
+
end
|
|
54
|
+
|
|
30
55
|
# Declares a query parameter that names another aggregate's identity.
|
|
31
56
|
#
|
|
32
57
|
# A plain attribute typed as a reference; a query has no root of its own to act on.
|
|
@@ -61,7 +86,8 @@ module Hecks
|
|
|
61
86
|
cursor: @cursor,
|
|
62
87
|
authorization: @authorization,
|
|
63
88
|
null_semantics: @null_semantics,
|
|
64
|
-
inspection: @inspection
|
|
89
|
+
inspection: @inspection,
|
|
90
|
+
returns: @returns
|
|
65
91
|
)
|
|
66
92
|
end
|
|
67
93
|
|
|
@@ -55,7 +55,7 @@ module Hecks
|
|
|
55
55
|
#
|
|
56
56
|
# Projected ahead of time into bootstrap_table.rb for the bootstrap window before
|
|
57
57
|
# the grammar table itself is built (MetaValidator.bootstrapping?); kept in sync by
|
|
58
|
-
#
|
|
58
|
+
# hecks project_bootstrap_table, pinned by spec/bootstrap_table_spec.rb.
|
|
59
59
|
BOOTSTRAP_FALLBACK = BootstrapTable::RESOLVES
|
|
60
60
|
|
|
61
61
|
# Reads how a (word, context) pair resolves rule references, off the self-hosted
|