Module: Spy::Strategy::Base

Defined in:
lib/spy/strategy/base.rb

Class Method Summary collapse

Class Method Details

._build_method_call(spy, receiver, *args, &block) ⇒ Object



55
56
57
58
59
60
61
62
63
# File 'lib/spy/strategy/base.rb', line 55

def _build_method_call(spy, receiver, *args, &block)
  Spy::MethodCall.new(
    proc { Spy::Strategy::Base._call_original(spy, receiver, *args, &block) },
    spy.original.name,
    receiver,
    caller.drop_while { |path| path =~ /lib\/spy\/strategy/ },
    *args,
    &block)
end

._call_and_record(spy, receiver, args, opts = {}, &block) ⇒ Object



65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/spy/strategy/base.rb', line 65

def _call_and_record(spy, receiver, args, opts = {}, &block)
  spy.instance_eval do
    if @internal[:instead]
      @internal[:instead].call(Spy::Strategy::Base._build_method_call(spy, receiver, *args, &block))
    else
      record = opts[:record] || Spy::Strategy::Base._build_method_call(spy, receiver, *args, &block)
      @call_history << record

      result = Spy::Strategy::Base._call_original(spy, receiver, *args, &block)
      record.result = result
    end
  end
end

._call_original(spy, receiver, *args, &block) ⇒ Object



79
80
81
82
83
84
85
# File 'lib/spy/strategy/base.rb', line 79

def _call_original(spy, receiver, *args, &block)
  if spy.original.is_a?(UnboundMethod)
    spy.original.bind(receiver).call(*args, &block)
  else
    spy.original.call(*args, &block)
  end
end

.call(spy, receiver, *args, &block) ⇒ Object



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/spy/strategy/base.rb', line 7

def call(spy, receiver, *args, &block)
  spy.instance_eval do
    # TODO - abstract the method call into an object and cache this in
    #   method using an instance variable instead of a local variable.
    #   This will let us be a bit more elegant about how we do before/after
    #   callbacks. We can also merge MethodCall with this responsibility so
    #   it isn't just a data struct
    is_active = if @internal[:conditional_filters].any?
                  mc = Spy::Strategy::Base._build_method_call(spy, receiver, *args, &block)
                  @internal[:conditional_filters].all? { |f| f.call(mc) }
                else
                  true
                end

    return Spy::Strategy::Base._call_original(spy, receiver, *args, &block) unless is_active

    if @internal[:before_callbacks].any?
      mc = Spy::Strategy::Base._build_method_call(spy, receiver, *args, &block)
      @internal[:before_callbacks].each { |f| f.call(mc) }
    end

    if @internal[:around_procs].any?
      mc = Spy::Strategy::Base._build_method_call(spy, receiver, *args, &block)

      # Procify the original call
      # Still return the result from it
      result = nil
      original_proc = proc do
        result = Spy::Strategy::Base._call_and_record(spy, receiver, args, { :record => mc }, &block)
      end

      # Keep wrapping the original proc with each around_proc
      @internal[:around_procs].reduce(original_proc) do |p, wrapper|
        proc { wrapper.call(mc, &p) }
      end.call
    else
      result = Spy::Strategy::Base._call_and_record(spy, receiver, args, &block)
    end

    if @internal[:after_callbacks].any?
      mc = @call_history.last
      @internal[:after_callbacks].each { |f| f.call(mc) }
    end

    result
  end
end