rubocop-fourshark 0.3.0 → 0.5.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -0
- data/README.md +12 -0
- data/config/default.yml +6 -0
- data/lib/rubocop/cop/rails/bidirectional_association.rb +31 -42
- data/lib/rubocop/cop/rspec/inverse_of_matcher.rb +3 -3
- data/lib/rubocop/fourshark/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8f3bb315d43f2566a53923bb26dd2c22024f52f70d85e5cf6e3de77707cd3267
|
|
4
|
+
data.tar.gz: b412c10e92d9d9c68b9d291379b87deea8bf06d60e448be493c3800308908604
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2a779bab95e9568e42c16a69982cb0cb6988f7972297a94953c0865c2491741b07c612fbfa16376a4a92b42be3600929efc6156832b49ccf00c48e5baf853f6b
|
|
7
|
+
data.tar.gz: c5ff6b67765e40271346cb8cc2cbc6675b49931704289e5a3338670730eb8052bc1c336f3b20c71c30baf2d005528f90bfd2c6e3dafafa4638a11ce26da66c1d
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
## [0.5.0] - 2026-06-29
|
|
2
|
+
|
|
3
|
+
### Changed
|
|
4
|
+
|
|
5
|
+
- Require `rubocop` `>= 1.87` — earlier versions drop the host project's `AllCops/Exclude` when this plugin's config is merged
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- `Rails/BidirectionalAssociation` no longer crashes on associations with non-literal options (e.g. `inverse_of: nil`); associations that explicitly opt out of an inverse are skipped
|
|
10
|
+
|
|
11
|
+
## [0.4.0] - 2026-06-29
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- `Layout/MultilineMethodCallIndentation` configured to `indented` — multiline method-call chains indent continuation calls one step from the receiver instead of aligning with the first call
|
|
16
|
+
|
|
1
17
|
## [0.3.0] - 2026-06-19
|
|
2
18
|
|
|
3
19
|
### Added
|
data/README.md
CHANGED
|
@@ -36,6 +36,18 @@ Activating the plugin auto-loads the gem's `config/default.yml`, which enables e
|
|
|
36
36
|
|
|
37
37
|
> **Note — plugins are not transitively activated.** `rubocop-fourshark` depends on the upstream plugins (`rubocop-rails`, `rubocop-rspec`, `rubocop-rspec_rails`, `rubocop-performance`, `rubocop-factory_bot`), but `lint_roller` does not auto-activate a plugin's dependencies. Each repo still lists the upstream plugins it uses in its own `plugins:` block.
|
|
38
38
|
|
|
39
|
+
> **Note — list `rubocop-fourshark` last.** When this gem configures a cop that an upstream plugin also ships (e.g. `RSpec/Dialect`, owned by `rubocop-rspec`), RuboCop merges the plugins' default config in `plugins:` order and the **last** one wins. List `rubocop-fourshark` **after** the upstream plugins so its configuration is the one that takes effect:
|
|
40
|
+
>
|
|
41
|
+
> ```yaml
|
|
42
|
+
> plugins:
|
|
43
|
+
> - rubocop-rspec
|
|
44
|
+
> - rubocop-rspec_rails
|
|
45
|
+
> - rubocop-rails
|
|
46
|
+
> - rubocop-performance
|
|
47
|
+
> - rubocop-factory_bot
|
|
48
|
+
> - rubocop-fourshark
|
|
49
|
+
> ```
|
|
50
|
+
|
|
39
51
|
## Cops
|
|
40
52
|
|
|
41
53
|
All cops are **enabled by default** the moment the plugin is activated. Cops scoped to a path (models, specs, factories) only run on files matching that path. Each cop's source file under [`lib/rubocop/cop`](lib/rubocop/cop) carries runnable `@example` blocks showing the bad/good shapes.
|
data/config/default.yml
CHANGED
|
@@ -8,6 +8,12 @@ Layout/MultilineStatementSpacing:
|
|
|
8
8
|
Enabled: true
|
|
9
9
|
VersionAdded: '0.2.0'
|
|
10
10
|
|
|
11
|
+
# Stock cop configured (not a 4Shark cop): enforce the `indented` style for
|
|
12
|
+
# multiline method-call chains — continuation calls are indented one step from
|
|
13
|
+
# the receiver instead of aligning with the first call.
|
|
14
|
+
Layout/MultilineMethodCallIndentation:
|
|
15
|
+
EnforcedStyle: indented
|
|
16
|
+
|
|
11
17
|
Style/DisallowSafeNavigation:
|
|
12
18
|
Description: 'Do not use safe navigation (`&.`). Use explicit conditionals instead.'
|
|
13
19
|
Enabled: true
|
|
@@ -75,18 +75,12 @@ module RuboCop
|
|
|
75
75
|
processed_source.ast.each_descendant(:send).filter_map do |node|
|
|
76
76
|
next unless %i[belongs_to has_many has_one].include?(node.method_name)
|
|
77
77
|
|
|
78
|
-
# Skip polymorphic associations
|
|
78
|
+
# Skip polymorphic associations, `as:` options, and explicit `inverse_of: nil/false`
|
|
79
79
|
next if polymorphic_or_as?(node)
|
|
80
|
+
next if inverse_disabled?(node)
|
|
80
81
|
|
|
81
82
|
model_name = class_name_from_ast
|
|
82
|
-
|
|
83
|
-
assoc_name =
|
|
84
|
-
begin
|
|
85
|
-
node.first_argument.value if node.first_argument
|
|
86
|
-
rescue StandardError
|
|
87
|
-
nil
|
|
88
|
-
end
|
|
89
|
-
|
|
83
|
+
assoc_name = literal_value(node.first_argument)
|
|
90
84
|
inverse_name = extract_inverse_of(node)
|
|
91
85
|
target_class = extract_class_name(node, assoc_name)
|
|
92
86
|
|
|
@@ -95,45 +89,40 @@ module RuboCop
|
|
|
95
89
|
end
|
|
96
90
|
|
|
97
91
|
def extract_inverse_of(node)
|
|
98
|
-
|
|
99
|
-
return nil unless kwargs && kwargs.hash_type?
|
|
100
|
-
|
|
101
|
-
pair =
|
|
102
|
-
begin
|
|
103
|
-
kwargs.pairs.find { |p| p.key.value == :inverse_of }
|
|
104
|
-
rescue StandardError
|
|
105
|
-
nil
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
pair.value.value if pair && pair.value
|
|
92
|
+
literal_value(option_value(node, :inverse_of))
|
|
109
93
|
end
|
|
110
94
|
|
|
111
95
|
def extract_class_name(node, assoc_name)
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
class_name_pair =
|
|
116
|
-
begin
|
|
117
|
-
kwargs.pairs.find { |p| p.key.value == :class_name }
|
|
118
|
-
rescue StandardError
|
|
119
|
-
nil
|
|
120
|
-
end
|
|
96
|
+
literal_value(option_value(node, :class_name)) || assoc_name.to_s.camelize
|
|
97
|
+
end
|
|
121
98
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
assoc_name.to_s.camelize
|
|
126
|
-
end
|
|
99
|
+
def inverse_disabled?(node)
|
|
100
|
+
value = option_value(node, :inverse_of)
|
|
101
|
+
value.falsey_literal? if value
|
|
127
102
|
end
|
|
128
103
|
|
|
129
104
|
def polymorphic_or_as?(node)
|
|
105
|
+
%i[polymorphic as].any? { |key| option_pair(node, key) }
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# The keyword options hash is the last argument; pairs whose key is not a
|
|
109
|
+
# plain symbol (string keys, double-splats) are skipped rather than read.
|
|
110
|
+
def option_pair(node, key)
|
|
130
111
|
kwargs = node.last_argument
|
|
131
|
-
return
|
|
112
|
+
return nil unless kwargs.respond_to?(:hash_type?) && kwargs.hash_type?
|
|
132
113
|
|
|
133
|
-
kwargs.pairs.
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
114
|
+
kwargs.pairs.find { |pair| pair.key.sym_type? && pair.key.value == key }
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def option_value(node, key)
|
|
118
|
+
pair = option_pair(node, key)
|
|
119
|
+
pair.value if pair
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# A node's literal value, only when it actually carries one — guards
|
|
123
|
+
# against non-literal options like `inverse_of: nil` or `class_name: Foo`.
|
|
124
|
+
def literal_value(node)
|
|
125
|
+
node.value if node.respond_to?(:value)
|
|
137
126
|
end
|
|
138
127
|
|
|
139
128
|
def class_name_from_ast
|
|
@@ -159,9 +148,9 @@ module RuboCop
|
|
|
159
148
|
return '' if name.nil?
|
|
160
149
|
|
|
161
150
|
name.gsub('::', '/')
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
151
|
+
.gsub(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2')
|
|
152
|
+
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
|
153
|
+
.downcase
|
|
165
154
|
end
|
|
166
155
|
end
|
|
167
156
|
end
|
|
@@ -129,9 +129,9 @@ module RuboCop
|
|
|
129
129
|
# "UserAccount" → "user_account"; "Plan::Statement" → "plan/statement"
|
|
130
130
|
def camel_to_snake(name)
|
|
131
131
|
name.gsub('::', '/')
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
132
|
+
.gsub(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2')
|
|
133
|
+
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
|
134
|
+
.downcase
|
|
135
135
|
end
|
|
136
136
|
end
|
|
137
137
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rubocop-fourshark
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Paulo Ribeiro
|
|
@@ -29,14 +29,14 @@ dependencies:
|
|
|
29
29
|
requirements:
|
|
30
30
|
- - ">="
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
|
-
version: 1.
|
|
32
|
+
version: '1.87'
|
|
33
33
|
type: :runtime
|
|
34
34
|
prerelease: false
|
|
35
35
|
version_requirements: !ruby/object:Gem::Requirement
|
|
36
36
|
requirements:
|
|
37
37
|
- - ">="
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
|
-
version: 1.
|
|
39
|
+
version: '1.87'
|
|
40
40
|
- !ruby/object:Gem::Dependency
|
|
41
41
|
name: rubocop-factory_bot
|
|
42
42
|
requirement: !ruby/object:Gem::Requirement
|