rubocop-rbs_inline 1.7.0 → 1.8.0

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.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/.claude/hooks/self-review.sh +89 -0
  3. data/.claude/settings.json +8 -0
  4. data/.rubocop.yml +9 -3
  5. data/CHANGELOG.md +19 -0
  6. data/CLAUDE.md +9 -14
  7. data/README.md +54 -6
  8. data/config/default.yml +3 -4
  9. data/lib/rubocop/cop/rbs_inline_cops.rb +15 -7
  10. data/lib/rubocop/cop/style/rbs_inline/data_class_comment_alignment.rb +2 -9
  11. data/lib/rubocop/cop/style/rbs_inline/data_define_with_block.rb +3 -9
  12. data/lib/rubocop/cop/style/rbs_inline/embedded_rbs_spacing.rb +3 -2
  13. data/lib/rubocop/cop/style/rbs_inline/invalid_comment.rb +2 -2
  14. data/lib/rubocop/cop/style/rbs_inline/invalid_types.rb +1 -0
  15. data/lib/rubocop/cop/style/rbs_inline/keyword_separator.rb +2 -2
  16. data/lib/rubocop/cop/style/rbs_inline/method_comment_spacing.rb +3 -2
  17. data/lib/rubocop/cop/style/rbs_inline/missing_data_class_annotation.rb +2 -9
  18. data/lib/rubocop/cop/style/rbs_inline/missing_struct_class_annotation.rb +2 -16
  19. data/lib/rubocop/cop/style/rbs_inline/missing_type_annotation.rb +3 -16
  20. data/lib/rubocop/cop/style/rbs_inline/mixin/annotation_keywords.rb +16 -0
  21. data/lib/rubocop/cop/style/rbs_inline/{ast_utils.rb → mixin/ast_utils.rb} +16 -0
  22. data/lib/rubocop/cop/style/rbs_inline/{comment_parser.rb → mixin/comment_parser.rb} +8 -0
  23. data/lib/rubocop/cop/style/rbs_inline/mixin/data_class_matcher.rb +22 -0
  24. data/lib/rubocop/cop/style/rbs_inline/{data_struct_helper.rb → mixin/data_struct_helper.rb} +14 -5
  25. data/lib/rubocop/cop/style/rbs_inline/mixin/file_filter.rb +110 -0
  26. data/lib/rubocop/cop/style/rbs_inline/{source_code_helper.rb → mixin/source_code_helper.rb} +3 -5
  27. data/lib/rubocop/cop/style/rbs_inline/mixin/struct_class_matcher.rb +32 -0
  28. data/lib/rubocop/cop/style/rbs_inline/parameters_separator.rb +2 -2
  29. data/lib/rubocop/cop/style/rbs_inline/redundant_annotation_with_skip.rb +2 -11
  30. data/lib/rubocop/cop/style/rbs_inline/redundant_instance_variable_annotation.rb +1 -0
  31. data/lib/rubocop/cop/style/rbs_inline/redundant_type_annotation.rb +6 -15
  32. data/lib/rubocop/cop/style/rbs_inline/require_rbs_inline_comment.rb +74 -23
  33. data/lib/rubocop/cop/style/rbs_inline/struct_class_comment_alignment.rb +2 -16
  34. data/lib/rubocop/cop/style/rbs_inline/struct_new_with_block.rb +3 -9
  35. data/lib/rubocop/cop/style/rbs_inline/unmatched_annotations.rb +31 -6
  36. data/lib/rubocop/cop/style/rbs_inline/untyped_instance_variable.rb +16 -6
  37. data/lib/rubocop/cop/style/rbs_inline/variable_comment_spacing.rb +3 -2
  38. data/lib/rubocop/rbs_inline/version.rb +1 -1
  39. data/sig/gems/rubocop/rubocop.rbs +8 -0
  40. data/sig/rubocop/cop/style/rbs_inline/data_class_comment_alignment.rbs +4 -5
  41. data/sig/rubocop/cop/style/rbs_inline/data_define_with_block.rbs +4 -5
  42. data/sig/rubocop/cop/style/rbs_inline/embedded_rbs_spacing.rbs +2 -0
  43. data/sig/rubocop/cop/style/rbs_inline/invalid_comment.rbs +4 -3
  44. data/sig/rubocop/cop/style/rbs_inline/invalid_types.rbs +2 -0
  45. data/sig/rubocop/cop/style/rbs_inline/keyword_separator.rbs +4 -3
  46. data/sig/rubocop/cop/style/rbs_inline/method_comment_spacing.rbs +2 -0
  47. data/sig/rubocop/cop/style/rbs_inline/missing_data_class_annotation.rbs +4 -5
  48. data/sig/rubocop/cop/style/rbs_inline/missing_struct_class_annotation.rbs +4 -10
  49. data/sig/rubocop/cop/style/rbs_inline/missing_type_annotation.rbs +4 -8
  50. data/sig/rubocop/cop/style/rbs_inline/mixin/annotation_keywords.rbs +16 -0
  51. data/sig/rubocop/cop/style/rbs_inline/{ast_utils.rbs → mixin/ast_utils.rbs} +9 -1
  52. data/sig/rubocop/cop/style/rbs_inline/{class_comment_alignment.rbs → mixin/class_comment_alignment.rbs} +1 -1
  53. data/sig/rubocop/cop/style/rbs_inline/{comment_parser.rbs → mixin/comment_parser.rbs} +5 -1
  54. data/sig/rubocop/cop/style/rbs_inline/mixin/data_class_matcher.rbs +18 -0
  55. data/sig/rubocop/cop/style/rbs_inline/{data_struct_helper.rbs → mixin/data_struct_helper.rbs} +6 -1
  56. data/sig/rubocop/cop/style/rbs_inline/mixin/file_filter.rbs +63 -0
  57. data/sig/rubocop/cop/style/rbs_inline/{missing_class_annotation.rbs → mixin/missing_class_annotation.rbs} +1 -1
  58. data/sig/rubocop/cop/style/rbs_inline/{source_code_helper.rbs → mixin/source_code_helper.rbs} +1 -1
  59. data/sig/rubocop/cop/style/rbs_inline/mixin/struct_class_matcher.rbs +26 -0
  60. data/sig/rubocop/cop/style/rbs_inline/parameters_separator.rbs +4 -3
  61. data/sig/rubocop/cop/style/rbs_inline/redundant_annotation_with_skip.rbs +4 -4
  62. data/sig/rubocop/cop/style/rbs_inline/redundant_instance_variable_annotation.rbs +2 -0
  63. data/sig/rubocop/cop/style/rbs_inline/redundant_type_annotation.rbs +4 -4
  64. data/sig/rubocop/cop/style/rbs_inline/require_rbs_inline_comment.rbs +30 -5
  65. data/sig/rubocop/cop/style/rbs_inline/struct_class_comment_alignment.rbs +4 -10
  66. data/sig/rubocop/cop/style/rbs_inline/struct_new_with_block.rbs +4 -5
  67. data/sig/rubocop/cop/style/rbs_inline/unmatched_annotations.rbs +13 -0
  68. data/sig/rubocop/cop/style/rbs_inline/untyped_instance_variable.rbs +10 -0
  69. data/sig/rubocop/cop/style/rbs_inline/variable_comment_spacing.rbs +2 -0
  70. metadata +24 -17
  71. data/sig/rubocop/cop/style/rbs_inline/redundant_argument_type.rbs +0 -85
  72. data/sig/rubocop/cop/style/rbs_inline/redundant_return_type.rbs +0 -109
  73. /data/lib/rubocop/cop/style/rbs_inline/{class_comment_alignment.rb → mixin/class_comment_alignment.rb} +0 -0
  74. /data/lib/rubocop/cop/style/rbs_inline/{missing_class_annotation.rb → mixin/missing_class_annotation.rb} +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5f1bf0f9d17e73042a1c33ae69ffe0cf079bedb1423119b36a524d085cfe6f6a
4
- data.tar.gz: '0797210c998bb891bcd07b68f3d4cc9e779cf775ea051e6529c8b052ed58642a'
3
+ metadata.gz: e4bebfc6eae9ec29990f1dafdf2fc773737b2cf001c450702b138b1d9ab81dec
4
+ data.tar.gz: f9ebb04f3712f5f02cd6b7388ea74b056fdce19027be61ed6b651cf1b5915ca8
5
5
  SHA512:
6
- metadata.gz: bb484322f4605db7c86dddf047de1ad1dbe477faf11b7d736edaa544132b87c1b7c0481cd13a6154662a0e318daeaf4880102882288cf02b84ba88eb8d3372f5
7
- data.tar.gz: 141d659c28c9c9b2bef362b7f5b57bccf68aaec436b553e19785d97d162a0293c94d0d79ad7d29b7300f0b2583cce353c3152503ec965ab521eeff6fe3bb1127
6
+ metadata.gz: 46b9e51e95573630afbe686500cdf154a2cdf2d76bd19f441552fe76267682fb586118f96e7b0c5316352b49fc6e5ddc3b080fd1dc8b6711d31e382694ad767d
7
+ data.tar.gz: 9bd7d22ee40b4d009b1c2f2f86d855a37ee32349c12afffdebbda6cf5edf54bf9c474f67bdfb170987ea512c0934deb48d709f1afbc49acef88f968ebff4297a
@@ -0,0 +1,89 @@
1
+ #!/bin/bash
2
+ #
3
+ # PreToolUse hook: review code before `git commit`.
4
+ #
5
+ # Fires before a Bash `git commit` command and blocks the first commit attempt
6
+ # for a given change-set, asking Claude to review the code before committing.
7
+ # The review uses the `self-review` skill when available, and falls back to the
8
+ # bundled `code-review` skill otherwise — so the hook works even in projects
9
+ # that don't ship the custom self-review skill.
10
+ #
11
+ # A per-change-set marker (keyed by a hash of the diff, stored under .git/)
12
+ # prevents an infinite block loop: once a change-set has been surfaced for
13
+ # review, the matching commit is allowed through. If the review leads to fixes,
14
+ # the diff changes, so the new state is reviewed once more before it commits.
15
+ #
16
+
17
+ set -euo pipefail
18
+
19
+ # Read JSON input from stdin
20
+ input=$(cat)
21
+
22
+ tool_name=$(echo "$input" | jq -r '.tool_name // empty')
23
+ command=$(echo "$input" | jq -r '.tool_input.command // empty')
24
+
25
+ # Only gate the Bash tool running a git commit.
26
+ if [[ "$tool_name" != "Bash" ]]; then
27
+ exit 0
28
+ fi
29
+ # Match `git commit`, or `git -C <path> commit`.
30
+ commit_re='git[[:space:]]+(-C[[:space:]]+[^[:space:]]+[[:space:]]+)?commit'
31
+ if [[ ! "$command" =~ $commit_re ]]; then
32
+ exit 0
33
+ fi
34
+
35
+ # If the command targets a specific repo via `git -C <path>`, operate there too.
36
+ work_dir="."
37
+ if [[ "$command" =~ git[[:space:]]+-C[[:space:]]+([^[:space:]]+) ]]; then
38
+ work_dir="${BASH_REMATCH[1]}"
39
+ fi
40
+
41
+ # Not a git repo → nothing to do.
42
+ git_dir=$(git -C "$work_dir" rev-parse --absolute-git-dir 2>/dev/null || true)
43
+ if [[ -z "$git_dir" ]]; then
44
+ exit 0
45
+ fi
46
+
47
+ # Hash what will be committed. `git status --porcelain` is included so a commit
48
+ # that only adds untracked files isn't mistaken for empty; `git diff HEAD` adds
49
+ # tracked content. On the first commit there is no HEAD, so use the working state.
50
+ if git -C "$work_dir" rev-parse --verify HEAD >/dev/null 2>&1; then
51
+ changeset=$(git -C "$work_dir" status --porcelain; git -C "$work_dir" diff HEAD)
52
+ else
53
+ changeset=$(git -C "$work_dir" status --porcelain; git -C "$work_dir" diff; git -C "$work_dir" diff --cached)
54
+ fi
55
+
56
+ # Nothing to review (e.g. a message-only `--amend`) → let it proceed.
57
+ if [[ -z "$changeset" ]]; then
58
+ exit 0
59
+ fi
60
+
61
+ hash=$(printf '%s' "$changeset" | git hash-object --stdin)
62
+ state_file="$git_dir/self-review-reviewed"
63
+
64
+ # Already surfaced for review → allow the commit.
65
+ if [[ -f "$state_file" ]] && grep -qxF "$hash" "$state_file"; then
66
+ exit 0
67
+ fi
68
+
69
+ # Record this change-set and block once to force a review first.
70
+ echo "$hash" >> "$state_file"
71
+
72
+ review_prompt='SELF-REVIEW REQUIRED before committing. Review the changes that are
73
+ about to be committed BEFORE running git commit again:
74
+
75
+ - If the `self-review` skill is available, invoke it (Skill tool, skill "self-review").
76
+ - Otherwise, run the bundled `/code-review` skill on the working diff.
77
+
78
+ If the review finds issues, fix them and review again. Once it is clean, run the same
79
+ git commit command again to proceed — it will be allowed through.'
80
+
81
+ jq -n --arg reason "$review_prompt" '{
82
+ "hookSpecificOutput": {
83
+ "hookEventName": "PreToolUse",
84
+ "permissionDecision": "deny",
85
+ "permissionDecisionReason": $reason
86
+ }
87
+ }'
88
+
89
+ exit 0
@@ -1,4 +1,7 @@
1
1
  {
2
+ "permissions": {
3
+ "allow": ["RemoteTrigger"]
4
+ },
2
5
  "hooks": {
3
6
  "SessionStart": [
4
7
  {
@@ -19,6 +22,11 @@
19
22
  {
20
23
  "type": "command",
21
24
  "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/pre-commit-check.sh"
25
+ },
26
+ {
27
+ "type": "command",
28
+ "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/self-review.sh",
29
+ "timeout": 10000
22
30
  }
23
31
  ]
24
32
  }
data/.rubocop.yml CHANGED
@@ -56,16 +56,22 @@ RSpec/NamedSubject:
56
56
  RSpec/NestedGroups:
57
57
  Max: 5
58
58
 
59
+ # Mixin specs mirror `lib/.../rbs_inline/mixin/`, but the modules keep the
60
+ # `RuboCop::Cop::Style::RbsInline` namespace, so the path never matches the constant.
61
+ RSpec/SpecFilePathFormat:
62
+ Exclude:
63
+ - "spec/rubocop/cop/style/rbs_inline/mixin/**/*_spec.rb"
64
+
59
65
  # RbsInline
66
+ Style/RbsInline:
67
+ Mode: opt_out
68
+
60
69
  Style/RbsInline/MissingTypeAnnotation:
61
70
  EnforcedStyle: doc_style_and_return_annotation
62
71
 
63
72
  Style/RbsInline/RedundantTypeAnnotation:
64
73
  EnforcedStyle: doc_style_and_return_annotation
65
74
 
66
- Style/RbsInline/RequireRbsInlineComment:
67
- EnforcedStyle: never
68
-
69
75
  # Style
70
76
  Style/AccessorGrouping:
71
77
  Enabled: false
data/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.8.0 (2026-07-26)
4
+
5
+ ### Enhancements
6
+
7
+ - **Style/RbsInline**: Added a shared `Mode` setting (`opt_in` / `opt_out`) at the department level to filter which files each cop checks based on the `# rbs_inline: enabled` / `disabled` magic comment.
8
+ - **Style/RbsInline/RequireRbsInlineComment**: Added the `AllowMissingComment` option, which lets projects use rbs-inline on only some of their files while keeping the opt-in filter for the rest.
9
+
10
+ ### Bug Fixes
11
+
12
+ - **Style/RbsInline/DataClassCommentAlignment**, **Style/RbsInline/StructClassCommentAlignment**: Fixed the expected annotation column being derived from arguments that cannot carry an annotation (a splat, or for `Struct.new` a leading struct name or `keyword_init:`), which reported false positives on already aligned code and made autocorrect over-pad the annotations.
13
+ - **Style/RbsInline/MissingDataClassAnnotation**, **Style/RbsInline/MissingStructClassAnnotation**: Fixed autocorrect padding the inserted annotations to the width of an argument that cannot carry one (a splat, or for `Struct.new` a leading struct name or `keyword_init:`).
14
+ - **Style/RbsInline/UnmatchedAnnotations**: Fixed a crash on method definitions taking a destructuring argument (ex. `def foo((a, b))`). The crash also aborted the inspection of the method definition, causing false positives on its valid annotations.
15
+ - **Style/RbsInline/RequireRbsInlineComment**: Fixed a crash (`IndexError`) on a file whose leading comment block ends without a trailing newline. The offense is now reported and the magic comment is inserted on its own line.
16
+ - **Style/RbsInline/RedundantTypeAnnotation**: Fixed `--auto-gen-config` generating an `EnforcedStyle` that does not resolve the offenses (including the unsupported `return_type_annotation`, which made RuboCop fail to start on the generated `.rubocop_todo.yml`). No style can make redundant annotations offense-free, so the offending files are now excluded instead.
17
+
18
+ ### Deprecations
19
+
20
+ - **Style/RbsInline/RequireRbsInlineComment**: `EnforcedStyle` is deprecated in favor of the department-level `Mode`. Migrate `always` → `Style/RbsInline: Mode: opt_in`, `never` → `Style/RbsInline: Mode: opt_out`. Will be removed in the next major version.
21
+
3
22
  ## 1.7.0 (2026-07-20)
4
23
 
5
24
  ### New Features
data/CLAUDE.md CHANGED
@@ -23,7 +23,7 @@ bundle exec rake rubocop:autocorrect_all # all autocorrect
23
23
  bundle exec rake steep # runs steep check
24
24
  bundle exec rake rbs:validate # validates RBS signatures
25
25
 
26
- # Default rake task (runs specs, rubocop, and type check)
26
+ # Default rake task (rubocop, specs, steep, rbs:validate)
27
27
  bundle exec rake
28
28
 
29
29
  # Generate a new cop
@@ -34,32 +34,27 @@ bundle exec rake 'new_cop[Style/RbsInline/CopName]'
34
34
 
35
35
  ### Cop Structure
36
36
 
37
- All cops live under `RuboCop::Cop::Style::RbsInline` namespace in `lib/rubocop/cop/style/rbs_inline/`. Each cop validates a different aspect of RBS::Inline annotations:
37
+ Cops live in `lib/rubocop/cop/style/rbs_inline/`, one per file; the shared modules they mix in live in `lib/rubocop/cop/style/rbs_inline/mixin/`. Both are under the `RuboCop::Cop::Style::RbsInline` namespace — only the directory separates them, as in `rubocop`'s `cop/mixin/`. `config/default.yml` lists every cop and its options; read it instead of a list kept here.
38
38
 
39
- - **InvalidComment** - Validates `#:` and `# @rbs` comment syntax
40
- - **InvalidTypes** - Validates RBS type syntax in annotations
41
- - **KeywordSeparator** - Ensures keywords like `module-self` aren't followed by `:`
42
- - **ParametersSeparator** - Ensures parameter annotations use `:` separator
43
- - **RedundantArgumentType** - Detects redundant argument type specs (configurable style)
44
- - **RedundantReturnType** - Detects redundant return type specs (3 style options)
45
- - **UnmatchedAnnotations** - Ensures annotation parameters match actual method parameters
39
+ Conventions:
46
40
 
47
- ### Shared CommentParser Module
48
-
49
- `comment_parser.rb` is a module mixed into cops that need to parse RBS::Inline annotations. It uses `RBS::Inline::AnnotationParser` and Prism to parse comments, and provides helpers for finding leading annotations, inline comments, and return annotations relative to method definitions.
41
+ - Every cop `prepend`s `FileFilter` except `RequireRbsInlineComment`.
42
+ - `Data.define` and `Struct.new` cops come in pairs sharing a base module. Behavior belongs in the module; only the node matcher and `MSG` in the cop.
50
43
 
51
44
  ### Plugin System
52
45
 
53
- The gem integrates with RuboCop via LintRoller (`lib/rubocop/rbs_inline/plugin.rb`). Default cop configuration is in `config/default.yml`.
46
+ The gem integrates with RuboCop via LintRoller (`lib/rubocop/rbs_inline/plugin.rb`), which points RuboCop at `config/default.yml`.
54
47
 
55
48
  ### Type Signatures
56
49
 
57
- RBS type signatures for all source files are maintained in `sig/` directory. The project uses Steep for static type checking, configured via `Steepfile`.
50
+ `sig/rubocop/` is generated from `lib/` by the hooks in `.claude/hooks/`. Never write anything there. `sig/gems/` is hand-written stubs for third-party gems and is *not* regenerated do not delete it when refreshing signatures.
58
51
 
59
52
  ### Testing Pattern
60
53
 
61
54
  Tests use RuboCop's RSpec support helpers (`expect_offense` / `expect_no_offenses`). Test files mirror the cop file structure under `spec/rubocop/cop/style/rbs_inline/`.
62
55
 
56
+ `:config` specs build a bare `RuboCop::Config`, so `config/default.yml` and RuboCop's department-to-cop defaults are not merged in. A spec that sets a value at the department level proves nothing about how it resolves in a real run.
57
+
63
58
  ## Code Style Notes
64
59
 
65
60
  - `Layout/LeadingCommentSpace` and `Style/CommentedKeyword` are disabled because RBS::Inline `#:` comments violate these rules by design.
data/README.md CHANGED
@@ -27,6 +27,23 @@ plugins:
27
27
 
28
28
  rubocop-rbs_inline provides the following cops to validate [RBS::Inline](https://github.com/soutaro/rbs-inline) annotations:
29
29
 
30
+ ### Style/RbsInline (shared configuration)
31
+
32
+ The `Style/RbsInline` department has a shared `Mode` setting that gates whether each `Style/RbsInline/*` cop reports offenses on a given file:
33
+
34
+ - `Mode: opt_in` — cops only check files that carry `# rbs_inline: enabled`. Files with `# rbs_inline: disabled` or no magic comment are skipped. Matches RBS::Inline's opt-in mode.
35
+ - `Mode: opt_out` — cops check every file except those with `# rbs_inline: disabled`. Matches RBS::Inline's opt-out mode.
36
+ - unset — cops check every file (legacy behavior; the default will change to `opt_in` in the next major release).
37
+
38
+ Declare it once at the department level in your `.rubocop.yml`:
39
+
40
+ ```yaml
41
+ Style/RbsInline:
42
+ Mode: opt_in
43
+ ```
44
+
45
+ Unknown `Mode` values (e.g. `Mode: opt-in`) emit a warning and disable filtering for the run.
46
+
30
47
  ### Style/RbsInline/DataClassCommentAlignment
31
48
 
32
49
  Checks that `#:` inline type annotations in a multiline `Data.define` call are aligned to the same column. The expected column is determined by the longest attribute name (plus its trailing comma). Folded `Data.define` calls (where multiple attributes share a line) are excluded.
@@ -238,7 +255,11 @@ Enforces that method definitions and `attr_*` declarations have RBS inline type
238
255
  - `all`: Checks all methods regardless of visibility
239
256
  - `public`: Only checks public methods and `attr_*` declarations
240
257
 
241
- Methods annotated with `# @rbs skip` are always excluded.
258
+ Always excluded, regardless of `EnforcedStyle`:
259
+
260
+ - Methods annotated with `# @rbs skip` or `# @rbs override`.
261
+ - Parameters whose name starts with `_`.
262
+ - The `...` forward-all parameter.
242
263
 
243
264
  **Examples (EnforcedStyle: doc_style):**
244
265
  ```ruby
@@ -466,13 +487,26 @@ end
466
487
 
467
488
  ### Style/RbsInline/RequireRbsInlineComment
468
489
 
469
- Enforces presence or absence of `# rbs_inline:` magic comment for consistency.
490
+ Enforces the presence or absence of the `# rbs_inline:` magic comment, based on the shared [`Mode`](#stylerbsinline-shared-configuration) setting:
491
+
492
+ - Under `Mode: opt_in`, files must carry `# rbs_inline: enabled` (or `# rbs_inline: disabled`).
493
+ - Under `Mode: opt_out`, files must not carry `# rbs_inline: enabled`.
494
+
495
+ **Configuration:**
496
+
497
+ - `AllowMissingComment` (default: `false`) — under `Mode: opt_in`, set to `true` to skip enforcement of the magic comment on individual files. Useful when only part of the project uses rbs-inline: the shared `Mode: opt_in` filter still applies to every other cop (they only report on files that opt in), but this cop stops requiring the magic comment on files that intentionally do not use rbs-inline.
498
+
499
+ ```yaml
500
+ Style/RbsInline:
501
+ Mode: opt_in
502
+
503
+ Style/RbsInline/RequireRbsInlineComment:
504
+ AllowMissingComment: true
505
+ ```
470
506
 
471
- **Configuration:** `EnforcedStyle` (default: `always`)
472
- - `always`: Requires `# rbs_inline: enabled` or `# rbs_inline: disabled`
473
- - `never`: Forbids `# rbs_inline: enabled` (allows `# rbs_inline: disabled`)
507
+ The legacy `EnforcedStyle` parameter (`always` / `never`) is deprecated in favor of `Mode`; it will be removed in the next major release.
474
508
 
475
- **Examples (EnforcedStyle: always):**
509
+ **Examples (Mode: opt_in):**
476
510
  ```ruby
477
511
  # bad
478
512
  class Foo
@@ -484,6 +518,18 @@ class Foo
484
518
  end
485
519
  ```
486
520
 
521
+ **Examples (Mode: opt_in, AllowMissingComment: true):**
522
+ ```ruby
523
+ # good - the magic comment is not enforced per file
524
+ class Foo
525
+ end
526
+
527
+ # good
528
+ # rbs_inline: enabled
529
+ class Foo
530
+ end
531
+ ```
532
+
487
533
  ### Style/RbsInline/StructClassCommentAlignment
488
534
 
489
535
  Checks that `#:` inline type annotations in a multiline `Struct.new` call are aligned to the same column. The expected column is determined by the longest attribute name (plus its trailing comma). Folded `Struct.new` calls (where multiple attributes share a line) are excluded.
@@ -613,6 +659,8 @@ Style/RbsInline/MissingTypeAnnotation:
613
659
  Visibility: public
614
660
  ```
615
661
 
662
+ To restrict every cop to files that carry `# rbs_inline: enabled`, see [Style/RbsInline (shared configuration)](#stylerbsinline-shared-configuration).
663
+
616
664
  See [config/default.yml](config/default.yml) for all available configuration options.
617
665
 
618
666
  ## Development
data/config/default.yml CHANGED
@@ -5,6 +5,7 @@ Style/RbsInline:
5
5
  Exclude:
6
6
  - 'spec/**/*'
7
7
  - 'test/**/*'
8
+ Mode: ~
8
9
 
9
10
  Style/RbsInline/DataClassCommentAlignment:
10
11
  Description: "Checks that `#:` inline type annotations in `Data.define` blocks are aligned."
@@ -94,10 +95,8 @@ Style/RbsInline/RequireRbsInlineComment:
94
95
  Description: "Checks the presence or absence of `# rbs_inline: enabled` magic comment."
95
96
  Enabled: true
96
97
  VersionAdded: "1.5.0"
97
- EnforcedStyle: always
98
- SupportedStyles:
99
- - always
100
- - never
98
+ AllowMissingComment: false
99
+ EnforcedStyle: ~
101
100
 
102
101
  Style/RbsInline/StructClassCommentAlignment:
103
102
  Description: "Checks that `#:` inline type annotations in `Struct.new` blocks are aligned."
@@ -1,11 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "style/rbs_inline/ast_utils"
4
- require_relative "style/rbs_inline/source_code_helper"
5
- require_relative "style/rbs_inline/comment_parser"
6
- require_relative "style/rbs_inline/data_struct_helper"
7
- require_relative "style/rbs_inline/missing_class_annotation"
8
- require_relative "style/rbs_inline/class_comment_alignment"
3
+ # Mixins first, in dependency order. Cops follow, alphabetically: `rake new_cop` sorts a
4
+ # generated require only against the others in the same directory, so the two blocks have
5
+ # to stay apart for it to land in the right place.
6
+ require_relative "style/rbs_inline/mixin/annotation_keywords"
7
+ require_relative "style/rbs_inline/mixin/ast_utils"
8
+ require_relative "style/rbs_inline/mixin/source_code_helper"
9
+ require_relative "style/rbs_inline/mixin/comment_parser"
10
+ require_relative "style/rbs_inline/mixin/data_struct_helper"
11
+ require_relative "style/rbs_inline/mixin/missing_class_annotation"
12
+ require_relative "style/rbs_inline/mixin/class_comment_alignment"
13
+ require_relative "style/rbs_inline/mixin/data_class_matcher"
14
+ require_relative "style/rbs_inline/mixin/file_filter"
15
+ require_relative "style/rbs_inline/mixin/struct_class_matcher"
16
+
9
17
  require_relative "style/rbs_inline/data_class_comment_alignment"
10
18
  require_relative "style/rbs_inline/data_define_with_block"
11
19
  require_relative "style/rbs_inline/embedded_rbs_spacing"
@@ -14,6 +22,7 @@ require_relative "style/rbs_inline/invalid_types"
14
22
  require_relative "style/rbs_inline/keyword_separator"
15
23
  require_relative "style/rbs_inline/method_comment_spacing"
16
24
  require_relative "style/rbs_inline/missing_data_class_annotation"
25
+ require_relative "style/rbs_inline/missing_struct_class_annotation"
17
26
  require_relative "style/rbs_inline/missing_type_annotation"
18
27
  require_relative "style/rbs_inline/parameters_separator"
19
28
  require_relative "style/rbs_inline/redundant_annotation_with_skip"
@@ -22,7 +31,6 @@ require_relative "style/rbs_inline/redundant_type_annotation"
22
31
  require_relative "style/rbs_inline/require_rbs_inline_comment"
23
32
  require_relative "style/rbs_inline/struct_class_comment_alignment"
24
33
  require_relative "style/rbs_inline/struct_new_with_block"
25
- require_relative "style/rbs_inline/missing_struct_class_annotation"
26
34
  require_relative "style/rbs_inline/unmatched_annotations"
27
35
  require_relative "style/rbs_inline/untyped_instance_variable"
28
36
  require_relative "style/rbs_inline/variable_comment_spacing"
@@ -26,7 +26,9 @@ module RuboCop
26
26
  # )
27
27
  #
28
28
  class DataClassCommentAlignment < Base
29
+ prepend FileFilter
29
30
  include ClassCommentAlignment
31
+ include DataClassMatcher
30
32
  extend AutoCorrector
31
33
 
32
34
  MSG = "Misaligned inline type annotation for Data attribute."
@@ -37,15 +39,6 @@ module RuboCop
37
39
 
38
40
  check_comment_alignment(node)
39
41
  end
40
-
41
- private
42
-
43
- # @rbs node: RuboCop::AST::SendNode
44
- def struct_like_class?(node) #: bool
45
- return false unless node.method_name == :define
46
-
47
- (r = node.receiver).is_a?(RuboCop::AST::ConstNode) && r.short_name == :Data
48
- end
49
42
  end
50
43
  end
51
44
  end
@@ -28,6 +28,9 @@ module RuboCop
28
28
  # end
29
29
  #
30
30
  class DataDefineWithBlock < Base
31
+ prepend FileFilter
32
+ include DataClassMatcher
33
+
31
34
  MSG = "Do not use `Data.define` with a block. RBS::Inline does not parse block contents, " \
32
35
  "so methods defined in the block will not be recognized. " \
33
36
  "Use a separate class definition instead."
@@ -41,15 +44,6 @@ module RuboCop
41
44
 
42
45
  add_offense(node)
43
46
  end
44
-
45
- private
46
-
47
- # @rbs node: RuboCop::AST::SendNode
48
- def struct_like_class?(node) #: bool
49
- return false unless node.method_name == :define
50
-
51
- (r = node.receiver).is_a?(RuboCop::AST::ConstNode) && r.short_name == :Data
52
- end
53
47
  end
54
48
  end
55
49
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "source_code_helper"
4
- require_relative "comment_parser"
3
+ require_relative "mixin/source_code_helper"
4
+ require_relative "mixin/comment_parser"
5
5
 
6
6
  module RuboCop
7
7
  module Cop
@@ -26,6 +26,7 @@ module RuboCop
26
26
  # end
27
27
  #
28
28
  class EmbeddedRbsSpacing < Base
29
+ prepend FileFilter
29
30
  extend AutoCorrector
30
31
  include SourceCodeHelper
31
32
  include CommentParser
@@ -20,12 +20,12 @@ module RuboCop
20
20
  # # @rbs param: String
21
21
  #
22
22
  class InvalidComment < Base
23
+ prepend FileFilter
23
24
  extend AutoCorrector
25
+ include AnnotationKeywords
24
26
 
25
27
  MSG = "Invalid RBS annotation comment found."
26
28
 
27
- # refs: https://github.com/soutaro/rbs-inline/blob/main/lib/rbs/inline/annotation_parser/tokenizer.rb
28
- RBS_INLINE_KEYWORDS = %w[inherits override use module-self generic skip module class].freeze #: Array[String]
29
29
  RBS_INLINE_KEYWORD_PATTERN = RBS_INLINE_KEYWORDS.join("|") #: String
30
30
 
31
31
  SIGNATURE_PATTERN = '\(.*\)\s*(\??\s*{.*?}\s*)?->\s*.*'
@@ -21,6 +21,7 @@ module RuboCop
21
21
  # def method(arg); end
22
22
  #
23
23
  class InvalidTypes < Base
24
+ prepend FileFilter
24
25
  include CommentParser
25
26
  include RangeHelp
26
27
  include SourceCodeHelper
@@ -15,14 +15,14 @@ module RuboCop
15
15
  # # @rbs module-self String
16
16
  #
17
17
  class KeywordSeparator < Base
18
+ prepend FileFilter
18
19
  extend AutoCorrector
20
+ include AnnotationKeywords
19
21
  include CommentParser
20
22
  include RangeHelp
21
23
 
22
24
  MSG = "Do not use `:` after the keyword."
23
25
 
24
- # refs: https://github.com/soutaro/rbs-inline/blob/main/lib/rbs/inline/annotation_parser/tokenizer.rb
25
- RBS_INLINE_KEYWORDS = %w[inherits override use module-self generic skip module class].freeze #: Array[String]
26
26
  # `override` and `skip` are standalone markers that take no arguments.
27
27
  # Even before a method definition they may not be followed by `:` alone,
28
28
  # because `# @rbs override:` (no type) is not a valid parameter annotation.
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "source_code_helper"
4
- require_relative "comment_parser"
3
+ require_relative "mixin/source_code_helper"
4
+ require_relative "mixin/comment_parser"
5
5
 
6
6
  module RuboCop
7
7
  module Cop
@@ -56,6 +56,7 @@ module RuboCop
56
56
  # end
57
57
  #
58
58
  class MethodCommentSpacing < Base
59
+ prepend FileFilter
59
60
  extend AutoCorrector
60
61
  include RangeHelp
61
62
  include SourceCodeHelper
@@ -21,7 +21,9 @@ module RuboCop
21
21
  # )
22
22
  #
23
23
  class MissingDataClassAnnotation < Base
24
+ prepend FileFilter
24
25
  include MissingClassAnnotation
26
+ include DataClassMatcher
25
27
  extend AutoCorrector
26
28
 
27
29
  MSG = "Missing inline type annotation for Data attribute (e.g., `#: Type`)."
@@ -32,15 +34,6 @@ module RuboCop
32
34
 
33
35
  check_missing_annotations(node)
34
36
  end
35
-
36
- private
37
-
38
- # @rbs node: RuboCop::AST::SendNode
39
- def struct_like_class?(node) #: bool
40
- return false unless node.method_name == :define
41
-
42
- (r = node.receiver).is_a?(RuboCop::AST::ConstNode) && r.short_name == :Data
43
- end
44
37
  end
45
38
  end
46
39
  end
@@ -22,7 +22,9 @@ module RuboCop
22
22
  # )
23
23
  #
24
24
  class MissingStructClassAnnotation < Base
25
+ prepend FileFilter
25
26
  include MissingClassAnnotation
27
+ include StructClassMatcher
26
28
  extend AutoCorrector
27
29
 
28
30
  MSG = "Missing inline type annotation for Struct attribute (e.g., `#: Type`)."
@@ -33,22 +35,6 @@ module RuboCop
33
35
 
34
36
  check_missing_annotations(node)
35
37
  end
36
-
37
- private
38
-
39
- # @rbs node: RuboCop::AST::SendNode
40
- def struct_like_class?(node) #: bool
41
- return false unless node.method_name == :new
42
-
43
- (r = node.receiver).is_a?(RuboCop::AST::ConstNode) && r.short_name == :Struct
44
- end
45
-
46
- # `Struct.new` treats a leading string argument as the struct name, so only
47
- # symbol arguments are attributes.
48
- # @rbs arg: RuboCop::AST::Node
49
- def attr_argument?(arg) #: bool
50
- arg.sym_type?
51
- end
52
38
  end
53
39
  end
54
40
  end
@@ -22,7 +22,8 @@ module RuboCop
22
22
  # - `all`: Checks all methods regardless of visibility (default)
23
23
  # - `public`: Only checks public methods and `attr_*` declarations
24
24
  #
25
- # Methods annotated with `# @rbs skip` are always excluded from inspection.
25
+ # Methods annotated with `# @rbs skip` or `# @rbs override`, parameters with a leading
26
+ # `_`, and the `...` parameter are always excluded.
26
27
  #
27
28
  # @example EnforcedStyle: doc_style
28
29
  # # bad
@@ -116,6 +117,7 @@ module RuboCop
116
117
  # attr_reader :name #: String
117
118
  #
118
119
  class MissingTypeAnnotation < Base # rubocop:disable Metrics/ClassLength
120
+ prepend FileFilter
119
121
  include ASTUtils
120
122
  include CommentParser
121
123
  include ConfigurableEnforcedStyle
@@ -347,21 +349,6 @@ module RuboCop
347
349
  add_offense(node, message: ATTRIBUTE_METHOD_MESSAGE)
348
350
  end
349
351
 
350
- # Returns the last line of the method parameter list (the closing ) line, or the def line if no parens).
351
- # @rbs node: RuboCop::AST::DefNode
352
- def method_parameter_list_end_line(node) #: Integer
353
- args_node = args_node_for(node)
354
- end_line(args_node, default: node.location.line)
355
- end
356
-
357
- # @rbs node: RuboCop::AST::DefNode
358
- def args_node_for(node) #: RuboCop::AST::Node
359
- case node.type
360
- when :defs then node.children[2]
361
- else node.children[1]
362
- end
363
- end
364
-
365
352
  # @rbs node: RuboCop::AST::DefNode
366
353
  def method_has_arguments?(node) #: bool
367
354
  args_node_for(node).children.any?
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ module RbsInline
7
+ # Provides the list of keywords that may follow `# @rbs` in an annotation comment.
8
+ #
9
+ # refs: https://github.com/soutaro/rbs-inline/blob/main/lib/rbs/inline/annotation_parser/tokenizer.rb
10
+ module AnnotationKeywords
11
+ RBS_INLINE_KEYWORDS = %w[inherits override use module-self generic skip module class].freeze #: Array[String]
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -12,6 +12,22 @@ module RuboCop
12
12
  location.end&.line || default
13
13
  end
14
14
 
15
+ # Returns the arguments node of a method definition.
16
+ # @rbs node: RuboCop::AST::DefNode
17
+ def args_node_for(node) #: RuboCop::AST::Node
18
+ case node.type
19
+ when :def then node.children[1]
20
+ when :defs then node.children[2]
21
+ else raise
22
+ end
23
+ end
24
+
25
+ # Returns the last line of the method parameter list (the closing ) line, or the def line if no parens).
26
+ # @rbs node: RuboCop::AST::DefNode
27
+ def method_parameter_list_end_line(node) #: Integer
28
+ end_line(args_node_for(node), default: node.location.line)
29
+ end
30
+
15
31
  # @rbs node: RuboCop::AST::Node
16
32
  def name_location(node) #: untyped
17
33
  location = node.location #: untyped