rubocop 0.47.1 → 0.48.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.

Potentially problematic release.


This version of rubocop might be problematic. Click here for more details.

Files changed (242) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +28 -16
  3. data/config/default.yml +203 -115
  4. data/config/disabled.yml +0 -5
  5. data/config/enabled.yml +92 -8
  6. data/lib/rubocop.rb +24 -1
  7. data/lib/rubocop/ast/builder.rb +7 -2
  8. data/lib/rubocop/ast/node.rb +23 -20
  9. data/lib/rubocop/ast/node/and_node.rb +37 -0
  10. data/lib/rubocop/ast/node/array_node.rb +4 -1
  11. data/lib/rubocop/ast/node/case_node.rb +1 -0
  12. data/lib/rubocop/ast/node/ensure_node.rb +25 -0
  13. data/lib/rubocop/ast/node/hash_node.rb +10 -3
  14. data/lib/rubocop/ast/node/if_node.rb +2 -0
  15. data/lib/rubocop/ast/node/mixin/binary_operator_node.rb +23 -0
  16. data/lib/rubocop/ast/node/mixin/predicate_operator_node.rb +35 -0
  17. data/lib/rubocop/ast/node/or_node.rb +37 -0
  18. data/lib/rubocop/ast/node/resbody_node.rb +25 -0
  19. data/lib/rubocop/ast/node/send_node.rb +190 -0
  20. data/lib/rubocop/ast/node/when_node.rb +1 -1
  21. data/lib/rubocop/ast/traversal.rb +15 -15
  22. data/lib/rubocop/comment_config.rb +1 -1
  23. data/lib/rubocop/config.rb +39 -15
  24. data/lib/rubocop/config_loader.rb +34 -13
  25. data/lib/rubocop/cop/bundler/ordered_gems.rb +23 -4
  26. data/lib/rubocop/cop/commissioner.rb +4 -0
  27. data/lib/rubocop/cop/cop.rb +5 -0
  28. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +53 -0
  29. data/lib/rubocop/cop/lint/debugger.rb +8 -1
  30. data/lib/rubocop/cop/lint/def_end_alignment.rb +2 -1
  31. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +2 -4
  32. data/lib/rubocop/cop/lint/duplicate_case_condition.rb +1 -1
  33. data/lib/rubocop/cop/lint/each_with_object_argument.rb +3 -1
  34. data/lib/rubocop/cop/lint/empty_ensure.rb +6 -2
  35. data/lib/rubocop/cop/lint/ensure_return.rb +1 -1
  36. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +20 -18
  37. data/lib/rubocop/cop/lint/handle_exceptions.rb +1 -3
  38. data/lib/rubocop/cop/lint/literal_in_condition.rb +1 -1
  39. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
  40. data/lib/rubocop/cop/lint/multiple_compare.rb +5 -3
  41. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +26 -18
  42. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +7 -8
  43. data/lib/rubocop/cop/lint/require_parentheses.rb +7 -13
  44. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +7 -3
  45. data/lib/rubocop/cop/lint/shadowed_exception.rb +2 -6
  46. data/lib/rubocop/cop/lint/string_conversion_in_interpolation.rb +7 -8
  47. data/lib/rubocop/cop/lint/unneeded_disable.rb +35 -11
  48. data/lib/rubocop/cop/lint/unneeded_splat_expansion.rb +1 -1
  49. data/lib/rubocop/cop/lint/unreachable_code.rb +5 -2
  50. data/lib/rubocop/cop/lint/unused_block_argument.rb +6 -6
  51. data/lib/rubocop/cop/lint/useless_assignment.rb +2 -1
  52. data/lib/rubocop/cop/lint/useless_comparison.rb +5 -4
  53. data/lib/rubocop/cop/lint/useless_setter_call.rb +1 -1
  54. data/lib/rubocop/cop/message_annotator.rb +7 -3
  55. data/lib/rubocop/cop/metrics/abc_size.rb +1 -1
  56. data/lib/rubocop/cop/metrics/block_nesting.rb +4 -4
  57. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +2 -2
  58. data/lib/rubocop/cop/metrics/line_length.rb +2 -9
  59. data/lib/rubocop/cop/metrics/parameter_lists.rb +4 -3
  60. data/lib/rubocop/cop/metrics/perceived_complexity.rb +2 -2
  61. data/lib/rubocop/cop/mixin/access_modifier_node.rb +1 -1
  62. data/lib/rubocop/cop/mixin/array_hash_indentation.rb +2 -2
  63. data/lib/rubocop/cop/mixin/check_assignment.rb +6 -6
  64. data/lib/rubocop/cop/mixin/duplication.rb +1 -1
  65. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -1
  66. data/lib/rubocop/cop/mixin/ignored_pattern.rb +27 -0
  67. data/lib/rubocop/cop/mixin/method_preference.rb +2 -0
  68. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +17 -29
  69. data/lib/rubocop/cop/mixin/on_method_def.rb +3 -3
  70. data/lib/rubocop/cop/mixin/percent_literal.rb +27 -0
  71. data/lib/rubocop/cop/mixin/rescue_node.rb +21 -0
  72. data/lib/rubocop/cop/mixin/safe_mode.rb +1 -1
  73. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -1
  74. data/lib/rubocop/cop/mixin/statement_modifier.rb +2 -1
  75. data/lib/rubocop/cop/mixin/target_rails_version.rb +16 -0
  76. data/lib/rubocop/cop/mixin/unused_argument.rb +1 -1
  77. data/lib/rubocop/cop/offense.rb +3 -3
  78. data/lib/rubocop/cop/performance/casecmp.rb +1 -1
  79. data/lib/rubocop/cop/performance/detect.rb +2 -1
  80. data/lib/rubocop/cop/performance/double_start_end_with.rb +35 -1
  81. data/lib/rubocop/cop/performance/end_with.rb +3 -1
  82. data/lib/rubocop/cop/performance/flat_map.rb +6 -6
  83. data/lib/rubocop/cop/performance/lstrip_rstrip.rb +2 -2
  84. data/lib/rubocop/cop/performance/range_include.rb +3 -1
  85. data/lib/rubocop/cop/performance/redundant_match.rb +6 -5
  86. data/lib/rubocop/cop/performance/regexp_match.rb +10 -3
  87. data/lib/rubocop/cop/performance/reverse_each.rb +2 -1
  88. data/lib/rubocop/cop/performance/size.rb +6 -11
  89. data/lib/rubocop/cop/performance/start_with.rb +3 -1
  90. data/lib/rubocop/cop/performance/string_replacement.rb +13 -18
  91. data/lib/rubocop/cop/performance/times_map.rb +4 -4
  92. data/lib/rubocop/cop/rails/action_filter.rb +42 -42
  93. data/lib/rubocop/cop/rails/active_support_aliases.rb +68 -0
  94. data/lib/rubocop/cop/rails/blank.rb +131 -0
  95. data/lib/rubocop/cop/rails/date.rb +25 -28
  96. data/lib/rubocop/cop/rails/delegate_allow_blank.rb +5 -7
  97. data/lib/rubocop/cop/rails/dynamic_find_by.rb +7 -3
  98. data/lib/rubocop/cop/rails/exit.rb +9 -9
  99. data/lib/rubocop/cop/rails/file_path.rb +5 -14
  100. data/lib/rubocop/cop/rails/find_by.rb +8 -10
  101. data/lib/rubocop/cop/rails/find_each.rb +6 -9
  102. data/lib/rubocop/cop/rails/has_and_belongs_to_many.rb +1 -0
  103. data/lib/rubocop/cop/rails/http_positional_arguments.rb +15 -7
  104. data/lib/rubocop/cop/rails/output.rb +3 -5
  105. data/lib/rubocop/cop/rails/output_safety.rb +4 -8
  106. data/lib/rubocop/cop/rails/pluralization_grammar.rb +25 -24
  107. data/lib/rubocop/cop/rails/present.rb +137 -0
  108. data/lib/rubocop/cop/rails/read_write_attribute.rb +9 -18
  109. data/lib/rubocop/cop/rails/relative_date_constant.rb +53 -0
  110. data/lib/rubocop/cop/rails/request_referer.rb +7 -4
  111. data/lib/rubocop/cop/rails/reversible_migration.rb +1 -2
  112. data/lib/rubocop/cop/rails/safe_navigation.rb +2 -1
  113. data/lib/rubocop/cop/rails/save_bang.rb +10 -10
  114. data/lib/rubocop/cop/rails/skips_model_validations.rb +23 -6
  115. data/lib/rubocop/cop/rails/time_zone.rb +20 -18
  116. data/lib/rubocop/cop/rails/uniq_before_pluck.rb +3 -2
  117. data/lib/rubocop/cop/rails/validation.rb +8 -11
  118. data/lib/rubocop/cop/registry.rb +3 -3
  119. data/lib/rubocop/cop/security/json_load.rb +1 -1
  120. data/lib/rubocop/cop/security/marshal_load.rb +5 -1
  121. data/lib/rubocop/cop/security/yaml_load.rb +3 -3
  122. data/lib/rubocop/cop/severity.rb +1 -1
  123. data/lib/rubocop/cop/style/alias.rb +5 -5
  124. data/lib/rubocop/cop/style/align_hash.rb +1 -1
  125. data/lib/rubocop/cop/style/align_parameters.rb +5 -5
  126. data/lib/rubocop/cop/style/and_or.rb +16 -31
  127. data/lib/rubocop/cop/style/attr.rb +14 -8
  128. data/lib/rubocop/cop/style/auto_resource_cleanup.rb +8 -11
  129. data/lib/rubocop/cop/style/block_delimiters.rb +11 -13
  130. data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +19 -23
  131. data/lib/rubocop/cop/style/case_indentation.rb +2 -0
  132. data/lib/rubocop/cop/style/class_and_module_children.rb +1 -1
  133. data/lib/rubocop/cop/style/class_check.rb +5 -7
  134. data/lib/rubocop/cop/style/closing_parenthesis_indentation.rb +5 -4
  135. data/lib/rubocop/cop/style/collection_methods.rb +8 -8
  136. data/lib/rubocop/cop/style/colon_method_call.rb +2 -9
  137. data/lib/rubocop/cop/style/conditional_assignment.rb +38 -45
  138. data/lib/rubocop/cop/style/constant_name.rb +1 -1
  139. data/lib/rubocop/cop/style/documentation_method.rb +1 -0
  140. data/lib/rubocop/cop/style/dot_position.rb +3 -7
  141. data/lib/rubocop/cop/style/double_negation.rb +2 -1
  142. data/lib/rubocop/cop/style/each_with_object.rb +1 -1
  143. data/lib/rubocop/cop/style/empty_else.rb +2 -2
  144. data/lib/rubocop/cop/style/empty_line_after_magic_comment.rb +63 -0
  145. data/lib/rubocop/cop/style/empty_line_between_defs.rb +74 -4
  146. data/lib/rubocop/cop/style/empty_lines_around_begin_body.rb +42 -0
  147. data/lib/rubocop/cop/style/empty_lines_around_exception_handling_keywords.rb +127 -0
  148. data/lib/rubocop/cop/style/empty_literal.rb +17 -9
  149. data/lib/rubocop/cop/style/end_of_line.rb +25 -3
  150. data/lib/rubocop/cop/style/file_name.rb +1 -1
  151. data/lib/rubocop/cop/style/first_method_argument_line_break.rb +1 -1
  152. data/lib/rubocop/cop/style/first_parameter_indentation.rb +17 -19
  153. data/lib/rubocop/cop/style/for.rb +2 -4
  154. data/lib/rubocop/cop/style/format_string.rb +5 -4
  155. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +1 -1
  156. data/lib/rubocop/cop/style/identical_conditional_branches.rb +27 -1
  157. data/lib/rubocop/cop/style/if_unless_modifier.rb +2 -2
  158. data/lib/rubocop/cop/style/indent_assignment.rb +2 -2
  159. data/lib/rubocop/cop/style/indent_hash.rb +2 -1
  160. data/lib/rubocop/cop/style/indent_heredoc.rb +173 -0
  161. data/lib/rubocop/cop/style/indentation_width.rb +61 -29
  162. data/lib/rubocop/cop/style/inverse_methods.rb +130 -0
  163. data/lib/rubocop/cop/style/lambda_call.rb +15 -11
  164. data/lib/rubocop/cop/style/line_end_concatenation.rb +4 -4
  165. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +26 -14
  166. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +6 -16
  167. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +4 -1
  168. data/lib/rubocop/cop/style/missing_else.rb +4 -3
  169. data/lib/rubocop/cop/style/mixin_grouping.rb +97 -0
  170. data/lib/rubocop/cop/style/multiline_memoization.rb +38 -5
  171. data/lib/rubocop/cop/style/multiline_method_call_brace_layout.rb +2 -3
  172. data/lib/rubocop/cop/style/multiline_method_call_indentation.rb +38 -19
  173. data/lib/rubocop/cop/style/mutable_constant.rb +5 -1
  174. data/lib/rubocop/cop/style/negated_if.rb +73 -1
  175. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +21 -19
  176. data/lib/rubocop/cop/style/next.rb +5 -5
  177. data/lib/rubocop/cop/style/non_nil_check.rb +7 -10
  178. data/lib/rubocop/cop/style/not.rb +3 -4
  179. data/lib/rubocop/cop/style/numeric_literals.rb +25 -3
  180. data/lib/rubocop/cop/style/numeric_predicate.rb +1 -1
  181. data/lib/rubocop/cop/style/one_line_conditional.rb +2 -2
  182. data/lib/rubocop/cop/style/op_method.rb +2 -2
  183. data/lib/rubocop/cop/style/parallel_assignment.rb +6 -3
  184. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +52 -6
  185. data/lib/rubocop/cop/style/perl_backrefs.rb +1 -1
  186. data/lib/rubocop/cop/style/preferred_hash_methods.rb +9 -9
  187. data/lib/rubocop/cop/style/raise_args.rb +28 -24
  188. data/lib/rubocop/cop/style/redundant_freeze.rb +5 -7
  189. data/lib/rubocop/cop/style/redundant_parentheses.rb +2 -3
  190. data/lib/rubocop/cop/style/redundant_self.rb +17 -35
  191. data/lib/rubocop/cop/style/rescue_modifier.rb +2 -14
  192. data/lib/rubocop/cop/style/self_assignment.rb +3 -3
  193. data/lib/rubocop/cop/style/send.rb +4 -5
  194. data/lib/rubocop/cop/style/space_after_not.rb +7 -8
  195. data/lib/rubocop/cop/style/space_around_keyword.rb +8 -9
  196. data/lib/rubocop/cop/style/space_around_operators.rb +19 -15
  197. data/lib/rubocop/cop/style/space_before_first_arg.rb +17 -14
  198. data/lib/rubocop/cop/style/space_inside_brackets.rb +1 -1
  199. data/lib/rubocop/cop/style/space_inside_hash_literal_braces.rb +3 -3
  200. data/lib/rubocop/cop/style/space_inside_parens.rb +1 -1
  201. data/lib/rubocop/cop/style/special_global_vars.rb +14 -14
  202. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +2 -1
  203. data/lib/rubocop/cop/style/string_literals.rb +1 -1
  204. data/lib/rubocop/cop/style/string_methods.rb +10 -5
  205. data/lib/rubocop/cop/style/struct_inheritance.rb +4 -15
  206. data/lib/rubocop/cop/style/symbol_array.rb +31 -35
  207. data/lib/rubocop/cop/style/symbol_proc.rb +2 -2
  208. data/lib/rubocop/cop/style/ternary_parentheses.rb +41 -13
  209. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +6 -9
  210. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +4 -1
  211. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  212. data/lib/rubocop/cop/style/unneeded_capital_w.rb +1 -2
  213. data/lib/rubocop/cop/style/unneeded_percent_q.rb +1 -1
  214. data/lib/rubocop/cop/style/word_array.rb +12 -34
  215. data/lib/rubocop/cop/style/zero_length_predicate.rb +11 -4
  216. data/lib/rubocop/cop/team.rb +4 -1
  217. data/lib/rubocop/cop/util.rb +33 -26
  218. data/lib/rubocop/cop/variable_force.rb +13 -13
  219. data/lib/rubocop/cop/variable_force/assignment.rb +1 -8
  220. data/lib/rubocop/cop/variable_force/branch.rb +318 -0
  221. data/lib/rubocop/cop/variable_force/branchable.rb +21 -0
  222. data/lib/rubocop/cop/variable_force/reference.rb +1 -3
  223. data/lib/rubocop/cop/variable_force/scope.rb +36 -20
  224. data/lib/rubocop/cop/variable_force/variable.rb +9 -8
  225. data/lib/rubocop/formatter/colorizable.rb +10 -10
  226. data/lib/rubocop/formatter/formatter_set.rb +1 -1
  227. data/lib/rubocop/formatter/html_formatter.rb +2 -1
  228. data/lib/rubocop/formatter/simple_text_formatter.rb +4 -2
  229. data/lib/rubocop/magic_comment.rb +20 -6
  230. data/lib/rubocop/options.rb +1 -1
  231. data/lib/rubocop/platform.rb +11 -0
  232. data/lib/rubocop/processed_source.rb +1 -1
  233. data/lib/rubocop/remote_config.rb +18 -6
  234. data/lib/rubocop/result_cache.rb +8 -8
  235. data/lib/rubocop/rspec/cop_helper.rb +2 -0
  236. data/lib/rubocop/rspec/shared_contexts.rb +20 -0
  237. data/lib/rubocop/rspec/shared_examples.rb +1 -1
  238. data/lib/rubocop/runner.rb +2 -2
  239. data/lib/rubocop/target_finder.rb +64 -6
  240. data/lib/rubocop/version.rb +2 -4
  241. metadata +27 -4
  242. data/lib/rubocop/cop/variable_force/locatable.rb +0 -200
@@ -25,10 +25,8 @@ module RuboCop
25
25
  return if block_length(node).zero?
26
26
 
27
27
  method, _args, _body = *node
28
- return unless method.send_type?
29
-
30
- _receiver, method_name, *args = *method
31
- return unless method_name == :each && args.empty?
28
+ return unless method.send_type? && method.method?(:each) &&
29
+ !method.arguments?
32
30
 
33
31
  if style == :for
34
32
  incorrect_style_detected(method)
@@ -24,12 +24,13 @@ module RuboCop
24
24
  PATTERN
25
25
 
26
26
  def on_send(node)
27
- return unless (selector = formatter(node))
27
+ formatter(node) do |selector|
28
+ detected_style = selector == :% ? :percent : selector
28
29
 
29
- detected_style = selector == :% ? :percent : selector
30
- return if detected_style == style
30
+ return if detected_style == style
31
31
 
32
- add_offense(node, :selector, message(detected_style))
32
+ add_offense(node, :selector, message(detected_style))
33
+ end
33
34
  end
34
35
 
35
36
  def message(detected_style)
@@ -12,7 +12,7 @@ module RuboCop
12
12
  include ConfigurableEnforcedStyle
13
13
  include FrozenStringLiteral
14
14
 
15
- MSG = 'Missing frozen string literal comment.'.freeze
15
+ MSG = 'Missing magic comment `# frozen_string_literal: true`.'.freeze
16
16
  MSG_UNNECESSARY = 'Unnecessary frozen string literal comment.'.freeze
17
17
  SHEBANG = '#!'.freeze
18
18
 
@@ -40,6 +40,28 @@ module RuboCop
40
40
  # else
41
41
  # do_y
42
42
  # end
43
+ #
44
+ # @bad
45
+ # switch foo
46
+ # when 1
47
+ # do_x
48
+ # when 2
49
+ # do_x
50
+ # else
51
+ # do_x
52
+ # end
53
+ #
54
+ # @good
55
+ # switch foo
56
+ # when 1
57
+ # do_x
58
+ # do_y
59
+ # when 2
60
+ # # nothing
61
+ # else
62
+ # do_x
63
+ # do_z
64
+ # end
43
65
  class IdenticalConditionalBranches < Cop
44
66
  MSG = 'Move `%s` out of the conditional.'.freeze
45
67
 
@@ -58,7 +80,11 @@ module RuboCop
58
80
  def on_case(node)
59
81
  return unless node.else? && node.else_branch
60
82
 
61
- check_branches(node.when_branches.map(&:body).push(node.else_branch))
83
+ branches = node.when_branches.map(&:body).push(node.else_branch)
84
+
85
+ return if branches.any?(&:nil?)
86
+
87
+ check_branches(branches)
62
88
  end
63
89
 
64
90
  private
@@ -13,8 +13,8 @@ module RuboCop
13
13
  'Another good alternative is the usage of control flow ' \
14
14
  '`&&`/`||`.'.freeze
15
15
 
16
- ASSIGNMENT_TYPES = [:lvasgn, :casgn, :cvasgn,
17
- :gvasgn, :ivasgn, :masgn].freeze
16
+ ASSIGNMENT_TYPES = %i(lvasgn casgn cvasgn
17
+ gvasgn ivasgn masgn).freeze
18
18
 
19
19
  def on_if(node)
20
20
  return unless eligible_node?(node)
@@ -16,8 +16,8 @@ module RuboCop
16
16
  # # good
17
17
  # value =
18
18
  # if foo
19
- # 'bar'
20
- # end
19
+ # 'bar'
20
+ # end
21
21
  #
22
22
  # The indentation of the remaining lines can be corrected with
23
23
  # other cops such as `IndentationConsistency` and `EndAlignment`.
@@ -63,7 +63,8 @@ module RuboCop
63
63
  return if ignored_node?(hash_node)
64
64
 
65
65
  left_brace = hash_node.loc.begin
66
- first_pair = hash_node.children.first
66
+ first_pair = hash_node.pairs.first
67
+
67
68
  if first_pair
68
69
  return if first_pair.source_range.line == left_brace.line
69
70
 
@@ -0,0 +1,173 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # This cops checks the indentation of the here document bodies. The bodies
7
+ # are indented one step.
8
+ # In Ruby 2.3 or newer, squiggly heredocs (`<<~`) should be used. If you
9
+ # use the older rubies, you should introduce some library to your project
10
+ # (e.g. ActiveSupport, Powerpack or Unindent).
11
+ #
12
+ # @example
13
+ #
14
+ # # bad
15
+ # <<-END
16
+ # something
17
+ # END
18
+ #
19
+ # # good
20
+ # # When EnforcedStyle is squiggly, bad code is auto-corrected to the
21
+ # # following code.
22
+ # <<~END
23
+ # something
24
+ # END
25
+ #
26
+ # # good
27
+ # # When EnforcedStyle is active_support, bad code is auto-corrected to
28
+ # # the following code.
29
+ # <<-END.strip_heredoc
30
+ # something
31
+ # END
32
+ class IndentHeredoc < Cop
33
+ include ConfigurableEnforcedStyle
34
+ include SafeMode
35
+
36
+ RUBY23_MSG = 'Use %d spaces for indentation in a heredoc by using ' \
37
+ '`<<~` instead of `%s`.'.freeze
38
+ LIBRARY_MSG = 'Use %d spaces for indentation in a heredoc by using %s.'
39
+ .freeze
40
+ StripMethods = {
41
+ unindent: 'unindent',
42
+ active_support: 'strip_heredoc',
43
+ powerpack: 'strip_indent'
44
+ }.freeze
45
+
46
+ def on_str(node)
47
+ return unless heredoc?(node)
48
+
49
+ body_indent_level = body_indent_level(node)
50
+
51
+ if heredoc_indent_type(node) == '~'
52
+ expected_indent_level = base_indent_level(node) + indentation_width
53
+ return if expected_indent_level == body_indent_level
54
+ else
55
+ return unless body_indent_level.zero?
56
+ end
57
+
58
+ add_offense(node, :heredoc_body)
59
+ end
60
+
61
+ alias on_dstr on_str
62
+ alias on_xstr on_str
63
+
64
+ def autocorrect(node)
65
+ check_style!
66
+
67
+ case style
68
+ when :squiggly
69
+ correct_by_squiggly(node)
70
+ else
71
+ correct_by_library(node)
72
+ end
73
+ end
74
+
75
+ private
76
+
77
+ def style
78
+ style = super
79
+ return style unless style == :auto_detection
80
+
81
+ if target_ruby_version >= 2.3
82
+ :squiggly
83
+ elsif rails?
84
+ :active_support
85
+ end
86
+ end
87
+
88
+ def message(node)
89
+ case style
90
+ when :squiggly
91
+ current_indent_type = "<<#{heredoc_indent_type(node)}"
92
+ format(RUBY23_MSG, indentation_width, current_indent_type)
93
+ when nil
94
+ method = "some library(e.g. ActiveSupport's `String#strip_heredoc`)"
95
+ format(LIBRARY_MSG, indentation_width, method)
96
+ else
97
+ method = "`String##{StripMethods[style]}`"
98
+ format(LIBRARY_MSG, indentation_width, method)
99
+ end
100
+ end
101
+
102
+ def correct_by_squiggly(node)
103
+ return if target_ruby_version < 2.3
104
+ lambda do |corrector|
105
+ if heredoc_indent_type(node) == '~'
106
+ corrector.replace(node.loc.heredoc_body, indented_body(node))
107
+ else
108
+ heredoc_begenning = node.loc.expression.source
109
+ corrected = heredoc_begenning.sub(/<<-?/, '<<~')
110
+ corrector.replace(node.loc.expression, corrected)
111
+ end
112
+ end
113
+ end
114
+
115
+ def correct_by_library(node)
116
+ lambda do |corrector|
117
+ corrector.replace(node.loc.heredoc_body, indented_body(node))
118
+ corrected = ".#{StripMethods[style]}"
119
+ corrector.insert_after(node.loc.expression, corrected)
120
+ end
121
+ end
122
+
123
+ def check_style!
124
+ case style
125
+ when nil
126
+ raise Warning, "Auto-correction does not work for #{cop_name}. " \
127
+ 'Please configure EnforcedStyle.'
128
+ when :squiggly
129
+ if target_ruby_version < 2.3
130
+ raise Warning, '`squiggly` style is selectable only on Ruby ' \
131
+ "2.3 or higher for #{cop_name}."
132
+ end
133
+ end
134
+ end
135
+
136
+ def heredoc?(node)
137
+ node.loc.is_a?(Parser::Source::Map::Heredoc)
138
+ end
139
+
140
+ def indented_body(node)
141
+ body = node.loc.heredoc_body.source
142
+ body_indent_level = body_indent_level(node)
143
+ correct_indent_level = base_indent_level(node) + indentation_width
144
+ body.gsub(/^\s{#{body_indent_level}}/, ' ' * correct_indent_level)
145
+ end
146
+
147
+ def body_indent_level(node)
148
+ body = node.loc.heredoc_body.source
149
+ indent_level(body)
150
+ end
151
+
152
+ def base_indent_level(node)
153
+ base_line_num = node.loc.expression.line
154
+ base_line = processed_source.lines[base_line_num - 1]
155
+ indent_level(base_line)
156
+ end
157
+
158
+ def indent_level(str)
159
+ str.scan(/^\s*/).reject { |line| line == "\n" }.min_by(&:size).size
160
+ end
161
+
162
+ # Returns '~', '-' or nil
163
+ def heredoc_indent_type(node)
164
+ node.source[/^<<([~-])/, 1]
165
+ end
166
+
167
+ def indentation_width
168
+ @config.for_cop('IndentationWidth')['Width'] || 2
169
+ end
170
+ end
171
+ end
172
+ end
173
+ end
@@ -3,38 +3,70 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # This cops checks for indentation that doesn't use two spaces.
6
+ # This cops checks for indentation that doesn't use the specified number
7
+ # of spaces.
7
8
  #
8
- # @example
9
+ # See also the IndentationConsistency cop which is the companion to this
10
+ # one.
9
11
  #
12
+ # @example
13
+ # # bad, Width: 2
10
14
  # class A
11
15
  # def test
12
16
  # puts 'hello'
13
17
  # end
14
18
  # end
15
- class IndentationWidth < Cop
19
+ #
20
+ # # bad, Width: 2,
21
+ # IgnoredPatterns:
22
+ # - '^\s*module'
23
+ # module A
24
+ # class B
25
+ # def test
26
+ # puts 'hello'
27
+ # end
28
+ # end
29
+ # end
30
+ #
31
+ # # good, Width: 2
32
+ # class A
33
+ # def test
34
+ # puts 'hello'
35
+ # end
36
+ # end
37
+ #
38
+ # # good, Width: 2,
39
+ # IgnoredPatterns:
40
+ # - '^\s*module'
41
+ # module A
42
+ # class B
43
+ # def test
44
+ # puts 'hello'
45
+ # end
46
+ # end
47
+ # end
48
+ class IndentationWidth < Cop # rubocop:disable Metrics/ClassLength
16
49
  include EndKeywordAlignment
17
50
  include AutocorrectAlignment
18
51
  include OnMethodDef
19
52
  include CheckAssignment
20
53
  include AccessModifierNode
54
+ include IgnoredPattern
21
55
 
22
56
  SPECIAL_MODIFIERS = %w(private protected).freeze
23
57
 
24
58
  def on_rescue(node)
25
- _begin_node, *rescue_nodes, else_node = *node
26
- rescue_nodes.each do |rescue_node|
27
- _, _, body = *rescue_node
28
- check_indentation(rescue_node.loc.keyword, body)
29
- end
59
+ _begin_node, *_rescue_nodes, else_node = *node
30
60
  check_indentation(node.loc.else, else_node)
31
61
  end
32
62
 
33
63
  def on_ensure(node)
34
- _body, ensure_body = *node
35
- check_indentation(node.loc.keyword, ensure_body)
64
+ check_indentation(node.loc.keyword, node.body)
36
65
  end
37
66
 
67
+ alias on_resbody on_ensure
68
+ alias on_for on_ensure
69
+
38
70
  def on_kwbegin(node)
39
71
  # Check indentation against end keyword but only if it's first on its
40
72
  # line.
@@ -69,26 +101,21 @@ module RuboCop
69
101
  def on_send(node)
70
102
  super
71
103
  return unless modifier_and_def_on_same_line?(node)
72
- _, _, *args = *node
73
104
 
74
- *_, body = *args.first
105
+ *_, body = *node.first_argument
75
106
 
76
107
  def_end_config = config.for_cop('Lint/DefEndAlignment')
77
108
  style = def_end_config['EnforcedStyleAlignWith'] || 'start_of_line'
78
- base = style == 'def' ? args.first : node
109
+ base = style == 'def' ? node.first_argument : node
79
110
 
80
111
  check_indentation(base.source_range, body)
81
- ignore_node(args.first)
112
+ ignore_node(node.first_argument)
82
113
  end
83
114
 
84
115
  def on_method_def(node, _method_name, _args, body)
85
116
  check_indentation(node.loc.keyword, body) unless ignored_node?(node)
86
117
  end
87
118
 
88
- def on_for(node)
89
- check_indentation(node.loc.keyword, node.body)
90
- end
91
-
92
119
  def on_while(node, base = node)
93
120
  return if ignored_node?(node)
94
121
 
@@ -230,24 +257,29 @@ module RuboCop
230
257
  end
231
258
 
232
259
  def indentation_to_check?(base_loc, body_node)
233
- return false unless body_node
260
+ return false if skip_check?(base_loc, body_node)
261
+
262
+ if %i(rescue ensure).include?(body_node.type)
263
+ block_body, = *body_node
264
+ return unless block_body
265
+ end
266
+
267
+ true
268
+ end
269
+
270
+ def skip_check?(base_loc, body_node)
271
+ return true if ignored_line?(base_loc)
272
+ return true unless body_node
234
273
 
235
274
  # Don't check if expression is on same line as "then" keyword, etc.
236
- return false if body_node.loc.line == base_loc.line
275
+ return true if body_node.loc.line == base_loc.line
237
276
 
238
- return false if starts_with_access_modifier?(body_node)
277
+ return true if starts_with_access_modifier?(body_node)
239
278
 
240
279
  # Don't check indentation if the line doesn't start with the body.
241
280
  # For example, lines like "else do_something".
242
281
  first_char_pos_on_line = body_node.source_range.source_line =~ /\S/
243
- return false unless body_node.loc.column == first_char_pos_on_line
244
-
245
- if [:rescue, :ensure].include?(body_node.type)
246
- block_body, = *body_node
247
- return unless block_body
248
- end
249
-
250
- true
282
+ return true unless body_node.loc.column == first_char_pos_on_line
251
283
  end
252
284
 
253
285
  def offending_range(body_node, indentation)
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # This cop check for usages of not (`not` or `!`) called on a method
7
+ # when an inverse of that method can be used instead.
8
+ # Methods that can be inverted by a not (`not` or `!`) should be defined
9
+ # in `InverseMethods`
10
+ # Methods that are inverted by inverting the return
11
+ # of the block that is passed to the method should be defined in
12
+ # `InverseBlocks`
13
+ #
14
+ # @example
15
+ # # bad
16
+ # !foo.none?
17
+ # !foo.any? { |f| f.even? }
18
+ # !foo.blank?
19
+ # !(foo == bar)
20
+ # foo.select { |f| !f.even? }
21
+ # foo.reject { |f| f != 7 }
22
+ #
23
+ # # good
24
+ # foo.none?
25
+ # foo.blank?
26
+ # foo.any? { |f| f.even? }
27
+ # foo != bar
28
+ # foo == bar
29
+ class InverseMethods < Cop
30
+ MSG = 'Use `%{inverse}` instead of inverting `%{method}`.'.freeze
31
+ EQUALITY_METHODS = %i(== != =~ !~ <= >= < >).freeze
32
+
33
+ def_node_matcher :inverse_candidate?, <<-PATTERN
34
+ {
35
+ (send $(send (...) $_ ...) :!)
36
+ (send (block $(send (...) $_) ...) :!)
37
+ (send (begin $(send (...) $_ ...)) :!)
38
+ }
39
+ PATTERN
40
+
41
+ def_node_matcher :inverse_block?, <<-PATTERN
42
+ (block $(send (...) $_) ... { $(send ... :!)
43
+ $(send (...) {:!= :!~} ...)
44
+ (begin ... $(send ... :!))
45
+ (begin ... $(send (...) {:!= :!~} ...))
46
+ })
47
+ PATTERN
48
+
49
+ def on_send(node)
50
+ inverse_candidate?(node) do |_method_call, method|
51
+ return unless inverse_methods.key?(method)
52
+
53
+ add_offense(node,
54
+ :expression,
55
+ format(MSG, method: method,
56
+ inverse: inverse_methods[method]))
57
+ end
58
+ end
59
+
60
+ def on_block(node)
61
+ inverse_block?(node) do |_method_call, method, _block|
62
+ return unless inverse_blocks.key?(method)
63
+
64
+ add_offense(node,
65
+ :expression,
66
+ format(MSG, method: method,
67
+ inverse: inverse_blocks[method]))
68
+ end
69
+ end
70
+
71
+ def autocorrect(node)
72
+ method_call, method = inverse_candidate?(node)
73
+
74
+ if method_call && method
75
+ lambda do |corrector|
76
+ corrector.remove(not_to_receiver(node, method_call))
77
+ corrector.replace(method_call.loc.selector,
78
+ inverse_methods[method].to_s)
79
+
80
+ if EQUALITY_METHODS.include?(method)
81
+ corrector.remove(end_parentheses(node, method_call))
82
+ end
83
+ end
84
+ else
85
+ correct_inverse_block(node)
86
+ end
87
+ end
88
+
89
+ def correct_inverse_block(node)
90
+ method_call, method, block = inverse_block?(node)
91
+ selector = block.loc.selector.source
92
+
93
+ lambda do |corrector|
94
+ corrector.replace(method_call.loc.selector,
95
+ inverse_blocks[method].to_s)
96
+
97
+ if ['!=', '!~'].include?(selector)
98
+ selector[0] = '='
99
+ corrector.replace(block.loc.selector, selector)
100
+ else
101
+ corrector.remove(block.loc.selector)
102
+ end
103
+ end
104
+ end
105
+
106
+ def inverse_methods
107
+ @inverse_methods ||= cop_config['InverseMethods']
108
+ .merge(cop_config['InverseMethods'].invert)
109
+ end
110
+
111
+ def inverse_blocks
112
+ @inverse_blocks ||= cop_config['InverseBlocks']
113
+ .merge(cop_config['InverseBlocks'].invert)
114
+ end
115
+
116
+ def not_to_receiver(node, method_call)
117
+ Parser::Source::Range.new(node.loc.expression.source_buffer,
118
+ node.loc.selector.begin_pos,
119
+ method_call.loc.expression.begin_pos)
120
+ end
121
+
122
+ def end_parentheses(node, method_call)
123
+ Parser::Source::Range.new(node.loc.expression.source_buffer,
124
+ method_call.loc.expression.end_pos,
125
+ node.loc.expression.end_pos)
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end