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.
Files changed (209) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +4 -4
  4. data/config/default.yml +158 -48
  5. data/lib/rubocop.rb +19 -4
  6. data/lib/rubocop/ast/builder.rb +45 -42
  7. data/lib/rubocop/ast/node.rb +12 -19
  8. data/lib/rubocop/ast/node/array_node.rb +13 -0
  9. data/lib/rubocop/ast/node/block_node.rb +5 -1
  10. data/lib/rubocop/ast/node/case_match_node.rb +56 -0
  11. data/lib/rubocop/ast/node/def_node.rb +11 -0
  12. data/lib/rubocop/ast/node/forward_args_node.rb +18 -0
  13. data/lib/rubocop/ast/node/mixin/method_dispatch_node.rb +8 -0
  14. data/lib/rubocop/ast/node/regexp_node.rb +2 -4
  15. data/lib/rubocop/ast/traversal.rb +29 -10
  16. data/lib/rubocop/cli.rb +10 -4
  17. data/lib/rubocop/cli/command/show_cops.rb +11 -4
  18. data/lib/rubocop/comment_config.rb +6 -1
  19. data/lib/rubocop/config.rb +36 -10
  20. data/lib/rubocop/config_loader.rb +42 -33
  21. data/lib/rubocop/config_loader_resolver.rb +1 -1
  22. data/lib/rubocop/config_obsoletion.rb +4 -1
  23. data/lib/rubocop/config_validator.rb +66 -92
  24. data/lib/rubocop/cop/autocorrect_logic.rb +6 -3
  25. data/lib/rubocop/cop/badge.rb +5 -5
  26. data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +1 -1
  27. data/lib/rubocop/cop/corrector.rb +48 -24
  28. data/lib/rubocop/cop/correctors/alignment_corrector.rb +2 -2
  29. data/lib/rubocop/cop/correctors/condition_corrector.rb +1 -2
  30. data/lib/rubocop/cop/correctors/empty_line_corrector.rb +1 -1
  31. data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +3 -3
  32. data/lib/rubocop/cop/correctors/line_break_corrector.rb +2 -2
  33. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +1 -1
  34. data/lib/rubocop/cop/correctors/string_literal_corrector.rb +2 -2
  35. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -1
  36. data/lib/rubocop/cop/generator.rb +3 -4
  37. data/lib/rubocop/cop/generator/configuration_injector.rb +1 -1
  38. data/lib/rubocop/cop/internal_affairs/offense_location_keyword.rb +1 -1
  39. data/lib/rubocop/cop/layout/array_alignment.rb +53 -10
  40. data/lib/rubocop/cop/layout/block_end_newline.rb +5 -3
  41. data/lib/rubocop/cop/layout/dot_position.rb +1 -1
  42. data/lib/rubocop/cop/layout/else_alignment.rb +8 -0
  43. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +2 -1
  44. data/lib/rubocop/cop/layout/end_of_line.rb +2 -2
  45. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +16 -10
  46. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +1 -1
  47. data/lib/rubocop/cop/layout/hash_alignment.rb +8 -4
  48. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
  49. data/lib/rubocop/cop/layout/heredoc_indentation.rb +2 -2
  50. data/lib/rubocop/cop/layout/{tab.rb → indentation_style.rb} +48 -6
  51. data/lib/rubocop/cop/layout/leading_comment_space.rb +34 -3
  52. data/lib/rubocop/cop/layout/line_length.rb +32 -3
  53. data/lib/rubocop/cop/layout/multiline_block_layout.rb +15 -6
  54. data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +0 -4
  55. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +1 -1
  56. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +3 -3
  57. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +133 -0
  58. data/lib/rubocop/cop/layout/space_around_operators.rb +19 -1
  59. data/lib/rubocop/cop/layout/space_before_block_braces.rb +2 -2
  60. data/lib/rubocop/cop/layout/space_before_first_arg.rb +8 -0
  61. data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +1 -1
  62. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +2 -2
  63. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +2 -9
  64. data/lib/rubocop/cop/layout/space_inside_range_literal.rb +2 -2
  65. data/lib/rubocop/cop/lint/boolean_symbol.rb +12 -0
  66. data/lib/rubocop/cop/lint/debugger.rb +2 -2
  67. data/lib/rubocop/cop/lint/erb_new_arguments.rb +1 -1
  68. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +1 -1
  69. data/lib/rubocop/cop/lint/inherit_exception.rb +1 -1
  70. data/lib/rubocop/cop/lint/interpolation_check.rb +1 -1
  71. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
  72. data/lib/rubocop/cop/lint/loop.rb +6 -4
  73. data/lib/rubocop/cop/lint/multiple_comparison.rb +1 -1
  74. data/lib/rubocop/cop/lint/nested_method_definition.rb +2 -2
  75. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +2 -2
  76. data/lib/rubocop/cop/lint/number_conversion.rb +1 -1
  77. data/lib/rubocop/cop/lint/percent_string_array.rb +2 -2
  78. data/lib/rubocop/cop/lint/raise_exception.rb +75 -0
  79. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +1 -1
  80. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +12 -7
  81. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +1 -1
  82. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +1 -1
  83. data/lib/rubocop/cop/lint/struct_new_override.rb +58 -0
  84. data/lib/rubocop/cop/lint/suppressed_exception.rb +12 -22
  85. data/lib/rubocop/cop/lint/unified_integer.rb +0 -2
  86. data/lib/rubocop/cop/lint/unused_method_argument.rb +32 -6
  87. data/lib/rubocop/cop/lint/uri_regexp.rb +4 -4
  88. data/lib/rubocop/cop/lint/useless_setter_call.rb +4 -0
  89. data/lib/rubocop/cop/migration/department_name.rb +47 -6
  90. data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +4 -0
  91. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +6 -1
  92. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +7 -7
  93. data/lib/rubocop/cop/mixin/hash_transform_method.rb +171 -0
  94. data/lib/rubocop/cop/mixin/line_length_help.rb +1 -1
  95. data/lib/rubocop/cop/mixin/method_complexity.rb +5 -0
  96. data/lib/rubocop/cop/mixin/statement_modifier.rb +4 -3
  97. data/lib/rubocop/cop/mixin/trailing_comma.rb +3 -10
  98. data/lib/rubocop/cop/naming/class_and_module_camel_case.rb +1 -1
  99. data/lib/rubocop/cop/naming/constant_name.rb +2 -1
  100. data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +1 -1
  101. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
  102. data/lib/rubocop/cop/naming/method_name.rb +30 -0
  103. data/lib/rubocop/cop/naming/method_parameter_name.rb +1 -1
  104. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +1 -1
  105. data/lib/rubocop/cop/registry.rb +15 -3
  106. data/lib/rubocop/cop/style/access_modifier_declarations.rb +26 -6
  107. data/lib/rubocop/cop/style/alias.rb +4 -4
  108. data/lib/rubocop/cop/style/and_or.rb +5 -6
  109. data/lib/rubocop/cop/style/array_join.rb +1 -1
  110. data/lib/rubocop/cop/style/block_delimiters.rb +60 -1
  111. data/lib/rubocop/cop/style/case_equality.rb +24 -1
  112. data/lib/rubocop/cop/style/character_literal.rb +2 -2
  113. data/lib/rubocop/cop/style/collection_methods.rb +2 -0
  114. data/lib/rubocop/cop/style/conditional_assignment.rb +8 -8
  115. data/lib/rubocop/cop/style/copyright.rb +1 -1
  116. data/lib/rubocop/cop/style/dir.rb +1 -1
  117. data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +49 -0
  118. data/lib/rubocop/cop/style/documentation.rb +43 -5
  119. data/lib/rubocop/cop/style/double_cop_disable_directive.rb +1 -1
  120. data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
  121. data/lib/rubocop/cop/style/each_with_object.rb +3 -3
  122. data/lib/rubocop/cop/style/empty_method.rb +1 -1
  123. data/lib/rubocop/cop/style/end_block.rb +6 -0
  124. data/lib/rubocop/cop/style/even_odd.rb +1 -1
  125. data/lib/rubocop/cop/style/expand_path_arguments.rb +3 -3
  126. data/lib/rubocop/cop/style/exponential_notation.rb +119 -0
  127. data/lib/rubocop/cop/style/format_string.rb +2 -2
  128. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +89 -11
  129. data/lib/rubocop/cop/style/hash_each_methods.rb +89 -0
  130. data/lib/rubocop/cop/style/hash_syntax.rb +3 -5
  131. data/lib/rubocop/cop/style/hash_transform_keys.rb +83 -0
  132. data/lib/rubocop/cop/style/hash_transform_values.rb +80 -0
  133. data/lib/rubocop/cop/style/if_unless_modifier.rb +23 -3
  134. data/lib/rubocop/cop/style/inverse_methods.rb +9 -5
  135. data/lib/rubocop/cop/style/lambda.rb +3 -2
  136. data/lib/rubocop/cop/style/lambda_call.rb +2 -2
  137. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +7 -205
  138. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +169 -0
  139. data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +54 -0
  140. data/lib/rubocop/cop/style/mixin_grouping.rb +1 -1
  141. data/lib/rubocop/cop/style/module_function.rb +58 -12
  142. data/lib/rubocop/cop/style/multiline_if_modifier.rb +1 -1
  143. data/lib/rubocop/cop/style/multiline_memoization.rb +1 -1
  144. data/lib/rubocop/cop/style/multiline_when_then.rb +5 -1
  145. data/lib/rubocop/cop/style/mutable_constant.rb +2 -4
  146. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +4 -4
  147. data/lib/rubocop/cop/style/next.rb +2 -2
  148. data/lib/rubocop/cop/style/nil_comparison.rb +1 -1
  149. data/lib/rubocop/cop/style/non_nil_check.rb +4 -4
  150. data/lib/rubocop/cop/style/not.rb +1 -1
  151. data/lib/rubocop/cop/style/numeric_literal_prefix.rb +1 -1
  152. data/lib/rubocop/cop/style/numeric_literals.rb +1 -1
  153. data/lib/rubocop/cop/style/numeric_predicate.rb +5 -4
  154. data/lib/rubocop/cop/style/one_line_conditional.rb +4 -3
  155. data/lib/rubocop/cop/style/or_assignment.rb +4 -3
  156. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +7 -7
  157. data/lib/rubocop/cop/style/percent_q_literals.rb +1 -1
  158. data/lib/rubocop/cop/style/perl_backrefs.rb +2 -2
  159. data/lib/rubocop/cop/style/proc.rb +1 -1
  160. data/lib/rubocop/cop/style/raise_args.rb +1 -1
  161. data/lib/rubocop/cop/style/random_with_offset.rb +3 -3
  162. data/lib/rubocop/cop/style/redundant_condition.rb +18 -6
  163. data/lib/rubocop/cop/style/redundant_conditional.rb +1 -1
  164. data/lib/rubocop/cop/style/redundant_exception.rb +3 -3
  165. data/lib/rubocop/cop/style/redundant_interpolation.rb +2 -2
  166. data/lib/rubocop/cop/style/redundant_percent_q.rb +2 -2
  167. data/lib/rubocop/cop/style/redundant_return.rb +5 -7
  168. data/lib/rubocop/cop/style/redundant_self.rb +1 -1
  169. data/lib/rubocop/cop/style/redundant_sort.rb +2 -2
  170. data/lib/rubocop/cop/style/rescue_modifier.rb +1 -1
  171. data/lib/rubocop/cop/style/return_nil.rb +1 -1
  172. data/lib/rubocop/cop/style/safe_navigation.rb +1 -1
  173. data/lib/rubocop/cop/style/self_assignment.rb +1 -1
  174. data/lib/rubocop/cop/style/special_global_vars.rb +1 -1
  175. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +1 -4
  176. data/lib/rubocop/cop/style/string_hash_keys.rb +1 -1
  177. data/lib/rubocop/cop/style/symbol_array.rb +3 -3
  178. data/lib/rubocop/cop/style/symbol_literal.rb +2 -2
  179. data/lib/rubocop/cop/style/ternary_parentheses.rb +2 -3
  180. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +35 -22
  181. data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +41 -0
  182. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +88 -0
  183. data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +44 -0
  184. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  185. data/lib/rubocop/cop/style/unpack_first.rb +0 -4
  186. data/lib/rubocop/cop/style/variable_interpolation.rb +1 -1
  187. data/lib/rubocop/cop/style/while_until_modifier.rb +1 -1
  188. data/lib/rubocop/cop/style/word_array.rb +1 -1
  189. data/lib/rubocop/cop/style/yoda_condition.rb +16 -1
  190. data/lib/rubocop/cop/style/zero_length_predicate.rb +1 -1
  191. data/lib/rubocop/cop/variable_force.rb +4 -1
  192. data/lib/rubocop/formatter/clang_style_formatter.rb +1 -1
  193. data/lib/rubocop/formatter/formatter_set.rb +1 -1
  194. data/lib/rubocop/formatter/junit_formatter.rb +74 -0
  195. data/lib/rubocop/formatter/pacman_formatter.rb +1 -1
  196. data/lib/rubocop/formatter/tap_formatter.rb +1 -1
  197. data/lib/rubocop/node_pattern.rb +96 -10
  198. data/lib/rubocop/options.rb +7 -1
  199. data/lib/rubocop/processed_source.rb +1 -4
  200. data/lib/rubocop/rspec/cop_helper.rb +1 -1
  201. data/lib/rubocop/rspec/expect_offense.rb +1 -1
  202. data/lib/rubocop/rspec/shared_contexts.rb +5 -4
  203. data/lib/rubocop/runner.rb +1 -1
  204. data/lib/rubocop/target_ruby.rb +151 -0
  205. data/lib/rubocop/version.rb +1 -1
  206. metadata +39 -12
  207. data/lib/rubocop/cop/lint/end_in_method.rb +0 -40
  208. data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +0 -209
  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 sym_name =~ /[\p{Alnum}"']\z/
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 sym_name =~ /\A[_a-z]\w*[?!]?\z/i
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.insert_after(key, pair_node.inverse_delimiter(true))
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/Tab` cop.
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 node.modifier_form? && too_long_single_line?(node)
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.source_range, replacement) }
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.source_range, '->')
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.source_range, arg_str)
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.source_range, replacement)
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.source_range, '()')
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
- TRAILING_WHITESPACE_REGEX = /\s+\Z/.freeze
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
- add_offense_for_require_parentheses(node)
157
+ extend RequireParentheses
159
158
  when :omit_parentheses
160
- add_offense_for_omit_parentheses(node)
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
- def autocorrect(node)
168
- case style
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