spy_rb 3.3.0 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9c273641c4e1545c5b41bca19c98f20a5bc1fcac
4
- data.tar.gz: 766f1883942aa7fbee3ccc76815b2c21a2d5fba0
3
+ metadata.gz: 53c61d7800f4dfd159fc081d34ad780b225cc5b1
4
+ data.tar.gz: 68c92a4fbadef7bf61acfcb1aa84d5405e16e41a
5
5
  SHA512:
6
- metadata.gz: 0df0382a994eae8fe1d650713c7239d4daf0d2c9545eae5636c58bd07c249f744726978922cabe21cc42202070137f8c05046b44f8d15821d0d86345c175694b
7
- data.tar.gz: 67000b046fa2d28f5159d9f8c13e48625f05fa620007367a979e9c1cbd4eb730d7f098f081fe60b7c06f93caf3769f95f1e01d09b4bcf6276e4cc899c35fd5de
6
+ metadata.gz: ccd3238f674765a9d9ee84f5fad2fd66f9c336118f8bf1a5698b927a719bec36257da6c4792522a5ae917faf75e7c5f2c7bb03ee3d98246ac58043ac2c91740f
7
+ data.tar.gz: '0984f22b7e030d699c503319e18701931398632255c6ddc487e0e285fe6c3949b1d08e45327e476dbcc0aa05a204822f65a554bf0081df2a915f857b93e07fde'
@@ -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)
@@ -1,21 +1,26 @@
1
1
  module Spy
2
2
  class MethodCall
3
- attr_reader :name, :receiver, :caller, :args, :block
4
- attr_accessor :result
3
+ attr_reader :receiver, :backtrace, :args, :block, :result
5
4
 
6
- def initialize(replayer, name, receiver, method_caller, *args)
7
- @replayer = replayer
8
- @name = name
5
+ def initialize(spy, receiver, args, block, backtrace)
6
+ @spy = spy
9
7
  @receiver = receiver
10
- @args = args
11
- @caller = method_caller
12
- @block = Proc.new if block_given?
8
+ @args = args
9
+ @block = block
10
+ @backtrace = backtrace
13
11
  end
14
12
 
15
- def replay
16
- @replayer.call
13
+ def name
14
+ @spy.original.name
17
15
  end
18
16
 
19
- alias call_original replay
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/determine_visibility'
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 = @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 = @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
@@ -1,38 +1,18 @@
1
- require 'spy/determine_visibility'
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 = @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 = @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
@@ -1,3 +1,3 @@
1
1
  module Spy
2
- VERSION = '3.3.0'
2
+ VERSION = '4.0.0'
3
3
  end
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: 3.3.0
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-01-28 00:00:00.000000000 Z
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/strategy/base.rb
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
@@ -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