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.
@@ -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
@@ -1,5 +1,5 @@
1
1
  language: ruby
2
2
  rvm:
3
3
  - "1.9.3"
4
+ - "2.0.0"
4
5
  - jruby-19mode
5
- - rbx-19mode
data/Gemfile CHANGED
@@ -5,5 +5,5 @@ gemspec
5
5
  gem 'pry'
6
6
  gem 'pry-nav'
7
7
  gem 'yard'
8
- gem 'redcarpet'
8
+ gem 'redcarpet', platforms: :mri
9
9
  gem 'rake'
@@ -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
- opts[:force] ||= false
37
+
39
38
  @previously_defined = currently_defined?
40
- if @previously_defined || !opts[:force]
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 @previously_defined
54
- and_return(@original_value)
55
- end
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
 
@@ -35,6 +35,8 @@ module Spy
35
35
  def remove(spy)
36
36
  if @hooked_constants[spy.constant_name] == spy
37
37
  @hooked_constants.delete(spy.constant_name)
38
+ else
39
+ raise "#{spy.constant_name} was never added"
38
40
  end
39
41
  self
40
42
  end
@@ -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
- if (base_object_respond_to?(method_name, true)) || !hook_opts[:force]
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(method_visibility, method_name) if method_visibility
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
- if value.nil? || value.is_a?(Hash) && value.has_key?(:force)
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
- raise "can only call through if original method is set" unless method_visibility
118
- if original_method
119
- @plan = original_method
120
- else
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 = @plan ? @plan.call(*args, &block) : nil
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 = @method_visibility = @method_owner= nil
206
+ @hook_opts = @original_method = @arity_range = @original_method_visibility = @method_owner= nil
224
207
  end
225
208
 
226
- def method_visibility
227
- @method_visibility ||=
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 base_object_respond_to?(method_name, include_private = false)
213
+ def method_visibility_of(method_name, all = true)
240
214
  if @singleton_method
241
- base_object.respond_to?(method_name, include_private)
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.instance_methods.include?(method_name) || (
244
- include_private && base_object.private_instance_methods.include?(method_name)
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
- self.class.check_arity_against_range!(arity_range, arity)
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 ||= self.class.arity_range_of(original_method) if original_method
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
- all_methods += base_object.instance_methods(false) + base_object.private_instance_methods(false) if base_object.respond_to?(:instance_methods)
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
@@ -1,3 +1,3 @@
1
1
  module Spy
2
- VERSION = "0.2.1"
2
+ VERSION = "0.2.2"
3
3
  end
@@ -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
- spy = Subroutine.new(@pen, :no_method).and_return(:yep)
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)
@@ -50,6 +50,18 @@ class Pen
50
50
  def another
51
51
  "another"
52
52
  end
53
+
54
+ def public_method
55
+ end
56
+
57
+ protected
58
+ def protected_method
59
+ end
60
+
61
+ private
62
+ def private_method
63
+ end
64
+
53
65
  end
54
66
  end
55
67
 
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.1
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-25 00:00:00.000000000 Z
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: 1.8.23
122
+ rubygems_version: 2.0.0
131
123
  signing_key:
132
- specification_version: 3
124
+ specification_version: 4
133
125
  summary: A simple non destructive mocking library.
134
126
  test_files:
135
127
  - spec/spec_helper.rb