rubocop-fourshark 0.4.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 +10 -0
- data/README.md +12 -0
- data/lib/rubocop/cop/rails/bidirectional_association.rb +28 -39
- 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,13 @@
|
|
|
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
|
+
|
|
1
11
|
## [0.4.0] - 2026-06-29
|
|
2
12
|
|
|
3
13
|
### 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.
|
|
@@ -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
|
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
|