hecks 2.7.0 → 2.8.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 +13 -0
- data/lib/hecks/adapters/driven/memory.rb +1 -1
- data/lib/hecks/adapters/driven/postgres.rb +1 -1
- data/lib/hecks/adapters/driven/prism.rb +1 -1
- data/lib/hecks/adapters/driven/sqlite/projection.rb +1 -1
- data/lib/hecks/adapters/driven/tenant_provisioner.rb +31 -10
- data/lib/hecks/behaviors/expectations.rb +2 -2
- data/lib/hecks/bluebook/assembly/contract.rb +1 -1
- data/lib/hecks/bluebook/assembly/contracts.rb +5 -5
- data/lib/hecks/bluebook/assembly/specializer.rb +2 -2
- data/lib/hecks/bluebook/assembly.rb +1 -1
- data/lib/hecks/bluebook/behaviour/chapter.rb +5 -2
- data/lib/hecks/bluebook/behaviour/read_model.rb +18 -0
- data/lib/hecks/bluebook/capabilities.rb +2 -2
- data/lib/hecks/bluebook/chapter.rb +1 -1
- data/lib/hecks/bluebook/dsl/aggregate_builder.rb +2 -2
- data/lib/hecks/bluebook/dsl/binding_proxy.rb +6 -1
- data/lib/hecks/bluebook/dsl/bluebook_builder.rb +2 -2
- data/lib/hecks/bluebook/dsl/entity_builder.rb +1 -1
- data/lib/hecks/bluebook/dsl/generic_dispatch.rb +1 -1
- data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +14 -9
- data/lib/hecks/bluebook/dsl/rule_reference.rb +3 -3
- data/lib/hecks/bluebook/dsl/translation_builder.rb +1 -1
- data/lib/hecks/bluebook/dsl/world_builder.rb +5 -0
- data/lib/hecks/bluebook/meta_validator/judge.rb +3 -3
- data/lib/hecks/bluebook/meta_validator/plan.rb +4 -4
- data/lib/hecks/bluebook/meta_validator/readings.rb +1 -1
- data/lib/hecks/bluebook/meta_validator/reconstruction.rb +2 -2
- data/lib/hecks/bluebook/meta_validator/shapes.rb +1 -1
- data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +11 -10
- data/lib/hecks/bluebook/meta_validator.rb +1 -1
- data/lib/hecks/bluebook/model_check/client_profile.rb +4 -70
- data/lib/hecks/bluebook/model_check.rb +12 -13
- data/lib/hecks/cache_dir.rb +103 -0
- data/lib/hecks/cli/document.rb +104 -0
- data/lib/hecks/cli/ir.rb +47 -0
- data/lib/hecks/cli/mcp.rb +32 -0
- data/lib/hecks/cli/mcp_door.rb +461 -0
- data/lib/hecks/cli/model_check.rb +270 -0
- data/lib/hecks/cli/project_cli.rb +123 -0
- data/lib/hecks/cli/project_diagrams.rb +43 -0
- data/lib/hecks/cli/run.rb +219 -0
- data/lib/hecks/cli/smoke_test.rb +59 -0
- data/lib/hecks/cli/stores.rb +54 -0
- data/lib/hecks/cli.rb +166 -0
- data/lib/hecks/facade/handle.rb +2 -2
- data/lib/hecks/facade/surface/aggregate_door.rb +1 -1
- data/lib/hecks/language/bluebook/vocabulary.bluebook +16 -0
- data/lib/hecks/mcp_door_scope.rb +176 -0
- data/lib/hecks/ports/persistence/append_only.rb +1 -1
- data/lib/hecks/ports/persistence/plugins/era/era_check.rb +1 -1
- data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +2 -2
- data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +2 -2
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +2 -2
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +1 -1
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +1 -1
- data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +12 -6
- data/lib/hecks/ports/persistence/state_codec.rb +1 -1
- data/lib/hecks/projections/deploy/fargate.rb +1 -1
- data/lib/hecks/projections/deploy/lambda.rb +3 -3
- data/lib/hecks/projections/reference.rb +7 -1
- data/lib/hecks/projector/exporter.rb +4 -4
- data/lib/hecks/projector/target.rb +1 -1
- data/lib/hecks/release/runner/ci_publisher.rb +96 -0
- data/lib/hecks/release/runner/commands.rb +68 -0
- data/lib/hecks/release/runner/console.rb +52 -0
- data/lib/hecks/release/runner/gem_publisher.rb +44 -0
- data/lib/hecks/release/runner/git.rb +48 -0
- data/lib/hecks/release/runner/npm_publisher.rb +89 -0
- data/lib/hecks/release/runner/preflight.rb +119 -0
- data/lib/hecks/release/runner/published.rb +55 -0
- data/lib/hecks/release/runner/tagger.rb +87 -0
- data/lib/hecks/release/runner.rb +244 -0
- data/lib/hecks/router/namespace_installer.rb +1 -1
- data/lib/hecks/runtime/command_interpreter.rb +3 -3
- data/lib/hecks/runtime/command_rules/admissibility.rb +2 -2
- data/lib/hecks/runtime/entity_element.rb +1 -1
- data/lib/hecks/runtime/entity_interpreter.rb +1 -1
- data/lib/hecks/runtime/invocation.rb +1 -1
- data/lib/hecks/runtime/loader.rb +1 -1
- data/lib/hecks/runtime/outbox.rb +1 -1
- data/lib/hecks/runtime/reaction_invocation.rb +3 -3
- data/lib/hecks/runtime/read_model_interpreter.rb +37 -15
- data/lib/hecks/runtime/reference_hop.rb +4 -4
- data/lib/hecks/runtime/registry/verification.rb +11 -11
- data/lib/hecks/runtime/registry.rb +8 -4
- data/lib/hecks/runtime/saga_interpreter.rb +1 -1
- data/lib/hecks/runtime/value/coercion.rb +3 -3
- data/lib/hecks/runtime/value/entity_list_coercion.rb +1 -1
- data/lib/hecks/storehouse.rb +18 -12
- data/lib/hecks/version.rb +1 -1
- data/lib/hecks/vocabulary.rb +5 -0
- data/lib/hecks.rb +6 -1
- metadata +28 -58
- 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
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 66f85d62ad01467ff2ae17c6d3be63c706bea69a9e6f7b20839d9f5fc22234a5
|
|
4
|
+
data.tar.gz: 45413f0bd639bfe548ca9f8f7970d5136ed6aa30a25765870ca0212806af3c90
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b817baff1d4e990f1161080d23f9f10fadd2e1eb8a6f76b1ed551fe021992311f10d64f0eef63218e515905fa2757d879a607abc4b40ecfeb4d0d45a6011a8a6
|
|
7
|
+
data.tar.gz: '0819f496494a76afe81697f8a83301c07acef480b218501748616f1537f0c5d3c0148d67271dea0fd4eea6b6bcb9bbb278331a203883b3c169c08cd59f384451'
|
data/exe/hecks
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
# The `hecks` command the gem installs: run, read, check and serve a domain you
|
|
4
|
+
# supply. `hecks` with no arguments lists the subcommands; `hecks <command> --help`
|
|
5
|
+
# prints one's usage. The router is `Hecks::CLI` (lib/hecks/cli.rb).
|
|
6
|
+
#
|
|
7
|
+
# The gem's own `lib` goes first on the load path, as it does for the `bin/`
|
|
8
|
+
# scripts, so this file also runs straight from a checkout.
|
|
9
|
+
|
|
10
|
+
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
|
11
|
+
require "hecks/cli"
|
|
12
|
+
|
|
13
|
+
exit Hecks::CLI.start(ARGV)
|
|
@@ -217,7 +217,7 @@ module Hecks
|
|
|
217
217
|
#
|
|
218
218
|
# @param id [Integer] the row id `outbox_enqueue` assigned
|
|
219
219
|
# @return [Boolean] true when the row was pending and is now claimed; false when it is
|
|
220
|
-
# unknown or
|
|
220
|
+
# unknown or not pending
|
|
221
221
|
def outbox_claim(id) # rubocop:disable Naming/PredicateMethod
|
|
222
222
|
row = @outbox.find { |held| held.id == id }
|
|
223
223
|
return false unless row&.pending?
|
|
@@ -247,7 +247,7 @@ module Hecks
|
|
|
247
247
|
# an update to apply; nil writes unconditionally. Ignored for a delete
|
|
248
248
|
# @return [Runtime::Instance, PG::Result, nil] for a save, a new instance over the
|
|
249
249
|
# entry's state with `version` set to the stored `hecks_version`, or nil when
|
|
250
|
-
# `expected_version`
|
|
250
|
+
# `expected_version` did not match and nothing was written; for a delete, the
|
|
251
251
|
# `DELETE` statement's `PG::Result`
|
|
252
252
|
# @raise [PG::Error] if the statement fails
|
|
253
253
|
# rubocop:disable Metrics/AbcSize -- the CAS/plain upsert split is one
|
|
@@ -85,7 +85,7 @@ module Hecks
|
|
|
85
85
|
# never edited out from under it), but wrong for anything that
|
|
86
86
|
# legitimately reloads an edited file in-process: a stale cached
|
|
87
87
|
# tree reports a `given`/`ensures` block at its old line number,
|
|
88
|
-
# which
|
|
88
|
+
# which does not match the freshly re-executed file's own
|
|
89
89
|
# `block.source_location` — surfacing as "did not survive
|
|
90
90
|
# extraction" on a perfectly valid file. Built for real building
|
|
91
91
|
# `Hecks::Codemod` (lib/hecks/codemod.rb), which needs exactly this
|
|
@@ -15,7 +15,7 @@ module Hecks
|
|
|
15
15
|
# Rebuilds a read store from the authoritative journal, entry by entry.
|
|
16
16
|
# A value object is written as its JSON object and a reference as the
|
|
17
17
|
# bare id it holds — the same shapes the command path writes, so there
|
|
18
|
-
# is no second representation to accept here
|
|
18
|
+
# is no second representation to accept here.
|
|
19
19
|
class SqliteProjection < Sqlite
|
|
20
20
|
# Replaces or deletes the read store's row for one journal entry, encoding the entry's
|
|
21
21
|
# state directly rather than through a `Runtime::Instance`.
|
|
@@ -4,7 +4,7 @@ require "fileutils"
|
|
|
4
4
|
|
|
5
5
|
module Hecks
|
|
6
6
|
module Adapters
|
|
7
|
-
#
|
|
7
|
+
# The imperative half of provisioning a tenant, pulled out of
|
|
8
8
|
# `bin/project_tenant` and behind a real driven port
|
|
9
9
|
# (`Deploy::Tenant.port "TenantProvisioning"`) instead — the same
|
|
10
10
|
# hexagonal reasoning `GithubChecks` already gives for its own
|
|
@@ -16,34 +16,55 @@ module Hecks
|
|
|
16
16
|
# `PortOperationInterpreter#ask`'s own "every failure is an answer"
|
|
17
17
|
# comment for why nothing here needs its own rescue.
|
|
18
18
|
#
|
|
19
|
-
#
|
|
19
|
+
# ## What it leaves out
|
|
20
|
+
#
|
|
21
|
+
# Deliberately does not boot the target domain — that step (proving
|
|
20
22
|
# it boots for real, running the tenant_capable? gate) stays in
|
|
21
|
-
# `bin/project_tenant` itself, called
|
|
23
|
+
# `bin/project_tenant` itself, called after this operation answers,
|
|
22
24
|
# not nested inside it. Booting a whole domain from inside an
|
|
23
25
|
# adapter method that is itself running mid-dispatch (this port
|
|
24
26
|
# operation) is a real, separate concern from writing one file, and
|
|
25
27
|
# keeping the two apart avoids a nested `Hecks.boot` call ever
|
|
26
28
|
# running inside another boot's own dispatch call stack.
|
|
27
29
|
#
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
+
# ## Return shape
|
|
31
|
+
#
|
|
32
|
+
# Returns a hash shaped like `Tenancy::Tenant.Register`'s own
|
|
33
|
+
# arguments, on purpose — `tenancy.hecksagon`'s own `translates`
|
|
30
34
|
# reaction forwards an answered event's payload verbatim, so this
|
|
31
|
-
# adapter's own return value
|
|
35
|
+
# adapter's own return value is the translation from Deploy's
|
|
32
36
|
# vocabulary into Tenancy's, decided here rather than in a mapping
|
|
33
37
|
# layer neither side could see into.
|
|
34
38
|
class TenantProvisioner
|
|
39
|
+
# Accepts the arguments every driven adapter is built with and keeps none of them.
|
|
40
|
+
#
|
|
41
|
+
# @param aggregate [Object, nil] unused
|
|
42
|
+
# @param settings [Hash] unused
|
|
43
|
+
# @param root [String, nil] unused
|
|
35
44
|
def initialize(aggregate: nil, settings: {}, root: nil); end
|
|
36
45
|
|
|
37
|
-
#
|
|
46
|
+
# Writes the tenant's environment overlay file under its domain directory.
|
|
47
|
+
#
|
|
48
|
+
# `directory:` is required, not derived from `domain` — a real,
|
|
38
49
|
# confirmed bug found only under CI's own real-Postgres suite: a
|
|
39
|
-
# domain's own
|
|
50
|
+
# domain's own declared name (`domain`, e.g. "Scratch") is not a
|
|
40
51
|
# filesystem path, and File.expand_path(domain, Dir.pwd) silently
|
|
41
52
|
# resolved to the wrong directory (relative to whatever the
|
|
42
|
-
#
|
|
53
|
+
# running process' own cwd happened to be) whenever the CLI's own
|
|
43
54
|
# `--domain=` value didn't happen to equal its own directory
|
|
44
55
|
# argument by coincidence. `bin/project_tenant` passes its own
|
|
45
56
|
# real `domain_directory` local straight through.
|
|
46
|
-
|
|
57
|
+
#
|
|
58
|
+
# Every argument arrives either bare or wrapped as `{ value: ... }`; both are read.
|
|
59
|
+
#
|
|
60
|
+
# @param slug [String, Hash] the tenant's slug, which names the overlay file
|
|
61
|
+
# @param domain [String, Hash] the declared domain name the overlay is for
|
|
62
|
+
# @param realm [String, Hash] the realm the overlay declares
|
|
63
|
+
# @param schema [String, Hash] the schema the overlay declares
|
|
64
|
+
# @param database [String, Hash] the database the overlay declares
|
|
65
|
+
# @param adapter [String, Hash] the persistence adapter the overlay declares
|
|
66
|
+
# @param directory [String, Hash] the domain's own directory on disk
|
|
67
|
+
# @return [Hash{Symbol => Object}] `:slug`, `:domain`, `:realm` and `:schema`, as given
|
|
47
68
|
def provision(slug:, domain:, realm:, schema:, database:, adapter:, directory:)
|
|
48
69
|
domain_directory = File.expand_path(directory[:value] || directory)
|
|
49
70
|
|
|
@@ -228,7 +228,7 @@ module Hecks
|
|
|
228
228
|
# the dispatch's own result
|
|
229
229
|
# @return [Hash{Symbol => Object}] the settled record's current state, read
|
|
230
230
|
# back from the repository; `result.state` (or `{}`) when the result has no
|
|
231
|
-
# id or the repository
|
|
231
|
+
# id or the repository does not have that aggregate/record
|
|
232
232
|
def settled_state(runtime, verb, result)
|
|
233
233
|
return result.state || {} unless result.respond_to?(:id) && result.id
|
|
234
234
|
|
|
@@ -266,7 +266,7 @@ module Hecks
|
|
|
266
266
|
# only so long as nothing else ever asked it to resolve a port-operation
|
|
267
267
|
# verb. Now that a `policy` can legitimately `trigger` a port operation
|
|
268
268
|
# (`ReactionInvocation#resolve_target`'s own port-operation branch),
|
|
269
|
-
# that raise
|
|
269
|
+
# that raise does not happen, so this checks directly instead.
|
|
270
270
|
#
|
|
271
271
|
# @param runtime [Runtime::Dispatcher, Runtime::RemoteDispatcher] the suite's
|
|
272
272
|
# booted runtime
|
|
@@ -151,7 +151,7 @@ module Hecks
|
|
|
151
151
|
# Entity's contract claims `owner: :parent`
|
|
152
152
|
#
|
|
153
153
|
# `shape` and `handler` are not on this list — S17 (ADR 0026) made Member and
|
|
154
|
-
# Dispatch nested entities, so neither is a parent field
|
|
154
|
+
# Dispatch nested entities, so neither is a parent field the way
|
|
155
155
|
# `owner` is. `spec/assembly_spec` derives this set from `Plan` and the
|
|
156
156
|
# contracts directly and fails on any drift, rather than trusting this list to
|
|
157
157
|
# stay in sync with a second hand-written copy kept by the model generator.
|
|
@@ -243,7 +243,7 @@ module Hecks
|
|
|
243
243
|
|
|
244
244
|
# S17, ADR 0026 — Handler is a genuine entity now, nested under
|
|
245
245
|
# ProcessManager (`entity "Handler"`, reaction.bluebook). Neither
|
|
246
|
-
# `position` nor `handler` is a stored field
|
|
246
|
+
# `position` nor `handler` is a stored field: a saga
|
|
247
247
|
# answers each event once, so `event_type` is Handler's own real,
|
|
248
248
|
# non-positional identity (no walk-minted `position` to derive),
|
|
249
249
|
# and the process manager it belongs to is structural now — which
|
|
@@ -429,10 +429,10 @@ module Hecks
|
|
|
429
429
|
# A member's pairs are an open map, which is why Member is its own root in
|
|
430
430
|
# the language. The IR keeps them as a plain hash on the value object, so
|
|
431
431
|
# they are assembled with their shape rather than as a construct.
|
|
432
|
-
# S17, ADR 0026 — Member is a genuine entity
|
|
433
|
-
# ValueObject (`entity "Member"`, shape.bluebook). It no
|
|
434
|
-
#
|
|
435
|
-
#
|
|
432
|
+
# S17, ADR 0026 — Member is a genuine entity, nested under
|
|
433
|
+
# ValueObject (`entity "Member"`, shape.bluebook). It holds no
|
|
434
|
+
# `shape` field at all (a free-text, un-parsed spelling would suit
|
|
435
|
+
# only a standalone root ; an entity's element is
|
|
436
436
|
# never serialized as text) — only `position` (walk-minted, see
|
|
437
437
|
# `entity_own_identity`, judge.rb) and `pairs` (still an open map,
|
|
438
438
|
# still one row per entry, still why a value object cannot hold it
|
|
@@ -21,8 +21,8 @@ module Hecks
|
|
|
21
21
|
module Specializer
|
|
22
22
|
module_function
|
|
23
23
|
|
|
24
|
-
# S17, ADR 0026 — `Handler` is a genuine entity
|
|
25
|
-
# `ProcessManager`, so `.aggregate` alone
|
|
24
|
+
# S17, ADR 0026 — `Handler` is a genuine entity, nested under
|
|
25
|
+
# `ProcessManager`, so `.aggregate` alone does not find it —
|
|
26
26
|
# it hangs off some aggregate's own `.entities` instead
|
|
27
27
|
# (searched recursively, the same reason `Value::Coercion#find_
|
|
28
28
|
# entity` does: a nested entity, like `Dispatch` inside
|
|
@@ -31,7 +31,7 @@ module Hecks
|
|
|
31
31
|
# ## What stays hand-written
|
|
32
32
|
#
|
|
33
33
|
# The containment — which construct holds which — stays hand-written; it is
|
|
34
|
-
# not a field table. The runtime surface is
|
|
34
|
+
# not a field table. The runtime surface is not built here at all — the
|
|
35
35
|
# door is a per-boot projection, facade/surface.rb.
|
|
36
36
|
class Assembly
|
|
37
37
|
# Builds the graph the runtime runs from one chapter's declared hash.
|
|
@@ -91,15 +91,18 @@ module Hecks
|
|
|
91
91
|
@ports_by_name[port.name] = port
|
|
92
92
|
end
|
|
93
93
|
|
|
94
|
-
# A
|
|
94
|
+
# A translated reaction is also declared in the hecksagon —
|
|
95
95
|
# `HecksagonBuilder#translates` builds an ordinary `Policy` (same
|
|
96
96
|
# shape, same `PolicyInterpreter` runtime, as one written inside a
|
|
97
97
|
# `policy` block in this chapter's own `.bluebook`) and attaches it
|
|
98
98
|
# here, after the chapter already exists, the same reasoning
|
|
99
99
|
# `add_port` gives one method up. Kept out of the bluebook itself
|
|
100
|
-
# on purpose: which
|
|
100
|
+
# on purpose: which foreign domain's event this chapter reacts to
|
|
101
101
|
# is a wiring/context-mapping decision, not a fact the domain
|
|
102
102
|
# states about its own model.
|
|
103
|
+
#
|
|
104
|
+
# @param policy [Bluebook::Policy] the translated reaction to attach
|
|
105
|
+
# @return [Array<Bluebook::Policy>] this chapter's policies, with `policy` appended
|
|
103
106
|
def add_policy(policy)
|
|
104
107
|
@policies << policy
|
|
105
108
|
end
|
|
@@ -9,6 +9,24 @@ module Hecks
|
|
|
9
9
|
# @return [Array<Symbol>] each declared `group_by` field's name, in declaration order
|
|
10
10
|
def group_by_fields = @group_by.map { |row| row[:field].to_sym }
|
|
11
11
|
|
|
12
|
+
# Reports whether this read model's `group_by` names every identity head
|
|
13
|
+
# of the aggregate it groups (ADR 0061, decision D1).
|
|
14
|
+
#
|
|
15
|
+
# Such a key path cannot be shared by two rows, so it is accepted from the
|
|
16
|
+
# declaration alone and never checked for a collision at dispatch. Any
|
|
17
|
+
# other key path is checked per request.
|
|
18
|
+
#
|
|
19
|
+
# @param aggregate [Bluebook::Aggregate, nil] the aggregate of this read
|
|
20
|
+
# model's one many-side head
|
|
21
|
+
# @return [Boolean] false when `aggregate` is nil or declares no identity,
|
|
22
|
+
# since uniqueness cannot then be shown
|
|
23
|
+
def groups_by_identity?(aggregate)
|
|
24
|
+
return false unless aggregate
|
|
25
|
+
|
|
26
|
+
identity = Array(aggregate.identity_heads).map(&:to_sym)
|
|
27
|
+
!identity.empty? && (identity - group_by_fields).empty?
|
|
28
|
+
end
|
|
29
|
+
|
|
12
30
|
# `!!` rather than a bare `@count` — the DSL/reconstruction
|
|
13
31
|
# boundary (ReadModel#initialize) already normalises to
|
|
14
32
|
# `true`/`nil`, so this is belt and braces against a future
|
|
@@ -19,11 +19,11 @@ module Hecks
|
|
|
19
19
|
# Who may sign in, and with what role — rust/host's Google-OAuth
|
|
20
20
|
# provision/member_rows resolve this instead of an env var naming
|
|
21
21
|
# the aggregate (HECKS_MEMBERSHIP_AGGREGATE). Same declared-
|
|
22
|
-
# not-named shape AUTHORIZATION already is for Governance.
|
|
22
|
+
# not-named shape `AUTHORIZATION` already is for Governance.
|
|
23
23
|
MEMBERSHIP = "membership".freeze
|
|
24
24
|
# A stable organizational identity, independent of how it was
|
|
25
25
|
# authenticated — recognised by declaration, not the literal name
|
|
26
|
-
# "Identity". Same declared-not-named shape AUTHORIZATION already
|
|
26
|
+
# "Identity". Same declared-not-named shape `AUTHORIZATION` already
|
|
27
27
|
# is. rust/host does not build this chapter's payloads; any field
|
|
28
28
|
# mapping lives on the consuming hecksagon's `translates` ACL.
|
|
29
29
|
IDENTITY = "identity".freeze
|
|
@@ -4,7 +4,7 @@ require_relative "../ir"
|
|
|
4
4
|
|
|
5
5
|
module Hecks
|
|
6
6
|
module Bluebook
|
|
7
|
-
# The chapter,
|
|
7
|
+
# The chapter, which is not the namespace it lives in.
|
|
8
8
|
#
|
|
9
9
|
# `Hecks::Bluebook` was briefly a class, because dropping the
|
|
10
10
|
# old `IR::` segment would otherwise have produced
|
|
@@ -198,7 +198,7 @@ module Hecks
|
|
|
198
198
|
# never `[]`). Wave 6 (identity-and-relationships arc) un-deprecates
|
|
199
199
|
# all three for real: a relationship word now retains the author's
|
|
200
200
|
# domain concept in IR — still stored as one or more target
|
|
201
|
-
# identities, but
|
|
201
|
+
# identities, but not collapsed to a bare `reference_to`
|
|
202
202
|
# during assembly. `MetaValidator.shadow_parsing?` still routes to
|
|
203
203
|
# `legacy_has_many`/`legacy_has_one` so frozen era text written
|
|
204
204
|
# under the old (lying/collapsing) meaning still parses the way it
|
|
@@ -511,7 +511,7 @@ module Hecks
|
|
|
511
511
|
# are this construct's own refusal wording, not shared, since
|
|
512
512
|
# `declared_by:` only exists here so far. Unresolved (no
|
|
513
513
|
# candidate yet, or `declared_by:` naming an aggregate that
|
|
514
|
-
# hasn't declared it yet) is
|
|
514
|
+
# hasn't declared it yet) is not a fourth branch that
|
|
515
515
|
# raises here — see `#pending_chapter_given`, below, for why:
|
|
516
516
|
# a chapter split across files can genuinely reference a
|
|
517
517
|
# precondition a later file declares, and "not found among
|
|
@@ -77,7 +77,7 @@ module Hecks
|
|
|
77
77
|
end
|
|
78
78
|
|
|
79
79
|
def method_missing(verb, *args, **kwargs, &block)
|
|
80
|
-
# A
|
|
80
|
+
# **A bare call** — no args, no kwargs, no block — starts (or
|
|
81
81
|
# continues, on `AttributePath` itself below) a Privacy
|
|
82
82
|
# marking chain: `Registration.attendee.medications.has_phi(
|
|
83
83
|
# readable_by: "Privacy officer")`. No existing real
|
|
@@ -115,10 +115,15 @@ module Hecks
|
|
|
115
115
|
@path = path
|
|
116
116
|
end
|
|
117
117
|
|
|
118
|
+
# Records a `has_<category>` marking, or extends the attribute path by one segment.
|
|
119
|
+
#
|
|
118
120
|
# @param verb [Symbol] `has_<category>` to record the marking and end the chain;
|
|
119
121
|
# any other bare name to extend the path one segment further
|
|
120
122
|
# @param readable_by [String] required only for a `has_<category>` call — the
|
|
121
123
|
# Governance role a read must hold to see this field unredacted
|
|
124
|
+
# @param args [Array] must be empty; a positional argument is refused
|
|
125
|
+
# @param kwargs [Hash] must be empty; any keyword but `readable_by:` is refused
|
|
126
|
+
# @param block [Proc, nil] must be absent; a block is refused
|
|
122
127
|
# @return [Bluebook::DSL::AttributePath, nil] a longer chain for a plain segment;
|
|
123
128
|
# `nil` (nothing further to chain) for a `has_<category>` call
|
|
124
129
|
# @raise [Malformed] if a `has_<category>` call omits `readable_by:`, or any call
|
|
@@ -431,9 +431,9 @@ module Hecks
|
|
|
431
431
|
# manager's own structural check fails
|
|
432
432
|
def self.build(name, version: nil, &block)
|
|
433
433
|
registry = Hecks.current_registry
|
|
434
|
-
#
|
|
434
|
+
# Which file called `Hecks.bluebook`, recorded for
|
|
435
435
|
# `Registry#record_bluebook_source` — two frames up: this
|
|
436
|
-
# method's own caller is `Hecks.bluebook` (hecks.rb), and
|
|
436
|
+
# method's own caller is `Hecks.bluebook` (hecks.rb), and its
|
|
437
437
|
# caller is the real `.bluebook` file's own top-level call site.
|
|
438
438
|
caller_location = caller_locations(2, 1)&.first
|
|
439
439
|
registry&.record_bluebook_source(name, caller_location&.path)
|
|
@@ -243,7 +243,7 @@ module Hecks
|
|
|
243
243
|
# since ADR 0028, `command` only queues a descriptor and actually
|
|
244
244
|
# builds at `#drain_pending!` time, well after this whole block
|
|
245
245
|
# (including every `given` in it) has already run, so textual
|
|
246
|
-
# order within the block
|
|
246
|
+
# order within the block does not actually matter here; named
|
|
247
247
|
# for the reader anyway, since `given`'s own resolution logic
|
|
248
248
|
# (`CommandBuilder#reference_named_given`) still reads whatever
|
|
249
249
|
# `@named_givens` holds at the command's own build time, not by
|
|
@@ -8,7 +8,7 @@ module Hecks
|
|
|
8
8
|
# already shipped) only checks a word's admissibility; this module
|
|
9
9
|
# executes the safe, mechanical subset of what a word actually
|
|
10
10
|
# does, read live off the same self-hosted grammar table — so a
|
|
11
|
-
# builder method for one of these words
|
|
11
|
+
# builder method for one of these words need not be
|
|
12
12
|
# hand-written at all. Called from `WordGate#method_missing`'s own
|
|
13
13
|
# "admitted here, no builder method for it yet" branch, so it only
|
|
14
14
|
# ever sees a word whose (context, word) pair the grammar already
|
|
@@ -31,7 +31,7 @@ module Hecks
|
|
|
31
31
|
@translates = []
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
-
# Marks
|
|
34
|
+
# Marks this chapter as a bounded context — a consumer-owned chapter
|
|
35
35
|
# that `uses_framework` / `uses_embryonaut_bluebook` will not load.
|
|
36
36
|
# Framework and vendored packages get the mark automatically from
|
|
37
37
|
# those words; they never write `bounded` in their own bluebooks.
|
|
@@ -158,12 +158,12 @@ module Hecks
|
|
|
158
158
|
bluebook_ir.add_port(built)
|
|
159
159
|
end
|
|
160
160
|
|
|
161
|
-
# A
|
|
161
|
+
# A translation boundary, not a business rule — `translates "Name"
|
|
162
162
|
# do on Foreign::Domain::SomeEvent; trigger Local.Command; end`
|
|
163
|
-
# builds the
|
|
163
|
+
# builds the exact same `Policy` a `policy` block inside this
|
|
164
164
|
# domain's own `.bluebook` would (same `on_impl`/`trigger_impl`,
|
|
165
165
|
# same `PolicyInterpreter` runtime — reusing `PolicyBuilder`
|
|
166
|
-
# directly, zero new runtime semantics). What's new is only
|
|
166
|
+
# directly, zero new runtime semantics). What's new is only where
|
|
167
167
|
# it can be written: a cross-domain reaction is a wiring/context-
|
|
168
168
|
# mapping decision (this chapter conforming to a foreign chapter's
|
|
169
169
|
# published event), the same kind of decision `port`/
|
|
@@ -171,23 +171,28 @@ module Hecks
|
|
|
171
171
|
# model states about itself, which `policy` (inside the bluebook)
|
|
172
172
|
# remains the right word for.
|
|
173
173
|
#
|
|
174
|
-
#
|
|
175
|
-
# call's arguments are evaluated eagerly, under
|
|
174
|
+
# Must be a block, not `translates Event, into: Command` — a flat
|
|
175
|
+
# call's arguments are evaluated eagerly, under this builder's own
|
|
176
176
|
# `ConstShim` resolver (`BindingProxy.namespace`, set up by
|
|
177
|
-
# `self.build` below), which mints a `BindingProxy`
|
|
177
|
+
# `self.build` below), which mints a `BindingProxy` instance per
|
|
178
178
|
# segment and cannot answer a further `::` (it is not a Module) —
|
|
179
179
|
# a multi-segment reference like `Deploy::Tenant::TenantProvisioned`
|
|
180
180
|
# would raise before this method ever ran. `port_impl`'s own
|
|
181
181
|
# `ConstShim.with(->(const) { const })` swap only works because
|
|
182
182
|
# its own callers never pass a multi-segment bare constant as an
|
|
183
183
|
# eagerly-evaluated argument — everything of that shape lives
|
|
184
|
-
# inside
|
|
184
|
+
# inside its block, evaluated later, under the swapped resolver.
|
|
185
185
|
# A block defers evaluation the same way; a flat call cannot.
|
|
186
|
+
#
|
|
187
|
+
# @param name [String, Symbol] the reaction's name
|
|
188
|
+
# @yield the `on`/`trigger` block, evaluated later under the scoped resolver
|
|
189
|
+
# @return [Array<Bluebook::Policy>] the chapter's policies, with the new one appended
|
|
190
|
+
# @raise [Malformed] if no bluebook is registered for this domain to attach the reaction to
|
|
186
191
|
def translates(name, &block)
|
|
187
192
|
bluebook_ir = Hecks.current_registry.bluebook(@domain) or
|
|
188
193
|
raise Malformed, "#{@domain} declares no such bluebook — translates needs one to attach its reaction to"
|
|
189
194
|
|
|
190
|
-
#
|
|
195
|
+
# Same resolver BluebookBuilder itself uses for a `policy`
|
|
191
196
|
# block's own `on`/`trigger` (bluebook_builder.rb) — a
|
|
192
197
|
# `ScopedConstant`, not the bare passthrough `port_impl` swaps
|
|
193
198
|
# to, because `on`/`trigger` here take genuinely multi-segment
|
|
@@ -147,8 +147,8 @@ module Hecks
|
|
|
147
147
|
.find { |rule| rule.description == description }
|
|
148
148
|
end
|
|
149
149
|
|
|
150
|
-
# **Which construct uses which primitive** —
|
|
151
|
-
# Hash
|
|
150
|
+
# **Which construct uses which primitive** — not a Ruby-only
|
|
151
|
+
# Hash, because the
|
|
152
152
|
# user's own correction — "my goal is that if they read the same
|
|
153
153
|
# table they behave identically" — means a table only Ruby ever
|
|
154
154
|
# reads cannot deliver that, no matter how faithfully it is
|
|
@@ -172,7 +172,7 @@ module Hecks
|
|
|
172
172
|
# after `grammar_registry` is fully built and memoized, so reads
|
|
173
173
|
# the real table, every time, no exception.
|
|
174
174
|
#
|
|
175
|
-
#
|
|
175
|
+
# Not kept in sync by hand — the same `resolves_via`/
|
|
176
176
|
# `disambiguator` columns, projected ahead of time into the
|
|
177
177
|
# committed lib/hecks/bluebook/dsl/bootstrap_table.rb
|
|
178
178
|
# (bin/project_bootstrap_table, pinned by spec/bootstrap_table_spec.rb).
|
|
@@ -268,7 +268,7 @@ module Hecks
|
|
|
268
268
|
# Parses a whole `.translation` file into a `Translation` — the
|
|
269
269
|
# domain's own `from:`/`to:` era pair, its list of `aggregate`
|
|
270
270
|
# translation blocks (each built by `TranslationAggregateBuilder`
|
|
271
|
-
# above), and any `retired` aggregates that
|
|
271
|
+
# above), and any `retired` aggregates that do not exist in the
|
|
272
272
|
# destination era.
|
|
273
273
|
class TranslationBuilder
|
|
274
274
|
GRAMMAR_CONTEXT = "Translation".freeze
|
|
@@ -13,6 +13,11 @@ module Hecks
|
|
|
13
13
|
|
|
14
14
|
# A call with a block records the block's own settings as a nested Hash, so a bind can
|
|
15
15
|
# group settings (`preview do ... end`); a call without one records its argument.
|
|
16
|
+
#
|
|
17
|
+
# @param key [Symbol] the setting's name, recorded verbatim
|
|
18
|
+
# @param args [Array] the setting's value: one argument is kept as is, several as an array
|
|
19
|
+
# @param block [Proc, nil] a nested settings block, evaluated on a fresh collector
|
|
20
|
+
# @return [Object] the value recorded under `key`
|
|
16
21
|
def method_missing(key, *args, &block)
|
|
17
22
|
@values[key.to_sym] =
|
|
18
23
|
if block
|
|
@@ -302,7 +302,7 @@ module Hecks
|
|
|
302
302
|
end
|
|
303
303
|
|
|
304
304
|
# Entity-owned categories have no top-level aggregate for the runtime
|
|
305
|
-
# to route a bare verb into
|
|
305
|
+
# to route a bare verb into — `Member`'s own "Pair" reaches
|
|
306
306
|
# the runtime as `ValueObject.Member.Pair`, and a nested one
|
|
307
307
|
# (`Dispatch`, inside `Handler`) reaches it as `ProcessManager.
|
|
308
308
|
# Handler.Dispatch.Bind` — the dotted shape `EntityInterpreter#call`
|
|
@@ -567,8 +567,8 @@ module Hecks
|
|
|
567
567
|
# Reference its type is Reference<X>, another aggregate's head
|
|
568
568
|
# Holds its type names an entity this aggregate declares
|
|
569
569
|
#
|
|
570
|
-
# Nothing is skipped
|
|
571
|
-
#
|
|
570
|
+
# Nothing is skipped. Without Reference and Holds the walk would drop
|
|
571
|
+
# both kinds and the meta-domain would silently not contain
|
|
572
572
|
# Account#customer_id or Account#ledger.
|
|
573
573
|
# Each alternate carries its own map, read from the language. Borrowing the
|
|
574
574
|
# primary's map dispatched `type:` where Reference declares `points_at:`,
|
|
@@ -108,7 +108,7 @@ module Hecks
|
|
|
108
108
|
# S17, ADR 0026 — Member/Handler/Dispatch are entities now
|
|
109
109
|
# (`entity "Member" do ... end`, nested under `ValueObject`/
|
|
110
110
|
# `ProcessManager`/`Handler`), not their own top-level
|
|
111
|
-
# aggregates — so `meta.aggregates` alone
|
|
111
|
+
# aggregates — so `meta.aggregates` alone does not find
|
|
112
112
|
# them the way it always found a standalone `aggregate
|
|
113
113
|
# "Member"`. Each still needs its own named category here:
|
|
114
114
|
# `Assembly::Contracts` keeps a bespoke entry for each
|
|
@@ -125,8 +125,8 @@ module Hecks
|
|
|
125
125
|
# itself ever declares are exactly the three this ADR
|
|
126
126
|
# names. `entity_owned: true` records why this is a
|
|
127
127
|
# category at all — the real runtime has no top-level
|
|
128
|
-
# aggregate named "Member" to dispatch a bare verb into
|
|
129
|
-
#
|
|
128
|
+
# aggregate named "Member" to dispatch a bare verb into,
|
|
129
|
+
# so the judge has to build a dotted one instead
|
|
130
130
|
# (see `Judge#verb_for`).
|
|
131
131
|
#
|
|
132
132
|
# Recurses — `Dispatch` nests inside `Handler`, which nests
|
|
@@ -158,7 +158,7 @@ module Hecks
|
|
|
158
158
|
# Every verb the language declares, spelled as the judge would
|
|
159
159
|
# dispatch it. S17, ADR 0026 — an entity-owned category (its
|
|
160
160
|
# own `entity_owned` flag) has no real top-level aggregate the
|
|
161
|
-
# runtime can route a bare verb into
|
|
161
|
+
# runtime can route a bare verb into, so it is
|
|
162
162
|
# spelled dotted here too — `Bluebook::ValueObject.Member.
|
|
163
163
|
# Declare`, `Bluebook::ProcessManager.Handler.Dispatch.Bind` —
|
|
164
164
|
# matching `Judge#verb_for`/`#dotted_prefix`'s own build
|
|
@@ -364,7 +364,7 @@ module Hecks
|
|
|
364
364
|
# same way Shapes#provenance reads it back.
|
|
365
365
|
return encode_literal(node.provenance) if field == :provenance
|
|
366
366
|
|
|
367
|
-
# `identified_by` is
|
|
367
|
+
# `identified_by` is not a field of any declaration — it is a list,
|
|
368
368
|
# filled by Identify one part at a time, so it is read through `identity_rows`
|
|
369
369
|
# like every other list rather than special-cased here. What this branch
|
|
370
370
|
# existed to protect is now structural : a path cannot come back as its head,
|
|
@@ -228,7 +228,7 @@ module Hecks
|
|
|
228
228
|
# by its own dotted `ValueObject.Member.Pair`. Its data therefore
|
|
229
229
|
# lives inline on the value object's own dispatched state — same as
|
|
230
230
|
# any other entity list — not behind a separate `DeclaredIn` query:
|
|
231
|
-
# there is no such query
|
|
231
|
+
# there is no such query, because there is no top-level
|
|
232
232
|
# "Member" aggregate left to hold one. Pairs are still an open map,
|
|
233
233
|
# which no value object can hold, so they still come back one pair
|
|
234
234
|
# at a time.
|
|
@@ -330,7 +330,7 @@ module Hecks
|
|
|
330
330
|
# Handler.Dispatch`/`...Dispatch.Bind`. Its data therefore lives
|
|
331
331
|
# inline on the process manager's own dispatched state — same as
|
|
332
332
|
# any other entity list — not behind a separate `DeclaredIn`
|
|
333
|
-
# query : there is no such query
|
|
333
|
+
# query : there is no such query, the same fix
|
|
334
334
|
# `Reconstruction#members_of` already made for Member.
|
|
335
335
|
def process_manager(row)
|
|
336
336
|
declaration("ProcessManager", row,
|
|
@@ -32,7 +32,7 @@ module Hecks
|
|
|
32
32
|
default: decode_literal(text(field[:default])),
|
|
33
33
|
# Read back the same way `list` is — both are booleans about the
|
|
34
34
|
# attribute, held as text, and dropping either would rebuild a
|
|
35
|
-
# bluebook that
|
|
35
|
+
# bluebook that says something other than what was written.
|
|
36
36
|
optional: text(field[:optional]).to_s == "true",
|
|
37
37
|
pattern: presence(text(field[:pattern])),
|
|
38
38
|
# The round trip is the only way in. The grammar registry keeps the
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
require "digest"
|
|
2
2
|
require "fileutils"
|
|
3
|
+
require_relative "../../cache_dir"
|
|
3
4
|
|
|
4
5
|
module Hecks
|
|
5
6
|
module Bluebook
|
|
@@ -145,13 +146,10 @@ module Hecks
|
|
|
145
146
|
#
|
|
146
147
|
# Fails toward a real boot, never toward a wrong table — same
|
|
147
148
|
# loud-not-silent discipline this codebase already holds CI to
|
|
148
|
-
# (`postgres_io_relevant_changed`'s own header). A missing file, a
|
|
149
|
-
#
|
|
150
|
-
#
|
|
151
|
-
#
|
|
152
|
-
# for exactly this kind of local, disposable-but-useful-while-it-
|
|
153
|
-
# lasts artifact (`Storehouse::LOG_ROOT`'s own header names the
|
|
154
|
-
# same convention).
|
|
149
|
+
# (`postgres_io_relevant_changed`'s own header). A missing file, a corrupt
|
|
150
|
+
# Marshal blob, a permission error or an unwritable cache directory degrades
|
|
151
|
+
# to "no disk cache today", never to a crash or a served-but-wrong table.
|
|
152
|
+
# The cache lives under `Hecks::CacheDir`, never the gem's read-only directory.
|
|
155
153
|
#
|
|
156
154
|
# **Atomic write, not a lock** — `qa_sweep --all` spawns up to 4
|
|
157
155
|
# children at once, any of which could reach a cold cache
|
|
@@ -166,7 +164,10 @@ module Hecks
|
|
|
166
164
|
# change, the same shape `Storehouse::BOOT_ROOT`'s own
|
|
167
165
|
# `HECKS_STOREHOUSE_ROOT` override uses, for the day this needs to
|
|
168
166
|
# be ruled out while debugging something else entirely.
|
|
169
|
-
|
|
167
|
+
#
|
|
168
|
+
# @return [String] the directory cache entries are written to:
|
|
169
|
+
# `hecks_syntax_boot_cache` under `Hecks::CacheDir`
|
|
170
|
+
def cache_dir = Hecks::CacheDir.path("hecks_syntax_boot_cache")
|
|
170
171
|
|
|
171
172
|
# Reports whether the cross-process disk cache is turned on.
|
|
172
173
|
#
|
|
@@ -203,7 +204,7 @@ module Hecks
|
|
|
203
204
|
return unless disk_cache_enabled?
|
|
204
205
|
|
|
205
206
|
path = disk_cache_path(chapters)
|
|
206
|
-
FileUtils.mkdir_p(
|
|
207
|
+
FileUtils.mkdir_p(cache_dir)
|
|
207
208
|
tmp_path = "#{path}.#{Process.pid}.tmp"
|
|
208
209
|
File.binwrite(tmp_path, Marshal.dump(result))
|
|
209
210
|
File.rename(tmp_path, path)
|
|
@@ -217,7 +218,7 @@ module Hecks
|
|
|
217
218
|
# chapter]` pairs to key the cache entry on
|
|
218
219
|
# @return [String] the disk cache file path for `chapters`
|
|
219
220
|
def disk_cache_path(chapters)
|
|
220
|
-
File.join(
|
|
221
|
+
File.join(cache_dir, "#{disk_cache_key(chapters)}.marshal")
|
|
221
222
|
end
|
|
222
223
|
|
|
223
224
|
# Builds the cache key for `chapters`.
|