hecks 3.10.0 → 3.12.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/examples/pizzas/bluebook/pizzas.bluebook +29 -0
- data/examples/pizzas/bluebook/pizzas.hecksagon +7 -0
- data/exe/hecks +4 -4
- data/lib/hecks/adapters/driven/d1.rb +2 -10
- data/lib/hecks/adapters/driven/heki.adapter +1 -1
- data/lib/hecks/adapters/driven/heki.rb +2 -12
- data/lib/hecks/adapters/driven/lambda.adapter +1 -1
- data/lib/hecks/adapters/driven/lambda.rb +3 -18
- data/lib/hecks/adapters/driven/postgres.rb +4 -11
- data/lib/hecks/adapters/driven/sqlite.adapter +1 -1
- data/lib/hecks/adapters/driven/sqlite.rb +2 -10
- data/lib/hecks/adapters/driving/admission.rb +46 -0
- data/lib/hecks/adapters/driving/cli/nesting.rb +36 -0
- data/lib/hecks/adapters/driving/cli/shorthand.rb +88 -0
- data/lib/hecks/adapters/driving/cli.rb +127 -0
- data/lib/hecks/adapters/driving/cli_runner/answers.rb +160 -0
- data/lib/hecks/adapters/driving/cli_runner/resolution.rb +158 -0
- data/lib/hecks/adapters/driving/cli_runner/settling.rb +120 -0
- data/lib/hecks/adapters/driving/cli_runner/streaming.rb +93 -0
- data/lib/hecks/adapters/driving/cli_runner/suggestions.rb +47 -0
- data/lib/hecks/adapters/driving/cli_runner.rb +70 -0
- data/lib/hecks/adapters/driving/command_request.rb +121 -0
- data/lib/hecks/adapters/driving/handle.rb +214 -0
- data/lib/hecks/adapters/driving/json.rb +136 -0
- data/lib/hecks/adapters/driving/launcher_options.rb +267 -0
- data/lib/hecks/adapters/driving/mcp/properties.rb +49 -0
- data/lib/hecks/adapters/driving/mcp/tool_calls.rb +116 -0
- data/lib/hecks/adapters/driving/mcp/tool_definitions/auditing.rb +53 -0
- data/lib/hecks/adapters/driving/mcp/tool_definitions/calling.rb +71 -0
- data/lib/hecks/adapters/driving/mcp/tool_definitions/reading.rb +99 -0
- data/lib/hecks/adapters/driving/mcp/tool_definitions.rb +18 -0
- data/lib/hecks/adapters/driving/mcp.rb +159 -0
- data/lib/hecks/adapters/driving/mcp_guide_cache.rb +78 -0
- data/lib/hecks/adapters/driving/mcp_scope/argument_policy.rb +97 -0
- data/lib/hecks/adapters/driving/mcp_scope/env_problems.rb +69 -0
- data/lib/hecks/adapters/driving/mcp_scope/presenter.rb +83 -0
- data/lib/hecks/adapters/driving/mcp_scope.rb +213 -0
- data/lib/hecks/adapters/driving/newcomer.rb +50 -0
- data/lib/hecks/adapters/driving/ruby/aggregate_module.rb +171 -0
- data/lib/hecks/adapters/driving/ruby/chapter.rb +91 -0
- data/lib/hecks/adapters/driving/ruby.rb +83 -0
- data/lib/hecks/adapters/driving/usage_cache.rb +144 -0
- data/lib/hecks/{doors.rb → adapters/driving.rb} +10 -6
- data/lib/hecks/behaviors/expectations/boot.rb +1 -1
- data/lib/hecks/bench/ruby_runner.rb +1 -1
- data/lib/hecks/bluebook/ask_resolution.rb +130 -0
- data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +8 -2
- data/lib/hecks/bluebook/assembly/contracts/read_models.rb +1 -1
- data/lib/hecks/bluebook/assembly/contracts/rules.rb +4 -2
- data/lib/hecks/bluebook/assembly/contracts/structure.rb +3 -1
- data/lib/hecks/bluebook/assembly/marks.rb +4 -15
- data/lib/hecks/bluebook/assembly/scalars.rb +39 -0
- data/lib/hecks/bluebook/attribute.rb +1 -1
- data/lib/hecks/bluebook/behaviour/command.rb +13 -8
- data/lib/hecks/bluebook/behaviour/policy.rb +30 -0
- data/lib/hecks/bluebook/capabilities/attribute_values.rb +72 -0
- data/lib/hecks/bluebook/capabilities.rb +91 -9
- data/lib/hecks/bluebook/domain_port.rb +16 -4
- data/lib/hecks/bluebook/dsl/adapter_builder.rb +18 -6
- data/lib/hecks/bluebook/dsl/binding_proxy.rb +13 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/computed_sources.rb +98 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/fan_out_rows.rb +42 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/projected_fields.rb +14 -2
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/provisions.rb +69 -3
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/with_projections.rb +17 -10
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +5 -0
- data/lib/hecks/bluebook/dsl/bootstrap_table.rb +2 -0
- data/lib/hecks/bluebook/dsl/command_builder/mutations.rb +8 -1
- data/lib/hecks/bluebook/dsl/command_builder/operands.rb +121 -0
- data/lib/hecks/bluebook/dsl/command_builder.rb +2 -0
- data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +10 -1
- data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +45 -2
- data/lib/hecks/bluebook/dsl/policy_builder.rb +47 -10
- data/lib/hecks/bluebook/dsl/rule_reference.rb +7 -4
- data/lib/hecks/bluebook/dsl/world_builder.rb +1 -1
- data/lib/hecks/bluebook/expression/ast_json/emitters.rb +6 -0
- data/lib/hecks/bluebook/expression/ast_json.rb +9 -6
- data/lib/hecks/bluebook/expression/ast_reader.rb +14 -9
- data/lib/hecks/bluebook/expression/projection.json +36 -0
- data/lib/hecks/bluebook/expression/resolver/operations.rb +31 -0
- data/lib/hecks/bluebook/expression/resolver/parsing.rb +38 -5
- data/lib/hecks/bluebook/expression/resolver/scanning.rb +22 -5
- data/lib/hecks/bluebook/expression/resolver/values.rb +10 -0
- data/lib/hecks/bluebook/expression/resolver.rb +20 -1
- data/lib/hecks/bluebook/hecksagon.rb +23 -3
- data/lib/hecks/bluebook/lifecycle.rb +22 -3
- data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +13 -1
- data/lib/hecks/bluebook/meta_validator/modes.rb +4 -1
- data/lib/hecks/bluebook/meta_validator/readings.rb +24 -1
- data/lib/hecks/bluebook/meta_validator/reconstruction/heads.rb +2 -1
- data/lib/hecks/bluebook/meta_validator/reconstruction.rb +6 -3
- data/lib/hecks/bluebook/meta_validator/shapes.rb +5 -0
- data/lib/hecks/bluebook/meta_validator/verdict_cache.rb +1 -1
- data/lib/hecks/bluebook/meta_validator.rb +12 -12
- data/lib/hecks/bluebook/model_check/ask_checks.rb +71 -0
- data/lib/hecks/bluebook/model_check/policy_checks.rb +2 -1
- data/lib/hecks/bluebook/model_check/reference_checks.rb +70 -0
- data/lib/hecks/bluebook/model_check.rb +8 -2
- data/lib/hecks/bluebook/policy.rb +4 -2
- data/lib/hecks/bluebook/smoke_test.rb +1 -1
- data/lib/hecks/bluebook/synthesizer.rb +2 -0
- data/lib/hecks/bluebook.rb +2 -0
- data/lib/hecks/cli/command_table.rb +1 -1
- data/lib/hecks/cli/console.rb +2 -1
- data/lib/hecks/cli/document.rb +1 -1
- data/lib/hecks/cli/launcher_words.rb +4 -4
- data/lib/hecks/cli/mcp.rb +4 -4
- data/lib/hecks/cli/project_cli/launcher_source.rb +2 -2
- data/lib/hecks/cli/project_cli/templates.rb +5 -5
- data/lib/hecks/cli/project_cli.rb +9 -6
- data/lib/hecks/cli/run.rb +2 -2
- data/lib/hecks/cli/smoke_http/checks.rb +4 -1
- data/lib/hecks/cli/smoke_http/transport.rb +3 -3
- data/lib/hecks/cli/smoke_http.rb +3 -0
- data/lib/hecks/codemod.rb +5 -2
- data/lib/hecks/corpus/routes.rb +7 -0
- data/lib/hecks/corpus/rust.rb +3 -2
- data/lib/hecks/deploy/bluebook/deploy.bluebook +34 -4
- data/lib/hecks/doc/reference/rendering.rb +6 -3
- data/lib/hecks/forms/app/commands.rb +8 -7
- data/lib/hecks/forms/app/queries.rb +2 -1
- data/lib/hecks/forms/app.rb +1 -1
- data/lib/hecks/forms/record_renderer.rb +1 -1
- data/lib/hecks/framework/bluebook/privacy.bluebook +11 -0
- data/lib/hecks/fuzzing/concurrent_dispatch.rb +4 -1
- data/lib/hecks/fuzzing/failure_triage.rb +2 -1
- data/lib/hecks/fuzzing/mutation/run.rb +11 -4
- data/lib/hecks/fuzzing/properties/catalog.rb +6 -4
- data/lib/hecks/fuzzing/properties/guaranteed_by_construction.rb +18 -11
- data/lib/hecks/fuzzing/properties/guards.rb +1 -1
- data/lib/hecks/fuzzing/self_consistency/saga_redelivery.rb +1 -1
- data/lib/hecks/fuzzing/self_consistency.rb +6 -2
- data/lib/hecks/fuzzing/shrinker.rb +3 -1
- data/lib/hecks/fuzzing/value_generator.rb +19 -5
- data/lib/hecks/gate/stages.yml +33 -7
- data/lib/hecks/grammar/evolve.rb +1 -1
- data/lib/hecks/grammar/expression_operators.json +372 -0
- data/lib/hecks/grammar/operators.rb +3 -1
- data/lib/hecks/hecks/adapters/codebase/corpus_tasks.rb +10 -10
- data/lib/hecks/hecks/adapters/codebase/inspection/rubycritic.rb +35 -0
- data/lib/hecks/hecks/adapters/codebase/inspection.rb +104 -0
- data/lib/hecks/hecks/adapters/codebase/publishing.rb +2 -1
- data/lib/hecks/hecks/adapters/codebase/release_facts.rb +12 -2
- data/lib/hecks/hecks/adapters/codebase/source_tree.rb +2 -1
- data/lib/hecks/hecks/adapters/codebase/test_runner.rb +1 -1
- data/lib/hecks/hecks/adapters/cost_explorer.rb +8 -5
- data/lib/hecks/hecks/adapters/deploy_toolchain/statuses.rb +2 -1
- data/lib/hecks/hecks/adapters/finding_github.rb +13 -6
- data/lib/hecks/hecks/adapters/first_admin.rb +2 -2
- data/lib/hecks/hecks/adapters/github_rulesets.rb +6 -3
- data/lib/hecks/hecks/adapters/in_process_boot.rb +1 -1
- data/lib/hecks/hecks/adapters/journal_store/compaction.rb +1 -1
- data/lib/hecks/hecks/adapters/journal_store/edge_audit.rb +10 -20
- data/lib/hecks/hecks/adapters/journal_store/held_domain.rb +28 -5
- data/lib/hecks/hecks/adapters/local_files.rb +2 -2
- data/lib/hecks/hecks/adapters/rehearsal/audit_report.rb +107 -0
- data/lib/hecks/hecks/adapters/rehearsal/census.rb +71 -0
- data/lib/hecks/hecks/adapters/rehearsal/declaration.rb +133 -0
- data/lib/hecks/hecks/adapters/rehearsal/environment.rb +83 -0
- data/lib/hecks/hecks/adapters/rehearsal/inquiry.rb +142 -0
- data/lib/hecks/hecks/adapters/rehearsal/memory_store.rb +96 -0
- data/lib/hecks/hecks/adapters/rehearsal/postgres_census.rb +100 -0
- data/lib/hecks/hecks/adapters/rehearsal/postgres_reading.rb +69 -0
- data/lib/hecks/hecks/adapters/rehearsal/postgres_store.rb +133 -0
- data/lib/hecks/hecks/adapters/rehearsal/rows.rb +41 -0
- data/lib/hecks/hecks/adapters/rehearsal/rust_audit.rb +83 -0
- data/lib/hecks/hecks/adapters/rehearsal/subject.rb +104 -0
- data/lib/hecks/hecks/adapters/rehearsal.rb +54 -0
- data/lib/hecks/hecks/adapters/rehearsal_store.adapter +7 -0
- data/lib/hecks/hecks/adapters/rehearsal_store.rb +81 -0
- data/lib/hecks/hecks/adapters/terminal.rb +13 -11
- data/lib/hecks/hecks/codebase.behaviors +13 -1
- data/lib/hecks/hecks/codebase.bluebook +239 -5
- data/lib/hecks/hecks/custodian.behaviors +24 -6
- data/lib/hecks/hecks/custodian.bluebook +6 -1227
- data/lib/hecks/hecks/deploy.behaviors +1 -1
- data/lib/hecks/hecks/deploy.world +1 -3
- data/lib/hecks/hecks/hecks.behaviors +1 -1
- data/lib/hecks/hecks/hecks.hecksagon +53 -18
- data/lib/hecks/hecks/hecks.world +13 -10
- data/lib/hecks/hecks/rehearsal.bluebook +477 -0
- data/lib/hecks/hecks/site.behaviors +1 -1
- data/lib/hecks/hecks/site.world +0 -1
- data/lib/hecks/hecks/tooling.bluebook +1238 -0
- data/lib/hecks/indifferent_key.rb +20 -0
- data/lib/hecks/language/adapter.bluebook +13 -3
- data/lib/hecks/language/bluebook/aggregate.bluebook +23 -0
- data/lib/hecks/language/bluebook/bluebook.behaviors +23 -0
- data/lib/hecks/language/bluebook/bluebook.bluebook +15 -0
- data/lib/hecks/language/bluebook/entity.bluebook +18 -0
- data/lib/hecks/language/bluebook/policy.behaviors +19 -0
- data/lib/hecks/language/bluebook/policy.bluebook +9 -1
- data/lib/hecks/language/bluebook/query.bluebook +1 -1
- data/lib/hecks/language/bluebook/vocabulary.bluebook +63 -4
- data/lib/hecks/language/hecksagon/domain_port.bluebook +1 -1
- data/lib/hecks/language/hecksagon/hecksagon.bluebook +22 -0
- data/lib/hecks/language/oidc.json +10 -0
- data/lib/hecks/language/port.bluebook +4 -4
- data/lib/hecks/literal.rb +12 -3
- data/lib/hecks/ports/key_vault.rb +7 -2
- data/lib/hecks/ports/persistence/plugins/era/era_check.rb +21 -10
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/boot.rb +4 -2
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +2 -1
- data/lib/hecks/ports/persistence/repository_factory.rb +6 -3
- data/lib/hecks/projection_files/expression_tables.rb +7 -2
- data/lib/hecks/projections/deploy/box/compose.rb +6 -4
- data/lib/hecks/projections/deploy/box/edge.rb +62 -0
- data/lib/hecks/projections/deploy/box/logging.rb +99 -0
- data/lib/hecks/projections/deploy/box/roll_scripts.rb +16 -8
- data/lib/hecks/projections/deploy/box/settings/cdn.rb +40 -0
- data/lib/hecks/projections/deploy/box/settings/logs.rb +40 -0
- data/lib/hecks/projections/deploy/box/settings/patterns.rb +11 -0
- data/lib/hecks/projections/deploy/box/settings/types.rb +16 -1
- data/lib/hecks/projections/deploy/box/settings.rb +6 -2
- data/lib/hecks/projections/deploy/box/stack_yaml.rb +5 -2
- data/lib/hecks/projections/deploy/box/templates/Makefile.tmpl +16 -0
- data/lib/hecks/projections/deploy/box/templates/box.yaml.tmpl +8 -4
- data/lib/hecks/projections/deploy/box/templates/deploy-box.sh.tmpl +32 -0
- data/lib/hecks/projections/deploy/box/templates/deploy-service.sh.tmpl +1 -1
- data/lib/hecks/projections/deploy/box/templates/edge.mk.tmpl +17 -0
- data/lib/hecks/projections/deploy/box/templates/edge.yaml.tmpl +65 -0
- data/lib/hecks/projections/deploy/box/templates/log-group.yaml.tmpl +12 -0
- data/lib/hecks/projections/deploy/box/templates/log-policy.yaml.tmpl +7 -0
- data/lib/hecks/projections/deploy/box/templates/render-compose-taskdef.sh.tmpl +5 -4
- data/lib/hecks/projections/deploy/box/templates/render-compose.sh.tmpl +5 -4
- data/lib/hecks/projections/deploy/box.rb +15 -3
- data/lib/hecks/projections/deploy/preview/preview.sh.erb +1 -1
- data/lib/hecks/projections/deploy/shared.rb +5 -2
- data/lib/hecks/projections/model/deviations.rb +2 -2
- data/lib/hecks/projections/model.rb +2 -2
- data/lib/hecks/projections/oidc.rb +13 -1
- data/lib/hecks/projections/shape.rb +5 -2
- data/lib/hecks/projections/site/cms_editor/attributes.rb +26 -6
- data/lib/hecks/projections/site/cms_editor/blocks.rb +157 -0
- data/lib/hecks/projections/site/cms_editor/checks.rb +14 -1
- data/lib/hecks/projections/site/cms_editor/clearing.rb +70 -0
- data/lib/hecks/projections/site/cms_editor/color.rb +124 -0
- data/lib/hecks/projections/site/cms_editor/composition.rb +42 -0
- data/lib/hecks/projections/site/cms_editor/destructive.rb +61 -0
- data/lib/hecks/projections/site/cms_editor/drafts.rb +102 -0
- data/lib/hecks/projections/site/cms_editor/hints.rb +74 -0
- data/lib/hecks/projections/site/cms_editor/icons.rb +86 -0
- data/lib/hecks/projections/site/cms_editor/key_kinds.rb +31 -0
- data/lib/hecks/projections/site/cms_editor/limits.rb +72 -0
- data/lib/hecks/projections/site/cms_editor/media.rb +1 -1
- data/lib/hecks/projections/site/cms_editor/moment.rb +34 -0
- data/lib/hecks/projections/site/cms_editor/palette.rb +115 -0
- data/lib/hecks/projections/site/cms_editor/pickers.rb +85 -0
- data/lib/hecks/projections/site/cms_editor/preview.rb +91 -0
- data/lib/hecks/projections/site/cms_editor/relations.rb +92 -0
- data/lib/hecks/projections/site/cms_editor/scale_checks.rb +66 -0
- data/lib/hecks/projections/site/cms_editor/scheduling.rb +150 -0
- data/lib/hecks/projections/site/cms_editor/schema.rb +96 -19
- data/lib/hecks/projections/site/cms_editor/setting.rb +52 -9
- data/lib/hecks/projections/site/cms_editor/targets.rb +86 -0
- data/lib/hecks/projections/site/cms_editor/templates/package.json.tmpl +18 -1
- data/lib/hecks/projections/site/cms_editor/templates/src/app.ts.tmpl +251 -57
- data/lib/hecks/projections/site/cms_editor/templates/src/assets.ts.tmpl +98 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/auth/membership.ts.tmpl +32 -24
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/app.css.tmpl +412 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/autosave.js.tmpl +144 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/blocks.js.tmpl +500 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/body_doc.js.tmpl +175 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/body_editor.js.tmpl +418 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/epoch.js.tmpl +61 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/forms.js.tmpl +210 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/lists.js.tmpl +40 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/main.js.tmpl +26 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/media_picker.js.tmpl +232 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/moments.js.tmpl +73 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/pickers.js.tmpl +152 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/preview.js.tmpl +98 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/shell.js.tmpl +140 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/toast.js.tmpl +66 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/choices.ts.tmpl +99 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/commands.ts.tmpl +78 -24
- data/lib/hecks/projections/site/cms_editor/templates/src/config.ts.tmpl +6 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/flash.ts.tmpl +52 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/host.ts.tmpl +19 -2
- data/lib/hecks/projections/site/cms_editor/templates/src/media/handler.ts.tmpl +31 -8
- data/lib/hecks/projections/site/cms_editor/templates/src/names.ts.tmpl +36 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/schema.ts.tmpl +131 -2
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/availability.ts.tmpl +15 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/block_list.js.tmpl +213 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/blocks.ts.tmpl +275 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/body_model.js.tmpl +8 -5
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/detail.ts.tmpl +88 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/dialogs.ts.tmpl +43 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/fields.ts.tmpl +229 -34
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/html.ts.tmpl +40 -81
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/icons.ts.tmpl +15 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/input.ts.tmpl +29 -12
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/links.ts.tmpl +100 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/moments.ts.tmpl +44 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/outline.ts.tmpl +53 -17
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/pages.ts.tmpl +178 -88
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/paging.ts.tmpl +82 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/pickers.ts.tmpl +110 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/preview.ts.tmpl +87 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/related.ts.tmpl +97 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/schedule.ts.tmpl +160 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/shell.ts.tmpl +211 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/table.ts.tmpl +151 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/theme.js.tmpl +16 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/values.ts.tmpl +69 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/words.ts.tmpl +97 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/world.ts.tmpl +35 -0
- data/lib/hecks/projections/site/cms_editor/templates/tsconfig.json.tmpl +2 -1
- data/lib/hecks/projections/site/cms_editor/theme.rb +29 -0
- data/lib/hecks/projections/site/cms_editor/theme_checks.rb +57 -0
- data/lib/hecks/projections/site/cms_editor.rb +49 -23
- data/lib/hecks/projections/site/role_probe.rb +2 -0
- data/lib/hecks/projections/site/site_root/workflow.rb +5 -0
- data/lib/hecks/projector/cli_audience.rb +22 -1
- data/lib/hecks/projector/cli_projector/listing.rb +1 -1
- data/lib/hecks/projector/cli_projector/option_specs.rb +1 -1
- data/lib/hecks/projector/cli_projector/usage.rb +15 -4
- data/lib/hecks/projector/docs_projector/closing.rb +1 -1
- data/lib/hecks/projector/docs_projector.rb +1 -1
- data/lib/hecks/projector/exporter/bindings.rb +40 -10
- data/lib/hecks/projector/exporter/capability_values.rb +55 -0
- data/lib/hecks/projector/narrate_projector/reactions.rb +1 -1
- data/lib/hecks/projector/target.rb +11 -0
- data/lib/hecks/projector.rb +32 -5
- data/lib/hecks/quality_control/adapters/github_checks.rb +12 -8
- data/lib/hecks/quality_control/adapters/github_issues.rb +8 -4
- data/lib/hecks/quality_control/cli/qa_open_pr.rb +2 -2
- data/lib/hecks/quality_control/cli/qa_sweep/checks/shrinking.rb +1 -1
- data/lib/hecks/quality_control/cli/qa_sweep/finding_report.rb +1 -1
- data/lib/hecks/quality_control/cli/qa_sweep.rb +1 -1
- data/lib/hecks/quality_control/quality_control.bluebook +6 -2
- data/lib/hecks/release/approval.rb +64 -0
- data/lib/hecks/router/{door.rb → aggregate_reader.rb} +5 -4
- data/lib/hecks/router/namespace_installer.rb +16 -16
- data/lib/hecks/router.rb +1 -1
- data/lib/hecks/runtime/best_effort.rb +22 -0
- data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +12 -2
- data/lib/hecks/runtime/command_interpreter.rb +3 -2
- data/lib/hecks/runtime/command_rules/emission.rb +1 -1
- data/lib/hecks/runtime/dispatcher.rb +4 -4
- data/lib/hecks/runtime/entity_element/location.rb +1 -1
- data/lib/hecks/runtime/event.rb +5 -0
- data/lib/hecks/runtime/identity.rb +7 -6
- data/lib/hecks/runtime/interpreting.rb +2 -1
- data/lib/hecks/runtime/invocation_builder.rb +1 -1
- data/lib/hecks/runtime/loader/boot_steps.rb +8 -5
- data/lib/hecks/runtime/loader.rb +10 -10
- data/lib/hecks/runtime/policy_interpreter/arguments.rb +7 -4
- data/lib/hecks/runtime/policy_interpreter/fan_out.rb +3 -3
- data/lib/hecks/runtime/policy_interpreter.rb +6 -6
- data/lib/hecks/runtime/port_operation_interpreter.rb +1 -1
- data/lib/hecks/runtime/reaction_invocation.rb +1 -1
- data/lib/hecks/runtime/rebuild_sweep.rb +11 -1
- data/lib/hecks/runtime/registry/ask_verification.rb +35 -0
- data/lib/hecks/runtime/registry/hecksagon_rules.rb +10 -0
- data/lib/hecks/runtime/registry/merging.rb +1 -1
- data/lib/hecks/runtime/registry/providers.rb +16 -0
- data/lib/hecks/runtime/registry/read_repository.rb +6 -4
- data/lib/hecks/runtime/registry/verification.rb +4 -1
- data/lib/hecks/runtime/registry/world_defaults.rb +29 -0
- data/lib/hecks/runtime/registry.rb +1 -1
- data/lib/hecks/runtime/saga_interpreter/compensation.rb +1 -1
- data/lib/hecks/runtime/saga_interpreter/delivery.rb +4 -4
- data/lib/hecks/runtime/saga_interpreter/transitions.rb +1 -1
- data/lib/hecks/runtime/saga_interpreter.rb +3 -3
- data/lib/hecks/runtime/tenant_check.rb +5 -4
- data/lib/hecks/runtime/value/coercion.rb +2 -2
- data/lib/hecks/runtime/value/validation.rb +16 -4
- data/lib/hecks/runtime.rb +9 -9
- data/lib/hecks/rust_build/host.rb +11 -4
- data/lib/hecks/rust_build/prebuilt_binary.rb +101 -0
- data/lib/hecks/rust_build/project_rust/target_ir.rb +1 -1
- data/lib/hecks/rust_build/wasm.rb +1 -1
- data/lib/hecks/rust_build/wasm_browser.rb +1 -1
- data/lib/hecks/rust_build.rb +11 -0
- data/lib/hecks/served_options.rb +53 -0
- data/lib/hecks/site/bluebook/site.bluebook +1 -0
- data/lib/hecks/storehouse/audit.rb +1 -1
- data/lib/hecks/storehouse/dispatching.rb +8 -6
- data/lib/hecks/storehouse/introspection.rb +2 -2
- data/lib/hecks/storehouse/querying.rb +6 -4
- data/lib/hecks/storehouse.rb +4 -4
- data/lib/hecks/tools/ci_gate_decision.rb +35 -0
- data/lib/hecks/tools/ci_gates.rb +20 -1
- data/lib/hecks/tools/comment_style/source_file.rb +4 -1
- data/lib/hecks/tools/deploy_recipe_lint/fixtures.rb +4 -1
- data/lib/hecks/tools/lanes/files.rb +8 -0
- data/lib/hecks/tools/lanes/prebuilt_workflow.rb +81 -0
- data/lib/hecks/tools/lanes/rows.rb +6 -0
- data/lib/hecks/tools/lanes.rb +1 -0
- data/lib/hecks/tools/oidc_manifests.rb +4 -5
- data/lib/hecks/tools/regeneration_run.rb +11 -4
- data/lib/hecks/tools/release_only.rb +111 -0
- data/lib/hecks/tools/site_routes/editor_files.rb +12 -5
- data/lib/hecks/tools/tenant_provisioning.rb +2 -2
- data/lib/hecks/tools/tools_doc.rb +4 -4
- data/lib/hecks/version.rb +1 -1
- data/lib/hecks/vocabulary.rb +19 -5
- data/lib/hecks.rb +15 -15
- data/lib/rubocop/cop/hecks/env_dump.rb +69 -0
- data/lib/rubocop/cop/hecks/monotonic_duration.rb +53 -0
- data/lib/rubocop/cop/hecks/no_wall_clock_in_runtime.rb +34 -0
- data/lib/rubocop/cop/hecks/raw_shell_interpolation.rb +79 -0
- data/lib/rubocop/cop/hecks/sleep_in_spec.rb +34 -0
- data/lib/rubocop/cop/hecks/swallowed_rescue.rb +37 -0
- data/lib/rubocop/cop/hecks/symbol_string_key_mix.rb +50 -0
- data/lib/rubocop/cop/hecks/untyped_raise.rb +37 -0
- data/prebuilt/9ee54e2f0d4d6d3fe046827779b221e02de665fba911a048ae5dd8b8fbfb7d90.marshal +0 -0
- data/prebuilt/d74a00e996222c1d8b676d5959092effc46b4dc59e0555f3bf9554ac58e3094a.marshal +0 -0
- data/prebuilt/verdicts-df19f35868d3284a70f55e42dcef87ef4e65e6a678e5135f72e1f6cff4c1357b.json +1 -0
- data/rust/.gitignore +6 -0
- data/rust/Cargo.toml +6 -0
- data/rust/build/src/binding_pass.rs +103 -0
- data/rust/build/src/cargo_sync.rs +6 -0
- data/rust/build/src/lineage_pass.rs +3 -3
- data/rust/build/src/main.rs +17 -5
- data/rust/build/src/pipeline.rs +48 -5
- data/rust/build/src/seams_pass.rs +123 -0
- data/rust/build/src/translation_pass.rs +167 -0
- data/rust/codegen/src/asks.rs +103 -0
- data/rust/codegen/src/commands.rs +13 -8
- data/rust/codegen/src/constraints.rs +25 -0
- data/rust/codegen/src/domain_generator.rs +2 -0
- data/rust/codegen/src/expr_emitter.rs +13 -0
- data/rust/codegen/src/json_codec.rs +54 -15
- data/rust/codegen/src/main.rs +1 -0
- data/rust/codegen/src/mutations.rs +128 -3
- data/rust/codegen/src/queries.rs +11 -2
- data/rust/codegen/src/reactions.rs +1 -1
- data/rust/codegen/src/types.rs +166 -8
- data/rust/host/HECKS_RELEASE +1 -1
- data/rust/host/src/api.rs +4 -4
- data/rust/host/src/bin/validate_harness.rs +43 -0
- data/rust/host/src/boundary_fuzz/expr_json.rs +2 -2
- data/rust/host/src/boundary_fuzz/ir.rs +1 -0
- data/rust/host/src/boundary_fuzz/server.rs +1 -1
- data/rust/host/src/checkout.rs +35 -19
- data/rust/host/src/commerce_ir.rs +408 -2
- data/rust/host/src/expr_json.rs +118 -0
- data/rust/host/src/extension.rs +13 -1
- data/rust/host/src/lib.rs +1 -0
- data/rust/host/src/mint.rs +1 -1
- data/rust/host/src/payments/tests.rs +27 -1
- data/rust/host/src/payments.rs +12 -4
- data/rust/host/src/platform_signin/attack_tests.rs +1100 -0
- data/rust/host/src/platform_signin/config.rs +512 -0
- data/rust/host/src/platform_signin/cookie.rs +237 -0
- data/rust/host/src/platform_signin/extension.rs +190 -0
- data/rust/host/src/platform_signin/fetcher.rs +322 -0
- data/rust/host/src/platform_signin/handler.rs +251 -0
- data/rust/host/src/platform_signin/handler_tests.rs +554 -0
- data/rust/host/src/platform_signin/jti.rs +196 -0
- data/rust/host/src/platform_signin/jwks.rs +542 -0
- data/rust/host/src/platform_signin/jws.rs +249 -0
- data/rust/host/src/platform_signin/known_answer_tests.rs +237 -0
- data/rust/host/src/platform_signin/mapping_tests.rs +254 -0
- data/rust/host/src/platform_signin/mod.rs +75 -0
- data/rust/host/src/platform_signin/mode_tests.rs +382 -0
- data/rust/host/src/platform_signin/pages.rs +204 -0
- data/rust/host/src/platform_signin/query.rs +233 -0
- data/rust/host/src/platform_signin/session.rs +151 -0
- data/rust/host/src/platform_signin/settings.rs +385 -0
- data/rust/host/src/platform_signin/strict_json.rs +351 -0
- data/rust/host/src/platform_signin/test_support.rs +235 -0
- data/rust/host/src/platform_signin/ttl_tests.rs +94 -0
- data/rust/host/src/platform_signin/verify.rs +604 -0
- data/rust/host/src/platform_signin/wiring_support.rs +319 -0
- data/rust/host/src/query_step.rs +22 -4
- data/rust/host/src/reference_validate.rs +653 -108
- data/rust/host/src/resend.rs +2 -0
- data/rust/host/src/server.rs +19 -6
- data/rust/host/src/ui_schema.rs +132 -5
- data/rust/host/src/web/newsletter.rs +7 -8
- data/rust/host/src/web/newsletter_send.rs +38 -13
- data/rust/host/src/web/registrations.rs +229 -26
- data/rust/host/src/web.rs +53 -9
- data/rust/parser/src/emit.rs +38 -6
- data/rust/parser/src/expr/ast_json.rs +7 -1
- data/rust/parser/src/expr/resolver.rs +171 -6
- data/rust/parser/src/ir.rs +7 -0
- data/rust/parser/src/keywords.rs +24 -0
- data/rust/parser/src/main.rs +3 -0
- data/rust/parser/src/parse/aggregate.rs +2 -1
- data/rust/parser/src/parse/chapter.rs +2 -2
- data/rust/parser/src/parse/command.rs +2 -0
- data/rust/parser/src/parse/hecksagon.rs +5 -2
- data/rust/parser/src/parse/lifecycle.rs +81 -0
- data/rust/parser/src/parse/mod.rs +15 -1
- data/rust/parser/src/parse/policy.rs +13 -2
- data/rust/parser/src/parse/value_object.rs +34 -17
- data/rust/parser/src/ruby_value.rs +1 -1
- data/rust/src/exemplar/commands.rs +4 -4
- data/rust/src/exemplar/constraints.rs +1 -1
- data/rust/src/exemplar/json.rs +43 -1
- data/rust/src/kernel/cli.rs +7 -5
- data/rust/src/kernel/dispatch.rs +2 -2
- data/rust/src/kernel/dispatch_guard_tests.rs +1 -1
- data/rust/src/kernel/expr.rs +66 -3
- data/rust/src/kernel/expression_operators/arithmetic.rs +130 -5
- data/rust/src/kernel/expression_operators/text.rs +26 -2
- data/rust/src/kernel/json.rs +15 -0
- data/rust/src/kernel/mod.rs +1 -1
- data/rust/src/kernel/orchestrate.rs +54 -5
- data/rust/src/kernel/orchestrate_guard_tests.rs +67 -0
- data/rust/src/kernel/pattern.rs +60 -0
- data/rust/src/kernel/reference_lookup.rs +90 -7
- metadata +178 -38
- data/lib/hecks/doors/cli_door/nesting.rb +0 -34
- data/lib/hecks/doors/cli_door/shorthand.rb +0 -85
- data/lib/hecks/doors/cli_door.rb +0 -124
- data/lib/hecks/doors/cli_runner/answers.rb +0 -138
- data/lib/hecks/doors/cli_runner/resolution.rb +0 -146
- data/lib/hecks/doors/cli_runner/settling.rb +0 -115
- data/lib/hecks/doors/cli_runner/streaming.rb +0 -90
- data/lib/hecks/doors/cli_runner/suggestions.rb +0 -43
- data/lib/hecks/doors/cli_runner.rb +0 -66
- data/lib/hecks/doors/command_request.rb +0 -119
- data/lib/hecks/doors/handle.rb +0 -208
- data/lib/hecks/doors/json_door.rb +0 -132
- data/lib/hecks/doors/launcher_options.rb +0 -247
- data/lib/hecks/doors/mcp_door/properties.rb +0 -47
- data/lib/hecks/doors/mcp_door/tool_calls.rb +0 -113
- data/lib/hecks/doors/mcp_door/tool_definitions/auditing.rb +0 -51
- data/lib/hecks/doors/mcp_door/tool_definitions/calling.rb +0 -69
- data/lib/hecks/doors/mcp_door/tool_definitions/reading.rb +0 -97
- data/lib/hecks/doors/mcp_door/tool_definitions.rb +0 -15
- data/lib/hecks/doors/mcp_door.rb +0 -156
- data/lib/hecks/doors/mcp_door_scope/argument_policy.rb +0 -92
- data/lib/hecks/doors/mcp_door_scope/env_problems.rb +0 -55
- data/lib/hecks/doors/mcp_door_scope/presenter.rb +0 -78
- data/lib/hecks/doors/mcp_door_scope.rb +0 -201
- data/lib/hecks/doors/mcp_guide_cache.rb +0 -75
- data/lib/hecks/doors/ruby_door/aggregate_door.rb +0 -162
- data/lib/hecks/doors/ruby_door/chapter.rb +0 -89
- data/lib/hecks/doors/ruby_door.rb +0 -80
- data/lib/hecks/doors/usage_cache.rb +0 -139
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/body_widget.js.tmpl +0 -282
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/media_picker.js.tmpl +0 -109
- data/prebuilt/c28d6d9db14eea3e17161e9d9c262efee30b256cf97693a7cfd552bce24b2f7f.marshal +0 -0
- data/prebuilt/cb375cba61ca0dbe8ddb9739c306510fe05e5f4b7a9b6955caff8224c63ea0e0.marshal +0 -0
- data/prebuilt/verdicts-d6d584ad43b5f3cebf88aafbbdbf024c38574acf18e06adffbc555f7786b1c2f.json +0 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: beba8cd60d4c859286fa1121e3b382cc63e826e010dfd336714befa036dfad94
|
|
4
|
+
data.tar.gz: 16deb6ba2dd98c8d09385e77a9773f92ef12726d097e71601d2e3cfdbb83ae00
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fe730368d2f8942c67a5510c5b8344bdad86f9aa0990515903e147da4fe71fbc6f17880ea2a1b26de4ffa0d24ad20c416455df58ee8a66617e1f832b2637e2b0
|
|
7
|
+
data.tar.gz: a41080c78fc7b1e9d43347fd4b965d6811c246baee7072214c5f7895564eccc94ce699b86bc739de0f3d7d7830fb8057e6bf2e0699496e201ffd057c7e6a39d5
|
|
@@ -35,6 +35,8 @@ Hecks.bluebook "Pizzas" do
|
|
|
35
35
|
attribute :value, String, pattern: '[^ \t\n\r]'
|
|
36
36
|
|
|
37
37
|
invariant("a topping is named") { !value.to_s.empty? }
|
|
38
|
+
# The pattern lets a form feed through; `.strip` is what sees past it.
|
|
39
|
+
invariant("a topping name is more than whitespace") { !value.to_s.strip.empty? }
|
|
38
40
|
end
|
|
39
41
|
|
|
40
42
|
value_object "ToppingAmount" do
|
|
@@ -69,6 +71,33 @@ Hecks.bluebook "Pizzas" do
|
|
|
69
71
|
order_by :name
|
|
70
72
|
end
|
|
71
73
|
|
|
74
|
+
# No `where`: every order answers, by identity when nothing orders them.
|
|
75
|
+
query "Everything" do
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Where-less and ordered. Equal prices keep identity order; the nested path reaches the cents.
|
|
79
|
+
query "ByPrice" do
|
|
80
|
+
order_by :"pizza.price_cents.cents"
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
query "ByPriceDescending" do
|
|
84
|
+
order_by :"pizza.price_cents.cents", :desc
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# `customer_name` is unset until a purchase, so these show where an unset value sorts.
|
|
88
|
+
query "ByCustomer" do
|
|
89
|
+
order_by :"customer_name.value"
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
query "ByCustomerDescending" do
|
|
93
|
+
order_by :"customer_name.value", :desc
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
query "ByCustomerUnsetLast" do
|
|
97
|
+
order_by :"customer_name.value"
|
|
98
|
+
nulls :last
|
|
99
|
+
end
|
|
100
|
+
|
|
72
101
|
# Both price queries reach through the nested Pizza value object with a dotted path.
|
|
73
102
|
query "CostingLessThan" do
|
|
74
103
|
attribute :ceiling, Price
|
|
@@ -4,6 +4,13 @@ Hecks.hecksagon "Pizzas" do
|
|
|
4
4
|
attaches "Governance"
|
|
5
5
|
Pizzas::Order.persisted_by("Memory")
|
|
6
6
|
|
|
7
|
+
# Every way in the example is named: the console (Ruby), `hecks run` (Cli), the forms and
|
|
8
|
+
# storehouse reader (Json) and `hecks mcp` (Mcp). An adapter left out would refuse the domain.
|
|
9
|
+
driven_by "Ruby"
|
|
10
|
+
driven_by "Cli"
|
|
11
|
+
driven_by "Json"
|
|
12
|
+
driven_by "Mcp"
|
|
13
|
+
|
|
7
14
|
# The primary port: an outside adapter (a payment webhook) translates an external fact into
|
|
8
15
|
# our vocabulary; business rules stay on Purchase, reached via OnPizzaPaymentReceived.
|
|
9
16
|
Pizzas::Order.port "PaymentGateway" do
|
data/exe/hecks
CHANGED
|
@@ -41,19 +41,19 @@ rescue StandardError => e
|
|
|
41
41
|
abort "cannot open Hecks: #{e.message.lines.first.strip}"
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
-
text, status, reason = Hecks::
|
|
44
|
+
text, status, reason = Hecks::Adapters::Driving::CliRunner.usage(
|
|
45
45
|
runtime: described, argv: ARGV, program: program
|
|
46
46
|
)
|
|
47
47
|
unless text
|
|
48
48
|
runtime = begin
|
|
49
|
-
Hecks::
|
|
49
|
+
Hecks::Adapters::Driving::LauncherOptions.quietly(hold: MEMORY_COMMANDS.include?(ARGV.first.to_s.chomp("!"))) { Hecks.boot_described(described, install_driving: false) }
|
|
50
50
|
rescue StandardError => e
|
|
51
51
|
abort "cannot open Hecks: #{e.message.lines.first.strip}"
|
|
52
52
|
end
|
|
53
53
|
# A question the world lists under `streams`, given `--stream`, tails until interrupted.
|
|
54
|
-
streamed = Hecks::
|
|
54
|
+
streamed = Hecks::Adapters::Driving::CliRunner.stream(runtime: runtime, argv: ARGV, program: program)
|
|
55
55
|
exit streamed unless streamed.nil?
|
|
56
|
-
text, status, reason = Hecks::
|
|
56
|
+
text, status, reason = Hecks::Adapters::Driving::CliRunner.call(
|
|
57
57
|
runtime: runtime, argv: ARGV, program: program
|
|
58
58
|
)
|
|
59
59
|
end
|
|
@@ -42,7 +42,7 @@ module Hecks
|
|
|
42
42
|
@aggregate = aggregate
|
|
43
43
|
@db = connect(settings)
|
|
44
44
|
# Saga rows are scoped by domain; one D1 database per domain, so aggregates share it.
|
|
45
|
-
@domain =
|
|
45
|
+
@domain = settings.fetch(:domain) { aggregate.name }.to_s
|
|
46
46
|
|
|
47
47
|
# No PRAGMA synchronous: D1 is managed and its query endpoint disallows PRAGMA writes.
|
|
48
48
|
create_aggregate_table!
|
|
@@ -100,7 +100,7 @@ module Hecks
|
|
|
100
100
|
|
|
101
101
|
# The settings are read under a Symbol or a String key; each credential is required.
|
|
102
102
|
def connect(settings)
|
|
103
|
-
credentials = %w[account_id database_id api_token].to_h { |name| [name,
|
|
103
|
+
credentials = %w[account_id database_id api_token].to_h { |name| [name, settings[name.to_sym]] }
|
|
104
104
|
credentials.each do |name, value|
|
|
105
105
|
raise Runtime::WiringError, "D1 needs a #{name.inspect} in its world settings" if value.to_s.empty?
|
|
106
106
|
end
|
|
@@ -109,14 +109,6 @@ module Hecks
|
|
|
109
109
|
api_token: credentials["api_token"])
|
|
110
110
|
end
|
|
111
111
|
|
|
112
|
-
# A setting read under its Symbol key, then its String key, then `default`.
|
|
113
|
-
def setting(settings, key, default)
|
|
114
|
-
return settings[key] if settings.key?(key)
|
|
115
|
-
return settings[key.to_s] if settings.key?(key.to_s)
|
|
116
|
-
|
|
117
|
-
default
|
|
118
|
-
end
|
|
119
|
-
|
|
120
112
|
# The batch's first statement: what the put will do, decided against the current row.
|
|
121
113
|
def status_statement(entry, insert_only)
|
|
122
114
|
outcome = insert_only ? "conflicted" : "replaced"
|
|
@@ -39,7 +39,7 @@ module Hecks
|
|
|
39
39
|
@journal_path = "#{@path}.journal"
|
|
40
40
|
@events = []
|
|
41
41
|
# Saga scope; falls back to the aggregate's name for a directly built adapter.
|
|
42
|
-
@domain =
|
|
42
|
+
@domain = settings.fetch(:domain) { aggregate.name }.to_s
|
|
43
43
|
FileUtils.mkdir_p(File.dirname(@path))
|
|
44
44
|
end
|
|
45
45
|
|
|
@@ -179,22 +179,12 @@ module Hecks
|
|
|
179
179
|
replay_journal(snapshot)
|
|
180
180
|
end
|
|
181
181
|
|
|
182
|
-
# `dir: :default` means no setting; a Symbol would make `File.join` raise TypeError.
|
|
183
182
|
def resolve_path(settings, root)
|
|
184
|
-
declared =
|
|
185
|
-
declared = "data" if declared == :default
|
|
183
|
+
declared = settings[:dir]
|
|
186
184
|
dir = declared.start_with?("/") ? declared : File.join(root || Dir.pwd, declared)
|
|
187
185
|
|
|
188
186
|
File.join(dir, "#{@aggregate.storage_name}.heki")
|
|
189
187
|
end
|
|
190
|
-
|
|
191
|
-
# A setting read under its Symbol key, then its String key, then `default`.
|
|
192
|
-
def setting(settings, key, default)
|
|
193
|
-
return settings[key] if settings.key?(key)
|
|
194
|
-
return settings[key.to_s] if settings.key?(key.to_s)
|
|
195
|
-
|
|
196
|
-
default
|
|
197
|
-
end
|
|
198
188
|
end
|
|
199
189
|
end
|
|
200
190
|
end
|
|
@@ -25,10 +25,10 @@ module Hecks
|
|
|
25
25
|
# to resolve which function to call; nil falls further back to `domain`
|
|
26
26
|
def initialize(aggregate:, settings: {}, root: nil)
|
|
27
27
|
@aggregate = aggregate
|
|
28
|
-
domain =
|
|
29
|
-
region =
|
|
28
|
+
domain = settings.fetch(:domain) { aggregate.name }
|
|
29
|
+
region = settings[:region]
|
|
30
30
|
# Explicit function name, for deployments whose function is not `hecks-<domain>`.
|
|
31
|
-
function =
|
|
31
|
+
function = settings[:function]
|
|
32
32
|
# `domain` only prefixes the instances lookup; the function to call is named by
|
|
33
33
|
# DOMAIN_NAME (set in a deployed Lambda, where root is always /var/task), else by
|
|
34
34
|
# root's basename, which matches hecks deploy recipe.project's stack name on a local boot.
|
|
@@ -75,21 +75,6 @@ module Hecks
|
|
|
75
75
|
Ports::Query::InMemory.execute(instances.values, specification, args)
|
|
76
76
|
end
|
|
77
77
|
|
|
78
|
-
# Reads a world setting under either a Symbol or a String key, with a fallback.
|
|
79
|
-
#
|
|
80
|
-
# Settings arrive symbol-keyed from the DSL and string-keyed from a round-tripped export.
|
|
81
|
-
#
|
|
82
|
-
# @param settings [Hash] the world settings Hash to read from
|
|
83
|
-
# @param key [Symbol] the setting name, tried as itself and as `key.to_s`
|
|
84
|
-
# @param fallback [Object] the value to return when neither key is present
|
|
85
|
-
# @return [Object] the setting's value, or `fallback` when absent
|
|
86
|
-
def setting(settings, key, fallback)
|
|
87
|
-
return settings[key] if settings.key?(key)
|
|
88
|
-
return settings[key.to_s] if settings.key?(key.to_s)
|
|
89
|
-
|
|
90
|
-
fallback
|
|
91
|
-
end
|
|
92
|
-
|
|
93
78
|
private
|
|
94
79
|
|
|
95
80
|
# Never memoized: the adapter outlives requests on a warm container, so a cached read
|
|
@@ -18,6 +18,7 @@ require_relative "postgres/outbox"
|
|
|
18
18
|
require_relative "postgres/reconnect"
|
|
19
19
|
require_relative "postgres/shared_connection"
|
|
20
20
|
require_relative "../../runtime/instance"
|
|
21
|
+
require_relative "../../indifferent_key"
|
|
21
22
|
|
|
22
23
|
module Hecks
|
|
23
24
|
module Adapters
|
|
@@ -57,7 +58,7 @@ module Hecks
|
|
|
57
58
|
# @raise [LoadError] if the `pg` gem is not installed
|
|
58
59
|
def self.connect_for(name, settings)
|
|
59
60
|
require_pg(name)
|
|
60
|
-
declared =
|
|
61
|
+
declared = IndifferentKey.read(settings, :database)
|
|
61
62
|
refuse_undeclared(name, declared)
|
|
62
63
|
configure(open_connection(declared), settings)
|
|
63
64
|
rescue StandardError => e
|
|
@@ -95,7 +96,7 @@ module Hecks
|
|
|
95
96
|
# PostgresEra's own: a schema/table that already exists is the ordinary case on every
|
|
96
97
|
# boot after the first, not news.
|
|
97
98
|
def self.configure(connection, settings)
|
|
98
|
-
schema =
|
|
99
|
+
schema = IndifferentKey.read(settings, :schema)
|
|
99
100
|
connection.exec("SET search_path TO #{connection.quote_ident(schema)}") if schema.to_s != ""
|
|
100
101
|
connection.exec("SET client_min_messages = warning")
|
|
101
102
|
connection
|
|
@@ -120,7 +121,7 @@ module Hecks
|
|
|
120
121
|
@db = PostgresSharedConnection.for(aggregate.name, settings, connector: self.class)
|
|
121
122
|
# Scopes saga rows; falls back to the aggregate's storage name when
|
|
122
123
|
# settings gives no domain (e.g. a directly-instantiated adapter).
|
|
123
|
-
@domain =
|
|
124
|
+
@domain = settings.fetch(:domain) { aggregate.storage_name }.to_s
|
|
124
125
|
create_tables!
|
|
125
126
|
end
|
|
126
127
|
|
|
@@ -139,14 +140,6 @@ module Hecks
|
|
|
139
140
|
create_outbox_table!
|
|
140
141
|
create_checkpoint_table!
|
|
141
142
|
end
|
|
142
|
-
|
|
143
|
-
# A setting read under its Symbol key, then its String key, then `default`.
|
|
144
|
-
def setting(settings, key, default)
|
|
145
|
-
return settings[key] if settings.key?(key)
|
|
146
|
-
return settings[key.to_s] if settings.key?(key.to_s)
|
|
147
|
-
|
|
148
|
-
default
|
|
149
|
-
end
|
|
150
143
|
end
|
|
151
144
|
end
|
|
152
145
|
end
|
|
@@ -60,7 +60,7 @@ module Hecks
|
|
|
60
60
|
@aggregate = aggregate
|
|
61
61
|
@path = resolve_path(settings, root)
|
|
62
62
|
# Scopes saga rows; falls back to the aggregate's name for a directly built adapter.
|
|
63
|
-
@domain =
|
|
63
|
+
@domain = settings.fetch(:domain) { aggregate.name }.to_s
|
|
64
64
|
open_database
|
|
65
65
|
create_tables!
|
|
66
66
|
end
|
|
@@ -106,16 +106,8 @@ module Hecks
|
|
|
106
106
|
create_checkpoint_table!
|
|
107
107
|
end
|
|
108
108
|
|
|
109
|
-
# A setting read under its Symbol key, then its String key, then `default`.
|
|
110
|
-
def setting(settings, key, default)
|
|
111
|
-
return settings[key] if settings.key?(key)
|
|
112
|
-
return settings[key.to_s] if settings.key?(key.to_s)
|
|
113
|
-
|
|
114
|
-
default
|
|
115
|
-
end
|
|
116
|
-
|
|
117
109
|
def resolve_path(settings, root)
|
|
118
|
-
declared =
|
|
110
|
+
declared = settings[:database]
|
|
119
111
|
return declared if declared.start_with?("/")
|
|
120
112
|
|
|
121
113
|
File.join(root || Dir.pwd, declared)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
require_relative "../../bluebook/hecksagon"
|
|
2
|
+
|
|
3
|
+
module Hecks
|
|
4
|
+
module Adapters
|
|
5
|
+
module Driving
|
|
6
|
+
# Which driving adapters a hecksagon may name with `driven_by`, and the refusal an adapter
|
|
7
|
+
# gets from a domain that left it out.
|
|
8
|
+
#
|
|
9
|
+
# A domain that declares no `driven_by` is open to every adapter. One that declares any is
|
|
10
|
+
# reached through those, and each adapter it omits refuses the domain.
|
|
11
|
+
module Admission
|
|
12
|
+
# The driving adapters a hecksagon can admit.
|
|
13
|
+
ADAPTERS = Bluebook::Hecksagon::DRIVING_ADAPTERS
|
|
14
|
+
|
|
15
|
+
# Raised by an adapter that a domain's hecksagon left out of `driven_by`.
|
|
16
|
+
class Refused < StandardError; end
|
|
17
|
+
|
|
18
|
+
module_function
|
|
19
|
+
|
|
20
|
+
# The sentence a domain gives an adapter it did not admit.
|
|
21
|
+
#
|
|
22
|
+
# @param registry [Runtime::Registry] the booted registry, whose hecksagons are asked
|
|
23
|
+
# @param adapter [String] the adapter reaching in, one of `ADAPTERS`
|
|
24
|
+
# @return [String, nil] the refusal, or nil when every domain admits `adapter`
|
|
25
|
+
def refusal(registry, adapter)
|
|
26
|
+
omitting = registry.hecksagons.values.find { |hecksagon| !hecksagon.driven_by?(adapter) }
|
|
27
|
+
return unless omitting
|
|
28
|
+
|
|
29
|
+
"#{omitting.domain} is not driven by #{adapter}: its hecksagon admits only " \
|
|
30
|
+
"#{omitting.driving.join(", ")} (driven_by)"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Raises when a domain in `registry` did not admit `adapter`.
|
|
34
|
+
#
|
|
35
|
+
# @param registry [Runtime::Registry] the booted registry
|
|
36
|
+
# @param adapter [String] the adapter reaching in, one of `ADAPTERS`
|
|
37
|
+
# @return [void]
|
|
38
|
+
# @raise [Refused] with the domain's sentence
|
|
39
|
+
def admit!(registry, adapter)
|
|
40
|
+
sentence = refusal(registry, adapter)
|
|
41
|
+
raise Refused, sentence if sentence
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module Hecks
|
|
2
|
+
module Adapters
|
|
3
|
+
module Driving
|
|
4
|
+
module Cli
|
|
5
|
+
# Sets values into the nested argument Hash a dotted path names, creating the intermediate
|
|
6
|
+
# Hashes on the way.
|
|
7
|
+
module Nesting
|
|
8
|
+
module_function
|
|
9
|
+
|
|
10
|
+
# Appends one element to a list argument, creating the list on first use.
|
|
11
|
+
#
|
|
12
|
+
# Repeats must grow the list (`bury` would silently keep only the last), and a single
|
|
13
|
+
# element is still a one-item list, since a `list_of` attribute must never see a bare
|
|
14
|
+
# object. Multi-field elements are left to `Json`: a flat command line cannot say
|
|
15
|
+
# which `a.x=` pairs with which `a.y=`.
|
|
16
|
+
def append(hash, path, value)
|
|
17
|
+
*branches, leaf = path.map(&:to_sym)
|
|
18
|
+
holder = branches[0..-2].reduce(hash) { |node, key| node[key] ||= {} }
|
|
19
|
+
list = holder[branches.last] ||= []
|
|
20
|
+
|
|
21
|
+
list << { leaf => value }
|
|
22
|
+
hash
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Sets one value at a nested path, creating intermediate Hashes and overwriting the leaf.
|
|
26
|
+
def bury(hash, path, value)
|
|
27
|
+
*branches, leaf = path.map(&:to_sym)
|
|
28
|
+
target = branches.reduce(hash) { |node, key| node[key] ||= {} }
|
|
29
|
+
target[leaf] = value
|
|
30
|
+
hash
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
module Hecks
|
|
2
|
+
module Adapters
|
|
3
|
+
module Driving
|
|
4
|
+
module Cli
|
|
5
|
+
# Rewrites the shorthand spellings of a command line into plain `name=value` words.
|
|
6
|
+
module Shorthand
|
|
7
|
+
module_function
|
|
8
|
+
|
|
9
|
+
# Rewrites the short forms into `name=value`: `--name` for a Boolean (a following `yes`,
|
|
10
|
+
# `no`, `true`, `false`, `on`, `off`, `1` or `0` is that flag's value, not an argument),
|
|
11
|
+
# `--name=value` as `name=value`, and one bare word as the command's first argument
|
|
12
|
+
# (`to` for a command on an existing aggregate, the first attribute for one that creates).
|
|
13
|
+
def normalize(spec, words, options)
|
|
14
|
+
pairs, bare = collect(words, options)
|
|
15
|
+
raise Runtime::NotFound, too_many_bare(bare) if bare.length > 1
|
|
16
|
+
|
|
17
|
+
pairs.map { |pair| bare.include?(pair) && !pair.include?("=") ? positional(pair, spec) : pair }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Every word as a pair, and the words that were neither a flag nor a pair.
|
|
21
|
+
def collect(words, options)
|
|
22
|
+
queue = words.dup
|
|
23
|
+
pairs = []
|
|
24
|
+
bare = []
|
|
25
|
+
until queue.empty?
|
|
26
|
+
word = queue.shift
|
|
27
|
+
pairs << pair_for(word, queue, options)
|
|
28
|
+
bare << word if bare_word?(word)
|
|
29
|
+
end
|
|
30
|
+
[pairs, bare]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# A word that is neither a `--flag` nor a `name=value` pair.
|
|
34
|
+
def bare_word?(word)
|
|
35
|
+
!word.start_with?("--") && !word.include?("=")
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# One word as a `name=value` pair; a `--flag` takes the Boolean word that follows it from
|
|
39
|
+
# `queue`.
|
|
40
|
+
def pair_for(word, queue, options)
|
|
41
|
+
return word unless word.start_with?("--")
|
|
42
|
+
return underscored(word.delete_prefix("--"), options) if word.include?("=")
|
|
43
|
+
|
|
44
|
+
path = flag(word.delete_prefix("--"), options)
|
|
45
|
+
value = BOOLEAN_WORDS.key?(queue.first.to_s.downcase) ? queue.shift : "true"
|
|
46
|
+
"#{path}=#{value}"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# A `name=value` pair whose name is spelled with dashes (`seed-start=3`), as the argument
|
|
50
|
+
# spelled with underscores, unless an argument is named with the dashes.
|
|
51
|
+
def underscored(pair, options)
|
|
52
|
+
name, value = pair.split("=", 2)
|
|
53
|
+
options.key?(name) ? pair : "#{name.tr("-", "_")}=#{value}"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# A `--name` flag, as the path of the Boolean argument it stands for. A dashed name
|
|
57
|
+
# (`--gem-only`) is the argument spelled with underscores (`gem_only`).
|
|
58
|
+
def flag(name, options)
|
|
59
|
+
name = name.tr("-", "_") unless options.key?(name) || options.keys.any? { |key| key.start_with?("#{name}.") }
|
|
60
|
+
path = options.key?(name) ? name : Cli.expand(name, options)
|
|
61
|
+
return path if options.dig(path, :type) == "Boolean"
|
|
62
|
+
|
|
63
|
+
raise Runtime::NotFound, "--#{name} is a flag, but this command has no Boolean argument #{name.inspect}"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# The one bare word, as a pair for the command's first argument the launcher does not
|
|
67
|
+
# mint.
|
|
68
|
+
def positional(word, spec)
|
|
69
|
+
first = spec[:arguments].find { |argument| !argument[:minted] }
|
|
70
|
+
return "#{first[:path]}=#{word}" if first
|
|
71
|
+
|
|
72
|
+
if spec[:arguments].any?
|
|
73
|
+
raise Runtime::NotFound, "#{word.inspect} is not name=value; this command's only argument is its run " \
|
|
74
|
+
"key, which is minted when omitted (run=<key> names one)"
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
raise Runtime::NotFound, "#{word.inspect} is not name=value, and this command takes no arguments"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Words the refusal for more than one unnamed argument.
|
|
81
|
+
def too_many_bare(bare)
|
|
82
|
+
"only one argument may go unnamed, not #{bare.map(&:inspect).join(", ")}; name the rest as name=value"
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
require_relative "../../runtime/errors"
|
|
2
|
+
|
|
3
|
+
module Hecks
|
|
4
|
+
module Adapters
|
|
5
|
+
module Driving
|
|
6
|
+
# Turns `path=value` command-line words into a nested, typed argument Hash.
|
|
7
|
+
# Types come from the projection, never from guessing at the value ("99" may be a String).
|
|
8
|
+
module Cli
|
|
9
|
+
# The words a Boolean is spelled with, and what each means.
|
|
10
|
+
BOOLEAN_WORDS = { "true" => true, "yes" => true, "1" => true, "on" => true,
|
|
11
|
+
"false" => false, "no" => false, "0" => false, "off" => false }.freeze
|
|
12
|
+
|
|
13
|
+
module_function
|
|
14
|
+
|
|
15
|
+
# Builds a command's nested, typed argument Hash from its `name=value` words.
|
|
16
|
+
#
|
|
17
|
+
# arguments(spec, ["reference.value=A-1", "sequence.value=99"])
|
|
18
|
+
# # => { reference: { value: "A-1" }, sequence: { value: 99 } }
|
|
19
|
+
#
|
|
20
|
+
# @param spec [Hash{Symbol => Object}] one command's entry from `Projector::CliProjector`
|
|
21
|
+
# @param pairs [Array<String>] the words after the command: `name=value` pairs (a path may
|
|
22
|
+
# be the short form of a single-field value object), `--name` for a Boolean, and at most
|
|
23
|
+
# one bare word, which fills the first argument
|
|
24
|
+
# @return [Hash{Symbol => Object}] the arguments nested by path, leaves cast to type
|
|
25
|
+
# @raise [Runtime::NotFound] if a path, flag or bare word does not fit the command
|
|
26
|
+
# @raise [Runtime::TypeMismatch] if a value does not parse as its Integer or Float
|
|
27
|
+
def arguments(spec, pairs)
|
|
28
|
+
options = declared_options(spec)
|
|
29
|
+
Shorthand.normalize(spec, pairs, options).each_with_object({}) { |pair, args| store(args, pair, options) }
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Every argument the command accepts, by path. Extra accepted arguments stay out of help,
|
|
33
|
+
# which teaches only to=....
|
|
34
|
+
def declared_options(spec)
|
|
35
|
+
(spec[:arguments] + Array(spec[:legacy_arguments])).to_h { |argument| [argument[:path], argument] }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Casts the value of one `name=value` pair and sets it into `args` at its path.
|
|
39
|
+
def store(args, pair, options)
|
|
40
|
+
path, value = split(pair)
|
|
41
|
+
full, argument = declared_argument(path, options)
|
|
42
|
+
keys = full.split(".")
|
|
43
|
+
return words(args, keys, value, argument[:type]) if argument[:words]
|
|
44
|
+
return Nesting.append(args, keys, cast(value, argument[:type])) if argument[:list]
|
|
45
|
+
|
|
46
|
+
Nesting.bury(args, keys, cast(value, argument[:type]))
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# The full path and declaration of the argument `path` names, expanding a value object's
|
|
50
|
+
# short form. `key?` rather than `||`, so the lookup honors the same spelling `full` chose.
|
|
51
|
+
def declared_argument(path, options)
|
|
52
|
+
full = options.key?(path) ? path : expand(path, options)
|
|
53
|
+
return [full, options[full]] if options.key?(full)
|
|
54
|
+
|
|
55
|
+
raise Runtime::NotFound, unknown(path, options.keys)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Cuts one word at its first `=`, so a value may itself contain `=`.
|
|
59
|
+
def split(pair)
|
|
60
|
+
name, value = pair.split("=", 2)
|
|
61
|
+
raise Runtime::NotFound, "#{pair.inspect} is not name=value" if value.nil?
|
|
62
|
+
|
|
63
|
+
[name, value]
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Expands a bare value-object name into the path of its only field.
|
|
67
|
+
# Left unchanged when several fields match, since guessing which was meant is worse.
|
|
68
|
+
def expand(path, options)
|
|
69
|
+
candidates = options.keys.select { |key| key.start_with?("#{path}.") }
|
|
70
|
+
candidates.length == 1 ? candidates.first : path
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Converts one value to its declared type; only Integer, Float and Boolean convert.
|
|
74
|
+
def cast(value, type)
|
|
75
|
+
case type
|
|
76
|
+
when "Integer" then Integer(value)
|
|
77
|
+
when "Float" then Float(value)
|
|
78
|
+
when "Boolean" then boolean(value)
|
|
79
|
+
else value
|
|
80
|
+
end
|
|
81
|
+
rescue ArgumentError
|
|
82
|
+
raise Runtime::TypeMismatch, "#{value.inspect} is not #{type} — the chapter declares this field as #{type}"
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Reads a Boolean word: `true`, `yes`, `1` or `on` is true; `false`, `no`, `0` or `off` is
|
|
86
|
+
# false; case does not matter. Anything else is refused, since guessing would turn a typo
|
|
87
|
+
# (`dry_run=ture`) into a silent false.
|
|
88
|
+
#
|
|
89
|
+
# @param value [String] the word
|
|
90
|
+
# @return [Boolean]
|
|
91
|
+
# @raise [Runtime::TypeMismatch] if the word is not one of those eight
|
|
92
|
+
def boolean(value)
|
|
93
|
+
BOOLEAN_WORDS.fetch(value.to_s.downcase) do
|
|
94
|
+
raise Runtime::TypeMismatch,
|
|
95
|
+
"#{value.inspect} is not Boolean — use true, false, yes, no, 1, 0, on or off"
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Adds the words of a `list_of` scalar argument to its Array: a comma-separated value is
|
|
100
|
+
# several elements and a repeated name adds more, each cast to the element type. The
|
|
101
|
+
# runtime refuses a lone scalar for a list, so the adapter is where every spelling becomes
|
|
102
|
+
# an
|
|
103
|
+
# Array.
|
|
104
|
+
#
|
|
105
|
+
# @param hash [Hash{Symbol => Object}] the arguments built so far
|
|
106
|
+
# @param path [Array<String>] the argument's dotted path
|
|
107
|
+
# @param value [String] the word after `=`
|
|
108
|
+
# @param type [String] the element type
|
|
109
|
+
# @return [Hash{Symbol => Object}] `hash`
|
|
110
|
+
def words(hash, path, value, type)
|
|
111
|
+
*branches, leaf = path.map(&:to_sym)
|
|
112
|
+
holder = branches.reduce(hash) { |node, key| node[key] ||= {} }
|
|
113
|
+
list = holder[leaf] ||= []
|
|
114
|
+
list.concat(value.split(",").map { |word| cast(word.strip, type) })
|
|
115
|
+
hash
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Words the refusal for an argument the command does not take, listing what it does.
|
|
119
|
+
def unknown(path, known)
|
|
120
|
+
"no argument #{path.inspect} — this command takes #{known.sort.join(", ")}"
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
require_relative "cli/nesting"
|
|
127
|
+
require_relative "cli/shorthand"
|