rubocop 0.70.0 → 0.72.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 +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
|