rubocop-rails 2.4.1
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 +7 -0
- data/LICENSE.txt +20 -0
- data/README.md +92 -0
- data/bin/setup +7 -0
- data/config/default.yml +510 -0
- data/lib/rubocop-rails.rb +12 -0
- data/lib/rubocop/cop/mixin/target_rails_version.rb +16 -0
- data/lib/rubocop/cop/rails/action_filter.rb +111 -0
- data/lib/rubocop/cop/rails/active_record_aliases.rb +48 -0
- data/lib/rubocop/cop/rails/active_record_override.rb +82 -0
- data/lib/rubocop/cop/rails/active_support_aliases.rb +69 -0
- data/lib/rubocop/cop/rails/application_controller.rb +36 -0
- data/lib/rubocop/cop/rails/application_job.rb +40 -0
- data/lib/rubocop/cop/rails/application_mailer.rb +40 -0
- data/lib/rubocop/cop/rails/application_record.rb +40 -0
- data/lib/rubocop/cop/rails/assert_not.rb +44 -0
- data/lib/rubocop/cop/rails/belongs_to.rb +102 -0
- data/lib/rubocop/cop/rails/blank.rb +164 -0
- data/lib/rubocop/cop/rails/bulk_change_table.rb +293 -0
- data/lib/rubocop/cop/rails/create_table_with_timestamps.rb +91 -0
- data/lib/rubocop/cop/rails/date.rb +161 -0
- data/lib/rubocop/cop/rails/delegate.rb +132 -0
- data/lib/rubocop/cop/rails/delegate_allow_blank.rb +37 -0
- data/lib/rubocop/cop/rails/dynamic_find_by.rb +91 -0
- data/lib/rubocop/cop/rails/enum_hash.rb +75 -0
- data/lib/rubocop/cop/rails/enum_uniqueness.rb +65 -0
- data/lib/rubocop/cop/rails/environment_comparison.rb +68 -0
- data/lib/rubocop/cop/rails/exit.rb +67 -0
- data/lib/rubocop/cop/rails/file_path.rb +108 -0
- data/lib/rubocop/cop/rails/find_by.rb +55 -0
- data/lib/rubocop/cop/rails/find_each.rb +51 -0
- data/lib/rubocop/cop/rails/has_and_belongs_to_many.rb +25 -0
- data/lib/rubocop/cop/rails/has_many_or_has_one_dependent.rb +106 -0
- data/lib/rubocop/cop/rails/helper_instance_variable.rb +39 -0
- data/lib/rubocop/cop/rails/http_positional_arguments.rb +117 -0
- data/lib/rubocop/cop/rails/http_status.rb +160 -0
- data/lib/rubocop/cop/rails/ignored_skip_action_filter_option.rb +94 -0
- data/lib/rubocop/cop/rails/inverse_of.rb +246 -0
- data/lib/rubocop/cop/rails/lexically_scoped_action_filter.rb +175 -0
- data/lib/rubocop/cop/rails/link_to_blank.rb +98 -0
- data/lib/rubocop/cop/rails/not_null_column.rb +67 -0
- data/lib/rubocop/cop/rails/output.rb +49 -0
- data/lib/rubocop/cop/rails/output_safety.rb +99 -0
- data/lib/rubocop/cop/rails/pluralization_grammar.rb +107 -0
- data/lib/rubocop/cop/rails/presence.rb +148 -0
- data/lib/rubocop/cop/rails/present.rb +153 -0
- data/lib/rubocop/cop/rails/rake_environment.rb +91 -0
- data/lib/rubocop/cop/rails/read_write_attribute.rb +74 -0
- data/lib/rubocop/cop/rails/redundant_allow_nil.rb +111 -0
- data/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb +136 -0
- data/lib/rubocop/cop/rails/reflection_class_name.rb +37 -0
- data/lib/rubocop/cop/rails/refute_methods.rb +76 -0
- data/lib/rubocop/cop/rails/relative_date_constant.rb +102 -0
- data/lib/rubocop/cop/rails/request_referer.rb +56 -0
- data/lib/rubocop/cop/rails/reversible_migration.rb +284 -0
- data/lib/rubocop/cop/rails/safe_navigation.rb +85 -0
- data/lib/rubocop/cop/rails/safe_navigation_with_blank.rb +48 -0
- data/lib/rubocop/cop/rails/save_bang.rb +331 -0
- data/lib/rubocop/cop/rails/scope_args.rb +29 -0
- data/lib/rubocop/cop/rails/skips_model_validations.rb +87 -0
- data/lib/rubocop/cop/rails/time_zone.rb +249 -0
- data/lib/rubocop/cop/rails/uniq_before_pluck.rb +105 -0
- data/lib/rubocop/cop/rails/unknown_env.rb +84 -0
- data/lib/rubocop/cop/rails/validation.rb +147 -0
- data/lib/rubocop/cop/rails_cops.rb +61 -0
- data/lib/rubocop/rails.rb +12 -0
- data/lib/rubocop/rails/inject.rb +18 -0
- data/lib/rubocop/rails/version.rb +10 -0
- metadata +148 -0
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rubocop'
|
4
|
+
require 'rack/utils'
|
5
|
+
|
6
|
+
require_relative 'rubocop/rails'
|
7
|
+
require_relative 'rubocop/rails/version'
|
8
|
+
require_relative 'rubocop/rails/inject'
|
9
|
+
|
10
|
+
RuboCop::Rails::Inject.defaults!
|
11
|
+
|
12
|
+
require_relative 'rubocop/cop/rails_cops'
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
# Common functionality for checking target rails version.
|
6
|
+
module TargetRailsVersion
|
7
|
+
def minimum_target_rails_version(version)
|
8
|
+
@minimum_target_rails_version = version
|
9
|
+
end
|
10
|
+
|
11
|
+
def support_target_rails_version?(version)
|
12
|
+
@minimum_target_rails_version <= version
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# This cop enforces the consistent use of action filter methods.
|
7
|
+
#
|
8
|
+
# The cop is configurable and can enforce the use of the older
|
9
|
+
# something_filter methods or the newer something_action methods.
|
10
|
+
#
|
11
|
+
# @example EnforcedStyle: action (default)
|
12
|
+
# # bad
|
13
|
+
# after_filter :do_stuff
|
14
|
+
# append_around_filter :do_stuff
|
15
|
+
# skip_after_filter :do_stuff
|
16
|
+
#
|
17
|
+
# # good
|
18
|
+
# after_action :do_stuff
|
19
|
+
# append_around_action :do_stuff
|
20
|
+
# skip_after_action :do_stuff
|
21
|
+
#
|
22
|
+
# @example EnforcedStyle: filter
|
23
|
+
# # bad
|
24
|
+
# after_action :do_stuff
|
25
|
+
# append_around_action :do_stuff
|
26
|
+
# skip_after_action :do_stuff
|
27
|
+
#
|
28
|
+
# # good
|
29
|
+
# after_filter :do_stuff
|
30
|
+
# append_around_filter :do_stuff
|
31
|
+
# skip_after_filter :do_stuff
|
32
|
+
class ActionFilter < Cop
|
33
|
+
include ConfigurableEnforcedStyle
|
34
|
+
|
35
|
+
MSG = 'Prefer `%<prefer>s` over `%<current>s`.'
|
36
|
+
|
37
|
+
FILTER_METHODS = %i[
|
38
|
+
after_filter
|
39
|
+
append_after_filter
|
40
|
+
append_around_filter
|
41
|
+
append_before_filter
|
42
|
+
around_filter
|
43
|
+
before_filter
|
44
|
+
prepend_after_filter
|
45
|
+
prepend_around_filter
|
46
|
+
prepend_before_filter
|
47
|
+
skip_after_filter
|
48
|
+
skip_around_filter
|
49
|
+
skip_before_filter
|
50
|
+
skip_filter
|
51
|
+
].freeze
|
52
|
+
|
53
|
+
ACTION_METHODS = %i[
|
54
|
+
after_action
|
55
|
+
append_after_action
|
56
|
+
append_around_action
|
57
|
+
append_before_action
|
58
|
+
around_action
|
59
|
+
before_action
|
60
|
+
prepend_after_action
|
61
|
+
prepend_around_action
|
62
|
+
prepend_before_action
|
63
|
+
skip_after_action
|
64
|
+
skip_around_action
|
65
|
+
skip_before_action
|
66
|
+
skip_action_callback
|
67
|
+
].freeze
|
68
|
+
|
69
|
+
def on_block(node)
|
70
|
+
check_method_node(node.send_node)
|
71
|
+
end
|
72
|
+
|
73
|
+
def on_send(node)
|
74
|
+
check_method_node(node) unless node.receiver
|
75
|
+
end
|
76
|
+
|
77
|
+
def autocorrect(node)
|
78
|
+
lambda do |corrector|
|
79
|
+
corrector.replace(node.loc.selector,
|
80
|
+
preferred_method(node.loc.selector.source).to_s)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def check_method_node(node)
|
87
|
+
return unless bad_methods.include?(node.method_name)
|
88
|
+
|
89
|
+
add_offense(node, location: :selector)
|
90
|
+
end
|
91
|
+
|
92
|
+
def message(node)
|
93
|
+
format(MSG, prefer: preferred_method(node.method_name),
|
94
|
+
current: node.method_name)
|
95
|
+
end
|
96
|
+
|
97
|
+
def bad_methods
|
98
|
+
style == :action ? FILTER_METHODS : ACTION_METHODS
|
99
|
+
end
|
100
|
+
|
101
|
+
def good_methods
|
102
|
+
style == :action ? ACTION_METHODS : FILTER_METHODS
|
103
|
+
end
|
104
|
+
|
105
|
+
def preferred_method(method)
|
106
|
+
good_methods[bad_methods.index(method.to_sym)]
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# Checks that ActiveRecord aliases are not used. The direct method names
|
7
|
+
# are more clear and easier to read.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# #bad
|
11
|
+
# Book.update_attributes!(author: 'Alice')
|
12
|
+
#
|
13
|
+
# #good
|
14
|
+
# Book.update!(author: 'Alice')
|
15
|
+
class ActiveRecordAliases < Cop
|
16
|
+
MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
|
17
|
+
|
18
|
+
ALIASES = {
|
19
|
+
update_attributes: :update,
|
20
|
+
update_attributes!: :update!
|
21
|
+
}.freeze
|
22
|
+
|
23
|
+
def on_send(node)
|
24
|
+
ALIASES.each do |bad, good|
|
25
|
+
next unless node.method?(bad)
|
26
|
+
|
27
|
+
add_offense(node,
|
28
|
+
message: format(MSG, prefer: good, current: bad),
|
29
|
+
location: :selector,
|
30
|
+
severity: :warning)
|
31
|
+
break
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
alias on_csend on_send
|
36
|
+
|
37
|
+
def autocorrect(node)
|
38
|
+
lambda do |corrector|
|
39
|
+
corrector.replace(
|
40
|
+
node.loc.selector,
|
41
|
+
ALIASES[node.method_name].to_s
|
42
|
+
)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# Checks for overriding built-in Active Record methods instead of using
|
7
|
+
# callbacks.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # bad
|
11
|
+
# class Book < ApplicationRecord
|
12
|
+
# def save
|
13
|
+
# self.title = title.upcase!
|
14
|
+
# super
|
15
|
+
# end
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# # good
|
19
|
+
# class Book < ApplicationRecord
|
20
|
+
# before_save :upcase_title
|
21
|
+
#
|
22
|
+
# def upcase_title
|
23
|
+
# self.title = title.upcase!
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
class ActiveRecordOverride < Cop
|
28
|
+
MSG =
|
29
|
+
'Use %<prefer>s callbacks instead of overriding the Active Record ' \
|
30
|
+
'method `%<bad>s`.'
|
31
|
+
BAD_METHODS = %i[create destroy save update].freeze
|
32
|
+
ACTIVE_RECORD_CLASSES = %w[ApplicationRecord ActiveModel::Base
|
33
|
+
ActiveRecord::Base].freeze
|
34
|
+
|
35
|
+
def on_def(node)
|
36
|
+
return unless BAD_METHODS.include?(node.method_name)
|
37
|
+
|
38
|
+
parent_class_name = find_parent_class_name(node)
|
39
|
+
return unless active_model?(parent_class_name)
|
40
|
+
|
41
|
+
return unless node.descendants.any?(&:zsuper_type?)
|
42
|
+
|
43
|
+
add_offense(node, message: message(node.method_name))
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def active_model?(parent_class_name)
|
49
|
+
ACTIVE_RECORD_CLASSES.include?(parent_class_name)
|
50
|
+
end
|
51
|
+
|
52
|
+
def callback_names(method_name)
|
53
|
+
names = %w[before_ around_ after_].map do |prefix|
|
54
|
+
"`#{prefix}#{method_name}`"
|
55
|
+
end
|
56
|
+
|
57
|
+
names[-1] = "or #{names.last}"
|
58
|
+
|
59
|
+
names.join(', ')
|
60
|
+
end
|
61
|
+
|
62
|
+
def message(method_name)
|
63
|
+
format(MSG, prefer: callback_names(method_name), bad: method_name)
|
64
|
+
end
|
65
|
+
|
66
|
+
def find_parent_class_name(node)
|
67
|
+
return nil unless node
|
68
|
+
|
69
|
+
if node.class_type?
|
70
|
+
parent_class_name = node.node_parts[1]
|
71
|
+
|
72
|
+
return nil if parent_class_name.nil?
|
73
|
+
|
74
|
+
return parent_class_name.source
|
75
|
+
end
|
76
|
+
|
77
|
+
find_parent_class_name(node.parent)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# This cop checks that ActiveSupport aliases to core ruby methods
|
7
|
+
# are not used.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # good
|
11
|
+
# 'some_string'.start_with?('prefix')
|
12
|
+
# 'some_string'.end_with?('suffix')
|
13
|
+
# [1, 2, 'a'] << 'b'
|
14
|
+
# [1, 2, 'a'].unshift('b')
|
15
|
+
#
|
16
|
+
# # bad
|
17
|
+
# 'some_string'.starts_with?('prefix')
|
18
|
+
# 'some_string'.ends_with?('suffix')
|
19
|
+
# [1, 2, 'a'].append('b')
|
20
|
+
# [1, 2, 'a'].prepend('b')
|
21
|
+
#
|
22
|
+
class ActiveSupportAliases < Cop
|
23
|
+
MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
|
24
|
+
|
25
|
+
ALIASES = {
|
26
|
+
starts_with?: {
|
27
|
+
original: :start_with?, matcher: '(send str :starts_with? _)'
|
28
|
+
},
|
29
|
+
ends_with?: {
|
30
|
+
original: :end_with?, matcher: '(send str :ends_with? _)'
|
31
|
+
},
|
32
|
+
append: { original: :<<, matcher: '(send array :append _)' },
|
33
|
+
prepend: { original: :unshift, matcher: '(send array :prepend _)' }
|
34
|
+
}.freeze
|
35
|
+
|
36
|
+
ALIASES.each do |aliased_method, options|
|
37
|
+
def_node_matcher aliased_method, options[:matcher]
|
38
|
+
end
|
39
|
+
|
40
|
+
def on_send(node)
|
41
|
+
ALIASES.each_key do |aliased_method|
|
42
|
+
register_offense(node, aliased_method) if
|
43
|
+
public_send(aliased_method, node)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def autocorrect(node)
|
48
|
+
return false if append(node)
|
49
|
+
|
50
|
+
lambda do |corrector|
|
51
|
+
method_name = node.loc.selector.source
|
52
|
+
replacement = ALIASES[method_name.to_sym][:original]
|
53
|
+
corrector.replace(node.loc.selector, replacement.to_s)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def register_offense(node, method_name)
|
60
|
+
add_offense(
|
61
|
+
node,
|
62
|
+
message: format(MSG, prefer: ALIASES[method_name][:original],
|
63
|
+
current: method_name)
|
64
|
+
)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# This cop checks that controllers subclass ApplicationController.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
#
|
10
|
+
# # good
|
11
|
+
# class MyController < ApplicationController
|
12
|
+
# # ...
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# # bad
|
16
|
+
# class MyController < ActionController::Base
|
17
|
+
# # ...
|
18
|
+
# end
|
19
|
+
class ApplicationController < Cop
|
20
|
+
MSG = 'Controllers should subclass `ApplicationController`.'
|
21
|
+
SUPERCLASS = 'ApplicationController'
|
22
|
+
BASE_PATTERN = '(const (const nil? :ActionController) :Base)'
|
23
|
+
|
24
|
+
# rubocop:disable Layout/ClassStructure
|
25
|
+
include RuboCop::Cop::EnforceSuperclass
|
26
|
+
# rubocop:enable Layout/ClassStructure
|
27
|
+
|
28
|
+
def autocorrect(node)
|
29
|
+
lambda do |corrector|
|
30
|
+
corrector.replace(node.source_range, self.class::SUPERCLASS)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# This cop checks that jobs subclass ApplicationJob with Rails 5.0.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
#
|
10
|
+
# # good
|
11
|
+
# class Rails5Job < ApplicationJob
|
12
|
+
# # ...
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# # bad
|
16
|
+
# class Rails4Job < ActiveJob::Base
|
17
|
+
# # ...
|
18
|
+
# end
|
19
|
+
class ApplicationJob < Cop
|
20
|
+
extend TargetRailsVersion
|
21
|
+
|
22
|
+
minimum_target_rails_version 5.0
|
23
|
+
|
24
|
+
MSG = 'Jobs should subclass `ApplicationJob`.'
|
25
|
+
SUPERCLASS = 'ApplicationJob'
|
26
|
+
BASE_PATTERN = '(const (const nil? :ActiveJob) :Base)'
|
27
|
+
|
28
|
+
# rubocop:disable Layout/ClassStructure
|
29
|
+
include RuboCop::Cop::EnforceSuperclass
|
30
|
+
# rubocop:enable Layout/ClassStructure
|
31
|
+
|
32
|
+
def autocorrect(node)
|
33
|
+
lambda do |corrector|
|
34
|
+
corrector.replace(node.source_range, self.class::SUPERCLASS)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# This cop checks that mailers subclass ApplicationMailer with Rails 5.0.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
#
|
10
|
+
# # good
|
11
|
+
# class MyMailer < ApplicationMailer
|
12
|
+
# # ...
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# # bad
|
16
|
+
# class MyMailer < ActionMailer::Base
|
17
|
+
# # ...
|
18
|
+
# end
|
19
|
+
class ApplicationMailer < Cop
|
20
|
+
extend TargetRailsVersion
|
21
|
+
|
22
|
+
minimum_target_rails_version 5.0
|
23
|
+
|
24
|
+
MSG = 'Mailers should subclass `ApplicationMailer`.'
|
25
|
+
SUPERCLASS = 'ApplicationMailer'
|
26
|
+
BASE_PATTERN = '(const (const nil? :ActionMailer) :Base)'
|
27
|
+
|
28
|
+
# rubocop:disable Layout/ClassStructure
|
29
|
+
include RuboCop::Cop::EnforceSuperclass
|
30
|
+
# rubocop:enable Layout/ClassStructure
|
31
|
+
|
32
|
+
def autocorrect(node)
|
33
|
+
lambda do |corrector|
|
34
|
+
corrector.replace(node.source_range, self.class::SUPERCLASS)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|