spy 0.2.1 → 0.2.2
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 +7 -0
- data/.travis.yml +1 -1
- data/Gemfile +1 -1
- data/lib/spy/constant.rb +7 -9
- data/lib/spy/nest.rb +2 -0
- data/lib/spy/subroutine.rb +73 -81
- data/lib/spy/version.rb +1 -1
- data/test/spy/test_subroutine.rb +22 -8
- data/test/support/pen.rb +12 -0
- metadata +13 -21
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 25f96e1254110c34d4b25ace27db39cf4933cc2a
|
4
|
+
data.tar.gz: 84320005a4c47158b70dc86fca661f6ae95f6ad6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 340277d830dfb87085d61fb443b834cb6636e8dda7b5d2af0166aab6835918747343849efed3b56032071d5d44b49cebaca0edb04df0c7997c10006cdb6cc897
|
7
|
+
data.tar.gz: 2b147cc08e3612270d8f18789bc4116621334e6da864bb3299b79ce857247513c467e4bf7f27e8c0354b064801445b392856489758fd6456015d44000dad987d
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/lib/spy/constant.rb
CHANGED
@@ -19,9 +19,7 @@ module Spy
|
|
19
19
|
raise "#{base_module.inspect} is not a kind of Module" unless base_module.is_a? Module
|
20
20
|
raise "#{constant_name.inspect} is not a kind of Symbol" unless constant_name.is_a? Symbol
|
21
21
|
@base_module, @constant_name = base_module, constant_name.to_sym
|
22
|
-
@original_value = nil
|
23
|
-
@new_value = nil
|
24
|
-
@previously_defined = nil
|
22
|
+
@original_value = @new_value = @previously_defined = nil
|
25
23
|
end
|
26
24
|
|
27
25
|
# full name of spied constant
|
@@ -33,11 +31,12 @@ module Spy
|
|
33
31
|
# @param opts [Hash{force => false}] set :force => true if you want it to ignore if the constant exists
|
34
32
|
# @return [self]
|
35
33
|
def hook(opts = {})
|
34
|
+
opts[:force] ||= false
|
36
35
|
Nest.fetch(base_module).add(self)
|
37
36
|
Agency.instance.recruit(self)
|
38
|
-
|
37
|
+
|
39
38
|
@previously_defined = currently_defined?
|
40
|
-
if
|
39
|
+
if previously_defined? || !opts[:force]
|
41
40
|
@original_value = base_module.const_get(constant_name, false)
|
42
41
|
end
|
43
42
|
and_return(@new_value)
|
@@ -50,10 +49,9 @@ module Spy
|
|
50
49
|
Nest.get(base_module).remove(self)
|
51
50
|
Agency.instance.retire(self)
|
52
51
|
|
53
|
-
if
|
54
|
-
|
55
|
-
|
56
|
-
@original_value = nil
|
52
|
+
and_return(@original_value) if previously_defined?
|
53
|
+
|
54
|
+
@original_value = @previously_defined = nil
|
57
55
|
self
|
58
56
|
end
|
59
57
|
|
data/lib/spy/nest.rb
CHANGED
data/lib/spy/subroutine.rb
CHANGED
@@ -38,10 +38,11 @@ module Spy
|
|
38
38
|
raise "#{base_object} method '#{method_name}' has already been hooked" if hooked?
|
39
39
|
|
40
40
|
hook_opts[:force] ||= base_object.is_a?(Double)
|
41
|
-
|
41
|
+
hook_opts[:visibility] ||= original_method_visibility
|
42
|
+
|
43
|
+
if original_method_visibility || !hook_opts[:force]
|
42
44
|
@original_method = current_method
|
43
45
|
end
|
44
|
-
hook_opts[:visibility] ||= method_visibility
|
45
46
|
|
46
47
|
base_object.send(define_method_with, method_name, override_method)
|
47
48
|
|
@@ -61,7 +62,7 @@ module Spy
|
|
61
62
|
|
62
63
|
if original_method && method_owner == original_method.owner
|
63
64
|
original_method.owner.send(:define_method, method_name, original_method)
|
64
|
-
original_method.owner.send(
|
65
|
+
original_method.owner.send(original_method_visibility, method_name) if original_method_visibility
|
65
66
|
else
|
66
67
|
method_owner.send(:remove_method, method_name)
|
67
68
|
end
|
@@ -83,18 +84,10 @@ module Spy
|
|
83
84
|
#
|
84
85
|
# @return [self]
|
85
86
|
def and_return(value = nil)
|
87
|
+
raise ArgumentError.new("value and block conflict. Choose one") if !(value.nil? || value.is_a?(Hash) && value.has_key?(:force)) && block_given?
|
86
88
|
if block_given?
|
87
89
|
@plan = Proc.new
|
88
|
-
|
89
|
-
if !(value.is_a?(Hash) && value[:force]) &&
|
90
|
-
original_method &&
|
91
|
-
original_method.arity >=0 &&
|
92
|
-
@plan.arity > original_method.arity
|
93
|
-
raise ArgumentError.new "The original method only has an arity of #{original_method.arity} you have an arity of #{@plan.arity}"
|
94
|
-
end
|
95
|
-
else
|
96
|
-
raise ArgumentError.new("value and block conflict. Choose one") if !value.nil?
|
97
|
-
end
|
90
|
+
check_for_too_many_arguments!(@plan)
|
98
91
|
else
|
99
92
|
@plan = Proc.new { value }
|
100
93
|
end
|
@@ -114,11 +107,10 @@ module Spy
|
|
114
107
|
# tells the spy to call the original method
|
115
108
|
# @return [self]
|
116
109
|
def and_call_through
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
@plan = Proc.new do |*args, &block|
|
110
|
+
@plan = Proc.new do |*args, &block|
|
111
|
+
if original_method
|
112
|
+
original_method.call(*args, &block)
|
113
|
+
else
|
122
114
|
base_object.send(:method_missing, method_name, *args, &block)
|
123
115
|
end
|
124
116
|
end
|
@@ -182,9 +174,12 @@ module Spy
|
|
182
174
|
# method.
|
183
175
|
def invoke(object, args, block, called_from)
|
184
176
|
check_arity!(args.size)
|
185
|
-
result =
|
177
|
+
result = if @plan
|
178
|
+
check_for_too_many_arguments!(@plan)
|
179
|
+
@plan.call(*args, &block)
|
180
|
+
end
|
186
181
|
ensure
|
187
|
-
calls << CallLog.new(object,called_from, args, block, result)
|
182
|
+
calls << CallLog.new(object, called_from, args, block, result)
|
188
183
|
end
|
189
184
|
|
190
185
|
# reset the call log
|
@@ -206,43 +201,32 @@ module Spy
|
|
206
201
|
METHOD
|
207
202
|
end
|
208
203
|
|
209
|
-
def call_with_yield(&block)
|
210
|
-
raise "no block sent" unless block
|
211
|
-
value = nil
|
212
|
-
@args_to_yield.each do |args|
|
213
|
-
if block.arity > -1 && args.length != block.arity
|
214
|
-
@error_generator.raise_wrong_arity_error args, block.arity
|
215
|
-
end
|
216
|
-
value = @eval_context ? @eval_context.instance_exec(*args, &block) : block.call(*args)
|
217
|
-
end
|
218
|
-
value
|
219
|
-
end
|
220
|
-
|
221
204
|
def clear_method!
|
222
205
|
@hooked = false
|
223
|
-
@hook_opts = @original_method = @arity_range = @
|
206
|
+
@hook_opts = @original_method = @arity_range = @original_method_visibility = @method_owner= nil
|
224
207
|
end
|
225
208
|
|
226
|
-
def
|
227
|
-
@
|
228
|
-
if base_object_respond_to?(method_name)
|
229
|
-
if original_method && original_method.owner.protected_method_defined?(method_name)
|
230
|
-
:protected
|
231
|
-
else
|
232
|
-
:public
|
233
|
-
end
|
234
|
-
elsif base_object_respond_to?(method_name, true)
|
235
|
-
:private
|
236
|
-
end
|
209
|
+
def original_method_visibility
|
210
|
+
@original_method_visibility ||= method_visibility_of(method_name)
|
237
211
|
end
|
238
212
|
|
239
|
-
def
|
213
|
+
def method_visibility_of(method_name, all = true)
|
240
214
|
if @singleton_method
|
241
|
-
base_object.
|
215
|
+
if base_object.public_methods(all).include?(method_name)
|
216
|
+
:public
|
217
|
+
elsif base_object.protected_methods(all).include?(method_name)
|
218
|
+
:protected
|
219
|
+
elsif base_object.private_methods(all).include?(method_name)
|
220
|
+
:private
|
221
|
+
end
|
242
222
|
else
|
243
|
-
base_object.
|
244
|
-
|
245
|
-
)
|
223
|
+
if base_object.public_instance_methods(all).include?(method_name)
|
224
|
+
:public
|
225
|
+
elsif base_object.protected_instance_methods(all).include?(method_name)
|
226
|
+
:protected
|
227
|
+
elsif base_object.private_instance_methods(all).include?(method_name)
|
228
|
+
:private
|
229
|
+
end
|
246
230
|
end
|
247
231
|
end
|
248
232
|
|
@@ -251,11 +235,41 @@ module Spy
|
|
251
235
|
end
|
252
236
|
|
253
237
|
def check_arity!(arity)
|
254
|
-
|
238
|
+
return unless arity_range
|
239
|
+
if arity < arity_range.min
|
240
|
+
raise ArgumentError.new("wrong number of arguments (#{arity} for #{arity_range.min})")
|
241
|
+
elsif arity > arity_range.max
|
242
|
+
raise ArgumentError.new("wrong number of arguments (#{arity} for #{arity_range.max})")
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
def check_for_too_many_arguments!(block)
|
247
|
+
return unless arity_range
|
248
|
+
min_arity = block.arity
|
249
|
+
min_arity = min_arity.abs - 1 if min_arity < 0
|
250
|
+
|
251
|
+
if min_arity > arity_range.max
|
252
|
+
raise ArgumentError.new("block requires #{min_arity} arguments while original_method require a maximum of #{arity_range.max}")
|
253
|
+
end
|
255
254
|
end
|
256
255
|
|
257
256
|
def arity_range
|
258
|
-
@arity_range ||=
|
257
|
+
@arity_range ||=
|
258
|
+
if original_method
|
259
|
+
min = max = 0
|
260
|
+
original_method.parameters.each do |type,_|
|
261
|
+
case type
|
262
|
+
when :req
|
263
|
+
min += 1
|
264
|
+
max += 1
|
265
|
+
when :opt
|
266
|
+
max += 1
|
267
|
+
when :rest
|
268
|
+
max = Float::INFINITY
|
269
|
+
end
|
270
|
+
end
|
271
|
+
(min..max)
|
272
|
+
end
|
259
273
|
end
|
260
274
|
|
261
275
|
def current_method
|
@@ -267,34 +281,6 @@ module Spy
|
|
267
281
|
end
|
268
282
|
|
269
283
|
class << self
|
270
|
-
# @private
|
271
|
-
def arity_range_of(block)
|
272
|
-
raise "#{block.inspect} does not respond to :parameters" unless block.respond_to?(:parameters)
|
273
|
-
min = max = 0
|
274
|
-
block.parameters.each do |type,_|
|
275
|
-
case type
|
276
|
-
when :req
|
277
|
-
min += 1
|
278
|
-
max += 1
|
279
|
-
when :opt
|
280
|
-
max += 1
|
281
|
-
when :rest
|
282
|
-
max = Float::INFINITY
|
283
|
-
end
|
284
|
-
end
|
285
|
-
(min..max)
|
286
|
-
end
|
287
|
-
|
288
|
-
# @private
|
289
|
-
def check_arity_against_range!(arity_range, arity)
|
290
|
-
return unless arity_range
|
291
|
-
if arity < arity_range.min
|
292
|
-
raise ArgumentError.new("wrong number of arguments (#{arity} for #{arity_range.min})")
|
293
|
-
elsif arity > arity_range.max
|
294
|
-
raise ArgumentError.new("wrong number of arguments (#{arity} for #{arity_range.max})")
|
295
|
-
end
|
296
|
-
end
|
297
|
-
|
298
284
|
# retrieve the method spy from an object
|
299
285
|
# @param base_object
|
300
286
|
# @param method_name [Symbol]
|
@@ -316,12 +302,18 @@ module Spy
|
|
316
302
|
|
317
303
|
# retrieve all the spies from a given object
|
318
304
|
# @param base_object
|
305
|
+
# @param singleton_method [Boolean] (true) only get singleton_method_spies
|
319
306
|
# @return [Array<Subroutine>]
|
320
|
-
def get_spies(base_object)
|
307
|
+
def get_spies(base_object, singleton_methods = true)
|
308
|
+
if singleton_methods
|
321
309
|
all_methods = base_object.public_methods(false) +
|
322
310
|
base_object.protected_methods(false) +
|
323
311
|
base_object.private_methods(false)
|
324
|
-
|
312
|
+
else
|
313
|
+
all_methods = base_object.instance_methods(false) +
|
314
|
+
base_object.private_instance_methods(false)
|
315
|
+
end
|
316
|
+
|
325
317
|
all_methods.map do |method_name|
|
326
318
|
Agency.instance.find(get_spy_id(base_object.method(method_name)))
|
327
319
|
end.compact
|
data/lib/spy/version.rb
CHANGED
data/test/spy/test_subroutine.rb
CHANGED
@@ -74,8 +74,7 @@ module Spy
|
|
74
74
|
end
|
75
75
|
|
76
76
|
def test_spy_can_hook_a_non_existent_method_if_param_set
|
77
|
-
|
78
|
-
spy.hook(force: true)
|
77
|
+
Subroutine.new(@pen, :no_method).hook(force:true).and_return(:yep)
|
79
78
|
assert_equal :yep, @pen.no_method
|
80
79
|
end
|
81
80
|
|
@@ -188,24 +187,39 @@ module Spy
|
|
188
187
|
def test_hook_mimics_public_visibility
|
189
188
|
spy_on(@pen, :public_method)
|
190
189
|
assert @pen.singleton_class.public_method_defined? :public_method
|
191
|
-
refute @pen.singleton_class.protected_method_defined? :public_method
|
192
|
-
refute @pen.singleton_class.private_method_defined? :public_method
|
193
190
|
end
|
194
191
|
|
195
192
|
def test_hook_mimics_protected_visibility
|
196
193
|
spy_on(@pen, :protected_method)
|
197
|
-
refute @pen.singleton_class.public_method_defined? :protected_method
|
198
194
|
assert @pen.singleton_class.protected_method_defined? :protected_method
|
199
|
-
refute @pen.singleton_class.private_method_defined? :protected_method
|
200
195
|
end
|
201
196
|
|
202
197
|
def test_hook_mimics_private_visibility
|
203
198
|
spy_on(@pen, :private_method)
|
204
|
-
refute @pen.singleton_class.public_method_defined? :private_method
|
205
|
-
refute @pen.singleton_class.protected_method_defined? :private_method
|
206
199
|
assert @pen.singleton_class.private_method_defined? :private_method
|
207
200
|
end
|
208
201
|
|
202
|
+
def test_hook_mimics_class_public_visibility
|
203
|
+
spy_on(Pen, :public_method)
|
204
|
+
assert Pen.public_method_defined? :public_method
|
205
|
+
Spy.off(Pen, :public_method)
|
206
|
+
assert Pen.public_method_defined? :public_method
|
207
|
+
end
|
208
|
+
|
209
|
+
def test_hook_mimics_class_protected_visibility
|
210
|
+
spy_on(Pen, :protected_method)
|
211
|
+
assert Pen.protected_method_defined? :protected_method
|
212
|
+
Spy.off(Pen, :protected_method)
|
213
|
+
assert Pen.protected_method_defined? :protected_method
|
214
|
+
end
|
215
|
+
|
216
|
+
def test_hook_mimics_class_private_visibility
|
217
|
+
spy_on(Pen, :private_method)
|
218
|
+
assert Pen.private_method_defined? :private_method
|
219
|
+
Spy.off(Pen, :private_method)
|
220
|
+
assert Pen.private_method_defined? :private_method
|
221
|
+
end
|
222
|
+
|
209
223
|
def test_spy_get_can_retrieve_a_spy
|
210
224
|
pen_write_spy = spy_on(@pen, :write).and_return(:hello)
|
211
225
|
assert_equal :hello, @pen.write(:world)
|
data/test/support/pen.rb
CHANGED
metadata
CHANGED
@@ -1,62 +1,55 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
5
|
-
prerelease:
|
4
|
+
version: 0.2.2
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Ryan Ong
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2013-02-
|
11
|
+
date: 2013-02-26 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: minitest
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - '>='
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: 4.5.0
|
22
20
|
type: :development
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- -
|
24
|
+
- - '>='
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: 4.5.0
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: rspec-core
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- -
|
31
|
+
- - '>='
|
36
32
|
- !ruby/object:Gem::Version
|
37
33
|
version: '0'
|
38
34
|
type: :development
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- -
|
38
|
+
- - '>='
|
44
39
|
- !ruby/object:Gem::Version
|
45
40
|
version: '0'
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: rspec-expectations
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
|
-
- -
|
45
|
+
- - '>='
|
52
46
|
- !ruby/object:Gem::Version
|
53
47
|
version: '0'
|
54
48
|
type: :development
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
|
-
- -
|
52
|
+
- - '>='
|
60
53
|
- !ruby/object:Gem::Version
|
61
54
|
version: '0'
|
62
55
|
description: A simple mocking library that doesn't spies your intelligence.
|
@@ -109,27 +102,26 @@ files:
|
|
109
102
|
- test/test_helper.rb
|
110
103
|
homepage: ''
|
111
104
|
licenses: []
|
105
|
+
metadata: {}
|
112
106
|
post_install_message:
|
113
107
|
rdoc_options: []
|
114
108
|
require_paths:
|
115
109
|
- lib
|
116
110
|
required_ruby_version: !ruby/object:Gem::Requirement
|
117
|
-
none: false
|
118
111
|
requirements:
|
119
|
-
- -
|
112
|
+
- - '>='
|
120
113
|
- !ruby/object:Gem::Version
|
121
114
|
version: '0'
|
122
115
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
123
|
-
none: false
|
124
116
|
requirements:
|
125
|
-
- -
|
117
|
+
- - '>='
|
126
118
|
- !ruby/object:Gem::Version
|
127
119
|
version: '0'
|
128
120
|
requirements: []
|
129
121
|
rubyforge_project:
|
130
|
-
rubygems_version:
|
122
|
+
rubygems_version: 2.0.0
|
131
123
|
signing_key:
|
132
|
-
specification_version:
|
124
|
+
specification_version: 4
|
133
125
|
summary: A simple non destructive mocking library.
|
134
126
|
test_files:
|
135
127
|
- spec/spec_helper.rb
|