hecks 2.7.0 → 2.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/exe/hecks +11 -0
- data/lib/hecks/adapters/driven/claude_code.rb +4 -104
- data/lib/hecks/adapters/driven/d1.rb +44 -237
- data/lib/hecks/adapters/driven/folder.rb +17 -76
- data/lib/hecks/adapters/driven/google_authentication.rb +15 -49
- data/lib/hecks/adapters/driven/governance_authorization.rb +23 -70
- data/lib/hecks/adapters/driven/heki/journal.rb +8 -41
- data/lib/hecks/adapters/driven/heki/saga_store.rb +12 -54
- data/lib/hecks/adapters/driven/heki/snapshot.rb +4 -12
- data/lib/hecks/adapters/driven/heki.rb +13 -42
- data/lib/hecks/adapters/driven/identity_registry.rb +3 -14
- data/lib/hecks/adapters/driven/in_memory_ordering.rb +9 -26
- data/lib/hecks/adapters/driven/in_process_key_vault.rb +2 -14
- data/lib/hecks/adapters/driven/lambda/client.rb +10 -51
- data/lib/hecks/adapters/driven/lambda.rb +10 -84
- data/lib/hecks/adapters/driven/local_storage.rb +5 -40
- data/lib/hecks/adapters/driven/memory.rb +18 -99
- data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +5 -21
- data/lib/hecks/adapters/driven/postgres/codec.rb +6 -28
- data/lib/hecks/adapters/driven/postgres/outbox.rb +3 -12
- data/lib/hecks/adapters/driven/postgres/reconnect.rb +4 -30
- data/lib/hecks/adapters/driven/postgres/schema_builder.rb +34 -108
- data/lib/hecks/adapters/driven/postgres.rb +145 -134
- data/lib/hecks/adapters/driven/postgres_era.adapter +4 -15
- data/lib/hecks/adapters/driven/prism.rb +7 -30
- data/lib/hecks/adapters/driven/sql_query_builder.rb +21 -121
- data/lib/hecks/adapters/driven/sqlite/codec.rb +8 -40
- data/lib/hecks/adapters/driven/sqlite/projection.rb +26 -82
- data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +40 -84
- data/lib/hecks/adapters/driven/sqlite.rb +128 -65
- data/lib/hecks/adapters/driven/tenant_provisioner.rb +15 -37
- data/lib/hecks/adapters/driven.rb +5 -36
- data/lib/hecks/adapters/driving/github_webhook.rb +8 -76
- data/lib/hecks/behaviors/dsl.rb +7 -25
- data/lib/hecks/behaviors/expectations.rb +32 -142
- data/lib/hecks/behaviors/ir.rb +7 -20
- data/lib/hecks/behaviors/rspec.rb +6 -17
- data/lib/hecks/behaviors/runner.rb +10 -34
- data/lib/hecks/behaviors.rb +4 -8
- data/lib/hecks/bluebook/aggregate.rb +9 -75
- data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +9 -38
- data/lib/hecks/bluebook/assembly/build.rb +4 -15
- data/lib/hecks/bluebook/assembly/contract.rb +15 -136
- data/lib/hecks/bluebook/assembly/contracts.rb +54 -174
- data/lib/hecks/bluebook/assembly/marks.rb +31 -223
- data/lib/hecks/bluebook/assembly/specializer.rb +6 -52
- data/lib/hecks/bluebook/assembly.rb +6 -45
- data/lib/hecks/bluebook/attribute.rb +12 -61
- data/lib/hecks/bluebook/behaviour/aggregate.rb +10 -39
- data/lib/hecks/bluebook/behaviour/attribute.rb +3 -14
- data/lib/hecks/bluebook/behaviour/chapter.rb +17 -42
- data/lib/hecks/bluebook/behaviour/command.rb +14 -66
- data/lib/hecks/bluebook/behaviour/domain_port.rb +4 -20
- data/lib/hecks/bluebook/behaviour/entity.rb +7 -27
- data/lib/hecks/bluebook/behaviour/hexagon.rb +23 -41
- data/lib/hecks/bluebook/behaviour/lifecycle.rb +15 -40
- data/lib/hecks/bluebook/behaviour/policy.rb +23 -52
- data/lib/hecks/bluebook/behaviour/process_manager.rb +30 -57
- data/lib/hecks/bluebook/behaviour/read_model.rb +38 -26
- data/lib/hecks/bluebook/behaviour/traits.rb +27 -64
- data/lib/hecks/bluebook/behaviour/value_object.rb +5 -24
- data/lib/hecks/bluebook/capabilities.rb +17 -49
- data/lib/hecks/bluebook/chapter.rb +10 -48
- data/lib/hecks/bluebook/command.rb +23 -81
- data/lib/hecks/bluebook/domain_port.rb +14 -63
- data/lib/hecks/bluebook/dsl/aggregate_builder/sealing.rb +50 -229
- data/lib/hecks/bluebook/dsl/aggregate_builder.rb +50 -377
- data/lib/hecks/bluebook/dsl/attribute_collector.rb +33 -204
- data/lib/hecks/bluebook/dsl/binding_proxy.rb +17 -65
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +86 -708
- data/lib/hecks/bluebook/dsl/bluebook_builder.rb +56 -170
- data/lib/hecks/bluebook/dsl/bootstrap_table.rb +1 -0
- data/lib/hecks/bluebook/dsl/command_builder.rb +74 -546
- data/lib/hecks/bluebook/dsl/const_shim.rb +8 -41
- data/lib/hecks/bluebook/dsl/domain_port_builder.rb +12 -87
- data/lib/hecks/bluebook/dsl/entity_builder.rb +44 -330
- data/lib/hecks/bluebook/dsl/generic_dispatch.rb +20 -269
- data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +26 -189
- data/lib/hecks/bluebook/dsl/identity_declaration.rb +13 -88
- data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +6 -20
- data/lib/hecks/bluebook/dsl/policy_builder.rb +16 -88
- data/lib/hecks/bluebook/dsl/port_builder.rb +2 -6
- data/lib/hecks/bluebook/dsl/port_operation_builder.rb +22 -96
- data/lib/hecks/bluebook/dsl/process_manager_builder.rb +31 -184
- data/lib/hecks/bluebook/dsl/query_builder.rb +11 -42
- data/lib/hecks/bluebook/dsl/read_model_builder.rb +75 -201
- data/lib/hecks/bluebook/dsl/rule_reference.rb +22 -163
- data/lib/hecks/bluebook/dsl/translation_builder.rb +28 -114
- data/lib/hecks/bluebook/dsl/value_object_builder.rb +10 -124
- data/lib/hecks/bluebook/dsl/word_gate.rb +16 -162
- data/lib/hecks/bluebook/dsl/world_builder.rb +19 -106
- data/lib/hecks/bluebook/entity.rb +13 -71
- data/lib/hecks/bluebook/expression/ast_json.rb +24 -190
- data/lib/hecks/bluebook/expression/ast_reader.rb +12 -54
- data/lib/hecks/bluebook/expression/canonical_form.rb +11 -88
- data/lib/hecks/bluebook/expression/evaluator.rb +47 -295
- data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +30 -147
- data/lib/hecks/bluebook/expression/resolver.rb +37 -660
- data/lib/hecks/bluebook/hexagon.rb +5 -28
- data/lib/hecks/bluebook/lifecycle.rb +5 -16
- data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +1 -7
- data/lib/hecks/bluebook/meta_validator/judge.rb +111 -361
- data/lib/hecks/bluebook/meta_validator/plan.rb +33 -162
- data/lib/hecks/bluebook/meta_validator/port_judge.rb +2 -7
- data/lib/hecks/bluebook/meta_validator/readings.rb +56 -342
- data/lib/hecks/bluebook/meta_validator/reconstruction.rb +24 -176
- data/lib/hecks/bluebook/meta_validator/shapes.rb +54 -268
- data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +47 -308
- data/lib/hecks/bluebook/meta_validator/translation_judge.rb +7 -43
- data/lib/hecks/bluebook/meta_validator/world_judge.rb +6 -18
- data/lib/hecks/bluebook/meta_validator.rb +79 -349
- data/lib/hecks/bluebook/model_check/client_profile.rb +10 -91
- data/lib/hecks/bluebook/model_check.rb +102 -600
- data/lib/hecks/bluebook/pattern_subset.rb +11 -69
- data/lib/hecks/bluebook/process_manager.rb +13 -83
- data/lib/hecks/bluebook/project_loader.rb +3 -39
- data/lib/hecks/bluebook/project_register.rb +12 -60
- data/lib/hecks/bluebook/query.rb +9 -48
- data/lib/hecks/bluebook/read_model.rb +57 -81
- data/lib/hecks/bluebook/reference.rb +7 -41
- data/lib/hecks/bluebook/smoke_test.rb +8 -98
- data/lib/hecks/bluebook/synthesizer.rb +13 -62
- data/lib/hecks/bluebook/translation.rb +26 -62
- data/lib/hecks/bluebook/value_object.rb +11 -36
- data/lib/hecks/bluebook.rb +5 -22
- data/lib/hecks/cache_dir.rb +84 -0
- data/lib/hecks/cli/document.rb +86 -0
- data/lib/hecks/cli/ir.rb +45 -0
- data/lib/hecks/cli/mcp.rb +31 -0
- data/lib/hecks/cli/mcp_door.rb +366 -0
- data/lib/hecks/cli/model_check.rb +203 -0
- data/lib/hecks/cli/project_cli.rb +90 -0
- data/lib/hecks/cli/project_diagrams.rb +36 -0
- data/lib/hecks/cli/run.rb +173 -0
- data/lib/hecks/cli/smoke_test.rb +45 -0
- data/lib/hecks/cli/stores.rb +53 -0
- data/lib/hecks/cli.rb +160 -0
- data/lib/hecks/construct.rb +8 -34
- data/lib/hecks/deploy/bluebook/deploy.bluebook +33 -142
- data/lib/hecks/deploy/bluebook/deploy.hecksagon +2 -9
- data/lib/hecks/embryonaut_bluebook/lock.rb +3 -35
- data/lib/hecks/embryonaut_bluebook/shape.rb +1 -17
- data/lib/hecks/embryonaut_bluebook/vendor.rb +8 -53
- data/lib/hecks/embryonaut_bluebook/vendor_cli.rb +4 -19
- data/lib/hecks/embryonaut_bluebook.rb +4 -71
- data/lib/hecks/facade/cli_door.rb +24 -106
- data/lib/hecks/facade/cli_runner.rb +28 -172
- data/lib/hecks/facade/command_request.rb +13 -33
- data/lib/hecks/facade/handle.rb +34 -121
- data/lib/hecks/facade/json_door.rb +31 -146
- data/lib/hecks/facade/surface/aggregate_door.rb +39 -104
- data/lib/hecks/facade/surface/chapter.rb +10 -54
- data/lib/hecks/facade/surface.rb +8 -23
- data/lib/hecks/facade.rb +10 -25
- data/lib/hecks/forms/app.rb +15 -70
- data/lib/hecks/forms/command_form_renderer.rb +10 -29
- data/lib/hecks/forms/field_renderer.rb +17 -156
- data/lib/hecks/forms/field_shape.rb +30 -222
- data/lib/hecks/forms/html.rb +12 -47
- data/lib/hecks/forms/index_renderer.rb +1 -4
- data/lib/hecks/forms/page.rb +3 -9
- data/lib/hecks/forms/params.rb +14 -60
- data/lib/hecks/forms/port_argument.rb +2 -19
- data/lib/hecks/forms/query_form_renderer.rb +4 -79
- data/lib/hecks/forms/record_renderer.rb +8 -75
- data/lib/hecks/forms/record_table.rb +7 -50
- data/lib/hecks/forms/reference_options.rb +3 -30
- data/lib/hecks/forms/value_object_shape.rb +8 -35
- data/lib/hecks/forms.rb +5 -33
- data/lib/hecks/fqn.rb +5 -12
- data/lib/hecks/framework/bluebook/compliance.bluebook +16 -65
- data/lib/hecks/framework/bluebook/console_settings.bluebook +47 -134
- data/lib/hecks/framework/bluebook/framework.hecksagon +5 -14
- data/lib/hecks/framework/bluebook/governance.bluebook +13 -34
- data/lib/hecks/framework/bluebook/identity.bluebook +11 -26
- data/lib/hecks/framework/bluebook/privacy.bluebook +8 -33
- data/lib/hecks/framework.rb +11 -80
- data/lib/hecks/freezer.rb +5 -39
- data/lib/hecks/grammar/expression.bluebook +15 -40
- data/lib/hecks/grammar/translation.bluebook +3 -6
- data/lib/hecks/grammar.rb +16 -41
- data/lib/hecks/ir.rb +14 -83
- data/lib/hecks/language/adapter.bluebook +2 -7
- data/lib/hecks/language/bluebook/aggregate.bluebook +56 -221
- data/lib/hecks/language/bluebook/attaches/paging.bluebook +6 -15
- data/lib/hecks/language/bluebook/bluebook.bluebook +15 -83
- data/lib/hecks/language/bluebook/bluebook.hecksagon +3 -15
- data/lib/hecks/language/bluebook/command.bluebook +27 -144
- data/lib/hecks/language/bluebook/entity.bluebook +24 -97
- data/lib/hecks/language/bluebook/policy.bluebook +16 -67
- data/lib/hecks/language/bluebook/process_manager.bluebook +28 -151
- data/lib/hecks/language/bluebook/projection.bluebook +126 -60
- data/lib/hecks/language/bluebook/query.bluebook +12 -43
- data/lib/hecks/language/bluebook/shape.bluebook +23 -73
- data/lib/hecks/language/bluebook/syntax.bluebook +51 -262
- data/lib/hecks/language/bluebook/vocabulary.bluebook +98 -197
- data/lib/hecks/language/hecksagon/adapter_binding.bluebook +3 -10
- data/lib/hecks/language/hecksagon/domain_port.bluebook +4 -19
- data/lib/hecks/language/hecksagon/hecksagon.bluebook +6 -25
- data/lib/hecks/language/hecksagon/port_operation.bluebook +3 -14
- data/lib/hecks/language/oidc.json +35 -0
- data/lib/hecks/language/port.bluebook +4 -17
- data/lib/hecks/language/translation/translation.bluebook +3 -9
- data/lib/hecks/language/translation/translation_aggregate.bluebook +5 -24
- data/lib/hecks/language/world/wiring.bluebook +1 -3
- data/lib/hecks/language/world/world.bluebook +5 -7
- data/lib/hecks/literal.rb +8 -50
- data/lib/hecks/mcp_door_scope.rb +95 -0
- data/lib/hecks/mcp_stdio_guard.rb +4 -41
- data/lib/hecks/naming.rb +29 -137
- data/lib/hecks/ports/access_control.rb +7 -23
- data/lib/hecks/ports/agent/answers.rb +5 -23
- data/lib/hecks/ports/agent.rb +47 -172
- data/lib/hecks/ports/authentication.rb +12 -39
- data/lib/hecks/ports/authorization.rb +16 -43
- data/lib/hecks/ports/clock.rb +5 -45
- data/lib/hecks/ports/extraction.rb +7 -12
- data/lib/hecks/ports/identity_assignment.rb +8 -29
- data/lib/hecks/ports/identity_generation.rb +6 -29
- data/lib/hecks/ports/identity_resolution.rb +2 -10
- data/lib/hecks/ports/key_vault.rb +9 -45
- data/lib/hecks/ports/persistence/append_only.rb +62 -65
- data/lib/hecks/ports/persistence/binding_policy.rb +4 -14
- data/lib/hecks/ports/persistence/codec_boundary.rb +20 -80
- data/lib/hecks/ports/persistence/null_saga_store.rb +4 -20
- data/lib/hecks/ports/persistence/plugin.rb +13 -42
- data/lib/hecks/ports/persistence/plugins/era/era_check.rb +38 -141
- data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +15 -115
- data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +16 -84
- data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +7 -26
- data/lib/hecks/ports/persistence/plugins/era/expected_era.rb +3 -22
- data/lib/hecks/ports/persistence/plugins/era/lineage.rb +55 -181
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/events.rb +77 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +12 -122
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +28 -128
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +73 -474
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +31 -124
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +45 -219
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +13 -108
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +18 -75
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +9 -49
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +6 -123
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +23 -55
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +14 -72
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +7 -16
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +14 -115
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +13 -45
- data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +127 -554
- data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +13 -63
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +2 -17
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +3 -14
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +13 -58
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +3 -17
- data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +9 -26
- data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +9 -25
- data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +22 -122
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +34 -123
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/renderer.rb +5 -12
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +3 -9
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +2 -14
- data/lib/hecks/ports/persistence/plugins/era.rb +4 -23
- data/lib/hecks/ports/persistence/postgres_dump/connection.rb +7 -23
- data/lib/hecks/ports/persistence/postgres_dump.rb +4 -35
- data/lib/hecks/ports/persistence/remote_runtime.rb +2 -24
- data/lib/hecks/ports/persistence/repository_factory.rb +8 -27
- data/lib/hecks/ports/persistence/state_codec.rb +23 -103
- data/lib/hecks/ports/persistence.rb +7 -14
- data/lib/hecks/ports/projection.rb +42 -84
- data/lib/hecks/ports/query/in_memory.rb +10 -58
- data/lib/hecks/ports/query/ordering.rb +11 -32
- data/lib/hecks/ports/query.rb +14 -37
- data/lib/hecks/ports.rb +2 -8
- data/lib/hecks/projections/bootstrap_table.rb +11 -43
- data/lib/hecks/projections/deploy/fargate/assembly.rb +2 -15
- data/lib/hecks/projections/deploy/fargate/cdn.rb +1 -48
- data/lib/hecks/projections/deploy/fargate/cdn_default.rb +2 -11
- data/lib/hecks/projections/deploy/fargate/check.rb +5 -14
- data/lib/hecks/projections/deploy/fargate/containers.rb +3 -78
- data/lib/hecks/projections/deploy/fargate/extras.rb +3 -44
- data/lib/hecks/projections/deploy/fargate/monitoring.rb +0 -44
- data/lib/hecks/projections/deploy/fargate/settings.rb +2 -54
- data/lib/hecks/projections/deploy/fargate/yaml.rb +13 -58
- data/lib/hecks/projections/deploy/fargate.rb +35 -202
- data/lib/hecks/projections/deploy/lambda.rb +151 -679
- data/lib/hecks/projections/deploy/preview/access_yaml.rb +1 -33
- data/lib/hecks/projections/deploy/preview/containers.rb +6 -111
- data/lib/hecks/projections/deploy/preview/routing_yaml.rb +4 -56
- data/lib/hecks/projections/deploy/preview/script.rb +2 -14
- data/lib/hecks/projections/deploy/preview/settings.rb +3 -33
- data/lib/hecks/projections/deploy/preview/task_yaml.rb +2 -38
- data/lib/hecks/projections/deploy/preview/template.rb +2 -58
- data/lib/hecks/projections/deploy/preview.rb +2 -67
- data/lib/hecks/projections/deploy/scripts/settings.rb +3 -25
- data/lib/hecks/projections/deploy/scripts.rb +4 -57
- data/lib/hecks/projections/deploy/shared.rb +47 -146
- data/lib/hecks/projections/deploy/smoke.rb +4 -61
- data/lib/hecks/projections/deploy/template_diff/comparer.rb +3 -25
- data/lib/hecks/projections/deploy/template_diff/loader.rb +2 -11
- data/lib/hecks/projections/deploy/template_diff.rb +5 -57
- data/lib/hecks/projections/diagrams.rb +20 -582
- data/lib/hecks/projections/glossary/html.rb +14 -130
- data/lib/hecks/projections/glossary/markdown.rb +8 -69
- data/lib/hecks/projections/glossary/mermaid.rb +9 -66
- data/lib/hecks/projections/glossary/sensitivity.rb +5 -34
- data/lib/hecks/projections/glossary/sentences.rb +14 -159
- data/lib/hecks/projections/glossary.rb +30 -222
- data/lib/hecks/projections/ir.rb +3 -10
- data/lib/hecks/projections/model/deviations.rb +15 -42
- data/lib/hecks/projections/model.rb +12 -51
- data/lib/hecks/projections/oidc.rb +12 -56
- data/lib/hecks/projections/parser_table.rb +9 -28
- data/lib/hecks/projections/reference.rb +9 -16
- data/lib/hecks/projections/rust_vocabulary.rb +12 -250
- data/lib/hecks/projections/shape.rb +3 -29
- data/lib/hecks/projections/statements.rb +7 -86
- data/lib/hecks/projections/vocabulary.rb +6 -22
- data/lib/hecks/projections.rb +2 -16
- data/lib/hecks/projector/cli_projector.rb +60 -375
- data/lib/hecks/projector/docs_projector.rb +10 -201
- data/lib/hecks/projector/exporter.rb +46 -138
- data/lib/hecks/projector/ir_projector.rb +2 -9
- data/lib/hecks/projector/narrate_projector.rb +15 -189
- data/lib/hecks/projector/target.rb +13 -76
- data/lib/hecks/projector.rb +30 -121
- data/lib/hecks/query_specification/common/comparators.rb +5 -26
- data/lib/hecks/query_specification/common/comparison.rb +35 -143
- data/lib/hecks/query_specification/common/dsl.rb +8 -24
- data/lib/hecks/query_specification/common/null_policy.rb +20 -70
- data/lib/hecks/query_specification/common/options.rb +2 -6
- data/lib/hecks/query_specification/common/where_clause.rb +2 -10
- data/lib/hecks/query_specification/field_path.rb +37 -77
- data/lib/hecks/query_specification/hop_path.rb +12 -76
- data/lib/hecks/release/gem_pin.rb +2 -26
- data/lib/hecks/release/runner/ci_publisher.rb +93 -0
- data/lib/hecks/release/runner/commands.rb +66 -0
- data/lib/hecks/release/runner/console.rb +52 -0
- data/lib/hecks/release/runner/gem_publisher.rb +43 -0
- data/lib/hecks/release/runner/git.rb +48 -0
- data/lib/hecks/release/runner/npm_publisher.rb +75 -0
- data/lib/hecks/release/runner/preflight.rb +104 -0
- data/lib/hecks/release/runner/published.rb +55 -0
- data/lib/hecks/release/runner/tagger.rb +80 -0
- data/lib/hecks/release/runner.rb +215 -0
- data/lib/hecks/rendering.rb +4 -26
- data/lib/hecks/router/namespace_installer.rb +12 -36
- data/lib/hecks/router.rb +4 -8
- data/lib/hecks/runtime/aggregate_lock.rb +8 -33
- data/lib/hecks/runtime/boot_gates.rb +3 -18
- data/lib/hecks/runtime/caller.rb +19 -59
- data/lib/hecks/runtime/capability_graph.rb +5 -21
- data/lib/hecks/runtime/command_interpreter/argument_gate.rb +16 -78
- data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +23 -160
- data/lib/hecks/runtime/command_interpreter.rb +125 -307
- data/lib/hecks/runtime/command_rules/admissibility.rb +95 -366
- data/lib/hecks/runtime/command_rules/arithmetic.rb +66 -196
- data/lib/hecks/runtime/command_rules/authorization.rb +13 -45
- data/lib/hecks/runtime/command_rules/emission.rb +8 -21
- data/lib/hecks/runtime/command_rules/references.rb +23 -202
- data/lib/hecks/runtime/dependency_planning.rb +30 -102
- data/lib/hecks/runtime/dispatcher.rb +82 -241
- data/lib/hecks/runtime/entity_element.rb +40 -462
- data/lib/hecks/runtime/entity_interpreter.rb +65 -220
- data/lib/hecks/runtime/errors.rb +32 -115
- data/lib/hecks/runtime/event.rb +3 -25
- data/lib/hecks/runtime/identity.rb +18 -154
- data/lib/hecks/runtime/instance.rb +18 -150
- data/lib/hecks/runtime/interpreting.rb +11 -70
- data/lib/hecks/runtime/invocation.rb +28 -164
- data/lib/hecks/runtime/loader.rb +48 -186
- data/lib/hecks/runtime/outbox.rb +38 -261
- data/lib/hecks/runtime/policy_interpreter.rb +38 -200
- data/lib/hecks/runtime/port_operation_interpreter.rb +26 -87
- data/lib/hecks/runtime/query_interpreter.rb +45 -187
- data/lib/hecks/runtime/reaction_invocation.rb +36 -138
- data/lib/hecks/runtime/read_model_interpreter.rb +139 -208
- data/lib/hecks/runtime/rebuild_sweep.rb +8 -54
- data/lib/hecks/runtime/reference_hop.rb +8 -81
- data/lib/hecks/runtime/refusal_wording.rb +8 -89
- data/lib/hecks/runtime/registry/saga_persistence.rb +10 -102
- data/lib/hecks/runtime/registry/verification.rb +52 -225
- data/lib/hecks/runtime/registry/world_defaults.rb +4 -53
- data/lib/hecks/runtime/registry.rb +103 -244
- data/lib/hecks/runtime/remote_dispatcher.rb +37 -152
- data/lib/hecks/runtime/routing.rb +4 -15
- data/lib/hecks/runtime/saga_interpreter/correlation.rb +14 -61
- data/lib/hecks/runtime/saga_interpreter.rb +79 -263
- data/lib/hecks/runtime/saga_pending_dispatch.rb +2 -43
- data/lib/hecks/runtime/tenant_check.rb +6 -68
- data/lib/hecks/runtime/tenant_scope.rb +3 -28
- data/lib/hecks/runtime/value/admission.rb +16 -67
- data/lib/hecks/runtime/value/coercion.rb +155 -641
- data/lib/hecks/runtime/value/entity_list_coercion.rb +26 -219
- data/lib/hecks/runtime/value.rb +12 -84
- data/lib/hecks/runtime.rb +17 -65
- data/lib/hecks/storehouse.rb +146 -567
- data/lib/hecks/tenancy/bluebook/tenancy.bluebook +8 -32
- data/lib/hecks/tenancy/bluebook/tenancy.hecksagon +6 -23
- data/lib/hecks/vendoring/git_environment.rb +2 -8
- data/lib/hecks/vendoring/git_source.rb +4 -10
- data/lib/hecks/vendoring.rb +7 -46
- data/lib/hecks/version.rb +3 -14
- data/lib/hecks/vocabulary.rb +5 -0
- data/lib/hecks.rb +32 -82
- data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +8 -46
- data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +11 -80
- data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +10 -99
- metadata +30 -59
- data/lib/hecks/bench/cli.rb +0 -74
- data/lib/hecks/bench/environment.rb +0 -100
- data/lib/hecks/bench/postgres_probe.rb +0 -41
- data/lib/hecks/bench/report.rb +0 -116
- data/lib/hecks/bench/ruby_runner.rb +0 -151
- data/lib/hecks/bench/run.rb +0 -55
- data/lib/hecks/bench/rust_runner.rb +0 -165
- data/lib/hecks/bench/stats.rb +0 -75
- data/lib/hecks/bench/suite.rb +0 -172
- data/lib/hecks/bench/workload.rb +0 -137
- data/lib/hecks/bench.rb +0 -28
- data/lib/hecks/codemod.rb +0 -443
- data/lib/hecks/corpus.rb +0 -479
- data/lib/hecks/doc/reference.rb +0 -585
- data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +0 -684
- data/lib/hecks/fuzzing/combination_miner.rb +0 -178
- data/lib/hecks/fuzzing/concurrent_dispatch.rb +0 -469
- data/lib/hecks/fuzzing/coverage_campaign.rb +0 -161
- data/lib/hecks/fuzzing/differential.rb +0 -192
- data/lib/hecks/fuzzing/domain_generator.rb +0 -871
- data/lib/hecks/fuzzing/era_boundary.rb +0 -154
- data/lib/hecks/fuzzing/form_census.rb +0 -285
- data/lib/hecks/fuzzing/generated_domain_check.rb +0 -171
- data/lib/hecks/fuzzing/invalid_value_generator.rb +0 -125
- data/lib/hecks/fuzzing/isolated_boot.rb +0 -658
- data/lib/hecks/fuzzing/nondeterministic.rb +0 -79
- data/lib/hecks/fuzzing/persistence_parity.rb +0 -253
- data/lib/hecks/fuzzing/properties/corrections.rb +0 -125
- data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +0 -688
- data/lib/hecks/fuzzing/properties/guards.rb +0 -398
- data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +0 -399
- data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +0 -137
- data/lib/hecks/fuzzing/properties/outbox.rb +0 -180
- data/lib/hecks/fuzzing/properties/querying.rb +0 -260
- data/lib/hecks/fuzzing/properties.rb +0 -267
- data/lib/hecks/fuzzing/qa_settings.rb +0 -164
- data/lib/hecks/fuzzing/replay.rb +0 -930
- data/lib/hecks/fuzzing/rotation_priority.rb +0 -114
- data/lib/hecks/fuzzing/rust_gap_manifest.rb +0 -139
- data/lib/hecks/fuzzing/self_consistency.rb +0 -825
- data/lib/hecks/fuzzing/sequence_generator/adversary.rb +0 -532
- data/lib/hecks/fuzzing/sequence_generator/catalog.rb +0 -171
- data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +0 -127
- data/lib/hecks/fuzzing/sequence_generator/picker.rb +0 -116
- data/lib/hecks/fuzzing/sequence_generator/query_binding.rb +0 -138
- data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +0 -344
- data/lib/hecks/fuzzing/sequence_generator.rb +0 -311
- data/lib/hecks/fuzzing/shrinker.rb +0 -309
- data/lib/hecks/fuzzing/structural_skips.rb +0 -53
- data/lib/hecks/fuzzing/sweep_depth.rb +0 -61
- data/lib/hecks/fuzzing/target_capabilities.rb +0 -255
- data/lib/hecks/fuzzing/value_generator.rb +0 -340
- data/lib/hecks/fuzzing.rb +0 -23
- data/lib/hecks/grammar/evolve.rb +0 -524
- data/lib/hecks/query_ir.rb +0 -482
|
@@ -4,28 +4,14 @@ require_relative "../../vocabulary"
|
|
|
4
4
|
module Hecks
|
|
5
5
|
module Bluebook
|
|
6
6
|
module Expression
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
# Include/Resolve AST (cached per distinct string, `ast_cache`) and
|
|
10
|
-
# interprets it against a call's own state/attrs. Leaf `Resolve`
|
|
11
|
-
# nodes delegate to `Resolver` for the dotted/arithmetic
|
|
12
|
-
# sub-grammar; `OPERATORS` is the comparison table projected from
|
|
13
|
-
# the grammar chapter (`PROJECTION`).
|
|
7
|
+
# Parses a canonical predicate string into an Or/And/Not/Compare/Include/Resolve AST
|
|
8
|
+
# and interprets it against a call's state/attrs; leaves delegate to `Resolver`.
|
|
14
9
|
module Evaluator
|
|
15
10
|
Operator = Struct.new(:symbol, :compares_less_than, :compares_equal, :negated, keyword_init: true)
|
|
16
11
|
|
|
17
|
-
# Six operators
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
# **Read, not restated**. This table is the checked-in projection of the
|
|
22
|
-
# grammar chapter's admitted set (bin/expression_projection), joined with
|
|
23
|
-
# the algebra Vocabulary::Comparison declares. The evaluator cannot
|
|
24
|
-
# boot the chapter that configures it — the Prism adapter normalises
|
|
25
|
-
# every predicate through CanonicalForm while a bluebook loads — so
|
|
26
|
-
# the projection is how the domain reaches here: regenerated when the
|
|
27
|
-
# ledger changes, held fresh by spec/operators_export_spec.rb, and
|
|
28
|
-
# held to the live machinery by spec/operator_conformance_spec.rb.
|
|
12
|
+
# Six comparison operators reduced to two primitives (less_than, equal).
|
|
13
|
+
# Read from the checked-in projection because the evaluator runs while the chapter boots.
|
|
14
|
+
# Freshness: spec/operators_export_spec.rb; conformance: spec/operator_conformance_spec.rb.
|
|
29
15
|
PROJECTION = JSON.parse(
|
|
30
16
|
File.read(File.join(__dir__, "projection.json")), symbolize_names: true
|
|
31
17
|
).freeze
|
|
@@ -37,13 +23,8 @@ module Hecks
|
|
|
37
23
|
|
|
38
24
|
COMPARISONS = OPERATORS.map(&:symbol).freeze
|
|
39
25
|
|
|
40
|
-
#
|
|
41
|
-
#
|
|
42
|
-
# strings — which branch a leaf's grammar takes is, like the boolean/
|
|
43
|
-
# comparison grammar above it, a pure function of the string. Only the
|
|
44
|
-
# final state/attrs dictionary read, inside Resolver.interpret, varies
|
|
45
|
-
# per call. Parsing the whole tree once and caching it (ast_cache,
|
|
46
|
-
# below) is what makes that safe.
|
|
26
|
+
# Leaf nodes hold parsed Resolver ASTs; only the state/attrs read varies per call,
|
|
27
|
+
# so the whole tree can be parsed once and cached.
|
|
47
28
|
Or = Struct.new(:left, :right, keyword_init: true)
|
|
48
29
|
And = Struct.new(:left, :right, keyword_init: true)
|
|
49
30
|
Not = Struct.new(:node, keyword_init: true)
|
|
@@ -53,17 +34,10 @@ module Hecks
|
|
|
53
34
|
|
|
54
35
|
module_function
|
|
55
36
|
|
|
56
|
-
#
|
|
57
|
-
#
|
|
58
|
-
# normalised at DSL-build time, so the same given/invariant's text is
|
|
59
|
-
# byte-identical across every dispatch that evaluates it — parsed once
|
|
60
|
-
# here, interpreted fresh against each call's own state/attrs. Matches
|
|
61
|
-
# MetaValidator.verdicts' unsynchronized `||= {}` idiom : redundant
|
|
62
|
-
# parse work under real parallelism, never corruption.
|
|
37
|
+
# Parsed AST per distinct predicate string, keyed by the exact string `call` receives.
|
|
38
|
+
# Unsynchronized `||=`: racing threads at worst parse twice, never corrupt.
|
|
63
39
|
#
|
|
64
|
-
# @return [Hash{String => Object}] the process-wide parse cache
|
|
65
|
-
# keyed by predicate string; each value is one of `Or`, `And`,
|
|
66
|
-
# `Not`, `Compare`, `Include`, or `Resolve`
|
|
40
|
+
# @return [Hash{String => Object}] the process-wide parse cache
|
|
67
41
|
def ast_cache = @ast_cache ||= {}
|
|
68
42
|
|
|
69
43
|
# Parses `expr` (cached per distinct string) and interprets it
|
|
@@ -82,72 +56,31 @@ module Hecks
|
|
|
82
56
|
interpret(ast_cache[expr] ||= parse(expr), state, attrs)
|
|
83
57
|
end
|
|
84
58
|
|
|
85
|
-
#
|
|
86
|
-
#
|
|
87
|
-
# never re-parsing the text: the one parse happened at DSL-build
|
|
88
|
-
# time behind `AstJson`, and `AstReader` turns that tree back into
|
|
89
|
-
# the same nodes `parse` would have built (the equivalence is
|
|
90
|
-
# pinned by spec/expression_ast_spec.rb over the bounded-
|
|
91
|
-
# exhaustive generator). A rule with no `ast` (an Assembly-
|
|
92
|
-
# rebuilt one, or a placeholder resolved outside build_rule)
|
|
93
|
-
# falls back to parsing its canonical — same cache, same key.
|
|
94
|
-
#
|
|
95
|
-
# HECKS_EVAL=string reverts to the text path wholesale, kept for
|
|
96
|
-
# one release as the escape hatch while the ast path beds in.
|
|
59
|
+
# Evaluates a Given/Invariant by walking its structured `ast`, falling back to
|
|
60
|
+
# parsing `canonical` when the rule has none. HECKS_EVAL=string forces the text path.
|
|
97
61
|
#
|
|
98
|
-
# @param rule [Bluebook::Given, Bluebook::Invariant] the rule to
|
|
99
|
-
#
|
|
100
|
-
#
|
|
101
|
-
#
|
|
102
|
-
#
|
|
103
|
-
# values, checked before `state`
|
|
62
|
+
# @param rule [Bluebook::Given, Bluebook::Invariant] the rule to evaluate
|
|
63
|
+
# @param state [Hash{Symbol => Object}] stored attribute values a `Resolve`/`Compare` leaf
|
|
64
|
+
# may resolve against
|
|
65
|
+
# @param attrs [Hash{Symbol => Object}] the call's own argument values, checked
|
|
66
|
+
# before `state`
|
|
104
67
|
# @return [Boolean] whether `rule` holds
|
|
105
|
-
# @raise [EvaluationError] if `rule` resolves an unknown attribute
|
|
106
|
-
#
|
|
107
|
-
# type
|
|
68
|
+
# @raise [EvaluationError] if `rule` resolves an unknown attribute/argument, or
|
|
69
|
+
# misapplies an operation
|
|
108
70
|
def call_rule(rule, state, attrs = {})
|
|
109
71
|
return call(rule.canonical, state, attrs) if ENV["HECKS_EVAL"] == "string"
|
|
110
72
|
|
|
111
73
|
interpret(ast_cache[rule.canonical] ||= nodes_for(rule), state, attrs)
|
|
112
74
|
end
|
|
113
75
|
|
|
114
|
-
# Returns `rule`'s
|
|
115
|
-
# present, otherwise parsed fresh from `canonical`.
|
|
116
|
-
#
|
|
117
|
-
# @param rule [Bluebook::Given, Bluebook::Invariant] the rule to
|
|
118
|
-
# read
|
|
119
|
-
# @return [Object] one of `Or`, `And`, `Not`, `Compare`, `Include`,
|
|
120
|
-
# or `Resolve`
|
|
76
|
+
# Returns `rule`'s AST from its `ast` field, else parsed from `canonical`.
|
|
121
77
|
def nodes_for(rule)
|
|
122
78
|
rule.ast ? AstReader.read_predicate(rule.ast) : parse(rule.canonical)
|
|
123
79
|
end
|
|
124
80
|
|
|
125
|
-
# Renders
|
|
126
|
-
#
|
|
127
|
-
#
|
|
128
|
-
# own, not what the block actually evaluated to — the difference
|
|
129
|
-
# between "the rule is right and my data is wrong" and "the rule
|
|
130
|
-
# is subtly wrong" is often just seeing the two operands. Scoped
|
|
131
|
-
# to the single shape that has one honest answer: `expr`'s own
|
|
132
|
-
# top-level node is a bare `Compare` — not `Or`/`And`/`Not` (which
|
|
133
|
-
# of several sub-comparisons would even be "the" one at fault is
|
|
134
|
-
# genuinely ambiguous), `Include` (no left/right to show), or
|
|
135
|
-
# `Resolve` (a bare boolean read, nothing to compare against).
|
|
136
|
-
# Values are rendered with `Rendering.describe`, the same house
|
|
137
|
-
# style every other refusal already prints a value through.
|
|
138
|
-
# Returns `nil` — not raised — on anything else, including an
|
|
139
|
-
# operand that itself fails to resolve (`EvaluationError`): a
|
|
140
|
-
# missing diagnostic is a worse debugging experience than none, a
|
|
141
|
-
# crash while building one is worse still.
|
|
142
|
-
#
|
|
143
|
-
# @param expr [String] the canonical predicate text that was just
|
|
144
|
-
# refused
|
|
145
|
-
# @param state [Hash{Symbol => Object}] the stored attribute values
|
|
146
|
-
# the operands may resolve against
|
|
147
|
-
# @param attrs [Hash{Symbol => Object}] the call's own argument
|
|
148
|
-
# values, checked before `state`
|
|
149
|
-
# @return [String, nil] `"left: X, right: Y"` when `expr` is a bare
|
|
150
|
-
# comparison whose operands both resolve; `nil` otherwise
|
|
81
|
+
# Renders a refused rule's two operands, for a refusal message.
|
|
82
|
+
# Only a bare top-level `Compare` has one honest answer; anything else, or an
|
|
83
|
+
# operand that fails to resolve, yields nil rather than raising.
|
|
151
84
|
def comparison_detail(expr, state, attrs = {})
|
|
152
85
|
node = ast_cache[expr] ||= parse(expr)
|
|
153
86
|
return nil unless node.is_a?(Compare)
|
|
@@ -159,12 +92,7 @@ module Hecks
|
|
|
159
92
|
nil
|
|
160
93
|
end
|
|
161
94
|
|
|
162
|
-
# Parses `expr`'s boolean/comparison grammar into an AST
|
|
163
|
-
# into `Resolver.parse` for each leaf.
|
|
164
|
-
#
|
|
165
|
-
# @param expr [String] the canonical predicate text to parse
|
|
166
|
-
# @return [Object] one of `Or`, `And`, `Not`, `Compare`, `Include`,
|
|
167
|
-
# or `Resolve`, chosen by `expr`'s own shape
|
|
95
|
+
# Parses `expr`'s boolean/comparison grammar into an AST; leaves go to `Resolver.parse`.
|
|
168
96
|
def parse(expr)
|
|
169
97
|
expr = strip_parens(expr.to_s.strip)
|
|
170
98
|
|
|
@@ -174,21 +102,8 @@ module Hecks
|
|
|
174
102
|
left, right = split_top_level(expr, "&&")
|
|
175
103
|
return And.new(left: parse(left), right: parse(right)) if left
|
|
176
104
|
|
|
177
|
-
#
|
|
178
|
-
#
|
|
179
|
-
# means `!(names.include?(x))`, never "call .include? on the negated
|
|
180
|
-
# receiver"), so the leading marker has to be stripped and the
|
|
181
|
-
# remainder re-parsed before anything downstream gets a chance to
|
|
182
|
-
# mis-scan across it. Tried after `match_include` instead, its
|
|
183
|
-
# naive `rindex(".include?(")` has no concept of a leading `!` —
|
|
184
|
-
# for `!names.include?(x)` it would swallow the `!` straight into
|
|
185
|
-
# the haystack text ("!names"), which `Resolver.parse` cannot
|
|
186
|
-
# resolve, so every spelling of negated membership would raise
|
|
187
|
-
# instead of evaluating. Checking here first fixes both the bare
|
|
188
|
-
# prefix (`!names.include?(x)`) and the parenthesized form
|
|
189
|
-
# (`!(names.include?(x))`) — the recursive `parse` call sees the
|
|
190
|
-
# clean remainder and correctly finds the `.include?` (or `&&`/`||`)
|
|
191
|
-
# inside it.
|
|
105
|
+
# `!` binds the whole remainder, so strip it before `match_include` runs;
|
|
106
|
+
# otherwise `!names.include?(x)` would swallow the `!` into the haystack text.
|
|
192
107
|
return Not.new(node: parse(Regexp.last_match(1))) if expr =~ /\A!(.+)\z/
|
|
193
108
|
|
|
194
109
|
membership = match_include(expr)
|
|
@@ -202,19 +117,7 @@ module Hecks
|
|
|
202
117
|
Resolve.new(expr: Resolver.parse(expr))
|
|
203
118
|
end
|
|
204
119
|
|
|
205
|
-
# Interprets a parsed boolean/comparison node against `state
|
|
206
|
-
# `attrs`.
|
|
207
|
-
#
|
|
208
|
-
# @param node [Object] a node `parse` produced (`Or`, `And`, `Not`,
|
|
209
|
-
# `Compare`, `Include`, or `Resolve`)
|
|
210
|
-
# @param state [Hash{Symbol => Object}] the stored attribute values
|
|
211
|
-
# a leaf may resolve against
|
|
212
|
-
# @param attrs [Hash{Symbol => Object}] the call's own argument
|
|
213
|
-
# values, checked before `state`
|
|
214
|
-
# @return [Boolean] whether `node` holds
|
|
215
|
-
# @raise [EvaluationError] if `node` is not one of the handled
|
|
216
|
-
# types, or a leaf it delegates to (`compare`, `includes?`,
|
|
217
|
-
# `Resolver.interpret`) refuses its operand
|
|
120
|
+
# Interprets a parsed boolean/comparison node against `state`/`attrs`.
|
|
218
121
|
def interpret(node, state, attrs)
|
|
219
122
|
case node
|
|
220
123
|
when Or then interpret(node.left, state, attrs) || interpret(node.right, state, attrs)
|
|
@@ -224,33 +127,13 @@ module Hecks
|
|
|
224
127
|
when Include then includes?([node.haystack, node.needle], state, attrs)
|
|
225
128
|
when Resolve then truthy?(Resolver.interpret(node.expr, state, attrs))
|
|
226
129
|
else
|
|
227
|
-
#
|
|
228
|
-
#
|
|
229
|
-
# type and `interpret` doesn't grow to match it. A missing
|
|
230
|
-
# arm here would instead return bare `nil`, and `Or`/`And`
|
|
231
|
-
# fold that straight into the boolean algebra as ordinary
|
|
232
|
-
# falsy — reading exactly like "the rule legitimately does
|
|
233
|
-
# not hold" rather than "the runtime cannot evaluate this
|
|
234
|
-
# rule at all", the one silent no-op this language otherwise
|
|
235
|
-
# refuses.
|
|
130
|
+
# Backstop: a missing arm would return nil, which Or/And read as an ordinary
|
|
131
|
+
# false instead of "cannot evaluate".
|
|
236
132
|
raise EvaluationError, "no interpreter handles #{node.class} — add a case before parse can produce it"
|
|
237
133
|
end
|
|
238
134
|
end
|
|
239
135
|
|
|
240
136
|
# Resolves `left`/`right` and applies `comparator` to the results.
|
|
241
|
-
#
|
|
242
|
-
# @param comparator [Operator] the comparison operator to apply
|
|
243
|
-
# @param left [Object] a `Resolver` leaf node (`Resolver.parse`'s
|
|
244
|
-
# own return) for the left operand
|
|
245
|
-
# @param right [Object] a `Resolver` leaf node (`Resolver.parse`'s
|
|
246
|
-
# own return) for the right operand
|
|
247
|
-
# @param state [Hash{Symbol => Object}] the stored attribute values
|
|
248
|
-
# the operands may resolve against
|
|
249
|
-
# @param attrs [Hash{Symbol => Object}] the call's own argument
|
|
250
|
-
# values, checked before `state`
|
|
251
|
-
# @return [Boolean] the comparison's result
|
|
252
|
-
# @raise [EvaluationError] if an operand does not resolve, or
|
|
253
|
-
# `less_than`/`equal?` cannot compare the resolved values
|
|
254
137
|
def compare(comparator, left, right, state, attrs)
|
|
255
138
|
lhs = Resolver.interpret(left, state, attrs)
|
|
256
139
|
rhs = Resolver.interpret(right, state, attrs)
|
|
@@ -258,31 +141,14 @@ module Hecks
|
|
|
258
141
|
apply(comparator, lhs, rhs)
|
|
259
142
|
end
|
|
260
143
|
|
|
261
|
-
#
|
|
262
|
-
# test (SignTest#compares_via names an Operator symbol) can apply the
|
|
263
|
-
# same primitives compare() uses against the literal 0, rather than
|
|
264
|
-
# re-deriving positive?/negative?/zero? by hand a second time.
|
|
265
|
-
#
|
|
266
|
-
# @param comparator [Operator] the comparison operator to apply
|
|
267
|
-
# @param lhs [Object] the already-resolved left operand
|
|
268
|
-
# @param rhs [Object] the already-resolved right operand
|
|
269
|
-
# @return [Boolean] `comparator`'s result over `lhs`/`rhs`
|
|
270
|
-
# @raise [EvaluationError] if `comparator` tests less-than and
|
|
271
|
-
# `lhs`/`rhs` are not both numeric or both String
|
|
144
|
+
# Applies the operator algebra to resolved values; SignTest reuses it against 0.
|
|
272
145
|
def apply(comparator, lhs, rhs)
|
|
273
146
|
result = (comparator.compares_less_than && less_than(lhs, rhs)) ||
|
|
274
147
|
(comparator.compares_equal && equal?(lhs, rhs))
|
|
275
148
|
comparator.negated ? !result : result
|
|
276
149
|
end
|
|
277
150
|
|
|
278
|
-
#
|
|
279
|
-
#
|
|
280
|
-
# @param lhs [Object] the already-resolved left operand
|
|
281
|
-
# @param rhs [Object] the already-resolved right operand
|
|
282
|
-
# @return [Boolean] whether `lhs` is less than `rhs`, comparing
|
|
283
|
-
# numerically if both are numeric, lexically if both are String
|
|
284
|
-
# @raise [EvaluationError] if `lhs`/`rhs` are not both numeric or
|
|
285
|
-
# both String
|
|
151
|
+
# The `<` primitive: numeric if both numeric, lexical if both String.
|
|
286
152
|
def less_than(lhs, rhs)
|
|
287
153
|
left = Resolver.numeric(lhs)
|
|
288
154
|
right = Resolver.numeric(rhs)
|
|
@@ -293,12 +159,7 @@ module Hecks
|
|
|
293
159
|
"comparison of #{class_of(lhs)} with #{Resolver.describe(rhs)} failed"
|
|
294
160
|
end
|
|
295
161
|
|
|
296
|
-
#
|
|
297
|
-
#
|
|
298
|
-
# @param lhs [Object] the already-resolved left operand
|
|
299
|
-
# @param rhs [Object] the already-resolved right operand
|
|
300
|
-
# @return [Boolean] whether `lhs` equals `rhs`, comparing
|
|
301
|
-
# numerically if both are numeric, `==` otherwise
|
|
162
|
+
# The `equal` primitive: numeric if both numeric, `==` otherwise.
|
|
302
163
|
def equal?(lhs, rhs)
|
|
303
164
|
left = Resolver.numeric(lhs)
|
|
304
165
|
right = Resolver.numeric(rhs)
|
|
@@ -307,42 +168,19 @@ module Hecks
|
|
|
307
168
|
lhs == rhs
|
|
308
169
|
end
|
|
309
170
|
|
|
310
|
-
#
|
|
311
|
-
#
|
|
312
|
-
# @param value [Object] the value to test
|
|
313
|
-
# @return [Boolean] Ruby's own truthiness: `false` for `nil` and
|
|
314
|
-
# `false`, `true` for everything else
|
|
171
|
+
# Ruby truthiness for a bare `Resolve` node.
|
|
315
172
|
def truthy?(value)
|
|
316
173
|
!value.nil? && value != false
|
|
317
174
|
end
|
|
318
175
|
|
|
319
176
|
# Names `value`'s class, for a refusal message.
|
|
320
|
-
#
|
|
321
|
-
# @param value [Object] the value to name
|
|
322
|
-
# @return [String] `"nil"` for `nil`, otherwise `value.class.name`
|
|
323
177
|
def class_of(value)
|
|
324
178
|
value.nil? ? "nil" : value.class.name
|
|
325
179
|
end
|
|
326
180
|
|
|
327
|
-
# The same mis-split `Resolver.match_call` had (its own comment
|
|
328
|
-
# has the full story), found here too by the same generator: a
|
|
329
|
-
# `.include?` needle can itself be — or contain — another
|
|
330
|
-
# `.include?` call (`"".include?(arr.all? { |el| "".include?("")
|
|
331
|
-
# }.to_s)`, a String built via `.to_s` off a block predicate
|
|
332
|
-
# whose own body happens to include one) — `rindex` finds the
|
|
333
|
-
# innermost occurrence, not the outermost this split actually
|
|
334
|
-
# needs. Fixed identically: try each occurrence left to right,
|
|
335
|
-
# keep the first whose own balanced-paren match reaches the
|
|
336
|
-
# string's last character — `Resolver.matching_paren` is reused
|
|
337
|
-
# directly rather than duplicated, the same depth-tracking rule
|
|
338
|
-
# either grammar layer needs here.
|
|
339
181
|
# Splits `expr` at its outermost `.include?(...)` call, if any.
|
|
340
|
-
#
|
|
341
|
-
#
|
|
342
|
-
# @return [Array(String, String), nil] the `[haystack_text,
|
|
343
|
-
# needle_text]` pair for the outermost `.include?(` occurrence
|
|
344
|
-
# whose matching close paren reaches `expr`'s last character, or
|
|
345
|
-
# `nil` if none does
|
|
182
|
+
# `rindex` would find an innermost call inside the needle, so try each occurrence left to
|
|
183
|
+
# right and keep the first whose matching paren reaches the last character.
|
|
346
184
|
def match_include(expr)
|
|
347
185
|
start = 0
|
|
348
186
|
marker = ".include?("
|
|
@@ -355,26 +193,10 @@ module Hecks
|
|
|
355
193
|
nil
|
|
356
194
|
end
|
|
357
195
|
|
|
358
|
-
#
|
|
359
|
-
# (language/bluebook/vocabulary.bluebook) — spec/vocabulary_conformance_spec
|
|
360
|
-
# holds this equal to the language, so the set of haystack types
|
|
361
|
-
# `.include?` supports cannot drift from what the language says it
|
|
362
|
-
# does.
|
|
196
|
+
# Held equal to Vocabulary::IncludeHaystack by spec/vocabulary_conformance_spec.
|
|
363
197
|
INCLUDE_HAYSTACKS = Hecks::Vocabulary.fetch("IncludeHaystack")
|
|
364
198
|
|
|
365
|
-
# Resolves and evaluates an `Include` node's
|
|
366
|
-
#
|
|
367
|
-
# @param parts [Array(Object, Object)] the `[haystack, needle]`
|
|
368
|
-
# pair of `Resolver` leaf nodes from `Include#haystack`/`#needle`
|
|
369
|
-
# @param state [Hash{Symbol => Object}] the stored attribute values
|
|
370
|
-
# the operands may resolve against
|
|
371
|
-
# @param attrs [Hash{Symbol => Object}] the call's own argument
|
|
372
|
-
# values, checked before `state`
|
|
373
|
-
# @return [Boolean] whether the resolved haystack includes the
|
|
374
|
-
# resolved needle (`equal?`-compared for an Array, `#include?`
|
|
375
|
-
# for a String); `false` for any other resolved haystack type
|
|
376
|
-
# @raise [EvaluationError] if the haystack resolves to a String and
|
|
377
|
-
# the needle does not
|
|
199
|
+
# Resolves and evaluates an `Include` node's `.include?` test.
|
|
378
200
|
def includes?(parts, state, attrs)
|
|
379
201
|
haystack, needle = parts
|
|
380
202
|
wanted = Resolver.interpret(needle, state, attrs)
|
|
@@ -389,11 +211,7 @@ module Hecks
|
|
|
389
211
|
end
|
|
390
212
|
end
|
|
391
213
|
|
|
392
|
-
# Strips
|
|
393
|
-
#
|
|
394
|
-
# @param expr [String] the expression text
|
|
395
|
-
# @return [String] `expr` with every redundant outer `(...)` pair
|
|
396
|
-
# removed; `expr` unchanged if it is not wholly parenthesized
|
|
214
|
+
# Strips redundant outer parens, recursively.
|
|
397
215
|
def strip_parens(expr)
|
|
398
216
|
return expr unless expr.start_with?("(") && expr.end_with?(")")
|
|
399
217
|
|
|
@@ -406,14 +224,7 @@ module Hecks
|
|
|
406
224
|
strip_parens(expr[1..-2].strip)
|
|
407
225
|
end
|
|
408
226
|
|
|
409
|
-
# Splits `expr` at its first top-level
|
|
410
|
-
#
|
|
411
|
-
# @param expr [String] the expression text
|
|
412
|
-
# @param operator [String] the operator text to split on, such as
|
|
413
|
-
# `"||"` or `"&&"`
|
|
414
|
-
# @return [Array(String, String), nil] the `[left, right]` operand
|
|
415
|
-
# text around the split, or `nil` if `expr` has no top-level
|
|
416
|
-
# occurrence
|
|
227
|
+
# Splits `expr` at its first top-level `operator`.
|
|
417
228
|
def split_top_level(expr, operator)
|
|
418
229
|
index = top_level_index(expr, operator)
|
|
419
230
|
return nil unless index
|
|
@@ -421,17 +232,8 @@ module Hecks
|
|
|
421
232
|
[expr[0...index].strip, expr[(index + operator.length)..].strip]
|
|
422
233
|
end
|
|
423
234
|
|
|
424
|
-
# Splits `expr` at its first top-level
|
|
425
|
-
#
|
|
426
|
-
# not mistaken for the middle of `===`, `<` is not mistaken for
|
|
427
|
-
# the leading `<` of `<=`).
|
|
428
|
-
#
|
|
429
|
-
# @param expr [String] the expression text
|
|
430
|
-
# @param operator [String] the comparison operator text to split
|
|
431
|
-
# on, such as `"=="` or `"<"`
|
|
432
|
-
# @return [Array(String, String), nil] the `[left, right]` operand
|
|
433
|
-
# text around the split, or `nil` if `expr` has no matching
|
|
434
|
-
# top-level occurrence
|
|
235
|
+
# Splits `expr` at its first top-level `operator` that is not part of a longer one
|
|
236
|
+
# (`==` inside `===`, `<` in `<=`).
|
|
435
237
|
def split_comparison(expr, operator)
|
|
436
238
|
index = top_level_index(expr, operator) { |at| !part_of_longer?(expr, at, operator) }
|
|
437
239
|
return nil unless index
|
|
@@ -439,15 +241,7 @@ module Hecks
|
|
|
439
241
|
[expr[0...index].strip, expr[(index + operator.length)..].strip]
|
|
440
242
|
end
|
|
441
243
|
|
|
442
|
-
#
|
|
443
|
-
# actually the middle of a longer operator's own spelling (`==`
|
|
444
|
-
# inside `===`, or `<`/`>`/`!`/`=` immediately before a bare `=`).
|
|
445
|
-
#
|
|
446
|
-
# @param expr [String] the expression text
|
|
447
|
-
# @param index [Integer] the index of the candidate occurrence
|
|
448
|
-
# @param operator [String] the operator text being tried
|
|
449
|
-
# @return [Boolean] whether this occurrence belongs to a longer
|
|
450
|
-
# operator and should be skipped
|
|
244
|
+
# Whether the `operator` at `index` is part of a longer operator's spelling.
|
|
451
245
|
def part_of_longer?(expr, index, operator)
|
|
452
246
|
after = expr[index + operator.length]
|
|
453
247
|
before = index.positive? ? expr[index - 1] : nil
|
|
@@ -458,21 +252,8 @@ module Hecks
|
|
|
458
252
|
false
|
|
459
253
|
end
|
|
460
254
|
|
|
461
|
-
#
|
|
462
|
-
#
|
|
463
|
-
# occurrence of `operator`, tracking quotes and every bracket
|
|
464
|
-
# kind (`(`/`)`, `{`/`}`, `[`/`]`) so an operator inside a nested
|
|
465
|
-
# call, block predicate, or array literal is never mistaken for a
|
|
466
|
-
# split point at this level.
|
|
467
|
-
#
|
|
468
|
-
# @param expr [String] the expression text
|
|
469
|
-
# @param operator [String] the operator text to search for
|
|
470
|
-
# @yieldparam index [Integer] a candidate top-level occurrence's
|
|
471
|
-
# index, offered so the caller can reject it (`split_comparison`
|
|
472
|
-
# uses this to skip a longer operator's own spelling)
|
|
473
|
-
# @yieldreturn [Boolean] whether to accept this occurrence
|
|
474
|
-
# @return [Integer, nil] the accepted occurrence's index, or `nil`
|
|
475
|
-
# if `operator` has no top-level occurrence the block accepts
|
|
255
|
+
# Finds the first top-level occurrence of `operator`, tracking quotes and all bracket
|
|
256
|
+
# kinds so an operator inside a call, block predicate or array literal is skipped.
|
|
476
257
|
def top_level_index(expr, operator)
|
|
477
258
|
depth = 0
|
|
478
259
|
quote = nil
|
|
@@ -485,38 +266,9 @@ module Hecks
|
|
|
485
266
|
quote = nil if char == quote
|
|
486
267
|
elsif ['"', "'"].include?(char)
|
|
487
268
|
quote = char
|
|
488
|
-
# `{`/`}` depth
|
|
489
|
-
#
|
|
490
|
-
#
|
|
491
|
-
# inside a call's parens is never mistaken for a top-level
|
|
492
|
-
# split point ; `{`/`}` needed the identical treatment the
|
|
493
|
-
# moment `Bluebook::Expression::Resolver` grew block-taking
|
|
494
|
-
# `.all?`/`.any?`/`.none? { |s| PREDICATE }` support (see
|
|
495
|
-
# resolver.rb's own `BlockPredicate` addition) -- without
|
|
496
|
-
# this, an operator inside the block's own predicate (e.g.
|
|
497
|
-
# `s.length > 0`) reads as a top-level split of the whole
|
|
498
|
-
# `value.split("::").all? { |s| s.length > 0 }` expression,
|
|
499
|
-
# confirmed live via `Lexicon::Lexicon.Lookup`/`Query::Query.
|
|
500
|
-
# Run` (the exact `Phrase` invariant this gap was found
|
|
501
|
-
# against) : the stray `>` split the expression in half
|
|
502
|
-
# before `Resolver.parse` ever saw the block as one atomic
|
|
503
|
-
# leaf, and the two halves then failed independently with
|
|
504
|
-
# the same raw `TypeError` the block-predicate fix was
|
|
505
|
-
# built to close. `{`/`}` cannot legitimately appear inside
|
|
506
|
-
# a quoted literal either, so this sits beside the existing
|
|
507
|
-
# paren-depth branch, not instead of it.
|
|
508
|
-
#
|
|
509
|
-
# `[`/`]` -- the identical lesson a third time (found live via
|
|
510
|
-
# the type-directed bounded-exhaustive expression generator,
|
|
511
|
-
# Phase 7 of the equivalence-gap plan): `Resolver::ArrayLiteral`
|
|
512
|
-
# (`[a, b]`) can appear as a general sub-expression, not only
|
|
513
|
-
# as `.include?`'s own haystack, the moment an array-typed
|
|
514
|
-
# attribute or a synthesized literal is embedded anywhere else
|
|
515
|
-
# -- so without counting `[`/`]` toward depth here too, an
|
|
516
|
-
# element containing a top-level `+`/comparison of its own
|
|
517
|
-
# (`[0, 0 + 0]`) reads as a split point for this expression's
|
|
518
|
-
# own boolean/comparison grammar, exactly the way an
|
|
519
|
-
# un-tracked `{`/`}` does for block predicates.
|
|
269
|
+
# `{`/`}` and `[`/`]` count toward depth like parens: an operator inside a
|
|
270
|
+
# block predicate (`.all? { |s| s.length > 0 }`) or array literal (`[0, 0 + 0]`)
|
|
271
|
+
# must not read as a split point for the enclosing expression.
|
|
520
272
|
elsif ["(", "{", "["].include?(char)
|
|
521
273
|
depth += 1
|
|
522
274
|
elsif [")", "}", "]"].include?(char)
|