rubocop 0.48.1 → 0.49.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 +4 -3
- data/config/default.yml +397 -357
- data/config/disabled.yml +29 -29
- data/config/enabled.yml +366 -326
- data/lib/rubocop.rb +85 -70
- data/lib/rubocop/ast/builder.rb +4 -1
- data/lib/rubocop/ast/node.rb +2 -2
- data/lib/rubocop/ast/node/and_node.rb +1 -1
- data/lib/rubocop/ast/node/args_node.rb +24 -0
- data/lib/rubocop/ast/node/block_node.rb +107 -0
- data/lib/rubocop/ast/node/case_node.rb +1 -1
- data/lib/rubocop/ast/node/ensure_node.rb +1 -1
- data/lib/rubocop/ast/node/for_node.rb +1 -1
- data/lib/rubocop/ast/node/if_node.rb +1 -1
- data/lib/rubocop/ast/node/mixin/parameterized_node.rb +74 -0
- data/lib/rubocop/ast/node/or_node.rb +1 -1
- data/lib/rubocop/ast/node/pair_node.rb +1 -1
- data/lib/rubocop/ast/node/resbody_node.rb +1 -1
- data/lib/rubocop/ast/node/send_node.rb +36 -57
- data/lib/rubocop/ast/node/super_node.rb +42 -0
- data/lib/rubocop/ast/node/until_node.rb +1 -1
- data/lib/rubocop/ast/node/when_node.rb +1 -1
- data/lib/rubocop/ast/node/while_node.rb +1 -1
- data/lib/rubocop/cli.rb +10 -0
- data/lib/rubocop/config.rb +23 -7
- data/lib/rubocop/config_loader.rb +19 -3
- data/lib/rubocop/cop/badge.rb +1 -1
- data/lib/rubocop/cop/bundler/duplicated_gem.rb +2 -2
- data/lib/rubocop/cop/commissioner.rb +1 -1
- data/lib/rubocop/cop/cop.rb +10 -0
- data/lib/rubocop/cop/{style → layout}/access_modifier_indentation.rb +33 -3
- data/lib/rubocop/cop/{style → layout}/align_array.rb +16 -1
- data/lib/rubocop/cop/{style → layout}/align_hash.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/align_parameters.rb +29 -1
- data/lib/rubocop/cop/{style → layout}/block_end_newline.rb +10 -5
- data/lib/rubocop/cop/{style → layout}/case_indentation.rb +64 -1
- data/lib/rubocop/cop/{style → layout}/closing_parenthesis_indentation.rb +2 -2
- data/lib/rubocop/cop/{style → layout}/comment_indentation.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/dot_position.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/else_alignment.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/empty_line_after_magic_comment.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/empty_line_between_defs.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/empty_lines.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/empty_lines_around_access_modifier.rb +2 -7
- data/lib/rubocop/cop/{style → layout}/empty_lines_around_begin_body.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/empty_lines_around_block_body.rb +2 -4
- data/lib/rubocop/cop/{style → layout}/empty_lines_around_class_body.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/empty_lines_around_exception_handling_keywords.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/empty_lines_around_method_body.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/empty_lines_around_module_body.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/end_of_line.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/extra_spacing.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/first_array_element_line_break.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/first_hash_element_line_break.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/first_method_argument_line_break.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/first_method_parameter_line_break.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/first_parameter_indentation.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/indent_array.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/indent_assignment.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/indent_hash.rb +2 -2
- data/lib/rubocop/cop/{style → layout}/indent_heredoc.rb +3 -3
- data/lib/rubocop/cop/{style → layout}/indentation_consistency.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/indentation_width.rb +10 -12
- data/lib/rubocop/cop/{style → layout}/initial_indentation.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/leading_comment_space.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/multiline_array_brace_layout.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/multiline_assignment_layout.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/multiline_block_layout.rb +21 -36
- data/lib/rubocop/cop/{style → layout}/multiline_hash_brace_layout.rb +5 -1
- data/lib/rubocop/cop/{style → layout}/multiline_method_call_brace_layout.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/multiline_method_call_indentation.rb +3 -3
- data/lib/rubocop/cop/{style → layout}/multiline_method_definition_brace_layout.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/multiline_operation_indentation.rb +6 -5
- data/lib/rubocop/cop/{style → layout}/rescue_ensure_alignment.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/space_after_colon.rb +2 -2
- data/lib/rubocop/cop/{style → layout}/space_after_comma.rb +2 -2
- data/lib/rubocop/cop/{style → layout}/space_after_method_name.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/space_after_not.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/space_after_semicolon.rb +2 -2
- data/lib/rubocop/cop/{style → layout}/space_around_block_parameters.rb +7 -5
- data/lib/rubocop/cop/{style → layout}/space_around_equals_in_parameter_default.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/space_around_keyword.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/space_around_operators.rb +6 -2
- data/lib/rubocop/cop/{style → layout}/space_before_block_braces.rb +6 -2
- data/lib/rubocop/cop/{style → layout}/space_before_comma.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/space_before_comment.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/space_before_first_arg.rb +4 -2
- data/lib/rubocop/cop/{style → layout}/space_before_semicolon.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/space_in_lambda_literal.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/space_inside_array_percent_literal.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/space_inside_block_braces.rb +3 -4
- data/lib/rubocop/cop/{style → layout}/space_inside_brackets.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/space_inside_hash_literal_braces.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/space_inside_parens.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/space_inside_percent_literal_delimiters.rb +8 -7
- data/lib/rubocop/cop/{style → layout}/space_inside_range_literal.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/space_inside_string_interpolation.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/tab.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/trailing_blank_lines.rb +1 -1
- data/lib/rubocop/cop/{style → layout}/trailing_whitespace.rb +2 -2
- data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
- data/lib/rubocop/cop/lint/ambiguous_operator.rb +4 -4
- data/lib/rubocop/cop/lint/debugger.rb +0 -15
- data/lib/rubocop/cop/lint/duplicate_methods.rb +2 -1
- data/lib/rubocop/cop/lint/rescue_type.rb +81 -0
- data/lib/rubocop/cop/lint/script_permission.rb +42 -0
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +1 -1
- data/lib/rubocop/cop/message_annotator.rb +23 -13
- data/lib/rubocop/cop/metrics/block_length.rb +1 -1
- data/lib/rubocop/cop/mixin/array_min_size.rb +59 -0
- data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +10 -11
- data/lib/rubocop/cop/mixin/def_node.rb +1 -1
- data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +1 -1
- data/lib/rubocop/cop/mixin/enforce_superclass.rb +36 -0
- data/lib/rubocop/cop/mixin/hash_alignment.rb +1 -1
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +7 -3
- data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
- data/lib/rubocop/cop/performance/caller.rb +41 -0
- data/lib/rubocop/cop/performance/compare_with_block.rb +60 -14
- data/lib/rubocop/cop/performance/double_start_end_with.rb +2 -2
- data/lib/rubocop/cop/performance/redundant_merge.rb +2 -0
- data/lib/rubocop/cop/rails/action_filter.rb +1 -3
- data/lib/rubocop/cop/rails/application_job.rb +32 -0
- data/lib/rubocop/cop/rails/application_record.rb +32 -0
- data/lib/rubocop/cop/rails/blank.rb +9 -3
- data/lib/rubocop/cop/rails/output_safety.rb +59 -15
- data/lib/rubocop/cop/rails/present.rb +9 -3
- data/lib/rubocop/cop/rails/relative_date_constant.rb +35 -4
- data/lib/rubocop/cop/rails/reversible_migration.rb +82 -18
- data/lib/rubocop/cop/rails/save_bang.rb +7 -2
- data/lib/rubocop/cop/rails/skips_model_validations.rb +7 -0
- data/lib/rubocop/cop/registry.rb +4 -3
- data/lib/rubocop/cop/security/eval.rb +9 -3
- data/lib/rubocop/cop/style/and_or.rb +1 -1
- data/lib/rubocop/cop/style/block_delimiters.rb +11 -17
- data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +1 -1
- data/lib/rubocop/cop/style/collection_methods.rb +1 -3
- data/lib/rubocop/cop/style/conditional_assignment.rb +1 -1
- data/lib/rubocop/cop/style/copyright.rb +2 -2
- data/lib/rubocop/cop/style/documentation_method.rb +1 -1
- data/lib/rubocop/cop/style/each_for_simple_loop.rb +2 -1
- data/lib/rubocop/cop/style/each_with_object.rb +10 -6
- data/lib/rubocop/cop/style/empty_case_condition.rb +2 -2
- data/lib/rubocop/cop/style/for.rb +4 -5
- data/lib/rubocop/cop/style/format_string.rb +49 -0
- data/lib/rubocop/cop/style/format_string_token.rb +141 -0
- data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +2 -2
- data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +1 -1
- data/lib/rubocop/cop/style/inverse_methods.rb +10 -1
- data/lib/rubocop/cop/style/lambda.rb +9 -9
- data/lib/rubocop/cop/style/line_end_concatenation.rb +4 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +3 -3
- data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +1 -2
- data/lib/rubocop/cop/style/method_name.rb +8 -2
- data/lib/rubocop/cop/style/mixin_grouping.rb +41 -3
- data/lib/rubocop/cop/style/multiline_block_chain.rb +7 -11
- data/lib/rubocop/cop/style/multiple_comparison.rb +77 -0
- data/lib/rubocop/cop/style/next.rb +11 -22
- data/lib/rubocop/cop/style/parallel_assignment.rb +10 -19
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +2 -2
- data/lib/rubocop/cop/style/self_assignment.rb +4 -0
- data/lib/rubocop/cop/style/single_line_block_params.rb +23 -17
- data/lib/rubocop/cop/style/symbol_array.rb +24 -13
- data/lib/rubocop/cop/style/symbol_proc.rb +4 -0
- data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/unneeded_interpolation.rb +4 -0
- data/lib/rubocop/cop/style/word_array.rb +33 -53
- data/lib/rubocop/cop/style/yoda_condition.rb +78 -0
- data/lib/rubocop/cop/team.rb +1 -14
- data/lib/rubocop/cop/util.rb +16 -0
- data/lib/rubocop/formatter/simple_text_formatter.rb +0 -11
- data/lib/rubocop/node_pattern.rb +52 -52
- data/lib/rubocop/options.rb +25 -0
- data/lib/rubocop/path_util.rb +17 -1
- data/lib/rubocop/result_cache.rb +8 -7
- data/lib/rubocop/rspec/expect_offense.rb +167 -0
- data/lib/rubocop/rspec/shared_examples.rb +0 -8
- data/lib/rubocop/rspec/support.rb +1 -0
- data/lib/rubocop/runner.rb +12 -2
- data/lib/rubocop/target_finder.rb +5 -0
- data/lib/rubocop/version.rb +1 -1
- metadata +101 -72
@@ -12,6 +12,7 @@ module RuboCop
|
|
12
12
|
# array.sort { |a, b| a.foo <=> b.foo }
|
13
13
|
# array.max { |a, b| a.foo <=> b.foo }
|
14
14
|
# array.min { |a, b| a.foo <=> b.foo }
|
15
|
+
# array.sort { |a, b| a[:foo] <=> b[:foo] }
|
15
16
|
#
|
16
17
|
# @good
|
17
18
|
# array.sort_by(&:foo)
|
@@ -21,37 +22,82 @@ module RuboCop
|
|
21
22
|
# end
|
22
23
|
# array.max_by(&:foo)
|
23
24
|
# array.min_by(&:foo)
|
25
|
+
# array.sort_by { |a| a[:foo] }
|
24
26
|
class CompareWithBlock < Cop
|
25
|
-
MSG = 'Use `%s_by
|
26
|
-
'`%s { |%s, %s| %s
|
27
|
+
MSG = 'Use `%s_by%s` instead of ' \
|
28
|
+
'`%s { |%s, %s| %s <=> %s }`.'.freeze
|
27
29
|
|
28
30
|
def_node_matcher :compare?, <<-END
|
29
|
-
(block
|
31
|
+
(block
|
32
|
+
$(send _ {:sort :min :max})
|
33
|
+
(args (arg $_a) (arg $_b))
|
34
|
+
$send)
|
35
|
+
END
|
36
|
+
|
37
|
+
def_node_matcher :replaceable_body?, <<-END
|
38
|
+
(send
|
39
|
+
(send (lvar %1) $_method $...)
|
40
|
+
:<=>
|
41
|
+
(send (lvar %2) _method $...))
|
30
42
|
END
|
31
43
|
|
32
44
|
def on_block(node)
|
33
|
-
compare?(node) do |send, var_a, var_b,
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
45
|
+
compare?(node) do |send, var_a, var_b, body|
|
46
|
+
replaceable_body?(body, var_a, var_b) do |method, args_a, args_b|
|
47
|
+
return unless slow_compare?(method, args_a, args_b)
|
48
|
+
range = compare_range(send, node)
|
49
|
+
add_offense(node, range,
|
50
|
+
message(send, method, var_a, var_b, args_a))
|
51
|
+
end
|
40
52
|
end
|
41
53
|
end
|
42
54
|
|
43
55
|
def autocorrect(node)
|
44
|
-
send, = *node
|
45
|
-
|
46
56
|
lambda do |corrector|
|
47
|
-
|
57
|
+
send, var_a, var_b, body = compare?(node)
|
58
|
+
method, arg, = replaceable_body?(body, var_a, var_b)
|
59
|
+
replacement =
|
60
|
+
if method == :[]
|
61
|
+
"#{send.method_name}_by { |a| a[#{arg.first.source}] }"
|
62
|
+
else
|
63
|
+
"#{send.method_name}_by(&:#{method})"
|
64
|
+
end
|
48
65
|
corrector.replace(compare_range(send, node),
|
49
|
-
|
66
|
+
replacement)
|
50
67
|
end
|
51
68
|
end
|
52
69
|
|
53
70
|
private
|
54
71
|
|
72
|
+
def slow_compare?(method, args_a, args_b)
|
73
|
+
return false unless args_a == args_b
|
74
|
+
if method == :[]
|
75
|
+
return false unless args_a.size == 1
|
76
|
+
key = args_a.first
|
77
|
+
return false unless %i[sym str int].include?(key.type)
|
78
|
+
else
|
79
|
+
return false unless args_a.empty?
|
80
|
+
end
|
81
|
+
true
|
82
|
+
end
|
83
|
+
|
84
|
+
def message(send, method, var_a, var_b, args)
|
85
|
+
compare_method = send.method_name
|
86
|
+
if method == :[]
|
87
|
+
key = args.first
|
88
|
+
instead = " { |a| a[#{key.source}] }"
|
89
|
+
str_a = "#{var_a}[#{key.source}]"
|
90
|
+
str_b = "#{var_b}[#{key.source}]"
|
91
|
+
else
|
92
|
+
instead = "(&:#{method})"
|
93
|
+
str_a = "#{var_a}.#{method}"
|
94
|
+
str_b = "#{var_b}.#{method}"
|
95
|
+
end
|
96
|
+
format(MSG, compare_method, instead,
|
97
|
+
compare_method, var_a, var_b,
|
98
|
+
str_a, str_b)
|
99
|
+
end
|
100
|
+
|
55
101
|
def compare_range(send, node)
|
56
102
|
range_between(send.loc.selector.begin_pos, node.loc.end.end_pos)
|
57
103
|
end
|
@@ -23,8 +23,8 @@ module RuboCop
|
|
23
23
|
# var2 = ...
|
24
24
|
# str.end_with?(var1, var2)
|
25
25
|
class DoubleStartEndWith < Cop
|
26
|
-
MSG = 'Use
|
27
|
-
'instead of
|
26
|
+
MSG = 'Use `%<receiver>s.%<method>s(%<combined_args>s)` ' \
|
27
|
+
'instead of `%<original_code>s`.'.freeze
|
28
28
|
|
29
29
|
def on_or(node)
|
30
30
|
receiver,
|
@@ -21,6 +21,8 @@ module RuboCop
|
|
21
21
|
|
22
22
|
def on_send(node)
|
23
23
|
each_redundant_merge(node) do |receiver, pairs|
|
24
|
+
return if pairs.any?(&:kwsplat_type?)
|
25
|
+
|
24
26
|
assignments = to_assignments(receiver, pairs).join('; ')
|
25
27
|
message = format(MSG, assignments, node.source)
|
26
28
|
add_offense(node, :expression, message)
|
@@ -0,0 +1,32 @@
|
|
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`.'.freeze
|
25
|
+
SUPERCLASS = 'ApplicationJob'.freeze
|
26
|
+
BASE_PATTERN = '(const (const nil :ActiveJob) :Base)'.freeze
|
27
|
+
|
28
|
+
include RuboCop::Cop::EnforceSuperclass
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# This cop checks that models subclass ApplicationRecord with Rails 5.0.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
#
|
10
|
+
# # good
|
11
|
+
# class Rails5Model < ApplicationRecord
|
12
|
+
# ...
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# # bad
|
16
|
+
# class Rails4Model < ActiveRecord::Base
|
17
|
+
# ...
|
18
|
+
# end
|
19
|
+
class ApplicationRecord < Cop
|
20
|
+
extend TargetRailsVersion
|
21
|
+
|
22
|
+
minimum_target_rails_version 5.0
|
23
|
+
|
24
|
+
MSG = 'Models should subclass `ApplicationRecord`.'.freeze
|
25
|
+
SUPERCLASS = 'ApplicationRecord'.freeze
|
26
|
+
BASE_PATTERN = '(const (const nil :ActiveRecord) :Base)'.freeze
|
27
|
+
|
28
|
+
include RuboCop::Cop::EnforceSuperclass
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -39,7 +39,7 @@ module RuboCop
|
|
39
39
|
# end
|
40
40
|
class Blank < Cop
|
41
41
|
MSG_NIL_OR_EMPTY = 'Use `%s.blank?` instead of `%s`.'.freeze
|
42
|
-
MSG_NOT_PRESENT = 'Use `%s
|
42
|
+
MSG_NOT_PRESENT = 'Use `%s` instead of `%s`.'.freeze
|
43
43
|
MSG_UNLESS_PRESENT = 'Use `if %s.blank?` instead of `%s`.'.freeze
|
44
44
|
|
45
45
|
def_node_matcher :nil_or_empty?, <<-PATTERN
|
@@ -69,7 +69,9 @@ module RuboCop
|
|
69
69
|
not_present?(node) do |receiver|
|
70
70
|
add_offense(node,
|
71
71
|
:expression,
|
72
|
-
format(MSG_NOT_PRESENT,
|
72
|
+
format(MSG_NOT_PRESENT,
|
73
|
+
replacement(receiver),
|
74
|
+
node.source))
|
73
75
|
end
|
74
76
|
end
|
75
77
|
|
@@ -113,7 +115,7 @@ module RuboCop
|
|
113
115
|
range = node.loc.expression
|
114
116
|
end
|
115
117
|
|
116
|
-
corrector.replace(range,
|
118
|
+
corrector.replace(range, replacement(variable1))
|
117
119
|
end
|
118
120
|
end
|
119
121
|
|
@@ -126,6 +128,10 @@ module RuboCop
|
|
126
128
|
node.loc.expression.begin.join(method_call.loc.expression)
|
127
129
|
end
|
128
130
|
end
|
131
|
+
|
132
|
+
def replacement(node)
|
133
|
+
node.respond_to?(:source) ? "#{node.source}.blank?" : 'blank?'
|
134
|
+
end
|
129
135
|
end
|
130
136
|
end
|
131
137
|
end
|
@@ -3,38 +3,78 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Rails
|
6
|
-
# This cop checks for the use of output safety calls like html_safe
|
7
|
-
# raw.
|
6
|
+
# This cop checks for the use of output safety calls like html_safe,
|
7
|
+
# raw, and safe_concat. These methods do not escape content. They
|
8
|
+
# simply return a SafeBuffer containing the content as is. Instead,
|
9
|
+
# use safe_join to join content and escape it and concat to
|
10
|
+
# concatenate content and escape it, ensuring its safety.
|
8
11
|
#
|
9
12
|
# @example
|
13
|
+
# user_content = "<b>hi</b>"
|
14
|
+
#
|
10
15
|
# # bad
|
11
|
-
# "<p>#{
|
16
|
+
# "<p>#{user_content}</p>".html_safe
|
17
|
+
# => ActiveSupport::SafeBuffer
|
18
|
+
# "<p><b>hi</b></p>"
|
12
19
|
#
|
13
20
|
# # good
|
14
|
-
# content_tag(:p,
|
21
|
+
# content_tag(:p, user_content)
|
22
|
+
# => ActiveSupport::SafeBuffer
|
23
|
+
# "<p><b>hi</b></p>"
|
15
24
|
#
|
16
25
|
# # bad
|
17
26
|
# out = ""
|
18
|
-
# out <<
|
19
|
-
# out <<
|
27
|
+
# out << "<li>#{user_content}</li>"
|
28
|
+
# out << "<li>#{user_content}</li>"
|
20
29
|
# out.html_safe
|
30
|
+
# => ActiveSupport::SafeBuffer
|
31
|
+
# "<li><b>hi</b></li><li><b>hi</b></li>"
|
21
32
|
#
|
22
33
|
# # good
|
23
34
|
# out = []
|
24
|
-
# out << content_tag(:li,
|
25
|
-
# out << content_tag(:li,
|
35
|
+
# out << content_tag(:li, user_content)
|
36
|
+
# out << content_tag(:li, user_content)
|
26
37
|
# safe_join(out)
|
38
|
+
# => ActiveSupport::SafeBuffer
|
39
|
+
# "<li><b>hi</b></li><li><b>hi</b></li>"
|
40
|
+
#
|
41
|
+
# # bad
|
42
|
+
# out = "<h1>trusted content</h1>".html_safe
|
43
|
+
# out.safe_concat(user_content)
|
44
|
+
# => ActiveSupport::SafeBuffer
|
45
|
+
# "<h1>trusted_content</h1><b>hi</b>"
|
46
|
+
#
|
47
|
+
# # good
|
48
|
+
# out = "<h1>trusted content</h1>".html_safe
|
49
|
+
# out.concat(user_content)
|
50
|
+
# => ActiveSupport::SafeBuffer
|
51
|
+
# "<h1>trusted_content</h1><b>hi</b>"
|
52
|
+
#
|
53
|
+
# # safe, though maybe not good style
|
54
|
+
# out = "trusted content"
|
55
|
+
# result = out.concat(user_content)
|
56
|
+
# => String "trusted content<b>hi</b>"
|
57
|
+
# # because when rendered in ERB the String will be escaped:
|
58
|
+
# <%= result %>
|
59
|
+
# => trusted content<b>hi</b>
|
60
|
+
#
|
61
|
+
# # bad
|
62
|
+
# (user_content + " " + content_tag(:span, user_content)).html_safe
|
63
|
+
# => ActiveSupport::SafeBuffer
|
64
|
+
# "<b>hi</b> <span><b>hi</b></span>"
|
65
|
+
#
|
66
|
+
# # good
|
67
|
+
# safe_join([user_content, " ", content_tag(:span, user_content)])
|
68
|
+
# => ActiveSupport::SafeBuffer
|
69
|
+
# "<b>hi</b> <span><b>hi</b></span>"
|
27
70
|
#
|
28
71
|
class OutputSafety < Cop
|
29
|
-
MSG = 'Tagging a string as html safe may be a security risk
|
30
|
-
'prefer `safe_join` or other Rails tag helpers instead.'.freeze
|
72
|
+
MSG = 'Tagging a string as html safe may be a security risk.'.freeze
|
31
73
|
|
32
74
|
def on_send(node)
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
(looks_like_rails_html_safe?(node) ||
|
37
|
-
looks_like_rails_raw?(node))
|
75
|
+
return unless looks_like_rails_html_safe?(node) ||
|
76
|
+
looks_like_rails_raw?(node) ||
|
77
|
+
looks_like_rails_safe_concat?(node)
|
38
78
|
|
39
79
|
add_offense(node, :selector)
|
40
80
|
end
|
@@ -48,6 +88,10 @@ module RuboCop
|
|
48
88
|
def looks_like_rails_raw?(node)
|
49
89
|
node.command?(:raw) && node.arguments.one?
|
50
90
|
end
|
91
|
+
|
92
|
+
def looks_like_rails_safe_concat?(node)
|
93
|
+
node.method?(:safe_concat) && node.arguments.one?
|
94
|
+
end
|
51
95
|
end
|
52
96
|
end
|
53
97
|
end
|
@@ -35,7 +35,7 @@ module RuboCop
|
|
35
35
|
# # good
|
36
36
|
# something if foo.present?
|
37
37
|
class Present < Cop
|
38
|
-
MSG_NOT_BLANK = 'Use `%s
|
38
|
+
MSG_NOT_BLANK = 'Use `%s` instead of `%s`.'.freeze
|
39
39
|
MSG_EXISTS_AND_NOT_EMPTY = 'Use `%s.present?` instead of `%s`.'.freeze
|
40
40
|
MSG_UNLESS_BLANK = 'Use `if %s.present?` instead of `%s`.'.freeze
|
41
41
|
|
@@ -65,7 +65,9 @@ module RuboCop
|
|
65
65
|
not_blank?(node) do |receiver|
|
66
66
|
add_offense(node,
|
67
67
|
:expression,
|
68
|
-
format(MSG_NOT_BLANK,
|
68
|
+
format(MSG_NOT_BLANK,
|
69
|
+
replacement(receiver),
|
70
|
+
node.source))
|
69
71
|
end
|
70
72
|
end
|
71
73
|
|
@@ -118,7 +120,7 @@ module RuboCop
|
|
118
120
|
range = node.loc.expression
|
119
121
|
end
|
120
122
|
|
121
|
-
corrector.replace(range,
|
123
|
+
corrector.replace(range, replacement(variable1))
|
122
124
|
end
|
123
125
|
end
|
124
126
|
|
@@ -131,6 +133,10 @@ module RuboCop
|
|
131
133
|
node.loc.expression.begin.join(method_call.loc.expression)
|
132
134
|
end
|
133
135
|
end
|
136
|
+
|
137
|
+
def replacement(node)
|
138
|
+
node.respond_to?(:source) ? "#{node.source}.present?" : 'present?'
|
139
|
+
end
|
134
140
|
end
|
135
141
|
end
|
136
142
|
end
|
@@ -27,16 +27,47 @@ module RuboCop
|
|
27
27
|
def on_casgn(node)
|
28
28
|
_scope, _constant, rhs = *node
|
29
29
|
|
30
|
-
|
30
|
+
# rhs would be nil in a or_asgn node
|
31
|
+
return unless rhs
|
31
32
|
|
32
|
-
|
33
|
-
|
33
|
+
check_node(rhs)
|
34
|
+
end
|
35
|
+
|
36
|
+
def on_masgn(node)
|
37
|
+
lhs, rhs = *node
|
38
|
+
|
39
|
+
return unless rhs && rhs.array_type?
|
34
40
|
|
35
|
-
|
41
|
+
lhs.children.zip(rhs.children).each do |(name, value)|
|
42
|
+
check_node(value) if name.casgn_type?
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def on_or_asgn(node)
|
47
|
+
lhs, rhs = *node
|
48
|
+
|
49
|
+
return unless lhs.casgn_type?
|
50
|
+
|
51
|
+
check_node(rhs)
|
36
52
|
end
|
37
53
|
|
38
54
|
private
|
39
55
|
|
56
|
+
def check_node(node)
|
57
|
+
return unless node.irange_type? ||
|
58
|
+
node.erange_type? ||
|
59
|
+
node.send_type?
|
60
|
+
|
61
|
+
# for range nodes we need to check both their boundaries
|
62
|
+
nodes = node.send_type? ? [node] : node.children
|
63
|
+
|
64
|
+
nodes.each do |n|
|
65
|
+
if relative_date_method?(n)
|
66
|
+
add_offense(node.parent, :expression, format(MSG, n.method_name))
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
40
71
|
def relative_date_method?(node)
|
41
72
|
node.send_type? &&
|
42
73
|
RELATIVE_DATE_METHODS.include?(node.method_name) &&
|
@@ -10,7 +10,7 @@ module RuboCop
|
|
10
10
|
# # bad
|
11
11
|
# def change
|
12
12
|
# change_table :users do |t|
|
13
|
-
# t.
|
13
|
+
# t.remove :name
|
14
14
|
# end
|
15
15
|
# end
|
16
16
|
#
|
@@ -90,12 +90,49 @@ module RuboCop
|
|
90
90
|
# remove_foreign_key :accounts, :branches
|
91
91
|
# end
|
92
92
|
#
|
93
|
+
# @example
|
94
|
+
# # change_table
|
95
|
+
#
|
96
|
+
# # bad
|
97
|
+
# def change
|
98
|
+
# change_table :users do |t|
|
99
|
+
# t.remove :name
|
100
|
+
# t.change_default :authorized, 1
|
101
|
+
# t.change :price, :string
|
102
|
+
# end
|
103
|
+
# end
|
104
|
+
#
|
105
|
+
# # good
|
106
|
+
# def change
|
107
|
+
# change_table :users do |t|
|
108
|
+
# t.string :name
|
109
|
+
# end
|
110
|
+
# end
|
111
|
+
#
|
112
|
+
# # good
|
113
|
+
# def change
|
114
|
+
# reversible do |dir|
|
115
|
+
# change_table :users do |t|
|
116
|
+
# dir.up do
|
117
|
+
# t.change :price, :string
|
118
|
+
# end
|
119
|
+
#
|
120
|
+
# dir.down do
|
121
|
+
# t.change :price, :integer
|
122
|
+
# end
|
123
|
+
# end
|
124
|
+
# end
|
125
|
+
# end
|
126
|
+
#
|
93
127
|
# @see http://api.rubyonrails.org/classes/ActiveRecord/Migration/CommandRecorder.html
|
94
128
|
class ReversibleMigration < Cop
|
95
129
|
MSG = '%s is not reversible.'.freeze
|
130
|
+
IRREVERSIBLE_CHANGE_TABLE_CALLS = %i[
|
131
|
+
change change_default remove
|
132
|
+
].freeze
|
96
133
|
|
97
134
|
def_node_matcher :irreversible_schema_statement_call, <<-END
|
98
|
-
(send nil ${:
|
135
|
+
(send nil ${:change_table_comment :execute :remove_belongs_to} ...)
|
99
136
|
END
|
100
137
|
|
101
138
|
def_node_matcher :drop_table_call, <<-END
|
@@ -114,6 +151,10 @@ module RuboCop
|
|
114
151
|
(send nil :remove_foreign_key _ $_)
|
115
152
|
END
|
116
153
|
|
154
|
+
def_node_matcher :change_table_call, <<-END
|
155
|
+
(send nil :change_table $_ ...)
|
156
|
+
END
|
157
|
+
|
117
158
|
def on_send(node)
|
118
159
|
return unless within_change_method?(node)
|
119
160
|
return if within_reversible_block?(node)
|
@@ -125,6 +166,13 @@ module RuboCop
|
|
125
166
|
check_remove_foreign_key_node(node)
|
126
167
|
end
|
127
168
|
|
169
|
+
def on_block(node)
|
170
|
+
return unless within_change_method?(node)
|
171
|
+
return if within_reversible_block?(node)
|
172
|
+
|
173
|
+
check_change_table_node(node.send_node, node.body)
|
174
|
+
end
|
175
|
+
|
128
176
|
private
|
129
177
|
|
130
178
|
def check_irreversible_schema_statement_node(node)
|
@@ -177,28 +225,44 @@ module RuboCop
|
|
177
225
|
end
|
178
226
|
end
|
179
227
|
|
180
|
-
def
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
228
|
+
def check_change_table_node(node, block)
|
229
|
+
change_table_call(node) do |arg|
|
230
|
+
if target_rails_version < 4.0
|
231
|
+
add_offense(
|
232
|
+
node, :expression,
|
233
|
+
format(MSG, 'change_table')
|
234
|
+
)
|
235
|
+
elsif block.send_type?
|
236
|
+
check_change_table_offense(arg, block)
|
237
|
+
else
|
238
|
+
block.each_child_node do |child_node|
|
239
|
+
check_change_table_offense(arg, child_node)
|
240
|
+
end
|
186
241
|
end
|
187
|
-
parent = parent.parent
|
188
242
|
end
|
189
|
-
|
243
|
+
end
|
244
|
+
|
245
|
+
def check_change_table_offense(receiver, node)
|
246
|
+
method_name = node.method_name
|
247
|
+
return if receiver != node.receiver &&
|
248
|
+
!IRREVERSIBLE_CHANGE_TABLE_CALLS.include?(method_name)
|
249
|
+
add_offense(
|
250
|
+
node, :expression,
|
251
|
+
format(MSG, "change_table(with #{method_name})")
|
252
|
+
)
|
253
|
+
end
|
254
|
+
|
255
|
+
def within_change_method?(node)
|
256
|
+
node.each_ancestor(:def).any? do |ancestor|
|
257
|
+
method_name, = *ancestor
|
258
|
+
method_name == :change
|
259
|
+
end
|
190
260
|
end
|
191
261
|
|
192
262
|
def within_reversible_block?(node)
|
193
|
-
|
194
|
-
|
195
|
-
if parent.block_type?
|
196
|
-
_, block_name = *parent.to_a.first
|
197
|
-
return true if block_name == :reversible
|
198
|
-
end
|
199
|
-
parent = parent.parent
|
263
|
+
node.each_ancestor(:block).any? do |ancestor|
|
264
|
+
ancestor.block_type? && ancestor.send_node.method?(:reversible)
|
200
265
|
end
|
201
|
-
false
|
202
266
|
end
|
203
267
|
|
204
268
|
def all_hash_key?(args, *keys)
|