rubocop 1.18.4 → 1.21.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 (130) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +65 -13
  4. data/lib/rubocop/cli.rb +18 -0
  5. data/lib/rubocop/config_loader.rb +2 -2
  6. data/lib/rubocop/config_loader_resolver.rb +21 -6
  7. data/lib/rubocop/cop/base.rb +2 -2
  8. data/lib/rubocop/cop/bundler/gem_filename.rb +103 -0
  9. data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +12 -11
  10. data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -1
  11. data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +2 -2
  12. data/lib/rubocop/cop/correctors/line_break_corrector.rb +1 -1
  13. data/lib/rubocop/cop/correctors/require_library_corrector.rb +23 -0
  14. data/lib/rubocop/cop/documentation.rb +1 -1
  15. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -1
  16. data/lib/rubocop/cop/internal_affairs/inherit_deprecated_cop_class.rb +34 -0
  17. data/lib/rubocop/cop/internal_affairs/undefined_config.rb +71 -0
  18. data/lib/rubocop/cop/internal_affairs.rb +2 -0
  19. data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
  20. data/lib/rubocop/cop/layout/class_structure.rb +2 -1
  21. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +9 -0
  22. data/lib/rubocop/cop/layout/end_alignment.rb +3 -2
  23. data/lib/rubocop/cop/layout/hash_alignment.rb +7 -3
  24. data/lib/rubocop/cop/layout/heredoc_indentation.rb +0 -7
  25. data/lib/rubocop/cop/layout/leading_comment_space.rb +2 -2
  26. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +33 -14
  27. data/lib/rubocop/cop/layout/line_length.rb +1 -1
  28. data/lib/rubocop/cop/layout/multiline_block_layout.rb +1 -1
  29. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +3 -0
  30. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +22 -9
  31. data/lib/rubocop/cop/layout/single_line_block_chain.rb +15 -4
  32. data/lib/rubocop/cop/layout/space_after_not.rb +1 -0
  33. data/lib/rubocop/cop/layout/space_around_equals_in_parameter_default.rb +2 -1
  34. data/lib/rubocop/cop/layout/space_around_keyword.rb +2 -2
  35. data/lib/rubocop/cop/layout/space_around_operators.rb +8 -1
  36. data/lib/rubocop/cop/layout/space_before_brackets.rb +1 -0
  37. data/lib/rubocop/cop/layout/space_before_comment.rb +1 -1
  38. data/lib/rubocop/cop/layout/space_inside_parens.rb +5 -5
  39. data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +1 -1
  40. data/lib/rubocop/cop/layout/trailing_whitespace.rb +24 -1
  41. data/lib/rubocop/cop/lint/ambiguous_operator_precedence.rb +107 -0
  42. data/lib/rubocop/cop/lint/ambiguous_range.rb +105 -0
  43. data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +5 -2
  44. data/lib/rubocop/cop/lint/debugger.rb +2 -4
  45. data/lib/rubocop/cop/lint/duplicate_methods.rb +8 -5
  46. data/lib/rubocop/cop/lint/empty_in_pattern.rb +1 -1
  47. data/lib/rubocop/cop/lint/erb_new_arguments.rb +1 -1
  48. data/lib/rubocop/cop/lint/float_out_of_range.rb +1 -1
  49. data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +67 -0
  50. data/lib/rubocop/cop/lint/number_conversion.rb +7 -1
  51. data/lib/rubocop/cop/lint/shadowed_argument.rb +1 -1
  52. data/lib/rubocop/cop/lint/unused_method_argument.rb +2 -3
  53. data/lib/rubocop/cop/lint/useless_times.rb +1 -1
  54. data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
  55. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -1
  56. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
  57. data/lib/rubocop/cop/mixin/annotation_comment.rb +57 -34
  58. data/lib/rubocop/cop/mixin/code_length.rb +1 -1
  59. data/lib/rubocop/cop/mixin/documentation_comment.rb +5 -2
  60. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +19 -1
  61. data/lib/rubocop/cop/mixin/heredoc.rb +7 -0
  62. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +2 -2
  63. data/lib/rubocop/cop/mixin/percent_array.rb +13 -7
  64. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +9 -1
  65. data/lib/rubocop/cop/mixin/require_library.rb +59 -0
  66. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  67. data/lib/rubocop/cop/naming/ascii_identifiers.rb +0 -3
  68. data/lib/rubocop/cop/naming/constant_name.rb +1 -1
  69. data/lib/rubocop/cop/naming/inclusive_language.rb +27 -10
  70. data/lib/rubocop/cop/style/accessor_grouping.rb +2 -2
  71. data/lib/rubocop/cop/style/and_or.rb +4 -0
  72. data/lib/rubocop/cop/style/ascii_comments.rb +0 -3
  73. data/lib/rubocop/cop/style/block_delimiters.rb +39 -6
  74. data/lib/rubocop/cop/style/case_equality.rb +6 -9
  75. data/lib/rubocop/cop/style/collection_methods.rb +2 -1
  76. data/lib/rubocop/cop/style/comment_annotation.rb +25 -39
  77. data/lib/rubocop/cop/style/commented_keyword.rb +2 -1
  78. data/lib/rubocop/cop/style/conditional_assignment.rb +19 -5
  79. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +1 -1
  80. data/lib/rubocop/cop/style/documentation.rb +23 -8
  81. data/lib/rubocop/cop/style/double_negation.rb +12 -1
  82. data/lib/rubocop/cop/style/empty_method.rb +1 -1
  83. data/lib/rubocop/cop/style/encoding.rb +26 -15
  84. data/lib/rubocop/cop/style/explicit_block_argument.rb +46 -11
  85. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +1 -1
  86. data/lib/rubocop/cop/style/hash_as_last_array_item.rb +11 -0
  87. data/lib/rubocop/cop/style/hash_except.rb +4 -3
  88. data/lib/rubocop/cop/style/hash_transform_keys.rb +0 -3
  89. data/lib/rubocop/cop/style/identical_conditional_branches.rb +30 -5
  90. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +3 -2
  91. data/lib/rubocop/cop/style/lambda_call.rb +1 -1
  92. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +6 -6
  93. data/lib/rubocop/cop/style/method_def_parentheses.rb +10 -1
  94. data/lib/rubocop/cop/style/missing_else.rb +7 -0
  95. data/lib/rubocop/cop/style/mutable_constant.rb +68 -6
  96. data/lib/rubocop/cop/style/negated_if.rb +1 -1
  97. data/lib/rubocop/cop/style/negated_unless.rb +1 -1
  98. data/lib/rubocop/cop/style/non_nil_check.rb +2 -2
  99. data/lib/rubocop/cop/style/not.rb +2 -2
  100. data/lib/rubocop/cop/style/parallel_assignment.rb +1 -1
  101. data/lib/rubocop/cop/style/percent_q_literals.rb +2 -2
  102. data/lib/rubocop/cop/style/raise_args.rb +1 -1
  103. data/lib/rubocop/cop/style/redundant_begin.rb +25 -0
  104. data/lib/rubocop/cop/style/redundant_condition.rb +2 -3
  105. data/lib/rubocop/cop/style/redundant_freeze.rb +4 -3
  106. data/lib/rubocop/cop/style/redundant_interpolation.rb +1 -1
  107. data/lib/rubocop/cop/style/redundant_percent_q.rb +2 -3
  108. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +83 -0
  109. data/lib/rubocop/cop/style/redundant_sort.rb +19 -4
  110. data/lib/rubocop/cop/style/regexp_literal.rb +3 -3
  111. data/lib/rubocop/cop/style/return_nil.rb +2 -1
  112. data/lib/rubocop/cop/style/semicolon.rb +32 -24
  113. data/lib/rubocop/cop/style/single_line_block_params.rb +3 -1
  114. data/lib/rubocop/cop/style/sole_nested_conditional.rb +4 -0
  115. data/lib/rubocop/cop/style/special_global_vars.rb +21 -0
  116. data/lib/rubocop/cop/style/static_class.rb +1 -2
  117. data/lib/rubocop/cop/style/string_concatenation.rb +1 -1
  118. data/lib/rubocop/cop/style/struct_inheritance.rb +3 -0
  119. data/lib/rubocop/cop/style/symbol_array.rb +3 -3
  120. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  121. data/lib/rubocop/cop/style/word_array.rb +23 -5
  122. data/lib/rubocop/cop/style/yoda_condition.rb +4 -7
  123. data/lib/rubocop/cop/util.rb +7 -2
  124. data/lib/rubocop/magic_comment.rb +44 -15
  125. data/lib/rubocop/options.rb +1 -1
  126. data/lib/rubocop/result_cache.rb +1 -1
  127. data/lib/rubocop/runner.rb +1 -2
  128. data/lib/rubocop/version.rb +1 -1
  129. data/lib/rubocop.rb +9 -2
  130. metadata +14 -5
@@ -60,8 +60,8 @@ module RuboCop
60
60
  # @!method redundant_sort?(node)
61
61
  def_node_matcher :redundant_sort?, <<~MATCHER
62
62
  {
63
- (send $(send _ $:sort ...) ${:last :first})
64
- (send $(send _ $:sort ...) ${:[] :at :slice} {(int 0) (int -1)})
63
+ (send $(send _ $:sort) ${:last :first})
64
+ (send $(send _ $:sort) ${:[] :at :slice} {(int 0) (int -1)})
65
65
 
66
66
  (send $(send _ $:sort_by _) ${:last :first})
67
67
  (send $(send _ $:sort_by _) ${:[] :at :slice} {(int 0) (int -1)})
@@ -76,13 +76,30 @@ module RuboCop
76
76
 
77
77
  def on_send(node)
78
78
  if (sort_node, sorter, accessor = redundant_sort?(node.parent))
79
+ return if use_size_method_in_block?(sort_node)
80
+
79
81
  ancestor = node.parent
80
82
  elsif (sort_node, sorter, accessor = redundant_sort?(node.parent&.parent))
83
+ return if use_size_method_in_block?(sort_node)
84
+
81
85
  ancestor = node.parent.parent
82
86
  else
83
87
  return
84
88
  end
85
89
 
90
+ register_offense(ancestor, sort_node, sorter, accessor)
91
+ end
92
+
93
+ private
94
+
95
+ def use_size_method_in_block?(sort_node)
96
+ return true if sort_node.send_type? && sort_node.block_node&.body&.method?(:size)
97
+ return false unless sort_node.block_argument?
98
+
99
+ sort_node.last_argument.children.first.value == :size
100
+ end
101
+
102
+ def register_offense(ancestor, sort_node, sorter, accessor)
86
103
  message = message(ancestor, sorter, accessor)
87
104
 
88
105
  add_offense(offense_range(sort_node, ancestor), message: message) do |corrector|
@@ -90,8 +107,6 @@ module RuboCop
90
107
  end
91
108
  end
92
109
 
93
- private
94
-
95
110
  def autocorrect(corrector, node, sort_node, sorter, accessor)
96
111
  # Remove accessor, e.g. `first` or `[-1]`.
97
112
  corrector.remove(range_between(accessor_start(node), node.loc.expression.end_pos))
@@ -107,7 +107,7 @@ module RuboCop
107
107
  private
108
108
 
109
109
  def allowed_slash_literal?(node)
110
- style == :slashes && !contains_disallowed_slash?(node) || allowed_mixed_slash?(node)
110
+ (style == :slashes && !contains_disallowed_slash?(node)) || allowed_mixed_slash?(node)
111
111
  end
112
112
 
113
113
  def allowed_mixed_slash?(node)
@@ -115,13 +115,13 @@ module RuboCop
115
115
  end
116
116
 
117
117
  def allowed_percent_r_literal?(node)
118
- style == :slashes && contains_disallowed_slash?(node) ||
118
+ (style == :slashes && contains_disallowed_slash?(node)) ||
119
119
  style == :percent_r ||
120
120
  allowed_mixed_percent_r?(node) || allowed_omit_parentheses_with_percent_r_literal?(node)
121
121
  end
122
122
 
123
123
  def allowed_mixed_percent_r?(node)
124
- style == :mixed && node.multiline? || contains_disallowed_slash?(node)
124
+ (style == :mixed && node.multiline?) || contains_disallowed_slash?(node)
125
125
  end
126
126
 
127
127
  def contains_disallowed_slash?(node)
@@ -74,7 +74,8 @@ module RuboCop
74
74
  end
75
75
 
76
76
  def correct_style?(node)
77
- style == :return && !return_nil_node?(node) || style == :return_nil && !return_node?(node)
77
+ (style == :return && !return_nil_node?(node)) ||
78
+ (style == :return_nil && !return_node?(node))
78
79
  end
79
80
 
80
81
  def scoped_node?(node)
@@ -32,38 +32,29 @@ module RuboCop
32
32
 
33
33
  MSG = 'Do not use semicolons to terminate expressions.'
34
34
 
35
+ def self.autocorrect_incompatible_with
36
+ [Style::SingleLineMethods]
37
+ end
38
+
35
39
  def on_new_investigation
36
40
  return if processed_source.blank?
37
41
 
38
- @processed_source = processed_source
39
-
40
42
  check_for_line_terminator_or_opener
41
43
  end
42
44
 
43
- def on_begin(node) # rubocop:todo Metrics/CyclomaticComplexity
45
+ def on_begin(node)
44
46
  return if cop_config['AllowAsExpressionSeparator']
45
47
 
46
48
  exprs = node.children
47
49
 
48
50
  return if exprs.size < 2
49
51
 
50
- # create a map matching lines to the number of expressions on them
51
- exprs_lines = exprs.map(&:first_line)
52
- lines = exprs_lines.group_by(&:itself)
53
-
54
- lines.each do |line, expr_on_line|
52
+ expressions_per_line(exprs).each do |line, expr_on_line|
55
53
  # Every line with more than one expression on it is a
56
54
  # potential offense
57
55
  next unless expr_on_line.size > 1
58
56
 
59
- # TODO: Find the correct position of the semicolon. We don't know
60
- # if the first semicolon on the line is a separator of
61
- # expressions. It's just a guess.
62
- column = @processed_source[line - 1].index(';')
63
-
64
- next unless column
65
-
66
- convention_on(line, column, false)
57
+ find_semicolon_positions(line) { |pos| register_semicolon(line, pos, true) }
67
58
  end
68
59
  end
69
60
 
@@ -71,9 +62,9 @@ module RuboCop
71
62
 
72
63
  def check_for_line_terminator_or_opener
73
64
  # Make the obvious check first
74
- return unless @processed_source.raw_source.include?(';')
65
+ return unless processed_source.raw_source.include?(';')
75
66
 
76
- each_semicolon { |line, column| convention_on(line, column, true) }
67
+ each_semicolon { |line, column| register_semicolon(line, column, false) }
77
68
  end
78
69
 
79
70
  def each_semicolon
@@ -84,15 +75,32 @@ module RuboCop
84
75
  end
85
76
 
86
77
  def tokens_for_lines
87
- @processed_source.tokens.group_by(&:line)
78
+ processed_source.tokens.group_by(&:line)
88
79
  end
89
80
 
90
- def convention_on(line, column, autocorrect)
91
- range = source_range(@processed_source.buffer, line, column)
92
- # Don't attempt to autocorrect if semicolon is separating statements
93
- # on the same line
81
+ def register_semicolon(line, column, after_expression)
82
+ range = source_range(processed_source.buffer, line, column)
83
+
94
84
  add_offense(range) do |corrector|
95
- corrector.remove(range) if autocorrect
85
+ if after_expression
86
+ corrector.replace(range, "\n")
87
+ else
88
+ corrector.remove(range)
89
+ end
90
+ end
91
+ end
92
+
93
+ def expressions_per_line(exprs)
94
+ # create a map matching lines to the number of expressions on them
95
+ exprs_lines = exprs.map(&:first_line)
96
+ exprs_lines.group_by(&:itself)
97
+ end
98
+
99
+ def find_semicolon_positions(line)
100
+ # Scan for all the semicolons on the line
101
+ semicolons = processed_source[line - 1].enum_for(:scan, ';')
102
+ semicolons.each do
103
+ yield Regexp.last_match.begin(0)
96
104
  end
97
105
  end
98
106
  end
@@ -109,7 +109,9 @@ module RuboCop
109
109
  # we remove any leading underscores before comparing.
110
110
  actual_args_no_underscores = actual_args.map { |arg| arg.to_s.sub(/^_+/, '') }
111
111
 
112
- actual_args_no_underscores == target_args(method_name)
112
+ # Allow the arguments if the names match but not all are given
113
+ expected_args = target_args(method_name).first(actual_args_no_underscores.size)
114
+ actual_args_no_underscores == expected_args
113
115
  end
114
116
  end
115
117
  end
@@ -38,6 +38,10 @@ module RuboCop
38
38
 
39
39
  MSG = 'Consider merging nested conditions into outer `%<conditional_type>s` conditions.'
40
40
 
41
+ def self.autocorrect_incompatible_with
42
+ [Style::NegatedIf, Style::NegatedUnless]
43
+ end
44
+
41
45
  def on_if(node)
42
46
  return if node.ternary? || node.else? || node.elsif?
43
47
 
@@ -5,9 +5,14 @@ module RuboCop
5
5
  module Style
6
6
  #
7
7
  # This cop looks for uses of Perl-style global variables.
8
+ # Correcting to global variables in the 'English' library
9
+ # will add a require statement to the top of the file if
10
+ # enabled by RequireEnglish config.
8
11
  #
9
12
  # @example EnforcedStyle: use_english_names (default)
10
13
  # # good
14
+ # require 'English' # or this could be in another file.
15
+ #
11
16
  # puts $LOAD_PATH
12
17
  # puts $LOADED_FEATURES
13
18
  # puts $PROGRAM_NAME
@@ -50,6 +55,8 @@ module RuboCop
50
55
  #
51
56
  class SpecialGlobalVars < Base
52
57
  include ConfigurableEnforcedStyle
58
+ include RangeHelp
59
+ include RequireLibrary
53
60
  extend AutoCorrector
54
61
 
55
62
  MSG_BOTH = 'Prefer `%<prefer>s` from the stdlib \'English\' ' \
@@ -90,6 +97,8 @@ module RuboCop
90
97
  # Anything *not* in this set is provided by the English library.
91
98
  NON_ENGLISH_VARS = Set.new(%i[$LOAD_PATH $LOADED_FEATURES $PROGRAM_NAME ARGV]).freeze
92
99
 
100
+ LIBRARY_NAME = 'English'
101
+
93
102
  def on_gvar(node)
94
103
  global_var, = *node
95
104
 
@@ -117,6 +126,8 @@ module RuboCop
117
126
  def autocorrect(corrector, node, global_var)
118
127
  node = node.parent while node.parent&.begin_type? && node.parent.children.one?
119
128
 
129
+ ensure_required(corrector, node, LIBRARY_NAME) if should_require_english?(global_var)
130
+
120
131
  corrector.replace(node, replacement(node, global_var))
121
132
  end
122
133
 
@@ -172,6 +183,16 @@ module RuboCop
172
183
 
173
184
  "{#{preferred_name}}"
174
185
  end
186
+
187
+ def add_require_english?
188
+ cop_config['RequireEnglish']
189
+ end
190
+
191
+ def should_require_english?(global_var)
192
+ style == :use_english_names &&
193
+ add_require_english? &&
194
+ !NON_ENGLISH_VARS.include?(preferred_names(global_var).first)
195
+ end
175
196
  end
176
197
  end
177
198
  end
@@ -60,8 +60,7 @@ module RuboCop
60
60
  return false if nodes.empty?
61
61
 
62
62
  nodes.all? do |node|
63
- node_visibility(node) == :public &&
64
- node.defs_type? ||
63
+ (node_visibility(node) == :public && node.defs_type?) ||
65
64
  sclass_convertible_to_module?(node) ||
66
65
  node.equals_asgn? ||
67
66
  extend_call?(node)
@@ -93,7 +93,7 @@ module RuboCop
93
93
 
94
94
  def offensive_for_mode?(receiver_node)
95
95
  mode = cop_config['Mode'].to_sym
96
- mode == :aggressive || mode == :conservative && receiver_node.str_type?
96
+ mode == :aggressive || (mode == :conservative && receiver_node.str_type?)
97
97
  end
98
98
 
99
99
  def line_end_concatenation?(node)
@@ -5,6 +5,9 @@ module RuboCop
5
5
  module Style
6
6
  # This cop checks for inheritance from Struct.new.
7
7
  #
8
+ # It is marked as unsafe auto-correction because it will change the
9
+ # inheritance tree (e.g. return value of `Module#ancestors`).
10
+ #
8
11
  # @example
9
12
  # # bad
10
13
  # class Person < Struct.new(:first_name, :last_name)
@@ -35,7 +35,7 @@ module RuboCop
35
35
  extend AutoCorrector
36
36
 
37
37
  PERCENT_MSG = 'Use `%i` or `%I` for an array of symbols.'
38
- ARRAY_MSG = 'Use `[]` for an array of symbols.'
38
+ ARRAY_MSG = 'Use `%<prefer>s` for an array of symbols.'
39
39
 
40
40
  class << self
41
41
  attr_accessor :largest_brackets
@@ -60,7 +60,7 @@ module RuboCop
60
60
  end
61
61
  end
62
62
 
63
- def correct_bracketed(corrector, node)
63
+ def build_bracketed_array(node)
64
64
  syms = node.children.map do |c|
65
65
  if c.dsym_type?
66
66
  string_literal = to_string_literal(c.source)
@@ -71,7 +71,7 @@ module RuboCop
71
71
  end
72
72
  end
73
73
 
74
- corrector.replace(node, "[#{syms.join(', ')}]")
74
+ "[#{syms.join(', ')}]"
75
75
  end
76
76
 
77
77
  def to_symbol_literal(string)
@@ -192,7 +192,7 @@ module RuboCop
192
192
 
193
193
  def allowed_method_name?(node)
194
194
  allowed_method_names.include?(node.method_name) ||
195
- exact_name_match? && !names_match?(node)
195
+ (exact_name_match? && !names_match?(node))
196
196
  end
197
197
 
198
198
  def allowed_writer?(method_name)
@@ -9,6 +9,9 @@ module RuboCop
9
9
  # Alternatively, it can check for uses of the %w() syntax, in projects
10
10
  # which do not want to include that syntax.
11
11
  #
12
+ # NOTE: When using the `percent` style, %w() arrays containing a space
13
+ # will be registered as offenses.
14
+ #
12
15
  # Configuration option: MinSize
13
16
  # If set, arrays with fewer elements than this value will not trigger the
14
17
  # cop. For example, a `MinSize` of `3` will not enforce a style on an
@@ -21,12 +24,18 @@ module RuboCop
21
24
  # # bad
22
25
  # ['foo', 'bar', 'baz']
23
26
  #
27
+ # # bad (contains spaces)
28
+ # %w[foo\ bar baz\ quux]
29
+ #
24
30
  # @example EnforcedStyle: brackets
25
31
  # # good
26
32
  # ['foo', 'bar', 'baz']
27
33
  #
28
34
  # # bad
29
35
  # %w[foo bar baz]
36
+ #
37
+ # # good (contains spaces)
38
+ # ['foo bar', 'baz quux']
30
39
  class WordArray < Base
31
40
  include ArrayMinSize
32
41
  include ArraySyntax
@@ -35,7 +44,7 @@ module RuboCop
35
44
  extend AutoCorrector
36
45
 
37
46
  PERCENT_MSG = 'Use `%w` or `%W` for an array of words.'
38
- ARRAY_MSG = 'Use `[]` for an array of words.'
47
+ ARRAY_MSG = 'Use `%<prefer>s` for an array of words.'
39
48
 
40
49
  class << self
41
50
  attr_accessor :largest_brackets
@@ -53,18 +62,27 @@ module RuboCop
53
62
 
54
63
  private
55
64
 
56
- def complex_content?(strings)
65
+ def complex_content?(strings, complex_regex: word_regex)
57
66
  strings.any? do |s|
67
+ next unless s.str_content
68
+
58
69
  string = s.str_content.dup.force_encoding(::Encoding::UTF_8)
59
- !string.valid_encoding? || !word_regex.match?(string) || / /.match?(string)
70
+ !string.valid_encoding? ||
71
+ (complex_regex && !complex_regex.match?(string)) ||
72
+ / /.match?(string)
60
73
  end
61
74
  end
62
75
 
76
+ def invalid_percent_array_contents?(node)
77
+ # Disallow %w() arrays that contain invalid encoding or spaces
78
+ complex_content?(node.values, complex_regex: false)
79
+ end
80
+
63
81
  def word_regex
64
82
  Regexp.new(cop_config['WordRegex'])
65
83
  end
66
84
 
67
- def correct_bracketed(corrector, node)
85
+ def build_bracketed_array(node)
68
86
  words = node.children.map do |word|
69
87
  if word.dstr_type?
70
88
  string_literal = to_string_literal(word.source)
@@ -75,7 +93,7 @@ module RuboCop
75
93
  end
76
94
  end
77
95
 
78
- corrector.replace(node, "[#{words.join(', ')}]")
96
+ "[#{words.join(', ')}]"
79
97
  end
80
98
  end
81
99
  end
@@ -58,14 +58,11 @@ module RuboCop
58
58
  extend AutoCorrector
59
59
 
60
60
  MSG = 'Reverse the order of the operands `%<source>s`.'
61
-
62
61
  REVERSE_COMPARISON = { '<' => '>', '<=' => '>=', '>' => '<', '>=' => '<=' }.freeze
63
-
64
62
  EQUALITY_OPERATORS = %i[== !=].freeze
65
-
66
63
  NONCOMMUTATIVE_OPERATORS = %i[===].freeze
67
-
68
64
  PROGRAM_NAMES = %i[$0 $PROGRAM_NAME].freeze
65
+ RESTRICT_ON_SEND = RuboCop::AST::Node::COMPARISON_OPERATORS
69
66
 
70
67
  # @!method file_constant_equal_program_name?(node)
71
68
  def_node_matcher :file_constant_equal_program_name?, <<~PATTERN
@@ -74,7 +71,7 @@ module RuboCop
74
71
 
75
72
  def on_send(node)
76
73
  return unless yoda_compatible_condition?(node)
77
- return if equality_only? && non_equality_operator?(node) ||
74
+ return if (equality_only? && non_equality_operator?(node)) ||
78
75
  file_constant_equal_program_name?(node)
79
76
 
80
77
  valid_yoda?(node) || add_offense(node) do |corrector|
@@ -102,8 +99,8 @@ module RuboCop
102
99
  lhs = node.receiver
103
100
  rhs = node.first_argument
104
101
 
105
- return true if lhs.literal? && rhs.literal? ||
106
- !lhs.literal? && !rhs.literal? ||
102
+ return true if (lhs.literal? && rhs.literal?) ||
103
+ (!lhs.literal? && !rhs.literal?) ||
107
104
  interpolation?(lhs)
108
105
 
109
106
  enforce_yoda? ? lhs.literal? : rhs.literal?