spy 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|