class MuchStub::Stub

Attributes

do[R]
ivar_name[R]
method_name[R]
name[R]

Public Class Methods

key(object, method_name) click to toggle source
# File lib/much-stub.rb, line 87
def self.key(object, method_name)
  "--#{object.object_id}--#{method_name}--"
end
new(object, method_name, orig_caller = nil, &block) click to toggle source
# File lib/much-stub.rb, line 93
def initialize(object, method_name, orig_caller = nil, &block)
  orig_caller ||= caller_locations
  @metaclass   = class << object; self; end
  @method_name = method_name.to_s
  @name        = "__muchstub_stub__#{object.object_id}_#{@method_name}"
  @ivar_name   = "@__muchstub_stub_#{object.object_id}_" \
                 "#{@method_name.to_sym.object_id}"

  setup(object, orig_caller)

  @do     = block
  @lookup = {}
end

Public Instance Methods

call(*pargs, orig_caller: nil, **kargs, &block) click to toggle source
# File lib/much-stub.rb, line 115
def call(*pargs, orig_caller: nil, **kargs, &block)
  orig_caller ||= caller_locations
  args = combined_args(pargs, kargs)
  unless MuchStub.arity_matches?(@method, args)
    raise(
      StubArityError.new(
        @method,
        args,
        method_name: @method_name,
        backtrace: orig_caller,
      ),
    )
  end
  lookup(pargs, kargs, orig_caller).call(*pargs, **kargs, &block)
rescue NotStubbedError
  @lookup.rehash
  lookup(pargs, kargs, orig_caller).call(*pargs, **kargs, &block)
end
call_method(*pargs, **kargs, &block) click to toggle source
# File lib/much-stub.rb, line 111
def call_method(*pargs, **kargs, &block)
  @method.call(*pargs, **kargs, &block)
end
do=(block) click to toggle source
# File lib/much-stub.rb, line 107
def do=(block)
  @do = block || @do
end
inspect() click to toggle source
# File lib/much-stub.rb, line 171
def inspect
  "#<#{self.class}:#{format("0x0%x", (object_id << 1))}" \
  " @method_name=#{@method_name.inspect}" \
  ">"
end
on_call(&on_call_block) click to toggle source
# File lib/much-stub.rb, line 151
def on_call(&on_call_block)
  stub_block =
    ->(*pargs, **kargs, &block){
      on_call_block&.call(MuchStub::Call.new(*pargs, **kargs, &block))
    }
  if @lookup.empty?
    @do = stub_block
  elsif @lookup.value?(nil)
    @lookup.transform_values!{ |value| value.nil? ? stub_block : value }
  end
  self
end
teardown() click to toggle source
# File lib/much-stub.rb, line 164
def teardown
  @metaclass.send(:undef_method, @method_name)
  MuchStub.send(:remove_instance_variable, @ivar_name)
  @metaclass.send(:alias_method, @method_name, @name)
  @metaclass.send(:undef_method, @name)
end
with(*pargs, **kargs, &block) click to toggle source
# File lib/much-stub.rb, line 134
def with(*pargs, **kargs, &block)
  orig_caller = caller_locations
  args = combined_args(pargs, kargs)
  unless MuchStub.arity_matches?(@method, args)
    raise(
      StubArityError.new(
        @method,
        args,
        method_name: @method_name,
        backtrace: orig_caller,
      ),
    )
  end
  @lookup[args] = block
  self
end

Private Instance Methods

combined_args(pargs, kargs) click to toggle source
# File lib/much-stub.rb, line 238
def combined_args(pargs, kargs)
  pargs + [(kargs.empty? ? nil : kargs)].compact
end
inspect_call(args) click to toggle source
# File lib/much-stub.rb, line 234
def inspect_call(args)
  "`#{@method_name}(#{args.map(&:inspect).join(",")})`"
end
inspect_lookup_stubs() click to toggle source
# File lib/much-stub.rb, line 230
def inspect_lookup_stubs
  @lookup.keys.map{ |args| "    - #{inspect_call(args)}" }.join("\n")
end
lookup(pargs, kargs, orig_caller) click to toggle source
# File lib/much-stub.rb, line 211
def lookup(pargs, kargs, orig_caller)
  args = combined_args(pargs, kargs)
  @lookup.fetch(args) do
    self.do ||
    begin
      msg = "#{inspect_call(args)} not stubbed."
      inspect_lookup_stubs.tap do |stubs|
        msg += "\nStubs:\n#{stubs}" unless stubs.empty?
      end
      raise NotStubbedError, msg, orig_caller.map(&:to_s)
    end
  end ||
  raise(
    StubError,
    "#{inspect_call(args)} stubbed with no block.",
    orig_caller.map(&:to_s),
  )
end
setup(object, orig_caller) click to toggle source
# File lib/much-stub.rb, line 179
    def setup(object, orig_caller)
      unless object.respond_to?(@method_name)
        msg = "#{object.inspect} does not respond to `#{@method_name}`"
        raise StubError, msg, orig_caller.map(&:to_s)
      end
      is_constant          = object.is_a?(Module)
      local_object_methods = object.methods(false).map(&:to_s)
      all_object_methods   = object.methods.map(&:to_s)
      if (is_constant && !local_object_methods.include?(@method_name)) ||
         (!is_constant && !all_object_methods.include?(@method_name))
        params_list = ParameterList.new(object, @method_name)
        @metaclass.class_eval <<-method
          def #{@method_name}(#{params_list}); super; end
        method
      end

      # already stubbed
      unless local_object_methods.include?(@name)
        @metaclass.send(:alias_method, @name, @method_name)
      end
      @method = object.method(@name)

      MuchStub.instance_variable_set(@ivar_name, self)
      @metaclass.class_eval <<-stub_method
        def #{@method_name}(*pargs, **kargs, &block)
          MuchStub
            .instance_variable_get("#{@ivar_name}")
            .call(*pargs, orig_caller: caller_locations, **kargs, &block)
        end
      stub_method
    end