Module: RuboCop::Cop::MinitestCopRule

Overview

Provide a method to define offense rule for Minitest cops.

Instance Method Summary collapse

Instance Method Details

#define_rule(assertion_method, target_method:, preferred_method: nil, inverse: false) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Define offense rule for Minitest cops.

Examples:

define_rule :assert, target_method: :match
define_rule :refute, target_method: :match
define_rule :assert, target_method: :include?, preferred_method: :assert_includes
define_rule :assert, target_method: :instance_of?, inverse: true

Multiple target methods

# `preferred_method` is required
define_rule :assert, target_method: i[match match? =~],
            preferred_method: :assert_match, inverse: 'regexp_type?'

Parameters:

  • assertion_method (Symbol)

    Assertion method like ‘assert` or `refute`.

  • target_method (Symbol, Array<Symbol>)

    Method name(s) offensed by assertion method arguments.

  • preferred_method (Symbol) (defaults to: nil)

    Is required if passing multiple target methods. Custom method name replaced by autocorrection. The preferred method name that connects ‘assertion_method` and `target_method` with `_` is the default name.

  • inverse (Boolean, String) (defaults to: false)

    An optional param. Order of arguments replaced by autocorrection. If string is passed, it becomes a predicate method for the first argument node.



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/rubocop/cop/mixin/minitest_cop_rule.rb', line 31

def define_rule(assertion_method, target_method:, preferred_method: nil, inverse: false)
  target_methods = Array(target_method)
  if target_methods.size > 1 && preferred_method.nil?
    raise ArgumentError, '`:preferred_method` keyword argument must be used if using more than one target method.'
  end

  preferred_method = "#{assertion_method}_#{target_methods.first.to_s.delete('?')}" if preferred_method.nil?

  class_eval("    include ArgumentRangeHelper\n    extend AutoCorrector\n\n    MSG = 'Prefer using `\#{preferred_method}(%<new_arguments>s)`.'\n    RESTRICT_ON_SEND = %i[\#{assertion_method}].freeze\n\n    def on_send(node)\n      return unless node.method?(:\#{assertion_method})\n      return unless node.arguments.first&.call_type?\n      return if node.arguments.first.arguments.empty? ||\n                \#{target_methods}.none? { |target_method| node.arguments.first.method?(target_method) }\n\n      add_offense(node, message: offense_message(node.arguments)) do |corrector|\n        autocorrect(corrector, node, node.arguments)\n      end\n    end\n\n    def autocorrect(corrector, node, arguments)\n      corrector.replace(node.loc.selector, '\#{preferred_method}')\n\n      new_arguments = new_arguments(arguments).join(', ')\n\n      corrector.replace(node.first_argument, new_arguments)\n    end\n\n    private\n\n    def offense_message(arguments)\n      message_argument = arguments.last if arguments.first != arguments.last\n\n      new_arguments = [\n        new_arguments(arguments),\n        message_argument&.source\n      ].flatten.compact.join(', ')\n\n      format(\n        MSG,\n        new_arguments: new_arguments\n      )\n    end\n\n    def new_arguments(arguments)\n      receiver = correct_receiver(arguments.first.receiver)\n      method_argument = arguments.first.arguments.first\n\n      new_arguments = [receiver, method_argument&.source].compact\n      inverse_condition = if %w[true false].include?('\#{inverse}')\n        \#{inverse}\n      else\n        method_argument.\#{inverse}\n      end\n      new_arguments.reverse! if inverse_condition\n      new_arguments\n    end\n\n    def correct_receiver(receiver)\n      receiver ? receiver.source : 'self'\n    end\n  RUBY\nend\n", __FILE__, __LINE__ + 1)