rubocop-rails 2.6.0 → 2.9.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/README.md +16 -0
- data/config/default.yml +189 -6
- data/lib/rubocop/cop/mixin/active_record_helper.rb +12 -3
- data/lib/rubocop/cop/mixin/enforce_superclass.rb +40 -0
- data/lib/rubocop/cop/mixin/index_method.rb +25 -11
- data/lib/rubocop/cop/rails/action_filter.rb +10 -14
- data/lib/rubocop/cop/rails/active_record_aliases.rb +13 -17
- data/lib/rubocop/cop/rails/active_record_callbacks_order.rb +148 -0
- data/lib/rubocop/cop/rails/active_record_override.rb +1 -1
- data/lib/rubocop/cop/rails/active_support_aliases.rb +12 -21
- data/lib/rubocop/cop/rails/after_commit_override.rb +91 -0
- data/lib/rubocop/cop/rails/application_controller.rb +3 -7
- data/lib/rubocop/cop/rails/application_job.rb +2 -1
- data/lib/rubocop/cop/rails/application_mailer.rb +2 -7
- data/lib/rubocop/cop/rails/application_record.rb +2 -7
- data/lib/rubocop/cop/rails/arel_star.rb +41 -0
- data/lib/rubocop/cop/rails/assert_not.rb +8 -10
- data/lib/rubocop/cop/rails/attribute_default_block_value.rb +90 -0
- data/lib/rubocop/cop/rails/belongs_to.rb +9 -18
- data/lib/rubocop/cop/rails/blank.rb +27 -27
- data/lib/rubocop/cop/rails/bulk_change_table.rb +1 -1
- data/lib/rubocop/cop/rails/content_tag.rb +20 -33
- data/lib/rubocop/cop/rails/create_table_with_timestamps.rb +2 -1
- data/lib/rubocop/cop/rails/date.rb +10 -11
- data/lib/rubocop/cop/rails/default_scope.rb +61 -0
- data/lib/rubocop/cop/rails/delegate.rb +10 -10
- data/lib/rubocop/cop/rails/delegate_allow_blank.rb +7 -8
- data/lib/rubocop/cop/rails/dynamic_find_by.rb +13 -11
- data/lib/rubocop/cop/rails/enum_hash.rb +11 -10
- data/lib/rubocop/cop/rails/enum_uniqueness.rb +2 -1
- data/lib/rubocop/cop/rails/environment_comparison.rb +18 -14
- data/lib/rubocop/cop/rails/exit.rb +4 -10
- data/lib/rubocop/cop/rails/file_path.rb +5 -4
- data/lib/rubocop/cop/rails/find_by.rb +13 -13
- data/lib/rubocop/cop/rails/find_by_id.rb +94 -0
- data/lib/rubocop/cop/rails/find_each.rb +16 -14
- data/lib/rubocop/cop/rails/has_and_belongs_to_many.rb +3 -2
- data/lib/rubocop/cop/rails/has_many_or_has_one_dependent.rb +4 -7
- data/lib/rubocop/cop/rails/helper_instance_variable.rb +4 -2
- data/lib/rubocop/cop/rails/http_positional_arguments.rb +25 -21
- data/lib/rubocop/cop/rails/http_status.rb +7 -9
- data/lib/rubocop/cop/rails/ignored_skip_action_filter_option.rb +8 -6
- data/lib/rubocop/cop/rails/index_by.rb +11 -2
- data/lib/rubocop/cop/rails/index_with.rb +11 -2
- data/lib/rubocop/cop/rails/inquiry.rb +39 -0
- data/lib/rubocop/cop/rails/inverse_of.rb +3 -2
- data/lib/rubocop/cop/rails/lexically_scoped_action_filter.rb +17 -15
- data/lib/rubocop/cop/rails/link_to_blank.rb +20 -20
- data/lib/rubocop/cop/rails/mailer_name.rb +86 -0
- data/lib/rubocop/cop/rails/match_route.rb +120 -0
- data/lib/rubocop/cop/rails/negate_include.rb +41 -0
- data/lib/rubocop/cop/rails/not_null_column.rb +2 -1
- data/lib/rubocop/cop/rails/order_by_id.rb +52 -0
- data/lib/rubocop/cop/rails/output.rb +5 -2
- data/lib/rubocop/cop/rails/output_safety.rb +3 -2
- data/lib/rubocop/cop/rails/pick.rb +21 -15
- data/lib/rubocop/cop/rails/pluck.rb +56 -0
- data/lib/rubocop/cop/rails/pluck_id.rb +56 -0
- data/lib/rubocop/cop/rails/pluck_in_where.rb +70 -0
- data/lib/rubocop/cop/rails/pluralization_grammar.rb +10 -14
- data/lib/rubocop/cop/rails/presence.rb +12 -13
- data/lib/rubocop/cop/rails/present.rb +30 -24
- data/lib/rubocop/cop/rails/rake_environment.rb +9 -11
- data/lib/rubocop/cop/rails/read_write_attribute.rb +12 -11
- data/lib/rubocop/cop/rails/redundant_allow_nil.rb +29 -31
- data/lib/rubocop/cop/rails/redundant_foreign_key.rb +9 -12
- data/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb +11 -10
- data/lib/rubocop/cop/rails/reflection_class_name.rb +4 -3
- data/lib/rubocop/cop/rails/refute_methods.rb +9 -10
- data/lib/rubocop/cop/rails/relative_date_constant.rb +20 -9
- data/lib/rubocop/cop/rails/render_inline.rb +41 -0
- data/lib/rubocop/cop/rails/render_plain_text.rb +71 -0
- data/lib/rubocop/cop/rails/request_referer.rb +7 -7
- data/lib/rubocop/cop/rails/reversible_migration.rb +82 -7
- data/lib/rubocop/cop/rails/safe_navigation.rb +12 -11
- data/lib/rubocop/cop/rails/safe_navigation_with_blank.rb +5 -10
- data/lib/rubocop/cop/rails/save_bang.rb +19 -22
- data/lib/rubocop/cop/rails/scope_args.rb +2 -1
- data/lib/rubocop/cop/rails/short_i18n.rb +74 -0
- data/lib/rubocop/cop/rails/skips_model_validations.rb +46 -11
- data/lib/rubocop/cop/rails/squished_sql_heredocs.rb +82 -0
- data/lib/rubocop/cop/rails/time_zone.rb +22 -20
- data/lib/rubocop/cop/rails/uniq_before_pluck.rb +10 -10
- data/lib/rubocop/cop/rails/unique_validation_without_index.rb +18 -8
- data/lib/rubocop/cop/rails/unknown_env.rb +15 -4
- data/lib/rubocop/cop/rails/validation.rb +15 -14
- data/lib/rubocop/cop/rails/where_equals.rb +94 -0
- data/lib/rubocop/cop/rails/where_exists.rb +126 -0
- data/lib/rubocop/cop/rails/where_not.rb +97 -0
- data/lib/rubocop/cop/rails_cops.rb +22 -0
- data/lib/rubocop/rails/schema_loader.rb +4 -4
- data/lib/rubocop/rails/schema_loader/schema.rb +5 -5
- data/lib/rubocop/rails/version.rb +5 -1
- metadata +37 -9
@@ -12,27 +12,30 @@ module RuboCop
|
|
12
12
|
#
|
13
13
|
# # good
|
14
14
|
# User.all.find_each
|
15
|
-
|
15
|
+
#
|
16
|
+
# @example IgnoredMethods: ['order']
|
17
|
+
# # good
|
18
|
+
# User.order(:foo).each
|
19
|
+
class FindEach < Base
|
20
|
+
extend AutoCorrector
|
21
|
+
|
16
22
|
MSG = 'Use `find_each` instead of `each`.'
|
23
|
+
RESTRICT_ON_SEND = %i[each].freeze
|
17
24
|
|
18
25
|
SCOPE_METHODS = %i[
|
19
26
|
all eager_load includes joins left_joins left_outer_joins not preload
|
20
27
|
references unscoped where
|
21
28
|
].freeze
|
22
|
-
IGNORED_METHODS = %i[order limit select].freeze
|
23
29
|
|
24
30
|
def on_send(node)
|
25
|
-
return unless node.receiver&.send_type?
|
26
|
-
node.method?(:each)
|
27
|
-
|
31
|
+
return unless node.receiver&.send_type?
|
28
32
|
return unless SCOPE_METHODS.include?(node.receiver.method_name)
|
29
|
-
return if method_chain(node).any? { |m|
|
30
|
-
|
31
|
-
add_offense(node, location: :selector)
|
32
|
-
end
|
33
|
+
return if method_chain(node).any? { |m| ignored?(m) }
|
33
34
|
|
34
|
-
|
35
|
-
|
35
|
+
range = node.loc.selector
|
36
|
+
add_offense(range) do |corrector|
|
37
|
+
corrector.replace(range, 'find_each')
|
38
|
+
end
|
36
39
|
end
|
37
40
|
|
38
41
|
private
|
@@ -41,9 +44,8 @@ module RuboCop
|
|
41
44
|
node.each_node(:send).map(&:method_name)
|
42
45
|
end
|
43
46
|
|
44
|
-
def
|
45
|
-
|
46
|
-
IGNORED_METHODS.include?(relation_method)
|
47
|
+
def ignored?(relation_method)
|
48
|
+
cop_config['IgnoredMethods'].include?(relation_method)
|
47
49
|
end
|
48
50
|
end
|
49
51
|
end
|
@@ -11,13 +11,14 @@ module RuboCop
|
|
11
11
|
#
|
12
12
|
# # good
|
13
13
|
# # has_many :ingredients, through: :recipe_ingredients
|
14
|
-
class HasAndBelongsToMany <
|
14
|
+
class HasAndBelongsToMany < Base
|
15
15
|
MSG = 'Prefer `has_many :through` to `has_and_belongs_to_many`.'
|
16
|
+
RESTRICT_ON_SEND = %i[has_and_belongs_to_many].freeze
|
16
17
|
|
17
18
|
def on_send(node)
|
18
19
|
return unless node.command?(:has_and_belongs_to_many)
|
19
20
|
|
20
|
-
add_offense(node
|
21
|
+
add_offense(node.loc.selector)
|
21
22
|
end
|
22
23
|
end
|
23
24
|
end
|
@@ -20,8 +20,9 @@ module RuboCop
|
|
20
20
|
# has_one :avatar, dependent: :destroy
|
21
21
|
# has_many :patients, through: :appointments
|
22
22
|
# end
|
23
|
-
class HasManyOrHasOneDependent <
|
23
|
+
class HasManyOrHasOneDependent < Base
|
24
24
|
MSG = 'Specify a `:dependent` option.'
|
25
|
+
RESTRICT_ON_SEND = %i[has_many has_one].freeze
|
25
26
|
|
26
27
|
def_node_search :active_resource_class?, <<~PATTERN
|
27
28
|
(const (const nil? :ActiveResource) :Base)
|
@@ -52,14 +53,10 @@ module RuboCop
|
|
52
53
|
|
53
54
|
def on_send(node)
|
54
55
|
return if active_resource?(node.parent)
|
55
|
-
|
56
|
-
unless association_without_options?(node)
|
57
|
-
return if valid_options?(association_with_options?(node))
|
58
|
-
end
|
59
|
-
|
56
|
+
return if !association_without_options?(node) && valid_options?(association_with_options?(node))
|
60
57
|
return if valid_options_in_with_options_block?(node)
|
61
58
|
|
62
|
-
add_offense(node
|
59
|
+
add_offense(node.loc.selector)
|
63
60
|
end
|
64
61
|
|
65
62
|
private
|
@@ -23,7 +23,7 @@ module RuboCop
|
|
23
23
|
# def welcome_message(user)
|
24
24
|
# "Hello #{user.name}"
|
25
25
|
# end
|
26
|
-
class HelperInstanceVariable <
|
26
|
+
class HelperInstanceVariable < Base
|
27
27
|
MSG = 'Do not use instance variables in helpers.'
|
28
28
|
|
29
29
|
def on_ivar(node)
|
@@ -31,7 +31,9 @@ module RuboCop
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def on_ivasgn(node)
|
34
|
-
|
34
|
+
return if node.parent.or_asgn_type?
|
35
|
+
|
36
|
+
add_offense(node.loc.name)
|
35
37
|
end
|
36
38
|
end
|
37
39
|
end
|
@@ -16,7 +16,9 @@ module RuboCop
|
|
16
16
|
#
|
17
17
|
# # good
|
18
18
|
# get :new, params: { user_id: 1 }
|
19
|
-
|
19
|
+
# get :new, **options
|
20
|
+
class HttpPositionalArguments < Base
|
21
|
+
extend AutoCorrector
|
20
22
|
extend TargetRailsVersion
|
21
23
|
|
22
24
|
MSG = 'Use keyword arguments instead of ' \
|
@@ -24,36 +26,37 @@ module RuboCop
|
|
24
26
|
KEYWORD_ARGS = %i[
|
25
27
|
method params session body flash xhr as headers env to
|
26
28
|
].freeze
|
27
|
-
|
29
|
+
RESTRICT_ON_SEND = %i[get post put patch delete head].freeze
|
28
30
|
|
29
31
|
minimum_target_rails_version 5.0
|
30
32
|
|
31
33
|
def_node_matcher :http_request?, <<~PATTERN
|
32
|
-
(send nil? {#{
|
34
|
+
(send nil? {#{RESTRICT_ON_SEND.map(&:inspect).join(' ')}} !nil? $_ ...)
|
35
|
+
PATTERN
|
36
|
+
|
37
|
+
def_node_matcher :kwsplat_hash?, <<~PATTERN
|
38
|
+
(hash (kwsplat _))
|
33
39
|
PATTERN
|
34
40
|
|
35
41
|
def on_send(node)
|
36
42
|
http_request?(node) do |data|
|
37
43
|
return unless needs_conversion?(data)
|
38
44
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
def autocorrect(node)
|
55
|
-
lambda do |corrector|
|
56
|
-
corrector.replace(node.loc.expression, correction(node))
|
45
|
+
message = format(MSG, verb: node.method_name)
|
46
|
+
|
47
|
+
add_offense(node.loc.selector, message: message) do |corrector|
|
48
|
+
# given a pre Rails 5 method: get :new, {user_id: @user.id}, {}
|
49
|
+
#
|
50
|
+
# @return lambda of auto correct procedure
|
51
|
+
# the result should look like:
|
52
|
+
# get :new, params: { user_id: @user.id }, session: {}
|
53
|
+
# the http_method is the method used to call the controller
|
54
|
+
# the controller node can be a symbol, method, object or string
|
55
|
+
# that represents the path/action on the Rails controller
|
56
|
+
# the data is the http parameters and environment sent in
|
57
|
+
# the Rails 5 http call
|
58
|
+
corrector.replace(node.loc.expression, correction(node))
|
59
|
+
end
|
57
60
|
end
|
58
61
|
end
|
59
62
|
|
@@ -61,6 +64,7 @@ module RuboCop
|
|
61
64
|
|
62
65
|
def needs_conversion?(data)
|
63
66
|
return true unless data.hash_type?
|
67
|
+
return false if kwsplat_hash?(data)
|
64
68
|
|
65
69
|
data.each_pair.none? do |pair|
|
66
70
|
special_keyword_arg?(pair.key) ||
|
@@ -31,8 +31,11 @@ module RuboCop
|
|
31
31
|
# render plain: 'foo/bar', status: 304
|
32
32
|
# redirect_to root_url, status: 301
|
33
33
|
#
|
34
|
-
class HttpStatus <
|
34
|
+
class HttpStatus < Base
|
35
35
|
include ConfigurableEnforcedStyle
|
36
|
+
extend AutoCorrector
|
37
|
+
|
38
|
+
RESTRICT_ON_SEND = %i[render redirect_to].freeze
|
36
39
|
|
37
40
|
def_node_matcher :http_status, <<~PATTERN
|
38
41
|
{
|
@@ -53,14 +56,9 @@ module RuboCop
|
|
53
56
|
checker = checker_class.new(status)
|
54
57
|
return unless checker.offensive?
|
55
58
|
|
56
|
-
add_offense(checker.node, message: checker.message)
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
def autocorrect(node)
|
61
|
-
lambda do |corrector|
|
62
|
-
checker = checker_class.new(node)
|
63
|
-
corrector.replace(node.loc.expression, checker.preferred_style)
|
59
|
+
add_offense(checker.node, message: checker.message) do |corrector|
|
60
|
+
corrector.replace(checker.node.loc.expression, checker.preferred_style)
|
61
|
+
end
|
64
62
|
end
|
65
63
|
end
|
66
64
|
|
@@ -37,18 +37,20 @@ module RuboCop
|
|
37
37
|
# end
|
38
38
|
#
|
39
39
|
# @see https://api.rubyonrails.org/classes/AbstractController/Callbacks/ClassMethods.html#method-i-_normalize_callback_options
|
40
|
-
class IgnoredSkipActionFilterOption <
|
40
|
+
class IgnoredSkipActionFilterOption < Base
|
41
41
|
MSG = <<~MSG.chomp.freeze
|
42
42
|
`%<ignore>s` option will be ignored when `%<prefer>s` and `%<ignore>s` are used together.
|
43
43
|
MSG
|
44
44
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
45
|
+
RESTRICT_ON_SEND = %i[
|
46
|
+
skip_after_action
|
47
|
+
skip_around_action
|
48
|
+
skip_before_action
|
49
|
+
skip_action_callback
|
50
50
|
].freeze
|
51
51
|
|
52
|
+
FILTERS = RESTRICT_ON_SEND.map { |method_name| ":#{method_name}" }
|
53
|
+
|
52
54
|
def_node_matcher :filter_options, <<~PATTERN
|
53
55
|
(send
|
54
56
|
nil?
|
@@ -11,19 +11,28 @@ module RuboCop
|
|
11
11
|
# @example
|
12
12
|
# # bad
|
13
13
|
# [1, 2, 3].each_with_object({}) { |el, h| h[foo(el)] = el }
|
14
|
+
# [1, 2, 3].to_h { |el| [foo(el), el] }
|
14
15
|
# [1, 2, 3].map { |el| [foo(el), el] }.to_h
|
15
16
|
# Hash[[1, 2, 3].collect { |el| [foo(el), el] }]
|
16
17
|
#
|
17
18
|
# # good
|
18
19
|
# [1, 2, 3].index_by { |el| foo(el) }
|
19
|
-
class IndexBy <
|
20
|
+
class IndexBy < Base
|
20
21
|
include IndexMethod
|
22
|
+
extend AutoCorrector
|
21
23
|
|
22
24
|
def_node_matcher :on_bad_each_with_object, <<~PATTERN
|
23
25
|
(block
|
24
26
|
({send csend} _ :each_with_object (hash))
|
25
27
|
(args (arg $_el) (arg _memo))
|
26
|
-
({send csend} (lvar _memo) :[]=
|
28
|
+
({send csend} (lvar _memo) :[]= $!`_memo (lvar _el)))
|
29
|
+
PATTERN
|
30
|
+
|
31
|
+
def_node_matcher :on_bad_to_h, <<~PATTERN
|
32
|
+
(block
|
33
|
+
({send csend} _ :to_h)
|
34
|
+
(args (arg $_el))
|
35
|
+
(array $_ (lvar _el)))
|
27
36
|
PATTERN
|
28
37
|
|
29
38
|
def_node_matcher :on_bad_map_to_h, <<~PATTERN
|
@@ -11,12 +11,14 @@ module RuboCop
|
|
11
11
|
# @example
|
12
12
|
# # bad
|
13
13
|
# [1, 2, 3].each_with_object({}) { |el, h| h[el] = foo(el) }
|
14
|
+
# [1, 2, 3].to_h { |el| [el, foo(el)] }
|
14
15
|
# [1, 2, 3].map { |el| [el, foo(el)] }.to_h
|
15
16
|
# Hash[[1, 2, 3].collect { |el| [el, foo(el)] }]
|
16
17
|
#
|
17
18
|
# # good
|
18
19
|
# [1, 2, 3].index_with { |el| foo(el) }
|
19
|
-
class IndexWith <
|
20
|
+
class IndexWith < Base
|
21
|
+
extend AutoCorrector
|
20
22
|
extend TargetRailsVersion
|
21
23
|
include IndexMethod
|
22
24
|
|
@@ -26,7 +28,14 @@ module RuboCop
|
|
26
28
|
(block
|
27
29
|
({send csend} _ :each_with_object (hash))
|
28
30
|
(args (arg $_el) (arg _memo))
|
29
|
-
({send csend} (lvar _memo) :[]= (lvar _el)
|
31
|
+
({send csend} (lvar _memo) :[]= (lvar _el) $!`_memo))
|
32
|
+
PATTERN
|
33
|
+
|
34
|
+
def_node_matcher :on_bad_to_h, <<~PATTERN
|
35
|
+
(block
|
36
|
+
({send csend} _ :to_h)
|
37
|
+
(args (arg $_el))
|
38
|
+
(array (lvar _el) $_))
|
30
39
|
PATTERN
|
31
40
|
|
32
41
|
def_node_matcher :on_bad_map_to_h, <<~PATTERN
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# This cop checks that Active Support's `inquiry` method is not used.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad - String#inquiry
|
10
|
+
# ruby = 'two'.inquiry
|
11
|
+
# ruby.two?
|
12
|
+
#
|
13
|
+
# # good
|
14
|
+
# ruby = 'two'
|
15
|
+
# ruby == 'two'
|
16
|
+
#
|
17
|
+
# # bad - Array#inquiry
|
18
|
+
# pets = %w(cat dog).inquiry
|
19
|
+
# pets.gopher?
|
20
|
+
#
|
21
|
+
# # good
|
22
|
+
# pets = %w(cat dog)
|
23
|
+
# pets.include? 'cat'
|
24
|
+
#
|
25
|
+
class Inquiry < Base
|
26
|
+
MSG = "Prefer Ruby's comparison operators over Active Support's `inquiry`."
|
27
|
+
RESTRICT_ON_SEND = %i[inquiry].freeze
|
28
|
+
|
29
|
+
def on_send(node)
|
30
|
+
return unless node.arguments.empty?
|
31
|
+
return unless (receiver = node.receiver)
|
32
|
+
return if !receiver.str_type? && !receiver.array_type?
|
33
|
+
|
34
|
+
add_offense(node.loc.selector)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -128,10 +128,11 @@ module RuboCop
|
|
128
128
|
#
|
129
129
|
# @see https://guides.rubyonrails.org/association_basics.html#bi-directional-associations
|
130
130
|
# @see https://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#module-ActiveRecord::Associations::ClassMethods-label-Setting+Inverses
|
131
|
-
class InverseOf <
|
131
|
+
class InverseOf < Base
|
132
132
|
SPECIFY_MSG = 'Specify an `:inverse_of` option.'
|
133
133
|
NIL_MSG = 'You specified `inverse_of: nil`, you probably meant to ' \
|
134
134
|
'use `inverse_of: false`.'
|
135
|
+
RESTRICT_ON_SEND = %i[has_many has_one belongs_to].freeze
|
135
136
|
|
136
137
|
def_node_matcher :association_recv_arguments, <<~PATTERN
|
137
138
|
(send $_ {:has_many :has_one :belongs_to} _ $...)
|
@@ -185,7 +186,7 @@ module RuboCop
|
|
185
186
|
|
186
187
|
return if options_contain_inverse_of?(options)
|
187
188
|
|
188
|
-
add_offense(node, message: message(options)
|
189
|
+
add_offense(node.loc.selector, message: message(options))
|
189
190
|
end
|
190
191
|
|
191
192
|
def scope?(arguments)
|
@@ -82,25 +82,27 @@ module RuboCop
|
|
82
82
|
# @content = Article.find(params[:article_id])
|
83
83
|
# end
|
84
84
|
# end
|
85
|
-
class LexicallyScopedActionFilter <
|
85
|
+
class LexicallyScopedActionFilter < Base
|
86
86
|
MSG = '%<action>s not explicitly defined on the %<type>s.'
|
87
87
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
88
|
+
RESTRICT_ON_SEND = %i[
|
89
|
+
after_action
|
90
|
+
append_after_action
|
91
|
+
append_around_action
|
92
|
+
append_before_action
|
93
|
+
around_action
|
94
|
+
before_action
|
95
|
+
prepend_after_action
|
96
|
+
prepend_around_action
|
97
|
+
prepend_before_action
|
98
|
+
skip_after_action
|
99
|
+
skip_around_action
|
100
|
+
skip_before_action
|
101
|
+
skip_action_callback
|
102
102
|
].freeze
|
103
103
|
|
104
|
+
FILTERS = RESTRICT_ON_SEND.map { |method_name| ":#{method_name}" }
|
105
|
+
|
104
106
|
def_node_matcher :only_or_except_filter_methods, <<~PATTERN
|
105
107
|
(send
|
106
108
|
nil?
|
@@ -20,8 +20,11 @@ module RuboCop
|
|
20
20
|
#
|
21
21
|
# # good
|
22
22
|
# link_to 'Click here', url, target: '_blank', rel: 'noreferrer'
|
23
|
-
class LinkToBlank <
|
23
|
+
class LinkToBlank < Base
|
24
|
+
extend AutoCorrector
|
25
|
+
|
24
26
|
MSG = 'Specify a `:rel` option containing noopener.'
|
27
|
+
RESTRICT_ON_SEND = %i[link_to].freeze
|
25
28
|
|
26
29
|
def_node_matcher :blank_target?, <<~PATTERN
|
27
30
|
(pair {(sym :target) (str "target")} {(str "_blank") (sym :_blank)})
|
@@ -36,36 +39,33 @@ module RuboCop
|
|
36
39
|
PATTERN
|
37
40
|
|
38
41
|
def on_send(node)
|
39
|
-
return unless node.method?(:link_to)
|
40
|
-
|
41
42
|
option_nodes = node.each_child_node(:hash)
|
42
43
|
|
43
44
|
option_nodes.map(&:children).each do |options|
|
44
45
|
blank = options.find { |o| blank_target?(o) }
|
45
|
-
|
46
|
+
next unless blank && options.none? { |o| includes_noopener?(o) }
|
47
|
+
|
48
|
+
add_offense(blank) do |corrector|
|
49
|
+
autocorrect(corrector, node, blank, option_nodes)
|
50
|
+
end
|
46
51
|
end
|
47
52
|
end
|
48
53
|
|
49
|
-
|
50
|
-
lambda do |corrector|
|
51
|
-
send_node = node.parent.parent
|
54
|
+
private
|
52
55
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
56
|
+
def autocorrect(corrector, send_node, node, option_nodes)
|
57
|
+
rel_node = nil
|
58
|
+
option_nodes.map(&:children).each do |options|
|
59
|
+
rel_node ||= options.find { |o| rel_node?(o) }
|
60
|
+
end
|
58
61
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
end
|
62
|
+
if rel_node
|
63
|
+
append_to_rel(rel_node, corrector)
|
64
|
+
else
|
65
|
+
add_rel(send_node, node, corrector)
|
64
66
|
end
|
65
67
|
end
|
66
68
|
|
67
|
-
private
|
68
|
-
|
69
69
|
def append_to_rel(rel_node, corrector)
|
70
70
|
existing_rel = rel_node.children.last.value
|
71
71
|
str_range = rel_node.children.last.loc.expression.adjust(
|
@@ -87,7 +87,7 @@ module RuboCop
|
|
87
87
|
def contains_noopener?(value)
|
88
88
|
return false unless value
|
89
89
|
|
90
|
-
rel_array = value.to_s.split
|
90
|
+
rel_array = value.to_s.split
|
91
91
|
rel_array.include?('noopener') || rel_array.include?('noreferrer')
|
92
92
|
end
|
93
93
|
end
|