hecks 1.3.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/hecks/adapters/driven/claude_code.rb +72 -7
- data/lib/hecks/adapters/driven/d1.rb +187 -23
- data/lib/hecks/adapters/driven/folder.rb +83 -10
- data/lib/hecks/adapters/driven/google_authentication.rb +33 -12
- data/lib/hecks/adapters/driven/governance_authorization.rb +87 -18
- data/lib/hecks/adapters/driven/heki/journal.rb +13 -4
- data/lib/hecks/adapters/driven/heki/saga_store.rb +56 -10
- data/lib/hecks/adapters/driven/heki/snapshot.rb +1 -1
- data/lib/hecks/adapters/driven/heki.rb +106 -9
- data/lib/hecks/adapters/driven/identity_registry.rb +12 -2
- data/lib/hecks/adapters/driven/in_memory_ordering.rb +25 -3
- data/lib/hecks/adapters/driven/in_process_key_vault.adapter +3 -0
- data/lib/hecks/adapters/driven/in_process_key_vault.rb +53 -0
- data/lib/hecks/adapters/driven/lambda/client.rb +67 -14
- data/lib/hecks/adapters/driven/lambda.rb +82 -35
- data/lib/hecks/adapters/driven/local_storage.rb +83 -10
- data/lib/hecks/adapters/driven/memory.rb +205 -9
- data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +21 -1
- data/lib/hecks/adapters/driven/postgres/codec.rb +27 -11
- data/lib/hecks/adapters/driven/postgres/outbox.rb +40 -2
- data/lib/hecks/adapters/driven/postgres/reconnect.rb +23 -7
- data/lib/hecks/adapters/driven/postgres/schema_builder.rb +14 -14
- data/lib/hecks/adapters/driven/postgres.rb +175 -28
- data/lib/hecks/adapters/driven/prism.rb +50 -11
- data/lib/hecks/adapters/driven/secure_random_identity.rb +3 -0
- data/lib/hecks/adapters/driven/sql_query_builder.rb +34 -22
- data/lib/hecks/adapters/driven/sqlite/codec.rb +38 -10
- data/lib/hecks/adapters/driven/sqlite/projection.rb +60 -32
- data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +12 -12
- data/lib/hecks/adapters/driven/sqlite.rb +181 -21
- data/lib/hecks/adapters/driven/system_clock.rb +3 -0
- data/lib/hecks/adapters/driven/tenant_provisioner.adapter +3 -0
- data/lib/hecks/adapters/driven/tenant_provisioner.rb +66 -0
- data/lib/hecks/adapters/driven.rb +6 -4
- data/lib/hecks/adapters/driving/github_webhook.rb +31 -18
- data/lib/hecks/behaviors/dsl.rb +60 -2
- data/lib/hecks/behaviors/expectations.rb +190 -29
- data/lib/hecks/behaviors/ir.rb +12 -1
- data/lib/hecks/behaviors/rspec.rb +9 -1
- data/lib/hecks/behaviors/runner.rb +21 -2
- data/lib/hecks/behaviors.rb +9 -1
- data/lib/hecks/bluebook/aggregate.rb +43 -13
- data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +17 -10
- data/lib/hecks/bluebook/assembly/build.rb +26 -5
- data/lib/hecks/bluebook/assembly/contract.rb +98 -23
- data/lib/hecks/bluebook/assembly/contracts.rb +59 -52
- data/lib/hecks/bluebook/assembly/marks.rb +159 -30
- data/lib/hecks/bluebook/assembly/specializer.rb +38 -21
- data/lib/hecks/bluebook/assembly.rb +32 -14
- data/lib/hecks/bluebook/attribute.rb +26 -12
- data/lib/hecks/bluebook/behaviour/aggregate.rb +43 -11
- data/lib/hecks/bluebook/behaviour/attribute.rb +18 -5
- data/lib/hecks/bluebook/behaviour/chapter.rb +76 -5
- data/lib/hecks/bluebook/behaviour/command.rb +55 -25
- data/lib/hecks/bluebook/behaviour/domain_port.rb +27 -7
- data/lib/hecks/bluebook/behaviour/entity.rb +20 -8
- data/lib/hecks/bluebook/behaviour/hexagon.rb +30 -4
- data/lib/hecks/bluebook/behaviour/lifecycle.rb +27 -6
- data/lib/hecks/bluebook/behaviour/policy.rb +42 -17
- data/lib/hecks/bluebook/behaviour/process_manager.rb +39 -8
- data/lib/hecks/bluebook/behaviour/query.rb +6 -1
- data/lib/hecks/bluebook/behaviour/read_model.rb +29 -8
- data/lib/hecks/bluebook/behaviour/traits.rb +48 -12
- data/lib/hecks/bluebook/behaviour/value_object.rb +21 -9
- data/lib/hecks/bluebook/capabilities.rb +27 -0
- data/lib/hecks/bluebook/chapter.rb +51 -9
- data/lib/hecks/bluebook/command.rb +62 -17
- data/lib/hecks/bluebook/domain_port.rb +34 -9
- data/lib/hecks/bluebook/dsl/adapter_builder.rb +24 -0
- data/lib/hecks/bluebook/dsl/aggregate_builder/sealing.rb +49 -49
- data/lib/hecks/bluebook/dsl/aggregate_builder.rb +282 -123
- data/lib/hecks/bluebook/dsl/attribute_collector.rb +112 -75
- data/lib/hecks/bluebook/dsl/binding_proxy.rb +81 -2
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +486 -117
- data/lib/hecks/bluebook/dsl/bluebook_builder.rb +179 -47
- data/lib/hecks/bluebook/dsl/bootstrap_table.rb +116 -0
- data/lib/hecks/bluebook/dsl/command_builder.rb +284 -122
- data/lib/hecks/bluebook/dsl/const_shim.rb +46 -15
- data/lib/hecks/bluebook/dsl/domain_port_builder.rb +90 -25
- data/lib/hecks/bluebook/dsl/entity_builder.rb +191 -61
- data/lib/hecks/bluebook/dsl/generic_dispatch.rb +148 -132
- data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +130 -30
- data/lib/hecks/bluebook/dsl/identity_declaration.rb +38 -21
- data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +27 -4
- data/lib/hecks/bluebook/dsl/policy_builder.rb +86 -36
- data/lib/hecks/bluebook/dsl/port_builder.rb +38 -7
- data/lib/hecks/bluebook/dsl/port_operation_builder.rb +56 -22
- data/lib/hecks/bluebook/dsl/process_manager_builder.rb +111 -47
- data/lib/hecks/bluebook/dsl/query_builder.rb +37 -8
- data/lib/hecks/bluebook/dsl/read_model_builder.rb +127 -52
- data/lib/hecks/bluebook/dsl/rule_reference.rb +97 -43
- data/lib/hecks/bluebook/dsl/translation_builder.rb +150 -44
- data/lib/hecks/bluebook/dsl/value_object_builder.rb +68 -20
- data/lib/hecks/bluebook/dsl/word_gate.rb +59 -53
- data/lib/hecks/bluebook/dsl/world_builder.rb +51 -8
- data/lib/hecks/bluebook/entity.rb +40 -11
- data/lib/hecks/bluebook/expression/ast_json.rb +128 -36
- data/lib/hecks/bluebook/expression/ast_reader.rb +32 -3
- data/lib/hecks/bluebook/expression/canonical_form.rb +55 -16
- data/lib/hecks/bluebook/expression/evaluator.rb +221 -43
- data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +54 -18
- data/lib/hecks/bluebook/expression/resolver.rb +369 -128
- data/lib/hecks/bluebook/hexagon.rb +35 -1
- data/lib/hecks/bluebook/lifecycle.rb +12 -1
- data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +2 -1
- data/lib/hecks/bluebook/meta_validator/judge.rb +126 -108
- data/lib/hecks/bluebook/meta_validator/plan.rb +81 -46
- data/lib/hecks/bluebook/meta_validator/port_judge.rb +3 -2
- data/lib/hecks/bluebook/meta_validator/readings.rb +200 -50
- data/lib/hecks/bluebook/meta_validator/reconstruction.rb +68 -41
- data/lib/hecks/bluebook/meta_validator/shapes.rb +166 -21
- data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +286 -46
- data/lib/hecks/bluebook/meta_validator/translation_judge.rb +11 -10
- data/lib/hecks/bluebook/meta_validator/world_judge.rb +6 -5
- data/lib/hecks/bluebook/meta_validator.rb +235 -139
- data/lib/hecks/bluebook/model_check.rb +434 -104
- data/lib/hecks/bluebook/pattern_subset.rb +32 -10
- data/lib/hecks/bluebook/policy.rb +15 -13
- data/lib/hecks/bluebook/process_manager.rb +27 -14
- data/lib/hecks/bluebook/project_discovery.rb +5 -0
- data/lib/hecks/bluebook/project_loader.rb +40 -0
- data/lib/hecks/bluebook/project_register.rb +50 -6
- data/lib/hecks/bluebook/query.rb +31 -4
- data/lib/hecks/bluebook/read_model.rb +35 -15
- data/lib/hecks/bluebook/reference.rb +26 -13
- data/lib/hecks/bluebook/smoke_test.rb +46 -23
- data/lib/hecks/bluebook/synthesizer.rb +46 -12
- data/lib/hecks/bluebook/translation.rb +34 -5
- data/lib/hecks/bluebook/value_object.rb +29 -11
- data/lib/hecks/bluebook.rb +5 -6
- data/lib/hecks/codemod.rb +138 -50
- data/lib/hecks/construct.rb +21 -7
- data/lib/hecks/corpus.rb +438 -0
- data/lib/hecks/deploy/bluebook/deploy.hecksagon +19 -0
- data/lib/hecks/doc/reference.rb +200 -31
- data/lib/hecks/embryonaut_bluebook.rb +38 -15
- data/lib/hecks/facade/cli_door.rb +69 -10
- data/lib/hecks/facade/cli_runner.rb +105 -24
- data/lib/hecks/facade/command_request.rb +23 -0
- data/lib/hecks/facade/handle.rb +155 -35
- data/lib/hecks/facade/json_door.rb +106 -25
- data/lib/hecks/facade/surface/aggregate_door.rb +50 -27
- data/lib/hecks/facade/surface/chapter.rb +26 -17
- data/lib/hecks/facade/surface.rb +16 -3
- data/lib/hecks/facade.rb +15 -4
- data/lib/hecks/forms/app.rb +46 -30
- data/lib/hecks/forms/command_form_renderer.rb +70 -9
- data/lib/hecks/forms/field_renderer.rb +142 -6
- data/lib/hecks/forms/field_shape.rb +183 -19
- data/lib/hecks/forms/html.rb +51 -7
- data/lib/hecks/forms/index_renderer.rb +14 -2
- data/lib/hecks/forms/page.rb +14 -0
- data/lib/hecks/forms/params.rb +120 -23
- data/lib/hecks/forms/port_argument.rb +14 -2
- data/lib/hecks/forms/query_form_renderer.rb +65 -2
- data/lib/hecks/forms/record_renderer.rb +60 -2
- data/lib/hecks/forms/record_table.rb +28 -1
- data/lib/hecks/forms/reference_options.rb +24 -0
- data/lib/hecks/forms/value_object_shape.rb +13 -3
- data/lib/hecks/forms.rb +24 -4
- data/lib/hecks/fqn.rb +59 -1
- data/lib/hecks/framework/bluebook/governance.bluebook +9 -0
- data/lib/hecks/framework/bluebook/privacy.bluebook +155 -0
- data/lib/hecks/framework/oidc.json +15 -0
- data/lib/hecks/framework.rb +79 -25
- data/lib/hecks/freezer.rb +27 -11
- data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +241 -106
- data/lib/hecks/fuzzing/combination_miner.rb +178 -0
- data/lib/hecks/fuzzing/concurrent_dispatch.rb +241 -45
- data/lib/hecks/fuzzing/coverage_campaign.rb +161 -0
- data/lib/hecks/fuzzing/differential.rb +192 -0
- data/lib/hecks/fuzzing/domain_generator.rb +871 -0
- data/lib/hecks/fuzzing/era_boundary.rb +68 -19
- data/lib/hecks/fuzzing/form_census.rb +121 -20
- data/lib/hecks/fuzzing/generated_domain_check.rb +171 -0
- data/lib/hecks/fuzzing/invalid_value_generator.rb +45 -6
- data/lib/hecks/fuzzing/isolated_boot.rb +137 -80
- data/lib/hecks/fuzzing/nondeterministic.rb +79 -0
- data/lib/hecks/fuzzing/persistence_parity.rb +111 -21
- data/lib/hecks/fuzzing/properties/corrections.rb +34 -9
- data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +300 -51
- data/lib/hecks/fuzzing/properties/guards.rb +86 -42
- data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +80 -32
- data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +40 -35
- data/lib/hecks/fuzzing/properties/outbox.rb +70 -32
- data/lib/hecks/fuzzing/properties/querying.rb +82 -28
- data/lib/hecks/fuzzing/properties.rb +84 -51
- data/lib/hecks/fuzzing/qa_settings.rb +164 -0
- data/lib/hecks/fuzzing/replay.rb +241 -133
- data/lib/hecks/fuzzing/rotation_priority.rb +48 -28
- data/lib/hecks/fuzzing/rust_gap_manifest.rb +139 -0
- data/lib/hecks/fuzzing/self_consistency.rb +315 -137
- data/lib/hecks/fuzzing/sequence_generator/adversary.rb +46 -40
- data/lib/hecks/fuzzing/sequence_generator/catalog.rb +18 -11
- data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +13 -12
- data/lib/hecks/fuzzing/sequence_generator/picker.rb +21 -12
- data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +59 -32
- data/lib/hecks/fuzzing/sequence_generator.rb +158 -23
- data/lib/hecks/fuzzing/shrinker.rb +309 -0
- data/lib/hecks/fuzzing/structural_skips.rb +37 -130
- data/lib/hecks/fuzzing/sweep_depth.rb +12 -4
- data/lib/hecks/fuzzing/target_capabilities.rb +107 -29
- data/lib/hecks/fuzzing/value_generator.rb +110 -22
- data/lib/hecks/fuzzing.rb +5 -0
- data/lib/hecks/grammar/evolve.rb +188 -12
- data/lib/hecks/grammar.rb +53 -7
- data/lib/hecks/ir.rb +51 -20
- data/lib/hecks/language/bluebook/bluebook.bluebook +41 -0
- data/lib/hecks/language/bluebook/policy.bluebook +11 -1
- data/lib/hecks/language/bluebook/vocabulary.bluebook +348 -13
- data/lib/hecks/language/hecksagon/hecksagon.bluebook +11 -0
- data/lib/hecks/language/oidc.json +5 -0
- data/lib/hecks/literal.rb +41 -9
- data/lib/hecks/naming.rb +112 -31
- data/lib/hecks/ports/access_control.rb +53 -2
- data/lib/hecks/ports/agent/answers.rb +83 -6
- data/lib/hecks/ports/agent.rb +119 -35
- data/lib/hecks/ports/authentication.rb +44 -4
- data/lib/hecks/ports/authorization.rb +50 -11
- data/lib/hecks/ports/clock.rb +42 -23
- data/lib/hecks/ports/extraction.rb +16 -0
- data/lib/hecks/ports/identity_assignment.rb +23 -2
- data/lib/hecks/ports/identity_generation.rb +17 -3
- data/lib/hecks/ports/identity_resolution.rb +17 -1
- data/lib/hecks/ports/key_vault.port +6 -0
- data/lib/hecks/ports/key_vault.rb +58 -0
- data/lib/hecks/ports/loading.rb +4 -0
- data/lib/hecks/ports/persistence/append_only.rb +172 -8
- data/lib/hecks/ports/persistence/binding_policy.rb +34 -0
- data/lib/hecks/ports/persistence/codec_boundary.rb +178 -0
- data/lib/hecks/ports/persistence/execution.rb +4 -0
- data/lib/hecks/ports/persistence/null_saga_store.rb +12 -1
- data/lib/hecks/ports/persistence/plugin.rb +42 -4
- data/lib/hecks/ports/persistence/plugins/era/era_check.rb +218 -25
- data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +77 -9
- data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +81 -24
- data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +29 -18
- data/lib/hecks/ports/persistence/plugins/era/lineage.rb +144 -60
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +103 -8
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +98 -23
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +282 -109
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +63 -25
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +118 -66
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +51 -28
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +34 -5
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +25 -12
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +129 -34
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +51 -6
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +33 -9
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +16 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +95 -6
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +25 -2
- data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +314 -90
- data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +68 -10
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +9 -3
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +9 -2
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +48 -8
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +16 -1
- data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +36 -5
- data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +23 -3
- data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +58 -19
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +96 -5
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/renderer.rb +15 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +9 -1
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +2 -2
- data/lib/hecks/ports/persistence/plugins/era.rb +12 -2
- data/lib/hecks/ports/persistence/remote_runtime.rb +9 -2
- data/lib/hecks/ports/persistence/repository_factory.rb +23 -3
- data/lib/hecks/ports/persistence/state_codec.rb +319 -0
- data/lib/hecks/ports/persistence.rb +36 -1
- data/lib/hecks/ports/projection.rb +61 -7
- data/lib/hecks/ports/query/in_memory.rb +41 -8
- data/lib/hecks/ports/query/ordering.rb +21 -6
- data/lib/hecks/ports/query.rb +35 -0
- data/lib/hecks/ports.rb +1 -0
- data/lib/hecks/projections/bootstrap_table.rb +147 -0
- data/lib/hecks/projections/diagrams.rb +315 -79
- data/lib/hecks/projections/glossary/html.rb +91 -3
- data/lib/hecks/projections/glossary/markdown.rb +50 -3
- data/lib/hecks/projections/glossary/mermaid.rb +49 -1
- data/lib/hecks/projections/glossary/sections.rb +1 -1
- data/lib/hecks/projections/glossary/sentences.rb +110 -5
- data/lib/hecks/projections/glossary.rb +173 -31
- data/lib/hecks/projections/ir.rb +1 -1
- data/lib/hecks/projections/model/deviations.rb +62 -17
- data/lib/hecks/projections/model.rb +75 -21
- data/lib/hecks/projections/oidc.rb +45 -8
- data/lib/hecks/projections/parser_table.rb +53 -12
- data/lib/hecks/projections/reference.rb +15 -3
- data/lib/hecks/projections/rust_vocabulary.rb +646 -0
- data/lib/hecks/projections/shape.rb +10 -2
- data/lib/hecks/projections/statements.rb +69 -22
- data/lib/hecks/projections/vocabulary.rb +26 -9
- data/lib/hecks/projections.rb +5 -3
- data/lib/hecks/projector/cli_projector.rb +245 -37
- data/lib/hecks/projector/docs_projector.rb +154 -28
- data/lib/hecks/projector/exporter.rb +104 -29
- data/lib/hecks/projector/ir_projector.rb +7 -1
- data/lib/hecks/projector/narrate_projector.rb +144 -23
- data/lib/hecks/projector/target.rb +42 -18
- data/lib/hecks/projector.rb +86 -18
- data/lib/hecks/query_ir.rb +94 -47
- data/lib/hecks/query_specification/common/comparators.rb +19 -3
- data/lib/hecks/query_specification/common/comparison.rb +109 -27
- data/lib/hecks/query_specification/common/dsl.rb +65 -9
- data/lib/hecks/query_specification/common/null_policy.rb +61 -15
- data/lib/hecks/query_specification/common/null_semantics.rb +4 -0
- data/lib/hecks/query_specification/common/options.rb +25 -0
- data/lib/hecks/query_specification/field_path.rb +69 -15
- data/lib/hecks/query_specification/hop_path.rb +57 -20
- data/lib/hecks/query_specification/read_model/specification.rb +4 -0
- data/lib/hecks/rendering.rb +9 -3
- data/lib/hecks/router/namespace_installer.rb +16 -3
- data/lib/hecks/router.rb +56 -1
- data/lib/hecks/runtime/aggregate_lock.rb +20 -11
- data/lib/hecks/runtime/boot_gates.rb +21 -3
- data/lib/hecks/runtime/caller.rb +40 -8
- data/lib/hecks/runtime/capability_graph.rb +13 -2
- data/lib/hecks/runtime/command_interpreter/argument_gate.rb +40 -41
- data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +45 -67
- data/lib/hecks/runtime/command_interpreter.rb +195 -113
- data/lib/hecks/runtime/command_rules/admissibility.rb +231 -80
- data/lib/hecks/runtime/command_rules/arithmetic.rb +154 -96
- data/lib/hecks/runtime/command_rules/authorization.rb +38 -17
- data/lib/hecks/runtime/command_rules/emission.rb +18 -1
- data/lib/hecks/runtime/command_rules/references.rb +145 -55
- data/lib/hecks/runtime/command_rules.rb +3 -0
- data/lib/hecks/runtime/dependency_planning.rb +56 -11
- data/lib/hecks/runtime/dispatcher.rb +263 -92
- data/lib/hecks/runtime/entity_element.rb +304 -67
- data/lib/hecks/runtime/entity_interpreter.rb +149 -88
- data/lib/hecks/runtime/errors.rb +37 -23
- data/lib/hecks/runtime/event.rb +15 -10
- data/lib/hecks/runtime/identity.rb +91 -23
- data/lib/hecks/runtime/instance.rb +103 -18
- data/lib/hecks/runtime/interpreting.rb +24 -16
- data/lib/hecks/runtime/invocation.rb +358 -0
- data/lib/hecks/runtime/loader.rb +105 -19
- data/lib/hecks/runtime/outbox.rb +164 -26
- data/lib/hecks/runtime/policy_interpreter.rb +73 -60
- data/lib/hecks/runtime/port_operation_interpreter.rb +42 -19
- data/lib/hecks/runtime/query_interpreter.rb +93 -74
- data/lib/hecks/runtime/reaction_invocation.rb +73 -28
- data/lib/hecks/runtime/read_model_interpreter.rb +60 -44
- data/lib/hecks/runtime/rebuild_sweep.rb +32 -4
- data/lib/hecks/runtime/reference_hop.rb +48 -6
- data/lib/hecks/runtime/refusal_wording.rb +142 -115
- data/lib/hecks/runtime/registry/saga_persistence.rb +32 -21
- data/lib/hecks/runtime/registry/verification.rb +153 -28
- data/lib/hecks/runtime/registry.rb +202 -32
- data/lib/hecks/runtime/remote_dispatcher.rb +125 -24
- data/lib/hecks/runtime/routing.rb +36 -154
- data/lib/hecks/runtime/saga_interpreter/correlation.rb +25 -27
- data/lib/hecks/runtime/saga_interpreter.rb +90 -76
- data/lib/hecks/runtime/saga_pending_dispatch.rb +12 -12
- data/lib/hecks/runtime/tenant_check.rb +33 -13
- data/lib/hecks/runtime/tenant_scope.rb +23 -5
- data/lib/hecks/runtime/value/admission.rb +75 -30
- data/lib/hecks/runtime/value/coercion.rb +555 -142
- data/lib/hecks/runtime/value/entity_list_coercion.rb +132 -60
- data/lib/hecks/runtime/value.rb +71 -21
- data/lib/hecks/runtime.rb +39 -7
- data/lib/hecks/storehouse.rb +368 -72
- data/lib/hecks/tenancy/bluebook/tenancy.bluebook +130 -0
- data/lib/hecks/tenancy/bluebook/tenancy.hecksagon +32 -0
- data/lib/hecks/version.rb +3 -3
- data/lib/hecks/vocabulary.rb +205 -4
- data/lib/hecks.rb +91 -11
- data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +19 -11
- data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +24 -12
- data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +38 -14
- metadata +28 -2
|
@@ -2,8 +2,11 @@ Hecks.bluebook "Bluebook" do
|
|
|
2
2
|
aggregate "Vocabulary" do
|
|
3
3
|
# These are DECLARATIONS, not runtime state — a language's admitted sets are
|
|
4
4
|
# fixed when the language is defined, which is what one_of means. They carry
|
|
5
|
-
# no commands on purpose : nothing dispatches a vocabulary
|
|
6
|
-
#
|
|
5
|
+
# no commands on purpose : nothing dispatches a vocabulary. They are READ
|
|
6
|
+
# from the IR and projected — bin/project_vocabulary writes the Ruby tables
|
|
7
|
+
# (lib/hecks/vocabulary.rb) the runtime's constants read, and
|
|
8
|
+
# bin/project_rust_vocabulary writes rust/src/kernel/vocab/ — so the
|
|
9
|
+
# runtimes carry no hand-typed copies to drift.
|
|
7
10
|
#
|
|
8
11
|
# Every one of these is a set the runtime must agree with, and every one has
|
|
9
12
|
# already drifted or leaked at least once :
|
|
@@ -171,9 +174,17 @@ Hecks.bluebook "Bluebook" do
|
|
|
171
174
|
# fires for a creating command, advance_lifecycle only when a transition
|
|
172
175
|
# applies — so this is the order a command that does both follows,
|
|
173
176
|
# confirmed by tracing a real dispatch, not read off the source.
|
|
177
|
+
#
|
|
178
|
+
# decode_arguments leads both dispatch orders: turning the caller's raw
|
|
179
|
+
# facts into a command's declared arguments, before any argument gate
|
|
180
|
+
# judges them. A no-op in Ruby today (routing already hands the
|
|
181
|
+
# interpreter a decoded hash) and in the Rust kernel's dispatch loop
|
|
182
|
+
# (generated `from_json` still decodes and gates in one pass) — declared
|
|
183
|
+
# now so the Rust kernel's step enum has a place for a generated decoder
|
|
184
|
+
# to move into, rather than the order being implied by generated code.
|
|
174
185
|
value_object "AggregateDispatchOrder" do
|
|
175
186
|
attribute :step, String,
|
|
176
|
-
one_of: ["refuse_unknown_arguments", "refuse_absent_arguments", "normalize_args",
|
|
187
|
+
one_of: ["decode_arguments", "refuse_unknown_arguments", "refuse_absent_arguments", "normalize_args",
|
|
177
188
|
"refuse_role_mismatch", "resolve_references", "hydrate", "enforce_givens",
|
|
178
189
|
"admissible_transition", "assign_creation_attributes", "apply_mutations",
|
|
179
190
|
"advance_lifecycle", "delegate_to_entity", "enforce_ensures", "enforce_invariants",
|
|
@@ -197,7 +208,7 @@ Hecks.bluebook "Bluebook" do
|
|
|
197
208
|
# both interpreters), even though nothing in the real corpus does yet.
|
|
198
209
|
value_object "EntityDispatchOrder" do
|
|
199
210
|
attribute :step, String,
|
|
200
|
-
one_of: ["refuse_unknown_arguments", "refuse_absent_arguments", "normalize_args",
|
|
211
|
+
one_of: ["decode_arguments", "refuse_unknown_arguments", "refuse_absent_arguments", "normalize_args",
|
|
201
212
|
"refuse_role_mismatch", "resolve_references", "hydrate_parent",
|
|
202
213
|
"locate_element", "enforce_givens", "admissible_transition", "apply_mutations",
|
|
203
214
|
"advance_lifecycle", "enforce_ensures", "enforce_invariants", "save", "emit"]
|
|
@@ -219,11 +230,10 @@ Hecks.bluebook "Bluebook" do
|
|
|
219
230
|
# declared them. Everything here is different in kind: a LANGUAGE-LEVEL
|
|
220
231
|
# refusal, the same wording for every domain, not authored per-bluebook —
|
|
221
232
|
# closer to Comparison/SignTest beside it than to a given. So it follows
|
|
222
|
-
# THEIR pattern, not given's: declared here
|
|
223
|
-
#
|
|
224
|
-
#
|
|
225
|
-
#
|
|
226
|
-
# hand-typed rather than read live off this very chapter at every call.
|
|
233
|
+
# THEIR pattern, not given's: declared here, and projected into the
|
|
234
|
+
# generated tables a dispatch actually reads (Runtime::RefusalWording in
|
|
235
|
+
# Ruby, kernel::vocab::RefusalSite in Rust) rather than read live off
|
|
236
|
+
# this very chapter at every call.
|
|
227
237
|
#
|
|
228
238
|
# `{name}` markers are placeholders — plain text substitution, not
|
|
229
239
|
# expression syntax ; a template is read, never evaluated. Two call
|
|
@@ -351,6 +361,303 @@ Hecks.bluebook "Bluebook" do
|
|
|
351
361
|
"or read {reference}.{remote_field} directly if this rule cannot wait"
|
|
352
362
|
end
|
|
353
363
|
|
|
364
|
+
# THE ARGUMENTS EACH RefusalTemplate TAKES, AND HOW EACH ONE IS WRITTEN.
|
|
365
|
+
# A template says WHERE a value goes; this says WHICH values a site
|
|
366
|
+
# takes (in the order its placeholders first appear) and how each is
|
|
367
|
+
# rendered before it goes there — so a caller hands over the raw value
|
|
368
|
+
# (a list of names, a name) rather than a string it formatted itself.
|
|
369
|
+
# BUG#134 was exactly the hand-formatted kind: Ruby's `declared_reading`
|
|
370
|
+
# fell back to "none" for an empty list, the Rust generators joined
|
|
371
|
+
# the list themselves and never did.
|
|
372
|
+
#
|
|
373
|
+
# Read by Runtime::RefusalWording.render_site (a missing or extra
|
|
374
|
+
# argument refuses to render at all) and projected into
|
|
375
|
+
# rust/src/kernel/vocab/refusal_template.rs as one typed args struct
|
|
376
|
+
# per site (`render_args` — a missing argument does not compile).
|
|
377
|
+
#
|
|
378
|
+
# shape — "scalar" (one value) or "list" (a collection of them)
|
|
379
|
+
# quoting — "none" (the value's own text) or "inspect" (Ruby's
|
|
380
|
+
# `#inspect`; Rust's `{:?}`), per value or per item
|
|
381
|
+
# separator — what a list's items are joined with
|
|
382
|
+
# sorted — "true" sorts a list's items first (before quoting)
|
|
383
|
+
# when_empty — what an empty list renders as
|
|
384
|
+
#
|
|
385
|
+
# Recorded from what the Ruby call sites did when this table was
|
|
386
|
+
# introduced; no wording changed. A value whose rendering depends on
|
|
387
|
+
# its runtime type (`Rendering.describe`, `offered.inspect` of an
|
|
388
|
+
# arbitrary value) stays a caller-rendered "none" scalar, as do the
|
|
389
|
+
# identity readings (`identity`, `heads`, `wants`) the Rust side already
|
|
390
|
+
# joins once at codegen time or inside `extract_wants`.
|
|
391
|
+
value_object "RefusalSiteArgument" do
|
|
392
|
+
attribute :refusal, String, admits: "Vocabulary::DomainRefusal"
|
|
393
|
+
attribute :site, String
|
|
394
|
+
attribute :argument, String
|
|
395
|
+
attribute :shape, String
|
|
396
|
+
attribute :quoting, String
|
|
397
|
+
attribute :separator, String
|
|
398
|
+
attribute :sorted, String
|
|
399
|
+
attribute :when_empty, String
|
|
400
|
+
|
|
401
|
+
member refusal: "NotFound", site: "creating_no_identity", argument: "command",
|
|
402
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
403
|
+
member refusal: "NotFound", site: "creating_no_identity", argument: "aggregate",
|
|
404
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
405
|
+
member refusal: "NotFound", site: "creating_no_identity", argument: "identity",
|
|
406
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
407
|
+
member refusal: "AlreadyExists", site: "creating_duplicate", argument: "command",
|
|
408
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
409
|
+
member refusal: "AlreadyExists", site: "creating_duplicate", argument: "aggregate",
|
|
410
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
411
|
+
member refusal: "AlreadyExists", site: "creating_duplicate", argument: "identity",
|
|
412
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
413
|
+
member refusal: "AlreadyExists", site: "creating_duplicate", argument: "offered",
|
|
414
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
415
|
+
member refusal: "AlreadyExists", site: "entity_duplicate", argument: "entity",
|
|
416
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
417
|
+
member refusal: "AlreadyExists", site: "entity_duplicate", argument: "aggregate",
|
|
418
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
419
|
+
member refusal: "AlreadyExists", site: "entity_duplicate", argument: "identity",
|
|
420
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
421
|
+
# One described value per identity head (MutationApplier), or the
|
|
422
|
+
# one offered element identity (EntityListCoercion).
|
|
423
|
+
member refusal: "AlreadyExists", site: "entity_duplicate", argument: "offered",
|
|
424
|
+
shape: "list", quoting: "none", separator: ", ", sorted: "false", when_empty: ""
|
|
425
|
+
member refusal: "NotFound", site: "acting_no_identity", argument: "command",
|
|
426
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
427
|
+
member refusal: "NotFound", site: "acting_no_identity", argument: "aggregate",
|
|
428
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
429
|
+
member refusal: "NotFound", site: "acting_no_identity", argument: "identity",
|
|
430
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
431
|
+
member refusal: "NotFound", site: "record_missing", argument: "aggregate",
|
|
432
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
433
|
+
member refusal: "NotFound", site: "record_missing", argument: "identity",
|
|
434
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
435
|
+
member refusal: "NotFound", site: "record_missing", argument: "offered",
|
|
436
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
437
|
+
member refusal: "NotFound", site: "entity_parent_no_identity", argument: "command",
|
|
438
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
439
|
+
member refusal: "NotFound", site: "entity_parent_no_identity", argument: "aggregate",
|
|
440
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
441
|
+
member refusal: "NotFound", site: "entity_parent_no_identity", argument: "entity",
|
|
442
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
443
|
+
member refusal: "NotFound", site: "entity_parent_no_identity", argument: "identity",
|
|
444
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
445
|
+
member refusal: "UnknownVerb", site: "entity_unknown", argument: "aggregate",
|
|
446
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
447
|
+
member refusal: "UnknownVerb", site: "entity_unknown", argument: "entity",
|
|
448
|
+
shape: "scalar", quoting: "inspect", separator: "", sorted: "false", when_empty: ""
|
|
449
|
+
member refusal: "NotFound", site: "entity_element_no_identity", argument: "command",
|
|
450
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
451
|
+
member refusal: "NotFound", site: "entity_element_no_identity", argument: "entity",
|
|
452
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
453
|
+
member refusal: "NotFound", site: "entity_element_no_identity", argument: "identity",
|
|
454
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
455
|
+
member refusal: "NotFound", site: "entity_element_missing", argument: "entity",
|
|
456
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
457
|
+
member refusal: "NotFound", site: "entity_element_missing", argument: "identity",
|
|
458
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
459
|
+
member refusal: "NotFound", site: "entity_element_missing", argument: "wants",
|
|
460
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
461
|
+
member refusal: "NotFound", site: "entity_element_missing", argument: "aggregate",
|
|
462
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
463
|
+
member refusal: "NotFound", site: "entity_element_missing", argument: "parent_id",
|
|
464
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
465
|
+
member refusal: "NotFound", site: "reference_target_missing", argument: "target",
|
|
466
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
467
|
+
member refusal: "NotFound", site: "reference_target_missing", argument: "heads",
|
|
468
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
469
|
+
member refusal: "NotFound", site: "reference_target_missing", argument: "key",
|
|
470
|
+
shape: "scalar", quoting: "inspect", separator: "", sorted: "false", when_empty: ""
|
|
471
|
+
member refusal: "NotFound", site: "read_model_reference_missing", argument: "aggregate",
|
|
472
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
473
|
+
member refusal: "NotFound", site: "read_model_reference_missing", argument: "offered",
|
|
474
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
475
|
+
member refusal: "TypeMismatch", site: "read_model_object_reference", argument: "query",
|
|
476
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
477
|
+
member refusal: "TypeMismatch", site: "read_model_object_reference", argument: "field",
|
|
478
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
479
|
+
member refusal: "UnknownVerb", site: "no_query", argument: "aggregate",
|
|
480
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
481
|
+
member refusal: "UnknownVerb", site: "no_query", argument: "query",
|
|
482
|
+
shape: "scalar", quoting: "inspect", separator: "", sorted: "false", when_empty: ""
|
|
483
|
+
member refusal: "UnknownVerb", site: "entity_query_missing", argument: "entity",
|
|
484
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
485
|
+
member refusal: "UnknownVerb", site: "entity_query_missing", argument: "query",
|
|
486
|
+
shape: "scalar", quoting: "inspect", separator: "", sorted: "false", when_empty: ""
|
|
487
|
+
member refusal: "UnknownVerb", site: "entity_holds_no_list", argument: "aggregate",
|
|
488
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
489
|
+
member refusal: "UnknownVerb", site: "entity_holds_no_list", argument: "entity",
|
|
490
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
491
|
+
member refusal: "UnknownVerb", site: "entity_no_command", argument: "entity",
|
|
492
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
493
|
+
member refusal: "UnknownVerb", site: "entity_no_command", argument: "command",
|
|
494
|
+
shape: "scalar", quoting: "inspect", separator: "", sorted: "false", when_empty: ""
|
|
495
|
+
member refusal: "UnknownVerb", site: "aggregate_no_command", argument: "aggregate",
|
|
496
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
497
|
+
member refusal: "UnknownVerb", site: "aggregate_no_command", argument: "command",
|
|
498
|
+
shape: "scalar", quoting: "inspect", separator: "", sorted: "false", when_empty: ""
|
|
499
|
+
member refusal: "UnknownVerb", site: "port_no_operation", argument: "port",
|
|
500
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
501
|
+
member refusal: "UnknownVerb", site: "port_no_operation", argument: "operation",
|
|
502
|
+
shape: "scalar", quoting: "inspect", separator: "", sorted: "false", when_empty: ""
|
|
503
|
+
member refusal: "UnknownVerb", site: "no_domain", argument: "domain",
|
|
504
|
+
shape: "scalar", quoting: "inspect", separator: "", sorted: "false", when_empty: ""
|
|
505
|
+
member refusal: "UnknownVerb", site: "no_domain", argument: "verb",
|
|
506
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
507
|
+
member refusal: "UnknownVerb", site: "no_read_model", argument: "domain",
|
|
508
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
509
|
+
member refusal: "UnknownVerb", site: "no_read_model", argument: "query",
|
|
510
|
+
shape: "scalar", quoting: "inspect", separator: "", sorted: "false", when_empty: ""
|
|
511
|
+
member refusal: "UnknownVerb", site: "not_fully_qualified", argument: "verb",
|
|
512
|
+
shape: "scalar", quoting: "inspect", separator: "", sorted: "false", when_empty: ""
|
|
513
|
+
member refusal: "UnknownVerb", site: "no_aggregate", argument: "domain",
|
|
514
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
515
|
+
member refusal: "UnknownVerb", site: "no_aggregate", argument: "aggregate",
|
|
516
|
+
shape: "scalar", quoting: "inspect", separator: "", sorted: "false", when_empty: ""
|
|
517
|
+
member refusal: "LifecycleRefused", site: "transition_blocked", argument: "command",
|
|
518
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
519
|
+
member refusal: "LifecycleRefused", site: "transition_blocked", argument: "field",
|
|
520
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
521
|
+
member refusal: "LifecycleRefused", site: "transition_blocked", argument: "current",
|
|
522
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
523
|
+
member refusal: "LifecycleRefused", site: "transition_blocked", argument: "allowed",
|
|
524
|
+
shape: "list", quoting: "inspect", separator: " or ", sorted: "false", when_empty: ""
|
|
525
|
+
member refusal: "TypeMismatch", site: "value_object_shape", argument: "name",
|
|
526
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
527
|
+
member refusal: "TypeMismatch", site: "value_object_shape", argument: "type",
|
|
528
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
529
|
+
member refusal: "TypeMismatch", site: "value_object_shape", argument: "offered",
|
|
530
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
531
|
+
member refusal: "TypeMismatch", site: "reference_wrong_shape", argument: "command",
|
|
532
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
533
|
+
member refusal: "TypeMismatch", site: "reference_wrong_shape", argument: "attribute",
|
|
534
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
535
|
+
member refusal: "TypeMismatch", site: "reference_wrong_shape", argument: "offered",
|
|
536
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
537
|
+
member refusal: "TypeMismatch", site: "reference_wrong_shape", argument: "known_by",
|
|
538
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
539
|
+
member refusal: "TypeMismatch", site: "multi_field_scalar", argument: "type",
|
|
540
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
541
|
+
member refusal: "TypeMismatch", site: "composite_identity", argument: "type",
|
|
542
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
543
|
+
member refusal: "TypeMismatch", site: "numeric_field", argument: "type",
|
|
544
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
545
|
+
member refusal: "TypeMismatch", site: "numeric_field", argument: "field",
|
|
546
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
547
|
+
member refusal: "TypeMismatch", site: "numeric_field", argument: "expected",
|
|
548
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
549
|
+
member refusal: "TypeMismatch", site: "numeric_field", argument: "offered",
|
|
550
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
551
|
+
member refusal: "TypeMismatch", site: "non_finite_field", argument: "type",
|
|
552
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
553
|
+
member refusal: "TypeMismatch", site: "non_finite_field", argument: "field",
|
|
554
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
555
|
+
member refusal: "TypeMismatch", site: "non_finite_field", argument: "offered",
|
|
556
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
557
|
+
member refusal: "TypeMismatch", site: "integer_range", argument: "type",
|
|
558
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
559
|
+
member refusal: "TypeMismatch", site: "integer_range", argument: "field",
|
|
560
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
561
|
+
member refusal: "TypeMismatch", site: "integer_range", argument: "offered",
|
|
562
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
563
|
+
member refusal: "TypeMismatch", site: "pattern_mismatch", argument: "type",
|
|
564
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
565
|
+
member refusal: "TypeMismatch", site: "pattern_mismatch", argument: "field",
|
|
566
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
567
|
+
member refusal: "TypeMismatch", site: "pattern_mismatch", argument: "pattern",
|
|
568
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
569
|
+
member refusal: "TypeMismatch", site: "pattern_mismatch", argument: "offered",
|
|
570
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
571
|
+
member refusal: "TypeMismatch", site: "arithmetic_amount", argument: "op",
|
|
572
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
573
|
+
member refusal: "TypeMismatch", site: "arithmetic_amount", argument: "target",
|
|
574
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
575
|
+
member refusal: "TypeMismatch", site: "arithmetic_amount", argument: "offered",
|
|
576
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
577
|
+
member refusal: "TypeMismatch", site: "arithmetic_current", argument: "op",
|
|
578
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
579
|
+
member refusal: "TypeMismatch", site: "arithmetic_current", argument: "target",
|
|
580
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
581
|
+
member refusal: "TypeMismatch", site: "arithmetic_current", argument: "offered",
|
|
582
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
583
|
+
member refusal: "TypeMismatch", site: "arithmetic_shared_field", argument: "op",
|
|
584
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
585
|
+
member refusal: "TypeMismatch", site: "arithmetic_shared_field", argument: "target",
|
|
586
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
587
|
+
member refusal: "UnknownArgument", site: "unknown_args", argument: "command",
|
|
588
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
589
|
+
member refusal: "UnknownArgument", site: "unknown_args", argument: "unknown",
|
|
590
|
+
shape: "list", quoting: "none", separator: ", ", sorted: "true", when_empty: ""
|
|
591
|
+
member refusal: "UnknownArgument", site: "unknown_args", argument: "declared",
|
|
592
|
+
shape: "list", quoting: "none", separator: ", ", sorted: "false", when_empty: "none"
|
|
593
|
+
member refusal: "AbsentArgument", site: "absent_args", argument: "command",
|
|
594
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
595
|
+
member refusal: "AbsentArgument", site: "absent_args", argument: "absent",
|
|
596
|
+
shape: "list", quoting: "none", separator: ", ", sorted: "true", when_empty: ""
|
|
597
|
+
member refusal: "AbsentArgument", site: "absent_args", argument: "declared",
|
|
598
|
+
shape: "list", quoting: "none", separator: ", ", sorted: "false", when_empty: "none"
|
|
599
|
+
member refusal: "InvariantViolation", site: "closed_set_member", argument: "type",
|
|
600
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
601
|
+
member refusal: "InvariantViolation", site: "closed_set_member", argument: "admitted",
|
|
602
|
+
shape: "list", quoting: "inspect", separator: ", ", sorted: "false", when_empty: ""
|
|
603
|
+
member refusal: "InvariantViolation", site: "closed_set_member", argument: "offered",
|
|
604
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
605
|
+
member refusal: "InvariantViolation", site: "value_object_invariant", argument: "name",
|
|
606
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
607
|
+
member refusal: "InvariantViolation", site: "value_object_invariant", argument: "description",
|
|
608
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
609
|
+
member refusal: "InvariantViolation", site: "value_object_invariant", argument: "offered",
|
|
610
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
611
|
+
member refusal: "InvariantViolation", site: "admits_declared_set", argument: "name",
|
|
612
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
613
|
+
member refusal: "InvariantViolation", site: "admits_declared_set", argument: "admits",
|
|
614
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
615
|
+
member refusal: "InvariantViolation", site: "admits_declared_set", argument: "admitted",
|
|
616
|
+
shape: "list", quoting: "inspect", separator: ", ", sorted: "false", when_empty: ""
|
|
617
|
+
member refusal: "InvariantViolation", site: "admits_declared_set", argument: "offered",
|
|
618
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
619
|
+
member refusal: "InvariantViolation", site: "undeclared_set", argument: "name",
|
|
620
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
621
|
+
member refusal: "InvariantViolation", site: "undeclared_set", argument: "admits",
|
|
622
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
623
|
+
member refusal: "Unauthorized", site: "tenant_required", argument: "query",
|
|
624
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
625
|
+
member refusal: "Unauthorized", site: "tenant_required", argument: "field",
|
|
626
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
627
|
+
member refusal: "Unauthorized", site: "role_mismatch", argument: "command",
|
|
628
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
629
|
+
member refusal: "Unauthorized", site: "role_mismatch", argument: "role",
|
|
630
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
631
|
+
member refusal: "Unauthorized", site: "role_mismatch", argument: "caller_role",
|
|
632
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
633
|
+
member refusal: "Unauthorized", site: "cross_tenant_reference", argument: "aggregate",
|
|
634
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
635
|
+
member refusal: "Unauthorized", site: "cross_tenant_reference", argument: "field",
|
|
636
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
637
|
+
member refusal: "Unauthorized", site: "cross_tenant_reference", argument: "tenant",
|
|
638
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
639
|
+
member refusal: "Unauthorized", site: "cross_tenant_reference", argument: "attribute",
|
|
640
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
641
|
+
member refusal: "Unauthorized", site: "cross_tenant_reference", argument: "target",
|
|
642
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
643
|
+
member refusal: "Unauthorized", site: "cross_tenant_reference", argument: "target_field",
|
|
644
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
645
|
+
member refusal: "Unauthorized", site: "cross_tenant_reference", argument: "other",
|
|
646
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
647
|
+
member refusal: "AttributeAbsent", site: "absent_read", argument: "aggregate",
|
|
648
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
649
|
+
member refusal: "AttributeAbsent", site: "absent_read", argument: "field",
|
|
650
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
651
|
+
member refusal: "ProjectionAbsent", site: "absent_read", argument: "aggregate",
|
|
652
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
653
|
+
member refusal: "ProjectionAbsent", site: "absent_read", argument: "field",
|
|
654
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
655
|
+
member refusal: "ProjectionAbsent", site: "absent_read", argument: "reference",
|
|
656
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
657
|
+
member refusal: "ProjectionAbsent", site: "absent_read", argument: "remote_field",
|
|
658
|
+
shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
|
|
659
|
+
end
|
|
660
|
+
|
|
354
661
|
# SagaInterpreter::REFUSED.
|
|
355
662
|
#
|
|
356
663
|
# A leg answers an EVENT — `on "AccountDebited"` — or it answers one of these,
|
|
@@ -373,10 +680,9 @@ Hecks.bluebook "Bluebook" do
|
|
|
373
680
|
# rendering convention, the same guess for every domain, not
|
|
374
681
|
# authored per-bluebook — closer to Comparison/SignTest than to a
|
|
375
682
|
# given. `pattern` is the regex SOURCE, no delimiters or flags
|
|
376
|
-
# (Ruby's own `Regexp#source`) —
|
|
377
|
-
#
|
|
378
|
-
#
|
|
379
|
-
# conformance_spec.rb already holds RefusalTemplate to.
|
|
683
|
+
# (Ruby's own `Regexp#source`) — FieldShape builds its four constants
|
|
684
|
+
# off these rows, and bin/project_field_hints writes the Rust host's
|
|
685
|
+
# copy from them, so neither side is typed by hand.
|
|
380
686
|
#
|
|
381
687
|
# `resolves_to` names WHICH Field attribute a match sets — `html_type`
|
|
382
688
|
# for email/url/tel (three candidates, only one wins, checked in that
|
|
@@ -392,5 +698,34 @@ Hecks.bluebook "Bluebook" do
|
|
|
392
698
|
member name: "tel", pattern: 'phone|\btel(ephone)?\b', resolves_to: "html_type"
|
|
393
699
|
member name: "textarea", pattern: '\b(text|body|note|notes|description|message|comment)\b', resolves_to: "kind"
|
|
394
700
|
end
|
|
701
|
+
|
|
702
|
+
# The Rust keywords (strict + reserved) a generated identifier must not
|
|
703
|
+
# collide with — RustProjection::Projector::RUST_KEYWORDS (rust/project/
|
|
704
|
+
# naming.rb) reads this, and bin/project_reserved_names projects it into
|
|
705
|
+
# rust/codegen/src/reserved_names.rs, so the Ruby and Rust generators
|
|
706
|
+
# escape (a field: `r#type`) or refuse (a module name) the SAME words.
|
|
707
|
+
# Declared once here because the two hand-typed copies were held equal
|
|
708
|
+
# by nothing but a comment.
|
|
709
|
+
value_object "RustReservedWord" do
|
|
710
|
+
attribute :word, String,
|
|
711
|
+
one_of: ["as", "break", "const", "continue", "crate", "dyn", "else", "enum", "extern", "false",
|
|
712
|
+
"fn", "for", "if", "impl", "in", "let", "loop", "match", "mod", "move", "mut", "pub",
|
|
713
|
+
"ref", "return", "self", "Self", "static", "struct", "super", "trait", "true", "type",
|
|
714
|
+
"unsafe", "use", "where", "while", "abstract", "become", "box", "do", "final", "macro",
|
|
715
|
+
"override", "priv", "typeof", "unsized", "virtual", "yield", "try"]
|
|
716
|
+
end
|
|
717
|
+
|
|
718
|
+
# The keys a domain's own name must not take, because that name doubles
|
|
719
|
+
# as a Cargo `[features]` key: every key rust/Cargo.toml already uses
|
|
720
|
+
# outside `[features]` (`[package]`, `[lib]`, `[[bin]]`) plus `default`,
|
|
721
|
+
# which Cargo reserves for the auto-enabled feature set. Read by
|
|
722
|
+
# RustProjection::Projector::CARGO_RESERVED_DOMAIN_NAMES and projected by
|
|
723
|
+
# bin/project_reserved_names, same as RustReservedWord above.
|
|
724
|
+
value_object "CargoReservedName" do
|
|
725
|
+
attribute :name, String,
|
|
726
|
+
one_of: ["name", "version", "edition", "path", "authors", "license", "description", "default",
|
|
727
|
+
"features", "package", "lib", "bin", "dependencies", "dev-dependencies",
|
|
728
|
+
"build-dependencies", "workspace"]
|
|
729
|
+
end
|
|
395
730
|
end
|
|
396
731
|
end
|
|
@@ -100,6 +100,16 @@ Hecks.bluebook "Hecksagon" do
|
|
|
100
100
|
member word: "uses_framework", context: "Hecksagon", body: "none", inner: "", opens: "", fills: "framework_members"
|
|
101
101
|
member word: "uses_embryonaut_bluebook", context: "Hecksagon", body: "none", inner: "", opens: "", fills: "vendored_bluebooks"
|
|
102
102
|
member word: "port", context: "Hecksagon", body: "keywords", inner: "DomainPort", opens: "DomainPort", fills: "", calls: "port_impl"
|
|
103
|
+
# A CROSS-DOMAIN REACTION, WIRED HERE INSTEAD OF THE BLUEBOOK — same
|
|
104
|
+
# underlying `Policy` shape a `policy` block already builds
|
|
105
|
+
# (`inner`/`opens: "Policy"` reuses that context's own `on`/`trigger`
|
|
106
|
+
# wholesale, zero new inner vocabulary), but declared as a wiring
|
|
107
|
+
# decision (which FOREIGN domain's event this chapter conforms to),
|
|
108
|
+
# the same kind of decision `port`/`uses_framework` already are.
|
|
109
|
+
# No `calls:` — `HecksagonBuilder#translates` is an ordinary method,
|
|
110
|
+
# the same shape `subscribe`/`uses_framework` already are, reached
|
|
111
|
+
# by Ruby's own method lookup before `word_gate` ever runs.
|
|
112
|
+
member word: "translates", context: "Hecksagon", body: "keywords", inner: "Policy", opens: "Policy", fills: ""
|
|
103
113
|
|
|
104
114
|
end
|
|
105
115
|
|
|
@@ -125,6 +135,7 @@ Hecks.bluebook "Hecksagon" do
|
|
|
125
135
|
member keyword: "uses_framework", context: "Hecksagon", at: "1", named: "", kind: "text", required: "true", fills: "framework_members"
|
|
126
136
|
member keyword: "uses_embryonaut_bluebook", context: "Hecksagon", at: "1", named: "", kind: "text", required: "true", fills: "vendored_bluebooks"
|
|
127
137
|
member keyword: "port", context: "Hecksagon", at: "1", named: "", kind: "text", required: "true", fills: "name"
|
|
138
|
+
member keyword: "translates", context: "Hecksagon", at: "1", named: "", kind: "text", required: "true", fills: "name"
|
|
128
139
|
|
|
129
140
|
end
|
|
130
141
|
end
|
|
@@ -76,6 +76,11 @@
|
|
|
76
76
|
"verb": "Bluebook::Bluebook.Normalise",
|
|
77
77
|
"role": "Language"
|
|
78
78
|
},
|
|
79
|
+
{
|
|
80
|
+
"scope": "bluebook:bluebook.provide",
|
|
81
|
+
"verb": "Bluebook::Bluebook.Provide",
|
|
82
|
+
"role": "Language"
|
|
83
|
+
},
|
|
79
84
|
{
|
|
80
85
|
"scope": "bluebook:command.acts_on",
|
|
81
86
|
"verb": "Bluebook::Command.ActsOn",
|
data/lib/hecks/literal.rb
CHANGED
|
@@ -1,31 +1,31 @@
|
|
|
1
1
|
module Hecks
|
|
2
|
-
#
|
|
2
|
+
# The one spelling for a captured Ruby literal on the wire.
|
|
3
3
|
#
|
|
4
4
|
# Several `to_h` fields hold a value the author wrote in a bluebook —
|
|
5
5
|
# `where(status: { eq: "open" })`, `then_set append: { direction: { value:
|
|
6
6
|
# "credit" } }`, `dispatch ... with: { number: :source }`, an attribute's
|
|
7
|
-
# `default:` — as
|
|
7
|
+
# `default:` — as text, because the export has to stand on its own and a
|
|
8
8
|
# String field cannot say "this one was a Symbol". Every such field is the
|
|
9
9
|
# same question and now gets the same answer.
|
|
10
10
|
#
|
|
11
11
|
# It was three answers before, and they disagreed on both axes that matter.
|
|
12
|
-
# `Mutation#appended_fields` spelled a Symbol
|
|
13
|
-
# `inspect`; `QuerySpecification.render_value` spelled a Symbol with a
|
|
12
|
+
# `Mutation#appended_fields` spelled a Symbol bare and everything else
|
|
13
|
+
# `inspect`; `QuerySpecification.render_value` spelled a Symbol with a colon
|
|
14
14
|
# and everything else `to_s`. So `:amount` crossed as "amount" in a mutation
|
|
15
15
|
# and ":amount" in a saga binding — the same value, two spellings, and each
|
|
16
16
|
# reader had to know which field it was looking at. Worse, `to_s`/`inspect`
|
|
17
|
-
# on a Hash is Ruby's
|
|
17
|
+
# on a Hash is Ruby's own rendering, which moved under us: 3.3 writes
|
|
18
18
|
# `{:value=>"credit"}` and 3.4 writes `{value: "credit"}` for the identical
|
|
19
19
|
# Hash, so the wire format was silently pinned to an interpreter version.
|
|
20
20
|
#
|
|
21
|
-
#
|
|
21
|
+
# Self-describing is the rule, stated once here rather than inherited from
|
|
22
22
|
# whatever `inspect` happens to do: a symbol wears its colon, a string wears
|
|
23
23
|
# its quotes, a hash wears `{key: value}` braces, a list wears its brackets,
|
|
24
24
|
# and a number, a boolean and nil are bare. `read` is the exact inverse, and
|
|
25
25
|
# is the only thing that should ever take one of these strings apart.
|
|
26
|
-
# A
|
|
26
|
+
# A mutation source that reads the record's own state — `sets :positions,
|
|
27
27
|
# append: { knights: state(:knights) }`. A bare Symbol in a mutation
|
|
28
|
-
# source always names a command
|
|
28
|
+
# source always names a command argument (and imports it as one when
|
|
29
29
|
# the target's own field carries the same name — `CommandBuilder
|
|
30
30
|
# #resolve_append_fields!`); before this there was no way to say "the
|
|
31
31
|
# value this field already holds", so a command could not snapshot its
|
|
@@ -43,6 +43,12 @@ module Hecks
|
|
|
43
43
|
module Literal
|
|
44
44
|
module_function
|
|
45
45
|
|
|
46
|
+
# Turns a Ruby value into its self-describing wire spelling.
|
|
47
|
+
#
|
|
48
|
+
# @param value [Object] value to render: nil, Symbol, String, StateRef, true,
|
|
49
|
+
# false, Integer, Float, Hash, or Array (recursively)
|
|
50
|
+
# @return [String] the self-describing spelling `read` can parse back
|
|
51
|
+
# @raise [ArgumentError] if `value` is a type with no pinned literal spelling
|
|
46
52
|
def render(value)
|
|
47
53
|
case value
|
|
48
54
|
when nil then "nil"
|
|
@@ -67,6 +73,9 @@ module Hecks
|
|
|
67
73
|
# `return`; splitting them into named predicates would just rename
|
|
68
74
|
# each line without changing what it does, and would separate this
|
|
69
75
|
# method from the `render` it is the deliberate mirror of.
|
|
76
|
+
# @param text [String, #to_s] wire spelling produced by `render`, or a bare word
|
|
77
|
+
# @return [Object] nil, true, false, Integer, Float, Symbol, StateRef, String,
|
|
78
|
+
# Hash, or Array — or `text` itself, stripped, when it matches no known spelling
|
|
70
79
|
# rubocop:disable-next Metrics/CyclomaticComplexity
|
|
71
80
|
# rubocop:disable-next Metrics/PerceivedComplexity
|
|
72
81
|
def read(text)
|
|
@@ -87,12 +96,28 @@ module Hecks
|
|
|
87
96
|
|
|
88
97
|
ESCAPED = { '"' => '\\"', "\\" => "\\\\" }.freeze
|
|
89
98
|
|
|
99
|
+
# Wraps `text` in double quotes, escaping embedded quotes and backslashes.
|
|
100
|
+
#
|
|
101
|
+
# @param text [String] raw text to quote
|
|
102
|
+
# @return [String] the quoted, escaped spelling
|
|
90
103
|
def quote(text) = "\"#{text.gsub(/["\\]/) { |char| ESCAPED[char] }}\""
|
|
91
104
|
|
|
105
|
+
# Tells whether `raw` is a double-quoted literal.
|
|
106
|
+
#
|
|
107
|
+
# @param raw [String] wire text to check
|
|
108
|
+
# @return [Boolean]
|
|
92
109
|
def quoted?(raw) = raw.length >= 2 && raw.start_with?('"') && raw.end_with?('"')
|
|
93
110
|
|
|
111
|
+
# Strips the surrounding quotes from a quoted literal and unescapes it.
|
|
112
|
+
#
|
|
113
|
+
# @param raw [String] a quoted literal, as `quoted?` would confirm
|
|
114
|
+
# @return [String] the unescaped text inside the quotes
|
|
94
115
|
def unquote(raw) = raw[1..-2].gsub(/\\(.)/) { ::Regexp.last_match(1) }
|
|
95
116
|
|
|
117
|
+
# Parses a `{key: value, ...}` wire literal.
|
|
118
|
+
#
|
|
119
|
+
# @param raw [String] text starting with `{` and ending with `}`
|
|
120
|
+
# @return [Hash{Symbol => Object}] the parsed hash, values read recursively via `read`
|
|
96
121
|
def read_hash(raw)
|
|
97
122
|
split_items(raw[1..-2]).to_h do |item|
|
|
98
123
|
key, _, held = item.partition(":")
|
|
@@ -100,12 +125,19 @@ module Hecks
|
|
|
100
125
|
end
|
|
101
126
|
end
|
|
102
127
|
|
|
128
|
+
# Parses a `[value, ...]` wire literal.
|
|
129
|
+
#
|
|
130
|
+
# @param raw [String] text starting with `[` and ending with `]`
|
|
131
|
+
# @return [Array<Object>] the parsed values, each read recursively via `read`
|
|
103
132
|
def read_array(raw) = split_items(raw[1..-2]).map { |item| read(item) }
|
|
104
133
|
|
|
105
|
-
# Split on the commas that are actually
|
|
134
|
+
# Split on the commas that are actually separators — never one inside a
|
|
106
135
|
# quoted string or a nested brace/bracket. Scanned rather than
|
|
107
136
|
# `String#split(", ")`, which tore `"a, b"` in half and lost the second
|
|
108
137
|
# field of anything nested.
|
|
138
|
+
#
|
|
139
|
+
# @param body [String] the text between a literal's outer braces or brackets
|
|
140
|
+
# @return [Array<String>] each item's raw text, stripped, with empty items dropped
|
|
109
141
|
def split_items(body)
|
|
110
142
|
items = []
|
|
111
143
|
current = +""
|