rubocop 0.46.0 → 0.47.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of rubocop might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/LICENSE.txt +1 -1
- data/README.md +77 -2
- data/config/default.yml +151 -74
- data/config/disabled.yml +9 -0
- data/config/enabled.yml +49 -9
- data/lib/rubocop.rb +36 -8
- data/lib/rubocop/ast/builder.rb +59 -0
- data/lib/rubocop/ast/node.rb +607 -0
- data/lib/rubocop/ast/node/array_node.rb +45 -0
- data/lib/rubocop/ast/node/case_node.rb +63 -0
- data/lib/rubocop/ast/node/for_node.rb +53 -0
- data/lib/rubocop/ast/node/hash_node.rb +102 -0
- data/lib/rubocop/ast/node/if_node.rb +136 -0
- data/lib/rubocop/ast/node/keyword_splat_node.rb +45 -0
- data/lib/rubocop/ast/node/mixin/conditional_node.rb +45 -0
- data/lib/rubocop/ast/node/mixin/hash_element_node.rb +125 -0
- data/lib/rubocop/ast/node/mixin/modifier_node.rb +17 -0
- data/lib/rubocop/ast/node/pair_node.rb +64 -0
- data/lib/rubocop/ast/node/until_node.rb +43 -0
- data/lib/rubocop/ast/node/when_node.rb +61 -0
- data/lib/rubocop/ast/node/while_node.rb +43 -0
- data/lib/rubocop/ast/sexp.rb +16 -0
- data/lib/rubocop/{ast_node → ast}/traversal.rb +1 -1
- data/lib/rubocop/cli.rb +18 -14
- data/lib/rubocop/comment_config.rb +1 -3
- data/lib/rubocop/config.rb +93 -35
- data/lib/rubocop/config_loader.rb +1 -1
- data/lib/rubocop/cop/badge.rb +73 -0
- data/lib/rubocop/cop/bundler/duplicated_gem.rb +2 -2
- data/lib/rubocop/cop/bundler/ordered_gems.rb +43 -3
- data/lib/rubocop/cop/commissioner.rb +17 -6
- data/lib/rubocop/cop/cop.rb +25 -112
- data/lib/rubocop/cop/lint/ambiguous_operator.rb +9 -4
- data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +7 -0
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +18 -4
- data/lib/rubocop/cop/lint/block_alignment.rb +40 -9
- data/lib/rubocop/cop/lint/circular_argument_reference.rb +14 -0
- data/lib/rubocop/cop/lint/condition_position.rb +14 -16
- data/lib/rubocop/cop/lint/debugger.rb +28 -0
- data/lib/rubocop/cop/lint/def_end_alignment.rb +21 -1
- data/lib/rubocop/cop/lint/deprecated_class_methods.rb +13 -1
- data/lib/rubocop/cop/lint/duplicate_case_condition.rb +26 -22
- data/lib/rubocop/cop/lint/duplicate_methods.rb +15 -1
- data/lib/rubocop/cop/lint/duplicated_key.rb +16 -8
- data/lib/rubocop/cop/lint/each_with_object_argument.rb +9 -0
- data/lib/rubocop/cop/lint/else_layout.rb +26 -29
- data/lib/rubocop/cop/lint/empty_ensure.rb +38 -0
- data/lib/rubocop/cop/lint/empty_expression.rb +11 -1
- data/lib/rubocop/cop/lint/empty_interpolation.rb +8 -0
- data/lib/rubocop/cop/lint/empty_when.rb +14 -16
- data/lib/rubocop/cop/lint/end_alignment.rb +48 -28
- data/lib/rubocop/cop/lint/end_in_method.rb +23 -0
- data/lib/rubocop/cop/lint/ensure_return.rb +21 -0
- data/lib/rubocop/cop/lint/float_out_of_range.rb +5 -0
- data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +29 -4
- data/lib/rubocop/cop/lint/handle_exceptions.rb +40 -0
- data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +7 -2
- data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +11 -2
- data/lib/rubocop/cop/lint/invalid_character_literal.rb +3 -0
- data/lib/rubocop/cop/lint/literal_in_condition.rb +34 -36
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +8 -0
- data/lib/rubocop/cop/lint/loop.rb +36 -0
- data/lib/rubocop/cop/lint/multiple_compare.rb +46 -0
- data/lib/rubocop/cop/lint/nested_method_definition.rb +22 -0
- data/lib/rubocop/cop/lint/next_without_accumulator.rb +5 -0
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +8 -0
- data/lib/rubocop/cop/lint/percent_string_array.rb +27 -13
- data/lib/rubocop/cop/lint/percent_symbol_array.rb +14 -4
- data/lib/rubocop/cop/lint/rand_one.rb +7 -3
- data/lib/rubocop/cop/lint/require_parentheses.rb +20 -19
- data/lib/rubocop/cop/lint/rescue_exception.rb +20 -0
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +66 -0
- data/lib/rubocop/cop/lint/shadowed_exception.rb +6 -1
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +24 -0
- data/lib/rubocop/cop/lint/string_conversion_in_interpolation.rb +8 -0
- data/lib/rubocop/cop/lint/underscore_prefixed_variable_name.rb +24 -0
- data/lib/rubocop/cop/lint/unified_integer.rb +5 -0
- data/lib/rubocop/cop/lint/unneeded_disable.rb +2 -2
- data/lib/rubocop/cop/lint/unneeded_splat_expansion.rb +5 -0
- data/lib/rubocop/cop/lint/unreachable_code.rb +17 -0
- data/lib/rubocop/cop/lint/unused_block_argument.rb +2 -0
- data/lib/rubocop/cop/lint/unused_method_argument.rb +10 -0
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +28 -1
- data/lib/rubocop/cop/lint/useless_assignment.rb +18 -0
- data/lib/rubocop/cop/lint/useless_comparison.rb +3 -1
- data/lib/rubocop/cop/lint/useless_else_without_rescue.rb +16 -1
- data/lib/rubocop/cop/lint/useless_setter_call.rb +16 -4
- data/lib/rubocop/cop/lint/void.rb +52 -0
- data/lib/rubocop/cop/message_annotator.rb +102 -0
- data/lib/rubocop/cop/metrics/block_length.rb +6 -0
- data/lib/rubocop/cop/metrics/block_nesting.rb +17 -5
- data/lib/rubocop/cop/metrics/line_length.rb +11 -4
- data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -2
- data/lib/rubocop/cop/mixin/array_syntax.rb +2 -11
- data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +12 -5
- data/lib/rubocop/cop/mixin/configurable_formatting.rb +48 -0
- data/lib/rubocop/cop/mixin/configurable_max.rb +3 -3
- data/lib/rubocop/cop/mixin/configurable_naming.rb +5 -33
- data/lib/rubocop/cop/mixin/configurable_numbering.rb +6 -47
- data/lib/rubocop/cop/mixin/documentation_comment.rb +7 -1
- data/lib/rubocop/cop/mixin/duplication.rb +46 -0
- data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +2 -2
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +14 -11
- data/lib/rubocop/cop/mixin/hash_alignment.rb +114 -0
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +3 -3
- data/lib/rubocop/cop/mixin/negative_conditional.rb +21 -7
- data/lib/rubocop/cop/mixin/on_method_def.rb +14 -0
- data/lib/rubocop/cop/mixin/on_normal_if_unless.rb +1 -24
- data/lib/rubocop/cop/mixin/statement_modifier.rb +8 -13
- data/lib/rubocop/cop/mixin/target_ruby_version.rb +16 -0
- data/lib/rubocop/cop/mixin/trailing_comma.rb +2 -3
- data/lib/rubocop/cop/offense.rb +1 -1
- data/lib/rubocop/cop/performance/case_when_splat.rb +56 -59
- data/lib/rubocop/cop/performance/detect.rb +2 -2
- data/lib/rubocop/cop/performance/flat_map.rb +3 -3
- data/lib/rubocop/cop/performance/redundant_merge.rb +3 -6
- data/lib/rubocop/cop/performance/regexp_match.rb +201 -0
- data/lib/rubocop/cop/rails/delegate.rb +2 -2
- data/lib/rubocop/cop/rails/delegate_allow_blank.rb +10 -19
- data/lib/rubocop/cop/rails/enum_uniqueness.rb +12 -40
- data/lib/rubocop/cop/rails/file_path.rb +80 -0
- data/lib/rubocop/cop/rails/find_each.rb +5 -14
- data/lib/rubocop/cop/rails/http_positional_arguments.rb +30 -24
- data/lib/rubocop/cop/rails/not_null_column.rb +23 -0
- data/lib/rubocop/cop/rails/reversible_migration.rb +217 -0
- data/lib/rubocop/cop/rails/safe_navigation.rb +4 -2
- data/lib/rubocop/cop/rails/skips_model_validations.rb +46 -0
- data/lib/rubocop/cop/rails/time_zone.rb +1 -1
- data/lib/rubocop/cop/rails/uniq_before_pluck.rb +7 -5
- data/lib/rubocop/cop/registry.rb +170 -0
- data/lib/rubocop/cop/{lint → security}/eval.rb +7 -1
- data/lib/rubocop/cop/security/marshal_load.rb +33 -0
- data/lib/rubocop/cop/security/yaml_load.rb +37 -0
- data/lib/rubocop/cop/style/align_hash.rb +138 -169
- data/lib/rubocop/cop/style/and_or.rb +1 -1
- data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +10 -15
- data/lib/rubocop/cop/style/case_indentation.rb +36 -27
- data/lib/rubocop/cop/style/conditional_assignment.rb +64 -47
- data/lib/rubocop/cop/style/each_with_object.rb +4 -1
- data/lib/rubocop/cop/style/else_alignment.rb +14 -20
- data/lib/rubocop/cop/style/empty_case_condition.rb +16 -25
- data/lib/rubocop/cop/style/empty_else.rb +20 -22
- data/lib/rubocop/cop/style/empty_literal.rb +4 -4
- data/lib/rubocop/cop/style/empty_method.rb +12 -6
- data/lib/rubocop/cop/style/encoding.rb +1 -1
- data/lib/rubocop/cop/style/file_name.rb +24 -4
- data/lib/rubocop/cop/style/first_method_argument_line_break.rb +1 -1
- data/lib/rubocop/cop/style/format_string.rb +17 -48
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +40 -11
- data/lib/rubocop/cop/style/guard_clause.rb +11 -17
- data/lib/rubocop/cop/style/hash_syntax.rb +24 -42
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +40 -28
- data/lib/rubocop/cop/style/if_inside_else.rb +6 -9
- data/lib/rubocop/cop/style/if_unless_modifier.rb +16 -25
- data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +3 -9
- data/lib/rubocop/cop/style/indent_array.rb +1 -1
- data/lib/rubocop/cop/style/indentation_width.rb +29 -60
- data/lib/rubocop/cop/style/infinite_loop.rb +21 -22
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +86 -0
- data/lib/rubocop/cop/style/{method_call_parentheses.rb → method_call_without_args_parentheses.rb} +8 -1
- data/lib/rubocop/cop/style/missing_else.rb +40 -14
- data/lib/rubocop/cop/style/multiline_if_modifier.rb +5 -15
- data/lib/rubocop/cop/style/multiline_if_then.rb +14 -8
- data/lib/rubocop/cop/style/multiline_method_call_indentation.rb +3 -3
- data/lib/rubocop/cop/style/multiline_ternary_operator.rb +1 -5
- data/lib/rubocop/cop/style/mutable_constant.rb +3 -2
- data/lib/rubocop/cop/style/negated_if.rb +3 -19
- data/lib/rubocop/cop/style/negated_while.rb +2 -17
- data/lib/rubocop/cop/style/nested_modifier.rb +16 -43
- data/lib/rubocop/cop/style/nested_ternary_operator.rb +3 -5
- data/lib/rubocop/cop/style/next.rb +23 -21
- data/lib/rubocop/cop/style/non_nil_check.rb +2 -3
- data/lib/rubocop/cop/style/not.rb +1 -3
- data/lib/rubocop/cop/style/numeric_literals.rb +2 -2
- data/lib/rubocop/cop/style/one_line_conditional.rb +12 -22
- data/lib/rubocop/cop/style/option_hash.rb +4 -15
- data/lib/rubocop/cop/style/parallel_assignment.rb +1 -3
- data/lib/rubocop/cop/style/parentheses_around_condition.rb +8 -12
- data/lib/rubocop/cop/style/percent_q_literals.rb +15 -12
- data/lib/rubocop/cop/style/redundant_freeze.rb +3 -2
- data/lib/rubocop/cop/style/redundant_parentheses.rb +27 -4
- data/lib/rubocop/cop/style/redundant_return.rb +4 -8
- data/lib/rubocop/cop/style/safe_navigation.rb +13 -6
- data/lib/rubocop/cop/style/space_after_colon.rb +2 -4
- data/lib/rubocop/cop/style/space_around_block_parameters.rb +1 -1
- data/lib/rubocop/cop/style/space_around_operators.rb +15 -13
- data/lib/rubocop/cop/style/string_methods.rb +1 -3
- data/lib/rubocop/cop/style/symbol_array.rb +1 -5
- data/lib/rubocop/cop/style/ternary_parentheses.rb +5 -6
- data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +2 -5
- data/lib/rubocop/cop/style/trailing_comma_in_literal.rb +1 -1
- data/lib/rubocop/cop/style/unless_else.rb +1 -5
- data/lib/rubocop/cop/style/when_then.rb +4 -2
- data/lib/rubocop/cop/style/while_until_do.rb +9 -13
- data/lib/rubocop/cop/style/while_until_modifier.rb +12 -11
- data/lib/rubocop/cop/style/word_array.rb +5 -9
- data/lib/rubocop/cop/team.rb +16 -15
- data/lib/rubocop/cop/util.rb +13 -3
- data/lib/rubocop/formatter/clang_style_formatter.rb +2 -2
- data/lib/rubocop/formatter/disabled_config_formatter.rb +2 -1
- data/lib/rubocop/magic_comment.rb +196 -0
- data/lib/rubocop/options.rb +5 -4
- data/lib/rubocop/processed_source.rb +1 -1
- data/lib/rubocop/rspec/cop_helper.rb +9 -0
- data/lib/rubocop/rspec/shared_examples.rb +1 -1
- data/lib/rubocop/runner.rb +7 -2
- data/lib/rubocop/version.rb +1 -1
- metadata +41 -14
- data/lib/rubocop/ast_node.rb +0 -624
- data/lib/rubocop/ast_node/builder.rb +0 -30
- data/lib/rubocop/ast_node/sexp.rb +0 -13
- data/lib/rubocop/cop/mixin/hash_node.rb +0 -14
- data/lib/rubocop/cop/mixin/if_node.rb +0 -42
@@ -61,8 +61,8 @@ module RuboCop
|
|
61
61
|
|
62
62
|
def delegate?(body)
|
63
63
|
receiver, = *body
|
64
|
-
|
65
|
-
|
64
|
+
receiver.respond_to?(:type) && receiver.send_type? &&
|
65
|
+
receiver.child_nodes.empty?
|
66
66
|
end
|
67
67
|
|
68
68
|
def arguments_match?(args, body)
|
@@ -17,44 +17,35 @@ module RuboCop
|
|
17
17
|
MSG = '`allow_blank` is not a valid option, use `allow_nil`.'.freeze
|
18
18
|
|
19
19
|
def_node_matcher :delegate, <<-PATTERN
|
20
|
-
(send
|
20
|
+
(send nil :delegate _ $hash)
|
21
21
|
PATTERN
|
22
22
|
|
23
|
-
def_node_matcher :
|
24
|
-
(
|
25
|
-
PATTERN
|
26
|
-
|
27
|
-
def_node_matcher :allow_blank?, <<-PATTERN
|
28
|
-
(pair $(sym :allow_blank) true)
|
23
|
+
def_node_matcher :allow_blank_option?, <<-PATTERN
|
24
|
+
(pair (sym :allow_blank) true)
|
29
25
|
PATTERN
|
30
26
|
|
31
27
|
def on_send(node)
|
32
28
|
offending_node = allow_blank_option(node)
|
29
|
+
|
33
30
|
return unless offending_node
|
34
31
|
|
35
|
-
|
36
|
-
add_offense(node, allow_blank.source_range, MSG)
|
32
|
+
add_offense(offending_node, :expression, MSG)
|
37
33
|
end
|
38
34
|
|
39
|
-
|
40
|
-
offending_node = allow_blank_option(node)
|
41
|
-
return unless offending_node
|
35
|
+
private
|
42
36
|
|
43
|
-
|
37
|
+
def autocorrect(pair_node)
|
44
38
|
lambda do |corrector|
|
45
|
-
corrector.replace(
|
39
|
+
corrector.replace(pair_node.key.source_range, 'allow_nil')
|
46
40
|
end
|
47
41
|
end
|
48
42
|
|
49
|
-
private
|
50
|
-
|
51
43
|
def allow_blank_option(node)
|
52
44
|
options_hash = delegate(node)
|
45
|
+
|
53
46
|
return unless options_hash
|
54
|
-
options = delegate_options(options_hash)
|
55
|
-
return unless options
|
56
47
|
|
57
|
-
|
48
|
+
options_hash.pairs.find { |opt| allow_blank_option?(opt) }
|
58
49
|
end
|
59
50
|
end
|
60
51
|
end
|
@@ -18,53 +18,25 @@ module RuboCop
|
|
18
18
|
# # good
|
19
19
|
# enum status: [:active, :archived]
|
20
20
|
class EnumUniqueness < Cop
|
21
|
-
|
22
|
-
|
23
|
-
def on_send(node)
|
24
|
-
_receiver, method_name, *args = *node
|
25
|
-
|
26
|
-
return unless method_name == :enum
|
27
|
-
|
28
|
-
enum_name, enum_args = parse_args(args)
|
21
|
+
include Duplication
|
29
22
|
|
30
|
-
|
31
|
-
return if dupes.empty?
|
32
|
-
|
33
|
-
add_offense(node, :selector, format(MSG, dupes.join(','), enum_name))
|
34
|
-
end
|
23
|
+
MSG = 'Duplicate value `%s` found in `%s` enum declaration.'.freeze
|
35
24
|
|
36
|
-
|
25
|
+
def_node_matcher :enum_declaration, <<-END
|
26
|
+
(send nil :enum (hash (pair (_ $_) $_)))
|
27
|
+
END
|
37
28
|
|
38
|
-
def
|
39
|
-
|
40
|
-
|
41
|
-
else
|
42
|
-
enum_hash_values(enum_args)
|
43
|
-
end
|
44
|
-
end
|
29
|
+
def on_send(node)
|
30
|
+
enum_declaration(node) do |name, args|
|
31
|
+
items = args.values
|
45
32
|
|
46
|
-
|
47
|
-
array_node.each_child_node.map(&:source)
|
48
|
-
end
|
33
|
+
return unless duplicates?(items)
|
49
34
|
|
50
|
-
|
51
|
-
|
52
|
-
|
35
|
+
consecutive_duplicates(items).each do |item|
|
36
|
+
add_offense(item, :expression, format(MSG, item.source, name))
|
37
|
+
end
|
53
38
|
end
|
54
39
|
end
|
55
|
-
|
56
|
-
def arr_dupes(array)
|
57
|
-
array.select { |element| array.count(element) > 1 }.uniq
|
58
|
-
end
|
59
|
-
|
60
|
-
def parse_args(args)
|
61
|
-
enum_config = args.first.each_child_node.first.child_nodes
|
62
|
-
|
63
|
-
enum_name = enum_config.first.source
|
64
|
-
enum_opts = enum_config.last
|
65
|
-
|
66
|
-
[enum_name, enum_opts]
|
67
|
-
end
|
68
40
|
end
|
69
41
|
end
|
70
42
|
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# This cop is used to identify usages of file path joining process
|
7
|
+
# to use `Rails.root.join` clause.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # bad
|
11
|
+
# Rails.root.join('app/models/goober')
|
12
|
+
# File.join(Rails.root, 'app/models/goober')
|
13
|
+
# "#{Rails.root}/app/models/goober"
|
14
|
+
#
|
15
|
+
# # good
|
16
|
+
# Rails.root.join('app', 'models', 'goober')
|
17
|
+
class FilePath < Cop
|
18
|
+
MSG = 'Please use `Rails.root.join(\'path\', \'to\')` instead.'.freeze
|
19
|
+
|
20
|
+
def_node_search :file_join_nodes, <<-PATTERN
|
21
|
+
(send (const nil :File) :join ...)
|
22
|
+
PATTERN
|
23
|
+
|
24
|
+
def_node_search :file_join_nodes?, <<-PATTERN
|
25
|
+
(send (const nil :File) :join ...)
|
26
|
+
PATTERN
|
27
|
+
|
28
|
+
def_node_search :rails_root_nodes?, <<-PATTERN
|
29
|
+
(send (const nil :Rails) :root)
|
30
|
+
PATTERN
|
31
|
+
|
32
|
+
def_node_search :rails_root_join_nodes, <<-PATTERN
|
33
|
+
(send (send (const nil :Rails) :root) :join ...)
|
34
|
+
PATTERN
|
35
|
+
|
36
|
+
def on_dstr(node)
|
37
|
+
return unless rails_root_nodes?(node)
|
38
|
+
register_offense(node)
|
39
|
+
end
|
40
|
+
|
41
|
+
def on_send(node)
|
42
|
+
check_for_file_join_with_rails_root(node)
|
43
|
+
check_for_rails_root_join_with_slash_separated_path(node)
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def check_for_file_join_with_rails_root(node)
|
49
|
+
return unless file_join_nodes?(node)
|
50
|
+
return unless file_join_nodes(node).map(&:method_args)
|
51
|
+
.flatten
|
52
|
+
.any? { |e| rails_root_nodes?(e) }
|
53
|
+
|
54
|
+
register_offense(node)
|
55
|
+
end
|
56
|
+
|
57
|
+
def check_for_rails_root_join_with_slash_separated_path(node)
|
58
|
+
return unless rails_root_nodes?(node)
|
59
|
+
return unless rails_root_join_nodes(node).map(&:method_args)
|
60
|
+
.flatten
|
61
|
+
.any? do |arg|
|
62
|
+
arg.source =~ %r{/}
|
63
|
+
end
|
64
|
+
|
65
|
+
register_offense(node)
|
66
|
+
end
|
67
|
+
|
68
|
+
def register_offense(node)
|
69
|
+
line_range = node.loc.column...node.loc.last_column
|
70
|
+
|
71
|
+
add_offense(
|
72
|
+
node,
|
73
|
+
source_range(processed_source.buffer, node.loc.line, line_range),
|
74
|
+
MSG
|
75
|
+
)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -18,12 +18,11 @@ module RuboCop
|
|
18
18
|
SCOPE_METHODS = [:all, :where, :not].freeze
|
19
19
|
|
20
20
|
def on_send(node)
|
21
|
-
receiver,
|
22
|
-
return unless
|
23
|
-
return if receiver.nil?
|
21
|
+
receiver, method, _selector = *node
|
22
|
+
return unless receiver && method == :each
|
24
23
|
|
25
|
-
_model,
|
26
|
-
return unless SCOPE_METHODS.include?(
|
24
|
+
_model, preceding_method = *receiver
|
25
|
+
return unless SCOPE_METHODS.include?(preceding_method)
|
27
26
|
return if method_chain(node).any? { |m| ignored_by_find_each?(m) }
|
28
27
|
|
29
28
|
add_offense(node, node.loc.selector, MSG)
|
@@ -38,15 +37,7 @@ module RuboCop
|
|
38
37
|
private
|
39
38
|
|
40
39
|
def method_chain(node)
|
41
|
-
|
42
|
-
if node.parent
|
43
|
-
method_chain(node.parent) << node.method_name
|
44
|
-
else
|
45
|
-
[node.method_name]
|
46
|
-
end
|
47
|
-
else
|
48
|
-
[]
|
49
|
-
end
|
40
|
+
[*node.ancestors, node].map(&:method_name)
|
50
41
|
end
|
51
42
|
|
52
43
|
def ignored_by_find_each?(relation_method)
|
@@ -3,9 +3,9 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Rails
|
6
|
-
# This cop is used to identify usages of http methods
|
7
|
-
#
|
8
|
-
#
|
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 arguments.
|
9
9
|
#
|
10
10
|
# @example
|
11
11
|
# # bad
|
@@ -17,45 +17,50 @@ module RuboCop
|
|
17
17
|
MSG = 'Use keyword arguments instead of ' \
|
18
18
|
'positional arguments for http call: `%s`.'.freeze
|
19
19
|
KEYWORD_ARGS = [
|
20
|
-
:headers, :env, :params, :body, :flash, :as,
|
21
|
-
:xhr, :session, :method, :format
|
20
|
+
:headers, :env, :params, :body, :flash, :as, :xhr, :session, :method
|
22
21
|
].freeze
|
23
22
|
HTTP_METHODS = [:get, :post, :put, :patch, :delete, :head].freeze
|
24
23
|
|
24
|
+
def_node_matcher :http_request?, <<-END
|
25
|
+
(send nil {#{HTTP_METHODS.map(&:inspect).join(' ')}} !nil $_data ...)
|
26
|
+
END
|
27
|
+
|
25
28
|
def on_send(node)
|
26
|
-
|
27
|
-
# if the first word on the line is not an http method, then skip
|
28
|
-
return unless HTTP_METHODS.include?(http_method)
|
29
|
+
data = http_request?(node)
|
29
30
|
# if the data is nil then we don't need to add keyword arguments
|
30
31
|
# because there is no data to put in params or headers, so skip
|
31
32
|
return if data.nil?
|
32
33
|
return unless needs_conversion?(data)
|
33
|
-
|
34
|
-
# there is an edge case here where sometimes the http method is
|
35
|
-
# wrapped into another method, but its just safer to skip those
|
36
|
-
# cases and process manually
|
37
|
-
return unless receiver.nil?
|
38
|
-
# a http_method without a path?, must be something else
|
39
|
-
return if http_path.nil?
|
34
|
+
|
40
35
|
add_offense(node, node.loc.selector, format(MSG, node.method_name))
|
41
36
|
end
|
42
37
|
|
43
38
|
# @return [Boolean] true if the line needs to be converted
|
44
39
|
def needs_conversion?(data)
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
value =
|
49
|
-
|
40
|
+
return true unless data.hash_type?
|
41
|
+
children = data.child_nodes
|
42
|
+
|
43
|
+
value = children.find do |d|
|
44
|
+
special_keyword_arg?(d.children.first) ||
|
45
|
+
(format_arg?(d.children.first) && children.size == 1)
|
50
46
|
end
|
47
|
+
|
51
48
|
value.nil?
|
52
49
|
end
|
53
50
|
|
51
|
+
def special_keyword_arg?(node)
|
52
|
+
KEYWORD_ARGS.include?(node.children.first) if node.type == :sym
|
53
|
+
end
|
54
|
+
|
55
|
+
def format_arg?(node)
|
56
|
+
node.children.first == :format if node.type == :sym
|
57
|
+
end
|
58
|
+
|
54
59
|
def convert_hash_data(data, type)
|
55
60
|
# empty hash or no hash return empty string
|
56
|
-
return '' if data.nil? || data.children.
|
61
|
+
return '' if data.nil? || data.children.empty?
|
57
62
|
hash_data = if data.hash_type?
|
58
|
-
format('{ %s }', data.
|
63
|
+
format('{ %s }', data.pairs.map(&:source).join(', '))
|
59
64
|
else
|
60
65
|
# user supplies an object,
|
61
66
|
# no need to surround with braces
|
@@ -78,11 +83,12 @@ module RuboCop
|
|
78
83
|
_receiver, http_method, http_path, *data = *node
|
79
84
|
controller_action = http_path.source
|
80
85
|
params = convert_hash_data(data.first, 'params')
|
81
|
-
headers = convert_hash_data(data.last, 'headers') if data.
|
86
|
+
headers = convert_hash_data(data.last, 'headers') if data.size > 1
|
82
87
|
# the range of the text to replace, which is the whole line
|
83
88
|
code_to_replace = node.loc.expression
|
84
89
|
# what to replace with
|
85
|
-
|
90
|
+
format = parentheses?(node) ? '%s(%s%s%s)' : '%s %s%s%s'
|
91
|
+
new_code = format(format, http_method, controller_action,
|
86
92
|
params, headers)
|
87
93
|
->(corrector) { corrector.replace(code_to_replace, new_code) }
|
88
94
|
end
|
@@ -9,10 +9,13 @@ module RuboCop
|
|
9
9
|
# @example
|
10
10
|
# # bad
|
11
11
|
# add_column :users, :name, :string, null: false
|
12
|
+
# add_reference :products, :category, null: false
|
12
13
|
#
|
13
14
|
# # good
|
14
15
|
# add_column :users, :name, :string, null: true
|
15
16
|
# add_column :users, :name, :string, null: false, default: ''
|
17
|
+
# add_reference :products, :category
|
18
|
+
# add_reference :products, :category, null: false, default: 1
|
16
19
|
class NotNullColumn < Cop
|
17
20
|
MSG = 'Do not add a NOT NULL column without a default value.'.freeze
|
18
21
|
|
@@ -20,6 +23,10 @@ module RuboCop
|
|
20
23
|
(send nil :add_column _ _ _ (hash $...))
|
21
24
|
PATTERN
|
22
25
|
|
26
|
+
def_node_matcher :add_not_null_reference?, <<-PATTERN
|
27
|
+
(send nil :add_reference _ _ (hash $...))
|
28
|
+
PATTERN
|
29
|
+
|
23
30
|
def_node_matcher :null_false?, <<-PATTERN
|
24
31
|
(pair (sym :null) (false))
|
25
32
|
PATTERN
|
@@ -29,7 +36,23 @@ module RuboCop
|
|
29
36
|
PATTERN
|
30
37
|
|
31
38
|
def on_send(node)
|
39
|
+
check_add_column(node)
|
40
|
+
check_add_reference(node)
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def check_add_column(node)
|
32
46
|
pairs = add_not_null_column?(node)
|
47
|
+
check_pairs(pairs)
|
48
|
+
end
|
49
|
+
|
50
|
+
def check_add_reference(node)
|
51
|
+
pairs = add_not_null_reference?(node)
|
52
|
+
check_pairs(pairs)
|
53
|
+
end
|
54
|
+
|
55
|
+
def check_pairs(pairs)
|
33
56
|
return unless pairs
|
34
57
|
return if pairs.any? { |pair| has_default?(pair) }
|
35
58
|
|
@@ -0,0 +1,217 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# This cop checks whether the change method of the migration file is
|
7
|
+
# reversible.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # bad
|
11
|
+
# def change
|
12
|
+
# change_table :users do |t|
|
13
|
+
# t.column :name, :string
|
14
|
+
# end
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# # good
|
18
|
+
# def change
|
19
|
+
# create_table :users do |t|
|
20
|
+
# t.string :name
|
21
|
+
# end
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# # good
|
25
|
+
# def change
|
26
|
+
# reversible do |dir|
|
27
|
+
# change_table :users do |t|
|
28
|
+
# dir.up do
|
29
|
+
# t.column :name, :string
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# dir.down do
|
33
|
+
# t.remove :name
|
34
|
+
# end
|
35
|
+
# end
|
36
|
+
# end
|
37
|
+
# end
|
38
|
+
#
|
39
|
+
# @example
|
40
|
+
# # drop_table
|
41
|
+
#
|
42
|
+
# # bad
|
43
|
+
# def change
|
44
|
+
# drop_table :users
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# # good
|
48
|
+
# def change
|
49
|
+
# drop_table :users do |t|
|
50
|
+
# t.string :name
|
51
|
+
# end
|
52
|
+
# end
|
53
|
+
#
|
54
|
+
# @example
|
55
|
+
# # change_column_default
|
56
|
+
#
|
57
|
+
# # bad
|
58
|
+
# def change
|
59
|
+
# change_column_default(:suppliers, :qualification, 'new')
|
60
|
+
# end
|
61
|
+
#
|
62
|
+
# # good
|
63
|
+
# def change
|
64
|
+
# change_column_default(:posts, :state, from: nil, to: "draft")
|
65
|
+
# end
|
66
|
+
#
|
67
|
+
# @example
|
68
|
+
# # remove_column
|
69
|
+
#
|
70
|
+
# # bad
|
71
|
+
# def change
|
72
|
+
# remove_column(:suppliers, :qualification)
|
73
|
+
# end
|
74
|
+
#
|
75
|
+
# # good
|
76
|
+
# def change
|
77
|
+
# remove_column(:suppliers, :qualification, :string)
|
78
|
+
# end
|
79
|
+
#
|
80
|
+
# @example
|
81
|
+
# # remove_foreign_key
|
82
|
+
#
|
83
|
+
# # bad
|
84
|
+
# def change
|
85
|
+
# remove_foreign_key :accounts, column: :owner_id
|
86
|
+
# end
|
87
|
+
#
|
88
|
+
# # good
|
89
|
+
# def change
|
90
|
+
# remove_foreign_key :accounts, :branches
|
91
|
+
# end
|
92
|
+
#
|
93
|
+
# @see http://api.rubyonrails.org/classes/ActiveRecord/Migration/CommandRecorder.html
|
94
|
+
class ReversibleMigration < Cop
|
95
|
+
MSG = '%s is not reversible.'.freeze
|
96
|
+
|
97
|
+
def_node_matcher :irreversible_schema_statement_call, <<-END
|
98
|
+
(send nil ${:change_table :change_table_comment :execute :remove_belongs_to} ...)
|
99
|
+
END
|
100
|
+
|
101
|
+
def_node_matcher :drop_table_call, <<-END
|
102
|
+
(send nil :drop_table ...)
|
103
|
+
END
|
104
|
+
|
105
|
+
def_node_matcher :change_column_default_call, <<-END
|
106
|
+
(send nil :change_column_default _ _ $...)
|
107
|
+
END
|
108
|
+
|
109
|
+
def_node_matcher :remove_column_call, <<-END
|
110
|
+
(send nil :remove_column $...)
|
111
|
+
END
|
112
|
+
|
113
|
+
def_node_matcher :remove_foreign_key_call, <<-END
|
114
|
+
(send nil :remove_foreign_key _ $_)
|
115
|
+
END
|
116
|
+
|
117
|
+
def on_send(node)
|
118
|
+
return unless within_change_method?(node)
|
119
|
+
return if within_reversible_block?(node)
|
120
|
+
|
121
|
+
check_irreversible_schema_statement_node(node)
|
122
|
+
check_drop_table_node(node)
|
123
|
+
check_change_column_default_node(node)
|
124
|
+
check_remove_column_node(node)
|
125
|
+
check_remove_foreign_key_node(node)
|
126
|
+
end
|
127
|
+
|
128
|
+
private
|
129
|
+
|
130
|
+
def check_irreversible_schema_statement_node(node)
|
131
|
+
irreversible_schema_statement_call(node) do |method_name|
|
132
|
+
add_offense(node, :expression, format(MSG, method_name))
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def check_drop_table_node(node)
|
137
|
+
drop_table_call(node) do
|
138
|
+
unless node.parent.block_type?
|
139
|
+
add_offense(
|
140
|
+
node, :expression,
|
141
|
+
format(MSG, 'drop_table(without block)')
|
142
|
+
)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def check_change_column_default_node(node)
|
148
|
+
change_column_default_call(node) do |args|
|
149
|
+
unless all_hash_key?(args.first, :from, :to)
|
150
|
+
add_offense(
|
151
|
+
node, :expression,
|
152
|
+
format(MSG, 'change_column_default(without :from and :to)')
|
153
|
+
)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def check_remove_column_node(node)
|
159
|
+
remove_column_call(node) do |args|
|
160
|
+
if args.to_a.size < 3
|
161
|
+
add_offense(
|
162
|
+
node, :expression,
|
163
|
+
format(MSG, 'remove_column(without type)')
|
164
|
+
)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def check_remove_foreign_key_node(node)
|
170
|
+
remove_foreign_key_call(node) do |arg|
|
171
|
+
if arg.hash_type?
|
172
|
+
add_offense(
|
173
|
+
node, :expression,
|
174
|
+
format(MSG, 'remove_foreign_key(without table)')
|
175
|
+
)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def within_change_method?(node)
|
181
|
+
parent = node.parent
|
182
|
+
while parent
|
183
|
+
if parent.def_type?
|
184
|
+
method_name, = *parent
|
185
|
+
return true if method_name == :change
|
186
|
+
end
|
187
|
+
parent = parent.parent
|
188
|
+
end
|
189
|
+
false
|
190
|
+
end
|
191
|
+
|
192
|
+
def within_reversible_block?(node)
|
193
|
+
parent = node.parent
|
194
|
+
while parent
|
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
|
200
|
+
end
|
201
|
+
false
|
202
|
+
end
|
203
|
+
|
204
|
+
def all_hash_key?(args, *keys)
|
205
|
+
return false unless args
|
206
|
+
return false unless args.hash_type?
|
207
|
+
|
208
|
+
hash_keys = args.to_a.map do |arg|
|
209
|
+
arg.to_a.first.children.first.to_sym
|
210
|
+
end
|
211
|
+
|
212
|
+
hash_keys & keys == keys
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|