rubocop 0.70.0 → 0.72.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +5 -10
- data/config/default.yml +50 -491
- data/lib/rubocop.rb +5 -53
- data/lib/rubocop/ast/builder.rb +2 -0
- data/lib/rubocop/ast/node.rb +1 -1
- data/lib/rubocop/ast/node/float_node.rb +12 -0
- data/lib/rubocop/ast/node/int_node.rb +12 -0
- data/lib/rubocop/ast/node/mixin/numeric_node.rb +21 -0
- data/lib/rubocop/ast/node/resbody_node.rb +1 -6
- data/lib/rubocop/cached_data.rb +1 -1
- data/lib/rubocop/config.rb +35 -6
- data/lib/rubocop/config_loader.rb +2 -2
- data/lib/rubocop/config_loader_resolver.rb +0 -6
- data/lib/rubocop/cop/cop.rb +0 -4
- data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +55 -0
- data/lib/rubocop/cop/layout/class_structure.rb +1 -1
- data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +3 -1
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +4 -0
- data/lib/rubocop/cop/layout/indent_first_argument.rb +6 -2
- data/lib/rubocop/cop/layout/indent_first_parameter.rb +7 -3
- data/lib/rubocop/cop/layout/indent_heredoc.rb +0 -1
- data/lib/rubocop/cop/layout/indentation_consistency.rb +13 -12
- data/lib/rubocop/cop/layout/indentation_width.rb +8 -4
- data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +2 -0
- data/lib/rubocop/cop/lint/number_conversion.rb +1 -1
- data/lib/rubocop/cop/mixin/hash_alignment.rb +4 -0
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +20 -22
- data/lib/rubocop/cop/style/commented_keyword.rb +1 -1
- data/lib/rubocop/cop/style/conditional_assignment.rb +2 -1
- data/lib/rubocop/cop/style/float_division.rb +94 -0
- data/lib/rubocop/cop/style/format_string.rb +7 -3
- data/lib/rubocop/cop/style/if_inside_else.rb +42 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +7 -1
- data/lib/rubocop/cop/style/safe_navigation.rb +1 -1
- data/lib/rubocop/cop/style/ternary_parentheses.rb +12 -2
- data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +4 -0
- data/lib/rubocop/cop/style/word_array.rb +2 -2
- data/lib/rubocop/cop/style/zero_length_predicate.rb +1 -1
- data/lib/rubocop/node_pattern.rb +84 -5
- data/lib/rubocop/options.rb +0 -2
- data/lib/rubocop/processed_source.rb +5 -1
- data/lib/rubocop/rspec/cop_helper.rb +0 -1
- data/lib/rubocop/rspec/shared_contexts.rb +0 -17
- data/lib/rubocop/rspec/support.rb +0 -1
- data/lib/rubocop/runner.rb +6 -7
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop/yaml_duplication_checker.rb +8 -2
- metadata +7 -69
- data/lib/rubocop/cop/mixin/target_rails_version.rb +0 -16
- data/lib/rubocop/cop/rails/action_filter.rb +0 -117
- data/lib/rubocop/cop/rails/active_record_aliases.rb +0 -48
- data/lib/rubocop/cop/rails/active_record_override.rb +0 -82
- data/lib/rubocop/cop/rails/active_support_aliases.rb +0 -69
- data/lib/rubocop/cop/rails/application_job.rb +0 -40
- data/lib/rubocop/cop/rails/application_record.rb +0 -40
- data/lib/rubocop/cop/rails/assert_not.rb +0 -44
- data/lib/rubocop/cop/rails/belongs_to.rb +0 -102
- data/lib/rubocop/cop/rails/blank.rb +0 -164
- data/lib/rubocop/cop/rails/bulk_change_table.rb +0 -289
- data/lib/rubocop/cop/rails/create_table_with_timestamps.rb +0 -91
- data/lib/rubocop/cop/rails/date.rb +0 -161
- data/lib/rubocop/cop/rails/delegate.rb +0 -132
- data/lib/rubocop/cop/rails/delegate_allow_blank.rb +0 -37
- data/lib/rubocop/cop/rails/dynamic_find_by.rb +0 -91
- data/lib/rubocop/cop/rails/enum_uniqueness.rb +0 -45
- data/lib/rubocop/cop/rails/environment_comparison.rb +0 -68
- data/lib/rubocop/cop/rails/exit.rb +0 -67
- data/lib/rubocop/cop/rails/file_path.rb +0 -108
- data/lib/rubocop/cop/rails/find_by.rb +0 -55
- data/lib/rubocop/cop/rails/find_each.rb +0 -51
- data/lib/rubocop/cop/rails/has_and_belongs_to_many.rb +0 -25
- data/lib/rubocop/cop/rails/has_many_or_has_one_dependent.rb +0 -106
- data/lib/rubocop/cop/rails/http_positional_arguments.rb +0 -117
- data/lib/rubocop/cop/rails/http_status.rb +0 -179
- data/lib/rubocop/cop/rails/ignored_skip_action_filter_option.rb +0 -94
- data/lib/rubocop/cop/rails/inverse_of.rb +0 -246
- data/lib/rubocop/cop/rails/lexically_scoped_action_filter.rb +0 -175
- data/lib/rubocop/cop/rails/link_to_blank.rb +0 -98
- data/lib/rubocop/cop/rails/not_null_column.rb +0 -67
- data/lib/rubocop/cop/rails/output.rb +0 -49
- data/lib/rubocop/cop/rails/output_safety.rb +0 -99
- data/lib/rubocop/cop/rails/pluralization_grammar.rb +0 -107
- data/lib/rubocop/cop/rails/presence.rb +0 -124
- data/lib/rubocop/cop/rails/present.rb +0 -153
- data/lib/rubocop/cop/rails/read_write_attribute.rb +0 -74
- data/lib/rubocop/cop/rails/redundant_allow_nil.rb +0 -111
- data/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb +0 -136
- data/lib/rubocop/cop/rails/reflection_class_name.rb +0 -37
- data/lib/rubocop/cop/rails/refute_methods.rb +0 -76
- data/lib/rubocop/cop/rails/relative_date_constant.rb +0 -93
- data/lib/rubocop/cop/rails/request_referer.rb +0 -56
- data/lib/rubocop/cop/rails/reversible_migration.rb +0 -286
- data/lib/rubocop/cop/rails/safe_navigation.rb +0 -87
- data/lib/rubocop/cop/rails/save_bang.rb +0 -316
- data/lib/rubocop/cop/rails/scope_args.rb +0 -29
- data/lib/rubocop/cop/rails/skips_model_validations.rb +0 -87
- data/lib/rubocop/cop/rails/time_zone.rb +0 -238
- data/lib/rubocop/cop/rails/uniq_before_pluck.rb +0 -105
- data/lib/rubocop/cop/rails/unknown_env.rb +0 -63
- data/lib/rubocop/cop/rails/validation.rb +0 -109
- data/lib/rubocop/rspec/shared_examples.rb +0 -59
@@ -1,55 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RuboCop
|
4
|
-
module Cop
|
5
|
-
module Rails
|
6
|
-
# This cop is used to identify usages of `where.first` and
|
7
|
-
# change them to use `find_by` instead.
|
8
|
-
#
|
9
|
-
# @example
|
10
|
-
# # bad
|
11
|
-
# User.where(name: 'Bruce').first
|
12
|
-
# User.where(name: 'Bruce').take
|
13
|
-
#
|
14
|
-
# # good
|
15
|
-
# User.find_by(name: 'Bruce')
|
16
|
-
class FindBy < Cop
|
17
|
-
include RangeHelp
|
18
|
-
|
19
|
-
MSG = 'Use `find_by` instead of `where.%<method>s`.'
|
20
|
-
TARGET_SELECTORS = %i[first take].freeze
|
21
|
-
|
22
|
-
def_node_matcher :where_first?, <<-PATTERN
|
23
|
-
(send ({send csend} _ :where ...) {:first :take})
|
24
|
-
PATTERN
|
25
|
-
|
26
|
-
def on_send(node)
|
27
|
-
return unless where_first?(node)
|
28
|
-
|
29
|
-
range = range_between(node.receiver.loc.selector.begin_pos,
|
30
|
-
node.loc.selector.end_pos)
|
31
|
-
|
32
|
-
add_offense(node, location: range,
|
33
|
-
message: format(MSG, method: node.method_name))
|
34
|
-
end
|
35
|
-
alias on_csend on_send
|
36
|
-
|
37
|
-
def autocorrect(node)
|
38
|
-
# Don't autocorrect where(...).first, because it can return different
|
39
|
-
# results from find_by. (They order records differently, so the
|
40
|
-
# 'first' record can be different.)
|
41
|
-
return if node.method?(:first)
|
42
|
-
|
43
|
-
where_loc = node.receiver.loc.selector
|
44
|
-
first_loc = range_between(node.loc.dot.begin_pos,
|
45
|
-
node.loc.selector.end_pos)
|
46
|
-
|
47
|
-
lambda do |corrector|
|
48
|
-
corrector.replace(where_loc, 'find_by')
|
49
|
-
corrector.replace(first_loc, '')
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
@@ -1,51 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RuboCop
|
4
|
-
module Cop
|
5
|
-
module Rails
|
6
|
-
# This cop is used to identify usages of `all.each` and
|
7
|
-
# change them to use `all.find_each` instead.
|
8
|
-
#
|
9
|
-
# @example
|
10
|
-
# # bad
|
11
|
-
# User.all.each
|
12
|
-
#
|
13
|
-
# # good
|
14
|
-
# User.all.find_each
|
15
|
-
class FindEach < Cop
|
16
|
-
MSG = 'Use `find_each` instead of `each`.'
|
17
|
-
|
18
|
-
SCOPE_METHODS = %i[
|
19
|
-
all eager_load includes joins left_joins left_outer_joins not preload
|
20
|
-
references unscoped where
|
21
|
-
].freeze
|
22
|
-
IGNORED_METHODS = %i[order limit select].freeze
|
23
|
-
|
24
|
-
def on_send(node)
|
25
|
-
return unless node.receiver&.send_type? &&
|
26
|
-
node.method?(:each)
|
27
|
-
|
28
|
-
return unless SCOPE_METHODS.include?(node.receiver.method_name)
|
29
|
-
return if method_chain(node).any? { |m| ignored_by_find_each?(m) }
|
30
|
-
|
31
|
-
add_offense(node, location: :selector)
|
32
|
-
end
|
33
|
-
|
34
|
-
def autocorrect(node)
|
35
|
-
->(corrector) { corrector.replace(node.loc.selector, 'find_each') }
|
36
|
-
end
|
37
|
-
|
38
|
-
private
|
39
|
-
|
40
|
-
def method_chain(node)
|
41
|
-
node.each_node(:send).map(&:method_name)
|
42
|
-
end
|
43
|
-
|
44
|
-
def ignored_by_find_each?(relation_method)
|
45
|
-
# Active Record's #find_each ignores various extra parameters
|
46
|
-
IGNORED_METHODS.include?(relation_method)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RuboCop
|
4
|
-
module Cop
|
5
|
-
module Rails
|
6
|
-
# This cop checks for the use of the has_and_belongs_to_many macro.
|
7
|
-
#
|
8
|
-
# @example
|
9
|
-
# # bad
|
10
|
-
# # has_and_belongs_to_many :ingredients
|
11
|
-
#
|
12
|
-
# # good
|
13
|
-
# # has_many :ingredients, through: :recipe_ingredients
|
14
|
-
class HasAndBelongsToMany < Cop
|
15
|
-
MSG = 'Prefer `has_many :through` to `has_and_belongs_to_many`.'
|
16
|
-
|
17
|
-
def on_send(node)
|
18
|
-
return unless node.command?(:has_and_belongs_to_many)
|
19
|
-
|
20
|
-
add_offense(node, location: :selector)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,106 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RuboCop
|
4
|
-
module Cop
|
5
|
-
module Rails
|
6
|
-
# This cop looks for `has_many` or `has_one` associations that don't
|
7
|
-
# specify a `:dependent` option.
|
8
|
-
# It doesn't register an offense if `:through` option was specified.
|
9
|
-
#
|
10
|
-
# @example
|
11
|
-
# # bad
|
12
|
-
# class User < ActiveRecord::Base
|
13
|
-
# has_many :comments
|
14
|
-
# has_one :avatar
|
15
|
-
# end
|
16
|
-
#
|
17
|
-
# # good
|
18
|
-
# class User < ActiveRecord::Base
|
19
|
-
# has_many :comments, dependent: :restrict_with_exception
|
20
|
-
# has_one :avatar, dependent: :destroy
|
21
|
-
# has_many :patients, through: :appointments
|
22
|
-
# end
|
23
|
-
class HasManyOrHasOneDependent < Cop
|
24
|
-
MSG = 'Specify a `:dependent` option.'
|
25
|
-
|
26
|
-
def_node_search :active_resource_class?, <<-PATTERN
|
27
|
-
(const (const nil? :ActiveResource) :Base)
|
28
|
-
PATTERN
|
29
|
-
|
30
|
-
def_node_matcher :association_without_options?, <<-PATTERN
|
31
|
-
(send nil? {:has_many :has_one} _)
|
32
|
-
PATTERN
|
33
|
-
|
34
|
-
def_node_matcher :association_with_options?, <<-PATTERN
|
35
|
-
(send nil? {:has_many :has_one} _ (hash $...))
|
36
|
-
PATTERN
|
37
|
-
|
38
|
-
def_node_matcher :dependent_option?, <<-PATTERN
|
39
|
-
(pair (sym :dependent) !nil)
|
40
|
-
PATTERN
|
41
|
-
|
42
|
-
def_node_matcher :present_option?, <<-PATTERN
|
43
|
-
(pair (sym :through) !nil)
|
44
|
-
PATTERN
|
45
|
-
|
46
|
-
def_node_matcher :with_options_block, <<-PATTERN
|
47
|
-
(block
|
48
|
-
(send nil? :with_options
|
49
|
-
(hash $...))
|
50
|
-
(args) ...)
|
51
|
-
PATTERN
|
52
|
-
|
53
|
-
def on_send(node)
|
54
|
-
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
|
-
|
60
|
-
return if valid_options_in_with_options_block?(node)
|
61
|
-
|
62
|
-
add_offense(node, location: :selector)
|
63
|
-
end
|
64
|
-
|
65
|
-
private
|
66
|
-
|
67
|
-
def valid_options_in_with_options_block?(node)
|
68
|
-
return true unless node.parent
|
69
|
-
|
70
|
-
n = node.parent.begin_type? ? node.parent.parent : node.parent
|
71
|
-
|
72
|
-
contain_valid_options_in_with_options_block?(n)
|
73
|
-
end
|
74
|
-
|
75
|
-
def contain_valid_options_in_with_options_block?(node)
|
76
|
-
if with_options_block(node)
|
77
|
-
return true if valid_options?(with_options_block(node))
|
78
|
-
|
79
|
-
return false unless node.parent
|
80
|
-
|
81
|
-
return true if contain_valid_options_in_with_options_block?(
|
82
|
-
node.parent.parent
|
83
|
-
)
|
84
|
-
end
|
85
|
-
|
86
|
-
false
|
87
|
-
end
|
88
|
-
|
89
|
-
def valid_options?(options)
|
90
|
-
return true unless options
|
91
|
-
return true if options.any? do |o|
|
92
|
-
dependent_option?(o) || present_option?(o)
|
93
|
-
end
|
94
|
-
|
95
|
-
false
|
96
|
-
end
|
97
|
-
|
98
|
-
def active_resource?(node)
|
99
|
-
return false if node.nil?
|
100
|
-
|
101
|
-
active_resource_class?(node)
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
@@ -1,117 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RuboCop
|
4
|
-
module Cop
|
5
|
-
module Rails
|
6
|
-
# This cop is used to identify usages of http methods like `get`, `post`,
|
7
|
-
# `put`, `patch` without the usage of keyword arguments in your tests and
|
8
|
-
# change them to use keyword args. This cop only applies to Rails >= 5.
|
9
|
-
# If you are running Rails < 5 you should disable the
|
10
|
-
# Rails/HttpPositionalArguments cop or set your TargetRailsVersion in your
|
11
|
-
# .rubocop.yml file to 4.0, etc.
|
12
|
-
#
|
13
|
-
# @example
|
14
|
-
# # bad
|
15
|
-
# get :new, { user_id: 1}
|
16
|
-
#
|
17
|
-
# # good
|
18
|
-
# get :new, params: { user_id: 1 }
|
19
|
-
class HttpPositionalArguments < Cop
|
20
|
-
extend TargetRailsVersion
|
21
|
-
|
22
|
-
MSG = 'Use keyword arguments instead of ' \
|
23
|
-
'positional arguments for http call: `%<verb>s`.'
|
24
|
-
KEYWORD_ARGS = %i[
|
25
|
-
method params session body flash xhr as headers env
|
26
|
-
].freeze
|
27
|
-
HTTP_METHODS = %i[get post put patch delete head].freeze
|
28
|
-
|
29
|
-
minimum_target_rails_version 5.0
|
30
|
-
|
31
|
-
def_node_matcher :http_request?, <<-PATTERN
|
32
|
-
(send nil? {#{HTTP_METHODS.map(&:inspect).join(' ')}} !nil? $_ ...)
|
33
|
-
PATTERN
|
34
|
-
|
35
|
-
def on_send(node)
|
36
|
-
http_request?(node) do |data|
|
37
|
-
return unless needs_conversion?(data)
|
38
|
-
|
39
|
-
add_offense(node, location: :selector,
|
40
|
-
message: format(MSG, verb: node.method_name))
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
# given a pre Rails 5 method: get :new, {user_id: @user.id}, {}
|
45
|
-
#
|
46
|
-
# @return lambda of auto correct procedure
|
47
|
-
# the result should look like:
|
48
|
-
# get :new, params: { user_id: @user.id }, session: {}
|
49
|
-
# the http_method is the method used to call the controller
|
50
|
-
# the controller node can be a symbol, method, object or string
|
51
|
-
# that represents the path/action on the Rails controller
|
52
|
-
# the data is the http parameters and environment sent in
|
53
|
-
# the Rails 5 http call
|
54
|
-
def autocorrect(node)
|
55
|
-
lambda do |corrector|
|
56
|
-
corrector.replace(node.loc.expression, correction(node))
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
private
|
61
|
-
|
62
|
-
def needs_conversion?(data)
|
63
|
-
return true unless data.hash_type?
|
64
|
-
|
65
|
-
data.each_pair.none? do |pair|
|
66
|
-
special_keyword_arg?(pair.key) ||
|
67
|
-
format_arg?(pair.key) && data.pairs.one?
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def special_keyword_arg?(node)
|
72
|
-
node.sym_type? && KEYWORD_ARGS.include?(node.value)
|
73
|
-
end
|
74
|
-
|
75
|
-
def format_arg?(node)
|
76
|
-
node.sym_type? && node.value == :format
|
77
|
-
end
|
78
|
-
|
79
|
-
def convert_hash_data(data, type)
|
80
|
-
return '' if data.hash_type? && data.empty?
|
81
|
-
|
82
|
-
hash_data = if data.hash_type?
|
83
|
-
format('{ %<data>s }',
|
84
|
-
data: data.pairs.map(&:source).join(', '))
|
85
|
-
else
|
86
|
-
# user supplies an object,
|
87
|
-
# no need to surround with braces
|
88
|
-
data.source
|
89
|
-
end
|
90
|
-
|
91
|
-
format(', %<type>s: %<hash_data>s', type: type, hash_data: hash_data)
|
92
|
-
end
|
93
|
-
|
94
|
-
def correction(node)
|
95
|
-
http_path, *data = *node.arguments
|
96
|
-
|
97
|
-
controller_action = http_path.source
|
98
|
-
params = convert_hash_data(data.first, 'params')
|
99
|
-
session = convert_hash_data(data.last, 'session') if data.size > 1
|
100
|
-
|
101
|
-
format(correction_template(node), name: node.method_name,
|
102
|
-
action: controller_action,
|
103
|
-
params: params,
|
104
|
-
session: session)
|
105
|
-
end
|
106
|
-
|
107
|
-
def correction_template(node)
|
108
|
-
if parentheses?(node)
|
109
|
-
'%<name>s(%<action>s%<params>s%<session>s)'
|
110
|
-
else
|
111
|
-
'%<name>s %<action>s%<params>s%<session>s'
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|
117
|
-
end
|
@@ -1,179 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RuboCop
|
4
|
-
module Cop
|
5
|
-
module Rails
|
6
|
-
# Enforces use of symbolic or numeric value to define HTTP status.
|
7
|
-
#
|
8
|
-
# @example EnforcedStyle: symbolic (default)
|
9
|
-
# # bad
|
10
|
-
# render :foo, status: 200
|
11
|
-
# render json: { foo: 'bar' }, status: 200
|
12
|
-
# render plain: 'foo/bar', status: 304
|
13
|
-
# redirect_to root_url, status: 301
|
14
|
-
#
|
15
|
-
# # good
|
16
|
-
# render :foo, status: :ok
|
17
|
-
# render json: { foo: 'bar' }, status: :ok
|
18
|
-
# render plain: 'foo/bar', status: :not_modified
|
19
|
-
# redirect_to root_url, status: :moved_permanently
|
20
|
-
#
|
21
|
-
# @example EnforcedStyle: numeric
|
22
|
-
# # bad
|
23
|
-
# render :foo, status: :ok
|
24
|
-
# render json: { foo: 'bar' }, status: :not_found
|
25
|
-
# render plain: 'foo/bar', status: :not_modified
|
26
|
-
# redirect_to root_url, status: :moved_permanently
|
27
|
-
#
|
28
|
-
# # good
|
29
|
-
# render :foo, status: 200
|
30
|
-
# render json: { foo: 'bar' }, status: 404
|
31
|
-
# render plain: 'foo/bar', status: 304
|
32
|
-
# redirect_to root_url, status: 301
|
33
|
-
#
|
34
|
-
class HttpStatus < Cop
|
35
|
-
begin
|
36
|
-
require 'rack/utils'
|
37
|
-
RACK_LOADED = true
|
38
|
-
rescue LoadError
|
39
|
-
RACK_LOADED = false
|
40
|
-
end
|
41
|
-
|
42
|
-
include ConfigurableEnforcedStyle
|
43
|
-
|
44
|
-
def_node_matcher :http_status, <<-PATTERN
|
45
|
-
{
|
46
|
-
(send nil? {:render :redirect_to} _ $hash)
|
47
|
-
(send nil? {:render :redirect_to} $hash)
|
48
|
-
}
|
49
|
-
PATTERN
|
50
|
-
|
51
|
-
def_node_matcher :status_code, <<-PATTERN
|
52
|
-
(hash <(pair (sym :status) ${int sym}) ...>)
|
53
|
-
PATTERN
|
54
|
-
|
55
|
-
def on_send(node)
|
56
|
-
http_status(node) do |hash_node|
|
57
|
-
status = status_code(hash_node)
|
58
|
-
return unless status
|
59
|
-
|
60
|
-
checker = checker_class.new(status)
|
61
|
-
return unless checker.offensive?
|
62
|
-
|
63
|
-
add_offense(checker.node, message: checker.message)
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
def support_autocorrect?
|
68
|
-
RACK_LOADED
|
69
|
-
end
|
70
|
-
|
71
|
-
def autocorrect(node)
|
72
|
-
lambda do |corrector|
|
73
|
-
checker = checker_class.new(node)
|
74
|
-
corrector.replace(node.loc.expression, checker.preferred_style)
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
private
|
79
|
-
|
80
|
-
def checker_class
|
81
|
-
case style
|
82
|
-
when :symbolic
|
83
|
-
SymbolicStyleChecker
|
84
|
-
when :numeric
|
85
|
-
NumericStyleChecker
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
# :nodoc:
|
90
|
-
class SymbolicStyleChecker
|
91
|
-
MSG = 'Prefer `%<prefer>s` over `%<current>s` ' \
|
92
|
-
'to define HTTP status code.'
|
93
|
-
DEFAULT_MSG = 'Prefer `symbolic` over `numeric` ' \
|
94
|
-
'to define HTTP status code.'
|
95
|
-
|
96
|
-
attr_reader :node
|
97
|
-
def initialize(node)
|
98
|
-
@node = node
|
99
|
-
end
|
100
|
-
|
101
|
-
def offensive?
|
102
|
-
!node.sym_type? && !custom_http_status_code?
|
103
|
-
end
|
104
|
-
|
105
|
-
def message
|
106
|
-
if RACK_LOADED
|
107
|
-
format(MSG, prefer: preferred_style, current: number.to_s)
|
108
|
-
else
|
109
|
-
DEFAULT_MSG
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
def preferred_style
|
114
|
-
symbol.inspect
|
115
|
-
end
|
116
|
-
|
117
|
-
private
|
118
|
-
|
119
|
-
def symbol
|
120
|
-
::Rack::Utils::SYMBOL_TO_STATUS_CODE.key(number)
|
121
|
-
end
|
122
|
-
|
123
|
-
def number
|
124
|
-
node.children.first
|
125
|
-
end
|
126
|
-
|
127
|
-
def custom_http_status_code?
|
128
|
-
node.int_type? &&
|
129
|
-
!::Rack::Utils::SYMBOL_TO_STATUS_CODE.value?(number)
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
# :nodoc:
|
134
|
-
class NumericStyleChecker
|
135
|
-
MSG = 'Prefer `%<prefer>s` over `%<current>s` ' \
|
136
|
-
'to define HTTP status code.'
|
137
|
-
DEFAULT_MSG = 'Prefer `numeric` over `symbolic` ' \
|
138
|
-
'to define HTTP status code.'
|
139
|
-
PERMITTED_STATUS = %i[error success missing redirect].freeze
|
140
|
-
|
141
|
-
attr_reader :node
|
142
|
-
def initialize(node)
|
143
|
-
@node = node
|
144
|
-
end
|
145
|
-
|
146
|
-
def offensive?
|
147
|
-
!node.int_type? && !permitted_symbol?
|
148
|
-
end
|
149
|
-
|
150
|
-
def message
|
151
|
-
if RACK_LOADED
|
152
|
-
format(MSG, prefer: preferred_style, current: symbol.inspect)
|
153
|
-
else
|
154
|
-
DEFAULT_MSG
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
def preferred_style
|
159
|
-
number.to_s
|
160
|
-
end
|
161
|
-
|
162
|
-
private
|
163
|
-
|
164
|
-
def number
|
165
|
-
::Rack::Utils::SYMBOL_TO_STATUS_CODE[symbol]
|
166
|
-
end
|
167
|
-
|
168
|
-
def symbol
|
169
|
-
node.value
|
170
|
-
end
|
171
|
-
|
172
|
-
def permitted_symbol?
|
173
|
-
node.sym_type? && PERMITTED_STATUS.include?(node.value)
|
174
|
-
end
|
175
|
-
end
|
176
|
-
end
|
177
|
-
end
|
178
|
-
end
|
179
|
-
end
|