Skip to content

Repository files navigation

NitroCop

Fast Ruby linter in Rust targeting RuboCop compatibility.

Note

🚧 Early-stage: Detection is high-fidelity on most codebases but edge cases remain. Autocorrect is not yet complete. Expect bugs.

Benchmark on the rubygems.org repo (1,226 files, Ruby 4.0), Apple Silicon:

ScenarionitrocopRuboCopSpeedup
Local dev (50 files changed)324ms1.14s3.5x
CI (no cache)318ms18.56s58.4x

Features

  • 916 cops from 6 RuboCop gems (rubocop, rubocop-rails, rubocop-performance, rubocop-rspec, rubocop-rspec_rails, rubocop-factory_bot)
  • 98.7% conformance against RuboCop across 5,590 open-source repos
  • Autocorrect (-a/-A) is partial — work in progress
  • Reads your existing .rubocop.yml — no migration needed
  • Uses Prism (Ruby's official parser) via ruby-prism crate
  • Parallel file processing with rayon

Quick Start (Work in progress 🚧)

Requires Rust 1.85+ (edition 2024).

cargo install nitrocop # not yet published — build from source for now

Then run it in your Ruby project:

nitrocop

Configuration

nitrocop reads .rubocop.yml with full support for:

  • inherit_from — local files, recursive
  • inherit_gem — resolves gem paths via bundle info
  • inherit_mode — merge/override for arrays
  • Department-level configRSpec:, Rails: Include/Exclude/Enabled
  • AllCopsNewCops, DisabledByDefault, Exclude, Include
  • Enabled: pending tri-state
  • Per-cop optionsEnforcedStyle, Max, AllowedMethods, AllowedPatterns, etc.

Config auto-discovery walks up from the target directory to find .rubocop.yml.

Cops

nitrocop supports 916 cops from 6 RuboCop gems.

Compared with RuboCop on 5,590 open-source repos (593k Ruby files).

98.7% of compared issue reports matched (28.3M of 28.6M). 502 of 916 cops matched exactly; 408 differed; 1 had no corpus data.

rubocop1.84.2 (588 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
Layout100366436.0%
Lint148876158.7%
Style28710618136.9%
Metrics101910.0%
Naming1911857.8%
Security63350.0%
Bundler76185.7%
Gemspec108280.0%
Migration110✓ 100.0%
Total58825932944.0%

rubocop-rails2.34.3 (138 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
Rails1381112780.4%

rubocop-performance1.26.1 (52 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
Performance5249394.2%

rubocop-rspec3.9.0 (113 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
RSpec113654857.5%

rubocop-rspec_rails2.32.0 (8 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
RSpecRails87187.5%

rubocop-factory_bot2.28.0 (11 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
FactoryBot11110✓ 100.0%

"Matched exactly" means nitrocop produced no extra issues and missed no issues for that cop anywhere in the corpus. No corpus data means the cop never appeared in the corpus, so it has not been compared yet. See docs/corpus.md for the full corpus breakdown.

Every cop reads its RuboCop YAML config options and has fixture-based test coverage.

Hybrid Mode

Use --rubocop-only to run nitrocop alongside RuboCop for cops it doesn't cover yet:

#!/usr/bin/env bash# bin/lint — fast hybrid linter
nitrocop "$@"
REMAINING=$(nitrocop --rubocop-only)if [ -n"$REMAINING" ];then
bundle exec rubocop --only "$REMAINING""$@"fi

CLI

nitrocop [OPTIONS] [PATHS]...
Arguments:
[PATHS]... Files or directories to lint [default: .]
Options:
-a, --autocorrect Autocorrect offenses (safe cops only)
-A, --autocorrect-all Autocorrect offenses (all cops, including unsafe)
-c, --config <PATH> Path to .rubocop.yml
-f, --format <FORMAT> Output format: text, json [default: text]
--only <COPS> Run only specified cops (comma-separated)
--except <COPS> Skip specified cops (comma-separated)
--rubocop-only Print cops NOT covered by nitrocop
--stdin <PATH> Read source from stdin, use PATH for display
--debug Print timing and debug info
--list-cops List all registered cops
--ignore-disable-comments Ignore all # rubocop:disable inline comments
--cache <true|false> Enable/disable file-level result caching [default: true]
--cache-clear Clear the result cache and exit
--init Pre-resolve gem paths and write lockfile to cache directory, then exit
--fail-level <SEV> Minimum severity for non-zero exit (convention/warning/error/fatal)
-F, --fail-fast Stop after first file with offenses
--force-exclusion Apply AllCops.Exclude to explicitly-passed files
-L, --list-target-files Print files that would be linted, then exit
--force-default-config Ignore all config files, use built-in defaults
-h, --help Print help

nitrocop now auto-refreshes its gem lockfile when it is missing or stale (for example after bundle update). --init remains available as an optional prewarm command.

Local Development

cargo check # fast compile check
cargo test# run all tests (4,800+)
cargo run -- .# lint current directory# Quality checks (must pass — zero tolerance)
cargo test config_audit # all YAML config keys implemented
cargo test prism_pitfalls # no missing node type handling# Benchmarks
cargo run --release --bin bench_nitrocop # full: setup + bench + conform
cargo run --release --bin bench_nitrocop -- bench # timing only

How It Works

  1. Config resolution — Walks up from target to find .rubocop.yml, resolves inherit_from/inherit_gem chains, merges layers
  2. File discovery — Uses the ignore crate for .gitignore-aware traversal, applies AllCops.Exclude/Include patterns
  3. Parallel linting — Each rayon worker thread parses files with Prism (ParseResult is !Send), runs all enabled cops per file
  4. Cop execution — Three check phases per file: check_lines (raw text), check_source (bytes + CodeMap), check_node (AST walk via batched dispatch table)
  5. Output — RuboCop-compatible text format or JSON

Limitations

These cops are registered but cannot be exercised under current Ruby versions:

  • Lint/ItWithoutArgumentsInBlockit is a block parameter in Ruby 3.4+, making this cop obsolete
  • Lint/NonDeterministicRequireOrderDir results are sorted since Ruby 3.0
  • Lint/NumberedParameterAssignment — assigning to _1 is a syntax error in Ruby 3.4+
  • Lint/UselessElseWithoutRescue — syntax error in Ruby 3.4+
  • Security/YAMLLoadYAML.load is safe since Ruby 3.1 (cop has max Ruby 3.0)

These cops are excluded from corpus reporting counts.

About

Experimental RuboCop rewrite in Rust

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
GitHub - buildrtech/nitrocop: Experimental RuboCop rewrite in Rust · GitHub
Skip to content

Repository files navigation

NitroCop

Fast Ruby linter in Rust targeting RuboCop compatibility.

Note

🚧 Early-stage: Detection is high-fidelity on most codebases but edge cases remain. Autocorrect is not yet complete. Expect bugs.

Benchmark on the rubygems.org repo (1,226 files, Ruby 4.0), Apple Silicon:

ScenarionitrocopRuboCopSpeedup
Local dev (50 files changed)324ms1.14s3.5x
CI (no cache)318ms18.56s58.4x

Features

  • 916 cops from 6 RuboCop gems (rubocop, rubocop-rails, rubocop-performance, rubocop-rspec, rubocop-rspec_rails, rubocop-factory_bot)
  • 98.7% conformance against RuboCop across 5,590 open-source repos
  • Autocorrect (-a/-A) is partial — work in progress
  • Reads your existing .rubocop.yml — no migration needed
  • Uses Prism (Ruby's official parser) via ruby-prism crate
  • Parallel file processing with rayon

Quick Start (Work in progress 🚧)

Requires Rust 1.85+ (edition 2024).

cargo install nitrocop # not yet published — build from source for now

Then run it in your Ruby project:

nitrocop

Configuration

nitrocop reads .rubocop.yml with full support for:

  • inherit_from — local files, recursive
  • inherit_gem — resolves gem paths via bundle info
  • inherit_mode — merge/override for arrays
  • Department-level configRSpec:, Rails: Include/Exclude/Enabled
  • AllCopsNewCops, DisabledByDefault, Exclude, Include
  • Enabled: pending tri-state
  • Per-cop optionsEnforcedStyle, Max, AllowedMethods, AllowedPatterns, etc.

Config auto-discovery walks up from the target directory to find .rubocop.yml.

Cops

nitrocop supports 916 cops from 6 RuboCop gems.

Compared with RuboCop on 5,590 open-source repos (593k Ruby files).

98.7% of compared issue reports matched (28.3M of 28.6M). 502 of 916 cops matched exactly; 408 differed; 1 had no corpus data.

rubocop1.84.2 (588 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
Layout100366436.0%
Lint148876158.7%
Style28710618136.9%
Metrics101910.0%
Naming1911857.8%
Security63350.0%
Bundler76185.7%
Gemspec108280.0%
Migration110✓ 100.0%
Total58825932944.0%

rubocop-rails2.34.3 (138 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
Rails1381112780.4%

rubocop-performance1.26.1 (52 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
Performance5249394.2%

rubocop-rspec3.9.0 (113 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
RSpec113654857.5%

rubocop-rspec_rails2.32.0 (8 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
RSpecRails87187.5%

rubocop-factory_bot2.28.0 (11 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
FactoryBot11110✓ 100.0%

"Matched exactly" means nitrocop produced no extra issues and missed no issues for that cop anywhere in the corpus. No corpus data means the cop never appeared in the corpus, so it has not been compared yet. See docs/corpus.md for the full corpus breakdown.

Every cop reads its RuboCop YAML config options and has fixture-based test coverage.

Hybrid Mode

Use --rubocop-only to run nitrocop alongside RuboCop for cops it doesn't cover yet:

#!/usr/bin/env bash# bin/lint — fast hybrid linter
nitrocop "$@"
REMAINING=$(nitrocop --rubocop-only)if [ -n"$REMAINING" ];then
bundle exec rubocop --only "$REMAINING""$@"fi

CLI

nitrocop [OPTIONS] [PATHS]...
Arguments:
[PATHS]... Files or directories to lint [default: .]
Options:
-a, --autocorrect Autocorrect offenses (safe cops only)
-A, --autocorrect-all Autocorrect offenses (all cops, including unsafe)
-c, --config <PATH> Path to .rubocop.yml
-f, --format <FORMAT> Output format: text, json [default: text]
--only <COPS> Run only specified cops (comma-separated)
--except <COPS> Skip specified cops (comma-separated)
--rubocop-only Print cops NOT covered by nitrocop
--stdin <PATH> Read source from stdin, use PATH for display
--debug Print timing and debug info
--list-cops List all registered cops
--ignore-disable-comments Ignore all # rubocop:disable inline comments
--cache <true|false> Enable/disable file-level result caching [default: true]
--cache-clear Clear the result cache and exit
--init Pre-resolve gem paths and write lockfile to cache directory, then exit
--fail-level <SEV> Minimum severity for non-zero exit (convention/warning/error/fatal)
-F, --fail-fast Stop after first file with offenses
--force-exclusion Apply AllCops.Exclude to explicitly-passed files
-L, --list-target-files Print files that would be linted, then exit
--force-default-config Ignore all config files, use built-in defaults
-h, --help Print help

nitrocop now auto-refreshes its gem lockfile when it is missing or stale (for example after bundle update). --init remains available as an optional prewarm command.

Local Development

cargo check # fast compile check
cargo test# run all tests (4,800+)
cargo run -- .# lint current directory# Quality checks (must pass — zero tolerance)
cargo test config_audit # all YAML config keys implemented
cargo test prism_pitfalls # no missing node type handling# Benchmarks
cargo run --release --bin bench_nitrocop # full: setup + bench + conform
cargo run --release --bin bench_nitrocop -- bench # timing only

How It Works

  1. Config resolution — Walks up from target to find .rubocop.yml, resolves inherit_from/inherit_gem chains, merges layers
  2. File discovery — Uses the ignore crate for .gitignore-aware traversal, applies AllCops.Exclude/Include patterns
  3. Parallel linting — Each rayon worker thread parses files with Prism (ParseResult is !Send), runs all enabled cops per file
  4. Cop execution — Three check phases per file: check_lines (raw text), check_source (bytes + CodeMap), check_node (AST walk via batched dispatch table)
  5. Output — RuboCop-compatible text format or JSON

Limitations

These cops are registered but cannot be exercised under current Ruby versions:

  • Lint/ItWithoutArgumentsInBlockit is a block parameter in Ruby 3.4+, making this cop obsolete
  • Lint/NonDeterministicRequireOrderDir results are sorted since Ruby 3.0
  • Lint/NumberedParameterAssignment — assigning to _1 is a syntax error in Ruby 3.4+
  • Lint/UselessElseWithoutRescue — syntax error in Ruby 3.4+
  • Security/YAMLLoadYAML.load is safe since Ruby 3.1 (cop has max Ruby 3.0)

These cops are excluded from corpus reporting counts.

About

Experimental RuboCop rewrite in Rust

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - buildrtech/nitrocop: Experimental RuboCop rewrite in Rust · GitHub
Skip to content

Repository files navigation

NitroCop

Fast Ruby linter in Rust targeting RuboCop compatibility.

Note

🚧 Early-stage: Detection is high-fidelity on most codebases but edge cases remain. Autocorrect is not yet complete. Expect bugs.

Benchmark on the rubygems.org repo (1,226 files, Ruby 4.0), Apple Silicon:

ScenarionitrocopRuboCopSpeedup
Local dev (50 files changed)324ms1.14s3.5x
CI (no cache)318ms18.56s58.4x

Features

  • 916 cops from 6 RuboCop gems (rubocop, rubocop-rails, rubocop-performance, rubocop-rspec, rubocop-rspec_rails, rubocop-factory_bot)
  • 98.7% conformance against RuboCop across 5,590 open-source repos
  • Autocorrect (-a/-A) is partial — work in progress
  • Reads your existing .rubocop.yml — no migration needed
  • Uses Prism (Ruby's official parser) via ruby-prism crate
  • Parallel file processing with rayon

Quick Start (Work in progress 🚧)

Requires Rust 1.85+ (edition 2024).

cargo install nitrocop # not yet published — build from source for now

Then run it in your Ruby project:

nitrocop

Configuration

nitrocop reads .rubocop.yml with full support for:

  • inherit_from — local files, recursive
  • inherit_gem — resolves gem paths via bundle info
  • inherit_mode — merge/override for arrays
  • Department-level configRSpec:, Rails: Include/Exclude/Enabled
  • AllCopsNewCops, DisabledByDefault, Exclude, Include
  • Enabled: pending tri-state
  • Per-cop optionsEnforcedStyle, Max, AllowedMethods, AllowedPatterns, etc.

Config auto-discovery walks up from the target directory to find .rubocop.yml.

Cops

nitrocop supports 916 cops from 6 RuboCop gems.

Compared with RuboCop on 5,590 open-source repos (593k Ruby files).

98.7% of compared issue reports matched (28.3M of 28.6M). 502 of 916 cops matched exactly; 408 differed; 1 had no corpus data.

rubocop1.84.2 (588 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
Layout100366436.0%
Lint148876158.7%
Style28710618136.9%
Metrics101910.0%
Naming1911857.8%
Security63350.0%
Bundler76185.7%
Gemspec108280.0%
Migration110✓ 100.0%
Total58825932944.0%

rubocop-rails2.34.3 (138 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
Rails1381112780.4%

rubocop-performance1.26.1 (52 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
Performance5249394.2%

rubocop-rspec3.9.0 (113 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
RSpec113654857.5%

rubocop-rspec_rails2.32.0 (8 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
RSpecRails87187.5%

rubocop-factory_bot2.28.0 (11 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
FactoryBot11110✓ 100.0%

"Matched exactly" means nitrocop produced no extra issues and missed no issues for that cop anywhere in the corpus. No corpus data means the cop never appeared in the corpus, so it has not been compared yet. See docs/corpus.md for the full corpus breakdown.

Every cop reads its RuboCop YAML config options and has fixture-based test coverage.

Hybrid Mode

Use --rubocop-only to run nitrocop alongside RuboCop for cops it doesn't cover yet:

#!/usr/bin/env bash# bin/lint — fast hybrid linter
nitrocop "$@"
REMAINING=$(nitrocop --rubocop-only)if [ -n"$REMAINING" ];then
bundle exec rubocop --only "$REMAINING""$@"fi

CLI

nitrocop [OPTIONS] [PATHS]...
Arguments:
[PATHS]... Files or directories to lint [default: .]
Options:
-a, --autocorrect Autocorrect offenses (safe cops only)
-A, --autocorrect-all Autocorrect offenses (all cops, including unsafe)
-c, --config <PATH> Path to .rubocop.yml
-f, --format <FORMAT> Output format: text, json [default: text]
--only <COPS> Run only specified cops (comma-separated)
--except <COPS> Skip specified cops (comma-separated)
--rubocop-only Print cops NOT covered by nitrocop
--stdin <PATH> Read source from stdin, use PATH for display
--debug Print timing and debug info
--list-cops List all registered cops
--ignore-disable-comments Ignore all # rubocop:disable inline comments
--cache <true|false> Enable/disable file-level result caching [default: true]
--cache-clear Clear the result cache and exit
--init Pre-resolve gem paths and write lockfile to cache directory, then exit
--fail-level <SEV> Minimum severity for non-zero exit (convention/warning/error/fatal)
-F, --fail-fast Stop after first file with offenses
--force-exclusion Apply AllCops.Exclude to explicitly-passed files
-L, --list-target-files Print files that would be linted, then exit
--force-default-config Ignore all config files, use built-in defaults
-h, --help Print help

nitrocop now auto-refreshes its gem lockfile when it is missing or stale (for example after bundle update). --init remains available as an optional prewarm command.

Local Development

cargo check # fast compile check
cargo test# run all tests (4,800+)
cargo run -- .# lint current directory# Quality checks (must pass — zero tolerance)
cargo test config_audit # all YAML config keys implemented
cargo test prism_pitfalls # no missing node type handling# Benchmarks
cargo run --release --bin bench_nitrocop # full: setup + bench + conform
cargo run --release --bin bench_nitrocop -- bench # timing only

How It Works

  1. Config resolution — Walks up from target to find .rubocop.yml, resolves inherit_from/inherit_gem chains, merges layers
  2. File discovery — Uses the ignore crate for .gitignore-aware traversal, applies AllCops.Exclude/Include patterns
  3. Parallel linting — Each rayon worker thread parses files with Prism (ParseResult is !Send), runs all enabled cops per file
  4. Cop execution — Three check phases per file: check_lines (raw text), check_source (bytes + CodeMap), check_node (AST walk via batched dispatch table)
  5. Output — RuboCop-compatible text format or JSON

Limitations

These cops are registered but cannot be exercised under current Ruby versions:

  • Lint/ItWithoutArgumentsInBlockit is a block parameter in Ruby 3.4+, making this cop obsolete
  • Lint/NonDeterministicRequireOrderDir results are sorted since Ruby 3.0
  • Lint/NumberedParameterAssignment — assigning to _1 is a syntax error in Ruby 3.4+
  • Lint/UselessElseWithoutRescue — syntax error in Ruby 3.4+
  • Security/YAMLLoadYAML.load is safe since Ruby 3.1 (cop has max Ruby 3.0)

These cops are excluded from corpus reporting counts.

About

Experimental RuboCop rewrite in Rust

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - buildrtech/nitrocop: Experimental RuboCop rewrite in Rust · GitHub
Skip to content

Repository files navigation

NitroCop

Fast Ruby linter in Rust targeting RuboCop compatibility.

Note

🚧 Early-stage: Detection is high-fidelity on most codebases but edge cases remain. Autocorrect is not yet complete. Expect bugs.

Benchmark on the rubygems.org repo (1,226 files, Ruby 4.0), Apple Silicon:

ScenarionitrocopRuboCopSpeedup
Local dev (50 files changed)324ms1.14s3.5x
CI (no cache)318ms18.56s58.4x

Features

  • 916 cops from 6 RuboCop gems (rubocop, rubocop-rails, rubocop-performance, rubocop-rspec, rubocop-rspec_rails, rubocop-factory_bot)
  • 98.7% conformance against RuboCop across 5,590 open-source repos
  • Autocorrect (-a/-A) is partial — work in progress
  • Reads your existing .rubocop.yml — no migration needed
  • Uses Prism (Ruby's official parser) via ruby-prism crate
  • Parallel file processing with rayon

Quick Start (Work in progress 🚧)

Requires Rust 1.85+ (edition 2024).

cargo install nitrocop # not yet published — build from source for now

Then run it in your Ruby project:

nitrocop

Configuration

nitrocop reads .rubocop.yml with full support for:

  • inherit_from — local files, recursive
  • inherit_gem — resolves gem paths via bundle info
  • inherit_mode — merge/override for arrays
  • Department-level configRSpec:, Rails: Include/Exclude/Enabled
  • AllCopsNewCops, DisabledByDefault, Exclude, Include
  • Enabled: pending tri-state
  • Per-cop optionsEnforcedStyle, Max, AllowedMethods, AllowedPatterns, etc.

Config auto-discovery walks up from the target directory to find .rubocop.yml.

Cops

nitrocop supports 916 cops from 6 RuboCop gems.

Compared with RuboCop on 5,590 open-source repos (593k Ruby files).

98.7% of compared issue reports matched (28.3M of 28.6M). 502 of 916 cops matched exactly; 408 differed; 1 had no corpus data.

rubocop1.84.2 (588 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
Layout100366436.0%
Lint148876158.7%
Style28710618136.9%
Metrics101910.0%
Naming1911857.8%
Security63350.0%
Bundler76185.7%
Gemspec108280.0%
Migration110✓ 100.0%
Total58825932944.0%

rubocop-rails2.34.3 (138 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
Rails1381112780.4%

rubocop-performance1.26.1 (52 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
Performance5249394.2%

rubocop-rspec3.9.0 (113 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
RSpec113654857.5%

rubocop-rspec_rails2.32.0 (8 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
RSpecRails87187.5%

rubocop-factory_bot2.28.0 (11 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
FactoryBot11110✓ 100.0%

"Matched exactly" means nitrocop produced no extra issues and missed no issues for that cop anywhere in the corpus. No corpus data means the cop never appeared in the corpus, so it has not been compared yet. See docs/corpus.md for the full corpus breakdown.

Every cop reads its RuboCop YAML config options and has fixture-based test coverage.

Hybrid Mode

Use --rubocop-only to run nitrocop alongside RuboCop for cops it doesn't cover yet:

#!/usr/bin/env bash# bin/lint — fast hybrid linter
nitrocop "$@"
REMAINING=$(nitrocop --rubocop-only)if [ -n"$REMAINING" ];then
bundle exec rubocop --only "$REMAINING""$@"fi

CLI

nitrocop [OPTIONS] [PATHS]...
Arguments:
[PATHS]... Files or directories to lint [default: .]
Options:
-a, --autocorrect Autocorrect offenses (safe cops only)
-A, --autocorrect-all Autocorrect offenses (all cops, including unsafe)
-c, --config <PATH> Path to .rubocop.yml
-f, --format <FORMAT> Output format: text, json [default: text]
--only <COPS> Run only specified cops (comma-separated)
--except <COPS> Skip specified cops (comma-separated)
--rubocop-only Print cops NOT covered by nitrocop
--stdin <PATH> Read source from stdin, use PATH for display
--debug Print timing and debug info
--list-cops List all registered cops
--ignore-disable-comments Ignore all # rubocop:disable inline comments
--cache <true|false> Enable/disable file-level result caching [default: true]
--cache-clear Clear the result cache and exit
--init Pre-resolve gem paths and write lockfile to cache directory, then exit
--fail-level <SEV> Minimum severity for non-zero exit (convention/warning/error/fatal)
-F, --fail-fast Stop after first file with offenses
--force-exclusion Apply AllCops.Exclude to explicitly-passed files
-L, --list-target-files Print files that would be linted, then exit
--force-default-config Ignore all config files, use built-in defaults
-h, --help Print help

nitrocop now auto-refreshes its gem lockfile when it is missing or stale (for example after bundle update). --init remains available as an optional prewarm command.

Local Development

cargo check # fast compile check
cargo test# run all tests (4,800+)
cargo run -- .# lint current directory# Quality checks (must pass — zero tolerance)
cargo test config_audit # all YAML config keys implemented
cargo test prism_pitfalls # no missing node type handling# Benchmarks
cargo run --release --bin bench_nitrocop # full: setup + bench + conform
cargo run --release --bin bench_nitrocop -- bench # timing only

How It Works

  1. Config resolution — Walks up from target to find .rubocop.yml, resolves inherit_from/inherit_gem chains, merges layers
  2. File discovery — Uses the ignore crate for .gitignore-aware traversal, applies AllCops.Exclude/Include patterns
  3. Parallel linting — Each rayon worker thread parses files with Prism (ParseResult is !Send), runs all enabled cops per file
  4. Cop execution — Three check phases per file: check_lines (raw text), check_source (bytes + CodeMap), check_node (AST walk via batched dispatch table)
  5. Output — RuboCop-compatible text format or JSON

Limitations

These cops are registered but cannot be exercised under current Ruby versions:

  • Lint/ItWithoutArgumentsInBlockit is a block parameter in Ruby 3.4+, making this cop obsolete
  • Lint/NonDeterministicRequireOrderDir results are sorted since Ruby 3.0
  • Lint/NumberedParameterAssignment — assigning to _1 is a syntax error in Ruby 3.4+
  • Lint/UselessElseWithoutRescue — syntax error in Ruby 3.4+
  • Security/YAMLLoadYAML.load is safe since Ruby 3.1 (cop has max Ruby 3.0)

These cops are excluded from corpus reporting counts.

About

Experimental RuboCop rewrite in Rust

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' GitHub - buildrtech/nitrocop: Experimental RuboCop rewrite in Rust · GitHub
Skip to content

Repository files navigation

NitroCop

Fast Ruby linter in Rust targeting RuboCop compatibility.

Note

🚧 Early-stage: Detection is high-fidelity on most codebases but edge cases remain. Autocorrect is not yet complete. Expect bugs.

Benchmark on the rubygems.org repo (1,226 files, Ruby 4.0), Apple Silicon:

ScenarionitrocopRuboCopSpeedup
Local dev (50 files changed)324ms1.14s3.5x
CI (no cache)318ms18.56s58.4x

Features

  • 916 cops from 6 RuboCop gems (rubocop, rubocop-rails, rubocop-performance, rubocop-rspec, rubocop-rspec_rails, rubocop-factory_bot)
  • 98.7% conformance against RuboCop across 5,590 open-source repos
  • Autocorrect (-a/-A) is partial — work in progress
  • Reads your existing .rubocop.yml — no migration needed
  • Uses Prism (Ruby's official parser) via ruby-prism crate
  • Parallel file processing with rayon

Quick Start (Work in progress 🚧)

Requires Rust 1.85+ (edition 2024).

cargo install nitrocop # not yet published — build from source for now

Then run it in your Ruby project:

nitrocop

Configuration

nitrocop reads .rubocop.yml with full support for:

  • inherit_from — local files, recursive
  • inherit_gem — resolves gem paths via bundle info
  • inherit_mode — merge/override for arrays
  • Department-level configRSpec:, Rails: Include/Exclude/Enabled
  • AllCopsNewCops, DisabledByDefault, Exclude, Include
  • Enabled: pending tri-state
  • Per-cop optionsEnforcedStyle, Max, AllowedMethods, AllowedPatterns, etc.

Config auto-discovery walks up from the target directory to find .rubocop.yml.

Cops

nitrocop supports 916 cops from 6 RuboCop gems.

Compared with RuboCop on 5,590 open-source repos (593k Ruby files).

98.7% of compared issue reports matched (28.3M of 28.6M). 502 of 916 cops matched exactly; 408 differed; 1 had no corpus data.

rubocop1.84.2 (588 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
Layout100366436.0%
Lint148876158.7%
Style28710618136.9%
Metrics101910.0%
Naming1911857.8%
Security63350.0%
Bundler76185.7%
Gemspec108280.0%
Migration110✓ 100.0%
Total58825932944.0%

rubocop-rails2.34.3 (138 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
Rails1381112780.4%

rubocop-performance1.26.1 (52 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
Performance5249394.2%

rubocop-rspec3.9.0 (113 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
RSpec113654857.5%

rubocop-rspec_rails2.32.0 (8 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
RSpecRails87187.5%

rubocop-factory_bot2.28.0 (11 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
FactoryBot11110✓ 100.0%

"Matched exactly" means nitrocop produced no extra issues and missed no issues for that cop anywhere in the corpus. No corpus data means the cop never appeared in the corpus, so it has not been compared yet. See docs/corpus.md for the full corpus breakdown.

Every cop reads its RuboCop YAML config options and has fixture-based test coverage.

Hybrid Mode

Use --rubocop-only to run nitrocop alongside RuboCop for cops it doesn't cover yet:

#!/usr/bin/env bash# bin/lint — fast hybrid linter
nitrocop "$@"
REMAINING=$(nitrocop --rubocop-only)if [ -n"$REMAINING" ];then
bundle exec rubocop --only "$REMAINING""$@"fi

CLI

nitrocop [OPTIONS] [PATHS]...
Arguments:
[PATHS]... Files or directories to lint [default: .]
Options:
-a, --autocorrect Autocorrect offenses (safe cops only)
-A, --autocorrect-all Autocorrect offenses (all cops, including unsafe)
-c, --config <PATH> Path to .rubocop.yml
-f, --format <FORMAT> Output format: text, json [default: text]
--only <COPS> Run only specified cops (comma-separated)
--except <COPS> Skip specified cops (comma-separated)
--rubocop-only Print cops NOT covered by nitrocop
--stdin <PATH> Read source from stdin, use PATH for display
--debug Print timing and debug info
--list-cops List all registered cops
--ignore-disable-comments Ignore all # rubocop:disable inline comments
--cache <true|false> Enable/disable file-level result caching [default: true]
--cache-clear Clear the result cache and exit
--init Pre-resolve gem paths and write lockfile to cache directory, then exit
--fail-level <SEV> Minimum severity for non-zero exit (convention/warning/error/fatal)
-F, --fail-fast Stop after first file with offenses
--force-exclusion Apply AllCops.Exclude to explicitly-passed files
-L, --list-target-files Print files that would be linted, then exit
--force-default-config Ignore all config files, use built-in defaults
-h, --help Print help

nitrocop now auto-refreshes its gem lockfile when it is missing or stale (for example after bundle update). --init remains available as an optional prewarm command.

Local Development

cargo check # fast compile check
cargo test# run all tests (4,800+)
cargo run -- .# lint current directory# Quality checks (must pass — zero tolerance)
cargo test config_audit # all YAML config keys implemented
cargo test prism_pitfalls # no missing node type handling# Benchmarks
cargo run --release --bin bench_nitrocop # full: setup + bench + conform
cargo run --release --bin bench_nitrocop -- bench # timing only

How It Works

  1. Config resolution — Walks up from target to find .rubocop.yml, resolves inherit_from/inherit_gem chains, merges layers
  2. File discovery — Uses the ignore crate for .gitignore-aware traversal, applies AllCops.Exclude/Include patterns
  3. Parallel linting — Each rayon worker thread parses files with Prism (ParseResult is !Send), runs all enabled cops per file
  4. Cop execution — Three check phases per file: check_lines (raw text), check_source (bytes + CodeMap), check_node (AST walk via batched dispatch table)
  5. Output — RuboCop-compatible text format or JSON

Limitations

These cops are registered but cannot be exercised under current Ruby versions:

  • Lint/ItWithoutArgumentsInBlockit is a block parameter in Ruby 3.4+, making this cop obsolete
  • Lint/NonDeterministicRequireOrderDir results are sorted since Ruby 3.0
  • Lint/NumberedParameterAssignment — assigning to _1 is a syntax error in Ruby 3.4+
  • Lint/UselessElseWithoutRescue — syntax error in Ruby 3.4+
  • Security/YAMLLoadYAML.load is safe since Ruby 3.1 (cop has max Ruby 3.0)

These cops are excluded from corpus reporting counts.

About

Experimental RuboCop rewrite in Rust

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - buildrtech/nitrocop: Experimental RuboCop rewrite in Rust · GitHub
Skip to content

Repository files navigation

NitroCop

Fast Ruby linter in Rust targeting RuboCop compatibility.

Note

🚧 Early-stage: Detection is high-fidelity on most codebases but edge cases remain. Autocorrect is not yet complete. Expect bugs.

Benchmark on the rubygems.org repo (1,226 files, Ruby 4.0), Apple Silicon:

ScenarionitrocopRuboCopSpeedup
Local dev (50 files changed)324ms1.14s3.5x
CI (no cache)318ms18.56s58.4x

Features

  • 916 cops from 6 RuboCop gems (rubocop, rubocop-rails, rubocop-performance, rubocop-rspec, rubocop-rspec_rails, rubocop-factory_bot)
  • 98.7% conformance against RuboCop across 5,590 open-source repos
  • Autocorrect (-a/-A) is partial — work in progress
  • Reads your existing .rubocop.yml — no migration needed
  • Uses Prism (Ruby's official parser) via ruby-prism crate
  • Parallel file processing with rayon

Quick Start (Work in progress 🚧)

Requires Rust 1.85+ (edition 2024).

cargo install nitrocop # not yet published — build from source for now

Then run it in your Ruby project:

nitrocop

Configuration

nitrocop reads .rubocop.yml with full support for:

  • inherit_from — local files, recursive
  • inherit_gem — resolves gem paths via bundle info
  • inherit_mode — merge/override for arrays
  • Department-level configRSpec:, Rails: Include/Exclude/Enabled
  • AllCopsNewCops, DisabledByDefault, Exclude, Include
  • Enabled: pending tri-state
  • Per-cop optionsEnforcedStyle, Max, AllowedMethods, AllowedPatterns, etc.

Config auto-discovery walks up from the target directory to find .rubocop.yml.

Cops

nitrocop supports 916 cops from 6 RuboCop gems.

Compared with RuboCop on 5,590 open-source repos (593k Ruby files).

98.7% of compared issue reports matched (28.3M of 28.6M). 502 of 916 cops matched exactly; 408 differed; 1 had no corpus data.

rubocop1.84.2 (588 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
Layout100366436.0%
Lint148876158.7%
Style28710618136.9%
Metrics101910.0%
Naming1911857.8%
Security63350.0%
Bundler76185.7%
Gemspec108280.0%
Migration110✓ 100.0%
Total58825932944.0%

rubocop-rails2.34.3 (138 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
Rails1381112780.4%

rubocop-performance1.26.1 (52 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
Performance5249394.2%

rubocop-rspec3.9.0 (113 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
RSpec113654857.5%

rubocop-rspec_rails2.32.0 (8 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
RSpecRails87187.5%

rubocop-factory_bot2.28.0 (11 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
FactoryBot11110✓ 100.0%

"Matched exactly" means nitrocop produced no extra issues and missed no issues for that cop anywhere in the corpus. No corpus data means the cop never appeared in the corpus, so it has not been compared yet. See docs/corpus.md for the full corpus breakdown.

Every cop reads its RuboCop YAML config options and has fixture-based test coverage.

Hybrid Mode

Use --rubocop-only to run nitrocop alongside RuboCop for cops it doesn't cover yet:

#!/usr/bin/env bash# bin/lint — fast hybrid linter
nitrocop "$@"
REMAINING=$(nitrocop --rubocop-only)if [ -n"$REMAINING" ];then
bundle exec rubocop --only "$REMAINING""$@"fi

CLI

nitrocop [OPTIONS] [PATHS]...
Arguments:
[PATHS]... Files or directories to lint [default: .]
Options:
-a, --autocorrect Autocorrect offenses (safe cops only)
-A, --autocorrect-all Autocorrect offenses (all cops, including unsafe)
-c, --config <PATH> Path to .rubocop.yml
-f, --format <FORMAT> Output format: text, json [default: text]
--only <COPS> Run only specified cops (comma-separated)
--except <COPS> Skip specified cops (comma-separated)
--rubocop-only Print cops NOT covered by nitrocop
--stdin <PATH> Read source from stdin, use PATH for display
--debug Print timing and debug info
--list-cops List all registered cops
--ignore-disable-comments Ignore all # rubocop:disable inline comments
--cache <true|false> Enable/disable file-level result caching [default: true]
--cache-clear Clear the result cache and exit
--init Pre-resolve gem paths and write lockfile to cache directory, then exit
--fail-level <SEV> Minimum severity for non-zero exit (convention/warning/error/fatal)
-F, --fail-fast Stop after first file with offenses
--force-exclusion Apply AllCops.Exclude to explicitly-passed files
-L, --list-target-files Print files that would be linted, then exit
--force-default-config Ignore all config files, use built-in defaults
-h, --help Print help

nitrocop now auto-refreshes its gem lockfile when it is missing or stale (for example after bundle update). --init remains available as an optional prewarm command.

Local Development

cargo check # fast compile check
cargo test# run all tests (4,800+)
cargo run -- .# lint current directory# Quality checks (must pass — zero tolerance)
cargo test config_audit # all YAML config keys implemented
cargo test prism_pitfalls # no missing node type handling# Benchmarks
cargo run --release --bin bench_nitrocop # full: setup + bench + conform
cargo run --release --bin bench_nitrocop -- bench # timing only

How It Works

  1. Config resolution — Walks up from target to find .rubocop.yml, resolves inherit_from/inherit_gem chains, merges layers
  2. File discovery — Uses the ignore crate for .gitignore-aware traversal, applies AllCops.Exclude/Include patterns
  3. Parallel linting — Each rayon worker thread parses files with Prism (ParseResult is !Send), runs all enabled cops per file
  4. Cop execution — Three check phases per file: check_lines (raw text), check_source (bytes + CodeMap), check_node (AST walk via batched dispatch table)
  5. Output — RuboCop-compatible text format or JSON

Limitations

These cops are registered but cannot be exercised under current Ruby versions:

  • Lint/ItWithoutArgumentsInBlockit is a block parameter in Ruby 3.4+, making this cop obsolete
  • Lint/NonDeterministicRequireOrderDir results are sorted since Ruby 3.0
  • Lint/NumberedParameterAssignment — assigning to _1 is a syntax error in Ruby 3.4+
  • Lint/UselessElseWithoutRescue — syntax error in Ruby 3.4+
  • Security/YAMLLoadYAML.load is safe since Ruby 3.1 (cop has max Ruby 3.0)

These cops are excluded from corpus reporting counts.

About

Experimental RuboCop rewrite in Rust

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); GitHub - buildrtech/nitrocop: Experimental RuboCop rewrite in Rust · GitHub
Skip to content

Repository files navigation

NitroCop

Fast Ruby linter in Rust targeting RuboCop compatibility.

Note

🚧 Early-stage: Detection is high-fidelity on most codebases but edge cases remain. Autocorrect is not yet complete. Expect bugs.

Benchmark on the rubygems.org repo (1,226 files, Ruby 4.0), Apple Silicon:

ScenarionitrocopRuboCopSpeedup
Local dev (50 files changed)324ms1.14s3.5x
CI (no cache)318ms18.56s58.4x

Features

  • 916 cops from 6 RuboCop gems (rubocop, rubocop-rails, rubocop-performance, rubocop-rspec, rubocop-rspec_rails, rubocop-factory_bot)
  • 98.7% conformance against RuboCop across 5,590 open-source repos
  • Autocorrect (-a/-A) is partial — work in progress
  • Reads your existing .rubocop.yml — no migration needed
  • Uses Prism (Ruby's official parser) via ruby-prism crate
  • Parallel file processing with rayon

Quick Start (Work in progress 🚧)

Requires Rust 1.85+ (edition 2024).

cargo install nitrocop # not yet published — build from source for now

Then run it in your Ruby project:

nitrocop

Configuration

nitrocop reads .rubocop.yml with full support for:

  • inherit_from — local files, recursive
  • inherit_gem — resolves gem paths via bundle info
  • inherit_mode — merge/override for arrays
  • Department-level configRSpec:, Rails: Include/Exclude/Enabled
  • AllCopsNewCops, DisabledByDefault, Exclude, Include
  • Enabled: pending tri-state
  • Per-cop optionsEnforcedStyle, Max, AllowedMethods, AllowedPatterns, etc.

Config auto-discovery walks up from the target directory to find .rubocop.yml.

Cops

nitrocop supports 916 cops from 6 RuboCop gems.

Compared with RuboCop on 5,590 open-source repos (593k Ruby files).

98.7% of compared issue reports matched (28.3M of 28.6M). 502 of 916 cops matched exactly; 408 differed; 1 had no corpus data.

rubocop1.84.2 (588 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
Layout100366436.0%
Lint148876158.7%
Style28710618136.9%
Metrics101910.0%
Naming1911857.8%
Security63350.0%
Bundler76185.7%
Gemspec108280.0%
Migration110✓ 100.0%
Total58825932944.0%

rubocop-rails2.34.3 (138 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
Rails1381112780.4%

rubocop-performance1.26.1 (52 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
Performance5249394.2%

rubocop-rspec3.9.0 (113 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
RSpec113654857.5%

rubocop-rspec_rails2.32.0 (8 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
RSpecRails87187.5%

rubocop-factory_bot2.28.0 (11 cops)

DepartmentCopsMatched exactlyDifferedMatched exactly %
FactoryBot11110✓ 100.0%

"Matched exactly" means nitrocop produced no extra issues and missed no issues for that cop anywhere in the corpus. No corpus data means the cop never appeared in the corpus, so it has not been compared yet. See docs/corpus.md for the full corpus breakdown.

Every cop reads its RuboCop YAML config options and has fixture-based test coverage.

Hybrid Mode

Use --rubocop-only to run nitrocop alongside RuboCop for cops it doesn't cover yet:

#!/usr/bin/env bash# bin/lint — fast hybrid linter
nitrocop "$@"
REMAINING=$(nitrocop --rubocop-only)if [ -n"$REMAINING" ];then
bundle exec rubocop --only "$REMAINING""$@"fi

CLI

nitrocop [OPTIONS] [PATHS]...
Arguments:
[PATHS]... Files or directories to lint [default: .]
Options:
-a, --autocorrect Autocorrect offenses (safe cops only)
-A, --autocorrect-all Autocorrect offenses (all cops, including unsafe)
-c, --config <PATH> Path to .rubocop.yml
-f, --format <FORMAT> Output format: text, json [default: text]
--only <COPS> Run only specified cops (comma-separated)
--except <COPS> Skip specified cops (comma-separated)
--rubocop-only Print cops NOT covered by nitrocop
--stdin <PATH> Read source from stdin, use PATH for display
--debug Print timing and debug info
--list-cops List all registered cops
--ignore-disable-comments Ignore all # rubocop:disable inline comments
--cache <true|false> Enable/disable file-level result caching [default: true]
--cache-clear Clear the result cache and exit
--init Pre-resolve gem paths and write lockfile to cache directory, then exit
--fail-level <SEV> Minimum severity for non-zero exit (convention/warning/error/fatal)
-F, --fail-fast Stop after first file with offenses
--force-exclusion Apply AllCops.Exclude to explicitly-passed files
-L, --list-target-files Print files that would be linted, then exit
--force-default-config Ignore all config files, use built-in defaults
-h, --help Print help

nitrocop now auto-refreshes its gem lockfile when it is missing or stale (for example after bundle update). --init remains available as an optional prewarm command.

Local Development

cargo check # fast compile check
cargo test# run all tests (4,800+)
cargo run -- .# lint current directory# Quality checks (must pass — zero tolerance)
cargo test config_audit # all YAML config keys implemented
cargo test prism_pitfalls # no missing node type handling# Benchmarks
cargo run --release --bin bench_nitrocop # full: setup + bench + conform
cargo run --release --bin bench_nitrocop -- bench # timing only

How It Works

  1. Config resolution — Walks up from target to find .rubocop.yml, resolves inherit_from/inherit_gem chains, merges layers
  2. File discovery — Uses the ignore crate for .gitignore-aware traversal, applies AllCops.Exclude/Include patterns
  3. Parallel linting — Each rayon worker thread parses files with Prism (ParseResult is !Send), runs all enabled cops per file
  4. Cop execution — Three check phases per file: check_lines (raw text), check_source (bytes + CodeMap), check_node (AST walk via batched dispatch table)
  5. Output — RuboCop-compatible text format or JSON

Limitations

These cops are registered but cannot be exercised under current Ruby versions:

  • Lint/ItWithoutArgumentsInBlockit is a block parameter in Ruby 3.4+, making this cop obsolete
  • Lint/NonDeterministicRequireOrderDir results are sorted since Ruby 3.0
  • Lint/NumberedParameterAssignment — assigning to _1 is a syntax error in Ruby 3.4+
  • Lint/UselessElseWithoutRescue — syntax error in Ruby 3.4+
  • Security/YAMLLoadYAML.load is safe since Ruby 3.1 (cop has max Ruby 3.0)

These cops are excluded from corpus reporting counts.

About

Experimental RuboCop rewrite in Rust

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages