class StrictlyFake

StrictlyFake - verifying fake

Constants

VERSION

Public Class Methods

new(real) click to toggle source
# File lib/strictly_fake.rb, line 25
def initialize(real)
  @real = real
  @fake = Fake.new
end

Public Instance Methods

method_missing(meth, *args, &block) click to toggle source

rubocop:disable Lint/MissingSuper

# File lib/strictly_fake.rb, line 44
def method_missing(meth, *args, &block)
  @fake.send(meth, *args, &block)
end
respond_to_missing?(meth, *_args) click to toggle source

rubocop:enable Lint/MissingSuper

Calls superclass method
# File lib/strictly_fake.rb, line 49
def respond_to_missing?(meth, *_args)
  @fake.respond_to?(meth) || super
end
stub(meth, &block) click to toggle source
# File lib/strictly_fake.rb, line 30
def stub(meth, &block)
  raise Error, "Can't stub #stub" if meth.to_s == 'stub'

  assert_method_defined(meth)

  expected_parameters = @real.method(meth).parameters
  actual_parameters = convert_to_lambda(&block).parameters

  assert_method_signature_match(meth, expected_parameters, actual_parameters)

  stub_method(meth, &block)
end

Private Instance Methods

assert_method_defined(meth) click to toggle source
# File lib/strictly_fake.rb, line 71
def assert_method_defined(meth)
  return if @real.respond_to?(meth)

  method_type = @real.is_a?(Class) ? '.' : '#'
  raise Error, "Can't stub non-existent method #{real_class_name}#{method_type}#{meth}"
end
assert_method_signature_match(meth, expected_parameters, actual_parameters) click to toggle source
# File lib/strictly_fake.rb, line 78
def assert_method_signature_match(meth, expected_parameters, actual_parameters)
  return if method_signatures_match?(expected_parameters, actual_parameters)

  method_type = @real.is_a?(Class) ? '.' : '#'

  raise Error, "Expected #{real_class_name}#{method_type}#{meth} stub to "\
    "accept (#{format_parametes(expected_parameters)}), but was (#{format_parametes(actual_parameters)})"
end
convert_to_lambda(&block) click to toggle source

Procs don't have `req` parameters, but lambdas do

# File lib/strictly_fake.rb, line 130
def convert_to_lambda(&block)
  obj = Object.new
  obj.define_singleton_method(:_, &block)
  obj.method(:_).to_proc
end
format_parametes(parameters) click to toggle source

rubocop:disable Metrics/MethodLength

# File lib/strictly_fake.rb, line 88
def format_parametes(parameters)
  parameters.map do |(type, name)|
    {
      req: 'req',
      opt: 'opt=',
      rest: '*rest',
      key: ":#{name}",
      keyreq: ":#{name}",
      keyrest: '**keyrest',
      block: '&block'
    }.fetch(type)
  end.join(', ')
end
method_signatures_match?(expected_parameters, actual_parameters) click to toggle source

rubocop:enable Metrics/MethodLength

# File lib/strictly_fake.rb, line 103
def method_signatures_match?(expected_parameters, actual_parameters)
  expected_keyword_parameters, expected_positional_parameters = split_parameters_by_type(expected_parameters)
  actual_keyword_parameters, actual_positional_parameters = split_parameters_by_type(actual_parameters)

  positional_arguments_match = expected_positional_parameters == actual_positional_parameters
  keyword_arguments_match = expected_keyword_parameters == actual_keyword_parameters

  positional_arguments_match && keyword_arguments_match
end
pop_keyrest(keyword_parameters) click to toggle source
# File lib/strictly_fake.rb, line 123
def pop_keyrest(keyword_parameters)
  return unless keyword_parameters.last && keyword_parameters.last.first == :keyrest

  keyword_parameters.pop
end
real_class_name() click to toggle source
# File lib/strictly_fake.rb, line 67
def real_class_name
  @real.is_a?(Class) ? @real.name : @real.class.name
end
split_parameters_by_type(parameters) click to toggle source
# File lib/strictly_fake.rb, line 113
def split_parameters_by_type(parameters)
  keyword_parameters, positional_parameters = parameters.partition { |(arg_type)| arg_type.to_s =~ /^key/ }
  keyrest = pop_keyrest(keyword_parameters)

  [
    keyword_parameters.map(&:last).sort + (keyrest ? [:keyrest] : []),
    positional_parameters.map(&:first).reject { |p| p == :block }
  ]
end
stub_method(meth, &block) click to toggle source
# File lib/strictly_fake.rb, line 55
def stub_method(meth, &block)
  if Object.respond_to?(meth)
    (class << self; self; end).class_eval do
      undef_method meth
    end
  end

  (class << @fake; self; end).class_eval do
    define_method(meth, &block)
  end
end