Skip to content

feat(ruby): add Ruby on Rails support (rspec, rubocop, rake, bundle)#724

Merged
pszymkowiak merged 4 commits intortk-ai:developfrom
navidemad:feat(ruby)/rails-support-unified
Mar 19, 2026
Merged

feat(ruby): add Ruby on Rails support (rspec, rubocop, rake, bundle)#724
pszymkowiak merged 4 commits intortk-ai:developfrom
navidemad:feat(ruby)/rails-support-unified

Conversation

@navidemad
Copy link

@navidemad navidemad commented Mar 19, 2026

Ruby Rails

Summary

Unifies 5 competing PRs (#198, #292, #379, #534, #643) into a single coherent Ruby on Rails implementation for RTK.

Adds RSpec, RuboCop, Minitest (via rake/rails test), and Bundler support with 3 new Rust command modules, 1 TOML filter, shared Ruby infrastructure, and automatic discover/rewrite rules.

Includes 56 unit tests across the 3 modules, 4 inline TOML tests, and 23 E2E assertions in scripts/test-ruby.sh — all 1035 tests passing.

New Commands

Command Savings Notes
rtk rspec 60%+ JSON auto-inject (--format json), text fallback with state-machine parser
rtk rubocop 60%+ JSON auto-inject, groups by cop/severity, skips JSON in autocorrect mode
rtk rake test 85%+ Minitest text parser, handles standard and minitest-reporters formats
rtk bundle install 90%+ TOML filter, short-circuits to ok bundle: complete on success
Key Design Decisions (click to expand)
Decision Detail
JSON injection Injects --format json for rspec/rubocop unless user specified -f/--format/-fj/--format=.... Skips in rubocop autocorrect mode (-a, -A).
Noise stripping (rspec) Strips Spring preloader, SimpleCov, DEPRECATION warnings, Finished in timing, Capybara screenshots (keeps path only).
3-tier JSON fallback (rspec) Strip noise → parse JSON → try original → text parser → fallback_tail(). Logs serde error on final fallback.
Safe JSON fallback (rubocop) JSON parse failure uses fallback_tail() instead of feeding JSON through the text parser.
State machine parsers Both rspec (text fallback) and minitest use state-machine text parsers for structured extraction.
TOML for bundle bundle install/update uses match_output short-circuit (90%+ savings on success) — natural fit for TOML DSL over a full Rust module.
Defensive arithmetic saturating_sub throughout, graceful degradation on parse failure.
Signal-aware exit codes exit_code_from_output returns 128 + signal on Unix per convention.
Shared Infrastructure & Registry (click to expand)
Function Purpose
ruby_exec(tool) Auto-detects bundle exec when Gemfile exists. Transitive deps like rake still go through bundler.
fallback_tail(output, label, n) Last-resort filter fallback showing final N lines with diagnostic logging.
exit_code_from_output(output, label) Signal-aware exit code extraction: returns 128 + signal on Unix.
count_tokens(text) Shared test helper for token savings assertions.

Discover Registry: Detection patterns for rspec, rubocop, rake test, rails test, bundle install/update (with bundle exec and bin/ variants).

Hook Integration

The discover registry now correctly rewrites the following commands:

Rewritten to From input
rtk rspec rspec
bundle exec rspec
bin/rspec
rtk rubocop rubocop
bundle exec rubocop
rtk rake test rake test
rails test
bundle exec rake test
bundle exec rails test
bin/rails test
rtk bundle ... bundle install
bundle update

How to Test

# 1. Run unit tests (no Ruby required)
cargo test --all

# 2. Run Ruby-specific tests only
cargo test rspec_cmd    # 28 tests
cargo test rubocop_cmd  # 18 tests
cargo test rake_cmd     # 10 tests

# 3. Build and install locally
cargo install --path .

# 4. Run E2E smoke tests (~60-120s, requires Ruby/Bundler/Rails)
bash scripts/test-ruby.sh
# Creates a temp Rails app, exercises all 4 commands:
# rspec (JSON/text fallback, pending, empty suite, failure caps)
# rubocop (JSON, autocorrect, offenses)
# rake test (minitest pass/fail, exit codes)
# bundle install (TOML filter, idempotent)
# + exit code preservation, bundle exec variants, token savings checks

Documentation

  • README.md: Ruby commands added to usage examples and hook rewrite table
  • CHANGELOG.md: Unreleased section with all Ruby features (rspec, rubocop, rake, bundle)
  • ARCHITECTURE.md: Ruby module table (rake, rspec, rubocop)

Attribution

Note

This PR unifies 5 competing implementations. Below is what was taken from each and why.

PR #198 (by @deril) — RSpec only

Incorporated: #[serde(default)] on backtrace field — reviewer-requested fix for RSpec versions that omit backtrace from JSON.

Not taken: Simpler rspec implementation — superseded by #292/#643's more robust version.


PR #292 (by @navidemad) — RSpec + RuboCop

Incorporated:

  • Primary source for rspec_cmd.rs, rubocop_cmd.rs, and shared utils (ruby_exec, fallback_tail, exit_code_from_output, count_tokens)
  • Noise-stripping regex, 3-tier JSON fallback, state-machine text parser, signal-aware exit codes
  • E2E smoke test script (test-ruby.sh) — used as base for the unified scripts/test-ruby.sh

PR #379 (by @navidemad) — Bundle + Rails (TOML DSL hybrid)

Incorporated:

  • The TOML filter concept for bundle install/update — simpler than a full Rust module for low-savings commands
  • E2E smoke test script (test-bundle-rails.sh) — contributed the rake test and bundle install sections to scripts/test-ruby.sh

Not taken: The 7 Rails TOML filters (db:migrate, generate, etc.) — lower savings (10-40%) and tightly coupled to TOML DSL internals. Also rails_cmd.rs routes/other routing — too complex for initial merge.


PR #534 (by @cosgroveb) — RSpec with parser trait

Incorporated: Improved format flag detection — handles -fj, -fjson, -fdocumentation, --format=... patterns that the other PRs missed, plus 4 dedicated tests.

Not taken: parser module trait-based architecture (adds indirection without benefit for standalone modules), tempfile --out approach (adds complexity), Gemfile.lock detection (the Gemfile check is simpler).


PR #643 (by @Maimer) — Most Complete

Incorporated: rake_cmd.rs (unique to this PR — only implementation of Minitest parsing), discover rules structure (most comprehensive), bundle-install.toml, ARCHITECTURE.md Ruby Module Architecture section and CLAUDE.md module table/fork-features updates. Preferred as base when approaches conflicted.

Summary

Module Source PRs Tests
Filters
rspec_cmd.rs #292/#643
+ #534 format detection
+ #198 serde fix
28
rubocop_cmd.rs #292/#643 18
rake_cmd.rs #643 (unique) 10
bundle-install.toml #643
+ #379 (concept)
4
Infrastructure
utils.rs additions #292/#643
discover/rules.rs #643 (most complete)
Testing
scripts/test-ruby.sh #292 (base)
+ #379 (rake/bundle sections)
23 E2E assertions
scripts/test-all.sh #292/#643
(Ruby conditional section)
3 smoke checks
Docs
README.md, CHANGELOG.md
ARCHITECTURE.md, CLAUDE.md #643 (Ruby architecture section, module table)

Closes #292, #379

Based on work by @deril (#198), @cosgroveb (#534), and @Maimer (#643) — thank you for your contributions.

navidemad and others added 2 commits March 19, 2026 13:40
Unifies 5 competing PRs (rtk-ai#198, rtk-ai#292, rtk-ai#379, rtk-ai#534, rtk-ai#643) into a single
coherent implementation.

New commands:
- rtk rspec: JSON parsing with text fallback (60%+ savings)
- rtk rubocop: JSON parsing, group by cop/severity (60%+ savings)
- rtk rake test: Minitest state machine parser (85-90% savings)
- rtk bundle install: TOML filter, strip Using lines (90%+ savings)

Shared infrastructure: ruby_exec(), fallback_tail(),
exit_code_from_output(), count_tokens() in utils.rs.

Discover/rewrite rules for rspec, rubocop, rake, rails, bundle
including bundle exec and bin/ variants.

E2E smoke tests (scripts/test-ruby.sh) covering all 4 commands.
56 new unit tests + 4 inline TOML tests. All 1035 tests passing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Navid EMAD <navid.emad@yespark.fr>
Rails' `rake test` ignores positional file args; use `TEST=path` syntax.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Navid EMAD <navid.emad@yespark.fr>
Integrate ARCHITECTURE.md Ruby Module Architecture section and CLAUDE.md
module table/fork-features from PR rtk-ai#643. Update PR description attribution.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Navid EMAD <navid.emad@yespark.fr>
PR description lives on GitHub, no need to track in the codebase.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Navid EMAD <navid.emad@yespark.fr>
@pszymkowiak
Copy link
Collaborator

Tested on a real Ruby project with rspec, rubocop, rake, bundler.

Results

Command RAW RTK Savings Verdict
rtk rspec 414 chars 328 chars 20% PASS — JSON injection works, failures shown compact
rtk rubocop 13155 chars 11127 chars 15% PASS — grouped by file with offense counts
rtk bundle install 132 chars 19 chars 85% PASS — "ok bundle: complete"
rtk rake test PASS — runs correctly

Savings are low on this small test project (3 specs, 4 files). Expected 60%+ on real Rails projects with hundreds of tests.

Quality

  • 1035 tests passing, compiles clean
  • Code well structured: 3 Rust modules + 1 TOML filter + shared infra
  • JSON auto-inject for rspec/rubocop, state-machine text fallback
  • ruby_exec() auto-detects bundle exec when Gemfile exists
  • Discover registry handles bundle exec rspec, bin/rspec, etc.

Note: rubocop stderr contains cops config warnings (~200 lines) that pass through unfiltered — this is rubocop's behavior when no .rubocop.yml exists, not a filter issue.

LGTM — ready to merge.

@pszymkowiak pszymkowiak merged commit 15bc0f8 into rtk-ai:develop Mar 19, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants