surrogate 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
data/Readme.md CHANGED
@@ -1,95 +1,379 @@
1
- Explanation and examples coming soon, but here is a simple example I wrote up for a lightning talk:
1
+ About
2
+ =====
3
+
4
+ Handrolling mocks is the best, but involves more overhead than necessary, and usually has less helpful
5
+ error messages. Surrogate addresses this by endowing your objects with common things that most mocks need.
6
+ Currently it is only integrated with RSpec.
7
+
8
+
9
+ Features
10
+ ========
11
+
12
+ * Declarative syntax
13
+ * Support default values
14
+ * Easily override values
15
+ * RSpec matchers for asserting what happend (what was invoked, with what args, how many times)
16
+ * RSpec matchers for asserting the Mock's interface matches the real object
17
+ * Support for exceptions
18
+ * Queue return values
19
+ * Initialization information is always recorded
20
+
21
+
22
+ Usage
23
+ =====
24
+
25
+ **Endow** a class with surrogate abilities
2
26
 
3
27
  ```ruby
4
- require 'surrogate'
5
- require 'surrogate/rspec'
28
+ class Mock
29
+ Surrogate.endow self
30
+ end
31
+ ```
32
+
33
+ Define a **class method** by using `define` in the block when endowing your class.
34
+
35
+ ```ruby
36
+ class MockClient
37
+ Surrogate.endow self do
38
+ define(:default_url) { 'http://example.com' }
39
+ end
40
+ end
41
+
42
+ MockClient.default_url # => "http://example.com"
43
+ ```
44
+
45
+ Define an **instance method** by using `define` outside the block after endowing your class.
46
+
47
+ ```ruby
48
+ class MockClient
49
+ Surrogate.endow self
50
+ define(:request) { ['result1', 'result2'] }
51
+ end
52
+
53
+ MockClient.new.request # => ["result1", "result2"]
54
+ ```
55
+
56
+ If you care about the **arguments**, your block can receive them.
57
+
58
+ ```ruby
59
+ class MockClient
60
+ Surrogate.endow self
61
+ define(:request) { |limit| limit.times.map { |i| "result#{i.next}" } }
62
+ end
63
+
64
+ MockClient.new.request 3 # => ["result1", "result2", "result3"]
65
+ ```
66
+
67
+ You don't need a **default if you set the ivar** of the same name
68
+
69
+ ```ruby
70
+ class MockClient
71
+ Surrogate.endow self
72
+ define(:initialize) { |id| @id = id }
73
+ define :id
74
+ end
75
+ MockClient.new(12).id # => 12
76
+ ```
77
+
78
+ **Override defaults** with `will_<verb>` and `will_have_<noun>`
79
+
80
+ ```ruby
81
+ class MockMP3
82
+ Surrogate.endow self
83
+ define :play # defaults are optional, will raise error if invoked without being told what to do
84
+ define :info
85
+ end
86
+
87
+ mp3 = MockMP3.new
88
+
89
+ # verbs
90
+ mp3.will_play true
91
+ mp3.play # => true
92
+
93
+ # nouns
94
+ mp3.will_have_info artist: 'Symphony of Science', title: 'Children of Africa'
95
+ mp3.info # => {:artist=>"Symphony of Science", :title=>"Children of Africa"}
96
+ ```
97
+
98
+ **Errors** get raised
99
+
100
+ ```ruby
101
+ class MockClient
102
+ Surrogate.endow self
103
+ define :request
104
+ end
105
+
106
+ client = MockClient.new
107
+ client.will_have_request StandardError.new('Remote service unavailable')
6
108
 
7
- module Mock
8
- class User
9
- Surrogate.endow self
10
- define(:name) { 'Josh' }
11
- define :phone_numbers
12
- define :add_phone_number do |area_code, number|
13
- @phone_numbers << [area_code, number]
14
- end
109
+ begin
110
+ client.request
111
+ rescue StandardError => e
112
+ e # => #<StandardError: Remote service unavailable>
113
+ end
114
+ ```
115
+
116
+ **Queue** up return values
117
+
118
+ ```ruby
119
+ class MockPlayer
120
+ Surrogate.endow self
121
+ define(:move) { 20 }
122
+ end
123
+
124
+ player = MockPlayer.new
125
+ player.will_move 1, 9, 3
126
+ player.move # => 1
127
+ player.move # => 9
128
+ player.move # => 3
129
+
130
+ # then back to default behaviour (or error if none provided)
131
+ player.move # => 20
132
+ ```
133
+
134
+ You can define **initialize**
135
+
136
+ ```ruby
137
+ class MockUser
138
+ Surrogate.endow self do
139
+ define(:find) { |id| new id }
15
140
  end
141
+ define(:initialize) { |id| @id = id }
142
+ define(:id) { @id }
143
+ end
144
+
145
+ user = MockUser.find 12
146
+ user.id # => 12
147
+ ```
148
+
149
+
150
+ RSpec Integration
151
+ =================
152
+
153
+ Currently only integrated with RSpec, since that's what I use. It has some builtin matchers
154
+ for querying what happened.
155
+
156
+ Load the RSpec matchers.
157
+
158
+ ```ruby
159
+ require 'surrogate/rspec'
160
+ ```
161
+
162
+ Nouns
163
+ -----
164
+
165
+ Given this mock and assuming the following examples happen within a spec
166
+
167
+ ```ruby
168
+ class MockMP3
169
+ Surrogate.endow self
170
+ define(:info) { 'some info' }
16
171
  end
172
+ ```
173
+
174
+ Check if **was invoked** with `have_been_asked_for_its`
175
+
176
+ ```ruby
177
+ mp3.should_not have_been_asked_for_its :info
178
+ mp3.info
179
+ mp3.should have_been_asked_for_its :info
180
+ ```
181
+
182
+ Invocation **cardinality** by chaining `times(n)`
183
+
184
+ ```ruby
185
+ mp3.info
186
+ mp3.info
187
+ mp3.should have_been_asked_for_its(:info).times(2)
188
+ ```
189
+
190
+ Invocation **arguments** by chaining `with(args)`
191
+
192
+ ```ruby
193
+ mp3.info :title
194
+ mp3.should have_been_asked_for_its(:info).with(:title)
195
+ ```
196
+
197
+ Supports RSpec's `no_args` matcher (the others coming in future versions)
198
+
199
+ ```ruby
200
+ mp3.info
201
+ mp3.should have_been_asked_for_its(:info).with(no_args)
202
+ ```
203
+
204
+ Cardinality of a specific set of args `with(args)` and `times(n)`
205
+
206
+ ```ruby
207
+ mp3.info :title
208
+ mp3.info :title
209
+ mp3.info :artist
210
+ mp3.should have_been_asked_for_its(:info).with(:title).times(2)
211
+ mp3.should have_been_asked_for_its(:info).with(:artist).times(1)
212
+ ```
213
+
214
+
215
+ Verbs
216
+ -----
217
+
218
+ Given this mock and assuming the following examples happen within a spec
219
+
220
+ ```ruby
221
+ class MockMP3
222
+ Surrogate.endow self
223
+ define(:play) { true }
224
+ end
225
+ ```
226
+
227
+ Check if **was invoked** with `have_been_told_to`
228
+
229
+ ```ruby
230
+ mp3.should_not have_been_told_to :play
231
+ mp3.play
232
+ mp3.should have_been_told_to :play
233
+ ```
234
+
235
+ Also supports the same `with(args)` and `times(n)` that nouns have.
236
+
237
+
238
+ Initialization
239
+ --------------
240
+
241
+ Query with `have_been_initialized_with`, which is exactly the same as saying `have_been_told_to(:initialize).with(...)`
242
+
243
+ ```ruby
244
+ class MockUser
245
+ Surrogate.endow self
246
+ define(:initialize) { |id| @id = id }
247
+ define :id
248
+ end
249
+ user = MockUser.new 12
250
+ user.id.should == 12
251
+ user.should have_been_initialized_with 12
252
+ ```
253
+
254
+ Initialization is **always recorded**, so that you don't have to override it just to be able to query.
255
+
256
+ ```ruby
257
+ class MockUser < Struct.new(:id)
258
+ Surrogate.endow self
259
+ end
260
+ user = MockUser.new 12
261
+ user.id.should == 12
262
+ user.should have_been_initialized_with 12
263
+ ```
264
+
265
+
266
+ Substitutability
267
+ ----------------
17
268
 
269
+ After you've implemented the real version of your mock (assuming a [top-down](http://vimeo.com/31267109) style of development),
270
+ how do you prevent your real object from getting out of synch with your mock?
271
+
272
+ Assert that your mock has the **same interface** as your real class.
273
+ This will fail if the mock inherits methods methods not on the real class. And it will fail
274
+ if the real class has or lacks any methods defined on the mock or inherited by the mock.
275
+
276
+ Presently, it will ignore methods defined directly in the mock (as it adds quite a few of its own methods,
277
+ and generally considers them to be helpers). In a future version, you will be able to tell it to treat other methods
278
+ as part of the API (will fail if they don't match, and maybe record their values).
279
+
280
+ ```ruby
18
281
  class User
282
+ def initialize(id)end
283
+ def id()end
284
+ end
285
+
286
+ class MockUser
287
+ Surrogate.endow self
288
+ define(:initialize) { |id| @id = id }
289
+ define :id
290
+ end
291
+
292
+ # they are the same
293
+ MockUser.should substitute_for User
294
+
295
+ # mock has extra method
296
+ MockUser.define :name
297
+ MockUser.should_not substitute_for User
298
+
299
+ # the same again via inheritance
300
+ class UserWithName < User
19
301
  def name()end
20
- def phone_numbers()end
21
- def add_phone_number()end
22
302
  end
303
+ MockUser.should substitute_for UserWithName
23
304
 
24
- describe do
25
- it 'ensures the mock lib looks like real lib' do
26
- Mock::User.should substitute_for User
27
- end
305
+ # real class has extra methods
306
+ class UserWithNameAndAddress < UserWithName
307
+ def address()end
308
+ end
309
+ MockUser.should_not substitute_for UserWithNameAndAddress
310
+ ```
28
311
 
29
- let(:user) { Mock::User.new }
312
+ Sometimes you don't want to have to implement the entire interface.
313
+ In these cases, you can assert that the methods on the mock are a **subset**
314
+ of the methods on the real class.
30
315
 
31
- example 'you can tell it how to behave and ask what happened with it' do
32
- user.will_have_name "Sally"
316
+ ```ruby
317
+ class User
318
+ def initialize(id)end
319
+ def id()end
320
+ def name()end
321
+ end
33
322
 
34
- user.should_not have_been_asked_for_its :name
35
- user.name.should == "Sally"
36
- user.should have_been_asked_for_its :name
37
- end
323
+ class MockUser
324
+ Surrogate.endow self
325
+ define(:initialize) { |id| @id = id }
326
+ define :id
38
327
  end
328
+
329
+ # doesn't matter that real user has a name as long as it has initialize and id
330
+ MockUser.should substitute_for User, subset: true
331
+
332
+ # but now it fails b/c it has no addres
333
+ MockUser.define :address
334
+ MockUser.should_not substitute_for User, subset: true
39
335
  ```
40
336
 
41
337
 
42
- TODO
43
- ----
338
+ How do I introduce my mocks?
339
+ ============================
44
340
 
45
- * substitutability
46
- * add methods for substitutability
341
+ This is known as dependency injection. There are many ways you can do this, you can pass the object into
342
+ the initializer, you can pass a factory to your class, you can give the class that depends on the mock a
343
+ setter and then override it whenever you feel it is necessary, you can use RSpec's `#stub` method to put
344
+ it into place.
47
345
 
346
+ Personally, I use [Deject](https://rubygems.org/gems/deject) another gem I wrote. For more on why I feel
347
+ it is a better solution than the above methods, see it's [readme](https://github.com/JoshCheek/deject/tree/938edc985c65358c074a7c7b7bbf18dc11e9450e#why-write-this).
48
348
 
49
- Features for future vuersions
50
- -----------------------------
51
349
 
52
- * change queue notation from will_x_qeue(1,2,3) to will_x(1,2,3)
53
- * arity option
54
- * support for raising errors
55
- * need some way to talk about and record blocks being passed
56
- * support all rspec matchers (RSpec::Mocks::ArgumentMatchers)
57
- * assertions for order of invocations & methods
350
+ But why write this?
351
+ ===================
58
352
 
353
+ Need to put an explanation here soon. In the meantime, I wrote a [blog](http://blog.8thlight.com/josh-cheek/2011/11/28/three-reasons-to-roll-your-own-mocks.html) that touches on the reasons.
59
354
 
60
355
 
61
- Future subset substitutability
356
+ Special Thanks
357
+ ==============
62
358
 
63
- # ===== Substitutability =====
359
+ * [Corey Haines](http://coreyhaines.com/) for pairing on it with me
360
+ * [8th Light](http://8thlight.com/) for giving me time to work on this during our weekly Wazas, and the general encouragement and interest
64
361
 
65
- # real user is not a suitable substitute if missing methods that mock user has
66
- user_class.should_not substitute_for Class.new
67
362
 
68
- # real user must have all of mock user's methods to be substitutable
69
- substitutable_real_user_class = Class.new do
70
- def self.find() end
71
- def initialize(id) end
72
- def id() end
73
- def name() end
74
- def address() end
75
- def phone_numbers() end
76
- def add_phone_number(area_code, number) end
77
- end
78
- user_class.should substitute_for substitutable_real_user_class
79
- user_class.should be_subset_of substitutable_real_user_class
363
+ TODO
364
+ ----
80
365
 
81
- # real user class is not a suitable substitutable if has extra methods, but is suitable subset
82
- real_user_class = substitutable_real_user_class.clone
83
- def real_user_class.some_class_meth() end
84
- user_class.should_not substitute_for real_user_class
85
- user_class.should be_subset_of real_user_class
366
+ * Add a better explanation for motivations
367
+ * Figure out whether I'm supposed to be using clone or dup for the object -.^ (looks like there may also be an `initialize_copy` method I can take advantage of instead of crazy stupid shit I'm doing now)
86
368
 
87
- real_user_class = substitutable_real_user_class.clone
88
- real_user_class.send(:define_method, :some_instance_method) {}
89
- user_class.should_not substitute_for real_user_class
90
- user_class.should be_subset_of real_user_class
91
369
 
92
- # subset substitutability does not work for superset
93
- real_user_class = substitutable_real_user_class.clone
94
- real_user_class.undef_method :address
95
- user_class.should_not be_subset_of real_user_class
370
+ Future Features
371
+ ---------------
372
+
373
+ * Support all RSpec matchers (hash_including, anything, etc. see them in RSpec::Mocks::ArgumentMatchers)
374
+ * have some sort of reinitialization that can hook into setup/teardown steps of test suite
375
+ * Support arity checking as part of substitutability
376
+ * Support for blocks
377
+ * Ability to disassociate the method name from the test (e.g. you shouldn't need to change a test just because you change a name)
378
+ * declare normal methods as being part of the API (e.g. for inheritance)
379
+ * assertions for order of invocations & methods
@@ -2,16 +2,16 @@ class Surrogate
2
2
 
3
3
  # Adds surrogate behaviour to your class / singleton class / instances
4
4
  #
5
- # please refactor me!
5
+ # please refactor me! ...may not be possible :(
6
6
  class Endower
7
- def self.endow(klass, &playlist)
8
- new(klass, &playlist).endow
7
+ def self.endow(klass, &block)
8
+ new(klass, &block).endow
9
9
  end
10
10
 
11
- attr_accessor :klass, :playlist
11
+ attr_accessor :klass, :block
12
12
 
13
- def initialize(klass, &playlist)
14
- self.klass, self.playlist = klass, playlist
13
+ def initialize(klass, &block)
14
+ self.klass, self.block = klass, block
15
15
  end
16
16
 
17
17
  def endow
@@ -33,7 +33,7 @@ class Surrogate
33
33
  def endow_singleton_class
34
34
  hatchery = add_hatchery_to singleton
35
35
  enable_defining_methods singleton
36
- singleton.module_eval &playlist if playlist
36
+ singleton.module_eval &block if block
37
37
  klass.instance_variable_set :@hatchling, Hatchling.new(klass, hatchery)
38
38
  klass
39
39
  end
@@ -49,11 +49,7 @@ class Surrogate
49
49
 
50
50
  def add_helpers_for(method_name, helper_name)
51
51
  klass.send :define_method, helper_name do |*args, &block|
52
- if args.size == 1
53
- @hatchling.prepare_method method_name, args, &block
54
- else
55
- @hatchling.prepare_method_queue method_name, args, &block
56
- end
52
+ @hatchling.prepare_method method_name, args, &block
57
53
  self
58
54
  end
59
55
  end
@@ -1,6 +1,7 @@
1
1
  class Surrogate
2
2
  UnknownMethod = Class.new StandardError
3
3
 
4
+
4
5
  # This contains the unique behaviour for each instance
5
6
  # It handles method invocation and records the appropriate information
6
7
  class Hatchling
@@ -17,31 +18,34 @@ class Surrogate
17
18
  def invoke_method(method_name, args, &block)
18
19
  invoked_methods[method_name] << args
19
20
  return get_default method_name, args unless has_ivar? method_name
20
- ivar = get_ivar method_name
21
-
22
- # This may soon need classes for each type which know how to invoke themselves
23
- case ivar
24
- when MethodQueue
25
- play_from_queue ivar, method_name
26
- when Exception
27
- raise ivar
28
- else
29
- ivar
30
- end
21
+ Value.factory(get_ivar method_name).value(self, method_name)
31
22
  end
32
23
 
33
24
  def prepare_method(method_name, args, &block)
34
- set_ivar method_name, *args
35
- end
36
-
37
- def prepare_method_queue(method_name, args, &block)
38
- set_ivar method_name, MethodQueue.new(args)
25
+ set_ivar method_name, Value.factory(*args, &block)
39
26
  end
40
27
 
41
28
  def invocations(method_name)
42
29
  invoked_methods[method_name]
43
30
  end
44
31
 
32
+ # maybe these four should be extracted into their own class
33
+ def has_ivar?(method_name)
34
+ instance.instance_variable_defined? "@#{method_name}"
35
+ end
36
+
37
+ def set_ivar(method_name, value)
38
+ instance.instance_variable_set "@#{method_name}", value
39
+ end
40
+
41
+ def get_ivar(method_name)
42
+ instance.instance_variable_get "@#{method_name}"
43
+ end
44
+
45
+ def unset_ivar(method_name)
46
+ instance.send :remove_instance_variable, "@#{method_name}"
47
+ end
48
+
45
49
  private
46
50
 
47
51
  def invoked_methods
@@ -57,33 +61,11 @@ class Surrogate
57
61
  end
58
62
  end
59
63
 
60
- def play_from_queue(queue, method_name)
61
- result = queue.dequeue
62
- unset_ivar method_name if queue.empty?
63
- result
64
- end
65
-
66
64
  def must_know(method_name)
67
65
  return if api_methods.has_key? method_name
68
66
  known_methods = api_methods.keys.map(&:to_s).map(&:inspect).join ', '
69
67
  raise UnknownMethod, "doesn't know \"#{method_name}\", only knows #{known_methods}"
70
68
  end
71
-
72
- def has_ivar?(method_name)
73
- instance.instance_variable_defined? "@#{method_name}"
74
- end
75
-
76
- def set_ivar(method_name, value)
77
- instance.instance_variable_set "@#{method_name}", value
78
- end
79
-
80
- def get_ivar(method_name)
81
- instance.instance_variable_get "@#{method_name}"
82
- end
83
-
84
- def unset_ivar(method_name)
85
- instance.send :remove_instance_variable, "@#{method_name}"
86
- end
87
69
  end
88
70
  end
89
71
 
@@ -1,2 +1,4 @@
1
+ # Maybe I should be my own gem?
2
+ require 'surrogate'
1
3
  require 'surrogate/rspec/api_method_matchers'
2
4
  require 'surrogate/rspec/substitutability_matchers'
@@ -0,0 +1,78 @@
1
+ class Surrogate
2
+
3
+ # Superclass for all types of values. Where a value is anything stored
4
+ # in an instance variable on a surrogate, intended to be returned by an api method
5
+ class Value
6
+
7
+ # convert raw arguments into a value
8
+ def self.factory(*args, &block)
9
+ arg = args.first
10
+ if args.size > 1
11
+ MethodQueue.new args
12
+ elsif arg.kind_of? Exception
13
+ Raisable.new arg
14
+ elsif arg.kind_of? Value
15
+ Recursive.new arg
16
+ else
17
+ Value.new arg
18
+ end
19
+ end
20
+
21
+ def initialize(value)
22
+ @value = value
23
+ end
24
+
25
+ def value(hatchling, method_name)
26
+ @value
27
+ end
28
+
29
+ def factory(*args, &block)
30
+ self.class.factory(*args, &block)
31
+ end
32
+ end
33
+ end
34
+
35
+
36
+ # the current set of possible values
37
+
38
+ class Surrogate
39
+ class Value
40
+
41
+ class Raisable < Value
42
+ def value(*)
43
+ raise @value
44
+ end
45
+ end
46
+
47
+
48
+ class Recursive < Value
49
+ def value(hatchling, method_name)
50
+ @value.value hatchling, method_name
51
+ end
52
+ end
53
+
54
+
55
+ class MethodQueue < Value
56
+ QueueEmpty = Class.new StandardError
57
+
58
+ def value(hatchling, method_name)
59
+ factory(dequeue).value(hatchling, method_name)
60
+ ensure
61
+ hatchling.unset_ivar method_name if empty?
62
+ end
63
+
64
+ def queue
65
+ @value
66
+ end
67
+
68
+ def dequeue
69
+ raise QueueEmpty if empty?
70
+ queue.shift
71
+ end
72
+
73
+ def empty?
74
+ queue.empty?
75
+ end
76
+ end
77
+ end
78
+ end
@@ -1,3 +1,3 @@
1
1
  class Surrogate
2
- VERSION = "0.3.0"
2
+ VERSION = "0.3.1"
3
3
  end
data/lib/surrogate.rb CHANGED
@@ -2,16 +2,15 @@ require 'surrogate/version'
2
2
  require 'surrogate/hatchling'
3
3
  require 'surrogate/hatchery'
4
4
  require 'surrogate/options'
5
- require 'surrogate/method_queue'
5
+ require 'surrogate/values'
6
6
  require 'surrogate/endower'
7
7
  require 'surrogate/api_comparer'
8
8
 
9
9
  class Surrogate
10
10
  UnpreparedMethodError = Class.new StandardError
11
11
 
12
- # TODO: Find a new name that isn't "playlist"
13
- def self.endow(klass, &playlist)
14
- Endower.endow klass, &playlist
12
+ def self.endow(klass, &block)
13
+ Endower.endow klass, &block
15
14
  klass
16
15
  end
17
16
  end
@@ -125,14 +125,21 @@ describe Surrogate do
125
125
  def add_phone_number(area_code, number) end
126
126
  end
127
127
  user_class.should substitute_for substitutable_real_user_class
128
+ user_class.should substitute_for substitutable_real_user_class, subset: true
128
129
 
129
- # real user class is not a suitable substitutable if has extra methods
130
+ # when real user class has extra methods, it is only substitutable as a subset
130
131
  real_user_class = substitutable_real_user_class.clone
131
132
  def real_user_class.some_class_meth() end
132
133
  user_class.should_not substitute_for real_user_class
133
134
 
134
- real_user_class = substitutable_real_user_class.clone
135
+ real_user_class = substitutable_real_user_class.dup
135
136
  real_user_class.send(:define_method, :some_instance_method) {}
136
137
  user_class.should_not substitute_for real_user_class
138
+ user_class.should substitute_for real_user_class, subset: true
139
+
140
+ # subset substitutability does not work for superset
141
+ real_user_class = substitutable_real_user_class.dup
142
+ real_user_class.send :undef_method, :address
143
+ user_class.should_not substitute_for real_user_class, subset: true
137
144
  end
138
145
  end
data/spec/spec_helper.rb CHANGED
@@ -1,2 +1 @@
1
- require 'surrogate'
2
1
  require 'surrogate/rspec'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: surrogate
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-04-30 00:00:00.000000000 Z
12
+ date: 2012-05-01 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
16
- requirement: &70298496271040 !ruby/object:Gem::Requirement
16
+ requirement: &70186184231320 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,7 +21,7 @@ dependencies:
21
21
  version: 2.8.0
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *70298496271040
24
+ version_requirements: *70186184231320
25
25
  description: Framework to aid in handrolling mock/spy objects.
26
26
  email:
27
27
  - josh.cheek@gmail.com
@@ -39,11 +39,11 @@ files:
39
39
  - lib/surrogate/endower.rb
40
40
  - lib/surrogate/hatchery.rb
41
41
  - lib/surrogate/hatchling.rb
42
- - lib/surrogate/method_queue.rb
43
42
  - lib/surrogate/options.rb
44
43
  - lib/surrogate/rspec.rb
45
44
  - lib/surrogate/rspec/api_method_matchers.rb
46
45
  - lib/surrogate/rspec/substitutability_matchers.rb
46
+ - lib/surrogate/values.rb
47
47
  - lib/surrogate/version.rb
48
48
  - spec/acceptance_spec.rb
49
49
  - spec/defining_api_methods_spec.rb
@@ -1,16 +0,0 @@
1
- class Surrogate
2
- class MethodQueue < Struct.new(:queue)
3
- QueueEmpty = Class.new StandardError
4
-
5
- def dequeue
6
- raise QueueEmpty if empty?
7
- current = queue.shift
8
- raise current if current.kind_of? Exception
9
- current
10
- end
11
-
12
- def empty?
13
- queue.empty?
14
- end
15
- end
16
- end