rubocop 0.79.0 → 0.83.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 (225) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +5 -5
  4. data/config/default.yml +184 -50
  5. data/lib/rubocop.rb +15 -5
  6. data/lib/rubocop/ast/builder.rb +2 -0
  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/mixin/method_dispatch_node.rb +8 -0
  12. data/lib/rubocop/ast/node/regexp_node.rb +2 -4
  13. data/lib/rubocop/ast/node/send_node.rb +4 -0
  14. data/lib/rubocop/ast/traversal.rb +20 -9
  15. data/lib/rubocop/cli.rb +11 -5
  16. data/lib/rubocop/comment_config.rb +6 -1
  17. data/lib/rubocop/config.rb +40 -10
  18. data/lib/rubocop/config_loader.rb +43 -33
  19. data/lib/rubocop/config_loader_resolver.rb +28 -1
  20. data/lib/rubocop/config_obsoletion.rb +4 -1
  21. data/lib/rubocop/config_validator.rb +18 -1
  22. data/lib/rubocop/cop/badge.rb +5 -5
  23. data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +1 -1
  24. data/lib/rubocop/cop/corrector.rb +48 -24
  25. data/lib/rubocop/cop/correctors/alignment_corrector.rb +2 -2
  26. data/lib/rubocop/cop/correctors/condition_corrector.rb +1 -2
  27. data/lib/rubocop/cop/correctors/empty_line_corrector.rb +1 -1
  28. data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +3 -3
  29. data/lib/rubocop/cop/correctors/line_break_corrector.rb +2 -2
  30. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +1 -1
  31. data/lib/rubocop/cop/correctors/string_literal_corrector.rb +2 -2
  32. data/lib/rubocop/cop/generator.rb +3 -2
  33. data/lib/rubocop/cop/internal_affairs/offense_location_keyword.rb +1 -1
  34. data/lib/rubocop/cop/layout/array_alignment.rb +53 -10
  35. data/lib/rubocop/cop/layout/block_end_newline.rb +5 -3
  36. data/lib/rubocop/cop/layout/condition_position.rb +12 -2
  37. data/lib/rubocop/cop/layout/dot_position.rb +1 -1
  38. data/lib/rubocop/cop/layout/else_alignment.rb +8 -0
  39. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +2 -1
  40. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +68 -0
  41. data/lib/rubocop/cop/layout/end_of_line.rb +2 -2
  42. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +16 -10
  43. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +1 -1
  44. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
  45. data/lib/rubocop/cop/layout/heredoc_indentation.rb +2 -2
  46. data/lib/rubocop/cop/layout/{tab.rb → indentation_style.rb} +48 -6
  47. data/lib/rubocop/cop/layout/leading_comment_space.rb +34 -3
  48. data/lib/rubocop/cop/layout/line_length.rb +36 -4
  49. data/lib/rubocop/cop/layout/multiline_block_layout.rb +1 -1
  50. data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +0 -4
  51. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +1 -1
  52. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +13 -4
  53. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +3 -3
  54. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +133 -0
  55. data/lib/rubocop/cop/layout/space_around_operators.rb +37 -2
  56. data/lib/rubocop/cop/layout/space_before_first_arg.rb +8 -0
  57. data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +1 -1
  58. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +2 -2
  59. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +2 -9
  60. data/lib/rubocop/cop/layout/space_inside_range_literal.rb +2 -2
  61. data/lib/rubocop/cop/layout/trailing_whitespace.rb +2 -2
  62. data/lib/rubocop/cop/lint/ambiguous_operator.rb +38 -0
  63. data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +14 -0
  64. data/lib/rubocop/cop/lint/boolean_symbol.rb +12 -0
  65. data/lib/rubocop/cop/lint/debugger.rb +2 -2
  66. data/lib/rubocop/cop/lint/duplicate_methods.rb +1 -5
  67. data/lib/rubocop/cop/lint/empty_when.rb +29 -6
  68. data/lib/rubocop/cop/lint/ensure_return.rb +18 -1
  69. data/lib/rubocop/cop/lint/erb_new_arguments.rb +1 -1
  70. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +1 -1
  71. data/lib/rubocop/cop/lint/inherit_exception.rb +1 -1
  72. data/lib/rubocop/cop/lint/interpolation_check.rb +1 -1
  73. data/lib/rubocop/cop/lint/literal_as_condition.rb +10 -13
  74. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
  75. data/lib/rubocop/cop/lint/loop.rb +6 -4
  76. data/lib/rubocop/cop/lint/multiple_comparison.rb +1 -1
  77. data/lib/rubocop/cop/lint/nested_method_definition.rb +2 -2
  78. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +2 -2
  79. data/lib/rubocop/cop/lint/number_conversion.rb +1 -1
  80. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +21 -9
  81. data/lib/rubocop/cop/lint/percent_string_array.rb +2 -2
  82. data/lib/rubocop/cop/lint/raise_exception.rb +75 -0
  83. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +1 -6
  84. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +12 -7
  85. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +1 -1
  86. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +1 -1
  87. data/lib/rubocop/cop/lint/struct_new_override.rb +58 -0
  88. data/lib/rubocop/cop/lint/suppressed_exception.rb +12 -28
  89. data/lib/rubocop/cop/lint/unified_integer.rb +0 -2
  90. data/lib/rubocop/cop/lint/unused_method_argument.rb +32 -6
  91. data/lib/rubocop/cop/lint/uri_regexp.rb +4 -4
  92. data/lib/rubocop/cop/lint/useless_access_modifier.rb +12 -0
  93. data/lib/rubocop/cop/lint/useless_assignment.rb +3 -2
  94. data/lib/rubocop/cop/lint/useless_else_without_rescue.rb +5 -0
  95. data/lib/rubocop/cop/lint/useless_setter_call.rb +4 -0
  96. data/lib/rubocop/cop/migration/department_name.rb +36 -10
  97. data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +4 -0
  98. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +6 -1
  99. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +16 -1
  100. data/lib/rubocop/cop/mixin/hash_transform_method.rb +178 -0
  101. data/lib/rubocop/cop/mixin/line_length_help.rb +2 -1
  102. data/lib/rubocop/cop/mixin/method_complexity.rb +5 -0
  103. data/lib/rubocop/cop/mixin/parser_diagnostic.rb +1 -1
  104. data/lib/rubocop/cop/mixin/statement_modifier.rb +7 -22
  105. data/lib/rubocop/cop/mixin/target_ruby_version.rb +5 -1
  106. data/lib/rubocop/cop/mixin/trailing_comma.rb +3 -10
  107. data/lib/rubocop/cop/naming/class_and_module_camel_case.rb +1 -1
  108. data/lib/rubocop/cop/naming/constant_name.rb +2 -1
  109. data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +1 -1
  110. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
  111. data/lib/rubocop/cop/naming/method_name.rb +26 -0
  112. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +1 -1
  113. data/lib/rubocop/cop/registry.rb +11 -4
  114. data/lib/rubocop/cop/style/access_modifier_declarations.rb +26 -6
  115. data/lib/rubocop/cop/style/alias.rb +4 -4
  116. data/lib/rubocop/cop/style/and_or.rb +5 -6
  117. data/lib/rubocop/cop/style/array_join.rb +1 -1
  118. data/lib/rubocop/cop/style/block_delimiters.rb +60 -1
  119. data/lib/rubocop/cop/style/case_equality.rb +24 -1
  120. data/lib/rubocop/cop/style/character_literal.rb +2 -2
  121. data/lib/rubocop/cop/style/collection_methods.rb +2 -0
  122. data/lib/rubocop/cop/style/conditional_assignment.rb +8 -8
  123. data/lib/rubocop/cop/style/copyright.rb +1 -1
  124. data/lib/rubocop/cop/style/dir.rb +1 -1
  125. data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +49 -0
  126. data/lib/rubocop/cop/style/documentation.rb +43 -5
  127. data/lib/rubocop/cop/style/double_cop_disable_directive.rb +1 -1
  128. data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
  129. data/lib/rubocop/cop/style/each_with_object.rb +3 -3
  130. data/lib/rubocop/cop/style/empty_method.rb +1 -5
  131. data/lib/rubocop/cop/style/end_block.rb +6 -0
  132. data/lib/rubocop/cop/style/even_odd.rb +1 -1
  133. data/lib/rubocop/cop/style/expand_path_arguments.rb +3 -3
  134. data/lib/rubocop/cop/style/exponential_notation.rb +119 -0
  135. data/lib/rubocop/cop/style/format_string.rb +2 -2
  136. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +89 -11
  137. data/lib/rubocop/cop/style/guard_clause.rb +25 -2
  138. data/lib/rubocop/cop/style/hash_each_methods.rb +89 -0
  139. data/lib/rubocop/cop/style/hash_syntax.rb +3 -5
  140. data/lib/rubocop/cop/style/hash_transform_keys.rb +83 -0
  141. data/lib/rubocop/cop/style/hash_transform_values.rb +80 -0
  142. data/lib/rubocop/cop/style/if_unless_modifier.rb +23 -3
  143. data/lib/rubocop/cop/style/if_with_semicolon.rb +16 -0
  144. data/lib/rubocop/cop/style/inverse_methods.rb +9 -5
  145. data/lib/rubocop/cop/style/lambda.rb +3 -2
  146. data/lib/rubocop/cop/style/lambda_call.rb +1 -21
  147. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +5 -0
  148. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +5 -4
  149. data/lib/rubocop/cop/style/mixin_grouping.rb +1 -1
  150. data/lib/rubocop/cop/style/module_function.rb +58 -12
  151. data/lib/rubocop/cop/style/multiline_if_modifier.rb +1 -1
  152. data/lib/rubocop/cop/style/multiline_memoization.rb +1 -1
  153. data/lib/rubocop/cop/style/multiline_when_then.rb +16 -1
  154. data/lib/rubocop/cop/style/mutable_constant.rb +2 -4
  155. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +4 -4
  156. data/lib/rubocop/cop/style/next.rb +2 -2
  157. data/lib/rubocop/cop/style/nil_comparison.rb +1 -1
  158. data/lib/rubocop/cop/style/non_nil_check.rb +4 -4
  159. data/lib/rubocop/cop/style/not.rb +1 -1
  160. data/lib/rubocop/cop/style/numeric_literal_prefix.rb +1 -1
  161. data/lib/rubocop/cop/style/numeric_literals.rb +1 -1
  162. data/lib/rubocop/cop/style/numeric_predicate.rb +1 -1
  163. data/lib/rubocop/cop/style/one_line_conditional.rb +4 -3
  164. data/lib/rubocop/cop/style/optional_arguments.rb +1 -1
  165. data/lib/rubocop/cop/style/or_assignment.rb +4 -3
  166. data/lib/rubocop/cop/style/percent_q_literals.rb +1 -1
  167. data/lib/rubocop/cop/style/perl_backrefs.rb +2 -2
  168. data/lib/rubocop/cop/style/proc.rb +1 -1
  169. data/lib/rubocop/cop/style/raise_args.rb +1 -1
  170. data/lib/rubocop/cop/style/random_with_offset.rb +3 -3
  171. data/lib/rubocop/cop/style/redundant_condition.rb +18 -6
  172. data/lib/rubocop/cop/style/redundant_conditional.rb +1 -1
  173. data/lib/rubocop/cop/style/redundant_exception.rb +3 -3
  174. data/lib/rubocop/cop/style/redundant_interpolation.rb +2 -2
  175. data/lib/rubocop/cop/style/redundant_percent_q.rb +2 -2
  176. data/lib/rubocop/cop/style/redundant_return.rb +5 -7
  177. data/lib/rubocop/cop/style/redundant_self.rb +1 -1
  178. data/lib/rubocop/cop/style/redundant_sort.rb +2 -2
  179. data/lib/rubocop/cop/style/rescue_modifier.rb +1 -1
  180. data/lib/rubocop/cop/style/return_nil.rb +1 -1
  181. data/lib/rubocop/cop/style/safe_navigation.rb +1 -1
  182. data/lib/rubocop/cop/style/self_assignment.rb +1 -1
  183. data/lib/rubocop/cop/style/slicing_with_range.rb +39 -0
  184. data/lib/rubocop/cop/style/special_global_vars.rb +1 -1
  185. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +1 -4
  186. data/lib/rubocop/cop/style/string_hash_keys.rb +1 -1
  187. data/lib/rubocop/cop/style/symbol_array.rb +3 -3
  188. data/lib/rubocop/cop/style/symbol_literal.rb +2 -2
  189. data/lib/rubocop/cop/style/ternary_parentheses.rb +2 -3
  190. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +35 -22
  191. data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +41 -0
  192. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +88 -0
  193. data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +44 -0
  194. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  195. data/lib/rubocop/cop/style/unpack_first.rb +0 -4
  196. data/lib/rubocop/cop/style/variable_interpolation.rb +1 -1
  197. data/lib/rubocop/cop/style/while_until_modifier.rb +1 -1
  198. data/lib/rubocop/cop/style/word_array.rb +1 -1
  199. data/lib/rubocop/cop/style/zero_length_predicate.rb +1 -1
  200. data/lib/rubocop/cop/util.rb +24 -0
  201. data/lib/rubocop/cop/variable_force.rb +4 -1
  202. data/lib/rubocop/cop/variable_force/assignment.rb +1 -0
  203. data/lib/rubocop/cop/variable_force/scope.rb +1 -0
  204. data/lib/rubocop/cop/variable_force/variable.rb +1 -0
  205. data/lib/rubocop/formatter/clang_style_formatter.rb +1 -1
  206. data/lib/rubocop/formatter/formatter_set.rb +1 -1
  207. data/lib/rubocop/formatter/junit_formatter.rb +74 -0
  208. data/lib/rubocop/formatter/pacman_formatter.rb +1 -1
  209. data/lib/rubocop/formatter/tap_formatter.rb +1 -1
  210. data/lib/rubocop/name_similarity.rb +12 -9
  211. data/lib/rubocop/node_pattern.rb +96 -10
  212. data/lib/rubocop/options.rb +18 -5
  213. data/lib/rubocop/processed_source.rb +1 -4
  214. data/lib/rubocop/rspec/cop_helper.rb +1 -1
  215. data/lib/rubocop/rspec/expect_offense.rb +1 -1
  216. data/lib/rubocop/rspec/shared_contexts.rb +0 -4
  217. data/lib/rubocop/runner.rb +7 -2
  218. data/lib/rubocop/target_finder.rb +6 -4
  219. data/lib/rubocop/target_ruby.rb +2 -2
  220. data/lib/rubocop/version.rb +1 -1
  221. metadata +35 -25
  222. data/lib/rubocop/cop/lint/end_in_method.rb +0 -40
  223. data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +0 -209
  224. data/lib/rubocop/formatter/disabled_lines_formatter.rb +0 -57
  225. data/lib/rubocop/string_util.rb +0 -14
@@ -104,7 +104,7 @@ module RuboCop
104
104
 
105
105
  corrected = "#{style}(#{node.receiver.source}, #{args})"
106
106
 
107
- corrector.replace(node.loc.expression, corrected)
107
+ corrector.replace(node, corrected)
108
108
  end
109
109
 
110
110
  def autocorrect_to_percent(corrector, node)
@@ -119,7 +119,7 @@ module RuboCop
119
119
  "[#{param_args.map(&:source).join(', ')}]"
120
120
  end
121
121
 
122
- corrector.replace(node.loc.expression, "#{format} % #{args}")
122
+ corrector.replace(node, "#{format} % #{args}")
123
123
  end
124
124
  end
125
125
  end
@@ -51,29 +51,65 @@ module RuboCop
51
51
  # module Baz
52
52
  # # ...
53
53
  # end
54
+ #
55
+ # @example EnforcedStyle: always_true
56
+ # # The `always_true` style enforces that the frozen string literal
57
+ # # comment is set to `true`. This is a stricter option than `always`
58
+ # # and forces projects to use frozen string literals.
59
+ # # bad
60
+ # # frozen_string_literal: false
61
+ #
62
+ # module Baz
63
+ # # ...
64
+ # end
65
+ #
66
+ # # bad
67
+ # module Baz
68
+ # # ...
69
+ # end
70
+ #
71
+ # # good
72
+ # # frozen_string_literal: true
73
+ #
74
+ # module Bar
75
+ # # ...
76
+ # end
54
77
  class FrozenStringLiteralComment < Cop
55
78
  include ConfigurableEnforcedStyle
56
79
  include FrozenStringLiteral
57
80
  include RangeHelp
58
81
 
59
- MSG = 'Missing magic comment `# frozen_string_literal: true`.'
82
+ MSG_MISSING_TRUE = 'Missing magic comment `# frozen_string_literal: '\
83
+ 'true`.'
84
+ MSG_MISSING = 'Missing frozen string literal comment.'
60
85
  MSG_UNNECESSARY = 'Unnecessary frozen string literal comment.'
86
+ MSG_DISABLED = 'Frozen string literal comment must be set to `true`.'
61
87
  SHEBANG = '#!'
62
88
 
63
89
  def investigate(processed_source)
64
90
  return if processed_source.tokens.empty?
65
91
 
66
- if frozen_string_literal_comment_exists?
67
- check_for_no_comment(processed_source)
92
+ case style
93
+ when :never
94
+ ensure_no_comment(processed_source)
95
+ when :always_true
96
+ ensure_enabled_comment(processed_source)
68
97
  else
69
- check_for_comment(processed_source)
98
+ ensure_comment(processed_source)
70
99
  end
71
100
  end
72
101
 
73
102
  def autocorrect(node)
74
103
  lambda do |corrector|
75
- if style == :never
104
+ case style
105
+ when :never
76
106
  remove_comment(corrector, node)
107
+ when :always_true
108
+ if frozen_string_literal_specified?
109
+ enable_comment(corrector)
110
+ else
111
+ insert_comment(corrector)
112
+ end
77
113
  else
78
114
  insert_comment(corrector)
79
115
  end
@@ -82,12 +118,27 @@ module RuboCop
82
118
 
83
119
  private
84
120
 
85
- def check_for_no_comment(processed_source)
86
- unnecessary_comment_offense(processed_source) if style == :never
121
+ def ensure_no_comment(processed_source)
122
+ return unless frozen_string_literal_comment_exists?
123
+
124
+ unnecessary_comment_offense(processed_source)
87
125
  end
88
126
 
89
- def check_for_comment(processed_source)
90
- offense(processed_source) unless style == :never
127
+ def ensure_comment(processed_source)
128
+ return if frozen_string_literal_comment_exists?
129
+
130
+ missing_offense(processed_source)
131
+ end
132
+
133
+ def ensure_enabled_comment(processed_source)
134
+ if frozen_string_literal_specified?
135
+ return if frozen_string_literals_enabled?
136
+
137
+ # The comment exists, but is not enabled.
138
+ disabled_offense(processed_source)
139
+ else # The comment doesn't exist at all.
140
+ missing_true_offense(processed_source)
141
+ end
91
142
  end
92
143
 
93
144
  def last_special_comment(processed_source)
@@ -111,11 +162,22 @@ module RuboCop
111
162
  end
112
163
  end
113
164
 
114
- def offense(processed_source)
165
+ def missing_offense(processed_source)
166
+ last_special_comment = last_special_comment(processed_source)
167
+ range = source_range(processed_source.buffer, 0, 0)
168
+
169
+ add_offense(last_special_comment,
170
+ location: range,
171
+ message: MSG_MISSING)
172
+ end
173
+
174
+ def missing_true_offense(processed_source)
115
175
  last_special_comment = last_special_comment(processed_source)
116
176
  range = source_range(processed_source.buffer, 0, 0)
117
177
 
118
- add_offense(last_special_comment, location: range)
178
+ add_offense(last_special_comment,
179
+ location: range,
180
+ message: MSG_MISSING_TRUE)
119
181
  end
120
182
 
121
183
  def unnecessary_comment_offense(processed_source)
@@ -127,11 +189,27 @@ module RuboCop
127
189
  message: MSG_UNNECESSARY)
128
190
  end
129
191
 
192
+ def disabled_offense(processed_source)
193
+ frozen_string_literal_comment =
194
+ frozen_string_literal_comment(processed_source)
195
+
196
+ add_offense(frozen_string_literal_comment,
197
+ location: frozen_string_literal_comment.pos,
198
+ message: MSG_DISABLED)
199
+ end
200
+
130
201
  def remove_comment(corrector, node)
131
202
  corrector.remove(range_with_surrounding_space(range: node.pos,
132
203
  side: :right))
133
204
  end
134
205
 
206
+ def enable_comment(corrector)
207
+ comment = frozen_string_literal_comment(processed_source)
208
+
209
+ corrector.replace(line_range(comment.line),
210
+ FROZEN_STRING_LITERAL_ENABLED)
211
+ end
212
+
135
213
  def insert_comment(corrector)
136
214
  comment = last_special_comment(processed_source)
137
215
 
@@ -35,6 +35,17 @@ module RuboCop
35
35
  # # good
36
36
  # raise 'exception' if something
37
37
  # ok
38
+ #
39
+ # # bad
40
+ # if something
41
+ # foo || raise('exception')
42
+ # else
43
+ # ok
44
+ # end
45
+ #
46
+ # # good
47
+ # foo || raise('exception') if something
48
+ # ok
38
49
  class GuardClause < Cop
39
50
  include MinBodyLength
40
51
  include StatementModifier
@@ -69,7 +80,8 @@ module RuboCop
69
80
  else
70
81
  opposite_keyword(node)
71
82
  end
72
- register_offense(node, guard_clause.source, kw)
83
+
84
+ register_offense(node, guard_clause_source(guard_clause), kw)
73
85
  end
74
86
 
75
87
  private
@@ -98,13 +110,24 @@ module RuboCop
98
110
  message: format(MSG, example: example))
99
111
  end
100
112
 
113
+ def guard_clause_source(guard_clause)
114
+ parent = guard_clause.parent
115
+
116
+ if parent.and_type? || parent.or_type?
117
+ guard_clause.parent.source
118
+ else
119
+ guard_clause.source
120
+ end
121
+ end
122
+
101
123
  def too_long_for_single_line?(node, example)
102
124
  max = max_line_length
103
125
  max && node.source_range.column + example.length > max
104
126
  end
105
127
 
106
128
  def accepted_form?(node, ending = false)
107
- accepted_if?(node, ending) || node.condition.multiline?
129
+ accepted_if?(node, ending) || node.condition.multiline? ||
130
+ node.parent&.assignment?
108
131
  end
109
132
 
110
133
  def accepted_if?(node, ending)
@@ -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