surrogate 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/Readme.md CHANGED
@@ -1,3 +1,5 @@
1
+ Explanation and examples coming soon.
2
+
1
3
  TODO
2
4
  ----
3
5
 
@@ -112,9 +112,9 @@ class Surrogate
112
112
  Set.new surrogate.singleton_class.api_method_names
113
113
  end
114
114
 
115
- # should have new
115
+ # should have new and clone (don't screw up substitutability because of how we implement these)
116
116
  def class_inherited_methods
117
- Set.new surrogate.singleton_class.instance_methods - surrogate.singleton_class.instance_methods(false) + [:new]
117
+ Set.new surrogate.singleton_class.instance_methods - surrogate.singleton_class.instance_methods(false)
118
118
  end
119
119
 
120
120
  # should not have new
@@ -1,6 +1,8 @@
1
1
  class Surrogate
2
2
 
3
3
  # adds surrogate behaviour to your class / singleton class / instances
4
+ #
5
+ # please refactor me!
4
6
  class Endower
5
7
  def self.endow(klass, &playlist)
6
8
  new(klass, &playlist).endow
@@ -60,19 +62,22 @@ class Surrogate
60
62
  end
61
63
 
62
64
  def can_get_a_new(klass)
63
- klass.define_singleton_method :reprise do
64
- new_klass = Class.new self
65
- surrogate = @surrogate
66
- Surrogate.endow new_klass do
67
- surrogate.api_methods.each do |method_name, options|
68
- define method_name, options.to_hash, &options.default_proc
65
+ klass.extend Module.new {
66
+ # use a module so that the method is inherited (important for substitutability)
67
+ def clone
68
+ new_klass = Class.new self
69
+ surrogate = @surrogate
70
+ Surrogate.endow new_klass do
71
+ surrogate.api_methods.each do |method_name, options|
72
+ define method_name, options.to_hash, &options.default_proc
73
+ end
69
74
  end
75
+ @hatchery.api_methods.each do |method_name, options|
76
+ new_klass.define method_name, options.to_hash, &options.default_proc
77
+ end
78
+ new_klass
70
79
  end
71
- @hatchery.api_methods.each do |method_name, options|
72
- new_klass.define method_name, options.to_hash, &options.default_proc
73
- end
74
- new_klass
75
- end
80
+ }
76
81
  end
77
82
 
78
83
  def remember_invocations_for_instances_of(klass)
@@ -86,13 +91,16 @@ class Surrogate
86
91
  end
87
92
 
88
93
  def hijack_instantiation_of(klass)
89
- def klass.new(*args)
90
- instance = allocate
91
- hatchery = @hatchery
92
- instance.instance_eval { @surrogate = Hatchling.new instance, hatchery }
93
- instance.send :initialize, *args
94
- instance
95
- end
94
+ # use a module so that the method is inherited (important for substitutability)
95
+ klass.extend Module.new {
96
+ def new(*args)
97
+ instance = allocate
98
+ hatchery = @hatchery
99
+ instance.instance_eval { @surrogate = Hatchling.new instance, hatchery }
100
+ instance.send :initialize, *args
101
+ instance
102
+ end
103
+ }
96
104
  end
97
105
 
98
106
  def enable_defining_methods(klass)
@@ -15,8 +15,14 @@ class Surrogate
15
15
  invoked_methods[method_name] << args
16
16
  return get_default method_name, args unless has_ivar? method_name
17
17
  ivar = get_ivar method_name
18
- return ivar unless ivar.kind_of? MethodQueue
19
- play_from_queue ivar, method_name
18
+ case ivar
19
+ when MethodQueue
20
+ play_from_queue ivar, method_name
21
+ when Exception
22
+ raise ivar
23
+ else
24
+ ivar
25
+ end
20
26
  end
21
27
 
22
28
  def prepare_method(method_name, args, &block)
@@ -4,7 +4,9 @@ class Surrogate
4
4
 
5
5
  def dequeue
6
6
  raise QueueEmpty if empty?
7
- queue.shift
7
+ current = queue.shift
8
+ raise current if current.kind_of? Exception
9
+ current
8
10
  end
9
11
 
10
12
  def empty?
@@ -1,3 +1,3 @@
1
1
  class Surrogate
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -36,7 +36,7 @@ describe Surrogate do
36
36
 
37
37
 
38
38
  # don't affect the real user class
39
- user_class = Mock::User.reprise
39
+ user_class = Mock::User.clone
40
40
 
41
41
 
42
42
  # ===== set a default =====
@@ -53,7 +53,7 @@ describe Surrogate do
53
53
  # might also be nice to provide a way to raise an error
54
54
 
55
55
  # tracking invocations
56
- user_class = Mock::User.reprise
56
+ user_class = Mock::User.clone
57
57
  user_class.should_not have_been_told_to :find
58
58
  user_class.find 12
59
59
  user_class.find 12
@@ -102,6 +102,13 @@ describe Surrogate do
102
102
  # user.phone_numbers.should == [['123', '456-7890']] # <-- should we use a hook, or default block to make this happen?
103
103
 
104
104
 
105
+ # ===== raise errors =====
106
+
107
+ # pass the error as the return value, it will be raised when method is invoked
108
+ error = StandardError.new("some message")
109
+ user.will_add_phone_number error
110
+ expect { user.add_phone_number }.to raise_error StandardError, "some message"
111
+
105
112
  # ===== Substitutability =====
106
113
 
107
114
  # real user is not a suitable substitute if missing methods that mock user has
@@ -9,7 +9,7 @@ describe 'define' do
9
9
  end
10
10
  end
11
11
 
12
- klass1 = pristine_klass.reprise
12
+ klass1 = pristine_klass.clone
13
13
  klass1.should_not have_been_told_to :find
14
14
  klass1.find(1).should == 123
15
15
  klass1.should have_been_told_to(:find).with(1)
@@ -73,6 +73,25 @@ describe 'define' do
73
73
  end
74
74
  end
75
75
  end
76
+
77
+ describe 'when an argument is an error' do
78
+ it 'raises the error on method invocation' do
79
+ mocked_class = Surrogate.endow(Class.new)
80
+ mocked_class.define :connect
81
+ mock = mocked_class.new
82
+ error = StandardError.new("some message")
83
+
84
+ # for single invocation
85
+ mock.will_connect error
86
+ expect { mock.connect }.to raise_error StandardError, "some message"
87
+
88
+ # for queue
89
+ mock.will_connect 1, error, 2
90
+ mock.connect.should == 1
91
+ expect { mock.connect }.to raise_error StandardError, "some message"
92
+ mock.connect.should == 2
93
+ end
94
+ end
76
95
  end
77
96
 
78
97
 
@@ -246,7 +265,7 @@ describe 'define' do
246
265
  end
247
266
 
248
267
 
249
- describe 'reprise' do
268
+ describe 'clone' do
250
269
  it 'a repetition or further performance of the klass' do
251
270
  pristine_klass = Class.new do
252
271
  Surrogate.endow self do
@@ -257,13 +276,13 @@ describe 'define' do
257
276
  define(:repeat) { 321 }
258
277
  end
259
278
 
260
- klass1 = pristine_klass.reprise
279
+ klass1 = pristine_klass.clone
261
280
  klass1.should_not have_been_told_to :find
262
281
  klass1.find(1).should == 123
263
282
  klass1.should have_been_told_to(:find).with(1)
264
283
  klass1.bind.should == 'abc'
265
284
 
266
- klass2 = pristine_klass.reprise
285
+ klass2 = pristine_klass.clone
267
286
  klass2.will_find 456
268
287
  klass2.find(2).should == 456
269
288
  klass1.find.should == 123
@@ -277,9 +296,9 @@ describe 'define' do
277
296
  klass1.new.repeat.should == 321
278
297
  end
279
298
 
280
- it 'is a subclass of the reprised class' do
299
+ it 'is a subclass of the cloned class' do
281
300
  superclass = Surrogate.endow Class.new
282
- superclass.reprise.new.should be_a_kind_of superclass
301
+ superclass.clone.new.should be_a_kind_of superclass
283
302
  end
284
303
  end
285
304
 
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.1.0
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,7 +13,7 @@ date: 2012-04-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
16
- requirement: &70192551591960 !ruby/object:Gem::Requirement
16
+ requirement: &70270582700600 !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: *70192551591960
24
+ version_requirements: *70270582700600
25
25
  description: Framework to aid in handrolling mock/spy objects.
26
26
  email:
27
27
  - josh.cheek@gmail.com