sevencop 0.22.0 → 0.23.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/Gemfile.lock +1 -1
- data/README.md +0 -16
- data/config/default.yml +0 -143
- data/lib/sevencop/cop_concerns.rb +0 -3
- data/lib/sevencop/version.rb +1 -1
- data/lib/sevencop.rb +0 -16
- metadata +2 -21
- data/lib/rubocop/cop/sevencop/rails_migration_add_check_constraint.rb +0 -111
- data/lib/rubocop/cop/sevencop/rails_migration_add_column_with_default_value.rb +0 -229
- data/lib/rubocop/cop/sevencop/rails_migration_add_foreign_key.rb +0 -166
- data/lib/rubocop/cop/sevencop/rails_migration_add_index_concurrently.rb +0 -164
- data/lib/rubocop/cop/sevencop/rails_migration_batch_in_batches.rb +0 -95
- data/lib/rubocop/cop/sevencop/rails_migration_batch_in_transaction.rb +0 -83
- data/lib/rubocop/cop/sevencop/rails_migration_batch_with_throttling.rb +0 -108
- data/lib/rubocop/cop/sevencop/rails_migration_change_column.rb +0 -113
- data/lib/rubocop/cop/sevencop/rails_migration_change_column_null.rb +0 -128
- data/lib/rubocop/cop/sevencop/rails_migration_create_table_force.rb +0 -89
- data/lib/rubocop/cop/sevencop/rails_migration_jsonb.rb +0 -131
- data/lib/rubocop/cop/sevencop/rails_migration_remove_column.rb +0 -258
- data/lib/rubocop/cop/sevencop/rails_migration_rename_column.rb +0 -81
- data/lib/rubocop/cop/sevencop/rails_migration_rename_table.rb +0 -79
- data/lib/rubocop/cop/sevencop/rails_migration_reserved_word_mysql.rb +0 -232
- data/lib/rubocop/cop/sevencop/rails_migration_unique_index_columns_count.rb +0 -92
- data/lib/sevencop/cop_concerns/batch_processing.rb +0 -32
- data/lib/sevencop/cop_concerns/column_type_method.rb +0 -26
- data/lib/sevencop/cop_concerns/disable_ddl_transaction.rb +0 -49
@@ -1,113 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RuboCop
|
4
|
-
module Cop
|
5
|
-
module Sevencop
|
6
|
-
# Avoid changing column type that is in use.
|
7
|
-
#
|
8
|
-
# Changing the type of a column causes the entire table to be rewritten.
|
9
|
-
# During this time, reads and writes are blocked in Postgres, and writes are blocked in MySQL and MariaDB.
|
10
|
-
#
|
11
|
-
# Some changes don’t require a table rewrite and are safe in PostgreSQL:
|
12
|
-
#
|
13
|
-
# Type | Safe Changes
|
14
|
-
# --- | ---
|
15
|
-
# `cidr` | Changing to `inet`
|
16
|
-
# `citext` | Changing to `text` if not indexed, changing to `string` with no `:limit` if not indexed
|
17
|
-
# `datetime` | Increasing or removing `:precision`, changing to `timestamptz` when session time zone is UTC in Postgres 12+
|
18
|
-
# `decimal` | Increasing `:precision` at same `:scale`, removing `:precision` and `:scale`
|
19
|
-
# `interval` | Increasing or removing `:precision`
|
20
|
-
# `numeric` | Increasing `:precision` at same `:scale`, removing `:precision` and `:scale`
|
21
|
-
# `string` | Increasing or removing `:limit`, changing to `text`, changing `citext` if not indexed
|
22
|
-
# `text` | Changing to `string` with no `:limit`, changing to `citext` if not indexed
|
23
|
-
# `time` | Increasing or removing `:precision`
|
24
|
-
# `timestamptz` | Increasing or removing `:limit`, changing to `datetime` when session time zone is UTC in Postgres 12+
|
25
|
-
#
|
26
|
-
# And some in MySQL and MariaDB:
|
27
|
-
#
|
28
|
-
# Type | Safe Changes
|
29
|
-
# --- | ---
|
30
|
-
# `string` | Increasing `:limit` from under 255 up to 255, increasing `:limit` from over 255 to the max
|
31
|
-
#
|
32
|
-
# A safer approach is to:
|
33
|
-
#
|
34
|
-
# 1. Create a new column
|
35
|
-
# 2. Write to both columns
|
36
|
-
# 3. Backfill data from the old column to the new column
|
37
|
-
# 4. Move reads from the old column to the new column
|
38
|
-
# 5. Stop writing to the old column
|
39
|
-
# 6. Drop the old column
|
40
|
-
#
|
41
|
-
# @safety
|
42
|
-
# Only meaningful if the table is in use and the type change is really unsafe as described above.
|
43
|
-
#
|
44
|
-
# @example
|
45
|
-
# # bad
|
46
|
-
# class ChangeUsersSomeColumnType < ActiveRecord::Migration[7.0]
|
47
|
-
# def change
|
48
|
-
# change_column :users, :some_column, :new_type
|
49
|
-
# end
|
50
|
-
# end
|
51
|
-
#
|
52
|
-
# # good
|
53
|
-
# class AddUsersAnotherColumn < ActiveRecord::Migration[7.0]
|
54
|
-
# def change
|
55
|
-
# add_column :users, :another_column, :new_type
|
56
|
-
# end
|
57
|
-
# end
|
58
|
-
#
|
59
|
-
# class RemoveUsersSomeColumn < ActiveRecord::Migration[7.0]
|
60
|
-
# def change
|
61
|
-
# remove_column :users, :some_column
|
62
|
-
# end
|
63
|
-
# end
|
64
|
-
class RailsMigrationChangeColumn < RuboCop::Cop::Base
|
65
|
-
MSG = 'Avoid changing column type that is in use.'
|
66
|
-
|
67
|
-
RESTRICT_ON_SEND = %i[
|
68
|
-
change
|
69
|
-
change_column
|
70
|
-
].freeze
|
71
|
-
|
72
|
-
# @param node [RuboCop::AST::SendNode]
|
73
|
-
# @return [void]
|
74
|
-
def on_send(node)
|
75
|
-
return unless bad?(node)
|
76
|
-
|
77
|
-
add_offense(node)
|
78
|
-
end
|
79
|
-
|
80
|
-
private
|
81
|
-
|
82
|
-
# @!method change?(node)
|
83
|
-
# @param node [RuboCop::AST::SendNode]
|
84
|
-
# @return [Boolean]
|
85
|
-
def_node_matcher :change?, <<~PATTERN
|
86
|
-
(send
|
87
|
-
lvar
|
88
|
-
:change
|
89
|
-
...
|
90
|
-
)
|
91
|
-
PATTERN
|
92
|
-
|
93
|
-
# @!method change_column?(node)
|
94
|
-
# @param node [RuboCop::AST::SendNode]
|
95
|
-
# @return [Boolean]
|
96
|
-
def_node_matcher :change_column?, <<~PATTERN
|
97
|
-
(send
|
98
|
-
nil?
|
99
|
-
:change_column
|
100
|
-
...
|
101
|
-
)
|
102
|
-
PATTERN
|
103
|
-
|
104
|
-
# @param node [RuboCop::AST::SendNode]
|
105
|
-
# @return [Boolean]
|
106
|
-
def bad?(node)
|
107
|
-
change?(node) ||
|
108
|
-
change_column?(node)
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|
@@ -1,128 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RuboCop
|
4
|
-
module Cop
|
5
|
-
module Sevencop
|
6
|
-
# Avoid simply setting `NOT NULL` constraint on an existing column in PostgreSQL.
|
7
|
-
#
|
8
|
-
# It blocks reads and writes while every row is checked.
|
9
|
-
# In PostgreSQL 12+, you can safely set `NOT NULL` constraint if corresponding check constraint exists.
|
10
|
-
#
|
11
|
-
# @safety
|
12
|
-
# Only meaningful in PostgreSQL 12+.
|
13
|
-
#
|
14
|
-
# @example
|
15
|
-
# # bad
|
16
|
-
# class SetNotNullColumnConstraintToUsersName < ActiveRecord::Migration[7.0]
|
17
|
-
# def change
|
18
|
-
# change_column_null :users, :name, false
|
19
|
-
# end
|
20
|
-
# end
|
21
|
-
#
|
22
|
-
# # good
|
23
|
-
# class SetNotNullCheckConstraintToUsersName < ActiveRecord::Migration[7.0]
|
24
|
-
# def change
|
25
|
-
# add_check_constraint :users, 'name IS NOT NULL', name: 'users_name_is_not_null', validate: false
|
26
|
-
# end
|
27
|
-
# end
|
28
|
-
#
|
29
|
-
# class ReplaceNotNullConstraintOnUsersName < ActiveRecord::Migration[7.0]
|
30
|
-
# def change
|
31
|
-
# validate_constraint :users, name: 'users_name_is_not_null'
|
32
|
-
# change_column_null :users, :name, false
|
33
|
-
# remove_check_constraint :users, name: 'users_name_is_not_null'
|
34
|
-
# end
|
35
|
-
# end
|
36
|
-
class RailsMigrationChangeColumnNull < RuboCop::Cop::Base
|
37
|
-
extend AutoCorrector
|
38
|
-
|
39
|
-
MSG = 'Avoid simply setting `NOT NULL` constraint on an existing column in PostgreSQL.'
|
40
|
-
|
41
|
-
RESTRICT_ON_SEND = %i[
|
42
|
-
change_column_null
|
43
|
-
].freeze
|
44
|
-
|
45
|
-
# @param node [RuboCop::AST::SendNode]
|
46
|
-
# @return [void]
|
47
|
-
def on_send(node)
|
48
|
-
return if in_second_migration?(node)
|
49
|
-
|
50
|
-
add_offense(node) do |corrector|
|
51
|
-
autocorrect(corrector, node)
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
private
|
56
|
-
|
57
|
-
# @!method parse_table_name_and_column_name(node)
|
58
|
-
# @param node [RuboCop::AST::SendNode]
|
59
|
-
# @return [Array<Symbol>, nil]
|
60
|
-
def_node_matcher :parse_table_name_and_column_name, <<~PATTERN
|
61
|
-
(send
|
62
|
-
nil?
|
63
|
-
_
|
64
|
-
({str sym} $_)
|
65
|
-
({str sym} $_)
|
66
|
-
...
|
67
|
-
)
|
68
|
-
PATTERN
|
69
|
-
|
70
|
-
# @!method remove_check_constraint?(node)
|
71
|
-
# @param node [RuboCop::AST::SendNode]
|
72
|
-
# @return [Boolean]
|
73
|
-
def_node_matcher :remove_check_constraint?, <<~PATTERN
|
74
|
-
(send nil? :remove_check_constraint ...)
|
75
|
-
PATTERN
|
76
|
-
|
77
|
-
# @!method validate_constraint?(node)
|
78
|
-
# @param node [RuboCop::AST::SendNode]
|
79
|
-
# @return [Boolean]
|
80
|
-
def_node_matcher :validate_constraint?, <<~PATTERN
|
81
|
-
(send nil? :validate_constraint ...)
|
82
|
-
PATTERN
|
83
|
-
|
84
|
-
# @param corrector [RuboCop::Cop::Corrector]
|
85
|
-
# @param node [RuboCop::AST::SendNode]
|
86
|
-
# @return [void]
|
87
|
-
def autocorrect(
|
88
|
-
corrector,
|
89
|
-
node
|
90
|
-
)
|
91
|
-
table_name, column_name = parse_table_name_and_column_name(node)
|
92
|
-
corrector.replace(
|
93
|
-
node,
|
94
|
-
format(
|
95
|
-
"add_check_constraint :%<table>s, '%<column>s IS NOT NULL', name: '%<constraint>s', validate: false",
|
96
|
-
column: column_name,
|
97
|
-
constraint: "#{table_name}_#{column_name}_is_not_null",
|
98
|
-
table: table_name
|
99
|
-
)
|
100
|
-
)
|
101
|
-
end
|
102
|
-
|
103
|
-
# @param node [RuboCop::AST::SendNode]
|
104
|
-
# @return [Boolean]
|
105
|
-
def called_after_validate_constraint?(node)
|
106
|
-
node.left_siblings.any? do |sibling|
|
107
|
-
validate_constraint?(sibling)
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
# @param node [RuboCop::AST::SendNode]
|
112
|
-
# @return [Boolean]
|
113
|
-
def called_before_remove_check_constraint?(node)
|
114
|
-
node.right_siblings.any? do |sibling|
|
115
|
-
remove_check_constraint?(sibling)
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
# @param node [RuboCop::AST::SendNode]
|
120
|
-
# @return [Boolean]
|
121
|
-
def in_second_migration?(node)
|
122
|
-
called_after_validate_constraint?(node) ||
|
123
|
-
called_before_remove_check_constraint?(node)
|
124
|
-
end
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
128
|
-
end
|
@@ -1,89 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RuboCop
|
4
|
-
module Cop
|
5
|
-
module Sevencop
|
6
|
-
# Create tables without `force: true` option.
|
7
|
-
#
|
8
|
-
# The `force: true` option can drop an existing table.
|
9
|
-
# If you indend to drop an existing table, explicitly call `drop_table` first.
|
10
|
-
#
|
11
|
-
# @example
|
12
|
-
# # bad
|
13
|
-
# class CreateUsers < ActiveRecord::Migration[7.0]
|
14
|
-
# def change
|
15
|
-
# create_table :users, force: true
|
16
|
-
# end
|
17
|
-
# end
|
18
|
-
#
|
19
|
-
# # good
|
20
|
-
# class CreateUsers < ActiveRecord::Migration[7.0]
|
21
|
-
# def change
|
22
|
-
# create_table :users
|
23
|
-
# end
|
24
|
-
# end
|
25
|
-
class RailsMigrationCreateTableForce < RuboCop::Cop::Base
|
26
|
-
extend AutoCorrector
|
27
|
-
|
28
|
-
include RangeHelp
|
29
|
-
|
30
|
-
MSG = 'Create tables without `force: true` option.'
|
31
|
-
|
32
|
-
RESTRICT_ON_SEND = %i[
|
33
|
-
create_table
|
34
|
-
].freeze
|
35
|
-
|
36
|
-
# @param node [RuboCop::AST::SendNode]
|
37
|
-
# @return [void]
|
38
|
-
def on_send(node)
|
39
|
-
option_node = option_force_true_from_create_table(node)
|
40
|
-
return unless option_node
|
41
|
-
|
42
|
-
add_offense(option_node) do |corrector|
|
43
|
-
autocorrect(corrector, option_node)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
private
|
48
|
-
|
49
|
-
# @!method option_force_true_from_create_table(node)
|
50
|
-
# @param node [RuboCop::AST::SendNode]
|
51
|
-
# @return [RuboCop::AST::PairNode, nil]
|
52
|
-
def_node_matcher :option_force_true_from_create_table, <<~PATTERN
|
53
|
-
(send
|
54
|
-
nil?
|
55
|
-
:create_table
|
56
|
-
_
|
57
|
-
(hash
|
58
|
-
<
|
59
|
-
$(pair
|
60
|
-
(sym :force)
|
61
|
-
true
|
62
|
-
)
|
63
|
-
...
|
64
|
-
>
|
65
|
-
)
|
66
|
-
)
|
67
|
-
PATTERN
|
68
|
-
|
69
|
-
# @param corrector [RuboCop::Cop::Corrector]
|
70
|
-
# @param node [RuboCop::AST::PairNode]
|
71
|
-
# @return [void]
|
72
|
-
def autocorrect(
|
73
|
-
corrector,
|
74
|
-
node
|
75
|
-
)
|
76
|
-
corrector.remove(
|
77
|
-
range_with_surrounding_comma(
|
78
|
-
range_with_surrounding_space(
|
79
|
-
node.location.expression,
|
80
|
-
side: :left
|
81
|
-
),
|
82
|
-
:left
|
83
|
-
)
|
84
|
-
)
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
@@ -1,131 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RuboCop
|
4
|
-
module Cop
|
5
|
-
module Sevencop
|
6
|
-
# Prefer `jsonb` to `json`.
|
7
|
-
#
|
8
|
-
# In PostgreSQL, there is no equality operator for the json column type,
|
9
|
-
# which can cause errors for existing `SELECT DISTINCT` queries in your application.
|
10
|
-
#
|
11
|
-
# @safety
|
12
|
-
# Only meaningful in PostgreSQL.
|
13
|
-
#
|
14
|
-
# @example
|
15
|
-
# # bad
|
16
|
-
# add_column :users, :properties, :json
|
17
|
-
#
|
18
|
-
# # good
|
19
|
-
# add_column :users, :properties, :jsonb
|
20
|
-
class RailsMigrationJsonb < RuboCop::Cop::Base
|
21
|
-
extend AutoCorrector
|
22
|
-
|
23
|
-
MSG = 'Prefer `jsonb` to `json`.'
|
24
|
-
|
25
|
-
RESTRICT_ON_SEND = %i[
|
26
|
-
add_column
|
27
|
-
change
|
28
|
-
change_column
|
29
|
-
json
|
30
|
-
].freeze
|
31
|
-
|
32
|
-
# @param node [RuboCop::AST::SendNode]
|
33
|
-
# @return [void]
|
34
|
-
def on_send(node)
|
35
|
-
json_range = json_range_from_target_send_node(node)
|
36
|
-
return unless json_range
|
37
|
-
|
38
|
-
add_offense(json_range) do |corrector|
|
39
|
-
corrector.replace(json_range, 'jsonb')
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
private
|
44
|
-
|
45
|
-
# @!method json_type_node_from_add_column(node)
|
46
|
-
# @param node [RuboCop::AST::SendNode]
|
47
|
-
# @return [RuboCop::AST::SymNode, nil]
|
48
|
-
def_node_matcher :json_type_node_from_add_column, <<~PATTERN
|
49
|
-
(send
|
50
|
-
nil?
|
51
|
-
_
|
52
|
-
_
|
53
|
-
_
|
54
|
-
$(sym :json)
|
55
|
-
)
|
56
|
-
PATTERN
|
57
|
-
alias json_type_node_from_change_column json_type_node_from_add_column
|
58
|
-
|
59
|
-
# @!method json_type_node_from_change(node)
|
60
|
-
# @param node [RuboCop::AST::SendNode]
|
61
|
-
# @return [RuboCop::AST::SymNode, nil]
|
62
|
-
def_node_matcher :json_type_node_from_change, <<~PATTERN
|
63
|
-
(send
|
64
|
-
lvar
|
65
|
-
_
|
66
|
-
_
|
67
|
-
$(sym :json)
|
68
|
-
)
|
69
|
-
PATTERN
|
70
|
-
|
71
|
-
# @!method json_type_node_from_json(node)
|
72
|
-
# @param node [RuboCop::AST::SendNode]
|
73
|
-
# @return [RuboCop::AST::SendNode, nil]
|
74
|
-
def_node_matcher :json_type_node_from_json, <<~PATTERN
|
75
|
-
$(send
|
76
|
-
lvar
|
77
|
-
_
|
78
|
-
...
|
79
|
-
)
|
80
|
-
PATTERN
|
81
|
-
|
82
|
-
# @param corrector [RuboCop::Cop::Corrector]
|
83
|
-
# @param node [RuboCop::AST::SendNode, RuboCop::AST::SymNode]
|
84
|
-
# @return [void]
|
85
|
-
def autocorrect(
|
86
|
-
corrector,
|
87
|
-
node
|
88
|
-
)
|
89
|
-
corrector.replace(node, 'jsonb')
|
90
|
-
end
|
91
|
-
|
92
|
-
# @param node [RuboCop::AST::SendNode]
|
93
|
-
# @return [RuboCop::AST::SymNode, nil]
|
94
|
-
def json_node_from_target_send_node(node)
|
95
|
-
case node.method_name
|
96
|
-
when :add_column
|
97
|
-
json_type_node_from_add_column(node)
|
98
|
-
when :change
|
99
|
-
json_type_node_from_change(node)
|
100
|
-
when :change_column
|
101
|
-
json_type_node_from_change_column(node)
|
102
|
-
when :json
|
103
|
-
json_type_node_from_json(node)
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
# @param node [RuboCop::AST::SendNode, RuboCop::AST::SymNode]
|
108
|
-
# @return [Parser::Source::Range]
|
109
|
-
def json_range_from_json_node(node)
|
110
|
-
case node.type
|
111
|
-
when :send
|
112
|
-
node.location.selector
|
113
|
-
when :sym
|
114
|
-
node.location.expression.with(
|
115
|
-
begin_pos: node.location.expression.begin_pos + 1
|
116
|
-
)
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
# @param node [RuboCop::AST::SendNode]
|
121
|
-
# @return [Parser::Source::Range]
|
122
|
-
def json_range_from_target_send_node(node)
|
123
|
-
json_node = json_node_from_target_send_node(node)
|
124
|
-
return unless json_node
|
125
|
-
|
126
|
-
json_range_from_json_node(json_node)
|
127
|
-
end
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
@@ -1,258 +0,0 @@
|
|
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
|