rubocop-migration 0.2.0 → 0.4.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 +5 -5
- data/.rubocop.yml +58 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +11 -1
- data/Gemfile.lock +89 -0
- data/LICENSE.txt +21 -0
- data/README.md +42 -18
- data/Rakefile +9 -3
- data/config/default.yml +151 -0
- data/data/reserved_words_mysql.txt +750 -0
- data/lib/rubocop/cop/migration/add_check_constraint.rb +111 -0
- data/lib/rubocop/cop/migration/add_column_with_default_value.rb +229 -0
- data/lib/rubocop/cop/migration/add_foreign_key.rb +166 -0
- data/lib/rubocop/cop/migration/add_index_columns_count.rb +114 -0
- data/lib/rubocop/cop/migration/add_index_concurrently.rb +164 -0
- data/lib/rubocop/cop/migration/add_index_duplicate.rb +183 -0
- data/lib/rubocop/cop/migration/batch_in_batches.rb +95 -0
- data/lib/rubocop/cop/migration/batch_in_transaction.rb +83 -0
- data/lib/rubocop/cop/migration/batch_with_throttling.rb +108 -0
- data/lib/rubocop/cop/migration/change_column.rb +113 -0
- data/lib/rubocop/cop/migration/change_column_null.rb +208 -0
- data/lib/rubocop/cop/migration/create_table_force.rb +89 -0
- data/lib/rubocop/cop/migration/jsonb.rb +131 -0
- data/lib/rubocop/cop/migration/remove_column.rb +246 -0
- data/lib/rubocop/cop/migration/rename_column.rb +81 -0
- data/lib/rubocop/cop/migration/rename_table.rb +79 -0
- data/lib/rubocop/cop/migration/reserved_word_mysql.rb +232 -0
- data/lib/rubocop/migration/config_loader.rb +51 -0
- data/lib/rubocop/migration/cop_concerns/batch_processing.rb +34 -0
- data/lib/rubocop/migration/cop_concerns/column_type_method.rb +28 -0
- data/lib/rubocop/migration/cop_concerns/disable_ddl_transaction.rb +51 -0
- data/lib/rubocop/migration/cop_concerns.rb +11 -0
- data/lib/rubocop/migration/rubocop_extension.rb +15 -0
- data/lib/rubocop/migration/version.rb +4 -2
- data/lib/rubocop/migration.rb +23 -0
- data/rubocop-migration.gemspec +25 -31
- metadata +49 -137
- data/.gitignore +0 -15
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/circle.yml +0 -6
- data/lib/rubocop/cop/migration/unsafe_migration.rb +0 -69
- data/lib/rubocop/migration/strong_migrations_checker.rb +0 -47
- data/lib/rubocop-migration.rb +0 -16
- data/vendor/.gitkeep +0 -0
@@ -0,0 +1,246 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/inflector'
|
4
|
+
require 'pathname'
|
5
|
+
|
6
|
+
module RuboCop
|
7
|
+
module Cop
|
8
|
+
module Migration
|
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 RemoveColumn < 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
|
+
# @param plural [String]
|
172
|
+
# @return [String]
|
173
|
+
def singularize(plural)
|
174
|
+
::ActiveSupport::Inflector.singularize(plural)
|
175
|
+
end
|
176
|
+
|
177
|
+
class Parser
|
178
|
+
class << self
|
179
|
+
# @param content [String]
|
180
|
+
# @param path [String]
|
181
|
+
# @param target_ruby_version [#to_s]
|
182
|
+
# @return [RuboCop::AST::Node]
|
183
|
+
def call(
|
184
|
+
content:,
|
185
|
+
path:,
|
186
|
+
target_ruby_version:
|
187
|
+
)
|
188
|
+
new(
|
189
|
+
content: content,
|
190
|
+
path: path,
|
191
|
+
target_ruby_version: target_ruby_version
|
192
|
+
).call
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
# @param content [String]
|
197
|
+
# @param path [String]
|
198
|
+
# @param target_ruby_version [#to_s]
|
199
|
+
def initialize(
|
200
|
+
content:,
|
201
|
+
path:,
|
202
|
+
target_ruby_version:
|
203
|
+
)
|
204
|
+
@content = content
|
205
|
+
@path = path
|
206
|
+
@target_ruby_version = target_ruby_version
|
207
|
+
end
|
208
|
+
|
209
|
+
# @return [RuboCop::AST::Node]
|
210
|
+
def call
|
211
|
+
parser.parse(buffer)
|
212
|
+
end
|
213
|
+
|
214
|
+
private
|
215
|
+
|
216
|
+
# @return [Parser::Source::Buffer]
|
217
|
+
def buffer
|
218
|
+
::Parser::Source::Buffer.new(
|
219
|
+
@path,
|
220
|
+
source: @content
|
221
|
+
)
|
222
|
+
end
|
223
|
+
|
224
|
+
# @return [RuboCop::AST::Builder]
|
225
|
+
def builder
|
226
|
+
::RuboCop::AST::Builder.new
|
227
|
+
end
|
228
|
+
|
229
|
+
def parser
|
230
|
+
parser_class.new(builder)
|
231
|
+
end
|
232
|
+
|
233
|
+
# @return [Class]
|
234
|
+
def parser_class
|
235
|
+
::Parser.const_get(parser_class_name)
|
236
|
+
end
|
237
|
+
|
238
|
+
# @return [String]
|
239
|
+
def parser_class_name
|
240
|
+
"Ruby#{@target_ruby_version.to_s.delete('.')}"
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Migration
|
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 RenameColumn < 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 Migration
|
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 RenameTable < 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
|
@@ -0,0 +1,232 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'set'
|
4
|
+
|
5
|
+
module RuboCop
|
6
|
+
module Cop
|
7
|
+
module Migration
|
8
|
+
# Avoid using MySQL reserved words as identifiers.
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# # bad
|
12
|
+
# # NOTE: `role` is a reserved word in MySQL.
|
13
|
+
# add_column :users, :role, :string
|
14
|
+
#
|
15
|
+
# # good
|
16
|
+
# add_column :users, :some_other_good_name, :string
|
17
|
+
class ReservedWordMysql < RuboCop::Cop::Base
|
18
|
+
include ::RuboCop::Migration::CopConcerns::ColumnTypeMethod
|
19
|
+
|
20
|
+
MSG = 'Avoid using MySQL reserved words as identifiers.'
|
21
|
+
|
22
|
+
# Obtained from https://dev.mysql.com/doc/refman/8.0/en/keywords.html.
|
23
|
+
PATH_TO_RESERVED_WORDS_FILE = File.expand_path(
|
24
|
+
'../../../../data/reserved_words_mysql.txt',
|
25
|
+
__dir__
|
26
|
+
).freeze
|
27
|
+
|
28
|
+
RESTRICT_ON_SEND = [
|
29
|
+
:add_column,
|
30
|
+
:add_index,
|
31
|
+
:add_reference,
|
32
|
+
:create_join_table,
|
33
|
+
:create_table,
|
34
|
+
:rename,
|
35
|
+
:rename_column,
|
36
|
+
:rename_index,
|
37
|
+
:rename_table,
|
38
|
+
*COLUMN_TYPE_METHOD_NAMES
|
39
|
+
].freeze
|
40
|
+
|
41
|
+
class << self
|
42
|
+
# @return [Array<String>]
|
43
|
+
def reserved_words
|
44
|
+
@reserved_words ||= ::Set.new(
|
45
|
+
::File.read(PATH_TO_RESERVED_WORDS_FILE).split("\n")
|
46
|
+
).freeze
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# @param node [RuboCop::AST::DefNode]
|
51
|
+
# @return [void]
|
52
|
+
def on_send(node)
|
53
|
+
offended_identifier_nodes_from(node).each do |identifier_node|
|
54
|
+
add_offense(identifier_node)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
# @!method index_name_option_from_add_index(node)
|
61
|
+
# @param node [RuboCop::AST::SendNode]
|
62
|
+
# @return [RuboCop::AST::Node, nil]
|
63
|
+
def_node_matcher :index_name_option_from_add_index, <<~PATTERN
|
64
|
+
(send
|
65
|
+
nil?
|
66
|
+
:add_index
|
67
|
+
_
|
68
|
+
_
|
69
|
+
(hash
|
70
|
+
<
|
71
|
+
(pair
|
72
|
+
(sym :name)
|
73
|
+
$_
|
74
|
+
)
|
75
|
+
>
|
76
|
+
...
|
77
|
+
)
|
78
|
+
)
|
79
|
+
PATTERN
|
80
|
+
|
81
|
+
# @!method index_name_option_from_add_reference(node)
|
82
|
+
# @param node [RuboCop::AST::SendNode]
|
83
|
+
# @return [RuboCop::AST::Node, nil]
|
84
|
+
def_node_matcher :index_name_option_from_add_reference, <<~PATTERN
|
85
|
+
(send
|
86
|
+
nil?
|
87
|
+
:add_reference
|
88
|
+
_
|
89
|
+
_
|
90
|
+
(hash
|
91
|
+
<
|
92
|
+
(pair
|
93
|
+
(sym :index)
|
94
|
+
(hash
|
95
|
+
<
|
96
|
+
(pair
|
97
|
+
(sym :name)
|
98
|
+
$_
|
99
|
+
)
|
100
|
+
>
|
101
|
+
...
|
102
|
+
)
|
103
|
+
)
|
104
|
+
>
|
105
|
+
...
|
106
|
+
)
|
107
|
+
)
|
108
|
+
PATTERN
|
109
|
+
|
110
|
+
# @!method index_name_option_from_column_type(node)
|
111
|
+
# @param node [RuboCop::AST::SendNode]
|
112
|
+
# @return [RuboCop::AST::Node, nil]
|
113
|
+
def_node_matcher :index_name_option_from_column_type, <<~PATTERN
|
114
|
+
(send
|
115
|
+
lvar
|
116
|
+
COLUMN_TYPE_METHOD_NAMES
|
117
|
+
_
|
118
|
+
(hash
|
119
|
+
<
|
120
|
+
(pair
|
121
|
+
(sym :index)
|
122
|
+
(hash
|
123
|
+
<
|
124
|
+
(pair
|
125
|
+
(sym :name)
|
126
|
+
$_
|
127
|
+
)
|
128
|
+
...
|
129
|
+
>
|
130
|
+
)
|
131
|
+
)
|
132
|
+
...
|
133
|
+
>
|
134
|
+
)
|
135
|
+
)
|
136
|
+
PATTERN
|
137
|
+
|
138
|
+
# @!method table_name_option_from(node)
|
139
|
+
# @param node [RuboCop::AST::SendNode]
|
140
|
+
# @return [RuboCop::AST::Node, nil]
|
141
|
+
def_node_matcher :table_name_option_from, <<~PATTERN
|
142
|
+
(send
|
143
|
+
nil?
|
144
|
+
:create_join_table
|
145
|
+
_
|
146
|
+
_
|
147
|
+
(hash
|
148
|
+
<
|
149
|
+
(pair
|
150
|
+
(sym :table_name)
|
151
|
+
$_
|
152
|
+
)
|
153
|
+
...
|
154
|
+
>
|
155
|
+
)
|
156
|
+
)
|
157
|
+
PATTERN
|
158
|
+
|
159
|
+
# @param node [RuboCop::AST::SendNode]
|
160
|
+
# @return [Array<RuboCop::AST::Node>]
|
161
|
+
def identifier_column_name_nodes_from(node)
|
162
|
+
case node.method_name
|
163
|
+
when :add_column, :rename
|
164
|
+
[node.arguments[1]]
|
165
|
+
when :rename_column
|
166
|
+
[node.arguments[2]]
|
167
|
+
when *COLUMN_TYPE_METHOD_NAMES
|
168
|
+
[node.arguments[0]]
|
169
|
+
else
|
170
|
+
[]
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
# @param node [RuboCop::AST::SendNode]
|
175
|
+
# @return [Array<RuboCop::AST::Node>]
|
176
|
+
def identifier_index_name_nodes_from(node)
|
177
|
+
case node.method_name
|
178
|
+
when :add_index
|
179
|
+
[index_name_option_from_add_index(node)].compact
|
180
|
+
when :add_reference
|
181
|
+
[index_name_option_from_add_reference(node)].compact
|
182
|
+
when :rename_index
|
183
|
+
[node.arguments[2]]
|
184
|
+
when *COLUMN_TYPE_METHOD_NAMES
|
185
|
+
[index_name_option_from_column_type(node)].compact
|
186
|
+
else
|
187
|
+
[]
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
# @param node [RuboCop::AST::SendNode]
|
192
|
+
# @return [Array<RuboCop::AST::Node>]
|
193
|
+
def identifier_nodes_from(node)
|
194
|
+
identifier_table_name_nodes_from(node) +
|
195
|
+
identifier_column_name_nodes_from(node) +
|
196
|
+
identifier_index_name_nodes_from(node)
|
197
|
+
end
|
198
|
+
|
199
|
+
# @param node [RuboCop::AST::SendNode]
|
200
|
+
# @return [Array<RuboCop::AST::Node>]
|
201
|
+
def identifier_table_name_nodes_from(node)
|
202
|
+
case node.method_name
|
203
|
+
when :create_join_table
|
204
|
+
[table_name_option_from(node)].compact
|
205
|
+
when :create_table
|
206
|
+
[node.arguments[0]]
|
207
|
+
when :rename_table
|
208
|
+
[node.arguments[1]]
|
209
|
+
else
|
210
|
+
[]
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
# @param node [RuboCop::AST::Node]
|
215
|
+
# @return [Array<RuboCop::AST::Node>]
|
216
|
+
def offended_identifier_nodes_from(node)
|
217
|
+
identifier_nodes_from(node).select do |identifier_node|
|
218
|
+
reserved_word_identifier_node?(identifier_node)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
# @param node [RuboCop::AST::Node]
|
223
|
+
# @return [Boolean]
|
224
|
+
def reserved_word_identifier_node?(node)
|
225
|
+
return false unless node.respond_to?(:value)
|
226
|
+
|
227
|
+
self.class.reserved_words.include?(node.value.to_s)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rubocop'
|
4
|
+
|
5
|
+
module RuboCop
|
6
|
+
module Migration
|
7
|
+
# Merge default RuboCop config with plugin config.
|
8
|
+
class ConfigLoader
|
9
|
+
class << self
|
10
|
+
# @param path [String]
|
11
|
+
# @return [RuboCop::Config]
|
12
|
+
def call(path:)
|
13
|
+
new(path: path).call
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# @param path [String]
|
18
|
+
def initialize(path:)
|
19
|
+
@path = path
|
20
|
+
end
|
21
|
+
|
22
|
+
# @return [RuboCop::Config]
|
23
|
+
def call
|
24
|
+
::RuboCop::ConfigLoader.merge_with_default(
|
25
|
+
plugin_config,
|
26
|
+
@path
|
27
|
+
)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
# @return [RuboCop::Config]
|
33
|
+
def plugin_config
|
34
|
+
config = ::RuboCop::Config.new(
|
35
|
+
plugin_config_hash,
|
36
|
+
@path
|
37
|
+
)
|
38
|
+
config.make_excludes_absolute
|
39
|
+
config
|
40
|
+
end
|
41
|
+
|
42
|
+
# @return [Hash]
|
43
|
+
def plugin_config_hash
|
44
|
+
::RuboCop::ConfigLoader.send(
|
45
|
+
:load_yaml_configuration,
|
46
|
+
@path
|
47
|
+
)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|