rubocop 0.78.0 → 0.82.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/LICENSE.txt +1 -1
- data/README.md +4 -4
- data/config/default.yml +158 -48
- data/lib/rubocop.rb +19 -4
- data/lib/rubocop/ast/builder.rb +45 -42
- data/lib/rubocop/ast/node.rb +12 -19
- data/lib/rubocop/ast/node/array_node.rb +13 -0
- data/lib/rubocop/ast/node/block_node.rb +5 -1
- data/lib/rubocop/ast/node/case_match_node.rb +56 -0
- data/lib/rubocop/ast/node/def_node.rb +11 -0
- data/lib/rubocop/ast/node/forward_args_node.rb +18 -0
- data/lib/rubocop/ast/node/mixin/method_dispatch_node.rb +8 -0
- data/lib/rubocop/ast/node/regexp_node.rb +2 -4
- data/lib/rubocop/ast/traversal.rb +29 -10
- data/lib/rubocop/cli.rb +10 -4
- data/lib/rubocop/cli/command/show_cops.rb +11 -4
- data/lib/rubocop/comment_config.rb +6 -1
- data/lib/rubocop/config.rb +36 -10
- data/lib/rubocop/config_loader.rb +42 -33
- data/lib/rubocop/config_loader_resolver.rb +1 -1
- data/lib/rubocop/config_obsoletion.rb +4 -1
- data/lib/rubocop/config_validator.rb +66 -92
- data/lib/rubocop/cop/autocorrect_logic.rb +6 -3
- data/lib/rubocop/cop/badge.rb +5 -5
- data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +1 -1
- data/lib/rubocop/cop/corrector.rb +48 -24
- data/lib/rubocop/cop/correctors/alignment_corrector.rb +2 -2
- data/lib/rubocop/cop/correctors/condition_corrector.rb +1 -2
- data/lib/rubocop/cop/correctors/empty_line_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +3 -3
- data/lib/rubocop/cop/correctors/line_break_corrector.rb +2 -2
- data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/string_literal_corrector.rb +2 -2
- data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -1
- data/lib/rubocop/cop/generator.rb +3 -4
- data/lib/rubocop/cop/generator/configuration_injector.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/offense_location_keyword.rb +1 -1
- data/lib/rubocop/cop/layout/array_alignment.rb +53 -10
- data/lib/rubocop/cop/layout/block_end_newline.rb +5 -3
- data/lib/rubocop/cop/layout/dot_position.rb +1 -1
- data/lib/rubocop/cop/layout/else_alignment.rb +8 -0
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +2 -1
- data/lib/rubocop/cop/layout/end_of_line.rb +2 -2
- data/lib/rubocop/cop/layout/first_array_element_indentation.rb +16 -10
- data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/hash_alignment.rb +8 -4
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
- data/lib/rubocop/cop/layout/heredoc_indentation.rb +2 -2
- data/lib/rubocop/cop/layout/{tab.rb → indentation_style.rb} +48 -6
- data/lib/rubocop/cop/layout/leading_comment_space.rb +34 -3
- data/lib/rubocop/cop/layout/line_length.rb +32 -3
- data/lib/rubocop/cop/layout/multiline_block_layout.rb +15 -6
- data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +0 -4
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_block_parameters.rb +3 -3
- data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +133 -0
- data/lib/rubocop/cop/layout/space_around_operators.rb +19 -1
- data/lib/rubocop/cop/layout/space_before_block_braces.rb +2 -2
- data/lib/rubocop/cop/layout/space_before_first_arg.rb +8 -0
- data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +1 -1
- data/lib/rubocop/cop/layout/space_inside_block_braces.rb +2 -2
- data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +2 -9
- data/lib/rubocop/cop/layout/space_inside_range_literal.rb +2 -2
- data/lib/rubocop/cop/lint/boolean_symbol.rb +12 -0
- data/lib/rubocop/cop/lint/debugger.rb +2 -2
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +1 -1
- data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +1 -1
- data/lib/rubocop/cop/lint/inherit_exception.rb +1 -1
- data/lib/rubocop/cop/lint/interpolation_check.rb +1 -1
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
- data/lib/rubocop/cop/lint/loop.rb +6 -4
- data/lib/rubocop/cop/lint/multiple_comparison.rb +1 -1
- data/lib/rubocop/cop/lint/nested_method_definition.rb +2 -2
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +2 -2
- data/lib/rubocop/cop/lint/number_conversion.rb +1 -1
- data/lib/rubocop/cop/lint/percent_string_array.rb +2 -2
- data/lib/rubocop/cop/lint/raise_exception.rb +75 -0
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +12 -7
- data/lib/rubocop/cop/lint/redundant_string_coercion.rb +1 -1
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +1 -1
- data/lib/rubocop/cop/lint/struct_new_override.rb +58 -0
- data/lib/rubocop/cop/lint/suppressed_exception.rb +12 -22
- data/lib/rubocop/cop/lint/unified_integer.rb +0 -2
- data/lib/rubocop/cop/lint/unused_method_argument.rb +32 -6
- data/lib/rubocop/cop/lint/uri_regexp.rb +4 -4
- data/lib/rubocop/cop/lint/useless_setter_call.rb +4 -0
- data/lib/rubocop/cop/migration/department_name.rb +47 -6
- data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +4 -0
- data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +6 -1
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +7 -7
- data/lib/rubocop/cop/mixin/hash_transform_method.rb +171 -0
- data/lib/rubocop/cop/mixin/line_length_help.rb +1 -1
- data/lib/rubocop/cop/mixin/method_complexity.rb +5 -0
- data/lib/rubocop/cop/mixin/statement_modifier.rb +4 -3
- data/lib/rubocop/cop/mixin/trailing_comma.rb +3 -10
- data/lib/rubocop/cop/naming/class_and_module_camel_case.rb +1 -1
- data/lib/rubocop/cop/naming/constant_name.rb +2 -1
- data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +1 -1
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
- data/lib/rubocop/cop/naming/method_name.rb +30 -0
- data/lib/rubocop/cop/naming/method_parameter_name.rb +1 -1
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +1 -1
- data/lib/rubocop/cop/registry.rb +15 -3
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +26 -6
- data/lib/rubocop/cop/style/alias.rb +4 -4
- data/lib/rubocop/cop/style/and_or.rb +5 -6
- data/lib/rubocop/cop/style/array_join.rb +1 -1
- data/lib/rubocop/cop/style/block_delimiters.rb +60 -1
- data/lib/rubocop/cop/style/case_equality.rb +24 -1
- data/lib/rubocop/cop/style/character_literal.rb +2 -2
- data/lib/rubocop/cop/style/collection_methods.rb +2 -0
- data/lib/rubocop/cop/style/conditional_assignment.rb +8 -8
- data/lib/rubocop/cop/style/copyright.rb +1 -1
- data/lib/rubocop/cop/style/dir.rb +1 -1
- data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +49 -0
- data/lib/rubocop/cop/style/documentation.rb +43 -5
- data/lib/rubocop/cop/style/double_cop_disable_directive.rb +1 -1
- data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
- data/lib/rubocop/cop/style/each_with_object.rb +3 -3
- data/lib/rubocop/cop/style/empty_method.rb +1 -1
- data/lib/rubocop/cop/style/end_block.rb +6 -0
- data/lib/rubocop/cop/style/even_odd.rb +1 -1
- data/lib/rubocop/cop/style/expand_path_arguments.rb +3 -3
- data/lib/rubocop/cop/style/exponential_notation.rb +119 -0
- data/lib/rubocop/cop/style/format_string.rb +2 -2
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +89 -11
- data/lib/rubocop/cop/style/hash_each_methods.rb +89 -0
- data/lib/rubocop/cop/style/hash_syntax.rb +3 -5
- data/lib/rubocop/cop/style/hash_transform_keys.rb +83 -0
- data/lib/rubocop/cop/style/hash_transform_values.rb +80 -0
- data/lib/rubocop/cop/style/if_unless_modifier.rb +23 -3
- data/lib/rubocop/cop/style/inverse_methods.rb +9 -5
- data/lib/rubocop/cop/style/lambda.rb +3 -2
- data/lib/rubocop/cop/style/lambda_call.rb +2 -2
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +7 -205
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +169 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +54 -0
- data/lib/rubocop/cop/style/mixin_grouping.rb +1 -1
- data/lib/rubocop/cop/style/module_function.rb +58 -12
- data/lib/rubocop/cop/style/multiline_if_modifier.rb +1 -1
- data/lib/rubocop/cop/style/multiline_memoization.rb +1 -1
- data/lib/rubocop/cop/style/multiline_when_then.rb +5 -1
- data/lib/rubocop/cop/style/mutable_constant.rb +2 -4
- data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +4 -4
- data/lib/rubocop/cop/style/next.rb +2 -2
- data/lib/rubocop/cop/style/nil_comparison.rb +1 -1
- data/lib/rubocop/cop/style/non_nil_check.rb +4 -4
- data/lib/rubocop/cop/style/not.rb +1 -1
- data/lib/rubocop/cop/style/numeric_literal_prefix.rb +1 -1
- data/lib/rubocop/cop/style/numeric_literals.rb +1 -1
- data/lib/rubocop/cop/style/numeric_predicate.rb +5 -4
- data/lib/rubocop/cop/style/one_line_conditional.rb +4 -3
- data/lib/rubocop/cop/style/or_assignment.rb +4 -3
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +7 -7
- data/lib/rubocop/cop/style/percent_q_literals.rb +1 -1
- data/lib/rubocop/cop/style/perl_backrefs.rb +2 -2
- data/lib/rubocop/cop/style/proc.rb +1 -1
- data/lib/rubocop/cop/style/raise_args.rb +1 -1
- data/lib/rubocop/cop/style/random_with_offset.rb +3 -3
- data/lib/rubocop/cop/style/redundant_condition.rb +18 -6
- data/lib/rubocop/cop/style/redundant_conditional.rb +1 -1
- data/lib/rubocop/cop/style/redundant_exception.rb +3 -3
- data/lib/rubocop/cop/style/redundant_interpolation.rb +2 -2
- data/lib/rubocop/cop/style/redundant_percent_q.rb +2 -2
- data/lib/rubocop/cop/style/redundant_return.rb +5 -7
- data/lib/rubocop/cop/style/redundant_self.rb +1 -1
- data/lib/rubocop/cop/style/redundant_sort.rb +2 -2
- data/lib/rubocop/cop/style/rescue_modifier.rb +1 -1
- data/lib/rubocop/cop/style/return_nil.rb +1 -1
- data/lib/rubocop/cop/style/safe_navigation.rb +1 -1
- data/lib/rubocop/cop/style/self_assignment.rb +1 -1
- data/lib/rubocop/cop/style/special_global_vars.rb +1 -1
- data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +1 -4
- data/lib/rubocop/cop/style/string_hash_keys.rb +1 -1
- data/lib/rubocop/cop/style/symbol_array.rb +3 -3
- data/lib/rubocop/cop/style/symbol_literal.rb +2 -2
- data/lib/rubocop/cop/style/ternary_parentheses.rb +2 -3
- data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +35 -22
- data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +41 -0
- data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +88 -0
- data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +44 -0
- data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
- data/lib/rubocop/cop/style/unpack_first.rb +0 -4
- data/lib/rubocop/cop/style/variable_interpolation.rb +1 -1
- data/lib/rubocop/cop/style/while_until_modifier.rb +1 -1
- data/lib/rubocop/cop/style/word_array.rb +1 -1
- data/lib/rubocop/cop/style/yoda_condition.rb +16 -1
- data/lib/rubocop/cop/style/zero_length_predicate.rb +1 -1
- data/lib/rubocop/cop/variable_force.rb +4 -1
- data/lib/rubocop/formatter/clang_style_formatter.rb +1 -1
- data/lib/rubocop/formatter/formatter_set.rb +1 -1
- data/lib/rubocop/formatter/junit_formatter.rb +74 -0
- data/lib/rubocop/formatter/pacman_formatter.rb +1 -1
- data/lib/rubocop/formatter/tap_formatter.rb +1 -1
- data/lib/rubocop/node_pattern.rb +96 -10
- data/lib/rubocop/options.rb +7 -1
- data/lib/rubocop/processed_source.rb +1 -4
- data/lib/rubocop/rspec/cop_helper.rb +1 -1
- data/lib/rubocop/rspec/expect_offense.rb +1 -1
- data/lib/rubocop/rspec/shared_contexts.rb +5 -4
- data/lib/rubocop/runner.rb +1 -1
- data/lib/rubocop/target_ruby.rb +151 -0
- data/lib/rubocop/version.rb +1 -1
- metadata +39 -12
- data/lib/rubocop/cop/lint/end_in_method.rb +0 -40
- data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +0 -209
- data/lib/rubocop/formatter/disabled_lines_formatter.rb +0 -57
@@ -0,0 +1,89 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# This cop checks for uses of `each_key` and `each_value` Hash methods.
|
7
|
+
#
|
8
|
+
# Note: If you have an array of two-element arrays, you can put
|
9
|
+
# parentheses around the block arguments to indicate that you're not
|
10
|
+
# working with a hash, and suppress RuboCop offenses.
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# # bad
|
14
|
+
# hash.keys.each { |k| p k }
|
15
|
+
# hash.values.each { |v| p v }
|
16
|
+
#
|
17
|
+
# # good
|
18
|
+
# hash.each_key { |k| p k }
|
19
|
+
# hash.each_value { |v| p v }
|
20
|
+
class HashEachMethods < Cop
|
21
|
+
include Lint::UnusedArgument
|
22
|
+
|
23
|
+
MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
|
24
|
+
|
25
|
+
def_node_matcher :kv_each, <<~PATTERN
|
26
|
+
(block $(send (send _ ${:keys :values}) :each) ...)
|
27
|
+
PATTERN
|
28
|
+
|
29
|
+
def on_block(node)
|
30
|
+
register_kv_offense(node)
|
31
|
+
end
|
32
|
+
|
33
|
+
def autocorrect(node)
|
34
|
+
lambda do |corrector|
|
35
|
+
correct_key_value_each(node, corrector)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def register_kv_offense(node)
|
42
|
+
kv_each(node) do |target, method|
|
43
|
+
return unless target.receiver.receiver
|
44
|
+
|
45
|
+
msg = format(message, prefer: "each_#{method[0..-2]}",
|
46
|
+
current: "#{method}.each")
|
47
|
+
|
48
|
+
add_offense(target, location: kv_range(target), message: msg)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def check_argument(variable)
|
53
|
+
return unless variable.block_argument?
|
54
|
+
|
55
|
+
(@block_args ||= []).push(variable)
|
56
|
+
end
|
57
|
+
|
58
|
+
def used?(arg)
|
59
|
+
@block_args.find { |var| var.declaration_node.loc == arg.loc }.used?
|
60
|
+
end
|
61
|
+
|
62
|
+
def correct_implicit(node, corrector, method_name)
|
63
|
+
corrector.replace(node, method_name)
|
64
|
+
correct_args(node, corrector)
|
65
|
+
end
|
66
|
+
|
67
|
+
def correct_key_value_each(node, corrector)
|
68
|
+
receiver = node.receiver.receiver
|
69
|
+
name = "each_#{node.receiver.method_name.to_s.chop}"
|
70
|
+
return correct_implicit(node, corrector, name) unless receiver
|
71
|
+
|
72
|
+
new_source = receiver.source + ".#{name}"
|
73
|
+
corrector.replace(node, new_source)
|
74
|
+
end
|
75
|
+
|
76
|
+
def correct_args(node, corrector)
|
77
|
+
args = node.parent.arguments
|
78
|
+
name, = *args.children.find { |arg| used?(arg) }
|
79
|
+
|
80
|
+
corrector.replace(args, "|#{name}|")
|
81
|
+
end
|
82
|
+
|
83
|
+
def kv_range(outer_node)
|
84
|
+
outer_node.receiver.loc.selector.join(outer_node.loc.selector)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -144,11 +144,11 @@ module RuboCop
|
|
144
144
|
# Prefer { :production? => false } over { production?: false } and
|
145
145
|
# similarly for other non-alnum final characters (except quotes,
|
146
146
|
# to prefer { "x y": 1 } over { :"x y" => 1 }).
|
147
|
-
return false unless
|
147
|
+
return false unless /[\p{Alnum}"']\z/.match?(sym_name)
|
148
148
|
end
|
149
149
|
|
150
150
|
# Most hash keys can be matched against a simple regex.
|
151
|
-
return true if
|
151
|
+
return true if /\A[_a-z]\w*[?!]?\z/i.match?(sym_name)
|
152
152
|
|
153
153
|
# For more complicated hash keys, let the parser validate the syntax.
|
154
154
|
parse("{ #{sym_name}: :foo }").valid_syntax?
|
@@ -188,11 +188,9 @@ module RuboCop
|
|
188
188
|
end
|
189
189
|
|
190
190
|
def autocorrect_hash_rockets(corrector, pair_node)
|
191
|
-
key = pair_node.key.source_range
|
192
191
|
op = pair_node.loc.operator
|
193
192
|
|
194
|
-
corrector.
|
195
|
-
corrector.insert_before(key, ':')
|
193
|
+
corrector.wrap(pair_node.key, ':', pair_node.inverse_delimiter(true))
|
196
194
|
corrector.remove(range_with_surrounding_space(range: op))
|
197
195
|
end
|
198
196
|
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# This cop looks for uses of `_.each_with_object({}) {...}`,
|
7
|
+
# `_.map {...}.to_h`, and `Hash[_.map {...}]` that are actually just
|
8
|
+
# transforming the keys of a hash, and tries to use a simpler & faster
|
9
|
+
# call to `transform_keys` instead.
|
10
|
+
#
|
11
|
+
# This can produce false positives if we are transforming an enumerable
|
12
|
+
# of key-value-like pairs that isn't actually a hash, e.g.:
|
13
|
+
# `[[k1, v1], [k2, v2], ...]`
|
14
|
+
#
|
15
|
+
# This cop should only be enabled on Ruby version 2.5 or newer
|
16
|
+
# (`transform_keys` was added in Ruby 2.5.)
|
17
|
+
#
|
18
|
+
# @example
|
19
|
+
# # bad
|
20
|
+
# {a: 1, b: 2}.each_with_object({}) { |(k, v), h| h[foo(k)] = v }
|
21
|
+
# {a: 1, b: 2}.map { |k, v| [k.to_s, v] }
|
22
|
+
#
|
23
|
+
# # good
|
24
|
+
# {a: 1, b: 2}.transform_keys { |k| foo(k) }
|
25
|
+
# {a: 1, b: 2}.transform_keys { |k| k.to_s }
|
26
|
+
class HashTransformKeys < Cop
|
27
|
+
extend TargetRubyVersion
|
28
|
+
include HashTransformMethod
|
29
|
+
|
30
|
+
minimum_target_ruby_version 2.5
|
31
|
+
|
32
|
+
def_node_matcher :on_bad_each_with_object, <<~PATTERN
|
33
|
+
(block
|
34
|
+
({send csend}
|
35
|
+
!{(send _ :each_with_index) (array ...)}
|
36
|
+
:each_with_object (hash))
|
37
|
+
(args
|
38
|
+
(mlhs
|
39
|
+
(arg $_)
|
40
|
+
(arg _val))
|
41
|
+
(arg _memo))
|
42
|
+
({send csend} (lvar _memo) :[]= $_ $(lvar _val)))
|
43
|
+
PATTERN
|
44
|
+
|
45
|
+
def_node_matcher :on_bad_hash_brackets_map, <<~PATTERN
|
46
|
+
(send
|
47
|
+
(const _ :Hash)
|
48
|
+
:[]
|
49
|
+
(block
|
50
|
+
({send csend} !(send _ :each_with_index) {:map :collect})
|
51
|
+
(args
|
52
|
+
(arg $_)
|
53
|
+
(arg _val))
|
54
|
+
(array $_ $(lvar _val))))
|
55
|
+
PATTERN
|
56
|
+
|
57
|
+
def_node_matcher :on_bad_map_to_h, <<~PATTERN
|
58
|
+
({send csend}
|
59
|
+
(block
|
60
|
+
({send csend}
|
61
|
+
!{(send _ :each_with_index) (array ...)}
|
62
|
+
{:map :collect})
|
63
|
+
(args
|
64
|
+
(arg $_)
|
65
|
+
(arg _val))
|
66
|
+
(array $_ $(lvar _val)))
|
67
|
+
:to_h)
|
68
|
+
PATTERN
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def extract_captures(match)
|
73
|
+
key_argname, key_body_expr, val_body_expr = *match
|
74
|
+
Captures.new(key_argname, key_body_expr, val_body_expr)
|
75
|
+
end
|
76
|
+
|
77
|
+
def new_method_name
|
78
|
+
'transform_keys'
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# This cop looks for uses of `_.each_with_object({}) {...}`,
|
7
|
+
# `_.map {...}.to_h`, and `Hash[_.map {...}]` that are actually just
|
8
|
+
# transforming the values of a hash, and tries to use a simpler & faster
|
9
|
+
# call to `transform_values` instead.
|
10
|
+
#
|
11
|
+
# This can produce false positives if we are transforming an enumerable
|
12
|
+
# of key-value-like pairs that isn't actually a hash, e.g.:
|
13
|
+
# `[[k1, v1], [k2, v2], ...]`
|
14
|
+
#
|
15
|
+
# This cop should only be enabled on Ruby version 2.4 or newer
|
16
|
+
# (`transform_values` was added in Ruby 2.4.)
|
17
|
+
#
|
18
|
+
# @example
|
19
|
+
# # bad
|
20
|
+
# {a: 1, b: 2}.each_with_object({}) { |(k, v), h| h[k] = foo(v) }
|
21
|
+
# {a: 1, b: 2}.map { |k, v| [k, v * v] }
|
22
|
+
#
|
23
|
+
# # good
|
24
|
+
# {a: 1, b: 2}.transform_values { |v| foo(v) }
|
25
|
+
# {a: 1, b: 2}.transform_values { |v| v * v }
|
26
|
+
class HashTransformValues < Cop
|
27
|
+
include HashTransformMethod
|
28
|
+
|
29
|
+
def_node_matcher :on_bad_each_with_object, <<~PATTERN
|
30
|
+
(block
|
31
|
+
({send csend}
|
32
|
+
!{(send _ :each_with_index) (array ...)}
|
33
|
+
:each_with_object (hash))
|
34
|
+
(args
|
35
|
+
(mlhs
|
36
|
+
(arg _key)
|
37
|
+
(arg $_))
|
38
|
+
(arg _memo))
|
39
|
+
({send csend} (lvar _memo) :[]= $(lvar _key) $_))
|
40
|
+
PATTERN
|
41
|
+
|
42
|
+
def_node_matcher :on_bad_hash_brackets_map, <<~PATTERN
|
43
|
+
(send
|
44
|
+
(const _ :Hash)
|
45
|
+
:[]
|
46
|
+
(block
|
47
|
+
({send csend} !(send _ :each_with_index) {:map :collect})
|
48
|
+
(args
|
49
|
+
(arg _key)
|
50
|
+
(arg $_))
|
51
|
+
(array $(lvar _key) $_)))
|
52
|
+
PATTERN
|
53
|
+
|
54
|
+
def_node_matcher :on_bad_map_to_h, <<~PATTERN
|
55
|
+
({send csend}
|
56
|
+
(block
|
57
|
+
({send csend}
|
58
|
+
!{(send _ :each_with_index) (array ...)}
|
59
|
+
{:map :collect})
|
60
|
+
(args
|
61
|
+
(arg _key)
|
62
|
+
(arg $_))
|
63
|
+
(array $(lvar _key) $_))
|
64
|
+
:to_h)
|
65
|
+
PATTERN
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def extract_captures(match)
|
70
|
+
val_argname, key_body_expr, val_body_expr = *match
|
71
|
+
Captures.new(val_argname, val_body_expr, key_body_expr)
|
72
|
+
end
|
73
|
+
|
74
|
+
def new_method_name
|
75
|
+
'transform_values'
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -9,7 +9,7 @@ module RuboCop
|
|
9
9
|
#
|
10
10
|
# The maximum line length is configured in the `Layout/LineLength`
|
11
11
|
# cop. The tab size is configured in the `IndentationWidth` of the
|
12
|
-
# `Layout/
|
12
|
+
# `Layout/IndentationStyle` cop.
|
13
13
|
#
|
14
14
|
# @example
|
15
15
|
# # bad
|
@@ -47,7 +47,7 @@ module RuboCop
|
|
47
47
|
def on_if(node)
|
48
48
|
msg = if eligible_node?(node)
|
49
49
|
MSG_USE_MODIFIER unless named_capture_in_condition?(node)
|
50
|
-
elsif
|
50
|
+
elsif too_long_due_to_modifier?(node)
|
51
51
|
MSG_USE_NORMAL
|
52
52
|
end
|
53
53
|
return unless msg
|
@@ -63,11 +63,16 @@ module RuboCop
|
|
63
63
|
else
|
64
64
|
to_modifier_form(node)
|
65
65
|
end
|
66
|
-
->(corrector) { corrector.replace(node
|
66
|
+
->(corrector) { corrector.replace(node, replacement) }
|
67
67
|
end
|
68
68
|
|
69
69
|
private
|
70
70
|
|
71
|
+
def too_long_due_to_modifier?(node)
|
72
|
+
node.modifier_form? && too_long_single_line?(node) &&
|
73
|
+
!another_statement_on_same_line?(node)
|
74
|
+
end
|
75
|
+
|
71
76
|
def ignored_patterns
|
72
77
|
config.for_cop('Layout/LineLength')['IgnoredPatterns'] || []
|
73
78
|
end
|
@@ -129,6 +134,21 @@ module RuboCop
|
|
129
134
|
node.ternary? || node.modifier_form? || node.elsif? || node.else?
|
130
135
|
end
|
131
136
|
|
137
|
+
def another_statement_on_same_line?(node)
|
138
|
+
line_no = node.source_range.last_line
|
139
|
+
|
140
|
+
# traverse the AST upwards until we find a 'begin' node
|
141
|
+
# we want to look at the following child and see if it is on the
|
142
|
+
# same line as this 'if' node
|
143
|
+
while node && !node.begin_type?
|
144
|
+
index = node.sibling_index
|
145
|
+
node = node.parent
|
146
|
+
end
|
147
|
+
|
148
|
+
node && (sibling = node.children[index + 1]) &&
|
149
|
+
sibling.source_range.first_line == line_no
|
150
|
+
end
|
151
|
+
|
132
152
|
def parenthesize?(node)
|
133
153
|
# Parenthesize corrected expression if changing to modifier-if form
|
134
154
|
# would change the meaning of the parent expression
|
@@ -44,7 +44,7 @@ module RuboCop
|
|
44
44
|
CAMEL_CASE = /[A-Z]+[a-z]+/.freeze
|
45
45
|
|
46
46
|
def self.autocorrect_incompatible_with
|
47
|
-
[Style::Not]
|
47
|
+
[Style::Not, Style::SymbolProc]
|
48
48
|
end
|
49
49
|
|
50
50
|
def_node_matcher :inverse_candidate?, <<~PATTERN
|
@@ -109,10 +109,7 @@ module RuboCop
|
|
109
109
|
corrector.remove(not_to_receiver(node, method_call))
|
110
110
|
corrector.replace(method_call.loc.selector,
|
111
111
|
inverse_methods[method].to_s)
|
112
|
-
|
113
|
-
if EQUALITY_METHODS.include?(method)
|
114
|
-
corrector.remove(end_parentheses(node, method_call))
|
115
|
-
end
|
112
|
+
remove_end_parenthesis(corrector, node, method, method_call)
|
116
113
|
end
|
117
114
|
end
|
118
115
|
|
@@ -187,6 +184,13 @@ module RuboCop
|
|
187
184
|
def dot_range(loc)
|
188
185
|
range_between(loc.dot.begin_pos, loc.expression.end_pos)
|
189
186
|
end
|
187
|
+
|
188
|
+
def remove_end_parenthesis(corrector, node, method, method_call)
|
189
|
+
return unless EQUALITY_METHODS.include?(method) ||
|
190
|
+
method_call.parent.begin_type?
|
191
|
+
|
192
|
+
corrector.remove(end_parentheses(node, method_call))
|
193
|
+
end
|
190
194
|
end
|
191
195
|
end
|
192
196
|
end
|
@@ -73,6 +73,7 @@ module RuboCop
|
|
73
73
|
location: node.send_node.source_range,
|
74
74
|
message: message(node, selector))
|
75
75
|
end
|
76
|
+
alias on_numblock on_block
|
76
77
|
|
77
78
|
def autocorrect(node)
|
78
79
|
if node.send_node.source == 'lambda'
|
@@ -108,13 +109,13 @@ module RuboCop
|
|
108
109
|
end
|
109
110
|
|
110
111
|
def autocorrect_method_to_literal(corrector, node)
|
111
|
-
corrector.replace(node.send_node
|
112
|
+
corrector.replace(node.send_node, '->')
|
112
113
|
|
113
114
|
return unless node.arguments?
|
114
115
|
|
115
116
|
arg_str = "(#{lambda_arg_string(node.arguments)})"
|
116
117
|
|
117
|
-
corrector.insert_after(node.send_node
|
118
|
+
corrector.insert_after(node.send_node, arg_str)
|
118
119
|
corrector.remove(arguments_with_whitespace(node))
|
119
120
|
end
|
120
121
|
|
@@ -37,7 +37,7 @@ module RuboCop
|
|
37
37
|
receiver = node.receiver.source
|
38
38
|
replacement = node.source.sub("#{receiver}.", "#{receiver}.call")
|
39
39
|
|
40
|
-
corrector.replace(node
|
40
|
+
corrector.replace(node, replacement)
|
41
41
|
else
|
42
42
|
add_parentheses(node, corrector) unless node.parenthesized?
|
43
43
|
corrector.remove(node.loc.selector)
|
@@ -54,7 +54,7 @@ module RuboCop
|
|
54
54
|
|
55
55
|
def add_parentheses(node, corrector)
|
56
56
|
if node.arguments.empty?
|
57
|
-
corrector.insert_after(node
|
57
|
+
corrector.insert_after(node, '()')
|
58
58
|
else
|
59
59
|
corrector.replace(args_begin(node), '(')
|
60
60
|
corrector.insert_after(args_end(node), ')')
|
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# rubocop:disable Metrics/ClassLength
|
4
3
|
module RuboCop
|
5
4
|
module Cop
|
6
5
|
module Style
|
@@ -43,7 +42,6 @@ module RuboCop
|
|
43
42
|
#
|
44
43
|
# @example EnforcedStyle: require_parentheses (default)
|
45
44
|
#
|
46
|
-
#
|
47
45
|
# # bad
|
48
46
|
# array.delete e
|
49
47
|
#
|
@@ -150,94 +148,23 @@ module RuboCop
|
|
150
148
|
include IgnoredMethods
|
151
149
|
include IgnoredPattern
|
152
150
|
|
153
|
-
|
151
|
+
def initialize(*)
|
152
|
+
super
|
153
|
+
return unless style_configured?
|
154
154
|
|
155
|
-
def on_send(node)
|
156
155
|
case style
|
157
156
|
when :require_parentheses
|
158
|
-
|
157
|
+
extend RequireParentheses
|
159
158
|
when :omit_parentheses
|
160
|
-
|
159
|
+
extend OmitParentheses
|
161
160
|
end
|
162
161
|
end
|
163
|
-
alias on_csend on_send
|
164
|
-
alias on_super on_send
|
165
|
-
alias on_yield on_send
|
166
162
|
|
167
|
-
|
168
|
-
|
169
|
-
when :require_parentheses
|
170
|
-
autocorrect_for_require_parentheses(node)
|
171
|
-
when :omit_parentheses
|
172
|
-
autocorrect_for_omit_parentheses(node)
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
def message(_node = nil)
|
177
|
-
case style
|
178
|
-
when :require_parentheses
|
179
|
-
'Use parentheses for method calls with arguments.'
|
180
|
-
when :omit_parentheses
|
181
|
-
'Omit parentheses for method calls with arguments.'
|
182
|
-
end
|
183
|
-
end
|
163
|
+
# @abstract Overridden in style modules
|
164
|
+
def autocorrect(_node); end
|
184
165
|
|
185
166
|
private
|
186
167
|
|
187
|
-
def add_offense_for_require_parentheses(node)
|
188
|
-
return if ignored_method?(node.method_name)
|
189
|
-
return if matches_ignored_pattern?(node.method_name)
|
190
|
-
return if eligible_for_parentheses_omission?(node)
|
191
|
-
return unless node.arguments? && !node.parenthesized?
|
192
|
-
|
193
|
-
add_offense(node)
|
194
|
-
end
|
195
|
-
|
196
|
-
def add_offense_for_omit_parentheses(node)
|
197
|
-
return unless node.parenthesized?
|
198
|
-
return if node.implicit_call?
|
199
|
-
return if super_call_without_arguments?(node)
|
200
|
-
return if allowed_camel_case_method_call?(node)
|
201
|
-
return if legitimate_call_with_parentheses?(node)
|
202
|
-
|
203
|
-
add_offense(node, location: node.loc.begin.join(node.loc.end))
|
204
|
-
end
|
205
|
-
|
206
|
-
def autocorrect_for_require_parentheses(node)
|
207
|
-
lambda do |corrector|
|
208
|
-
corrector.replace(args_begin(node), '(')
|
209
|
-
|
210
|
-
unless args_parenthesized?(node)
|
211
|
-
corrector.insert_after(args_end(node), ')')
|
212
|
-
end
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
216
|
-
def autocorrect_for_omit_parentheses(node)
|
217
|
-
lambda do |corrector|
|
218
|
-
if parentheses_at_the_end_of_multiline_call?(node)
|
219
|
-
corrector.replace(args_begin(node), ' \\')
|
220
|
-
else
|
221
|
-
corrector.replace(args_begin(node), ' ')
|
222
|
-
end
|
223
|
-
corrector.remove(node.loc.end)
|
224
|
-
end
|
225
|
-
end
|
226
|
-
|
227
|
-
def eligible_for_parentheses_omission?(node)
|
228
|
-
node.operator_method? || node.setter_method? || ignored_macro?(node)
|
229
|
-
end
|
230
|
-
|
231
|
-
def included_macros_list
|
232
|
-
cop_config.fetch('IncludedMacros', []).map(&:to_sym)
|
233
|
-
end
|
234
|
-
|
235
|
-
def ignored_macro?(node)
|
236
|
-
cop_config['IgnoreMacros'] &&
|
237
|
-
node.macro? &&
|
238
|
-
!included_macros_list.include?(node.method_name)
|
239
|
-
end
|
240
|
-
|
241
168
|
def args_begin(node)
|
242
169
|
loc = node.loc
|
243
170
|
selector =
|
@@ -257,132 +184,7 @@ module RuboCop
|
|
257
184
|
first_node = node.arguments.first
|
258
185
|
first_node.begin_type? && first_node.parenthesized_call?
|
259
186
|
end
|
260
|
-
|
261
|
-
def parentheses_at_the_end_of_multiline_call?(node)
|
262
|
-
node.multiline? &&
|
263
|
-
node.loc.begin.source_line
|
264
|
-
.gsub(TRAILING_WHITESPACE_REGEX, '')
|
265
|
-
.end_with?('(')
|
266
|
-
end
|
267
|
-
|
268
|
-
def super_call_without_arguments?(node)
|
269
|
-
node.super_type? && node.arguments.none?
|
270
|
-
end
|
271
|
-
|
272
|
-
def allowed_camel_case_method_call?(node)
|
273
|
-
node.camel_case_method? &&
|
274
|
-
(node.arguments.none? ||
|
275
|
-
cop_config['AllowParenthesesInCamelCaseMethod'])
|
276
|
-
end
|
277
|
-
|
278
|
-
def legitimate_call_with_parentheses?(node)
|
279
|
-
call_in_literals?(node) ||
|
280
|
-
call_with_ambiguous_arguments?(node) ||
|
281
|
-
call_in_logical_operators?(node) ||
|
282
|
-
call_in_optional_arguments?(node) ||
|
283
|
-
allowed_multiline_call_with_parentheses?(node) ||
|
284
|
-
allowed_chained_call_with_parentheses?(node)
|
285
|
-
end
|
286
|
-
|
287
|
-
def call_in_literals?(node)
|
288
|
-
node.parent &&
|
289
|
-
(node.parent.pair_type? ||
|
290
|
-
node.parent.array_type? ||
|
291
|
-
node.parent.range_type? ||
|
292
|
-
splat?(node.parent) ||
|
293
|
-
ternary_if?(node.parent))
|
294
|
-
end
|
295
|
-
|
296
|
-
def call_in_logical_operators?(node)
|
297
|
-
node.parent &&
|
298
|
-
(logical_operator?(node.parent) ||
|
299
|
-
node.parent.send_type? &&
|
300
|
-
node.parent.arguments.any?(&method(:logical_operator?)))
|
301
|
-
end
|
302
|
-
|
303
|
-
def call_in_optional_arguments?(node)
|
304
|
-
node.parent &&
|
305
|
-
(node.parent.optarg_type? || node.parent.kwoptarg_type?)
|
306
|
-
end
|
307
|
-
|
308
|
-
def call_with_ambiguous_arguments?(node)
|
309
|
-
call_with_braced_block?(node) ||
|
310
|
-
call_as_argument_or_chain?(node) ||
|
311
|
-
hash_literal_in_arguments?(node) ||
|
312
|
-
node.descendants.any? do |n|
|
313
|
-
ambigious_literal?(n) || logical_operator?(n) ||
|
314
|
-
call_with_braced_block?(n)
|
315
|
-
end
|
316
|
-
end
|
317
|
-
|
318
|
-
def call_with_braced_block?(node)
|
319
|
-
(node.send_type? || node.super_type?) &&
|
320
|
-
node.block_node && node.block_node.braces?
|
321
|
-
end
|
322
|
-
|
323
|
-
def call_as_argument_or_chain?(node)
|
324
|
-
node.parent &&
|
325
|
-
(node.parent.send_type? && !assigned_before?(node.parent, node) ||
|
326
|
-
node.parent.csend_type? || node.parent.super_type?)
|
327
|
-
end
|
328
|
-
|
329
|
-
def hash_literal_in_arguments?(node)
|
330
|
-
node.arguments.any? do |n|
|
331
|
-
hash_literal?(n) ||
|
332
|
-
n.send_type? && node.descendants.any?(&method(:hash_literal?))
|
333
|
-
end
|
334
|
-
end
|
335
|
-
|
336
|
-
def allowed_multiline_call_with_parentheses?(node)
|
337
|
-
cop_config['AllowParenthesesInMultilineCall'] && node.multiline?
|
338
|
-
end
|
339
|
-
|
340
|
-
def allowed_chained_call_with_parentheses?(node)
|
341
|
-
return false unless cop_config['AllowParenthesesInChaining']
|
342
|
-
|
343
|
-
previous = node.descendants.first
|
344
|
-
return false unless previous&.send_type?
|
345
|
-
|
346
|
-
previous.parenthesized? ||
|
347
|
-
allowed_chained_call_with_parentheses?(previous)
|
348
|
-
end
|
349
|
-
|
350
|
-
def ambigious_literal?(node)
|
351
|
-
splat?(node) || ternary_if?(node) || regexp_slash_literal?(node) ||
|
352
|
-
unary_literal?(node)
|
353
|
-
end
|
354
|
-
|
355
|
-
def splat?(node)
|
356
|
-
node.splat_type? || node.kwsplat_type? || node.block_pass_type?
|
357
|
-
end
|
358
|
-
|
359
|
-
def ternary_if?(node)
|
360
|
-
node.if_type? && node.ternary?
|
361
|
-
end
|
362
|
-
|
363
|
-
def logical_operator?(node)
|
364
|
-
(node.and_type? || node.or_type?) && node.logical_operator?
|
365
|
-
end
|
366
|
-
|
367
|
-
def hash_literal?(node)
|
368
|
-
node.hash_type? && node.braces?
|
369
|
-
end
|
370
|
-
|
371
|
-
def regexp_slash_literal?(node)
|
372
|
-
node.regexp_type? && node.loc.begin.source == '/'
|
373
|
-
end
|
374
|
-
|
375
|
-
def unary_literal?(node)
|
376
|
-
node.numeric_type? && node.sign? ||
|
377
|
-
node.parent&.send_type? && node.parent&.unary_operation?
|
378
|
-
end
|
379
|
-
|
380
|
-
def assigned_before?(node, target)
|
381
|
-
node.assignment? &&
|
382
|
-
node.loc.operator.begin < target.loc.begin
|
383
|
-
end
|
384
187
|
end
|
385
188
|
end
|
386
189
|
end
|
387
190
|
end
|
388
|
-
# rubocop:enable Metrics/ClassLength
|