rubocop-petal 1.8.0 → 1.9.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/config/default.yml +31 -0
- data/lib/rubocop/cop/grape/unnecessary_namespace.rb +10 -1
- data/lib/rubocop/cop/rspec/aggregate_failures_tag.rb +123 -0
- data/lib/rubocop/cop/sidekiq/helpers.rb +1 -1
- data/lib/rubocop/cop/sidekiq/job_location.rb +61 -0
- data/lib/rubocop/cop/sidekiq/job_naming.rb +60 -0
- data/lib/rubocop/cop/sidekiq/prefer_job.rb +40 -0
- data/lib/rubocop/petal/version.rb +1 -1
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 02e763ff0683f1009a5b4e387eea9beb7e19eea47670c634f7d182b182856e41
|
4
|
+
data.tar.gz: 66576879ea7a772d5323fcf89aadf9a91ea1e0a25ee2679553ec5c83d2e197d7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '02790f98ebe560dec0615c66faabf2c67ec9f062ef8db564026b76ee72dbbfb695bbe63946d418f5b8b2872275e684acf3f5d31a74bae35c54f0d30d5d31950d'
|
7
|
+
data.tar.gz: 2a363c24244f2c6b6b451bac58ccd9a65c6c0f4e5ab6d07160720ae28a707c85a2f3e273f38116b90cb3b2bf9f3a1d089f9f58cb422cfa89be002d720543c1e1
|
data/config/default.yml
CHANGED
@@ -59,6 +59,12 @@ RSpec/AggregateExamples:
|
|
59
59
|
- validate_inclusion_of
|
60
60
|
- validates_exclusion_of
|
61
61
|
|
62
|
+
RSpec/AggregateFailuresTag:
|
63
|
+
Description: 'Checks that the `:aggregate_failures` tag is only used on examples, not on example groups.'
|
64
|
+
Enabled: true
|
65
|
+
Include:
|
66
|
+
- spec/**/*
|
67
|
+
|
62
68
|
RSpec/ChewyStrategy:
|
63
69
|
Description: 'Prevent using Chewy strategy in tests.'
|
64
70
|
Enabled: true
|
@@ -156,12 +162,14 @@ Sidekiq/KeywordArguments:
|
|
156
162
|
Enabled: true
|
157
163
|
Include:
|
158
164
|
- app/workers/**/*
|
165
|
+
- app/jobs/**/*
|
159
166
|
|
160
167
|
Sidekiq/NoNilReturn:
|
161
168
|
Description: 'Prevent early nil return in workers'
|
162
169
|
Enabled: false
|
163
170
|
Include:
|
164
171
|
- app/workers/**/*
|
172
|
+
- app/jobs/**/*
|
165
173
|
|
166
174
|
Sidekiq/PerformInline:
|
167
175
|
Description: 'Suggest to use `perform_inline` instead of `new.perform` for Sidekiq workers.'
|
@@ -171,3 +179,26 @@ Sidekiq/SymbolArgument:
|
|
171
179
|
Description: "Prevent passing keywords arguments in worker's perform method"
|
172
180
|
Enabled: true
|
173
181
|
SafeAutoCorrect: false
|
182
|
+
|
183
|
+
Sidekiq/PreferJob:
|
184
|
+
Description: 'Prefer `Sidekiq::Job` over `Sidekiq::Worker`.'
|
185
|
+
Enabled: true
|
186
|
+
StyleGuide: https://github.com/sidekiq/sidekiq/wiki/Best-Practices#4-use-precise-terminology
|
187
|
+
Include:
|
188
|
+
- app/workers/**/*
|
189
|
+
- app/jobs/**/*
|
190
|
+
|
191
|
+
Sidekiq/JobNaming:
|
192
|
+
Description: 'Job class name should end with `Job` instead of `Worker`.'
|
193
|
+
Enabled: true
|
194
|
+
StyleGuide: https://github.com/sidekiq/sidekiq/wiki/Best-Practices#4-use-precise-terminology
|
195
|
+
Include:
|
196
|
+
- app/workers/**/*
|
197
|
+
- app/jobs/**/*
|
198
|
+
|
199
|
+
Sidekiq/JobLocation:
|
200
|
+
Description: 'Job class with `Job` suffix should be placed in `app/jobs` directory instead of `app/workers`.'
|
201
|
+
Enabled: true
|
202
|
+
StyleGuide: https://github.com/sidekiq/sidekiq/wiki/Best-Practices#4-use-precise-terminology
|
203
|
+
Include:
|
204
|
+
- app/workers/**/*
|
@@ -18,7 +18,16 @@ module RuboCop
|
|
18
18
|
'Specify endpoint name with an argument: `get :some_path`.'
|
19
19
|
HTTP_ACTIONS = Set.new(%i[get head put post patch delete])
|
20
20
|
GRAPE_NAMESPACE_ALIAS = Set.new(%i[namespace resource resources])
|
21
|
-
METHOD_JUSTIFY_NAMESPACE = Set.new(%i[route_param
|
21
|
+
METHOD_JUSTIFY_NAMESPACE = Set.new(%i[route_param
|
22
|
+
namespaces
|
23
|
+
resource
|
24
|
+
resources
|
25
|
+
version
|
26
|
+
before
|
27
|
+
after
|
28
|
+
finally
|
29
|
+
after_validation
|
30
|
+
before_validation])
|
22
31
|
|
23
32
|
def_node_matcher :namespace?, <<~PATTERN
|
24
33
|
(send nil? GRAPE_NAMESPACE_ALIAS ({sym | str} _))
|
@@ -0,0 +1,123 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Checks that the `:aggregate_failures` tag is only used on examples,
|
7
|
+
# not on example groups.
|
8
|
+
#
|
9
|
+
# The `:aggregate_failures` tag only works on individual examples (`it`, `specify`, etc.),
|
10
|
+
# not on example groups (`describe`, `context`, etc.).
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# # bad
|
14
|
+
# describe '#enabled?', :aggregate_failures do
|
15
|
+
# # ...
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# context 'when enabled', :aggregate_failures do
|
19
|
+
# # ...
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# # good
|
23
|
+
# it 'returns true', :aggregate_failures do
|
24
|
+
# # ...
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# specify 'the behavior', :aggregate_failures do
|
28
|
+
# # ...
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
class AggregateFailuresTag < Base
|
32
|
+
MSG = 'The `:aggregate_failures` tag should only be used on examples, not on example groups.'
|
33
|
+
|
34
|
+
EXAMPLE_METHODS = %i[
|
35
|
+
it
|
36
|
+
specify
|
37
|
+
example
|
38
|
+
scenario
|
39
|
+
its
|
40
|
+
fit
|
41
|
+
fspecify
|
42
|
+
fexample
|
43
|
+
fscenario
|
44
|
+
focus
|
45
|
+
xit
|
46
|
+
xspecify
|
47
|
+
xexample
|
48
|
+
xscenario
|
49
|
+
skip
|
50
|
+
pending
|
51
|
+
].freeze
|
52
|
+
|
53
|
+
RSPEC_METHODS = %i[
|
54
|
+
describe
|
55
|
+
context
|
56
|
+
feature
|
57
|
+
example_group
|
58
|
+
xdescribe
|
59
|
+
fdescribe
|
60
|
+
it
|
61
|
+
specify
|
62
|
+
example
|
63
|
+
scenario
|
64
|
+
its
|
65
|
+
fit
|
66
|
+
fspecify
|
67
|
+
fexample
|
68
|
+
fscenario
|
69
|
+
focus
|
70
|
+
xit
|
71
|
+
xspecify
|
72
|
+
xexample
|
73
|
+
xscenario
|
74
|
+
skip
|
75
|
+
pending
|
76
|
+
].freeze
|
77
|
+
|
78
|
+
def on_block(node)
|
79
|
+
return unless rspec_block?(node)
|
80
|
+
return unless aggregate_failures_tag?(node)
|
81
|
+
return if example_method?(node)
|
82
|
+
|
83
|
+
# Create a range that includes the method call up to and including the 'do' keyword
|
84
|
+
send_node = node.send_node
|
85
|
+
range = send_node.source_range.join(node.loc.begin)
|
86
|
+
add_offense(range)
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def rspec_block?(node)
|
92
|
+
send_node = node.send_node
|
93
|
+
return false unless send_node
|
94
|
+
return false unless send_node.send_type?
|
95
|
+
|
96
|
+
RSPEC_METHODS.include?(send_node.method_name)
|
97
|
+
end
|
98
|
+
|
99
|
+
def example_method?(node)
|
100
|
+
send_node = node.send_node
|
101
|
+
return false unless send_node
|
102
|
+
|
103
|
+
EXAMPLE_METHODS.include?(send_node.method_name)
|
104
|
+
end
|
105
|
+
|
106
|
+
def aggregate_failures_tag?(node)
|
107
|
+
send_node = node.send_node
|
108
|
+
return false unless send_node
|
109
|
+
|
110
|
+
send_node.arguments.any? do |arg|
|
111
|
+
if arg.sym_type? && arg.value == :aggregate_failures
|
112
|
+
true
|
113
|
+
elsif arg.hash_type?
|
114
|
+
arg.pairs.any? { |pair| pair.key.sym_type? && pair.key.value == :aggregate_failures }
|
115
|
+
else
|
116
|
+
false
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -7,7 +7,7 @@ module RuboCop
|
|
7
7
|
module Helpers
|
8
8
|
NODE_MATCHERS = lambda do
|
9
9
|
def_node_matcher :sidekiq_include?, <<~PATTERN
|
10
|
-
(send nil? :include (const (const nil? :Sidekiq) :Worker))
|
10
|
+
(send nil? :include (const (const {nil? cbase} :Sidekiq) {:Worker :Job}))
|
11
11
|
PATTERN
|
12
12
|
|
13
13
|
def_node_matcher :includes_sidekiq?, <<~PATTERN
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'helpers'
|
4
|
+
|
5
|
+
module RuboCop
|
6
|
+
module Cop
|
7
|
+
module Sidekiq
|
8
|
+
# This cop checks that Sidekiq job classes with "Job" suffix are placed in the
|
9
|
+
# `app/jobs` directory instead of `app/workers` directory.
|
10
|
+
# This follows the modern Sidekiq convention where jobs should be organized
|
11
|
+
# in the appropriate directory structure.
|
12
|
+
#
|
13
|
+
# @example
|
14
|
+
# # bad - Job class in app/workers directory
|
15
|
+
# # app/workers/my_job.rb
|
16
|
+
# class MyJob
|
17
|
+
# include Sidekiq::Job
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# # good - Job class in app/jobs directory
|
21
|
+
# # app/jobs/my_job.rb
|
22
|
+
# class MyJob
|
23
|
+
# include Sidekiq::Job
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# # good - Worker class can stay in app/workers (though not recommended)
|
27
|
+
# # app/workers/my_worker.rb
|
28
|
+
# class MyWorker
|
29
|
+
# include Sidekiq::Worker
|
30
|
+
# end
|
31
|
+
class JobLocation < Base
|
32
|
+
include Helpers
|
33
|
+
|
34
|
+
MSG = 'Job class with `Job` suffix should be placed in `app/jobs` directory instead of `app/workers`.'
|
35
|
+
|
36
|
+
def on_class(node)
|
37
|
+
return unless sidekiq_worker?(node)
|
38
|
+
|
39
|
+
class_name = extract_class_name(node)
|
40
|
+
return unless class_name
|
41
|
+
return unless class_name.end_with?('Job')
|
42
|
+
|
43
|
+
file_path = processed_source.buffer.name
|
44
|
+
return unless file_path.include?('app/workers/')
|
45
|
+
|
46
|
+
add_offense(node.children.first, message: MSG)
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def extract_class_name(node)
|
52
|
+
name_node = node.children.first
|
53
|
+
return unless name_node&.const_type?
|
54
|
+
|
55
|
+
# Get the last part of the constant name (e.g., "EmailJob" from "MyApp::EmailJob")
|
56
|
+
name_node.children.last.to_s
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'helpers'
|
4
|
+
|
5
|
+
module RuboCop
|
6
|
+
module Cop
|
7
|
+
module Sidekiq
|
8
|
+
# This cop checks that Sidekiq job class names end with "Job" instead of "Worker".
|
9
|
+
# Since Sidekiq 6.3, it is best practice to use "Job" terminology over "Worker".
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# # bad
|
13
|
+
# class MyWorker
|
14
|
+
# include Sidekiq::Job
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# class ProcessDataWorker
|
18
|
+
# include Sidekiq::Worker
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# # good
|
22
|
+
# class MyJob
|
23
|
+
# include Sidekiq::Job
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# class ProcessDataJob
|
27
|
+
# include Sidekiq::Job
|
28
|
+
# end
|
29
|
+
class JobNaming < Base
|
30
|
+
include Helpers
|
31
|
+
|
32
|
+
MSG = 'Job class name should end with `Job` instead of `Worker`.'
|
33
|
+
|
34
|
+
def_node_matcher :class_name, <<~PATTERN
|
35
|
+
(class (const _ $_) ...)
|
36
|
+
PATTERN
|
37
|
+
|
38
|
+
def on_class(node)
|
39
|
+
return unless sidekiq_worker?(node)
|
40
|
+
|
41
|
+
class_name = extract_class_name(node)
|
42
|
+
return unless class_name
|
43
|
+
return unless class_name.end_with?('Worker')
|
44
|
+
|
45
|
+
add_offense(node.children.first, message: MSG)
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def extract_class_name(node)
|
51
|
+
name_node = node.children.first
|
52
|
+
return unless name_node&.const_type?
|
53
|
+
|
54
|
+
# Get the last part of the constant name (e.g., "EmailWorker" from "MyApp::EmailWorker")
|
55
|
+
name_node.children.last.to_s
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'helpers'
|
4
|
+
|
5
|
+
module RuboCop
|
6
|
+
module Cop
|
7
|
+
module Sidekiq
|
8
|
+
# This cop checks for the use of `Sidekiq::Worker` and suggests using `Sidekiq::Job` instead.
|
9
|
+
# Since Sidekiq 6.3, it is best practice to use `Sidekiq::Job` over `Sidekiq::Worker`.
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# # bad
|
13
|
+
# class MyWorker
|
14
|
+
# include Sidekiq::Worker
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# # good
|
18
|
+
# class MyJob
|
19
|
+
# include Sidekiq::Job
|
20
|
+
# end
|
21
|
+
class PreferJob < Base
|
22
|
+
extend AutoCorrector
|
23
|
+
|
24
|
+
MSG = 'Prefer `Sidekiq::Job` over `Sidekiq::Worker`.'
|
25
|
+
|
26
|
+
def_node_matcher :sidekiq_worker_include?, <<~PATTERN
|
27
|
+
(send nil? :include (const (const {nil? cbase} :Sidekiq) :Worker))
|
28
|
+
PATTERN
|
29
|
+
|
30
|
+
def on_send(node)
|
31
|
+
return unless sidekiq_worker_include?(node)
|
32
|
+
|
33
|
+
add_offense(node, message: MSG) do |corrector|
|
34
|
+
corrector.replace(node.arguments.first, 'Sidekiq::Job')
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubocop-petal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jean-Francis Bastien
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
11
|
+
date: 2025-09-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: lint_roller
|
@@ -145,6 +145,7 @@ files:
|
|
145
145
|
- lib/rubocop/cop/rspec/aggregate_examples/matchers_with_side_effects.rb
|
146
146
|
- lib/rubocop/cop/rspec/aggregate_examples/metadata_helpers.rb
|
147
147
|
- lib/rubocop/cop/rspec/aggregate_examples/node_matchers.rb
|
148
|
+
- lib/rubocop/cop/rspec/aggregate_failures_tag.rb
|
148
149
|
- lib/rubocop/cop/rspec/chewy_strategy.rb
|
149
150
|
- lib/rubocop/cop/rspec/create_list_max.rb
|
150
151
|
- lib/rubocop/cop/rspec/json_response.rb
|
@@ -155,9 +156,12 @@ files:
|
|
155
156
|
- lib/rubocop/cop/sidekiq/const_argument.rb
|
156
157
|
- lib/rubocop/cop/sidekiq/date_time_argument.rb
|
157
158
|
- lib/rubocop/cop/sidekiq/helpers.rb
|
159
|
+
- lib/rubocop/cop/sidekiq/job_location.rb
|
160
|
+
- lib/rubocop/cop/sidekiq/job_naming.rb
|
158
161
|
- lib/rubocop/cop/sidekiq/keyword_arguments.rb
|
159
162
|
- lib/rubocop/cop/sidekiq/no_nil_return.rb
|
160
163
|
- lib/rubocop/cop/sidekiq/perform_inline.rb
|
164
|
+
- lib/rubocop/cop/sidekiq/prefer_job.rb
|
161
165
|
- lib/rubocop/cop/sidekiq/symbol_argument.rb
|
162
166
|
- lib/rubocop/petal.rb
|
163
167
|
- lib/rubocop/petal/plugin.rb
|