# frozen_string_literal: true module Matchi # Common matcher methods. module MatchersBase # Abstract matcher class. # # @raise [NotImplementedError] Override me inside a Matcher subclass please. def matches? raise ::NotImplementedError, 'matcher MUST respond to `matches?` method.' end # Returns a string representing the matcher. # # @example The readable definition of a FooBar matcher. # matcher = Matchi::Matchers::FooBar::Matcher.new(42) # matcher.to_s # => "foo_bar 42" # # @return [String] A string representing the matcher. def to_s s = matcher_name .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2') .gsub(/([a-z\d])([A-Z])/, '\1_\2') .downcase defined?(@expected) ? [s, @expected.inspect].join(' ') : s end # A string containing a human-readable representation of the matcher. # # @api public # # @return [String] The human-readable representation of the matcher. def inspect expected_inspect = @expected.inspect if defined?(@expected) "#{matcher_name}(#{expected_inspect})" end # Returns a hash of one key-value pair with a key corresponding to the # matcher and a value corresponding to its initialize parameters. # # @example A FooBar matcher serialized into a hash. # matcher = Matchi::Matchers::FooBar::Matcher.new(42) # matcher.to_h # => { FooBar: 42 } # # @return [Hash] A hash of one key-value pair. def to_h { matcher_name.to_sym => (defined?(@expected) ? Array(@expected) : []) } end private def matcher_name self .class .name .gsub(/\AMatchi::Matchers::/, '') .gsub(/::Matcher\z/, '') end end end