Skip to content

Read gemspec directives and dev deps as Ruby code (#1932) - #1936

Merged
Mikola Lysenko (mikolalysenko) merged 3 commits into
mainfrom
arch-refactor/1932-gemspec-code-lines
Nov 2, 2026
Merged

Mikola Lysenko (mikolalysenko) merged 3 commits into
mainfrom
arch-refactor/1932-gemspec-code-lines

Conversation

@mikolalysenko

@mikolalysenko Mikola Lysenko (mikolalysenko) commented Nov 1, 2026 •

Copy link
Copy Markdown
Collaborator

LLM Description written by Claude Code:claude-opus-5-5

Fixes #1932

Summary

Register row A54 (see Part 3, duplicated business logic). formats/gem/manifest.rs already has a shared Ruby code-line reader that skips =begin/=end blocks, heredoc bodies and __END__ data, and vex/product.rs uses it to read gemspecs. The two gemspec readers in formats/gem/gemspec.rs scanned raw lines instead, so:

  • a commented-out add_development_dependency was merged into the pin (~> 2, = 1.0.0 where Bundler locks = 1.0.0), and frozen installs failed;
  • a gemspec path: ROOT inside a heredoc body refused the whole Gemfile.

This PR drops the per-reader line scanning and routes every reader through the one shared reader.

Changes

  • for_each_code_line → code_lines (manifest.rs). The callback becomes an iterator that also yields the 0-based line index, so readers that return Err early can use ?. Its 3 existing callers (gemfile_lockfile, eval_gemfile_paths, vex::product::parse_gemspec) become plain for loops or a collect.
  • gemspec_directives iterates code_lines. The directive's line index has the same meaning as before.
  • dev_dependency_requirements iterates code_lines. Its own # check is gone, because the reader now matches on code only.
  • locked_exact_requirement's gem-line lookup iterates code_lines too. Otherwise a gem line inside =begin would count as the declaration that the directive has to come before.
  • Tests: a new begin_blocks_heredocs_and_end_data_are_not_code covers a directive in =begin, a heredoc and after __END__; a dev dependency in =begin and in a heredoc; and a gem line in =begin. Red→green: with main's readers restored and this test kept, it fails with left: Err("line 5: \gemspec path: ROOT`")`. With this PR it passes.

Size

git diff --stat: 3 files, +55/−31. That is about +33/−31 production lines and +22 test lines.

Behavior change

Only for Gemfiles and gemspecs with =begin blocks, heredocs, __END__ data or a leading BOM. Those lines are no longer read as gemspec directives, dev dependencies or gem declarations, as the issue's acceptance criteria require. Everything else is unchanged.

Verification

  • cargo clippy --workspace --all-features -- -D warnings: clean.
  • cargo test -p socket-patch-core --lib: 6996 passed. The 4 failures are the known root-sandbox ones that also fail on main: copy_tree symlinked root, vlt_heal unremovable lock, pypi_poetry and pypi_requirements wire failures.
  • CLI: in_process_gem_apply, in_process_gem_multi_platform and e2e_vex pass.
  • CI (82 checks) and Bugbot: green.

/code-review high

9 findings. I fixed 2:

  • the gem-line lookup now matches on code like the other readers;
  • I restored the \r trim in bundler_merges_dev_dependencies (removing it was not behavior-neutral).

Not fixed, with reasons:

  • A gem line inside an instance_eval <<~G heredoc is now missed. Ruby does evaluate it, but the issue asks for heredoc bodies to be skipped, and gemfile_lockfile and vex already treat them that way.
  • heredoc_ids misreads x <<FLAG (a shift) as a heredoc; an indented terminator closes a plain <<ID heredoc. Both are existing heuristics of the shared reader, which gemfile_lockfile and VEX already depend on. Fixing them is a separate change to manifest.rs.
  • vendor/gem.rs plan_gemfile_edit, vex/discover/gem.rs and redirect/upstream/gem.rs still hand-scan =begin. For the new test's Gemfile, the writer refuses ("declared more than once"), which fails closed. Routing them through code_lines is a follow-up, noted in the register.
  • Gemfile read twice, code_of re-run on stripped code, Vec::remove(0). All are negligible. The code_of re-run is what still detects an unterminated quote.

Risk

Low: one file's readers, plus a mechanical signature change in two callers. No cfg(windows)/cfg(unix) code was touched.

https://claude.ai/code/session_011f9aePo7nZ74KqPGHC4rvE


Generated by Claude Code

Assisted-by: Claude Code:claude-opus-5-5
@mikolalysenko Mikola Lysenko (mikolalysenko) added refactor Structural change: duplicated code or logic, missing abstraction, layering, dead code arch-refactor PR opened by the scheduled architecture refactor routine labels Nov 1, 2026
for_each_code_line becomes code_lines, an iterator that also yields
the 0-based line index. gemspec_directives, dev_dependency_requirements
and locked_exact_requirement's gem-line lookup now skip =begin/=end
blocks, heredoc bodies and __END__ data, as Ruby does, instead of
scanning raw lines. A commented-out dev dependency no longer pins
'~> 2, = 1.0.0' where Bundler locks '= 1.0.0', and a heredoc body no
longer refuses the Gemfile.

Fixes #1932

Assisted-by: Claude Code:claude-opus-5-5
The gem-declaration lookup reads the comment-stripped code like the
other code_lines readers, and bundler_merges_dev_dependencies keeps
trimming stray CRs from the BUNDLED WITH header.

Assisted-by: Claude Code:claude-opus-5-5
@mikolalysenko
Mikola Lysenko (mikolalysenko) marked this pull request as ready for review November 1, 2026 13:19
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

BugBot review


Generated by Claude Code

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit ba7b17d. Configure here.

Mikola Lysenko (mikolalysenko) pushed a commit that referenced this pull request Nov 1, 2026
Assisted-by: Claude Code:claude-opus-5-5
@mikolalysenko Mikola Lysenko (mikolalysenko) added the Ready for review Agent-verified: mergeable, CI green, Bugbot clean — awaiting human review label Nov 1, 2026
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

Ready for review (burn-down agent).

  • Head: ba7b17d4c32427b9be68975fb525b47a30db868b
  • CI: 82/82 checks green (32 success, 50 skipped), no main-wide failures
  • Bugbot: reviewed ba7b17d4c3, no findings; no unresolved review threads
  • Mergeable, no CHANGELOG.md change
  • Reviewer focus: for_each_code_line became the code_lines iterator in formats/gem/manifest.rs; check that the three existing callers still skip the same lines.

Generated by Claude Code

@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

Final review brief

What it does: The two gemspec readers in formats/gem/gemspec.rs (the gemspec directive reader and the dev-dependency reader) used to scan raw lines, so a dev dependency inside =begin/=end or a heredoc got merged into the pin, and a gemspec path: ROOT inside a heredoc refused the whole Gemfile. They now go through the shared Ruby code-line reader (for_each_code_line turned into the code_lines iterator), which already skips comment blocks, heredoc bodies and __END__ data.

Risk: Low. The change is limited to gem manifest parsing. The iterator conversion is mechanical for the 3 existing callers. Line indices keep their meaning (lines() vs split('\n') give the same indices, and BOM stripping doesn't shift lines), and directive.line < decl compares two indices from the same reader.

Look here:

Verified: Read the full diff and all callers of gemspec_directives (hosted/engine.rs only uses the dirs). Ran cargo test -p socket-patch-core --lib -- formats::gem vex::product: 208 passed. CHANGELOG.md is untouched. CI 82/82 green, Bugbot ✅ (no new issues).

Changes I made: none.

Open questions: none. The description lists the follow-ups (vendor/gem.rs, vex/discover/gem.rs and redirect/upstream/gem.rs still hand-scan =begin), and they fail closed.

Auto-merge (squash) is armed, so approving sends it straight to the merge queue.


Generated by Claude Code

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[agent] Reviewed ba7b17d4c32427b9be68975fb525b47a30db868b. Checked shared Ruby code-line iteration through gemspec directives, dev dependencies and VEX. No major correctness issues found. Validation: source and regression-test review plus the available exact-head CI checks; no local test pass is claimed.

@mikolalysenko
Mikola Lysenko (mikolalysenko) added this pull request to the merge queue Nov 2, 2026
Merged via the queue into main with commit eb3f017 Nov 2, 2026
82 checks passed
@mikolalysenko
Mikola Lysenko (mikolalysenko) deleted the arch-refactor/1932-gemspec-code-lines branch November 2, 2026 17:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

arch-refactor PR opened by the scheduled architecture refactor routine Ready for review Agent-verified: mergeable, CI green, Bugbot clean — awaiting human review refactor Structural change: duplicated code or logic, missing abstraction, layering, dead code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

gemspec readers treat =begin blocks and heredocs as code: route gemspec_directives and dev_dependency_requirements through manifest::for_each_code_line

3 participants