rubocop 1.19.1 → 1.22.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 (181) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +86 -14
  4. data/lib/rubocop/config.rb +5 -0
  5. data/lib/rubocop/config_loader.rb +4 -2
  6. data/lib/rubocop/config_validator.rb +9 -1
  7. data/lib/rubocop/cop/base.rb +3 -3
  8. data/lib/rubocop/cop/bundler/gem_filename.rb +103 -0
  9. data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +45 -21
  10. data/lib/rubocop/cop/bundler/ordered_gems.rb +3 -12
  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/ordered_gem_corrector.rb +11 -10
  14. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +3 -12
  15. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +1 -1
  16. data/lib/rubocop/cop/generator.rb +14 -8
  17. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -1
  18. data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
  19. data/lib/rubocop/cop/layout/class_structure.rb +2 -1
  20. data/lib/rubocop/cop/layout/dot_position.rb +31 -4
  21. data/lib/rubocop/cop/layout/end_alignment.rb +1 -1
  22. data/lib/rubocop/cop/layout/leading_comment_space.rb +1 -1
  23. data/lib/rubocop/cop/layout/line_length.rb +8 -6
  24. data/lib/rubocop/cop/layout/multiline_block_layout.rb +1 -1
  25. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +3 -0
  26. data/lib/rubocop/cop/layout/redundant_line_break.rb +1 -0
  27. data/lib/rubocop/cop/layout/single_line_block_chain.rb +15 -4
  28. data/lib/rubocop/cop/layout/space_after_not.rb +1 -0
  29. data/lib/rubocop/cop/layout/space_around_equals_in_parameter_default.rb +2 -1
  30. data/lib/rubocop/cop/layout/space_around_keyword.rb +2 -2
  31. data/lib/rubocop/cop/layout/space_before_brackets.rb +1 -0
  32. data/lib/rubocop/cop/layout/space_inside_parens.rb +74 -24
  33. data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +1 -1
  34. data/lib/rubocop/cop/lint/ambiguous_operator_precedence.rb +111 -0
  35. data/lib/rubocop/cop/lint/ambiguous_range.rb +8 -8
  36. data/lib/rubocop/cop/lint/assignment_in_condition.rb +7 -5
  37. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +18 -5
  38. data/lib/rubocop/cop/lint/boolean_symbol.rb +5 -0
  39. data/lib/rubocop/cop/lint/debugger.rb +2 -4
  40. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +4 -4
  41. data/lib/rubocop/cop/lint/disjunctive_assignment_in_constructor.rb +24 -1
  42. data/lib/rubocop/cop/lint/else_layout.rb +9 -5
  43. data/lib/rubocop/cop/lint/empty_in_pattern.rb +1 -1
  44. data/lib/rubocop/cop/lint/erb_new_arguments.rb +1 -1
  45. data/lib/rubocop/cop/lint/float_out_of_range.rb +1 -1
  46. data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +12 -3
  47. data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +67 -0
  48. data/lib/rubocop/cop/lint/interpolation_check.rb +5 -0
  49. data/lib/rubocop/cop/lint/loop.rb +4 -3
  50. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +5 -1
  51. data/lib/rubocop/cop/lint/number_conversion.rb +12 -1
  52. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -1
  53. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +4 -2
  54. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +17 -0
  55. data/lib/rubocop/cop/lint/percent_string_array.rb +10 -0
  56. data/lib/rubocop/cop/lint/raise_exception.rb +4 -0
  57. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +5 -4
  58. data/lib/rubocop/cop/lint/require_relative_self_path.rb +50 -0
  59. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +1 -1
  60. data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
  61. data/lib/rubocop/cop/lint/triple_quotes.rb +1 -1
  62. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +8 -3
  63. data/lib/rubocop/cop/lint/unused_method_argument.rb +2 -3
  64. data/lib/rubocop/cop/lint/useless_method_definition.rb +3 -2
  65. data/lib/rubocop/cop/lint/useless_setter_call.rb +7 -4
  66. data/lib/rubocop/cop/lint/useless_times.rb +4 -3
  67. data/lib/rubocop/cop/metrics/abc_size.rb +6 -0
  68. data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
  69. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -1
  70. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
  71. data/lib/rubocop/cop/mixin/annotation_comment.rb +57 -34
  72. data/lib/rubocop/cop/mixin/code_length.rb +1 -1
  73. data/lib/rubocop/cop/mixin/documentation_comment.rb +5 -2
  74. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +23 -1
  75. data/lib/rubocop/cop/mixin/heredoc.rb +1 -3
  76. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +2 -2
  77. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +9 -1
  78. data/lib/rubocop/cop/mixin/percent_array.rb +6 -1
  79. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +9 -1
  80. data/lib/rubocop/cop/mixin/string_literals_help.rb +5 -1
  81. data/lib/rubocop/cop/naming/ascii_identifiers.rb +0 -3
  82. data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
  83. data/lib/rubocop/cop/naming/constant_name.rb +1 -1
  84. data/lib/rubocop/cop/naming/inclusive_language.rb +9 -9
  85. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +5 -4
  86. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +7 -0
  87. data/lib/rubocop/cop/security/io_methods.rb +49 -0
  88. data/lib/rubocop/cop/security/json_load.rb +8 -7
  89. data/lib/rubocop/cop/security/open.rb +4 -0
  90. data/lib/rubocop/cop/security/yaml_load.rb +4 -0
  91. data/lib/rubocop/cop/style/accessor_grouping.rb +2 -2
  92. data/lib/rubocop/cop/style/and_or.rb +5 -0
  93. data/lib/rubocop/cop/style/arguments_forwarding.rb +13 -2
  94. data/lib/rubocop/cop/style/array_coercion.rb +21 -3
  95. data/lib/rubocop/cop/style/ascii_comments.rb +0 -3
  96. data/lib/rubocop/cop/style/block_delimiters.rb +23 -6
  97. data/lib/rubocop/cop/style/case_equality.rb +6 -9
  98. data/lib/rubocop/cop/style/case_like_if.rb +5 -0
  99. data/lib/rubocop/cop/style/class_and_module_children.rb +9 -0
  100. data/lib/rubocop/cop/style/collection_compact.rb +7 -5
  101. data/lib/rubocop/cop/style/collection_methods.rb +8 -6
  102. data/lib/rubocop/cop/style/combinable_loops.rb +3 -2
  103. data/lib/rubocop/cop/style/comment_annotation.rb +25 -39
  104. data/lib/rubocop/cop/style/commented_keyword.rb +4 -1
  105. data/lib/rubocop/cop/style/date_time.rb +5 -0
  106. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +1 -1
  107. data/lib/rubocop/cop/style/documentation.rb +23 -8
  108. data/lib/rubocop/cop/style/double_negation.rb +15 -5
  109. data/lib/rubocop/cop/style/empty_method.rb +1 -1
  110. data/lib/rubocop/cop/style/explicit_block_argument.rb +21 -11
  111. data/lib/rubocop/cop/style/float_division.rb +10 -2
  112. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +7 -2
  113. data/lib/rubocop/cop/style/global_std_stream.rb +4 -0
  114. data/lib/rubocop/cop/style/hash_each_methods.rb +5 -0
  115. data/lib/rubocop/cop/style/hash_except.rb +4 -3
  116. data/lib/rubocop/cop/style/hash_transform_keys.rb +4 -6
  117. data/lib/rubocop/cop/style/hash_transform_values.rb +4 -6
  118. data/lib/rubocop/cop/style/identical_conditional_branches.rb +18 -16
  119. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +18 -4
  120. data/lib/rubocop/cop/style/infinite_loop.rb +4 -3
  121. data/lib/rubocop/cop/style/inverse_methods.rb +9 -2
  122. data/lib/rubocop/cop/style/lambda_call.rb +1 -1
  123. data/lib/rubocop/cop/style/line_end_concatenation.rb +13 -0
  124. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +6 -6
  125. data/lib/rubocop/cop/style/module_function.rb +8 -9
  126. data/lib/rubocop/cop/style/mutable_constant.rb +73 -6
  127. data/lib/rubocop/cop/style/negated_if.rb +1 -1
  128. data/lib/rubocop/cop/style/negated_unless.rb +1 -1
  129. data/lib/rubocop/cop/style/non_nil_check.rb +2 -2
  130. data/lib/rubocop/cop/style/not.rb +2 -2
  131. data/lib/rubocop/cop/style/numbered_parameters.rb +46 -0
  132. data/lib/rubocop/cop/style/numbered_parameters_limit.rb +50 -0
  133. data/lib/rubocop/cop/style/numeric_literals.rb +7 -8
  134. data/lib/rubocop/cop/style/numeric_predicate.rb +5 -0
  135. data/lib/rubocop/cop/style/optional_arguments.rb +4 -0
  136. data/lib/rubocop/cop/style/optional_boolean_parameter.rb +14 -4
  137. data/lib/rubocop/cop/style/parallel_assignment.rb +1 -1
  138. data/lib/rubocop/cop/style/percent_q_literals.rb +2 -2
  139. data/lib/rubocop/cop/style/preferred_hash_methods.rb +9 -4
  140. data/lib/rubocop/cop/style/quoted_symbols.rb +10 -6
  141. data/lib/rubocop/cop/style/raise_args.rb +1 -1
  142. data/lib/rubocop/cop/style/redundant_argument.rb +19 -9
  143. data/lib/rubocop/cop/style/redundant_condition.rb +2 -3
  144. data/lib/rubocop/cop/style/redundant_fetch_block.rb +4 -0
  145. data/lib/rubocop/cop/style/redundant_file_extension_in_require.rb +12 -3
  146. data/lib/rubocop/cop/style/redundant_freeze.rb +4 -4
  147. data/lib/rubocop/cop/style/redundant_interpolation.rb +1 -1
  148. data/lib/rubocop/cop/style/redundant_percent_q.rb +2 -3
  149. data/lib/rubocop/cop/style/redundant_self.rb +10 -0
  150. data/lib/rubocop/cop/style/redundant_self_assignment.rb +4 -3
  151. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +1 -1
  152. data/lib/rubocop/cop/style/redundant_sort.rb +51 -18
  153. data/lib/rubocop/cop/style/regexp_literal.rb +3 -3
  154. data/lib/rubocop/cop/style/return_nil.rb +2 -1
  155. data/lib/rubocop/cop/style/safe_navigation.rb +13 -2
  156. data/lib/rubocop/cop/style/select_by_regexp.rb +133 -0
  157. data/lib/rubocop/cop/style/single_argument_dig.rb +5 -0
  158. data/lib/rubocop/cop/style/slicing_with_range.rb +13 -0
  159. data/lib/rubocop/cop/style/special_global_vars.rb +4 -0
  160. data/lib/rubocop/cop/style/static_class.rb +5 -5
  161. data/lib/rubocop/cop/style/string_chars.rb +4 -2
  162. data/lib/rubocop/cop/style/string_concatenation.rb +5 -1
  163. data/lib/rubocop/cop/style/string_hash_keys.rb +4 -0
  164. data/lib/rubocop/cop/style/struct_inheritance.rb +4 -0
  165. data/lib/rubocop/cop/style/swap_values.rb +4 -2
  166. data/lib/rubocop/cop/style/symbol_proc.rb +26 -0
  167. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +19 -0
  168. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  169. data/lib/rubocop/cop/style/yoda_condition.rb +24 -7
  170. data/lib/rubocop/cop/style/zero_length_predicate.rb +6 -0
  171. data/lib/rubocop/cop/util.rb +4 -3
  172. data/lib/rubocop/cops_documentation_generator.rb +17 -5
  173. data/lib/rubocop/options.rb +126 -112
  174. data/lib/rubocop/rake_task.rb +1 -1
  175. data/lib/rubocop/result_cache.rb +3 -3
  176. data/lib/rubocop/rspec/cop_helper.rb +1 -1
  177. data/lib/rubocop/rspec/expect_offense.rb +6 -2
  178. data/lib/rubocop/runner.rb +2 -3
  179. data/lib/rubocop/version.rb +1 -1
  180. data/lib/rubocop.rb +10 -2
  181. metadata +17 -9
@@ -5,8 +5,10 @@ module RuboCop
5
5
  module Style
6
6
  # Checks for uses of `String#split` with empty string or regexp literal argument.
7
7
  #
8
- # This cop is marked as unsafe. But probably it's quite unlikely that some other class would
9
- # define a `split` method that takes exactly the same arguments.
8
+ # @safety
9
+ # This cop is unsafe because it cannot be guaranteed that the receiver
10
+ # is actually a string. If another class has a `split` method with
11
+ # different behaviour, it would be registered as a false positive.
10
12
  #
11
13
  # @example
12
14
  # # bad
@@ -23,6 +23,10 @@ module RuboCop
23
23
  # This is useful when the receiver is some expression that returns string like `Pathname`
24
24
  # instead of a string literal.
25
25
  #
26
+ # @safety
27
+ # This cop is unsafe in `aggressive` mode, as it cannot be guaranteed that
28
+ # the receiver is actually a string, which can result in a false positive.
29
+ #
26
30
  # @example Mode: aggressive (default)
27
31
  # # bad
28
32
  # email_with_name = user.name + ' <' + user.email + '>'
@@ -93,7 +97,7 @@ module RuboCop
93
97
 
94
98
  def offensive_for_mode?(receiver_node)
95
99
  mode = cop_config['Mode'].to_sym
96
- mode == :aggressive || mode == :conservative && receiver_node.str_type?
100
+ mode == :aggressive || (mode == :conservative && receiver_node.str_type?)
97
101
  end
98
102
 
99
103
  def line_end_concatenation?(node)
@@ -6,6 +6,10 @@ module RuboCop
6
6
  # This cop checks for the use of strings as keys in hashes. The use of
7
7
  # symbols is preferred instead.
8
8
  #
9
+ # @safety
10
+ # This cop is unsafe because while symbols are preferred for hash keys,
11
+ # there are instances when string keys are required.
12
+ #
9
13
  # @example
10
14
  # # bad
11
15
  # { 'one' => 1, 'two' => 2, 'three' => 3 }
@@ -5,6 +5,10 @@ module RuboCop
5
5
  module Style
6
6
  # This cop checks for inheritance from Struct.new.
7
7
  #
8
+ # @safety
9
+ # Auto-correction is unsafe because it will change the inheritance
10
+ # tree (e.g. return value of `Module#ancestors`) of the constant.
11
+ #
8
12
  # @example
9
13
  # # bad
10
14
  # class Person < Struct.new(:first_name, :last_name)
@@ -4,8 +4,10 @@ module RuboCop
4
4
  module Cop
5
5
  module Style
6
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.
7
+ #
8
+ # @safety
9
+ # Autocorrection is unsafe, because the temporary variable used to
10
+ # swap variables will be removed, but may be referred to elsewhere.
9
11
  #
10
12
  # @example
11
13
  # # bad
@@ -8,6 +8,32 @@ module RuboCop
8
8
  # If you prefer a style that allows block for method with arguments,
9
9
  # please set `true` to `AllowMethodsWithArguments`.
10
10
  #
11
+ # @safety
12
+ # This cop is unsafe because `proc`s and blocks work differently
13
+ # when additional arguments are passed in. A block will silently
14
+ # ignore additional arguments, but a `proc` will raise
15
+ # an `ArgumentError`.
16
+ #
17
+ # For example:
18
+ #
19
+ # [source,ruby]
20
+ # ----
21
+ # class Foo
22
+ # def bar
23
+ # :bar
24
+ # end
25
+ # end
26
+ #
27
+ # def call(options = {}, &block)
28
+ # block.call(Foo.new, options)
29
+ # end
30
+ #
31
+ # call { |x| x.bar }
32
+ # #=> :bar
33
+ # call(&:bar)
34
+ # # ArgumentError: wrong number of arguments (given 1, expected 0)
35
+ # ----
36
+ #
11
37
  # @example
12
38
  # # bad
13
39
  # something.map { |s| s.upcase }
@@ -8,6 +8,25 @@ module RuboCop
8
8
  # that comma to be present. Blocks with more than one argument never
9
9
  # require a trailing comma.
10
10
  #
11
+ # @safety
12
+ # This cop is unsafe because a trailing comma can indicate there are
13
+ # more parameters that are not used.
14
+ #
15
+ # For example:
16
+ # [source,ruby]
17
+ # ----
18
+ # # with a trailing comma
19
+ # {foo: 1, bar: 2, baz: 3}.map {|key,| key }
20
+ # #=> [:foo, :bar, :baz]
21
+ #
22
+ # # without a trailing comma
23
+ # {foo: 1, bar: 2, baz: 3}.map {|key| key }
24
+ # #=> [[:foo, 1], [:bar, 2], [:baz, 3]]
25
+ # ----
26
+ #
27
+ # This can be fixed by replacing the trailing comma with a placeholder
28
+ # argument (such as `|key, _value|`).
29
+ #
11
30
  # @example
12
31
  # # bad
13
32
  # add { |foo, bar,| foo + bar }
@@ -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)
@@ -7,6 +7,26 @@ module RuboCop
7
7
  # i.e. comparison operations where the order of expression is reversed.
8
8
  # eg. `5 == x`
9
9
  #
10
+ # @safety
11
+ # This cop is unsafe because comparison operators can be defined
12
+ # differently on different classes, and are not guaranteed to
13
+ # have the same result if reversed.
14
+ #
15
+ # For example:
16
+ #
17
+ # [source,ruby]
18
+ # ----
19
+ # class MyKlass
20
+ # def ==(other)
21
+ # true
22
+ # end
23
+ # end
24
+ #
25
+ # obj = MyKlass.new
26
+ # obj == 'string' #=> true
27
+ # 'string' == obj #=> false
28
+ # ----
29
+ #
10
30
  # @example EnforcedStyle: forbid_for_all_comparison_operators (default)
11
31
  # # bad
12
32
  # 99 == foo
@@ -58,14 +78,11 @@ module RuboCop
58
78
  extend AutoCorrector
59
79
 
60
80
  MSG = 'Reverse the order of the operands `%<source>s`.'
61
-
62
81
  REVERSE_COMPARISON = { '<' => '>', '<=' => '>=', '>' => '<', '>=' => '<=' }.freeze
63
-
64
82
  EQUALITY_OPERATORS = %i[== !=].freeze
65
-
66
83
  NONCOMMUTATIVE_OPERATORS = %i[===].freeze
67
-
68
84
  PROGRAM_NAMES = %i[$0 $PROGRAM_NAME].freeze
85
+ RESTRICT_ON_SEND = RuboCop::AST::Node::COMPARISON_OPERATORS
69
86
 
70
87
  # @!method file_constant_equal_program_name?(node)
71
88
  def_node_matcher :file_constant_equal_program_name?, <<~PATTERN
@@ -74,7 +91,7 @@ module RuboCop
74
91
 
75
92
  def on_send(node)
76
93
  return unless yoda_compatible_condition?(node)
77
- return if equality_only? && non_equality_operator?(node) ||
94
+ return if (equality_only? && non_equality_operator?(node)) ||
78
95
  file_constant_equal_program_name?(node)
79
96
 
80
97
  valid_yoda?(node) || add_offense(node) do |corrector|
@@ -102,8 +119,8 @@ module RuboCop
102
119
  lhs = node.receiver
103
120
  rhs = node.first_argument
104
121
 
105
- return true if lhs.literal? && rhs.literal? ||
106
- !lhs.literal? && !rhs.literal? ||
122
+ return true if (lhs.literal? && rhs.literal?) ||
123
+ (!lhs.literal? && !rhs.literal?) ||
107
124
  interpolation?(lhs)
108
125
 
109
126
  enforce_yoda? ? lhs.literal? : rhs.literal?
@@ -9,6 +9,12 @@ module RuboCop
9
9
  # receiver.length < 1 and receiver.size == 0 that can be
10
10
  # replaced by receiver.empty? and !receiver.empty?.
11
11
  #
12
+ # @safety
13
+ # This cop is unsafe because it cannot be guaranteed that the receiver
14
+ # has an `empty?` method that is defined in terms of `length`. If there
15
+ # is a non-standard class that redefines `length` or `empty?`, the cop
16
+ # may register a false positive.
17
+ #
12
18
  # @example
13
19
  # # bad
14
20
  # [1, 2, 3].length == 0
@@ -113,7 +113,8 @@ module RuboCop
113
113
  if needs_escaping?(string) && compatible_external_encoding_for?(string)
114
114
  string.inspect
115
115
  else
116
- "'#{string.gsub('\\') { '\\\\' }}'"
116
+ # In a single-quoted strings, double quotes don't need to be escaped
117
+ "'#{string.gsub('\"', '"').gsub('\\') { '\\\\' }}'"
117
118
  end
118
119
  end
119
120
 
@@ -129,8 +130,8 @@ module RuboCop
129
130
  node1.respond_to?(:loc) && node2.respond_to?(:loc) && node1.loc.line == node2.loc.line
130
131
  end
131
132
 
132
- def indent(node)
133
- ' ' * node.loc.column
133
+ def indent(node, offset: 0)
134
+ ' ' * (node.loc.column + offset)
134
135
  end
135
136
 
136
137
  def to_supported_styles(enforced_style)
@@ -33,11 +33,12 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
33
33
  cops.with_department(department).sort!
34
34
  end
35
35
 
36
- def cops_body(cop, description, examples_objects, pars)
36
+ def cops_body(cop, description, examples_objects, safety_objects, pars) # rubocop:disable Metrics/AbcSize
37
37
  content = h2(cop.cop_name)
38
38
  content << required_ruby_version(cop)
39
39
  content << properties(cop)
40
40
  content << "#{description}\n"
41
+ content << safety_object(safety_objects) if safety_objects.any? { |s| !s.text.blank? }
41
42
  content << examples(examples_objects) if examples_objects.count.positive?
42
43
  content << configurations(pars)
43
44
  content << references(cop)
@@ -52,6 +53,16 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
52
53
  end
53
54
  end
54
55
 
56
+ def safety_object(safety_object_objects)
57
+ safety_object_objects.each_with_object(h3('Safety').dup) do |safety_object, content|
58
+ next if safety_object.text.blank?
59
+
60
+ content << "\n" unless content.end_with?("\n\n")
61
+ content << safety_object.text
62
+ content << "\n"
63
+ end
64
+ end
65
+
55
66
  def required_ruby_version(cop)
56
67
  return '' unless cop.respond_to?(:required_minimum_ruby_version)
57
68
 
@@ -61,8 +72,8 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
61
72
  # rubocop:disable Metrics/MethodLength
62
73
  def properties(cop)
63
74
  header = [
64
- 'Enabled by default', 'Safe', 'Supports autocorrection', 'VersionAdded',
65
- 'VersionChanged'
75
+ 'Enabled by default', 'Safe', 'Supports autocorrection', 'Version Added',
76
+ 'Version Changed'
66
77
  ]
67
78
  autocorrect = if cop.support_autocorrect?
68
79
  "Yes#{' (Unsafe)' unless cop.new(config).safe_autocorrect?}"
@@ -217,12 +228,13 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
217
228
  ]
218
229
  pars = cop_config.reject { |k| non_display_keys.include? k }
219
230
  description = 'No documentation'
220
- examples_object = []
231
+ examples_object = safety_object = []
221
232
  cop_code(cop) do |code_object|
222
233
  description = code_object.docstring unless code_object.docstring.blank?
223
234
  examples_object = code_object.tags('example')
235
+ safety_object = code_object.tags('safety')
224
236
  end
225
- cops_body(cop, description, examples_object, pars)
237
+ cops_body(cop, description, examples_object, safety_object, pars)
226
238
  end
227
239
 
228
240
  def cop_code(cop)
@@ -59,86 +59,111 @@ module RuboCop
59
59
 
60
60
  def define_options
61
61
  OptionParser.new do |opts|
62
- opts.banner = 'Usage: rubocop [options] [file1, file2, ...]'
62
+ opts.banner = rainbow.wrap('Usage: rubocop [options] [file1, file2, ...]').bright
63
63
 
64
- add_list_options(opts)
65
- add_only_options(opts)
66
- add_configuration_options(opts)
67
- add_formatting_options(opts)
68
-
69
- option(opts, '-r', '--require FILE') { |f| require_feature(f) }
70
-
71
- add_severity_option(opts)
72
- add_flags_with_optional_args(opts)
64
+ add_check_options(opts)
73
65
  add_cache_options(opts)
74
- add_boolean_flags(opts)
75
- add_aliases(opts)
66
+ add_output_options(opts)
67
+ add_autocorrection_options(opts)
68
+ add_config_generation_options(opts)
69
+ add_additional_modes(opts)
70
+ add_general_options(opts)
71
+ end
72
+ end
76
73
 
74
+ def add_check_options(opts) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
75
+ section(opts, 'Basic Options') do
76
+ option(opts, '-l', '--lint') do
77
+ @options[:only] ||= []
78
+ @options[:only] << 'Lint'
79
+ end
80
+ option(opts, '-x', '--fix-layout') do
81
+ @options[:only] ||= []
82
+ @options[:only] << 'Layout'
83
+ @options[:auto_correct] = true
84
+ end
85
+ option(opts, '--safe')
86
+ add_cop_selection_csv_option('except', opts)
87
+ add_cop_selection_csv_option('only', opts)
88
+ option(opts, '--only-guide-cops')
89
+ option(opts, '-F', '--fail-fast')
90
+ option(opts, '--disable-pending-cops')
91
+ option(opts, '--enable-pending-cops')
92
+ option(opts, '--ignore-disable-comments')
93
+ option(opts, '--force-exclusion')
94
+ option(opts, '--only-recognized-file-types')
95
+ option(opts, '--ignore-parent-exclusion')
96
+ option(opts, '--force-default-config')
77
97
  option(opts, '-s', '--stdin FILE')
98
+ option(opts, '-P', '--[no-]parallel')
99
+ add_severity_option(opts)
78
100
  end
79
101
  end
80
102
 
81
- def add_only_options(opts)
82
- add_cop_selection_csv_option('except', opts)
83
- add_cop_selection_csv_option('only', opts)
84
- option(opts, '--only-guide-cops')
85
- end
103
+ def add_output_options(opts) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
104
+ section(opts, 'Output Options') do
105
+ option(opts, '-f', '--format FORMATTER') do |key|
106
+ @options[:formatters] ||= []
107
+ @options[:formatters] << [key]
108
+ end
86
109
 
87
- def add_cop_selection_csv_option(option, opts)
88
- option(opts, "--#{option} [COP1,COP2,...]") do |list|
89
- unless list
90
- message = "--#{option} argument should be [COP1,COP2,...]."
110
+ option(opts, '-D', '--[no-]display-cop-names')
111
+ option(opts, '-E', '--extra-details')
112
+ option(opts, '-S', '--display-style-guide')
91
113
 
92
- raise OptionArgumentError, message
114
+ option(opts, '-o', '--out FILE') do |path|
115
+ if @options[:formatters]
116
+ @options[:formatters].last << path
117
+ else
118
+ @options[:output_path] = path
119
+ end
93
120
  end
94
121
 
95
- @options[:"#{option}"] = list.empty? ? [''] : list.split(',')
122
+ option(opts, '--stderr')
123
+ option(opts, '--display-time')
124
+ option(opts, '--display-only-failed')
125
+ option(opts, '--display-only-fail-level-offenses')
96
126
  end
97
127
  end
98
128
 
99
- def add_configuration_options(opts)
100
- option(opts, '-c', '--config FILE')
101
- option(opts, '--force-exclusion')
102
- option(opts, '--only-recognized-file-types')
103
- option(opts, '--ignore-parent-exclusion')
104
- option(opts, '--force-default-config')
105
- add_auto_gen_options(opts)
106
- end
107
-
108
- def add_auto_gen_options(opts)
109
- option(opts, '--auto-gen-config')
110
-
111
- option(opts, '--regenerate-todo') do
112
- @options.replace(ConfigRegeneration.new.options.merge(@options))
129
+ def add_autocorrection_options(opts)
130
+ section(opts, 'Auto-correction') do
131
+ option(opts, '-a', '--auto-correct') { @options[:safe_auto_correct] = true }
132
+ option(opts, '--safe-auto-correct') do
133
+ warn '--safe-auto-correct is deprecated; use --auto-correct'
134
+ @options[:safe_auto_correct] = @options[:auto_correct] = true
135
+ end
136
+ option(opts, '-A', '--auto-correct-all') { @options[:auto_correct] = true }
137
+ option(opts, '--disable-uncorrectable')
113
138
  end
139
+ end
114
140
 
115
- option(opts, '--exclude-limit COUNT') { @validator.validate_exclude_limit_option }
141
+ def add_config_generation_options(opts)
142
+ section(opts, 'Config Generation') do
143
+ option(opts, '--auto-gen-config')
116
144
 
117
- option(opts, '--disable-uncorrectable')
145
+ option(opts, '--regenerate-todo') do
146
+ @options.replace(ConfigRegeneration.new.options.merge(@options))
147
+ end
118
148
 
119
- option(opts, '--[no-]offense-counts')
120
- option(opts, '--[no-]auto-gen-only-exclude')
121
- option(opts, '--[no-]auto-gen-timestamp')
149
+ option(opts, '--exclude-limit COUNT') { @validator.validate_exclude_limit_option }
122
150
 
123
- option(opts, '--init')
151
+ option(opts, '--[no-]offense-counts')
152
+ option(opts, '--[no-]auto-gen-only-exclude')
153
+ option(opts, '--[no-]auto-gen-timestamp')
154
+ end
124
155
  end
125
156
 
126
- def add_formatting_options(opts)
127
- option(opts, '-f', '--format FORMATTER') do |key|
128
- @options[:formatters] ||= []
129
- @options[:formatters] << [key]
130
- end
157
+ def add_cop_selection_csv_option(option, opts)
158
+ option(opts, "--#{option} [COP1,COP2,...]") do |list|
159
+ unless list
160
+ message = "--#{option} argument should be [COP1,COP2,...]."
131
161
 
132
- option(opts, '-o', '--out FILE') do |path|
133
- if @options[:formatters]
134
- @options[:formatters].last << path
135
- else
136
- @options[:output_path] = path
162
+ raise OptionArgumentError, message
137
163
  end
138
- end
139
164
 
140
- option(opts, '--display-time')
141
- option(opts, '--display-only-failed')
165
+ @options[:"#{option}"] = list.empty? ? [''] : list.split(',')
166
+ end
142
167
  end
143
168
 
144
169
  def add_severity_option(opts)
@@ -148,62 +173,50 @@ module RuboCop
148
173
  table) do |severity|
149
174
  @options[:fail_level] = severity
150
175
  end
151
- option(opts, '--display-only-fail-level-offenses')
152
176
  end
153
177
 
154
- def add_flags_with_optional_args(opts)
155
- option(opts, '--show-cops [COP1,COP2,...]') do |list|
156
- @options[:show_cops] = list.nil? ? [] : list.split(',')
178
+ def add_cache_options(opts)
179
+ section(opts, 'Caching') do
180
+ option(opts, '-C', '--cache FLAG')
181
+ option(opts, '--cache-root DIR') { @validator.validate_cache_enabled_for_cache_root }
157
182
  end
158
183
  end
159
184
 
160
- def add_cache_options(opts)
161
- option(opts, '-C', '--cache FLAG')
162
- option(opts, '--cache-root DIR') { @validator.validate_cache_enabled_for_cache_root }
163
- end
164
-
165
- # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
166
- def add_boolean_flags(opts)
167
- option(opts, '-F', '--fail-fast')
168
- option(opts, '-d', '--debug')
169
- option(opts, '-D', '--[no-]display-cop-names')
170
- option(opts, '-E', '--extra-details')
171
- option(opts, '-S', '--display-style-guide')
172
- option(opts, '-a', '--auto-correct') { @options[:safe_auto_correct] = true }
173
- option(opts, '--safe-auto-correct') do
174
- warn '--safe-auto-correct is deprecated; use --auto-correct'
175
- @options[:safe_auto_correct] = @options[:auto_correct] = true
185
+ def add_additional_modes(opts)
186
+ section(opts, 'Additional Modes') do
187
+ option(opts, '-L', '--list-target-files')
188
+ option(opts, '--show-cops [COP1,COP2,...]') do |list|
189
+ @options[:show_cops] = list.nil? ? [] : list.split(',')
190
+ end
176
191
  end
177
- option(opts, '-A', '--auto-correct-all') { @options[:auto_correct] = true }
178
- option(opts, '--disable-pending-cops')
179
- option(opts, '--enable-pending-cops')
180
- option(opts, '--ignore-disable-comments')
181
-
182
- option(opts, '--safe')
183
-
184
- option(opts, '--stderr')
185
- option(opts, '--[no-]color')
186
-
187
- option(opts, '-v', '--version')
188
- option(opts, '-V', '--verbose-version')
189
- option(opts, '-P', '--[no-]parallel')
190
192
  end
191
- # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
192
193
 
193
- def add_aliases(opts)
194
- option(opts, '-l', '--lint') do
195
- @options[:only] ||= []
196
- @options[:only] << 'Lint'
194
+ def add_general_options(opts)
195
+ section(opts, 'General Options') do
196
+ option(opts, '--init')
197
+ option(opts, '-c', '--config FILE')
198
+ option(opts, '-d', '--debug')
199
+ option(opts, '-r', '--require FILE') { |f| require_feature(f) }
200
+ option(opts, '--[no-]color')
201
+ option(opts, '-v', '--version')
202
+ option(opts, '-V', '--verbose-version')
197
203
  end
198
- option(opts, '-x', '--fix-layout') do
199
- @options[:only] ||= []
200
- @options[:only] << 'Layout'
201
- @options[:auto_correct] = true
204
+ end
205
+
206
+ def rainbow
207
+ @rainbow ||= begin
208
+ rainbow = Rainbow.new
209
+ rainbow.enabled = false if ARGV.include?('--no-color')
210
+ rainbow
202
211
  end
203
212
  end
204
213
 
205
- def add_list_options(opts)
206
- option(opts, '-L', '--list-target-files')
214
+ # Creates a section of options in order to separate them visually when
215
+ # using `--help`.
216
+ def section(opts, heading, &_block)
217
+ heading = rainbow.wrap(heading).bright
218
+ opts.separator("\n#{heading}:\n")
219
+ yield
207
220
  end
208
221
 
209
222
  # Sets a value in the @options hash, based on the given long option and its
@@ -403,7 +416,7 @@ module RuboCop
403
416
  only: 'Run only the given cop(s).',
404
417
  only_guide_cops: ['Run only cops for rules that link to a',
405
418
  'style guide.'],
406
- except: 'Disable the given cop(s).',
419
+ except: 'Exclude the given cop(s).',
407
420
  require: 'Require Ruby file.',
408
421
  config: 'Specify configuration file.',
409
422
  auto_gen_config: ['Generate a configuration file acting as a',
@@ -422,29 +435,30 @@ module RuboCop
422
435
  'when running --auto-gen-config, except if the',
423
436
  'number of files with offenses is bigger than',
424
437
  'exclude-limit. Default is false.'],
425
- exclude_limit: ['Used together with --auto-gen-config to',
426
- 'set the limit for how many Exclude',
427
- "properties to generate. Default is #{MAX_EXCL}."],
438
+ exclude_limit: ['Set the limit for how many files to explicitly exclude.',
439
+ 'If there are more files than the limit, the cop will',
440
+ "be disabled instead. Default is #{MAX_EXCL}."],
428
441
  disable_uncorrectable: ['Used with --auto-correct to annotate any',
429
442
  'offenses that do not support autocorrect',
430
443
  'with `rubocop:todo` comments.'],
431
- force_exclusion: ['Force excluding files specified in the',
432
- 'configuration `Exclude` even if they are',
433
- 'explicitly passed as arguments.'],
444
+ force_exclusion: ['Any files excluded by `Exclude` in configuration',
445
+ 'files will be excluded, even if given explicitly',
446
+ 'as arguments.'],
434
447
  only_recognized_file_types: ['Inspect files given on the command line only if',
435
- 'they are listed in AllCops/Include parameters',
448
+ 'they are listed in `AllCops/Include` parameters',
436
449
  'of user configuration or default configuration.'],
437
450
  ignore_disable_comments: ['Run cops even when they are disabled locally',
438
- 'with a comment.'],
439
- ignore_parent_exclusion: ['Prevent from inheriting AllCops/Exclude from',
451
+ 'by a `rubocop:disable` directive.'],
452
+ ignore_parent_exclusion: ['Prevent from inheriting `AllCops/Exclude` from',
440
453
  'parent folders.'],
441
454
  force_default_config: ['Use default configuration even if configuration',
442
455
  'files are present in the directory tree.'],
443
456
  format: ['Choose an output formatter. This option',
444
457
  'can be specified multiple times to enable',
445
458
  'multiple formatters at the same time.',
446
- '[p]rogress is used by default',
447
- *FORMATTER_OPTION_LIST.map { |item| " #{item}" },
459
+ *FORMATTER_OPTION_LIST.map do |item|
460
+ " #{item}#{' (default)' if item == '[p]rogress'}"
461
+ end,
448
462
  ' custom formatter class name'],
449
463
  out: ['Write output to a file instead of STDOUT.',
450
464
  'This option applies to the previously',
@@ -33,7 +33,7 @@ module RuboCop
33
33
  private
34
34
 
35
35
  def run_cli(verbose, options)
36
- # We lazy-load rubocop so that the task doesn't dramatically impact the
36
+ # We lazy-load RuboCop so that the task doesn't dramatically impact the
37
37
  # load time of your Rakefile.
38
38
  require 'rubocop'
39
39
 
@@ -6,7 +6,7 @@ require 'etc'
6
6
  require 'zlib'
7
7
 
8
8
  module RuboCop
9
- # Provides functionality for caching rubocop runs.
9
+ # Provides functionality for caching RuboCop runs.
10
10
  # @api private
11
11
  class ResultCache
12
12
  NON_CHANGING = %i[color format formatters out debug fail_level auto_correct
@@ -45,7 +45,7 @@ module RuboCop
45
45
  def remove_oldest_files(files, dirs, cache_root, verbose)
46
46
  # Add 1 to half the number of files, so that we remove the file if
47
47
  # there's only 1 left.
48
- remove_count = 1 + files.length / 2
48
+ remove_count = 1 + (files.length / 2)
49
49
  puts "Removing the #{remove_count} oldest files from #{cache_root}" if verbose
50
50
  sorted = files.sort_by { |path| File.mtime(path) }
51
51
  remove_files(sorted, dirs, remove_count)
@@ -170,7 +170,7 @@ module RuboCop
170
170
  attr_accessor :source_checksum, :inhibit_cleanup
171
171
  end
172
172
 
173
- # The checksum of the rubocop program running the inspection.
173
+ # The checksum of the RuboCop program running the inspection.
174
174
  def rubocop_checksum
175
175
  ResultCache.source_checksum ||=
176
176
  begin
@@ -49,7 +49,7 @@ module CopHelper
49
49
  team = RuboCop::Cop::Team.new([cop], nil, raise_error: true)
50
50
  report = team.investigate(processed_source)
51
51
  @last_corrector = report.correctors.first || RuboCop::Cop::Corrector.new(processed_source)
52
- report.offenses
52
+ report.offenses.reject(&:disabled?)
53
53
  end
54
54
  end
55
55