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 +2 -0
- data/lib/surrogate/api_comparer.rb +2 -2
- data/lib/surrogate/endower.rb +26 -18
- data/lib/surrogate/hatchling.rb +8 -2
- data/lib/surrogate/method_queue.rb +3 -1
- data/lib/surrogate/version.rb +1 -1
- data/spec/acceptance_spec.rb +9 -2
- data/spec/defining_api_methods_spec.rb +25 -6
- metadata +3 -3
data/Readme.md
CHANGED
@@ -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)
|
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
|
data/lib/surrogate/endower.rb
CHANGED
@@ -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.
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
surrogate
|
68
|
-
|
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
|
-
|
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
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
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)
|
data/lib/surrogate/hatchling.rb
CHANGED
@@ -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
|
-
|
19
|
-
|
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)
|
data/lib/surrogate/version.rb
CHANGED
data/spec/acceptance_spec.rb
CHANGED
@@ -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.
|
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.
|
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.
|
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 '
|
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.
|
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.
|
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
|
299
|
+
it 'is a subclass of the cloned class' do
|
281
300
|
superclass = Surrogate.endow Class.new
|
282
|
-
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.
|
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: &
|
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: *
|
24
|
+
version_requirements: *70270582700600
|
25
25
|
description: Framework to aid in handrolling mock/spy objects.
|
26
26
|
email:
|
27
27
|
- josh.cheek@gmail.com
|