module RuboCop::Cop::RSpec::ExplicitHelper
def allowed_explicit_matchers
def allowed_explicit_matchers cop_config.fetch('AllowedExplicitMatchers', []) + BUILT_IN_MATCHERS end
def check_explicit(node) # rubocop:disable Metrics/MethodLength
def check_explicit(node) # rubocop:disable Metrics/MethodLength predicate_matcher_block?(node) do |actual, matcher| add_offense(node, message: message_explicit(matcher)) do |corrector| to_node = node.send_node corrector_explicit(corrector, to_node, actual, matcher, to_node) end ignore_node(node.children.first) return end return if part_of_ignored_node?(node) predicate_matcher?(node) do |actual, matcher| next unless replaceable_matcher?(matcher) add_offense(node, message: message_explicit(matcher)) do |corrector| next if uncorrectable_matcher?(node, matcher) corrector_explicit(corrector, node, actual, matcher, matcher) end end end
def corrector_explicit(corrector, to_node, actual, matcher, block_child)
def corrector_explicit(corrector, to_node, actual, matcher, block_child) replacement_matcher = replacement_matcher(to_node) corrector.replace(matcher, replacement_matcher) move_predicate(corrector, actual, matcher, block_child) corrector.replace(to_node.loc.selector, 'to') end
def heredoc_argument?(matcher)
def heredoc_argument?(matcher) matcher.arguments.select do |arg| arg.type?(:str, :dstr, :xstr) end.any?(&:heredoc?) end
def message_explicit(matcher)
def message_explicit(matcher) format(MSG_EXPLICIT, predicate_name: to_predicate_method(matcher.method_name), matcher_name: matcher.method_name) end
def move_predicate(corrector, actual, matcher, block_child)
def move_predicate(corrector, actual, matcher, block_child) predicate = to_predicate_method(matcher.method_name) args = LocationHelp.arguments_with_whitespace(matcher).source block_loc = LocationHelp.block_with_whitespace(block_child) block = block_loc ? block_loc.source : '' corrector.remove(block_loc) if block_loc corrector.insert_after(actual, ".#{predicate}" + args + block) end
def predicate_matcher_name?(name)
def predicate_matcher_name?(name) name = name.to_s return false if allowed_explicit_matchers.include?(name) (name.start_with?('be_', 'have_') && !name.end_with?('?')) || %w[include respond_to].include?(name) end
def replaceable_matcher?(matcher)
def replaceable_matcher?(matcher) case matcher.method_name.to_s when 'include' matcher.arguments.one? else true end end
def replacement_matcher(node)
def replacement_matcher(node) case [cop_config['Strict'], node.method?(:to)] when [true, true] 'be(true)' when [true, false] 'be(false)' when [false, true] 'be_truthy' else 'be_falsey' end end
def to_predicate_method(matcher)
def to_predicate_method(matcher) case matcher = matcher.to_s when 'be_a', 'be_an', 'be_a_kind_of', 'a_kind_of', 'be_kind_of' 'is_a?' when 'be_an_instance_of', 'be_instance_of', 'an_instance_of' 'instance_of?' when 'include' 'include?' when 'respond_to' 'respond_to?' when /\Ahave_(.+)/ "has_#{Regexp.last_match(1)}?" else "#{matcher[/\Abe_(.+)/, 1]}?" end end
def uncorrectable_matcher?(node, matcher)
def uncorrectable_matcher?(node, matcher) heredoc_argument?(matcher) && !same_line?(node, matcher) end