class Spy::Instance

Attributes

call_history[R]
original[R]
spied[R]
strategy[R]

Public Class Methods

new(blueprint) click to toggle source
# File lib/spy/instance.rb, line 13
def initialize(blueprint)
  original =
    case blueprint.type
    when :dynamic_delegation
      FakeMethod.new(blueprint.msg) { |*args, &block| blueprint.target.method_missing(blueprint.msg, *args, &block) }
    when :instance_method
      blueprint.target.instance_method(blueprint.msg)
    else
      blueprint.target.method(blueprint.msg)
    end

  @original = original
  @spied = blueprint.target
  @strategy = choose_strategy(blueprint)
  @call_history = []

  @internal = {}
  @internal[:conditional_filters] = []
  @internal[:before_callbacks] = []
  @internal[:after_callbacks]= []
  @internal[:around_procs] = []
  @internal[:instead]= nil
end

Public Instance Methods

after(&block) click to toggle source
# File lib/spy/instance.rb, line 76
def after(&block)
  @internal[:after_callbacks] << block
  self
end
apply(method_call) click to toggle source

@private

# File lib/spy/instance.rb, line 100
def apply(method_call)
  return method_call.call_original unless passes_all_conditions?(method_call)

  result = nil
  runner =
    if @internal[:instead]
      proc do
        @call_history << method_call
        result = @internal[:instead].call(method_call)
      end
    else
      proc do
        @call_history << method_call
        result = method_call.call_original(true)
      end
    end

  if @internal[:around_procs].any?
    runner = @internal[:around_procs].reduce(runner) do |p, wrapper|
      proc { wrapper[method_call, &p] }
    end
  end

  run_before_callbacks(method_call)

  runner.call

  run_after_callbacks(method_call)

  result
end
before(&block) click to toggle source
# File lib/spy/instance.rb, line 71
def before(&block)
  @internal[:before_callbacks] << block
  self
end
call_count() click to toggle source
# File lib/spy/instance.rb, line 41
def call_count
  @call_history.size
end
call_original(*args) click to toggle source

@private

# File lib/spy/instance.rb, line 91
def call_original(*args)
  if original.is_a?(UnboundMethod)
    call_original_unbound_method(*args)
  else
    call_original_method(*args)
  end
end
called?() click to toggle source
# File lib/spy/instance.rb, line 86
def called?
  @call_history.any?
end
instead(&block) click to toggle source
# File lib/spy/instance.rb, line 81
def instead(&block)
  @internal[:instead] = block
  self
end
name() click to toggle source
# File lib/spy/instance.rb, line 37
def name
  @original.name
end
replay_all() click to toggle source
# File lib/spy/instance.rb, line 45
def replay_all
  @call_history.map(&:replay)
end
start() click to toggle source
# File lib/spy/instance.rb, line 49
def start
  @strategy.apply
  self
end
stop() click to toggle source
# File lib/spy/instance.rb, line 54
def stop
  @strategy.undo
  self
end
when(&block) click to toggle source
# File lib/spy/instance.rb, line 59
def when(&block)
  @internal[:conditional_filters] << block
  self
end
wrap(&block) click to toggle source

Expect block to yield. Call the rest of the chain when it does

# File lib/spy/instance.rb, line 66
def wrap(&block)
  @internal[:around_procs] << block
  self
end

Private Instance Methods

call_original_method(_receiver, args, block) click to toggle source
# File lib/spy/instance.rb, line 150
def call_original_method(_receiver, args, block)
  original.call(*args, &block)
end
call_original_unbound_method(receiver, args, block) click to toggle source
# File lib/spy/instance.rb, line 146
def call_original_unbound_method(receiver, args, block)
  original.bind(receiver).call(*args, &block)
end
choose_strategy(blueprint) click to toggle source
# File lib/spy/instance.rb, line 154
def choose_strategy(blueprint)
  if blueprint.type == :dynamic_delegation
    Strategy::Intercept.new(self)
  elsif @original.owner == @spied || @original.owner == @spied.singleton_class
    Strategy::Wrap.new(self)
  else
    Strategy::Intercept.new(self)
  end
end
passes_all_conditions?(method_call) click to toggle source
# File lib/spy/instance.rb, line 134
def passes_all_conditions?(method_call)
  @internal[:conditional_filters].all? { |f| f[method_call] }
end
run_after_callbacks(method_call) click to toggle source
# File lib/spy/instance.rb, line 142
def run_after_callbacks(method_call)
  @internal[:after_callbacks].each { |f| f[method_call] }
end
run_before_callbacks(method_call) click to toggle source
# File lib/spy/instance.rb, line 138
def run_before_callbacks(method_call)
  @internal[:before_callbacks].each { |f| f[method_call] }
end