sonicop 26.8.101-aarch64-linux
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 +7 -0
- data/CONFORMANCE.md +109 -0
- data/LICENSE +21 -0
- data/NOTICE +7 -0
- data/README.ja.md +161 -0
- data/README.md +173 -0
- data/config/default.yml +6305 -0
- data/exe/sonicop +7 -0
- data/lib/sonicop/runner.rb +67 -0
- data/lib/sonicop/version.rb +6 -0
- data/lib/sonicop.rb +8 -0
- data/libexec/sonicop +0 -0
- data/licenses/RUBOCOP.txt +20 -0
- data/licenses/TREE_SITTER_RUBY.txt +21 -0
- metadata +59 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: b1298b2be973ee50f74c784c1d35d4f0b6a7fdb015bd8ac9d8677d07fb88ba0c
|
|
4
|
+
data.tar.gz: 3baadbdd3a5d6f10099820bc6b4d0cd890080b119b634b3c8dda391edb509e6d
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 39960db7a2d0ef1d1f30e0687a5a0f0a1c58333f1ed2516339b866c43beb5b62c82928e3fd47fcdd971648bcef5dbe00c248a4003ff5bb0114f504b6c3bbdf55
|
|
7
|
+
data.tar.gz: 3cdd38531491001e03abb895f4af8600999c9f267031c59d21a7b113c762adfd2ff5c997377dc16579898dc0b51dc0684f418a1f8c1fd01dc8099b66aaf705e0
|
data/CONFORMANCE.md
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# RuboCop conformance
|
|
2
|
+
|
|
3
|
+
Snapshot date: 2026-08-10
|
|
4
|
+
Reference: RuboCop 1.89.0
|
|
5
|
+
Corpus: the complete 1,759-file RuboCop source tree
|
|
6
|
+
Configuration: RuboCop 1.89.0 built-in defaults (`--force-default-config`)
|
|
7
|
+
|
|
8
|
+
The bundled `config/default.yml` records the upstream version it was vendored from in its header.
|
|
9
|
+
Re-fetch it with `scripts/sync_default_yml.sh <rubocop-version>`.
|
|
10
|
+
|
|
11
|
+
The comparison covers every cop Sonicop implemented at the snapshot date, listed verbatim in the
|
|
12
|
+
`cops` variable of the command below. Each JSON offense is normalized by path, cop, line, column,
|
|
13
|
+
length, severity, correctability, and message. Run `sonicop --show-cops` for the current set.
|
|
14
|
+
|
|
15
|
+
| Result | Count |
|
|
16
|
+
|---|---:|
|
|
17
|
+
| Reference offense locations | 4,052 |
|
|
18
|
+
| Sonicop offense locations | 4,052 |
|
|
19
|
+
| Matching locations | 4,052 |
|
|
20
|
+
| False positives | **0** |
|
|
21
|
+
| False negatives | **0** |
|
|
22
|
+
| Location recall | **100%** |
|
|
23
|
+
| Message/severity/correctability differences at matching locations | **0** |
|
|
24
|
+
|
|
25
|
+
All offenses from the implemented cops match RuboCop by location, message, severity, and
|
|
26
|
+
correctability. This includes RuboCop's source-line indexing for metric cops, line-length
|
|
27
|
+
correctability and exemptions, directive lexing around heredocs, and target-version syntax errors.
|
|
28
|
+
|
|
29
|
+
Run the harness against a local RuboCop and corpus. It defaults to `rubocop` on `PATH`
|
|
30
|
+
(`gem install rubocop`) as the reference and `./target/release/sonicop` (`make release`) as the
|
|
31
|
+
candidate, so both only need `--reference` / `--candidate` when they live elsewhere — for example
|
|
32
|
+
`--reference "bundle exec rubocop"` inside a bundled project:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
cops="Layout/EmptyLineAfterMagicComment,Layout/EndOfLine,Layout/LineLength,Layout/SpaceAfterComma,Layout/SpaceAroundOperators,Layout/SpaceInsideParens,Layout/TrailingEmptyLines,Layout/TrailingWhitespace,Lint/DuplicateMethods,Lint/Syntax,Lint/UnusedBlockArgument,Lint/UselessAssignment,Metrics/BlockLength,Metrics/ClassLength,Metrics/MethodLength,Metrics/ModuleLength,Metrics/ParameterLists,Naming/AsciiIdentifiers,Naming/ConstantName,Naming/MethodName,Naming/VariableName,Security/Eval,Style/FrozenStringLiteralComment,Style/HashSyntax,Style/NumericLiterals,Style/RedundantReturn,Style/Semicolon,Style/StringLiterals"
|
|
36
|
+
|
|
37
|
+
scripts/conformance_diff.sh \
|
|
38
|
+
--force-default-config \
|
|
39
|
+
--cop "${cops}" \
|
|
40
|
+
-- /path/to/rubocop
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
`Lint/Syntax` is also run independently over the corpus. The latest owayo tree-sitter grammar
|
|
44
|
+
accepts the modern syntax in all 1,759 files, while Sonicop resolves Ruby 2.6 from the corpus
|
|
45
|
+
gemspec and applies a post-parse syntax feature gate. Its four fatal offenses, including the legacy
|
|
46
|
+
parser recovery diagnostics, exactly match RuboCop.
|
|
47
|
+
|
|
48
|
+
## Limits of this measurement
|
|
49
|
+
|
|
50
|
+
The 100% above is a property of *this corpus*, not a general accuracy claim. RuboCop's own source
|
|
51
|
+
tree is RuboCop-clean and stylistically uniform, so entire classes of input never occur in it and
|
|
52
|
+
the comparison cannot exercise them. A cop that is never triggered contributes nothing to the
|
|
53
|
+
match count, and its absence is indistinguishable from agreement.
|
|
54
|
+
|
|
55
|
+
Two implemented cops are confirmed to produce **zero offenses on both sides** over this corpus, so
|
|
56
|
+
this run says nothing about them:
|
|
57
|
+
|
|
58
|
+
| Cop | Offenses in this corpus | Verified elsewhere |
|
|
59
|
+
|---|---:|---|
|
|
60
|
+
| `Layout/TrailingEmptyLines` | 0 | Diverges on line, column, length, and message for a file ending in a blank line |
|
|
61
|
+
| `Naming/AsciiIdentifiers` | 0 | Rails contains exactly two occurrences; both diverge on message casing |
|
|
62
|
+
|
|
63
|
+
Running the same harness over application code rather than linter source surfaces divergences this
|
|
64
|
+
corpus does not. Treat a clean run on any single corpus as evidence about that corpus.
|
|
65
|
+
|
|
66
|
+
Two properties of the harness itself also bound what a run can tell you:
|
|
67
|
+
|
|
68
|
+
- Only the cops passed to `--cop` are compared. Cops that RuboCop reports and Sonicop has not
|
|
69
|
+
implemented show up as false negatives, which is expected rather than a defect.
|
|
70
|
+
- RuboCop emits **only** `Lint/Syntax` for a file it considers fatally unparseable and suppresses
|
|
71
|
+
every other cop for that file, while Sonicop keeps inspecting it. Whenever the two disagree
|
|
72
|
+
about syntax validity — most easily triggered by a `TargetRubyVersion` the source does not
|
|
73
|
+
satisfy — the false-positive count is dominated by that single behaviour rather than by cop
|
|
74
|
+
logic. Check the reference output for `"severity": "fatal"` before reading a large false-positive
|
|
75
|
+
count as a cop problem.
|
|
76
|
+
|
|
77
|
+
Closing these gaps properly means migrating RuboCop's own spec suite, which exercises each cop
|
|
78
|
+
against inputs written to break it. Until that lands, this document records what was measured, not
|
|
79
|
+
an upper bound on what could differ.
|
|
80
|
+
|
|
81
|
+
## Rails configuration and scale
|
|
82
|
+
|
|
83
|
+
Rails source snapshot: `adf307b03b4241cbc0ed3821faf3b153ca6cd5cd` (Rails 8.2.0.alpha).
|
|
84
|
+
The reference process uses RuboCop 1.89.0 with the five plugins declared by Rails:
|
|
85
|
+
rubocop-minitest 0.40.0, rubocop-packaging 0.6.0, rubocop-performance 1.26.1,
|
|
86
|
+
rubocop-rails 2.36.0, and rubocop-md 2.0.4.
|
|
87
|
+
|
|
88
|
+
This corpus exercises `AllCops/DisabledByDefault`, external plugin cops, recursive excludes,
|
|
89
|
+
hidden paths, and the inherited `guides/.rubocop.yml` configuration.
|
|
90
|
+
|
|
91
|
+
| Compatibility check | RuboCop | Sonicop | Result |
|
|
92
|
+
|---|---:|---:|---|
|
|
93
|
+
| Ruby target files from repository root | 3,453 | 3,453 | Exact paths and order |
|
|
94
|
+
| Enabled cops for `activerecord/lib/active_record.rb` | 107 | 107 | Exact names and order |
|
|
95
|
+
| Enabled cops for a file under `guides/` | 102 | 102 | Exact names and order |
|
|
96
|
+
| Full-tree false positives | — | 0 | Pass |
|
|
97
|
+
|
|
98
|
+
RuboCop also discovers 75 Markdown targets through rubocop-md. Markdown extraction is outside
|
|
99
|
+
Sonicop's current parser scope, so those files are removed before comparing `-L` output.
|
|
100
|
+
|
|
101
|
+
The full 3,453-Ruby-file offense comparison reports 10 reference locations and no Sonicop
|
|
102
|
+
locations: zero false positives and 10 visible false negatives. The missing locations are three
|
|
103
|
+
`Style/RedundantPercentQ`, two `Lint/RedundantCopDisableDirective`, two
|
|
104
|
+
`Layout/IndentationWidth`, two unsupported `Lint/DuplicateMethods` cases, and one
|
|
105
|
+
`Lint/Debugger`. Artifacts: `/tmp/sonicop-conformance-rails-full-2`.
|
|
106
|
+
|
|
107
|
+
On the 402-file `activerecord/lib` subset, a warmed single run with cache and color disabled took
|
|
108
|
+
4.37 seconds for RuboCop and 0.35 seconds for Sonicop (`/usr/bin/time -p`): approximately
|
|
109
|
+
**12.5x faster** on the validation machine.
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Yohei
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/NOTICE
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Sonicop includes and adapts configuration data from RuboCop 1.89.0.
|
|
2
|
+
RuboCop is Copyright (c) 2012-26 Bozhidar Batsov and contributors,
|
|
3
|
+
licensed under the MIT License. See licenses/RUBOCOP.txt.
|
|
4
|
+
|
|
5
|
+
Sonicop links to owayo/tree-sitter-ruby, derived from tree-sitter-ruby.
|
|
6
|
+
tree-sitter-ruby is Copyright (c) 2016 Rob Rix and contributors,
|
|
7
|
+
licensed under the MIT License. See licenses/TREE_SITTER_RUBY.txt.
|
data/README.ja.md
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
<h1 align="center">
|
|
2
|
+
<img src="docs/images/sonicop_logo_header.png" width="600" alt="Sonicop">
|
|
3
|
+
</h1>
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<strong>Rust で実装した高速なネイティブ RuboCop 互換 Ruby リンター/フォーマッター。</strong>
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+
<p align="center">
|
|
10
|
+
<a href="https://github.com/owayo/sonicop/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/owayo/sonicop/actions/workflows/ci.yml/badge.svg?branch=main"></a>
|
|
11
|
+
<a href="https://rubygems.org/gems/sonicop"><img alt="Gem Version" src="https://img.shields.io/gem/v/sonicop"></a>
|
|
12
|
+
<a href="LICENSE"><img alt="License" src="https://img.shields.io/github/license/owayo/sonicop"></a>
|
|
13
|
+
</p>
|
|
14
|
+
|
|
15
|
+
<p align="center">
|
|
16
|
+
<a href="README.md">English</a> |
|
|
17
|
+
<a href="README.ja.md">日本語</a>
|
|
18
|
+
</p>
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 概要
|
|
23
|
+
|
|
24
|
+
Sonicop は、Ruby プロセスを起動せずに動作する高速な Rust 製 Ruby リンター/フォーマッターです。
|
|
25
|
+
既存の `.rubocop.yml` をそのまま利用でき、サブディレクトリごとの設定、設定の継承、対象ファイルの
|
|
26
|
+
Include/Exclude、severity、自動修正設定にも対応しています。
|
|
27
|
+
|
|
28
|
+
最新の Ruby 構文へ追従する
|
|
29
|
+
[owayo/tree-sitter-ruby](https://github.com/owayo/tree-sitter-ruby) を使い、ファイルを並列に検査して
|
|
30
|
+
修正をアトミックに適用します。RuboCop 1.89 互換の CLI と JSON 出力により、既存のエディタや
|
|
31
|
+
CI へ最小限の変更で導入できます。
|
|
32
|
+
|
|
33
|
+
## 主な機能
|
|
34
|
+
|
|
35
|
+
Layout、Lint、Metrics、Naming、Security、Style の各部門の Cop を実装しています。
|
|
36
|
+
実装済みの Cop はリリースごとに増えるため、一覧はバイナリ自身が正本です。
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# 認識済み Cop と実装状況の一覧
|
|
40
|
+
sonicop --show-cops
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
RuboCop 1.89 の全 609 Cop を同梱設定として認識します。実装済み Cop は検査を実行し、
|
|
44
|
+
認識済みで未実装の Cop は既存設定を壊さず `--debug` で一覧表示します。本家にも存在しない
|
|
45
|
+
Cop 名だけをエラーにし、必要なら `--ignore-unrecognized-cops` で続行できます。
|
|
46
|
+
|
|
47
|
+
## インストール
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
gem install sonicop
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Linux、macOS、Windows 向けの platform gem にはネイティブ実行ファイルが含まれます。
|
|
54
|
+
対応する platform gem がない環境では、source gem がインストール時に Cargo でビルドします。
|
|
55
|
+
|
|
56
|
+
最新版のソースから直接インストールすることもできます。
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
cargo install --git https://github.com/owayo/sonicop
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## 使い方
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
# 現在のプロジェクトを検査
|
|
66
|
+
sonicop
|
|
67
|
+
|
|
68
|
+
# Cop/部門を選択
|
|
69
|
+
sonicop --only Layout,Style/StringLiterals app spec
|
|
70
|
+
|
|
71
|
+
# 安全な自動修正/全自動修正
|
|
72
|
+
sonicop -a
|
|
73
|
+
sonicop -A
|
|
74
|
+
|
|
75
|
+
# RuboCop 互換形状の JSON
|
|
76
|
+
sonicop --format json
|
|
77
|
+
|
|
78
|
+
# 認識済み Cop と実装状況
|
|
79
|
+
sonicop --show-cops
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
主な互換オプションは `-l`、`-x`、`--only`、`--except`、`-s/--stdin`、
|
|
83
|
+
`-P/--parallel`、`-f/--format`、`-a/--autocorrect`、`-A/--autocorrect-all`、
|
|
84
|
+
`-L/--list-target-files`、`-c/--config`、`-v/--version`、`-V/--verbose-version` です。
|
|
85
|
+
|
|
86
|
+
### 設定
|
|
87
|
+
|
|
88
|
+
対象ファイルごとに `.rubocop.yml` を解決するため、1 回の実行でもサブディレクトリ設定が
|
|
89
|
+
適用されます。ローカル/HTTPS の `inherit_from`、`inherit_gem`、`inherit_mode`、
|
|
90
|
+
`AllCops/DisabledByDefault`、`Include`/`Exclude`、Cop ごとの `Enabled`、`Exclude`、
|
|
91
|
+
`Severity`、`Safe`、`SafeAutoCorrect` と設定値に対応します。宣言されたプラグイン由来の
|
|
92
|
+
Cop は「認識済み・未実装」として受理し、Ruby プラグインコード自体は実行しません。
|
|
93
|
+
|
|
94
|
+
```yaml
|
|
95
|
+
inherit_from: .rubocop_todo.yml
|
|
96
|
+
|
|
97
|
+
Layout/LineLength:
|
|
98
|
+
Max: 100
|
|
99
|
+
|
|
100
|
+
Style/StringLiterals:
|
|
101
|
+
EnforcedStyle: single_quotes
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
既存コマンドとの互換性を保つため、server/LSP/MCP、plugin、cache 系の引数も受理します。
|
|
105
|
+
未対応の機能を要求する引数は互換 no-op として stderr に明示します。現在、サーバートランスポート、
|
|
106
|
+
Ruby プラグイン実行、キャッシュ再利用、カスタム Cop、実装済み以外の Cop は実行しません。
|
|
107
|
+
|
|
108
|
+
### 適合性
|
|
109
|
+
|
|
110
|
+
実装済み Cop は、正規化した JSON offense を使って RuboCop 1.89 との一致を検証済みです。
|
|
111
|
+
本家の全 1,759 ファイルを本家既定設定で検査した現在のスナップショットは、参照 4,052 件中
|
|
112
|
+
4,052 件すべての位置が一致(**recall 100%**)し、**誤検出とメタデータ差もともに 0 件**です。コマンド、比較範囲、測定結果は
|
|
113
|
+
[CONFORMANCE.md](CONFORMANCE.md) にまとめています。Rails では Ruby 対象 3,453 ファイルと
|
|
114
|
+
ルート/`guides/` の有効 Cop 一覧が完全一致し、全体の誤検出は 0 件です。Active Record
|
|
115
|
+
402 ファイルの無キャッシュ実行は本家比で約 12.5 倍高速でした。
|
|
116
|
+
|
|
117
|
+
## 開発
|
|
118
|
+
|
|
119
|
+
入口は `make` に一本化しています。`make help` で全ターゲットを確認できます。gem 配布の
|
|
120
|
+
タスクは Rakefile 側にあり、`make` から呼び出します。
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
make build # デバッグビルド
|
|
124
|
+
make check # fmt、clippy、Rust テスト、Ruby ラッパーテスト、バージョン整合
|
|
125
|
+
make gem # source gem
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Cop の追加
|
|
129
|
+
|
|
130
|
+
Cop は `src/rules/<部門>/<cop>.rs` の 1 ファイルで、公開するのは `check(context, offenses)` の
|
|
131
|
+
1 関数だけです。登録は部門の `mod.rs` に 1 行を足します。
|
|
132
|
+
|
|
133
|
+
```rust
|
|
134
|
+
department_rules! {
|
|
135
|
+
"Layout";
|
|
136
|
+
line_length => ("LineLength", Convention),
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Cop 名と既定 severity を書くのはこの 1 行だけです。Cop 本体では名前は暗黙で、
|
|
141
|
+
`context.setting("Max")` が `Layout/LineLength: Max` を読み、`context.offense(message, range)` が
|
|
142
|
+
その Cop の名前と設定済み severity で報告します。Cop が自分の名前を 2 度書ける設計では、
|
|
143
|
+
レジストリと食い違っても型検査では捕まりません。
|
|
144
|
+
|
|
145
|
+
全ノード走査より `context.nodes_of("kind")` を優先してください。Cop は全ファイルに対して走るため、
|
|
146
|
+
Cop ごとの全走査はファイル規模ではなく Cop 数に比例して重くなります。
|
|
147
|
+
|
|
148
|
+
バージョンの正本は `Cargo.toml` です。`lib/sonicop/version.rb` は `make version-sync` で
|
|
149
|
+
生成してコミットします(gemspec がパッケージ時に読むため)。両者が食い違うと CI が落ちます。
|
|
150
|
+
|
|
151
|
+
`config/default.yml` は上流 RuboCop から取り込んだものです。再取得は
|
|
152
|
+
`scripts/sync_default_yml.sh <rubocop-version>` で行い、由来のバージョンがファイル先頭に
|
|
153
|
+
記録されます。
|
|
154
|
+
|
|
155
|
+
依存更新には `depup --install` を使います。Ruby grammar は再現可能性のため `Cargo.toml` で
|
|
156
|
+
fork のコミットを固定しています。
|
|
157
|
+
|
|
158
|
+
## ライセンス
|
|
159
|
+
|
|
160
|
+
[MIT](LICENSE)。同梱する RuboCop 既定設定とパーサー依存の著作権表示は
|
|
161
|
+
[NOTICE](NOTICE) および [`licenses/`](licenses/) に収録しています。
|
data/README.md
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
<h1 align="center">
|
|
2
|
+
<img src="docs/images/sonicop_logo_header.png" width="600" alt="Sonicop">
|
|
3
|
+
</h1>
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<strong>A fast, native RuboCop-compatible Ruby linter and formatter written in Rust.</strong>
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+
<p align="center">
|
|
10
|
+
<a href="https://github.com/owayo/sonicop/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/owayo/sonicop/actions/workflows/ci.yml/badge.svg?branch=main"></a>
|
|
11
|
+
<a href="https://rubygems.org/gems/sonicop"><img alt="Gem Version" src="https://img.shields.io/gem/v/sonicop"></a>
|
|
12
|
+
<a href="LICENSE"><img alt="License" src="https://img.shields.io/github/license/owayo/sonicop"></a>
|
|
13
|
+
</p>
|
|
14
|
+
|
|
15
|
+
<p align="center">
|
|
16
|
+
<a href="README.md">English</a> |
|
|
17
|
+
<a href="README.ja.md">日本語</a>
|
|
18
|
+
</p>
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Overview
|
|
23
|
+
|
|
24
|
+
Sonicop is a fast Ruby linter and formatter that runs as a native executable without starting a
|
|
25
|
+
Ruby process. Existing `.rubocop.yml` files work as-is, including nested configuration,
|
|
26
|
+
inheritance, file inclusion and exclusion, severity, and autocorrect settings.
|
|
27
|
+
|
|
28
|
+
It uses the actively maintained
|
|
29
|
+
[owayo/tree-sitter-ruby](https://github.com/owayo/tree-sitter-ruby) grammar, inspects files in
|
|
30
|
+
parallel, and applies corrections atomically. Its RuboCop 1.89-compatible CLI and JSON output fit
|
|
31
|
+
existing editor and CI integrations with minimal changes.
|
|
32
|
+
|
|
33
|
+
## Features
|
|
34
|
+
|
|
35
|
+
Sonicop implements cops in the Layout, Lint, Metrics, Naming, Security, and Style departments.
|
|
36
|
+
The implemented set grows with each release, so the binary itself is the authoritative list:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# Every recognized cop and its implementation status
|
|
40
|
+
sonicop --show-cops
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The bundled upstream configuration recognizes all 609 RuboCop 1.89 cops. Implemented cops run
|
|
44
|
+
normally; recognized but not-yet-implemented cops remain configuration-compatible and are
|
|
45
|
+
reported by `--debug`. Truly unknown cop names still fail validation unless
|
|
46
|
+
`--ignore-unrecognized-cops` is supplied.
|
|
47
|
+
|
|
48
|
+
## Installation
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
gem install sonicop
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Platform gems include native executables for Linux, macOS, and Windows. When a prebuilt platform
|
|
55
|
+
gem is unavailable, the source gem builds the executable with Cargo during installation.
|
|
56
|
+
|
|
57
|
+
You can also install the latest source directly:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
cargo install --git https://github.com/owayo/sonicop
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Usage
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# Inspect the current project
|
|
67
|
+
sonicop
|
|
68
|
+
|
|
69
|
+
# Select cops or departments
|
|
70
|
+
sonicop --only Layout,Style/StringLiterals app spec
|
|
71
|
+
|
|
72
|
+
# Safe correction / all correction
|
|
73
|
+
sonicop -a
|
|
74
|
+
sonicop -A
|
|
75
|
+
|
|
76
|
+
# RuboCop-shaped JSON
|
|
77
|
+
sonicop --format json
|
|
78
|
+
|
|
79
|
+
# Editor input
|
|
80
|
+
printf '%s\n' 'value=10000' | sonicop --stdin example.rb --format json
|
|
81
|
+
|
|
82
|
+
# List recognized cops and their implementation status
|
|
83
|
+
sonicop --show-cops
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Key compatibility flags include `-l`, `-x`, `--only`, `--except`, `-s/--stdin`, `-P/--parallel`,
|
|
87
|
+
`-f/--format`, `-a/--autocorrect`, `-A/--autocorrect-all`, `-L/--list-target-files`,
|
|
88
|
+
`-c/--config`, `-v/--version`, and `-V/--verbose-version`.
|
|
89
|
+
|
|
90
|
+
### Configuration
|
|
91
|
+
|
|
92
|
+
Sonicop resolves `.rubocop.yml` from each target file, so nested configurations apply within one
|
|
93
|
+
run. Local and HTTPS `inherit_from`, `inherit_gem`, `inherit_mode`,
|
|
94
|
+
`AllCops/DisabledByDefault`, `Include`, and `Exclude`, plus per-cop `Enabled`, `Exclude`,
|
|
95
|
+
`Severity`, `Safe`, `SafeAutoCorrect`, and cop settings are supported. Cops supplied by declared
|
|
96
|
+
plugins are accepted as recognized-but-unimplemented without executing Ruby plugin code.
|
|
97
|
+
|
|
98
|
+
```yaml
|
|
99
|
+
inherit_from: .rubocop_todo.yml
|
|
100
|
+
|
|
101
|
+
AllCops:
|
|
102
|
+
Exclude:
|
|
103
|
+
- "vendor/**/*"
|
|
104
|
+
|
|
105
|
+
Layout/LineLength:
|
|
106
|
+
Max: 100
|
|
107
|
+
|
|
108
|
+
Style/StringLiterals:
|
|
109
|
+
EnforcedStyle: single_quotes
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
The CLI accepts RuboCop's server/LSP/MCP, plugin, and cache flags to keep existing command lines
|
|
113
|
+
parse-compatible. These flags are reported as compatibility no-ops when they request unsupported
|
|
114
|
+
functionality. Sonicop does not currently provide server transports, Ruby plugin execution, cache
|
|
115
|
+
reuse, custom Ruby cops, or cops outside the implemented set.
|
|
116
|
+
|
|
117
|
+
### Conformance
|
|
118
|
+
|
|
119
|
+
The implemented cops are verified against RuboCop 1.89 using normalized JSON offenses.
|
|
120
|
+
On RuboCop's complete 1,759-file source tree with the upstream default configuration, the current
|
|
121
|
+
snapshot matches all 4,052 reference offense locations (**100% recall**) with **zero false
|
|
122
|
+
positives and zero metadata differences**. On Rails, all 3,453 Ruby target paths and the root/nested enabled-cop lists match
|
|
123
|
+
exactly, the full tree has zero false positives, and the 402-file Active Record subset runs about
|
|
124
|
+
12.5x faster without cache. See [CONFORMANCE.md](CONFORMANCE.md) for the commands, scope, and
|
|
125
|
+
measurements.
|
|
126
|
+
|
|
127
|
+
## Development
|
|
128
|
+
|
|
129
|
+
`make` is the single entry point; `make help` lists every target. The Rakefile holds the gem
|
|
130
|
+
packaging tasks that `make` delegates to.
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
make build # debug build
|
|
134
|
+
make check # fmt, clippy, Rust tests, Ruby wrapper tests, version consistency
|
|
135
|
+
make gem # source gem
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Adding a cop
|
|
139
|
+
|
|
140
|
+
A cop is one file under `src/rules/<department>/<cop>.rs` exposing a single
|
|
141
|
+
`check(context, offenses)`, plus one line in that department's `mod.rs`:
|
|
142
|
+
|
|
143
|
+
```rust
|
|
144
|
+
department_rules! {
|
|
145
|
+
"Layout";
|
|
146
|
+
line_length => ("LineLength", Convention),
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
That line is the only place the cop's name and default severity are written. Inside the cop the
|
|
151
|
+
name stays implicit: `context.setting("Max")` reads `Layout/LineLength: Max`, and
|
|
152
|
+
`context.offense(message, range)` reports under the cop's own name at its configured severity. A
|
|
153
|
+
cop that spelled its name a second time could disagree with the registry, and nothing in the type
|
|
154
|
+
system would catch it.
|
|
155
|
+
|
|
156
|
+
Prefer `context.nodes_of("kind")` over walking every node: each cop runs on every file, so a full
|
|
157
|
+
walk per cop is what makes inspection scale with the registry rather than with the file.
|
|
158
|
+
|
|
159
|
+
`Cargo.toml` is the single source of truth for the version. `lib/sonicop/version.rb` is generated
|
|
160
|
+
from it by `make version-sync` and committed, because the gemspec reads it at package time. CI
|
|
161
|
+
fails when the two disagree.
|
|
162
|
+
|
|
163
|
+
`config/default.yml` is vendored from upstream RuboCop; re-fetch it with
|
|
164
|
+
`scripts/sync_default_yml.sh <rubocop-version>`, which records the source version in the file
|
|
165
|
+
header.
|
|
166
|
+
|
|
167
|
+
Dependencies are updated with `depup --install`. The Ruby grammar dependency is pinned to an exact
|
|
168
|
+
fork commit in `Cargo.toml` for reproducible builds.
|
|
169
|
+
|
|
170
|
+
## License
|
|
171
|
+
|
|
172
|
+
[MIT](LICENSE). The bundled RuboCop default configuration and parser dependency retain their
|
|
173
|
+
upstream notices in [NOTICE](NOTICE) and [`licenses/`](licenses/).
|