rubocop 0.93.1 → 1.6.1

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 (199) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +36 -16
  3. data/config/default.yml +276 -82
  4. data/config/obsoletion.yml +196 -0
  5. data/exe/rubocop +1 -1
  6. data/lib/rubocop.rb +31 -2
  7. data/lib/rubocop/cli.rb +5 -1
  8. data/lib/rubocop/cli/command/auto_genenerate_config.rb +1 -1
  9. data/lib/rubocop/cli/command/execute_runner.rb +26 -11
  10. data/lib/rubocop/cli/command/suggest_extensions.rb +80 -0
  11. data/lib/rubocop/cli/command/version.rb +1 -1
  12. data/lib/rubocop/comment_config.rb +1 -1
  13. data/lib/rubocop/config.rb +4 -0
  14. data/lib/rubocop/config_loader.rb +34 -8
  15. data/lib/rubocop/config_loader_resolver.rb +12 -6
  16. data/lib/rubocop/config_obsoletion.rb +65 -247
  17. data/lib/rubocop/config_obsoletion/changed_enforced_styles.rb +33 -0
  18. data/lib/rubocop/config_obsoletion/changed_parameter.rb +21 -0
  19. data/lib/rubocop/config_obsoletion/cop_rule.rb +34 -0
  20. data/lib/rubocop/config_obsoletion/extracted_cop.rb +44 -0
  21. data/lib/rubocop/config_obsoletion/parameter_rule.rb +44 -0
  22. data/lib/rubocop/config_obsoletion/removed_cop.rb +41 -0
  23. data/lib/rubocop/config_obsoletion/renamed_cop.rb +34 -0
  24. data/lib/rubocop/config_obsoletion/rule.rb +41 -0
  25. data/lib/rubocop/config_obsoletion/split_cop.rb +27 -0
  26. data/lib/rubocop/config_regeneration.rb +1 -1
  27. data/lib/rubocop/config_validator.rb +25 -10
  28. data/lib/rubocop/cop/autocorrect_logic.rb +21 -6
  29. data/lib/rubocop/cop/badge.rb +9 -24
  30. data/lib/rubocop/cop/base.rb +33 -16
  31. data/lib/rubocop/cop/bundler/duplicated_gem.rb +26 -6
  32. data/lib/rubocop/cop/bundler/gem_comment.rb +1 -1
  33. data/lib/rubocop/cop/commissioner.rb +37 -23
  34. data/lib/rubocop/cop/cop.rb +2 -2
  35. data/lib/rubocop/cop/corrector.rb +3 -1
  36. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +2 -2
  37. data/lib/rubocop/cop/correctors/string_literal_corrector.rb +6 -8
  38. data/lib/rubocop/cop/force.rb +1 -1
  39. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +3 -3
  40. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +4 -5
  41. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +1 -1
  42. data/lib/rubocop/cop/generator.rb +3 -10
  43. data/lib/rubocop/cop/generator/configuration_injector.rb +1 -1
  44. data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +1 -1
  45. data/lib/rubocop/cop/layout/block_alignment.rb +3 -4
  46. data/lib/rubocop/cop/layout/class_structure.rb +22 -3
  47. data/lib/rubocop/cop/layout/def_end_alignment.rb +1 -1
  48. data/lib/rubocop/cop/layout/else_alignment.rb +15 -2
  49. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +80 -10
  50. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +1 -0
  51. data/lib/rubocop/cop/layout/empty_lines_around_arguments.rb +6 -1
  52. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -1
  53. data/lib/rubocop/cop/layout/end_alignment.rb +3 -3
  54. data/lib/rubocop/cop/layout/end_of_line.rb +5 -5
  55. data/lib/rubocop/cop/layout/extra_spacing.rb +1 -2
  56. data/lib/rubocop/cop/layout/first_argument_indentation.rb +7 -2
  57. data/lib/rubocop/cop/layout/hash_alignment.rb +4 -4
  58. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +12 -0
  59. data/lib/rubocop/cop/layout/line_length.rb +10 -13
  60. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +7 -3
  61. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +24 -18
  62. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +1 -1
  63. data/lib/rubocop/cop/layout/space_around_operators.rb +4 -1
  64. data/lib/rubocop/cop/layout/space_inside_parens.rb +35 -13
  65. data/lib/rubocop/cop/layout/trailing_whitespace.rb +37 -13
  66. data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +2 -1
  67. data/lib/rubocop/cop/lint/constant_definition_in_block.rb +26 -2
  68. data/lib/rubocop/cop/lint/debugger.rb +17 -28
  69. data/lib/rubocop/cop/lint/duplicate_branch.rb +93 -0
  70. data/lib/rubocop/cop/lint/duplicate_case_condition.rb +2 -12
  71. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +77 -0
  72. data/lib/rubocop/cop/lint/else_layout.rb +29 -3
  73. data/lib/rubocop/cop/lint/empty_block.rb +82 -0
  74. data/lib/rubocop/cop/lint/empty_class.rb +93 -0
  75. data/lib/rubocop/cop/lint/flip_flop.rb +8 -2
  76. data/lib/rubocop/cop/lint/interpolation_check.rb +7 -2
  77. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +39 -7
  78. data/lib/rubocop/cop/lint/loop.rb +4 -4
  79. data/lib/rubocop/cop/lint/missing_super.rb +7 -4
  80. data/lib/rubocop/cop/lint/nested_percent_literal.rb +14 -0
  81. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +58 -0
  82. data/lib/rubocop/cop/lint/number_conversion.rb +46 -13
  83. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +27 -8
  84. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +19 -16
  85. data/lib/rubocop/cop/lint/shadowed_exception.rb +4 -5
  86. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +13 -0
  87. data/lib/rubocop/cop/lint/to_enum_arguments.rb +86 -0
  88. data/lib/rubocop/cop/lint/to_json.rb +1 -1
  89. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +85 -0
  90. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +199 -0
  91. data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -2
  92. data/lib/rubocop/cop/lint/useless_method_definition.rb +2 -4
  93. data/lib/rubocop/cop/lint/useless_setter_call.rb +6 -1
  94. data/lib/rubocop/cop/metrics/abc_size.rb +25 -1
  95. data/lib/rubocop/cop/metrics/block_length.rb +13 -7
  96. data/lib/rubocop/cop/metrics/method_length.rb +7 -2
  97. data/lib/rubocop/cop/metrics/parameter_lists.rb +68 -2
  98. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +20 -10
  99. data/lib/rubocop/cop/metrics/utils/repeated_attribute_discount.rb +146 -0
  100. data/lib/rubocop/cop/metrics/utils/repeated_csend_discount.rb +6 -1
  101. data/lib/rubocop/cop/migration/department_name.rb +1 -1
  102. data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
  103. data/lib/rubocop/cop/mixin/configurable_numbering.rb +4 -3
  104. data/lib/rubocop/cop/mixin/enforce_superclass.rb +9 -1
  105. data/lib/rubocop/cop/mixin/ignored_methods.rb +36 -3
  106. data/lib/rubocop/cop/mixin/line_length_help.rb +1 -1
  107. data/lib/rubocop/cop/mixin/method_complexity.rb +6 -0
  108. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +1 -1
  109. data/lib/rubocop/cop/mixin/statement_modifier.rb +9 -4
  110. data/lib/rubocop/cop/mixin/string_help.rb +4 -1
  111. data/lib/rubocop/cop/mixin/visibility_help.rb +1 -3
  112. data/lib/rubocop/cop/naming/accessor_method_name.rb +15 -1
  113. data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +12 -2
  114. data/lib/rubocop/cop/naming/heredoc_delimiter_case.rb +11 -5
  115. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +67 -18
  116. data/lib/rubocop/cop/naming/predicate_name.rb +2 -1
  117. data/lib/rubocop/cop/naming/variable_number.rb +100 -8
  118. data/lib/rubocop/cop/offense.rb +3 -3
  119. data/lib/rubocop/cop/security/open.rb +12 -10
  120. data/lib/rubocop/cop/style/accessor_grouping.rb +1 -1
  121. data/lib/rubocop/cop/style/and_or.rb +11 -3
  122. data/lib/rubocop/cop/style/arguments_forwarding.rb +142 -0
  123. data/lib/rubocop/cop/style/bisected_attr_accessor.rb +0 -4
  124. data/lib/rubocop/cop/style/case_like_if.rb +0 -4
  125. data/lib/rubocop/cop/style/character_literal.rb +10 -11
  126. data/lib/rubocop/cop/style/class_and_module_children.rb +8 -3
  127. data/lib/rubocop/cop/style/collection_compact.rb +91 -0
  128. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +169 -0
  129. data/lib/rubocop/cop/style/documentation.rb +12 -1
  130. data/lib/rubocop/cop/style/double_negation.rb +6 -1
  131. data/lib/rubocop/cop/style/float_division.rb +44 -1
  132. data/lib/rubocop/cop/style/format_string.rb +8 -3
  133. data/lib/rubocop/cop/style/format_string_token.rb +47 -2
  134. data/lib/rubocop/cop/style/hash_syntax.rb +3 -3
  135. data/lib/rubocop/cop/style/identical_conditional_branches.rb +7 -2
  136. data/lib/rubocop/cop/style/if_inside_else.rb +37 -1
  137. data/lib/rubocop/cop/style/if_unless_modifier.rb +11 -3
  138. data/lib/rubocop/cop/style/if_with_semicolon.rb +39 -4
  139. data/lib/rubocop/cop/style/infinite_loop.rb +4 -0
  140. data/lib/rubocop/cop/style/ip_addresses.rb +1 -1
  141. data/lib/rubocop/cop/style/keyword_parameters_order.rb +12 -0
  142. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +10 -13
  143. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +8 -13
  144. data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +7 -11
  145. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +11 -2
  146. data/lib/rubocop/cop/style/mixin_grouping.rb +0 -4
  147. data/lib/rubocop/cop/style/multiple_comparison.rb +55 -7
  148. data/lib/rubocop/cop/style/negated_if_else_condition.rb +106 -0
  149. data/lib/rubocop/cop/style/nil_lambda.rb +52 -0
  150. data/lib/rubocop/cop/style/numeric_literals.rb +14 -11
  151. data/lib/rubocop/cop/style/perl_backrefs.rb +86 -9
  152. data/lib/rubocop/cop/style/raise_args.rb +21 -6
  153. data/lib/rubocop/cop/style/redundant_argument.rb +88 -0
  154. data/lib/rubocop/cop/style/redundant_condition.rb +2 -1
  155. data/lib/rubocop/cop/style/redundant_parentheses.rb +4 -0
  156. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +7 -1
  157. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +24 -8
  158. data/lib/rubocop/cop/style/redundant_self.rb +3 -0
  159. data/lib/rubocop/cop/style/safe_navigation.rb +16 -4
  160. data/lib/rubocop/cop/style/semicolon.rb +3 -0
  161. data/lib/rubocop/cop/style/single_line_block_params.rb +30 -7
  162. data/lib/rubocop/cop/style/sole_nested_conditional.rb +65 -3
  163. data/lib/rubocop/cop/style/special_global_vars.rb +1 -13
  164. data/lib/rubocop/cop/style/static_class.rb +97 -0
  165. data/lib/rubocop/cop/style/string_concatenation.rb +39 -2
  166. data/lib/rubocop/cop/style/string_literals.rb +14 -8
  167. data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +4 -3
  168. data/lib/rubocop/cop/style/swap_values.rb +108 -0
  169. data/lib/rubocop/cop/style/symbol_proc.rb +5 -3
  170. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +3 -1
  171. data/lib/rubocop/cop/style/while_until_modifier.rb +9 -0
  172. data/lib/rubocop/cop/team.rb +6 -1
  173. data/lib/rubocop/cop/util.rb +6 -2
  174. data/lib/rubocop/cop/variable_force/branch.rb +1 -1
  175. data/lib/rubocop/cop/variable_force/scope.rb +1 -1
  176. data/lib/rubocop/core_ext/hash.rb +20 -0
  177. data/lib/rubocop/ext/regexp_node.rb +36 -11
  178. data/lib/rubocop/ext/regexp_parser.rb +95 -0
  179. data/lib/rubocop/formatter/disabled_config_formatter.rb +21 -6
  180. data/lib/rubocop/formatter/emacs_style_formatter.rb +2 -0
  181. data/lib/rubocop/formatter/formatter_set.rb +2 -1
  182. data/lib/rubocop/formatter/git_hub_actions_formatter.rb +47 -0
  183. data/lib/rubocop/formatter/offense_count_formatter.rb +1 -1
  184. data/lib/rubocop/formatter/simple_text_formatter.rb +2 -0
  185. data/lib/rubocop/formatter/tap_formatter.rb +2 -0
  186. data/lib/rubocop/formatter/worst_offenders_formatter.rb +1 -1
  187. data/lib/rubocop/lockfile.rb +40 -0
  188. data/lib/rubocop/magic_comment.rb +2 -2
  189. data/lib/rubocop/options.rb +11 -1
  190. data/lib/rubocop/rake_task.rb +2 -2
  191. data/lib/rubocop/rspec/shared_contexts.rb +4 -0
  192. data/lib/rubocop/runner.rb +1 -1
  193. data/lib/rubocop/target_finder.rb +1 -1
  194. data/lib/rubocop/target_ruby.rb +65 -1
  195. data/lib/rubocop/version.rb +56 -6
  196. metadata +50 -9
  197. data/bin/console +0 -10
  198. data/bin/rubocop-profile +0 -32
  199. data/bin/setup +0 -7
@@ -26,9 +26,10 @@ module RuboCop
26
26
  # "Just some text"
27
27
  # "No special chars or interpolation"
28
28
  # "Every string in #{project} uses double_quotes"
29
- class StringLiterals < Cop
29
+ class StringLiterals < Base
30
30
  include ConfigurableEnforcedStyle
31
31
  include StringLiteralsHelp
32
+ extend AutoCorrector
32
33
 
33
34
  MSG_INCONSISTENT = 'Inconsistent quote style.'
34
35
 
@@ -46,7 +47,7 @@ module RuboCop
46
47
  quote_styles = detect_quote_styles(node)
47
48
 
48
49
  if quote_styles.size > 1
49
- add_offense(node, message: MSG_INCONSISTENT)
50
+ register_offense(node, message: MSG_INCONSISTENT)
50
51
  else
51
52
  check_multiline_quote_style(node, quote_styles[0])
52
53
  end
@@ -54,11 +55,17 @@ module RuboCop
54
55
  ignore_node(node)
55
56
  end
56
57
 
57
- def autocorrect(node)
58
- StringLiteralCorrector.correct(node, style)
58
+ private
59
+
60
+ def autocorrect(corrector, node)
61
+ StringLiteralCorrector.correct(corrector, node, style)
59
62
  end
60
63
 
61
- private
64
+ def register_offense(node, message: nil)
65
+ add_offense(node, message: message || message(node)) do |corrector|
66
+ autocorrect(corrector, node)
67
+ end
68
+ end
62
69
 
63
70
  def all_string_literals?(nodes)
64
71
  nodes.all? { |n| n.str_type? || n.dstr_type? }
@@ -99,14 +106,13 @@ module RuboCop
99
106
  end
100
107
 
101
108
  def check_multiline_quote_style(node, quote)
102
- range = node.source_range
103
109
  children = node.children
104
110
  if unexpected_single_quotes?(quote)
105
111
  all_children_with_quotes = children.all? { |c| wrong_quotes?(c) }
106
- add_offense(node, location: range) if all_children_with_quotes
112
+ register_offense(node) if all_children_with_quotes
107
113
  elsif unexpected_double_quotes?(quote) &&
108
114
  !accept_child_double_quotes?(children)
109
- add_offense(node, location: range)
115
+ register_offense(node)
110
116
  end
111
117
  end
112
118
 
@@ -19,12 +19,13 @@ module RuboCop
19
19
  #
20
20
  # # good
21
21
  # result = "Tests #{success ? "PASS" : "FAIL"}"
22
- class StringLiteralsInInterpolation < Cop
22
+ class StringLiteralsInInterpolation < Base
23
23
  include ConfigurableEnforcedStyle
24
24
  include StringLiteralsHelp
25
+ extend AutoCorrector
25
26
 
26
- def autocorrect(node)
27
- StringLiteralCorrector.correct(node, style)
27
+ def autocorrect(corrector, node)
28
+ StringLiteralCorrector.correct(corrector, node, style)
28
29
  end
29
30
 
30
31
  private
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # This cop enforces the use of shorthand-style swapping of 2 variables.
7
+ # Its autocorrection is marked as unsafe, because it can erroneously remove
8
+ # the temporary variable which is used later.
9
+ #
10
+ # @example
11
+ # # bad
12
+ # tmp = x
13
+ # x = y
14
+ # y = tmp
15
+ #
16
+ # # good
17
+ # x, y = y, x
18
+ #
19
+ class SwapValues < Base
20
+ include RangeHelp
21
+ extend AutoCorrector
22
+
23
+ MSG = 'Replace this and assignments at lines %<x_line>d '\
24
+ 'and %<y_line>d with `%<replacement>s`.'
25
+
26
+ SIMPLE_ASSIGNMENT_TYPES = %i[lvasgn ivasgn cvasgn gvasgn casgn].to_set.freeze
27
+
28
+ def on_asgn(node)
29
+ return if allowed_assignment?(node)
30
+
31
+ tmp_assign = node
32
+ x_assign, y_assign = *node.right_siblings.take(2)
33
+ return unless x_assign && y_assign && swapping_values?(tmp_assign, x_assign, y_assign)
34
+
35
+ add_offense(node, message: message(x_assign, y_assign)) do |corrector|
36
+ range = correction_range(tmp_assign, y_assign)
37
+ corrector.replace(range, replacement(x_assign))
38
+ end
39
+ end
40
+
41
+ SIMPLE_ASSIGNMENT_TYPES.each { |asgn_type| alias_method :"on_#{asgn_type}", :on_asgn }
42
+
43
+ private
44
+
45
+ def allowed_assignment?(node)
46
+ node.parent&.mlhs_type? || node.parent&.shorthand_asgn?
47
+ end
48
+
49
+ def swapping_values?(tmp_assign, x_assign, y_assign)
50
+ simple_assignment?(tmp_assign) &&
51
+ simple_assignment?(x_assign) &&
52
+ simple_assignment?(y_assign) &&
53
+ lhs(x_assign) == rhs(tmp_assign) &&
54
+ lhs(y_assign) == rhs(x_assign) &&
55
+ rhs(y_assign) == lhs(tmp_assign)
56
+ end
57
+
58
+ def simple_assignment?(node)
59
+ SIMPLE_ASSIGNMENT_TYPES.include?(node.type)
60
+ end
61
+
62
+ def message(x_assign, y_assign)
63
+ format(
64
+ MSG,
65
+ x_line: x_assign.first_line,
66
+ y_line: y_assign.first_line,
67
+ replacement: replacement(x_assign)
68
+ )
69
+ end
70
+
71
+ def replacement(x_assign)
72
+ x = lhs(x_assign)
73
+ y = rhs(x_assign)
74
+ "#{x}, #{y} = #{y}, #{x}"
75
+ end
76
+
77
+ def lhs(node)
78
+ case node.type
79
+ when :casgn
80
+ namespace, name, = *node
81
+ if namespace
82
+ "#{namespace.const_name}::#{name}"
83
+ else
84
+ name.to_s
85
+ end
86
+ else
87
+ node.children[0].to_s
88
+ end
89
+ end
90
+
91
+ def rhs(node)
92
+ case node.type
93
+ when :casgn
94
+ node.children[2].source
95
+ else
96
+ node.children[1].source
97
+ end
98
+ end
99
+
100
+ def correction_range(tmp_assign, y_assign)
101
+ range_by_whole_lines(
102
+ range_between(tmp_assign.source_range.begin_pos, y_assign.source_range.end_pos)
103
+ )
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
@@ -8,6 +8,7 @@ module RuboCop
8
8
  # @example
9
9
  # # bad
10
10
  # something.map { |s| s.upcase }
11
+ # something.map { _1.upcase }
11
12
  #
12
13
  # # good
13
14
  # something.map(&:upcase)
@@ -22,9 +23,9 @@ module RuboCop
22
23
 
23
24
  def_node_matcher :proc_node?, '(send (const {nil? cbase} :Proc) :new)'
24
25
  def_node_matcher :symbol_proc?, <<~PATTERN
25
- (block
26
+ ({block numblock}
26
27
  ${(send ...) (super ...) zsuper}
27
- $(args (arg _var))
28
+ ${(args (arg _)) %Integer}
28
29
  (send (lvar _var) $_))
29
30
  PATTERN
30
31
 
@@ -40,11 +41,12 @@ module RuboCop
40
41
  return if proc_node?(dispatch_node)
41
42
  return if %i[lambda proc].include?(dispatch_node.method_name)
42
43
  return if ignored_method?(dispatch_node.method_name)
43
- return if destructuring_block_argument?(arguments_node)
44
+ return if node.block_type? && destructuring_block_argument?(arguments_node)
44
45
 
45
46
  register_offense(node, method_name, dispatch_node.method_name)
46
47
  end
47
48
  end
49
+ alias on_numblock on_block
48
50
 
49
51
  def destructuring_block_argument?(argument_node)
50
52
  argument_node.one? && argument_node.source.include?(',')
@@ -36,6 +36,8 @@ module RuboCop
36
36
  MSG = 'Do not use trailing `_`s in parallel assignment. ' \
37
37
  'Prefer `%<code>s`.'
38
38
  UNDERSCORE = '_'
39
+ DISALLOW = %i[lvasgn splat].freeze
40
+ private_constant :DISALLOW
39
41
 
40
42
  def on_masgn(node)
41
43
  ranges = unneeded_ranges(node)
@@ -64,7 +66,7 @@ module RuboCop
64
66
 
65
67
  def find_first_possible_offense(variables)
66
68
  variables.reduce(nil) do |offense, variable|
67
- break offense unless %i[lvasgn splat].include?(variable.type)
69
+ break offense unless DISALLOW.include?(variable.type)
68
70
 
69
71
  var, = *variable
70
72
  var, = *var
@@ -24,6 +24,15 @@ module RuboCop
24
24
  #
25
25
  # # good
26
26
  # x += 1 until x > 10
27
+ #
28
+ # @example
29
+ # # bad
30
+ # x += 100 while x < 500 # a long comment that makes code too long if it were a single line
31
+ #
32
+ # # good
33
+ # while x < 500 # a long comment that makes code too long if it were a single line
34
+ # x += 100
35
+ # end
27
36
  class WhileUntilModifier < Base
28
37
  include StatementModifier
29
38
  extend AutoCorrector
@@ -99,7 +99,12 @@ module RuboCop
99
99
  def self.forces_for(cops)
100
100
  needed = Hash.new { |h, k| h[k] = [] }
101
101
  cops.each do |cop|
102
- Array(cop.class.joining_forces).each { |force| needed[force] << cop }
102
+ forces = cop.class.joining_forces
103
+ if forces.is_a?(Array)
104
+ forces.each { |force| needed[force] << cop }
105
+ elsif forces
106
+ needed[forces] << cop
107
+ end
103
108
  end
104
109
 
105
110
  needed.map do |force_class, joining_cops|
@@ -53,7 +53,7 @@ module RuboCop
53
53
  end
54
54
 
55
55
  def on_node(syms, sexp, excludes = [], &block)
56
- return to_enum(:on_node, syms, sexp, excludes) unless block_given?
56
+ return to_enum(:on_node, syms, sexp, excludes) unless block
57
57
 
58
58
  yield sexp if Array(syms).include?(sexp.type)
59
59
  return if Array(excludes).include?(sexp.type)
@@ -62,7 +62,7 @@ module RuboCop
62
62
  end
63
63
 
64
64
  def begins_its_line?(range)
65
- (range.source_line =~ /\S/) == range.column
65
+ range.source_line.index(/\S/) == range.column
66
66
  end
67
67
 
68
68
  # Returns, for example, a bare `if` node if the given node is an `if`
@@ -123,6 +123,10 @@ module RuboCop
123
123
  node1.loc.line == node2.loc.line
124
124
  end
125
125
 
126
+ def indent(node)
127
+ ' ' * node.loc.column
128
+ end
129
+
126
130
  def to_supported_styles(enforced_style)
127
131
  enforced_style
128
132
  .sub(/^Enforced/, 'Supported')
@@ -78,7 +78,7 @@ module RuboCop
78
78
  end
79
79
 
80
80
  def each_ancestor(include_self: false, &block)
81
- return to_enum(__method__, include_self: include_self) unless block_given?
81
+ return to_enum(__method__, include_self: include_self) unless block
82
82
 
83
83
  yield self if include_self
84
84
  scan_ancestors(&block)
@@ -61,7 +61,7 @@ module RuboCop
61
61
  end
62
62
 
63
63
  def each_node(&block)
64
- return to_enum(__method__) unless block_given?
64
+ return to_enum(__method__) unless block
65
65
 
66
66
  yield node if naked_top_level?
67
67
  scan_node(node, &block)
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Extensions to the core Hash class
4
+ class Hash
5
+ unless method_defined?(:slice)
6
+ # Adds `Hash#slice` for Ruby 2.4.
7
+ # Returns a hash containing a subset of keys. If a given key is not
8
+ # in the hash, it will not be returned.
9
+ #
10
+ # @return [Hash] hash containing only the keys given.
11
+ #
12
+ # @example
13
+ # { one: 1, two: 2 }.slice(:two, :three) #=> { two: 2 }
14
+ def slice(*keys)
15
+ h = {}
16
+ keys.each { |k| h[k] = self[k] if key?(k) }
17
+ h
18
+ end
19
+ end
20
+ end
@@ -10,18 +10,43 @@ module RuboCop
10
10
  end
11
11
  private_constant :ANY
12
12
 
13
- class << self
14
- attr_reader :parsed_cache
15
- end
16
- @parsed_cache = {}
17
-
18
13
  # @return [Regexp::Expression::Root, nil]
19
- def parsed_tree
20
- str = with_interpolations_blanked
21
- Ext::RegexpNode.parsed_cache[str] ||= begin
22
- Regexp::Parser.parse(str, options: options)
23
- rescue StandardError
24
- nil
14
+ # Note: we extend Regexp nodes to provide `loc` and `expression`
15
+ # see `ext/regexp_parser`.
16
+ attr_reader :parsed_tree
17
+
18
+ if Gem::Version.new(Regexp::Parser::VERSION) >= Gem::Version.new('2.0')
19
+ def assign_properties(*)
20
+ super
21
+
22
+ str = with_interpolations_blanked
23
+ @parsed_tree = begin
24
+ Regexp::Parser.parse(str, options: options)
25
+ rescue StandardError
26
+ nil
27
+ end
28
+ origin = loc.begin.end
29
+ @parsed_tree&.each_expression(true) { |e| e.origin = origin }
30
+ end
31
+ # Please remove this `else` branch when support for regexp_parser 1.8 will be dropped.
32
+ # It's for compatibility with regexp_arser 1.8 and will never be maintained.
33
+ else
34
+ def assign_properties(*)
35
+ super
36
+
37
+ str = with_interpolations_blanked
38
+ begin
39
+ @parsed_tree = Regexp::Parser.parse(str, options: options)
40
+ rescue StandardError
41
+ @parsed_tree = nil
42
+ else
43
+ origin = loc.begin.end
44
+ source = @parsed_tree.to_s
45
+ @parsed_tree.each_expression(true) do |e|
46
+ e.origin = origin
47
+ e.source = source
48
+ end
49
+ end
25
50
  end
26
51
  end
27
52
 
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Ext
5
+ # Extensions for `regexp_parser` gem
6
+ module RegexpParser
7
+ # Source map for RegexpParser nodes
8
+ class Map < ::Parser::Source::Map
9
+ attr_reader :body, :quantifier, :begin, :end
10
+
11
+ def initialize(expression, body:, quantifier: nil, begin_l: nil, end_l: nil)
12
+ @begin = begin_l
13
+ @end = end_l
14
+ @body = body
15
+ @quantifier = quantifier
16
+ super(expression)
17
+ end
18
+ end
19
+
20
+ module Expression
21
+ # Add `expression` and `loc` to all `regexp_parser` nodes
22
+ module Base
23
+ attr_accessor :origin
24
+
25
+ if Gem::Version.new(Regexp::Parser::VERSION) >= Gem::Version.new('2.0')
26
+ # Shortcut to `loc.expression`
27
+ def expression
28
+ @expression ||= origin.adjust(begin_pos: ts, end_pos: ts + full_length)
29
+ end
30
+ # Please remove this `else` branch when support for regexp_parser 1.8 will be dropped.
31
+ # It's for compatibility with regexp_arser 1.8 and will never be maintained.
32
+ else
33
+ attr_accessor :source
34
+
35
+ def start_index
36
+ # ts is a byte index; convert it to a character index
37
+ @start_index ||= source.byteslice(0, ts).length
38
+ end
39
+
40
+ # Shortcut to `loc.expression`
41
+ def expression
42
+ @expression ||= begin
43
+ origin.adjust(begin_pos: start_index, end_pos: start_index + full_length)
44
+ end
45
+ end
46
+ end
47
+
48
+ # @returns a location map like `parser` does, with:
49
+ # - expression: complete expression
50
+ # - quantifier: for `+`, `{1,2}`, etc.
51
+ # - begin/end: for `[` and `]` (only CharacterSet for now)
52
+ #
53
+ # E.g.
54
+ # [a-z]{2,}
55
+ # ^^^^^^^^^ expression
56
+ # ^^^^ quantifier
57
+ # ^^^^^ body
58
+ # ^ begin
59
+ # ^ end
60
+ #
61
+ # Please open issue if you need other locations
62
+ def loc
63
+ @loc ||= begin
64
+ Map.new(expression, **build_location)
65
+ end
66
+ end
67
+
68
+ private
69
+
70
+ def build_location
71
+ return { body: expression } unless (q = quantifier)
72
+
73
+ body = expression.adjust(end_pos: -q.text.length)
74
+ q_loc = expression.with(begin_pos: body.end_pos)
75
+ { body: body, quantifier: q_loc }
76
+ end
77
+ end
78
+
79
+ # Provide `CharacterSet` with `begin` and `end` locations.
80
+ module CharacterSet
81
+ def build_location
82
+ h = super
83
+ body = h[:body]
84
+ h.merge!(
85
+ begin_l: body.with(end_pos: body.begin_pos + 1),
86
+ end_l: body.with(begin_pos: body.end_pos - 1)
87
+ )
88
+ end
89
+ end
90
+ end
91
+ ::Regexp::Expression::Base.include Expression::Base
92
+ ::Regexp::Expression::CharacterSet.include Expression::CharacterSet
93
+ end
94
+ end
95
+ end