spy_rb 3.3.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/spy/instance.rb +61 -0
- data/lib/spy/method_call.rb +16 -11
- data/lib/spy/replace_method.rb +28 -0
- data/lib/spy/strategy/intercept.rb +3 -19
- data/lib/spy/strategy/wrap.rb +3 -23
- data/lib/spy/version.rb +1 -1
- metadata +3 -4
- data/lib/spy/determine_visibility.rb +0 -16
- data/lib/spy/strategy/base.rb +0 -89
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 53c61d7800f4dfd159fc081d34ad780b225cc5b1
|
4
|
+
data.tar.gz: 68c92a4fbadef7bf61acfcb1aa84d5405e16e41a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ccd3238f674765a9d9ee84f5fad2fd66f9c336118f8bf1a5698b927a719bec36257da6c4792522a5ae917faf75e7c5f2c7bb03ee3d98246ac58043ac2c91740f
|
7
|
+
data.tar.gz: '0984f22b7e030d699c503319e18701931398632255c6ddc487e0e285fe6c3949b1d08e45327e476dbcc0aa05a204822f65a554bf0081df2a915f857b93e07fde'
|
data/lib/spy/instance.rb
CHANGED
@@ -87,8 +87,69 @@ module Spy
|
|
87
87
|
@call_history.any?
|
88
88
|
end
|
89
89
|
|
90
|
+
# @private
|
91
|
+
def call_original(*args)
|
92
|
+
if original.is_a?(UnboundMethod)
|
93
|
+
call_original_unbound_method(*args)
|
94
|
+
else
|
95
|
+
call_original_method(*args)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# @private
|
100
|
+
def apply(method_call)
|
101
|
+
return method_call.call_original unless passes_all_conditions?(method_call)
|
102
|
+
|
103
|
+
run_before_callbacks(method_call)
|
104
|
+
|
105
|
+
result = nil
|
106
|
+
runner =
|
107
|
+
if @internal[:instead]
|
108
|
+
proc do
|
109
|
+
result = @internal[:instead].call(method_call)
|
110
|
+
end
|
111
|
+
else
|
112
|
+
proc do
|
113
|
+
@call_history << method_call
|
114
|
+
result = method_call.call_original(true)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
if @internal[:around_procs].any?
|
119
|
+
runner = @internal[:around_procs].reduce(runner) do |p, wrapper|
|
120
|
+
proc { wrapper[method_call, &p] }
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
runner.call
|
125
|
+
|
126
|
+
run_after_callbacks(method_call)
|
127
|
+
|
128
|
+
result
|
129
|
+
end
|
130
|
+
|
90
131
|
private
|
91
132
|
|
133
|
+
def passes_all_conditions?(method_call)
|
134
|
+
@internal[:conditional_filters].all? { |f| f[method_call] }
|
135
|
+
end
|
136
|
+
|
137
|
+
def run_before_callbacks(method_call)
|
138
|
+
@internal[:before_callbacks].each { |f| f[method_call] }
|
139
|
+
end
|
140
|
+
|
141
|
+
def run_after_callbacks(method_call)
|
142
|
+
@internal[:after_callbacks].each { |f| f[method_call] }
|
143
|
+
end
|
144
|
+
|
145
|
+
def call_original_unbound_method(receiver, args, block)
|
146
|
+
original.bind(receiver).call(*args, &block)
|
147
|
+
end
|
148
|
+
|
149
|
+
def call_original_method(_receiver, args, block)
|
150
|
+
original.call(*args, &block)
|
151
|
+
end
|
152
|
+
|
92
153
|
def choose_strategy(blueprint)
|
93
154
|
if blueprint.type == :dynamic_delegation
|
94
155
|
Strategy::Intercept.new(self)
|
data/lib/spy/method_call.rb
CHANGED
@@ -1,21 +1,26 @@
|
|
1
1
|
module Spy
|
2
2
|
class MethodCall
|
3
|
-
attr_reader :
|
4
|
-
attr_accessor :result
|
3
|
+
attr_reader :receiver, :backtrace, :args, :block, :result
|
5
4
|
|
6
|
-
def initialize(
|
7
|
-
@
|
8
|
-
@name = name
|
5
|
+
def initialize(spy, receiver, args, block, backtrace)
|
6
|
+
@spy = spy
|
9
7
|
@receiver = receiver
|
10
|
-
@args
|
11
|
-
@
|
12
|
-
@
|
8
|
+
@args = args
|
9
|
+
@block = block
|
10
|
+
@backtrace = backtrace
|
13
11
|
end
|
14
12
|
|
15
|
-
def
|
16
|
-
@
|
13
|
+
def name
|
14
|
+
@spy.original.name
|
17
15
|
end
|
18
16
|
|
19
|
-
|
17
|
+
def call_original(persist_result = false)
|
18
|
+
result = @spy.call_original(@receiver, @args, @block)
|
19
|
+
@result = result if persist_result
|
20
|
+
result
|
21
|
+
end
|
22
|
+
|
23
|
+
alias replay call_original
|
24
|
+
alias caller backtrace
|
20
25
|
end
|
21
26
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spy/method_call'
|
2
|
+
|
3
|
+
module Spy
|
4
|
+
module ReplaceMethod
|
5
|
+
def self.call(klass, spy, mode: nil, remove_existing: false)
|
6
|
+
klass.class_eval do
|
7
|
+
name = spy.original.name
|
8
|
+
|
9
|
+
remove_method(name) if remove_existing
|
10
|
+
|
11
|
+
case mode
|
12
|
+
when :stub
|
13
|
+
define_method(name, ReplaceMethod.impl(spy))
|
14
|
+
when :restore
|
15
|
+
define_method(name, spy.original)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.impl(spy)
|
21
|
+
proc do |*args, &block|
|
22
|
+
backtrace = caller.drop_while { |path| path =~ /lib\/spy\/replace_method\.rb$/ }
|
23
|
+
method_call = MethodCall.new(spy, self, args, block, backtrace)
|
24
|
+
spy.apply(method_call)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -1,5 +1,4 @@
|
|
1
|
-
require 'spy/
|
2
|
-
require 'spy/strategy/base'
|
1
|
+
require 'spy/replace_method'
|
3
2
|
|
4
3
|
module Spy
|
5
4
|
module Strategy
|
@@ -18,26 +17,11 @@ module Spy
|
|
18
17
|
end
|
19
18
|
|
20
19
|
def apply
|
21
|
-
spy
|
22
|
-
@target.class_eval do
|
23
|
-
# Add the spy to the intercept target
|
24
|
-
define_method spy.original.name do |*args, &block|
|
25
|
-
Spy::Strategy::Base.call(spy, self, *args, &block)
|
26
|
-
end
|
27
|
-
|
28
|
-
# Make the visibility of the spy match the spied original
|
29
|
-
unless spy.original.is_a?(FakeMethod)
|
30
|
-
visibility = DetermineVisibility.call(spy.original)
|
31
|
-
send(visibility, spy.original.name)
|
32
|
-
end
|
33
|
-
end
|
20
|
+
ReplaceMethod.call(@target, @spy, mode: :stub)
|
34
21
|
end
|
35
22
|
|
36
23
|
def undo
|
37
|
-
spy
|
38
|
-
@target.class_eval do
|
39
|
-
remove_method spy.original.name
|
40
|
-
end
|
24
|
+
ReplaceMethod.call(@target, @spy, remove_existing: true)
|
41
25
|
end
|
42
26
|
end
|
43
27
|
end
|
data/lib/spy/strategy/wrap.rb
CHANGED
@@ -1,38 +1,18 @@
|
|
1
|
-
require 'spy/
|
2
|
-
require 'spy/strategy/base'
|
1
|
+
require 'spy/replace_method'
|
3
2
|
|
4
3
|
module Spy
|
5
4
|
module Strategy
|
6
5
|
class Wrap
|
7
6
|
def initialize(spy)
|
8
7
|
@spy = spy
|
9
|
-
@visibility = DetermineVisibility.call(spy.original)
|
10
8
|
end
|
11
9
|
|
12
10
|
def apply
|
13
|
-
spy
|
14
|
-
visibility = @visibility
|
15
|
-
@spy.original.owner.class_eval do
|
16
|
-
undef_method spy.original.name
|
17
|
-
|
18
|
-
# Replace the method with the spy
|
19
|
-
define_method spy.original.name do |*args, &block|
|
20
|
-
Spy::Strategy::Base.call(spy, self, *args, &block)
|
21
|
-
end
|
22
|
-
|
23
|
-
# Make the visibility of the spy match the spied original
|
24
|
-
send(visibility, spy.original.name)
|
25
|
-
end
|
11
|
+
ReplaceMethod.call(@spy.original.owner, @spy, mode: :stub)
|
26
12
|
end
|
27
13
|
|
28
14
|
def undo
|
29
|
-
spy
|
30
|
-
visibility = @visibility
|
31
|
-
spy.original.owner.class_eval do
|
32
|
-
remove_method spy.original.name
|
33
|
-
define_method spy.original.name, spy.original
|
34
|
-
send(visibility, spy.original.name)
|
35
|
-
end
|
15
|
+
ReplaceMethod.call(@spy.original.owner, @spy, mode: :restore)
|
36
16
|
end
|
37
17
|
end
|
38
18
|
end
|
data/lib/spy/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spy_rb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 4.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Josh Bodah
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-04-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -51,14 +51,13 @@ files:
|
|
51
51
|
- lib/spy/api.rb
|
52
52
|
- lib/spy/blueprint.rb
|
53
53
|
- lib/spy/core.rb
|
54
|
-
- lib/spy/determine_visibility.rb
|
55
54
|
- lib/spy/errors.rb
|
56
55
|
- lib/spy/fake_method.rb
|
57
56
|
- lib/spy/instance.rb
|
58
57
|
- lib/spy/method_call.rb
|
59
58
|
- lib/spy/multi.rb
|
60
59
|
- lib/spy/registry.rb
|
61
|
-
- lib/spy/
|
60
|
+
- lib/spy/replace_method.rb
|
62
61
|
- lib/spy/strategy/intercept.rb
|
63
62
|
- lib/spy/strategy/wrap.rb
|
64
63
|
- lib/spy/version.rb
|
@@ -1,16 +0,0 @@
|
|
1
|
-
module Spy
|
2
|
-
module DetermineVisibility
|
3
|
-
# @param [Method, UnboundMethod] method
|
4
|
-
# @returns [Symbol] whether the method is public, private, or protected
|
5
|
-
def self.call(method)
|
6
|
-
owner = method.owner
|
7
|
-
%w(public private protected).each do |vis|
|
8
|
-
query = "#{vis}_method_defined?"
|
9
|
-
if owner.respond_to?(query) && owner.send(query, method.name)
|
10
|
-
return vis
|
11
|
-
end
|
12
|
-
end
|
13
|
-
raise NoMethodError, "couldn't find method #{method.name} belonging to #{owner}"
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
data/lib/spy/strategy/base.rb
DELETED
@@ -1,89 +0,0 @@
|
|
1
|
-
require 'spy/method_call'
|
2
|
-
|
3
|
-
module Spy
|
4
|
-
module Strategy
|
5
|
-
module Base
|
6
|
-
class << self
|
7
|
-
def call(spy, receiver, *args, &block)
|
8
|
-
spy.instance_eval do
|
9
|
-
# TODO - abstract the method call into an object and cache this in
|
10
|
-
# method using an instance variable instead of a local variable.
|
11
|
-
# This will let us be a bit more elegant about how we do before/after
|
12
|
-
# callbacks. We can also merge MethodCall with this responsibility so
|
13
|
-
# it isn't just a data struct
|
14
|
-
is_active = if @internal[:conditional_filters].any?
|
15
|
-
mc = Spy::Strategy::Base._build_method_call(spy, receiver, *args, &block)
|
16
|
-
@internal[:conditional_filters].all? { |f| f.call(mc) }
|
17
|
-
else
|
18
|
-
true
|
19
|
-
end
|
20
|
-
|
21
|
-
return Spy::Strategy::Base._call_original(spy, receiver, *args, &block) unless is_active
|
22
|
-
|
23
|
-
if @internal[:before_callbacks].any?
|
24
|
-
mc = Spy::Strategy::Base._build_method_call(spy, receiver, *args, &block)
|
25
|
-
@internal[:before_callbacks].each { |f| f.call(mc) }
|
26
|
-
end
|
27
|
-
|
28
|
-
if @internal[:around_procs].any?
|
29
|
-
mc = Spy::Strategy::Base._build_method_call(spy, receiver, *args, &block)
|
30
|
-
|
31
|
-
# Procify the original call
|
32
|
-
# Still return the result from it
|
33
|
-
result = nil
|
34
|
-
original_proc = proc do
|
35
|
-
result = Spy::Strategy::Base._call_and_record(spy, receiver, args, { :record => mc }, &block)
|
36
|
-
end
|
37
|
-
|
38
|
-
# Keep wrapping the original proc with each around_proc
|
39
|
-
@internal[:around_procs].reduce(original_proc) do |p, wrapper|
|
40
|
-
proc { wrapper.call(mc, &p) }
|
41
|
-
end.call
|
42
|
-
else
|
43
|
-
result = Spy::Strategy::Base._call_and_record(spy, receiver, args, &block)
|
44
|
-
end
|
45
|
-
|
46
|
-
if @internal[:after_callbacks].any?
|
47
|
-
mc = @call_history.last
|
48
|
-
@internal[:after_callbacks].each { |f| f.call(mc) }
|
49
|
-
end
|
50
|
-
|
51
|
-
result
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
def _build_method_call(spy, receiver, *args, &block)
|
56
|
-
Spy::MethodCall.new(
|
57
|
-
proc { Spy::Strategy::Base._call_original(spy, receiver, *args, &block) },
|
58
|
-
spy.original.name,
|
59
|
-
receiver,
|
60
|
-
caller.drop_while { |path| path =~ /lib\/spy\/strategy/ },
|
61
|
-
*args,
|
62
|
-
&block)
|
63
|
-
end
|
64
|
-
|
65
|
-
def _call_and_record(spy, receiver, args, opts = {}, &block)
|
66
|
-
spy.instance_eval do
|
67
|
-
if @internal[:instead]
|
68
|
-
@internal[:instead].call(Spy::Strategy::Base._build_method_call(spy, receiver, *args, &block))
|
69
|
-
else
|
70
|
-
record = opts[:record] || Spy::Strategy::Base._build_method_call(spy, receiver, *args, &block)
|
71
|
-
@call_history << record
|
72
|
-
|
73
|
-
result = Spy::Strategy::Base._call_original(spy, receiver, *args, &block)
|
74
|
-
record.result = result
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
def _call_original(spy, receiver, *args, &block)
|
80
|
-
if spy.original.is_a?(UnboundMethod)
|
81
|
-
spy.original.bind(receiver).call(*args, &block)
|
82
|
-
else
|
83
|
-
spy.original.call(*args, &block)
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|