sevencop 0.31.1 → 0.32.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fc9eabfebd03bc54220aefb905dcc084374a282323a47907cbd05b7bd03df7ae
4
- data.tar.gz: b27b429ddbdfa4324f2bb929fbd84622265133a78a5045cab24ac20171c62ae3
3
+ metadata.gz: b73ab476e9b75a7c542283153fb21a6e34bc065305f174ad7fc360d8d4fe83ab
4
+ data.tar.gz: 36704b1877d0042042c91112699c201566a60bfc84e9bea4eb00824f910d6516
5
5
  SHA512:
6
- metadata.gz: e9667ad3506390f48001dc07e16faa48c07eab28afb91f06d5406043481a0c7637fb789e2718b0f7c3414a6666b8f7cda70c950eb4b40c11217629748fc85880
7
- data.tar.gz: 799f7f8cd175b53edf5804b507e954834e030c5973887b8b148ea803b0ace967e60c181bbf4f212386607eff838371cfccb8d1d255b5e2414b0a6fc9cfccf746
6
+ metadata.gz: b6d0f76043cf888387a230e1de66233a0ba68be0b647883bd8dac259f7cd7c97b504a3ce24577a14fd15fc590f146e17ff605223e2616e6c13992ec4e9a855d0
7
+ data.tar.gz: ac8f462e97a095a80c612318d9eb69373c0b3c9ce11a3fc49c8143ba92d40adcdfc2279b6ad0edb0eaf07a6c12ac500a8090b12969feee0529ec91c981a1a72f
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- sevencop (0.31.1)
4
+ sevencop (0.32.0)
5
5
  activesupport
6
6
  rubocop
7
7
 
data/README.md CHANGED
@@ -40,6 +40,7 @@ Note that all cops are `Enabled: false` by default.
40
40
  - [Sevencop/RailsBelongsToOptional](lib/rubocop/cop/sevencop/rails_belongs_to_optional.rb)
41
41
  - [Sevencop/RailsDateAndTimeCalculation](lib/rubocop/cop/sevencop/rails_date_and_time_calculation.rb)
42
42
  - [Sevencop/RailsOrderField](lib/rubocop/cop/sevencop/rails_order_field.rb)
43
+ - [Sevencop/RailsOrderFieldInOrderOf](lib/rubocop/cop/sevencop/rails_order_field_in_order_of.rb)
43
44
  - [Sevencop/RailsSpecificActionName](lib/rubocop/cop/sevencop/rails_specific_action_name.rb)
44
45
  - [Sevencop/RailsUniquenessValidatorExplicitCaseSensitivity](lib/rubocop/cop/sevencop/rails_uniqueness_validator_explicit_case_sensitivity.rb)
45
46
  - [Sevencop/RailsWhereNot](lib/rubocop/cop/sevencop/rails_where_not.rb)
data/config/default.yml CHANGED
@@ -7,13 +7,13 @@ Sevencop/AutoloadOrdered:
7
7
 
8
8
  Sevencop/ConstantBase:
9
9
  Description: |
10
- Remove unnecessary `::` prefix from constant.
10
+ Avoid unnecessary `::` prefix on constant.
11
11
  Enabled: false
12
12
  VersionAdded: '0.31'
13
13
 
14
14
  Sevencop/FactoryBotAssociationOption:
15
15
  Description: |
16
- Remove redundant options from FactoryBot associations.
16
+ Avoid redundant options on FactoryBot associations.
17
17
  Enabled: false
18
18
  VersionAdded: '0.21'
19
19
 
@@ -95,6 +95,12 @@ Sevencop/RailsOrderField:
95
95
  Safe: false
96
96
  VersionAdded: '0.4'
97
97
 
98
+ Sevencop/RailsOrderFieldInOrderOf:
99
+ Description: |
100
+ Prefer `in_order_of` to MySQL `FIELD` function.
101
+ Enabled: false
102
+ VersionAdded: '0.32'
103
+
98
104
  Sevencop/RailsSpecificActionName:
99
105
  Description: |
100
106
  Use only specific action names.
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Sevencop
6
- # Remove unnecessary `::` prefix from constant.
6
+ # Avoid unnecessary `::` prefix on constant.
7
7
  #
8
8
  # @example
9
9
  # # bad
@@ -23,18 +23,18 @@ module RuboCop
23
23
  # end
24
24
  #
25
25
  # # good
26
- # class Klass
26
+ # class A
27
27
  # ::Const
28
28
  # end
29
29
  #
30
30
  # # good
31
- # class module
31
+ # class A
32
32
  # ::Const
33
33
  # end
34
34
  class ConstantBase < Base
35
35
  extend AutoCorrector
36
36
 
37
- MSG = 'Remove unnecessary `::` prefix from constant.'
37
+ MSG = 'Avoid unnecessary `::` prefix on constant.'
38
38
 
39
39
  # @param node [RuboCop::AST::CbaseNode]
40
40
  # @return [void]
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Sevencop
6
- # Remove redundant options from FactoryBot associations.
6
+ # Avoid redundant options on FactoryBot associations.
7
7
  #
8
8
  # @example
9
9
  # # bad
@@ -16,7 +16,7 @@ module RuboCop
16
16
 
17
17
  include RangeHelp
18
18
 
19
- MSG = 'Remove redundant options from FactoryBot associations.'
19
+ MSG = 'Avoid redundant options on FactoryBot associations.'
20
20
 
21
21
  RESTRICT_ON_SEND = %i[association].freeze
22
22
 
@@ -0,0 +1,316 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Sevencop
6
+ # Prefer `in_order_of` to MySQL `FIELD` function.
7
+ #
8
+ # @example
9
+ # # bad
10
+ # order('FIELD(id, 1, 2, 3)')
11
+ #
12
+ # # good
13
+ # in_order_of(:id, [1, 2, 3])
14
+ #
15
+ # # bad
16
+ # order(Arel.sql('FIELD(id, 1, 2, 3)'))
17
+ #
18
+ # # good
19
+ # in_order_of(:id, [1, 2, 3])
20
+ #
21
+ # # bad
22
+ # order('FIELD(id, 1, 2, 3) DESC')
23
+ #
24
+ # # good
25
+ # in_order_of(:id, [1, 2, 3]).reverse_order
26
+ #
27
+ # # bad
28
+ # order("FIELD(id, #{ids.join(', ')})")
29
+ #
30
+ # # good
31
+ # in_order_of(:id, ids)
32
+ class RailsOrderFieldInOrderOf < Base
33
+ extend AutoCorrector
34
+
35
+ REGEXP_FIELD_DSTR_HEAD = /
36
+ \A
37
+ \s*
38
+ field\(
39
+ \s*
40
+ (?<column_name>\w+)
41
+ ,\s*
42
+ \z
43
+ /ix.freeze
44
+
45
+ REGEXP_FIELD_DSTR_TAIL = /
46
+ \A
47
+ \s*
48
+ \)
49
+ \s*
50
+ (?:
51
+ \s+
52
+ (?<order>asc|desc)
53
+ )?
54
+ \z
55
+ /ix.freeze
56
+
57
+ REGEXP_FIELD_STR = /
58
+ \A
59
+ \s*
60
+ field\(
61
+ \s*
62
+ (?<column_name>\w+)
63
+ ,\s*
64
+ (?<values>.+)
65
+ \s*
66
+ \)
67
+ (?:
68
+ \s+
69
+ (?<order>asc|desc)
70
+ )?
71
+ \s*
72
+ \z
73
+ /ix.freeze
74
+
75
+ MSG = 'Prefer `in_order_of` to MySQL `FIELD` function.'
76
+
77
+ RESTRICT_ON_SEND = %i[
78
+ order
79
+ reorder
80
+ ].freeze
81
+
82
+ # @param node [RuboCop::AST::SendNode]
83
+ # @return [void]
84
+ def on_send(node)
85
+ return unless bad?(node)
86
+
87
+ add_offense(node) do |corrector|
88
+ autocorrect(corrector, node)
89
+ end
90
+ end
91
+
92
+ private
93
+
94
+ # @!method match_arel_sql_field?(node)
95
+ # @param node [RuboCop::AST::Node, nil]
96
+ # @return [Boolean]
97
+ def_node_matcher :match_arel_sql_field?, <<~PATTERN
98
+ (send
99
+ (const {nil? cbase} :Arel)
100
+ :sql
101
+ #match_field?
102
+ )
103
+ PATTERN
104
+
105
+ # @!method match_field?(node)
106
+ # @param node [RuboCop::AST::Node, nil]
107
+ # @return [Boolean]
108
+ def_node_matcher :match_field?, <<~PATTERN
109
+ {
110
+ #match_field_dstr?
111
+ #match_field_str?
112
+ }
113
+ PATTERN
114
+
115
+ # @!method match_field_dstr_body?(node)
116
+ # @param node [RuboCop::AST::Node, nil]
117
+ # @return [Boolean]
118
+ def_node_matcher :match_field_dstr_body?, <<~PATTERN
119
+ (begin
120
+ (send
121
+ _
122
+ :join
123
+ (str #match_field_dstr_body_separator?)
124
+ )
125
+ )
126
+ PATTERN
127
+
128
+ # @!method match_order_with_field?(node)
129
+ # @param node [RuboCop::AST::Node, nil]
130
+ # @return [Boolean]
131
+ def_node_matcher :match_order_with_field?, <<~PATTERN
132
+ (send
133
+ _
134
+ _
135
+ {
136
+ #match_arel_sql_field?
137
+ #match_field?
138
+ }
139
+ ...
140
+ )
141
+ PATTERN
142
+ alias bad? match_order_with_field?
143
+
144
+ # @param corrector [RuboCop::Cop::Corrector]
145
+ # @param node [RuboCop::AST::SendNode]
146
+ def autocorrect(
147
+ corrector,
148
+ node
149
+ )
150
+ corrector.replace(
151
+ node.location.expression.with(
152
+ begin_pos: node.location.selector.begin_pos
153
+ ),
154
+ format_in_order_of(node)
155
+ )
156
+ end
157
+
158
+ # @param node [RuboCop::AST::SendNode]
159
+ # @return [String, nil]
160
+ def extract_column_name(node)
161
+ if node.each_descendant(:dstr).any?
162
+ extract_column_name_from_dstr(node)
163
+ else
164
+ extract_column_name_from_str(node)
165
+ end
166
+ end
167
+
168
+ # @param node [RuboCop::AST::SendNode]
169
+ # @return [String]
170
+ def extract_column_name_from_dstr(node)
171
+ node.each_descendant(:str).first.value[REGEXP_FIELD_DSTR_HEAD, :column_name]
172
+ end
173
+
174
+ # @param node [RuboCop::AST::SendNode]
175
+ # @return [String]
176
+ def extract_column_name_from_str(node)
177
+ node.each_descendant(:str).first.value[REGEXP_FIELD_STR, :column_name]
178
+ end
179
+
180
+ # @param node [RuboCop::AST::SendNode]
181
+ # @return [String, nil]
182
+ def extract_order_from_dstr(node)
183
+ node.each_descendant(:str).to_a.last.value[REGEXP_FIELD_DSTR_TAIL, :order]
184
+ end
185
+
186
+ # @param node [RuboCop::AST::SendNode]
187
+ # @return [String, nil]
188
+ def extract_order_from_str(node)
189
+ node.each_descendant(:str).first.value[REGEXP_FIELD_STR, :order]
190
+ end
191
+
192
+ # @param node [RuboCop::AST::SendNode]
193
+ # @return [String, nil]
194
+ def extract_rest_order(node)
195
+ rest_order_arguments = node.arguments[1..]
196
+ return if rest_order_arguments.empty?
197
+
198
+ format(
199
+ '.order(%<rest_order_arguments>s)',
200
+ rest_order_arguments: rest_order_arguments.map(&:source).join(', ')
201
+ )
202
+ end
203
+
204
+ # @param node [RuboCop::AST::SendNode]
205
+ # @return [String, nil]
206
+ def extract_reverse_order_from_dstr(node)
207
+ '.reverse_order' if match_desc_on_dstr?(node)
208
+ end
209
+
210
+ # @param node [RuboCop::AST::SendNode]
211
+ # @return [String, nil]
212
+ def extract_reverse_order_from_str(node)
213
+ '.reverse_order' if match_desc_on_str?(node)
214
+ end
215
+
216
+ # @param node [RuboCop::AST::SendNode]
217
+ # @return [String]
218
+ def extract_values_from_dstr(node)
219
+ node.each_descendant.find do |descendant|
220
+ match_field_dstr_body?(descendant)
221
+ end.children.first.receiver.source
222
+ end
223
+
224
+ # @param node [RuboCop::AST::SendNode]
225
+ # @return [String]
226
+ def extract_values_from_str(node)
227
+ format(
228
+ '[%<values>s]',
229
+ values: node.each_descendant(:str).first.value[REGEXP_FIELD_STR, :values].split(',').map(&:strip).join(', ')
230
+ )
231
+ end
232
+
233
+ # @param node [RuboCop::AST::SendNode]
234
+ # @return [String]
235
+ def format_in_order_of(node)
236
+ if node.each_descendant(:dstr).any?
237
+ format_in_order_of_on_dstr(node)
238
+ else
239
+ format_in_order_of_on_str(node)
240
+ end
241
+ end
242
+
243
+ # @param node [RuboCop::AST::SendNode]
244
+ # @return [String]
245
+ def format_in_order_of_on_dstr(node)
246
+ format(
247
+ 'in_order_of(:%<column_name>s, %<values>s)%<reverse_order>s%<rest_order>s',
248
+ column_name: extract_column_name_from_dstr(node),
249
+ rest_order: extract_rest_order(node),
250
+ reverse_order: extract_reverse_order_from_dstr(node),
251
+ values: extract_values_from_dstr(node)
252
+ )
253
+ end
254
+
255
+ # @param node [RuboCop::AST::SendNode]
256
+ # @return [String]
257
+ def format_in_order_of_on_str(node)
258
+ format(
259
+ 'in_order_of(:%<column_name>s, %<values>s)%<reverse_order>s%<rest_order>s',
260
+ column_name: extract_column_name_from_str(node),
261
+ rest_order: extract_rest_order(node),
262
+ reverse_order: extract_reverse_order_from_str(node),
263
+ values: extract_values_from_str(node)
264
+ )
265
+ end
266
+
267
+ # @param node [RuboCop::AST::SendNode]
268
+ # @return [Boolean]
269
+ def match_desc_on_dstr?(node)
270
+ extract_order_from_dstr(node).to_s.casecmp('desc').zero?
271
+ end
272
+
273
+ # @param node [RuboCop::AST::SendNode]
274
+ # @return [Boolean]
275
+ def match_desc_on_str?(node)
276
+ extract_order_from_str(node).to_s.casecmp('desc').zero?
277
+ end
278
+
279
+ # @param node [RuboCop::AST::Node]
280
+ # @return [Boolean]
281
+ def match_field_dstr?(node)
282
+ node.dstr_type? &&
283
+ node.children.size == 3 &&
284
+ match_field_dstr_head?(node.children[0]) &&
285
+ match_field_dstr_body?(node.children[1]) &&
286
+ match_field_dstr_tail?(node.children[2])
287
+ end
288
+
289
+ # @param separator [String]
290
+ # @return [Boolean]
291
+ def match_field_dstr_body_separator?(separator)
292
+ separator.strip == ','
293
+ end
294
+
295
+ # @param node [RuboCop::AST::Node]
296
+ # @return [Boolean]
297
+ def match_field_dstr_head?(node)
298
+ node&.str_type? &&
299
+ node.value.match?(REGEXP_FIELD_DSTR_HEAD)
300
+ end
301
+
302
+ def match_field_dstr_tail?(node)
303
+ node&.str_type? &&
304
+ node.value.match?(REGEXP_FIELD_DSTR_TAIL)
305
+ end
306
+
307
+ # @param node [RuboCop::AST::Node]
308
+ # @return [Boolean]
309
+ def match_field_str?(node)
310
+ node.str_type? &&
311
+ node.value.match?(REGEXP_FIELD_STR)
312
+ end
313
+ end
314
+ end
315
+ end
316
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sevencop
4
- VERSION = '0.31.1'
4
+ VERSION = '0.32.0'
5
5
  end
data/lib/sevencop.rb CHANGED
@@ -16,6 +16,7 @@ require_relative 'rubocop/cop/sevencop/method_definition_ordered'
16
16
  require_relative 'rubocop/cop/sevencop/rails_belongs_to_optional'
17
17
  require_relative 'rubocop/cop/sevencop/rails_date_and_time_calculation'
18
18
  require_relative 'rubocop/cop/sevencop/rails_order_field'
19
+ require_relative 'rubocop/cop/sevencop/rails_order_field_in_order_of'
19
20
  require_relative 'rubocop/cop/sevencop/rails_specific_action_name'
20
21
  require_relative 'rubocop/cop/sevencop/rails_uniqueness_validator_explicit_case_sensitivity'
21
22
  require_relative 'rubocop/cop/sevencop/rails_where_not'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sevencop
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.31.1
4
+ version: 0.32.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryo Nakamura
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-11-15 00:00:00.000000000 Z
11
+ date: 2022-11-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -68,6 +68,7 @@ files:
68
68
  - lib/rubocop/cop/sevencop/rails_belongs_to_optional.rb
69
69
  - lib/rubocop/cop/sevencop/rails_date_and_time_calculation.rb
70
70
  - lib/rubocop/cop/sevencop/rails_order_field.rb
71
+ - lib/rubocop/cop/sevencop/rails_order_field_in_order_of.rb
71
72
  - lib/rubocop/cop/sevencop/rails_specific_action_name.rb
72
73
  - lib/rubocop/cop/sevencop/rails_uniqueness_validator_explicit_case_sensitivity.rb
73
74
  - lib/rubocop/cop/sevencop/rails_where_not.rb