rubocop 1.21.0 → 1.22.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 (118) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +43 -6
  4. data/lib/rubocop/config.rb +5 -0
  5. data/lib/rubocop/config_loader.rb +2 -0
  6. data/lib/rubocop/config_validator.rb +9 -1
  7. data/lib/rubocop/cop/base.rb +1 -1
  8. data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +34 -11
  9. data/lib/rubocop/cop/bundler/ordered_gems.rb +3 -12
  10. data/lib/rubocop/cop/correctors/ordered_gem_corrector.rb +11 -10
  11. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +3 -12
  12. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +1 -1
  13. data/lib/rubocop/cop/generator.rb +14 -8
  14. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -1
  15. data/lib/rubocop/cop/layout/dot_position.rb +25 -2
  16. data/lib/rubocop/cop/layout/line_length.rb +7 -5
  17. data/lib/rubocop/cop/layout/redundant_line_break.rb +1 -0
  18. data/lib/rubocop/cop/layout/space_inside_parens.rb +74 -24
  19. data/lib/rubocop/cop/lint/ambiguous_operator_precedence.rb +5 -1
  20. data/lib/rubocop/cop/lint/ambiguous_range.rb +7 -7
  21. data/lib/rubocop/cop/lint/assignment_in_condition.rb +7 -5
  22. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +18 -5
  23. data/lib/rubocop/cop/lint/boolean_symbol.rb +5 -0
  24. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +4 -4
  25. data/lib/rubocop/cop/lint/disjunctive_assignment_in_constructor.rb +24 -1
  26. data/lib/rubocop/cop/lint/else_layout.rb +9 -5
  27. data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +12 -3
  28. data/lib/rubocop/cop/lint/interpolation_check.rb +5 -0
  29. data/lib/rubocop/cop/lint/loop.rb +4 -3
  30. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +5 -1
  31. data/lib/rubocop/cop/lint/number_conversion.rb +5 -0
  32. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -1
  33. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +4 -2
  34. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +17 -0
  35. data/lib/rubocop/cop/lint/percent_string_array.rb +10 -0
  36. data/lib/rubocop/cop/lint/raise_exception.rb +4 -0
  37. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +5 -4
  38. data/lib/rubocop/cop/lint/require_relative_self_path.rb +49 -0
  39. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +1 -1
  40. data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
  41. data/lib/rubocop/cop/lint/triple_quotes.rb +1 -1
  42. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +8 -3
  43. data/lib/rubocop/cop/lint/useless_method_definition.rb +3 -2
  44. data/lib/rubocop/cop/lint/useless_setter_call.rb +7 -4
  45. data/lib/rubocop/cop/lint/useless_times.rb +3 -2
  46. data/lib/rubocop/cop/metrics/abc_size.rb +6 -0
  47. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +5 -1
  48. data/lib/rubocop/cop/mixin/heredoc.rb +1 -3
  49. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +9 -1
  50. data/lib/rubocop/cop/mixin/percent_array.rb +6 -1
  51. data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
  52. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +5 -4
  53. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +7 -0
  54. data/lib/rubocop/cop/security/io_methods.rb +49 -0
  55. data/lib/rubocop/cop/security/json_load.rb +8 -7
  56. data/lib/rubocop/cop/security/open.rb +4 -0
  57. data/lib/rubocop/cop/security/yaml_load.rb +4 -0
  58. data/lib/rubocop/cop/style/and_or.rb +4 -3
  59. data/lib/rubocop/cop/style/arguments_forwarding.rb +13 -2
  60. data/lib/rubocop/cop/style/array_coercion.rb +21 -3
  61. data/lib/rubocop/cop/style/case_like_if.rb +5 -0
  62. data/lib/rubocop/cop/style/class_and_module_children.rb +9 -0
  63. data/lib/rubocop/cop/style/collection_compact.rb +7 -5
  64. data/lib/rubocop/cop/style/collection_methods.rb +6 -5
  65. data/lib/rubocop/cop/style/combinable_loops.rb +3 -2
  66. data/lib/rubocop/cop/style/commented_keyword.rb +4 -1
  67. data/lib/rubocop/cop/style/date_time.rb +5 -0
  68. data/lib/rubocop/cop/style/double_negation.rb +15 -5
  69. data/lib/rubocop/cop/style/float_division.rb +10 -2
  70. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +6 -1
  71. data/lib/rubocop/cop/style/global_std_stream.rb +4 -0
  72. data/lib/rubocop/cop/style/hash_each_methods.rb +5 -0
  73. data/lib/rubocop/cop/style/hash_transform_keys.rb +4 -6
  74. data/lib/rubocop/cop/style/hash_transform_values.rb +4 -6
  75. data/lib/rubocop/cop/style/identical_conditional_branches.rb +18 -16
  76. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +15 -2
  77. data/lib/rubocop/cop/style/infinite_loop.rb +4 -3
  78. data/lib/rubocop/cop/style/inverse_methods.rb +9 -2
  79. data/lib/rubocop/cop/style/line_end_concatenation.rb +13 -0
  80. data/lib/rubocop/cop/style/module_function.rb +8 -9
  81. data/lib/rubocop/cop/style/mutable_constant.rb +12 -7
  82. data/lib/rubocop/cop/style/numbered_parameters.rb +46 -0
  83. data/lib/rubocop/cop/style/numbered_parameters_limit.rb +50 -0
  84. data/lib/rubocop/cop/style/numeric_literals.rb +7 -8
  85. data/lib/rubocop/cop/style/numeric_predicate.rb +5 -0
  86. data/lib/rubocop/cop/style/optional_arguments.rb +4 -0
  87. data/lib/rubocop/cop/style/optional_boolean_parameter.rb +14 -4
  88. data/lib/rubocop/cop/style/preferred_hash_methods.rb +9 -4
  89. data/lib/rubocop/cop/style/redundant_argument.rb +14 -7
  90. data/lib/rubocop/cop/style/redundant_fetch_block.rb +4 -0
  91. data/lib/rubocop/cop/style/redundant_file_extension_in_require.rb +12 -3
  92. data/lib/rubocop/cop/style/redundant_freeze.rb +0 -1
  93. data/lib/rubocop/cop/style/redundant_self.rb +10 -0
  94. data/lib/rubocop/cop/style/redundant_self_assignment.rb +4 -3
  95. data/lib/rubocop/cop/style/redundant_sort.rb +47 -29
  96. data/lib/rubocop/cop/style/safe_navigation.rb +13 -2
  97. data/lib/rubocop/cop/style/select_by_regexp.rb +106 -0
  98. data/lib/rubocop/cop/style/single_argument_dig.rb +5 -0
  99. data/lib/rubocop/cop/style/slicing_with_range.rb +13 -0
  100. data/lib/rubocop/cop/style/special_global_vars.rb +4 -0
  101. data/lib/rubocop/cop/style/static_class.rb +4 -3
  102. data/lib/rubocop/cop/style/string_chars.rb +4 -2
  103. data/lib/rubocop/cop/style/string_concatenation.rb +4 -0
  104. data/lib/rubocop/cop/style/string_hash_keys.rb +4 -0
  105. data/lib/rubocop/cop/style/struct_inheritance.rb +3 -2
  106. data/lib/rubocop/cop/style/swap_values.rb +4 -2
  107. data/lib/rubocop/cop/style/symbol_proc.rb +26 -0
  108. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +19 -0
  109. data/lib/rubocop/cop/style/yoda_condition.rb +20 -0
  110. data/lib/rubocop/cop/style/zero_length_predicate.rb +6 -0
  111. data/lib/rubocop/cop/util.rb +2 -2
  112. data/lib/rubocop/cops_documentation_generator.rb +17 -5
  113. data/lib/rubocop/options.rb +126 -112
  114. data/lib/rubocop/rspec/cop_helper.rb +1 -1
  115. data/lib/rubocop/rspec/expect_offense.rb +6 -2
  116. data/lib/rubocop/version.rb +1 -1
  117. data/lib/rubocop.rb +5 -0
  118. metadata +10 -5
@@ -10,14 +10,25 @@ module RuboCop
10
10
  # need to be changed to use safe navigation. We have limited the cop to
11
11
  # not register an offense for method chains that exceed 2 methods.
12
12
  #
13
- # Configuration option: ConvertCodeThatCanStartToReturnNil
14
- # The default for this is `false`. When configured to `true`, this will
13
+ # The default for `ConvertCodeThatCanStartToReturnNil` is `false`.
14
+ # When configured to `true`, this will
15
15
  # check for code in the format `!foo.nil? && foo.bar`. As it is written,
16
16
  # the return of this code is limited to `false` and whatever the return
17
17
  # of the method is. If this is converted to safe navigation,
18
18
  # `foo&.bar` can start returning `nil` as well as what the method
19
19
  # returns.
20
20
  #
21
+ # @safety
22
+ # Autocorrection is unsafe because if a value is `false`, the resulting
23
+ # code will have different behaviour or raise an error.
24
+ #
25
+ # [source,ruby]
26
+ # ----
27
+ # x = false
28
+ # x && x.foo # return false
29
+ # x&.foo # raises NoMethodError
30
+ # ----
31
+ #
21
32
  # @example
22
33
  # # bad
23
34
  # foo.bar if foo
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # This cop looks for places where an subset of an array
7
+ # is calculated based on a `Regexp` match, and suggests `grep` or
8
+ # `grep_v` instead.
9
+ #
10
+ # NOTE: `grep` and `grep_v` were optimized when used without a block
11
+ # in Ruby 3.0, but may be slower in previous versions.
12
+ # See https://bugs.ruby-lang.org/issues/17030
13
+ #
14
+ # @safety
15
+ # Autocorrection is marked as unsafe because `MatchData` will
16
+ # not be created by `grep`, but may have previously been relied
17
+ # upon after the `match?` or `=~` call.
18
+ #
19
+ # @example
20
+ # # bad (select or find_all)
21
+ # array.select { |x| x.match? /regexp/ }
22
+ # array.select { |x| /regexp/.match?(x) }
23
+ # array.select { |x| x =~ /regexp/ }
24
+ # array.select { |x| /regexp/ =~ x }
25
+ #
26
+ # # bad (reject)
27
+ # array.reject { |x| x.match? /regexp/ }
28
+ # array.reject { |x| /regexp/.match?(x) }
29
+ # array.reject { |x| x =~ /regexp/ }
30
+ # array.reject { |x| /regexp/ =~ x }
31
+ #
32
+ # # good
33
+ # array.grep(regexp)
34
+ # array.grep_v(regexp)
35
+ class SelectByRegexp < Base
36
+ extend AutoCorrector
37
+ include RangeHelp
38
+
39
+ MSG = 'Prefer `%<replacement>s` to `%<original_method>s` with a regexp match.'
40
+ RESTRICT_ON_SEND = %i[select find_all reject].freeze
41
+ REPLACEMENTS = { select: 'grep', find_all: 'grep', reject: 'grep_v' }.freeze
42
+ REGEXP_METHODS = %i[match? =~].to_set.freeze
43
+
44
+ # @!method regexp_match?(node)
45
+ def_node_matcher :regexp_match?, <<~PATTERN
46
+ {
47
+ (block send (args (arg $_)) ${(send _ %REGEXP_METHODS _) match-with-lvasgn})
48
+ (numblock send $1 ${(send _ %REGEXP_METHODS _) match-with-lvasgn})
49
+ }
50
+ PATTERN
51
+
52
+ # @!method calls_lvar?(node, name)
53
+ def_node_matcher :calls_lvar?, <<~PATTERN
54
+ {
55
+ (send (lvar %1) ...)
56
+ (send ... (lvar %1))
57
+ (match-with-lvasgn regexp (lvar %1))
58
+ }
59
+ PATTERN
60
+
61
+ def on_send(node)
62
+ return unless (block_node = node.block_node)
63
+ return if block_node.body.begin_type?
64
+ return unless (regexp_method_send_node = extract_send_node(block_node))
65
+
66
+ regexp = find_regexp(regexp_method_send_node)
67
+ register_offense(node, block_node, regexp)
68
+ end
69
+
70
+ private
71
+
72
+ def register_offense(node, block_node, regexp)
73
+ replacement = REPLACEMENTS[node.method_name.to_sym]
74
+ message = format(MSG, replacement: replacement, original_method: node.method_name)
75
+
76
+ add_offense(block_node, message: message) do |corrector|
77
+ # Only correct if it can be determined what the regexp is
78
+ if regexp
79
+ range = range_between(node.loc.selector.begin_pos, block_node.loc.end.end_pos)
80
+ corrector.replace(range, "#{replacement}(#{regexp.source})")
81
+ end
82
+ end
83
+ end
84
+
85
+ def extract_send_node(block_node)
86
+ return unless (block_arg_name, regexp_method_send_node = regexp_match?(block_node))
87
+
88
+ block_arg_name = :"_#{block_arg_name}" if block_node.numblock_type?
89
+ return unless calls_lvar?(regexp_method_send_node, block_arg_name)
90
+
91
+ regexp_method_send_node
92
+ end
93
+
94
+ def find_regexp(node)
95
+ return node.child_nodes.first if node.match_with_lvasgn_type?
96
+
97
+ if node.receiver.lvar_type?
98
+ node.first_argument
99
+ elsif node.first_argument.lvar_type?
100
+ node.receiver
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -6,6 +6,11 @@ module RuboCop
6
6
  # Sometimes using dig method ends up with just a single
7
7
  # argument. In such cases, dig should be replaced with [].
8
8
  #
9
+ # @safety
10
+ # This cop is unsafe because it cannot be guaranteed that the receiver
11
+ # is an `Enumerable` or does not have a nonstandard implementation
12
+ # of `dig`.
13
+ #
9
14
  # @example
10
15
  # # bad
11
16
  # { key: 'value' }.dig(:key)
@@ -6,6 +6,19 @@ module RuboCop
6
6
  # This cop checks that arrays are sliced with endless ranges instead of
7
7
  # `ary[start..-1]` on Ruby 2.6+.
8
8
  #
9
+ # @safety
10
+ # This cop is unsafe because `x..-1` and `x..` are only guaranteed to
11
+ # be equivalent for `Array#[]`, and the cop cannot determine what class
12
+ # the receiver is.
13
+ #
14
+ # For example:
15
+ # [source,ruby]
16
+ # ----
17
+ # sum = proc { |ary| ary.sum }
18
+ # sum[-3..-1] # => -6
19
+ # sum[-3..] # Hangs forever
20
+ # ----
21
+ #
9
22
  # @example
10
23
  # # bad
11
24
  # items[1..-1]
@@ -9,6 +9,10 @@ module RuboCop
9
9
  # will add a require statement to the top of the file if
10
10
  # enabled by RequireEnglish config.
11
11
  #
12
+ # @safety
13
+ # Autocorrection is marked as unsafe because if `RequireEnglish` is not
14
+ # true, replacing perl-style variables with english variables will break.
15
+ #
12
16
  # @example EnforcedStyle: use_english_names (default)
13
17
  # # good
14
18
  # require 'English' # or this could be in another file.
@@ -7,9 +7,10 @@ module RuboCop
7
7
  # replaced with a module. Classes should be used only when it makes sense to create
8
8
  # instances out of them.
9
9
  #
10
- # This cop is marked as unsafe, because it is possible that this class is a parent
11
- # for some other subclass, monkey-patched with instance methods or
12
- # a dummy instance is instantiated from it somewhere.
10
+ # @safety
11
+ # This cop is unsafe, because it is possible that this class is a parent
12
+ # for some other subclass, monkey-patched with instance methods or
13
+ # a dummy instance is instantiated from it somewhere.
13
14
  #
14
15
  # @example
15
16
  # # bad
@@ -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 + '>'
@@ -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,8 +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`).
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.
10
11
  #
11
12
  # @example
12
13
  # # bad
@@ -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 }
@@ -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
@@ -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
@@ -129,8 +129,8 @@ module RuboCop
129
129
  node1.respond_to?(:loc) && node2.respond_to?(:loc) && node1.loc.line == node2.loc.line
130
130
  end
131
131
 
132
- def indent(node)
133
- ' ' * node.loc.column
132
+ def indent(node, offset: 0)
133
+ ' ' * (node.loc.column + offset)
134
134
  end
135
135
 
136
136
  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)