rubocop-petal 1.4.0 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 99a53e19d1caafc491f963ad3a723fb1b06f9e15fc9d0914db50287c68af1dd6
4
- data.tar.gz: c1c37cbc85d3c4e56bdd2fffa928f8ce7f16db9afa5541014275a519d75146a5
3
+ metadata.gz: 9f52260437fb7b62b35bc5ca331edb0d443b28b2b45ea319c3bfc0aa13561d9a
4
+ data.tar.gz: 7180f8ef26b11cd926c56dd7cb79117e67ebfee8afff1a1baf5ff836b3a6c047
5
5
  SHA512:
6
- metadata.gz: 862c765c3e4c638372c04b441d569d25b260f0333e887cb25b76064ac82214173e4367b0225e4023b9ee4de9f804bb57b224bc524fb4beec46b9eff4bde8546d
7
- data.tar.gz: 263fe7fd0120e188d681dd68f7f44533e01c32d0a71596bc064781628175c7a40f0acea5cb22ec00707a8a67917fdb1dda1ee6811fea92ebf1047887346da20a
6
+ metadata.gz: c7752ae4a230a0a6d270e067712f9557d75705e38638c5a1de4de6ea04c2a2109bddd90ec38b85d9f796dc4fb42757550d0f2d7a9ea2107a1a7b5b7302c5bdc1
7
+ data.tar.gz: 997f99882b2203079aaff70c517709ce355bbcdf2a1709a413eed9f5d5aacce47949e224f0c29377133f6a05eac2d420c18a91298037ce698a16d99e67491a1d
data/config/default.yml CHANGED
@@ -4,6 +4,10 @@ Chewy/FieldType:
4
4
  Include:
5
5
  - app/chewy/**/*
6
6
 
7
+ Chewy/UpdateIndexArgument:
8
+ Description: 'Prevent single expression in update_index block.'
9
+ Enabled: true
10
+
7
11
  Grape/PreferNamespace:
8
12
  Description: 'Prevent usage of namespace aliases.'
9
13
  Enabled: true
@@ -146,6 +150,11 @@ Sidekiq/NoNilReturn:
146
150
  Include:
147
151
  - app/workers/**/*
148
152
 
153
+ Sidekiq/PerformInline:
154
+ Description: 'Suggest to use `perform_inline` instead of `new.perform` for Sidekiq workers.'
155
+ Enabled: true
156
+
149
157
  Sidekiq/SymbolArgument:
150
158
  Description: "Prevent passing keywords arguments in worker's perform method"
151
159
  Enabled: true
160
+ SafeAutoCorrect: false
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Chewy
6
+ # This cop checks for the use of block with single expression in `update_index` method
7
+ # and suggests to use method symbol as second argument instead of block.
8
+ #
9
+ # # bad
10
+ # update_index('index_name') { self }
11
+ #
12
+ # # good
13
+ # update_index('index_name', :self)
14
+ #
15
+ class UpdateIndexArgument < Base
16
+ extend AutoCorrector
17
+
18
+ MSG = 'Use method symbol as second argument instead of block.'
19
+
20
+ RESTRICT_ON_SEND = %i[update_index].freeze
21
+
22
+ # @!method block_with_single_expression?(node)
23
+ def_node_matcher :block_with_single_expression?, <<~PATTERN
24
+ (block
25
+ (send nil? :update_index (str _) $...)
26
+ (args)
27
+ $...)
28
+ PATTERN
29
+
30
+ def on_block(node)
31
+ block_with_single_expression?(node) do |existing_args, method_name|
32
+ return if method_name.last.children.compact.size > 1
33
+
34
+ method_name = method_name.first.source
35
+ add_offense(node.loc.expression) do |corrector|
36
+ corrector.replace(node.loc.expression, corrected_code(node, existing_args, method_name))
37
+ end
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def corrected_code(node, existing_args, method_name)
44
+ method_call = node.children[0]
45
+ index_name = method_call.children[2].source
46
+
47
+ if existing_args.any?
48
+ "update_index(#{index_name}, :#{method_name}, #{existing_args.map(&:source).join(', ')})"
49
+ else
50
+ "update_index(#{index_name}, :#{method_name})"
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -5,7 +5,7 @@ module RuboCop
5
5
  module Rails
6
6
  # Disallow ActiveRecord calls that pass interpolated or added strings as an argument.
7
7
  # https://github.com/airbnb/ruby/blob/12435e8136d2adf710de999bc0f6bef01215df2c/rubocop-airbnb/lib/rubocop/cop/airbnb/risky_activerecord_invocation.rb
8
- class RiskyActiverecordInvocation < Cop
8
+ class RiskyActiverecordInvocation < Base
9
9
  VULNERABLE_AR_METHODS = %i[
10
10
  delete_all
11
11
  destroy_all
@@ -6,7 +6,7 @@ module RuboCop
6
6
  module Cop
7
7
  module RSpec
8
8
  # RSpec public API methods that are commonly used in cops
9
- class AggregateExamples < ::RuboCop::Cop::Cop
9
+ class AggregateExamples < Base
10
10
  module Language
11
11
  RSPEC = '{(const {nil? cbase} :RSpec) nil?}'
12
12
 
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module RSpec
6
- class AggregateExamples < ::RuboCop::Cop::Cop
6
+ class AggregateExamples < Base
7
7
  # @internal Support methods for keeping newlines around examples.
8
8
  module LineRangeHelpers
9
9
  include RangeHelp
@@ -5,7 +5,7 @@ require_relative 'language'
5
5
  module RuboCop
6
6
  module Cop
7
7
  module RSpec
8
- class AggregateExamples < ::RuboCop::Cop::Cop
8
+ class AggregateExamples < Base
9
9
  # When aggregated, the expectations will fail when not supposed to or
10
10
  # have a risk of not failing when expected to. One example is
11
11
  # `validate_presence_of :comment` as it leaves an empty comment after
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module RSpec
6
- class AggregateExamples < ::RuboCop::Cop::Cop
6
+ class AggregateExamples < Base
7
7
  # @internal
8
8
  # Support methods for example metadata.
9
9
  # Examples with similar metadata are grouped.
@@ -5,7 +5,7 @@ require_relative 'language'
5
5
  module RuboCop
6
6
  module Cop
7
7
  module RSpec
8
- class AggregateExamples < ::RuboCop::Cop::Cop
8
+ class AggregateExamples < Base
9
9
  # @internal
10
10
  # Node matchers and searchers.
11
11
  module NodeMatchers
@@ -109,10 +109,11 @@ module RuboCop
109
109
  # expect(number).to be_odd
110
110
  # end
111
111
  #
112
- class AggregateExamples < ::RuboCop::Cop::Cop
112
+ class AggregateExamples < Base
113
113
  include LineRangeHelpers
114
114
  include MetadataHelpers
115
115
  include NodeMatchers
116
+ extend AutoCorrector
116
117
 
117
118
  # Methods from the following modules override and extend methods of this
118
119
  # class, extracting specific behavior.
@@ -124,25 +125,21 @@ module RuboCop
124
125
  example_group_with_several_examples(node) do |all_examples|
125
126
  example_clusters(all_examples).each_value do |examples|
126
127
  examples[1..].each do |example|
127
- add_offense(example,
128
- location: :expression,
129
- message: message_for(example, examples[0]))
128
+ add_offense(example, message: message_for(example, examples[0])) do |corrector|
129
+ clusters = example_clusters_for_autocorrect(example)
130
+ autocorrect(corrector, clusters)
131
+ end
130
132
  end
131
133
  end
132
134
  end
133
135
  end
134
136
 
135
- def autocorrect(example_node)
136
- clusters = example_clusters_for_autocorrect(example_node)
137
- return if clusters.empty?
138
-
139
- lambda do |corrector|
140
- clusters.each do |metadata, examples|
141
- range = range_for_replace(examples)
142
- replacement = aggregated_example(examples, metadata)
143
- corrector.replace(range, replacement)
144
- examples[1..].map { |example| drop_example(corrector, example) }
145
- end
137
+ def autocorrect(corrector, clusters)
138
+ clusters.each do |metadata, examples|
139
+ range = range_for_replace(examples)
140
+ replacement = aggregated_example(examples, metadata)
141
+ corrector.replace(range, replacement)
142
+ examples[1..].map { |example| drop_example(corrector, example) }
146
143
  end
147
144
  end
148
145
 
@@ -25,8 +25,8 @@ module RuboCop
25
25
 
26
26
  include Helpers
27
27
 
28
- MSG = 'Objects are not Sidekiq-serializable.'
29
- MSG_SELF = '`self` is not Sidekiq-serializable.'
28
+ MSG = 'Objects are not native JSON types.'
29
+ MSG_SELF = '`self` is not a native JSON type.'
30
30
 
31
31
  def_node_matcher :initializer?, <<~PATTERN
32
32
  (send const :new)
@@ -34,7 +34,7 @@ module RuboCop
34
34
  # # good
35
35
  # MyWorker.perform_async(Time.now.mday)
36
36
  #
37
- class DateTimeArgument < ::RuboCop::Cop::Cop
37
+ class DateTimeArgument < Base
38
38
  DURATION_METHODS = %i[
39
39
  second
40
40
  seconds
@@ -61,8 +61,8 @@ module RuboCop
61
61
 
62
62
  include Helpers
63
63
 
64
- DURATION_MSG = 'Durations are not Sidekiq-serializable; use the integer instead.'
65
- MSG = 'Date/Time objects are not Sidekiq-serializable; convert to integers or strings instead.'
64
+ DURATION_MSG = 'Durations are not native JSON types; use the integer instead.'
65
+ MSG = 'Date/Time objects are not native JSON types; convert to integers or strings instead.'
66
66
  ALLOWED_METHODS = %i[to_i to_s].freeze
67
67
 
68
68
  def_node_matcher :rational_literal?, <<~PATTERN
@@ -50,20 +50,49 @@ module RuboCop
50
50
  node.each_ancestor(:class, :block).detect { |anc| sidekiq_worker?(anc) }
51
51
  end
52
52
 
53
- def sidekiq_arguments(node)
53
+ def sidekiq_arguments(node, &block)
54
54
  return [] unless node.send_type? && (method_name = sidekiq_perform?(node))
55
+ return enum_for(:sidekiq_arguments, node) unless block
55
56
 
56
57
  # Drop the first argument for perform_at and perform_in
57
- expand_arguments(method_name == :perform_async ? node.arguments : node.arguments[1..])
58
+ expand_nodes(method_name == :perform_async ? node.arguments : node.arguments[1..], &block)
58
59
  end
59
60
 
60
- def expand_arguments(arguments)
61
- arguments.flat_map do |argument|
62
- if argument.array_type? || argument.hash_type?
63
- expand_arguments(argument.values)
64
- else
65
- argument
66
- end
61
+ def expand_nodes(nodes, &block)
62
+ return enum_for(:expand_nodes, nodes) unless block
63
+
64
+ nodes.each { |node| expand_node(node, &block) }
65
+ end
66
+
67
+ def expand_node(node, &block)
68
+ return enum_for(:expand_node, node) unless block
69
+
70
+ expand_hash_array_node(node, &block) || yield(node)
71
+ end
72
+
73
+ def expand_hash_array_node(node, &block)
74
+ expand_hash_node(node, &block) || expand_array_node(node, &block)
75
+ end
76
+
77
+ def expand_hash_node(node, &block)
78
+ return unless node.hash_type?
79
+ return enum_for(:expand_hash_node, node) unless block
80
+
81
+ node.pairs.each do |pair_node|
82
+ expand_hash_array_node(pair_node.key, &block) ||
83
+ expand_hash_array_node(pair_node.value, &block) ||
84
+ yield(pair_node)
85
+ end
86
+ end
87
+
88
+ def expand_array_node(node, &block)
89
+ return unless node.array_type?
90
+ return enum_for(:expand_array_node, node) unless block
91
+
92
+ if node.square_brackets?
93
+ expand_nodes(node.values, &block)
94
+ else
95
+ yield node
67
96
  end
68
97
  end
69
98
 
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Sidekiq
6
+ # Suggest to use `perform_inline` instead of `new.perform` for Sidekiq workers.
7
+ #
8
+ # @bad
9
+ # MyWorker.new.perform
10
+ #
11
+ # @good
12
+ # MyWorker.perform_inline
13
+ #
14
+ class PerformInline < Base
15
+ extend AutoCorrector
16
+ MSG = 'Use `perform_inline` instead of `new.perform`'
17
+
18
+ RESTRICT_ON_SEND = %i[perform].freeze
19
+
20
+ # @!method new_perform?(node)
21
+ def_node_matcher :new_perform?, <<~PATTERN
22
+ (send (send _ :new) :perform ...)
23
+ PATTERN
24
+
25
+ def on_send(node)
26
+ return unless new_perform?(node)
27
+
28
+ new_perform_node = node.source_range.with(
29
+ begin_pos: node.receiver.receiver.source_range.end_pos + 1,
30
+ end_pos: node.loc.selector.end_pos
31
+ )
32
+
33
+ add_offense(new_perform_node) do |corrector|
34
+ corrector.replace(new_perform_node, 'perform_inline')
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -14,17 +14,129 @@ module RuboCop
14
14
  # MyWorker.perform_async(:foo)
15
15
  #
16
16
  # # good
17
- # MyWorker.perform_async('foo')
17
+ # MyWorker.perform_async("foo")
18
+ #
19
+ # # bad
20
+ # MyWorker.perform_async(%i(foo))
21
+ #
22
+ # # good
23
+ # MyWorker.perform_async(%w(foo))
24
+ #
25
+ # # bad
26
+ # MyWorker.perform_async([:foo])
27
+ #
28
+ # # good
29
+ # MyWorker.perform_async(["foo"]))
30
+ #
31
+ # # bad
32
+ # MyWorker.perform_async(foo: 1)
33
+ #
34
+ # # good
35
+ # MyWorker.perform_async('foo' => 1)
36
+ #
37
+ # # bad
38
+ # MyWorker.perform_async('foo' => :baz)
39
+ #
40
+ # # good
41
+ # MyWorker.perform_async('foo' => "baz")
42
+ #
43
+ # # bad
44
+ # MyWorker.perform_async('foo' => [:bar]
45
+ #
46
+ # # good
47
+ # MyWorker.perform_async('foo' => ["baz"])
48
+ #
49
+ # # bad
50
+ # MyWorker.perform_async('foo' => %i(baz)
51
+ #
52
+ # # good
53
+ # MyWorker.perform_async('foo' => %w(baz))
54
+ #
55
+ # # bad
56
+ # MyWorker.perform_async('foo' => { bar: %i(baz) })
57
+ #
58
+ # # good
59
+ # MyWorker.perform_async('foo' => { bar: %w(baz) })
60
+ #
61
+ # # bad
62
+ # MyWorker.perform_async('foo' => { bar: [:baz]) })
63
+ #
64
+ # # good
65
+ # MyWorker.perform_async('foo' => { bar: ["baz"] })
66
+ #
18
67
  class SymbolArgument < Base
68
+ extend AutoCorrector
69
+
19
70
  include Helpers
20
71
 
21
- MSG = 'Symbols are not Sidekiq-serializable; use strings instead.'
72
+ MSG = 'Symbols are not native JSON types; use strings instead.'
22
73
 
23
74
  def on_send(node)
24
- sidekiq_arguments(node).select(&:sym_type?).each do |argument|
25
- add_offense(argument)
75
+ sidekiq_arguments(node)
76
+ .lazy
77
+ .select { |n| node_contains_symbol?(n) }
78
+ .each do |selected_node|
79
+ offense_data(selected_node) do |offense_node, replace_node, replace_value|
80
+ add_offense(offense_node) do |corrector|
81
+ corrector.replace(replace_node, replace_value)
82
+ end
83
+ end
26
84
  end
27
85
  end
86
+
87
+ private
88
+
89
+ def node_contains_symbol?(node)
90
+ node.sym_type? || symbol_percent_literal?(node) || pair_with_symbol?(node)
91
+ end
92
+
93
+ def symbol_percent_literal?(node)
94
+ node.array_type? && node.percent_literal?(:symbol)
95
+ end
96
+
97
+ def pair_with_symbol?(node)
98
+ node.pair_type? && (node.key.sym_type? || node.value.sym_type?)
99
+ end
100
+
101
+ def offense_data(node)
102
+ yield sym_replace_value(node) || array_replace_value(node) || pair_replace_value(node)
103
+ end
104
+
105
+ def sym_replace_value(node)
106
+ return unless node.sym_type?
107
+
108
+ [node, node, %("#{node.value}")]
109
+ end
110
+
111
+ def array_replace_value(node)
112
+ return unless node.array_type?
113
+
114
+ [node, node, "%w(#{node.values.map(&:value).join(' ')})"]
115
+ end
116
+
117
+ def pair_replace_value(node)
118
+ return unless node.pair_type?
119
+
120
+ pair_both_symbol(node) || pair_only_key_symbol(node) || pair_only_value_symbol(node)
121
+ end
122
+
123
+ def pair_both_symbol(node)
124
+ return unless node.key.sym_type? && node.value.sym_type?
125
+
126
+ [node, node, %("#{node.key.value}" => "#{node.value.value}")]
127
+ end
128
+
129
+ def pair_only_key_symbol(node)
130
+ return unless node.key.sym_type?
131
+
132
+ [node.key, node, %("#{node.key.value}" => #{node.value.source})]
133
+ end
134
+
135
+ def pair_only_value_symbol(node)
136
+ return unless node.value.sym_type?
137
+
138
+ [node.value, node.value, %("#{node.value.value}")]
139
+ end
28
140
  end
29
141
  end
30
142
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RuboCop
4
4
  module Petal
5
- VERSION = '1.4.0'
5
+ VERSION = '1.6.0'
6
6
  end
7
7
  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.0
4
+ version: 1.6.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: 2024-06-14 00:00:00.000000000 Z
11
+ date: 2025-01-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubocop
@@ -16,70 +16,70 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.59'
19
+ version: '1.70'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.59'
26
+ version: '1.70'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rubocop-factory_bot
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '2.24'
33
+ version: '2.26'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '2.24'
40
+ version: '2.26'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rubocop-performance
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '1.20'
47
+ version: '1.23'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '1.20'
54
+ version: '1.23'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rubocop-rails
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '2.23'
61
+ version: '2.28'
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '2.23'
68
+ version: '2.28'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rubocop-rspec
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '2.25'
75
+ version: '3.3'
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '2.25'
82
+ version: '3.3'
83
83
  description:
84
84
  email:
85
85
  - jfbastien@petalmd.com
@@ -96,6 +96,7 @@ files:
96
96
  - lib/rubocop-petal.rb
97
97
  - lib/rubocop/cop/chewy/field_type.rb
98
98
  - lib/rubocop/cop/chewy/reset_on_type.rb
99
+ - lib/rubocop/cop/chewy/update_index_argument.rb
99
100
  - lib/rubocop/cop/grape/helpers_include_module.rb
100
101
  - lib/rubocop/cop/grape/prefer_namespace.rb
101
102
  - lib/rubocop/cop/grape/unnecessary_namespace.rb
@@ -126,6 +127,7 @@ files:
126
127
  - lib/rubocop/cop/sidekiq/helpers.rb
127
128
  - lib/rubocop/cop/sidekiq/keyword_arguments.rb
128
129
  - lib/rubocop/cop/sidekiq/no_nil_return.rb
130
+ - lib/rubocop/cop/sidekiq/perform_inline.rb
129
131
  - lib/rubocop/cop/sidekiq/symbol_argument.rb
130
132
  - lib/rubocop/petal.rb
131
133
  - lib/rubocop/petal/inject.rb