Adopt line-aligned ast_transform 3.0; delete the mapping apparatus (3.0.0)#13
Merged
Conversation
Failing tests must report line numbers from the source the developer wrote, not the transformed code that executes. Unit tests cover RSpock::BacktraceFilter and the Minitest wrapper against a real registered SourceMap; a subprocess integration test pins the end-to-end behavior, including one test documenting that the Minitest plugin filter is still required — ast-transform's compile-with-source-path fix corrected file paths but line mapping still needs the filter. Co-authored-by: Cursor <cursoragent@cursor.com>
Raw line numbers — no Minitest plugin, no BacktraceFilter, no SourceMap — must be source line numbers once ast-transform emits line-aligned code. Four angles through the full RSpock transformation: - Then assertion failure cites the statement's source line - failing Where row cites the failing statement's source line - interaction setup executes at the interaction's own source line (today interactions hoist textually to the When position) - Cleanup-block failure cites the cleanup statement's source line Plus one green pin: the generated test name embeds the data row's source line — the row-isolation selector that must survive _line_number_ removal. All four alignment tests are red today. Co-authored-by: Cursor <cursoragent@cursor.com>
Stage 2 + 2b + 3 of the line-aligned emission plan: Adopt promoted machinery: node classes register on ASTTransform::Node (REGISTRY/Node.build/NodeBuilder deleted); parsers anchor IR nodes (s_at) at the statements they classify so lowered assertions and Mocha setups emit at their own source lines. TestMethodTransformation rebuilt around source order: Then/Expect sections lower in place, and execution-order needs that source order cannot express use ast-transform's deferral facility — interactions defer the When body via run_after (the paved road); raises-with- interactions composes the deferred execution into assert_raises via low-level defer; raises-without-interactions inlines the When body. The hoisted_setups accumulator is gone. _test_index_/_line_number_ removed: MethodCallToLVarTransformation (a full extra AST pass per test) deleted; the row line still flows into the generated test NAME (uniqueness + -n selector target) through internal __rspock_row_index__/__rspock_row_line__ block params. Deleted: BacktraceFilter, its Minitest adapter and plugin, the Rails generator + initializer template, and the source_map_rescue_wrapper — line-aligned emission makes raw VM line numbers the source line numbers, so there is nothing left to map. The subprocess canary inverts: it now asserts source-true output with zero filter machinery. All five line-alignment acceptance tests green; suite 232 tests, 0 failures. rspock now requires ast_transform ~> 3.0. Co-authored-by: Cursor <cursoragent@cursor.com>
README: the Rails generator section is replaced by "no setup needed"; the Debugging chapter now documents source-true backtraces and debugger display, the one interaction-stepping oddity, and the Where-row isolation triage (rerun command / -n by row line / conditional break on column locals) replacing the deleted _test_index_/_line_number_ magic variables. Test-name interpolation documents the appended '<index> line <line>' suffix as the row-isolation selector target. Skill (from the PR #11 branch, riding this one): drops the Rails generator setup, reframes tmp/ast_transform as line-matched, and replaces the magic-variable debugging advice with the same triage. Version 3.0.0; rspock requires ast_transform ~> 3.0. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Ruby 3.2 is EOL (March 2026) — required_ruby_version and the CI matrix move to 3.3+, which also lifts the temporary unparser < 0.9 Gemfile pin. The direct parser and unparser runtime dependencies are removed: rspock only touches both through ast_transform, which owns their floors (unparser >= 0.8, parser >= 3.3). Lockfile now on unparser 0.9.0. Co-authored-by: Cursor <cursoragent@cursor.com>
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Co-authored-by: Cursor <cursoragent@cursor.com>
dev.yml pins Ruby 4.0.6 (latest; converges with the org toolchain) and declares up/test; dev up provisions the per-machine .shadowenv.d (now gitignored) via rbenv, so the right Ruby activates without manual PATH surgery. .ruby-version gives plain rbenv users the same pin. Inert for external contributors — plain Bundler still works, README says so. Co-authored-by: Cursor <cursoragent@cursor.com>
dev now single-sources the project Ruby from the dependencies.rb manifest; dev.yml's ruby: key is removed. Toolchain-only manifest — gems stay bundler-managed via the hand-written gemspec/Gemfile. Co-authored-by: Cursor <cursoragent@cursor.com>
Updates to ast_transform's proc lowering (hidden closure is a non-lambda proc with method-scope pre-declarations): - Fixes the long-standing NameError when a Then expectation or an ensure-run Cleanup reads a local assigned in a When body deferred behind interaction setups. - New subprocess acceptance fixtures pin both: When-result readable in Then, and Cleanup seeing the When local after a failing Then. - Transformation expectations updated (proc do + result = result pre-declaration) and a new expectation pinning the emission shape. - CI adds Ruby 3.4. Co-authored-by: Cursor <cursoragent@cursor.com>
The When body is now wrapped in one thunk node placed at its execution point (after the last interaction setup, or composed into the assert_raises block); ast_transform's lowering re-emits the body at its own source lines. The raises-with-interactions branch loses the manual placement splice, and the hidden lvar is now __ast_thunk_N__. Co-authored-by: Cursor <cursoragent@cursor.com>
ast_transform's line-aligned emitter now indents freshly placed statements to their source column; transformation expectations pick up the indented (source-shaped) layout. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
The &block tests asserted regex fragments on deterministic unparser output. Replace them with exact expected source via assert_transforms, and make assert_transforms compare exactly instead of massaging trailing newlines (gsub(/\n$/, '') stripped two newlines from multi-line expectations, since $ also matches before a final newline). Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Codecov flagged build_raises_body's interactions arm and its insert_after helper as the only uncovered lines in test_method_transformation.rb. Pin the transformed shape (assert_raises wrapping the thunk call, inserted after the last Mocha setup) and add a behavioral example test exercising the combination end to end. Co-authored-by: Cursor <cursoragent@cursor.com>
Nothing Rails-specific remains: no generator, no backtrace cleaner to configure. The railtie still loads the rake tasks automatically, which is why the Rakefile snippet stays qualified as non-Rails. Co-authored-by: Cursor <cursoragent@cursor.com>
The old name described the deleted mechanism, not the behavior the test pins. Also spell out why the fixture's blank lines and split expressions are load-bearing: without them a non-aligned emitter would reproduce the source line numbers by coincidence. Co-authored-by: Cursor <cursoragent@cursor.com>
Prep for a future rubocop-shopify adoption (Layout/LineLength: 120), mirroring ast-transform. Expected-output heredocs keep their long lines (AllowHeredoc exempts them, and they pin real emitted output). Co-authored-by: Cursor <cursoragent@cursor.com>
The line-length wrap of validate_blocks' second raise pulled it into the PR's patch, and Codecov showed it had never been exercised: no test ended a test method on a block that requires a successor. Pin the BlockError for a When with no Then. Co-authored-by: Cursor <cursoragent@cursor.com>
3 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adopts ast_transform 3.0 line-aligned emission (rspockframework/ast-transform#12) and deletes RSpock's entire backtrace-mapping apparatus. Raw VM line numbers are now the source line numbers — backtraces, failure messages, breakpoints, and debugger display are source-true with zero runtime filtering.
Builds on the red acceptance tests from this branch's first commits; all five now pass: Then assertion failures, failing Where rows, interaction setups, and Cleanup failures cite their own source lines, and the generated test name still embeds the row line.
Simplification (Stage 2)
ASTTransform::Node— RSpock'sNode::REGISTRY,Node.build, and theNodeBuildersoverride are deleted; classes keep only accessors.TestMethodTransformationrebuilt around source order: Then/Expect sections lower in place (parsers anchor IR nodes at the statements they classify vias_at), and thehoisted_setupsaccumulator threading is gone._test_index_/_line_number_removed (MethodCallToLVarTransformationdeleted — a full extra AST pass per test). The row line still flows into the generated test NAME (uniqueness +-nselector target) through internal__rspock_row_index__/__rspock_row_line__block params.Execution-order via deferral (Stage 2b)
run_after(body, run: when_statements, after: last_setup)— the When body stays at its source position textually and executes after the last interaction setup. Only tests with interactions pay the lambda.raises+ interactions: low-leveldefer, with the deferred execution composed into theassert_raisesblock.raiseswithout interactions: the When body inlines directly intoassert_raises(unchanged).Deletions (Stage 3)
RSpock::BacktraceFilter,RSpock::Minitest::BacktraceFilter, the Minitest plugin, the Rails generator + initializer template, and the class-body rescue wrapper. The subprocess canary from #12 inverts: it now asserts source-true output with zero filter machinery.Breaking (3.0.0)
required_ruby_version >= 3.3, CI matrix now 3.3/4.0.parserandunparserruntime dependencies removed: rspock uses both only through ast_transform, which owns their floors._test_index_/_line_number_, the Rails generator, and the backtrace filters (above) are the user-facing removals.Docs
README loses the Rails-generator section and the magic-variables tips; Debugging documents "just works" plus the Where-row isolation triage (rerun command /
-nby row line / conditional break on column locals). The skill (riding from #11) gets the same updates.Suite: 232 tests, 0 failures. Supersedes the "plugin still needed" documentation test from #12.
Note: Gemfile temporarily pins ast_transform to the branch; swap to the released 3.0.0 before merge.
Made with Cursor