sevencop 0.21.0 → 0.22.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/.rubocop.yml +6 -0
- data/Gemfile.lock +13 -1
- data/README.md +17 -4
- data/config/default.yml +134 -0
- data/lib/rubocop/cop/sevencop/factory_bot_association_option.rb +1 -1
- data/lib/rubocop/cop/sevencop/factory_bot_association_style.rb +31 -31
- data/lib/rubocop/cop/sevencop/rails_inferred_spec_type.rb +1 -1
- data/lib/rubocop/cop/sevencop/rails_migration_add_check_constraint.rb +111 -0
- data/lib/rubocop/cop/sevencop/rails_migration_add_column_with_default_value.rb +229 -0
- data/lib/rubocop/cop/sevencop/rails_migration_add_foreign_key.rb +166 -0
- data/lib/rubocop/cop/sevencop/rails_migration_add_index_concurrently.rb +164 -0
- data/lib/rubocop/cop/sevencop/rails_migration_batch_in_batches.rb +95 -0
- data/lib/rubocop/cop/sevencop/rails_migration_batch_in_transaction.rb +83 -0
- data/lib/rubocop/cop/sevencop/rails_migration_batch_with_throttling.rb +108 -0
- data/lib/rubocop/cop/sevencop/rails_migration_change_column.rb +113 -0
- data/lib/rubocop/cop/sevencop/rails_migration_change_column_null.rb +128 -0
- data/lib/rubocop/cop/sevencop/rails_migration_create_table_force.rb +89 -0
- data/lib/rubocop/cop/sevencop/rails_migration_jsonb.rb +131 -0
- data/lib/rubocop/cop/sevencop/rails_migration_remove_column.rb +258 -0
- data/lib/rubocop/cop/sevencop/rails_migration_rename_column.rb +81 -0
- data/lib/rubocop/cop/sevencop/rails_migration_rename_table.rb +79 -0
- data/lib/rubocop/cop/sevencop/rails_migration_reserved_word_mysql.rb +2 -19
- data/lib/rubocop/cop/sevencop/rails_migration_unique_index_columns_count.rb +92 -0
- data/lib/sevencop/config_loader.rb +11 -10
- data/lib/sevencop/cop_concerns/batch_processing.rb +32 -0
- data/lib/sevencop/cop_concerns/column_type_method.rb +26 -0
- data/lib/sevencop/cop_concerns/disable_ddl_transaction.rb +49 -0
- data/lib/sevencop/cop_concerns.rb +3 -0
- data/lib/sevencop/rubocop_extension.rb +6 -1
- data/lib/sevencop/version.rb +1 -1
- data/lib/sevencop.rb +15 -0
- data/sevencop.gemspec +1 -0
- metadata +34 -2
@@ -0,0 +1,258 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/inflector'
|
4
|
+
require 'pathname'
|
5
|
+
|
6
|
+
module RuboCop
|
7
|
+
module Cop
|
8
|
+
module Sevencop
|
9
|
+
# Make sure the column is already ignored by the running app before removing it.
|
10
|
+
#
|
11
|
+
# Active Record caches database columns at runtime, so if you drop a column, it can cause exceptions until your app reboots.
|
12
|
+
#
|
13
|
+
# @safety
|
14
|
+
# The logic to check if it is included in `ignored_columns` may fail.
|
15
|
+
#
|
16
|
+
# @example
|
17
|
+
# # bad
|
18
|
+
# class User < ApplicationRecord
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# class RemoveUsersSomeColumn < ActiveRecord::Migration[7.0]
|
22
|
+
# def change
|
23
|
+
# remove_column :users, :some_column
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# # good
|
28
|
+
# class User < ApplicationRecord
|
29
|
+
# self.ignored_columns += %w[some_column]
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# class RemoveUsersSomeColumn < ActiveRecord::Migration[7.0]
|
33
|
+
# def change
|
34
|
+
# remove_column :users, :some_column
|
35
|
+
# end
|
36
|
+
# end
|
37
|
+
class RailsMigrationRemoveColumn < RuboCop::Cop::Base
|
38
|
+
MSG = 'Make sure the column is already ignored by the running app before removing it.'
|
39
|
+
|
40
|
+
RESTRICT_ON_SEND = %i[
|
41
|
+
remove_column
|
42
|
+
].freeze
|
43
|
+
|
44
|
+
# @param node [RuboCop::AST::SendNode]
|
45
|
+
# @return [void]
|
46
|
+
def on_send(node)
|
47
|
+
return unless bad?(node)
|
48
|
+
|
49
|
+
add_offense(node)
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
# @!method ignored_columns?(node)
|
55
|
+
# @param node [RuboCop::AST::Node]
|
56
|
+
# @return [Boolean]
|
57
|
+
def_node_matcher :ignored_columns?, <<~PATTERN
|
58
|
+
(send
|
59
|
+
self
|
60
|
+
:ignored_columns
|
61
|
+
...
|
62
|
+
)
|
63
|
+
PATTERN
|
64
|
+
|
65
|
+
# @!method remove_column?(node)
|
66
|
+
# @param node [RuboCop::AST::SendNode]
|
67
|
+
# @return [Boolean]
|
68
|
+
def_node_matcher :remove_column?, <<~PATTERN
|
69
|
+
(send
|
70
|
+
nil?
|
71
|
+
:remove_column
|
72
|
+
...
|
73
|
+
)
|
74
|
+
PATTERN
|
75
|
+
|
76
|
+
# @!method ignored_column_nodes_from(node)
|
77
|
+
# @param node [RuboCop::AST::Node]
|
78
|
+
# @return [Array<String, Symbol>, nil]
|
79
|
+
def_node_matcher :ignored_column_nodes_from, <<~PATTERN
|
80
|
+
`{
|
81
|
+
(op_asgn
|
82
|
+
(send
|
83
|
+
self
|
84
|
+
:ignored_columns
|
85
|
+
...
|
86
|
+
)
|
87
|
+
:+
|
88
|
+
(array
|
89
|
+
({str sym} $_)*
|
90
|
+
)
|
91
|
+
)
|
92
|
+
|
93
|
+
(send
|
94
|
+
self
|
95
|
+
:ignored_columns=
|
96
|
+
(array
|
97
|
+
({str sym} $_)*
|
98
|
+
)
|
99
|
+
)
|
100
|
+
}
|
101
|
+
PATTERN
|
102
|
+
|
103
|
+
# @param node [RuboCop::AST::SendNode]
|
104
|
+
# @return [Boolean]
|
105
|
+
def bad?(node)
|
106
|
+
remove_column?(node) &&
|
107
|
+
!ignored?(node)
|
108
|
+
end
|
109
|
+
|
110
|
+
# @param node [RuboCop::AST::SendNode]
|
111
|
+
# @return [String, nil]
|
112
|
+
def find_column_name_from(node)
|
113
|
+
node.arguments[1].value&.to_s
|
114
|
+
end
|
115
|
+
|
116
|
+
# @param table_name [String]
|
117
|
+
# @return [Array<String>]
|
118
|
+
def find_ignored_column_names_from(table_name)
|
119
|
+
pathname = model_pathname_from(
|
120
|
+
singularize(table_name)
|
121
|
+
)
|
122
|
+
return [] unless pathname.exist?
|
123
|
+
|
124
|
+
ignored_column_nodes = ignored_column_nodes_from(
|
125
|
+
parse(
|
126
|
+
content: pathname.read,
|
127
|
+
path: pathname.to_s
|
128
|
+
)
|
129
|
+
)
|
130
|
+
return [] unless ignored_column_nodes
|
131
|
+
|
132
|
+
ignored_column_nodes.map(&:to_s)
|
133
|
+
end
|
134
|
+
|
135
|
+
# @param node [RuboCop::AST::SendNode]
|
136
|
+
# @return [String, nil]
|
137
|
+
def find_table_name_from(node)
|
138
|
+
node.arguments[0].value&.to_s
|
139
|
+
end
|
140
|
+
|
141
|
+
# @param node [RuboCop::AST::SendNode]
|
142
|
+
# @return [Boolean]
|
143
|
+
def ignored?(node)
|
144
|
+
find_ignored_column_names_from(
|
145
|
+
find_table_name_from(node)
|
146
|
+
).include?(
|
147
|
+
find_column_name_from(node)
|
148
|
+
)
|
149
|
+
end
|
150
|
+
|
151
|
+
# @param snake_cased_model_name [String]
|
152
|
+
# @return [Pathname]
|
153
|
+
def model_pathname_from(snake_cased_model_name)
|
154
|
+
::Pathname.new("app/models/#{snake_cased_model_name}.rb")
|
155
|
+
end
|
156
|
+
|
157
|
+
# @param content [String]
|
158
|
+
# @param path [String]
|
159
|
+
# @return [RuboCop::AST::Node]
|
160
|
+
def parse(
|
161
|
+
content:,
|
162
|
+
path:
|
163
|
+
)
|
164
|
+
Parser.call(
|
165
|
+
content: content,
|
166
|
+
path: path,
|
167
|
+
target_ruby_version: target_ruby_version
|
168
|
+
)
|
169
|
+
end
|
170
|
+
|
171
|
+
# @return [#parse]
|
172
|
+
def parser
|
173
|
+
parser_class.new(::RuboCop::AST::Builder.new)
|
174
|
+
end
|
175
|
+
|
176
|
+
# @return [Class]
|
177
|
+
def parser_class
|
178
|
+
::Parser.const_get(
|
179
|
+
"Ruby#{target_ruby_version.to_s.delete('.')}"
|
180
|
+
)
|
181
|
+
end
|
182
|
+
|
183
|
+
# @param plural [String]
|
184
|
+
# @return [String]
|
185
|
+
def singularize(plural)
|
186
|
+
::ActiveSupport::Inflector.singularize(plural)
|
187
|
+
end
|
188
|
+
|
189
|
+
class Parser
|
190
|
+
class << self
|
191
|
+
# @param content [String]
|
192
|
+
# @param path [String]
|
193
|
+
# @param target_ruby_version [#to_s]
|
194
|
+
# @return [RuboCop::AST::Node]
|
195
|
+
def call(
|
196
|
+
content:,
|
197
|
+
path:,
|
198
|
+
target_ruby_version:
|
199
|
+
)
|
200
|
+
new(
|
201
|
+
content: content,
|
202
|
+
path: path,
|
203
|
+
target_ruby_version: target_ruby_version
|
204
|
+
).call
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
# @param content [String]
|
209
|
+
# @param path [String]
|
210
|
+
# @param target_ruby_version [#to_s]
|
211
|
+
def initialize(
|
212
|
+
content:,
|
213
|
+
path:,
|
214
|
+
target_ruby_version:
|
215
|
+
)
|
216
|
+
@content = content
|
217
|
+
@path = path
|
218
|
+
@target_ruby_version = target_ruby_version
|
219
|
+
end
|
220
|
+
|
221
|
+
# @return [RuboCop::AST::Node]
|
222
|
+
def call
|
223
|
+
parser.parse(buffer)
|
224
|
+
end
|
225
|
+
|
226
|
+
private
|
227
|
+
|
228
|
+
# @return [Parser::Source::Buffer]
|
229
|
+
def buffer
|
230
|
+
::Parser::Source::Buffer.new(
|
231
|
+
@path,
|
232
|
+
source: @content
|
233
|
+
)
|
234
|
+
end
|
235
|
+
|
236
|
+
# @return [RuboCop::AST::Builder]
|
237
|
+
def builder
|
238
|
+
::RuboCop::AST::Builder.new
|
239
|
+
end
|
240
|
+
|
241
|
+
def parser
|
242
|
+
parser_class.new(builder)
|
243
|
+
end
|
244
|
+
|
245
|
+
# @return [Class]
|
246
|
+
def parser_class
|
247
|
+
::Parser.const_get(parser_class_name)
|
248
|
+
end
|
249
|
+
|
250
|
+
# @return [String]
|
251
|
+
def parser_class_name
|
252
|
+
"Ruby#{@target_ruby_version.to_s.delete('.')}"
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Sevencop
|
6
|
+
# Avoid renaming columns that are in use.
|
7
|
+
#
|
8
|
+
# It will cause errors in your application.
|
9
|
+
# A safer approach is to:
|
10
|
+
#
|
11
|
+
# 1. Create a new column
|
12
|
+
# 2. Write to both columns
|
13
|
+
# 3. Backfill data from the old column to the new column
|
14
|
+
# 4. Move reads from the old column to the new column
|
15
|
+
# 5. Stop writing to the old column
|
16
|
+
# 6. Drop the old column
|
17
|
+
#
|
18
|
+
# @safety
|
19
|
+
# Only meaningful if the column is in use.
|
20
|
+
#
|
21
|
+
# @example
|
22
|
+
# # bad
|
23
|
+
# class RenameUsersSettingsToProperties < ActiveRecord::Migration[7.0]
|
24
|
+
# def change
|
25
|
+
# rename_column :users, :settings, :properties
|
26
|
+
# end
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# # good
|
30
|
+
# class AddUsersProperties < ActiveRecord::Migration[7.0]
|
31
|
+
# def change
|
32
|
+
# add_column :users, :properties, :jsonb
|
33
|
+
# end
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# class User < ApplicationRecord
|
37
|
+
# self.ignored_columns += %w[settings]
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
# class RemoveUsersSettings < ActiveRecord::Migration[7.0]
|
41
|
+
# def change
|
42
|
+
# remove_column :users, :settings
|
43
|
+
# end
|
44
|
+
# end
|
45
|
+
class RailsMigrationRenameColumn < RuboCop::Cop::Base
|
46
|
+
MSG = 'Avoid renaming columns that are in use.'
|
47
|
+
|
48
|
+
RESTRICT_ON_SEND = %i[
|
49
|
+
rename_column
|
50
|
+
].freeze
|
51
|
+
|
52
|
+
# @param node [RuboCop::AST::SendNode]
|
53
|
+
# @return [void]
|
54
|
+
def on_send(node)
|
55
|
+
return unless bad?(node)
|
56
|
+
|
57
|
+
add_offense(node)
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
# @!method rename_column?(node)
|
63
|
+
# @param node [RuboCop::AST::SendNode]
|
64
|
+
# @return [Boolean]
|
65
|
+
def_node_matcher :rename_column?, <<~PATTERN
|
66
|
+
(send
|
67
|
+
nil?
|
68
|
+
:rename_column
|
69
|
+
...
|
70
|
+
)
|
71
|
+
PATTERN
|
72
|
+
|
73
|
+
# @param node [RuboCop::AST::SendNode]
|
74
|
+
# @return [Boolean]
|
75
|
+
def bad?(node)
|
76
|
+
rename_column?(node)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Sevencop
|
6
|
+
# Avoid renaming tables that are in use.
|
7
|
+
#
|
8
|
+
# It will cause errors in your application.
|
9
|
+
# A safer approach is to:
|
10
|
+
#
|
11
|
+
# 1. Create a new table
|
12
|
+
# 2. Write to both tables
|
13
|
+
# 3. Backfill data from the old table to new table
|
14
|
+
# 4. Move reads from the old table to the new table
|
15
|
+
# 5. Stop writing to the old table
|
16
|
+
# 6. Drop the old table
|
17
|
+
#
|
18
|
+
# @safety
|
19
|
+
# Only meaningful if the table is in use.
|
20
|
+
#
|
21
|
+
# @example
|
22
|
+
# # bad
|
23
|
+
# class RenameUsersToAccouts < ActiveRecord::Migration[7.0]
|
24
|
+
# def change
|
25
|
+
# rename_table :users, :accounts
|
26
|
+
# end
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# # good
|
30
|
+
# class AddAccounts < ActiveRecord::Migration[7.0]
|
31
|
+
# def change
|
32
|
+
# create_table :accounts do |t|
|
33
|
+
# t.string :name, null: false
|
34
|
+
# end
|
35
|
+
# end
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# class RemoveUsers < ActiveRecord::Migration[7.0]
|
39
|
+
# def change
|
40
|
+
# remove_table :users
|
41
|
+
# end
|
42
|
+
# end
|
43
|
+
class RailsMigrationRenameTable < RuboCop::Cop::Base
|
44
|
+
MSG = 'Avoid renaming tables that are in use.'
|
45
|
+
|
46
|
+
RESTRICT_ON_SEND = %i[
|
47
|
+
rename_table
|
48
|
+
].freeze
|
49
|
+
|
50
|
+
# @param node [RuboCop::AST::SendNode]
|
51
|
+
# @return [void]
|
52
|
+
def on_send(node)
|
53
|
+
return unless bad?(node)
|
54
|
+
|
55
|
+
add_offense(node)
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
# @!method rename_table?(node)
|
61
|
+
# @param node [RuboCop::AST::SendNode]
|
62
|
+
# @return [Boolean]
|
63
|
+
def_node_matcher :rename_table?, <<~PATTERN
|
64
|
+
(send
|
65
|
+
nil?
|
66
|
+
:rename_table
|
67
|
+
...
|
68
|
+
)
|
69
|
+
PATTERN
|
70
|
+
|
71
|
+
# @param node [RuboCop::AST::SendNode]
|
72
|
+
# @return [Boolean]
|
73
|
+
def bad?(node)
|
74
|
+
rename_table?(node)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -15,24 +15,7 @@ module RuboCop
|
|
15
15
|
# # good
|
16
16
|
# add_column :users, :some_other_good_name, :string
|
17
17
|
class RailsMigrationReservedWordMysql < RuboCop::Cop::Base
|
18
|
-
|
19
|
-
%i[
|
20
|
-
bigint
|
21
|
-
binary
|
22
|
-
blob
|
23
|
-
boolean
|
24
|
-
date
|
25
|
-
datetime
|
26
|
-
decimal
|
27
|
-
float
|
28
|
-
integer
|
29
|
-
numeric
|
30
|
-
primary_key
|
31
|
-
string
|
32
|
-
text
|
33
|
-
time
|
34
|
-
]
|
35
|
-
).freeze
|
18
|
+
include ::Sevencop::CopConcerns::ColumnTypeMethod
|
36
19
|
|
37
20
|
MSG = 'Avoid using MySQL reserved words as identifiers.'
|
38
21
|
|
@@ -129,7 +112,7 @@ module RuboCop
|
|
129
112
|
# @return [RuboCop::AST::Node, nil]
|
130
113
|
def_node_matcher :index_name_option_from_column_type, <<~PATTERN
|
131
114
|
(send
|
132
|
-
|
115
|
+
lvar
|
133
116
|
COLUMN_TYPE_METHOD_NAMES
|
134
117
|
_
|
135
118
|
(hash
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Sevencop
|
6
|
+
# Keep unique index columns count less than a specified number.
|
7
|
+
#
|
8
|
+
# Adding a non-unique index with more than three columns rarely improves performance.
|
9
|
+
# Instead, start an index with columns that narrow down the results the most.
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# # bad
|
13
|
+
# add_index :users, %i[a b c d]
|
14
|
+
#
|
15
|
+
# # good (`MaxColumnsCount: 3` by default)
|
16
|
+
# add_index :users, %i[a b c]
|
17
|
+
class RailsMigrationUniqueIndexColumnsCount < RuboCop::Cop::Base
|
18
|
+
RESTRICT_ON_SEND = %i[
|
19
|
+
add_index
|
20
|
+
index
|
21
|
+
].freeze
|
22
|
+
|
23
|
+
# @param node [RuboCop::AST::SendNode]
|
24
|
+
# @return [void]
|
25
|
+
def on_send(node)
|
26
|
+
column_names_node = column_names_node_from(node)
|
27
|
+
return unless column_names_node
|
28
|
+
|
29
|
+
column_names_count = columns_count_from(column_names_node)
|
30
|
+
return if column_names_count <= max_columns_count
|
31
|
+
|
32
|
+
add_offense(
|
33
|
+
column_names_node,
|
34
|
+
message: "Keep unique index columns count less than #{max_columns_count}."
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
# @!method column_names_node_from_add_index(node)
|
41
|
+
# @param node [RuboCop::AST::SendNode]
|
42
|
+
# @return [RuboCop::AST::Node, nil]
|
43
|
+
def_node_matcher :column_names_node_from_add_index, <<~PATTERN
|
44
|
+
(send
|
45
|
+
nil?
|
46
|
+
_
|
47
|
+
_
|
48
|
+
$({array | sym} ...)
|
49
|
+
)
|
50
|
+
PATTERN
|
51
|
+
|
52
|
+
# @!method column_names_node_from_index(node)
|
53
|
+
# @param node [RuboCop::AST::SendNode]
|
54
|
+
# @return [RuboCop::AST::Node, nil]
|
55
|
+
def_node_matcher :column_names_node_from_index, <<~PATTERN
|
56
|
+
(send
|
57
|
+
(lvar ...)
|
58
|
+
_
|
59
|
+
$({array | sym} ...)
|
60
|
+
)
|
61
|
+
PATTERN
|
62
|
+
|
63
|
+
# @param node [RuboCop::AST::SendNode]
|
64
|
+
# @return [RuboCop::AST::Node, nil]
|
65
|
+
def column_names_node_from(node)
|
66
|
+
case node.method_name
|
67
|
+
when :add_index
|
68
|
+
column_names_node_from_add_index(node)
|
69
|
+
when :index
|
70
|
+
column_names_node_from_index(node)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# @param node [RuboCop::AST::Node]
|
75
|
+
# @return [Integer, nil]
|
76
|
+
def columns_count_from(node)
|
77
|
+
case node.type
|
78
|
+
when :array
|
79
|
+
node.values.count
|
80
|
+
when :sym
|
81
|
+
1
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# @return [Integer]
|
86
|
+
def max_columns_count
|
87
|
+
cop_config['MaxColumnsCount']
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -5,23 +5,24 @@ require 'rubocop'
|
|
5
5
|
module Sevencop
|
6
6
|
# Merge default RuboCop config with plugin config.
|
7
7
|
class ConfigLoader
|
8
|
-
PLUGIN_CONFIG_PATH = ::File.expand_path(
|
9
|
-
'../../config/default.yml',
|
10
|
-
__dir__
|
11
|
-
)
|
12
|
-
|
13
8
|
class << self
|
9
|
+
# @param path [String]
|
14
10
|
# @return [RuboCop::Config]
|
15
|
-
def call
|
16
|
-
new.call
|
11
|
+
def call(path:)
|
12
|
+
new(path: path).call
|
17
13
|
end
|
18
14
|
end
|
19
15
|
|
16
|
+
# @param path [String]
|
17
|
+
def initialize(path:)
|
18
|
+
@path = path
|
19
|
+
end
|
20
|
+
|
20
21
|
# @return [RuboCop::Config]
|
21
22
|
def call
|
22
23
|
::RuboCop::ConfigLoader.merge_with_default(
|
23
24
|
plugin_config,
|
24
|
-
|
25
|
+
@path
|
25
26
|
)
|
26
27
|
end
|
27
28
|
|
@@ -31,7 +32,7 @@ module Sevencop
|
|
31
32
|
def plugin_config
|
32
33
|
config = ::RuboCop::Config.new(
|
33
34
|
plugin_config_hash,
|
34
|
-
|
35
|
+
@path
|
35
36
|
)
|
36
37
|
config.make_excludes_absolute
|
37
38
|
config
|
@@ -41,7 +42,7 @@ module Sevencop
|
|
41
42
|
def plugin_config_hash
|
42
43
|
::RuboCop::ConfigLoader.send(
|
43
44
|
:load_yaml_configuration,
|
44
|
-
|
45
|
+
@path
|
45
46
|
)
|
46
47
|
end
|
47
48
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sevencop
|
4
|
+
module CopConcerns
|
5
|
+
module BatchProcessing
|
6
|
+
BATCH_PROCESSING_METHOD_NAMES = ::Set.new(
|
7
|
+
%i[
|
8
|
+
delete_all
|
9
|
+
update_all
|
10
|
+
]
|
11
|
+
).freeze
|
12
|
+
|
13
|
+
class << self
|
14
|
+
def included(klass)
|
15
|
+
super
|
16
|
+
klass.class_eval do
|
17
|
+
# @!method batch_processing?(node)
|
18
|
+
# @param node [RuboCop::AST::SendNode]
|
19
|
+
# @return [Boolean]
|
20
|
+
def_node_matcher :batch_processing?, <<~PATTERN
|
21
|
+
(send
|
22
|
+
!nil?
|
23
|
+
BATCH_PROCESSING_METHOD_NAMES
|
24
|
+
...
|
25
|
+
)
|
26
|
+
PATTERN
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sevencop
|
4
|
+
module CopConcerns
|
5
|
+
module ColumnTypeMethod
|
6
|
+
COLUMN_TYPE_METHOD_NAMES = ::Set.new(
|
7
|
+
%i[
|
8
|
+
bigint
|
9
|
+
binary
|
10
|
+
blob
|
11
|
+
boolean
|
12
|
+
date
|
13
|
+
datetime
|
14
|
+
decimal
|
15
|
+
float
|
16
|
+
integer
|
17
|
+
numeric
|
18
|
+
primary_key
|
19
|
+
string
|
20
|
+
text
|
21
|
+
time
|
22
|
+
]
|
23
|
+
).freeze
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sevencop
|
4
|
+
module CopConcerns
|
5
|
+
module DisableDdlTransaction
|
6
|
+
class << self
|
7
|
+
def included(klass)
|
8
|
+
super
|
9
|
+
klass.class_eval do
|
10
|
+
# @!method disable_ddl_transaction?(node)
|
11
|
+
# @param node [RuboCop::AST::SendNode]
|
12
|
+
# @return [Boolean]
|
13
|
+
def_node_matcher :disable_ddl_transaction?, <<~PATTERN
|
14
|
+
(send
|
15
|
+
nil?
|
16
|
+
:disable_ddl_transaction!
|
17
|
+
...
|
18
|
+
)
|
19
|
+
PATTERN
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
# @param corrector [RuboCop::Cop::Corrector]
|
27
|
+
# @param node [RuboCop::AST::SendNode]
|
28
|
+
# @return [void]
|
29
|
+
def insert_disable_ddl_transaction(
|
30
|
+
corrector,
|
31
|
+
node
|
32
|
+
)
|
33
|
+
corrector.insert_before(
|
34
|
+
node.each_ancestor(:def).first,
|
35
|
+
"disable_ddl_transaction!\n\n "
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
39
|
+
# @param node [RuboCop::AST::SendNode]
|
40
|
+
# @return [Boolean]
|
41
|
+
def within_disable_ddl_transaction?(node)
|
42
|
+
node.each_ancestor(:def).first&.left_siblings&.any? do |sibling|
|
43
|
+
sibling.is_a?(::RuboCop::AST::SendNode) &&
|
44
|
+
disable_ddl_transaction?(sibling)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|