surrogate 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Readme.md +40 -1
- data/lib/surrogate/endower.rb +34 -42
- data/lib/surrogate/hatchery.rb +30 -16
- data/lib/surrogate/hatchling.rb +5 -0
- data/lib/surrogate/rspec/api_method_matchers.rb +0 -4
- data/lib/surrogate/rspec/substitutability_matchers.rb +26 -16
- data/lib/surrogate/version.rb +1 -1
- data/spec/defining_api_methods_spec.rb +17 -18
- data/spec/rspec/substitute_for_spec.rb +123 -44
- metadata +4 -4
data/Readme.md
CHANGED
@@ -1,4 +1,43 @@
|
|
1
|
-
Explanation and examples coming soon
|
1
|
+
Explanation and examples coming soon, but here is a simple example I wrote up for a lightning talk:
|
2
|
+
|
3
|
+
```ruby
|
4
|
+
require 'surrogate'
|
5
|
+
require 'surrogate/rspec'
|
6
|
+
|
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
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class User
|
19
|
+
def name()end
|
20
|
+
def phone_numbers()end
|
21
|
+
def add_phone_number()end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe do
|
25
|
+
it 'ensures the mock lib looks like real lib' do
|
26
|
+
Mock::User.should substitute_for User
|
27
|
+
end
|
28
|
+
|
29
|
+
let(:user) { Mock::User.new }
|
30
|
+
|
31
|
+
example 'you can tell it how to behave and ask what happened with it' do
|
32
|
+
user.will_have_name "Sally"
|
33
|
+
|
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
|
38
|
+
end
|
39
|
+
```
|
40
|
+
|
2
41
|
|
3
42
|
TODO
|
4
43
|
----
|
data/lib/surrogate/endower.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
class Surrogate
|
2
2
|
|
3
|
-
#
|
3
|
+
# Adds surrogate behaviour to your class / singleton class / instances
|
4
4
|
#
|
5
5
|
# please refactor me!
|
6
6
|
class Endower
|
@@ -22,29 +22,31 @@ class Surrogate
|
|
22
22
|
private
|
23
23
|
|
24
24
|
def endow_klass
|
25
|
-
|
25
|
+
add_hatchery_to klass
|
26
|
+
klass.extend ClassMethods
|
26
27
|
enable_defining_methods klass
|
27
28
|
record_initialization_for_instances_of klass
|
28
29
|
remember_invocations_for_instances_of klass
|
29
30
|
remember_invocations_for_instances_of klass.singleton_class
|
30
|
-
hijack_instantiation_of klass
|
31
|
-
can_get_a_new klass
|
32
31
|
end
|
33
32
|
|
34
33
|
def endow_singleton_class
|
35
|
-
hatchery =
|
34
|
+
hatchery = add_hatchery_to singleton
|
36
35
|
enable_defining_methods singleton
|
37
36
|
singleton.module_eval &playlist if playlist
|
38
|
-
klass.instance_variable_set :@
|
37
|
+
klass.instance_variable_set :@hatchling, Hatchling.new(klass, hatchery)
|
39
38
|
klass
|
40
39
|
end
|
41
40
|
|
42
|
-
# yeesh :(
|
41
|
+
# yeesh :( pretty sure there isn't a better way to do this
|
43
42
|
def record_initialization_for_instances_of(klass)
|
44
43
|
def klass.method_added(meth)
|
45
|
-
return
|
44
|
+
return if meth != :initialize || @hijacking_initialize
|
46
45
|
@hijacking_initialize = true
|
47
46
|
current_initialize = instance_method :initialize
|
47
|
+
|
48
|
+
# `define' records the args while maintaining the old behaviour
|
49
|
+
# we have to do it stupidly like this because there is no to_proc on an unbound method
|
48
50
|
define :initialize do |*args, &block|
|
49
51
|
current_initialize.bind(self).call(*args, &block)
|
50
52
|
end
|
@@ -61,48 +63,16 @@ class Surrogate
|
|
61
63
|
klass.singleton_class
|
62
64
|
end
|
63
65
|
|
64
|
-
def can_get_a_new(klass)
|
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
|
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
|
79
|
-
end
|
80
|
-
}
|
81
|
-
end
|
82
|
-
|
83
66
|
def remember_invocations_for_instances_of(klass)
|
84
67
|
klass.send :define_method, :invocations do |method_name|
|
85
|
-
@
|
68
|
+
@hatchling.invocations method_name
|
86
69
|
end
|
87
70
|
end
|
88
71
|
|
89
|
-
def
|
72
|
+
def add_hatchery_to(klass)
|
90
73
|
klass.instance_variable_set :@hatchery, Surrogate::Hatchery.new(klass)
|
91
74
|
end
|
92
75
|
|
93
|
-
def hijack_instantiation_of(klass)
|
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
|
-
}
|
104
|
-
end
|
105
|
-
|
106
76
|
def enable_defining_methods(klass)
|
107
77
|
def klass.define(method_name, options={}, &block)
|
108
78
|
@hatchery.define method_name, options, block
|
@@ -113,4 +83,26 @@ class Surrogate
|
|
113
83
|
end
|
114
84
|
end
|
115
85
|
end
|
86
|
+
|
87
|
+
|
88
|
+
# use a module so that the method is inherited (important for substitutability)
|
89
|
+
module ClassMethods
|
90
|
+
def clone
|
91
|
+
hatchling, hatchery = @hatchling, @hatchery
|
92
|
+
Class.new self do
|
93
|
+
Surrogate.endow self do
|
94
|
+
hatchling.api_methods.each { |name, options| define name, options.to_hash, &options.default_proc }
|
95
|
+
end
|
96
|
+
hatchery.api_methods.each { |name, options| define name, options.to_hash, &options.default_proc }
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Custom new, because user can define initialize, and ivars should be set before it
|
101
|
+
def new(*args)
|
102
|
+
instance = allocate
|
103
|
+
instance.instance_variable_set :@hatchling, Hatchling.new(instance, @hatchery)
|
104
|
+
instance.send :initialize, *args
|
105
|
+
instance
|
106
|
+
end
|
107
|
+
end
|
116
108
|
end
|
data/lib/surrogate/hatchery.rb
CHANGED
@@ -1,19 +1,22 @@
|
|
1
1
|
class Surrogate
|
2
|
+
|
3
|
+
# This manages the definitions that were given to the class
|
4
|
+
# The hatchlings are added to the instances, and they look here
|
5
|
+
# to find out about how their methods are implemented.
|
2
6
|
class Hatchery
|
3
7
|
attr_accessor :klass
|
4
8
|
|
5
9
|
def initialize(klass)
|
6
10
|
self.klass = klass
|
7
|
-
|
8
|
-
end
|
9
|
-
|
10
|
-
def defines_methods
|
11
|
-
klass.singleton_class.send :define_method, :define, &method(:define)
|
11
|
+
klass_can_define_api_methods
|
12
12
|
end
|
13
13
|
|
14
14
|
def define(method_name, options={}, block)
|
15
|
-
|
15
|
+
add_api_method_for method_name
|
16
|
+
add_verb_helpers_for method_name
|
17
|
+
add_noun_helpers_for method_name
|
16
18
|
api_methods[method_name] = Options.new options, block
|
19
|
+
klass
|
17
20
|
end
|
18
21
|
|
19
22
|
def api_methods
|
@@ -24,24 +27,35 @@ class Surrogate
|
|
24
27
|
api_methods.keys - [:initialize]
|
25
28
|
end
|
26
29
|
|
27
|
-
|
28
|
-
|
30
|
+
private
|
31
|
+
|
32
|
+
def klass_can_define_api_methods
|
33
|
+
klass.singleton_class.send :define_method, :define, &method(:define)
|
34
|
+
end
|
35
|
+
|
36
|
+
def add_api_method_for(method_name)
|
29
37
|
klass.send :define_method, method_name do |*args, &block|
|
30
|
-
@
|
38
|
+
@hatchling.invoke_method method_name, args, &block
|
31
39
|
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def add_verb_helpers_for(method_name)
|
43
|
+
add_helpers_for method_name, "will_#{method_name}"
|
44
|
+
end
|
32
45
|
|
33
|
-
|
34
|
-
|
46
|
+
def add_noun_helpers_for(method_name)
|
47
|
+
add_helpers_for method_name, "will_have_#{method_name}"
|
48
|
+
end
|
49
|
+
|
50
|
+
def add_helpers_for(method_name, helper_name)
|
51
|
+
klass.send :define_method, helper_name do |*args, &block|
|
35
52
|
if args.size == 1
|
36
|
-
@
|
53
|
+
@hatchling.prepare_method method_name, args, &block
|
37
54
|
else
|
38
|
-
@
|
55
|
+
@hatchling.prepare_method_queue method_name, args, &block
|
39
56
|
end
|
40
57
|
self
|
41
58
|
end
|
42
|
-
|
43
|
-
# nouns
|
44
|
-
klass.send :alias_method, "will_have_#{method_name}", "will_#{method_name}"
|
45
59
|
end
|
46
60
|
end
|
47
61
|
end
|
data/lib/surrogate/hatchling.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
class Surrogate
|
2
2
|
UnknownMethod = Class.new StandardError
|
3
|
+
|
4
|
+
# This contains the unique behaviour for each instance
|
5
|
+
# It handles method invocation and records the appropriate information
|
3
6
|
class Hatchling
|
4
7
|
attr_accessor :instance, :hatchery
|
5
8
|
|
@@ -15,6 +18,8 @@ class Surrogate
|
|
15
18
|
invoked_methods[method_name] << args
|
16
19
|
return get_default method_name, args unless has_ivar? method_name
|
17
20
|
ivar = get_ivar method_name
|
21
|
+
|
22
|
+
# This may soon need classes for each type which know how to invoke themselves
|
18
23
|
case ivar
|
19
24
|
when MethodQueue
|
20
25
|
play_from_queue ivar, method_name
|
@@ -1,24 +1,34 @@
|
|
1
1
|
class Surrogate
|
2
|
-
|
3
|
-
module MessagesFor
|
4
|
-
::RSpec::Matchers.define :substitute_for do |original_class|
|
2
|
+
::RSpec::Matchers.define :substitute_for do |original_class, options={}|
|
5
3
|
|
6
|
-
|
4
|
+
comparison = nil
|
5
|
+
subset_only = options[:subset]
|
7
6
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
7
|
+
match do |mocked_class|
|
8
|
+
comparison = ApiComparer.new(mocked_class, original_class).compare
|
9
|
+
if subset_only
|
10
|
+
(comparison[:instance][:not_on_actual] + comparison[:class][:not_on_actual]).empty?
|
11
|
+
else
|
12
|
+
(comparison[:instance].values + comparison[:class].values).inject(:+).empty?
|
13
|
+
end
|
14
|
+
end
|
12
15
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
+
failure_message_for_should do
|
17
|
+
extra_instance_methods = comparison[:instance][:not_on_actual ].to_a
|
18
|
+
extra_class_methods = comparison[:class ][:not_on_actual ].to_a
|
19
|
+
missing_instance_methods = comparison[:instance][:not_on_surrogate].to_a
|
20
|
+
missing_class_methods = comparison[:class ][:not_on_surrogate].to_a
|
16
21
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
22
|
+
differences = []
|
23
|
+
differences << "has extra instance methods: #{extra_instance_methods.inspect}" if extra_instance_methods.any?
|
24
|
+
differences << "has extra class methods: #{extra_class_methods.inspect}" if extra_class_methods.any?
|
25
|
+
differences << "is missing instance methods: #{missing_instance_methods}" if !subset_only && missing_instance_methods.any?
|
26
|
+
differences << "is missing class methods: #{missing_class_methods}" if !subset_only && missing_class_methods.any?
|
27
|
+
"Was not substitutable because surrogate " << differences.join(', ')
|
28
|
+
end
|
29
|
+
|
30
|
+
failure_message_for_should_not do
|
31
|
+
"Should not have been substitute, but was"
|
21
32
|
end
|
22
33
|
end
|
23
34
|
end
|
24
|
-
|
data/lib/surrogate/version.rb
CHANGED
@@ -193,35 +193,34 @@ describe 'define' do
|
|
193
193
|
specify 'even works with inheritance' do
|
194
194
|
superclass = Class.new
|
195
195
|
superclass.send(:define_method, :initialize) { @a = 1 }
|
196
|
-
subclass = Class.new superclass
|
197
|
-
|
198
|
-
|
199
|
-
mocked_subclass.new.instance_variable_get(:@a).should == 1
|
196
|
+
subclass = Surrogate.endow Class.new superclass
|
197
|
+
subclass.define :abc
|
198
|
+
subclass.new.instance_variable_get(:@a).should == 1
|
200
199
|
end
|
201
200
|
|
202
201
|
context 'when not an api method' do
|
203
202
|
it 'respects arity (this is probably 1.9.3 only)' do
|
204
|
-
expect { mocked_class.new
|
203
|
+
expect { mocked_class.new 1 }.to raise_error ArgumentError, 'wrong number of arguments(1 for 0)'
|
205
204
|
end
|
206
205
|
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
@a = a
|
206
|
+
describe 'invocations are recorded anyway' do
|
207
|
+
specify 'even when initialize is defined after surrogate block' do
|
208
|
+
klass = Class.new do
|
209
|
+
Surrogate.endow self
|
210
|
+
def initialize(a) @a = a end
|
212
211
|
end
|
212
|
+
klass.new(1).should have_been_initialized_with 1
|
213
|
+
klass.new(1).instance_variable_get(:@a).should == 1
|
213
214
|
end
|
214
|
-
klass.new(1).should have_been_initialized_with 1
|
215
|
-
klass.new(1).instance_variable_get(:@a).should == 1
|
216
215
|
|
217
|
-
|
218
|
-
|
219
|
-
@a = a
|
216
|
+
specify 'even when initialize is defined before surrogate block' do
|
217
|
+
klass = Class.new do
|
218
|
+
def initialize(a) @a = a end
|
219
|
+
Surrogate.endow self
|
220
220
|
end
|
221
|
-
|
221
|
+
klass.new(1).should have_been_initialized_with 1
|
222
|
+
klass.new(1).instance_variable_get(:@a).should == 1
|
222
223
|
end
|
223
|
-
klass.new(1).should have_been_initialized_with 1
|
224
|
-
klass.new(1).instance_variable_get(:@a).should == 1
|
225
224
|
end
|
226
225
|
end
|
227
226
|
end
|
@@ -1,72 +1,151 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe 'substitute_for' do
|
4
|
+
context 'exact substitutability' do
|
5
|
+
context "returns true iff api methods and inherited methods match exactly to the other object's methods. Examples:" do
|
6
|
+
context "a surrogate with no api methods" do
|
7
|
+
let(:surrogate) { Surrogate.endow Class.new }
|
8
|
+
|
9
|
+
example "is substitutable for a class with no methods" do
|
10
|
+
surrogate.should substitute_for Class.new
|
11
|
+
end
|
12
|
+
|
13
|
+
example "is not substitutable for a class with instance methods" do
|
14
|
+
surrogate.should_not substitute_for Class.new { def foo()end }
|
15
|
+
end
|
16
|
+
|
17
|
+
example "is not substitutable for a class with class methods" do
|
18
|
+
surrogate.should_not substitute_for Class.new { def self.foo()end }
|
19
|
+
end
|
20
|
+
|
21
|
+
example "is not substitutable for a class with inherited instance methods" do
|
22
|
+
parent = Class.new { def foo()end }
|
23
|
+
surrogate.should_not substitute_for Class.new(parent)
|
24
|
+
end
|
25
|
+
|
26
|
+
example "is not substitutable for a class with inherited class methods" do
|
27
|
+
parent = Class.new { def self.foo()end }
|
28
|
+
surrogate.should_not substitute_for Class.new(parent)
|
29
|
+
end
|
30
|
+
end
|
4
31
|
|
5
|
-
context "returns true iff api methods and inherited methods match exactly to the other object's methods. Examples:" do
|
6
|
-
context "a surrogate with no api methods" do
|
7
|
-
let(:surrogate) { Surrogate.endow Class.new }
|
8
32
|
|
9
|
-
|
10
|
-
surrogate
|
11
|
-
end
|
33
|
+
context "a surrogate with an instance level api method" do
|
34
|
+
let(:surrogate) { Class.new { Surrogate.endow self; define :foo } }
|
12
35
|
|
13
|
-
|
14
|
-
|
15
|
-
|
36
|
+
example "is substitutable for a class with the same method" do
|
37
|
+
surrogate.should substitute_for Class.new { def foo()end }
|
38
|
+
end
|
16
39
|
|
17
|
-
|
18
|
-
|
19
|
-
|
40
|
+
example "is substitutable for a class that inherits the method" do
|
41
|
+
parent = Class.new { def foo()end }
|
42
|
+
surrogate.should substitute_for Class.new(parent)
|
43
|
+
end
|
20
44
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
end
|
45
|
+
example "is not substitutable for a class without the method" do
|
46
|
+
surrogate.should_not substitute_for Class.new
|
47
|
+
end
|
25
48
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
end
|
30
|
-
end
|
49
|
+
example "is not substitutable for a class with a different method" do
|
50
|
+
surrogate.should_not substitute_for Class.new { def bar()end }
|
51
|
+
end
|
31
52
|
|
53
|
+
example "is not substitutable for a class with additional methods" do
|
54
|
+
other = Class.new { def foo()end; def bar()end }
|
55
|
+
surrogate.should_not substitute_for other
|
56
|
+
end
|
32
57
|
|
33
|
-
|
34
|
-
|
58
|
+
example "is not substitutable for a class with the method and inerited additional methods" do
|
59
|
+
parent = Class.new { def bar()end }
|
60
|
+
surrogate.should_not substitute_for Class.new(parent) { def foo()end }
|
61
|
+
end
|
35
62
|
|
36
|
-
|
37
|
-
|
38
|
-
|
63
|
+
example "is not substitutable for a class with the method and additional class methods" do
|
64
|
+
surrogate.should_not substitute_for Class.new { def foo()end; def self.bar()end }
|
65
|
+
end
|
39
66
|
|
40
|
-
|
41
|
-
|
42
|
-
|
67
|
+
example "is not substitutable for a class with the method and inherited additional class methods" do
|
68
|
+
parent = Class.new { def self.bar()end }
|
69
|
+
surrogate.should_not substitute_for Class.new(parent) { def foo()end }
|
70
|
+
end
|
43
71
|
end
|
44
72
|
|
45
|
-
|
46
|
-
|
73
|
+
|
74
|
+
describe "it has helpful error messages" do
|
75
|
+
let(:surrogate) { Surrogate.endow Class.new }
|
76
|
+
|
77
|
+
specify 'when klass is missing an instance method' do
|
78
|
+
surrogate.define :meth
|
79
|
+
expect { surrogate.should substitute_for Class.new }.to \
|
80
|
+
raise_error(RSpec::Expectations::ExpectationNotMetError, "Was not substitutable because surrogate has extra instance methods: [:meth]")
|
81
|
+
end
|
82
|
+
|
83
|
+
specify 'when klass is missing a class method' do
|
84
|
+
surrogate = Surrogate.endow(Class.new) { define :meth }
|
85
|
+
expect { surrogate.should substitute_for Class.new }.to \
|
86
|
+
raise_error(RSpec::Expectations::ExpectationNotMetError, "Was not substitutable because surrogate has extra class methods: [:meth]")
|
87
|
+
end
|
88
|
+
|
89
|
+
specify 'when surrogate is missing an instance method' do
|
90
|
+
klass = Class.new { def meth() end }
|
91
|
+
expect { surrogate.should substitute_for klass }.to \
|
92
|
+
raise_error(RSpec::Expectations::ExpectationNotMetError, "Was not substitutable because surrogate is missing instance methods: [:meth]")
|
93
|
+
end
|
94
|
+
|
95
|
+
specify 'when surrogate is missing a class method' do
|
96
|
+
klass = Class.new { def self.meth() end }
|
97
|
+
expect { surrogate.should substitute_for klass }.to \
|
98
|
+
raise_error(RSpec::Expectations::ExpectationNotMetError, "Was not substitutable because surrogate is missing class methods: [:meth]")
|
99
|
+
end
|
100
|
+
|
101
|
+
specify 'when combined' do
|
102
|
+
surrogate = Surrogate.endow(Class.new) { define :surrogate_class_meth }.define :surrogate_instance_meth
|
103
|
+
klass = Class.new { def self.api_class_meth()end; def api_instance_meth() end }
|
104
|
+
expect { surrogate.should substitute_for klass }.to \
|
105
|
+
raise_error(RSpec::Expectations::ExpectationNotMetError, "Was not substitutable because surrogate has extra instance methods: [:surrogate_instance_meth], "\
|
106
|
+
"has extra class methods: [:surrogate_class_meth], "\
|
107
|
+
"is missing instance methods: [:api_instance_meth], "\
|
108
|
+
"is missing class methods: [:api_class_meth]")
|
109
|
+
end
|
110
|
+
|
111
|
+
specify "when negated (idk why you'd ever want this, though)" do
|
112
|
+
expect { surrogate.should_not substitute_for Class.new }.to \
|
113
|
+
raise_error(RSpec::Expectations::ExpectationNotMetError, "Should not have been substitute, but was")
|
114
|
+
end
|
47
115
|
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
|
48
120
|
|
49
|
-
|
50
|
-
|
121
|
+
context 'subset substitutability -- specified with subset: true option' do
|
122
|
+
context "returns true if api methods and inherited methods match are all implemented by other class. Examples:" do
|
123
|
+
example 'true when exact match' do
|
124
|
+
Surrogate.endow(Class.new).should substitute_for Class.new, subset: true
|
51
125
|
end
|
52
126
|
|
53
|
-
example
|
54
|
-
|
55
|
-
|
127
|
+
example 'true when other has additional instance methods and class methods' do
|
128
|
+
klass = Class.new { def self.class_meth()end; def instance_meth()end }
|
129
|
+
Surrogate.endow(Class.new).should substitute_for klass, subset: true
|
56
130
|
end
|
57
131
|
|
58
|
-
example
|
59
|
-
|
60
|
-
|
132
|
+
example 'false when other is missing instance methods' do
|
133
|
+
klass = Class.new { def self.extra_method()end; def extra_method()end }
|
134
|
+
expect { Surrogate.endow(Class.new).define(:meth).should substitute_for klass, subset:true }.to \
|
135
|
+
raise_error(RSpec::Expectations::ExpectationNotMetError, "Was not substitutable because surrogate has extra instance methods: [:meth]")
|
61
136
|
end
|
62
137
|
|
63
|
-
example
|
64
|
-
|
138
|
+
example 'false when other is missing class methods' do
|
139
|
+
klass = Class.new { def self.extra_method()end; def extra_method()end }
|
140
|
+
expect { Surrogate.endow(Class.new) { define :meth }.should substitute_for klass, subset:true }.to \
|
141
|
+
raise_error(RSpec::Expectations::ExpectationNotMetError, "Was not substitutable because surrogate has extra class methods: [:meth]")
|
65
142
|
end
|
66
143
|
|
67
|
-
example
|
68
|
-
|
69
|
-
|
144
|
+
example 'false when other is missing instance and class methods' do
|
145
|
+
klass = Class.new { def self.extra_method()end; def extra_method()end }
|
146
|
+
expect { Surrogate.endow(Class.new) { define :class_meth }.define(:instance_meth).should substitute_for klass, subset: true }.to \
|
147
|
+
raise_error(RSpec::Expectations::ExpectationNotMetError,
|
148
|
+
"Was not substitutable because surrogate has extra instance methods: [:instance_meth], has extra class methods: [:class_meth]")
|
70
149
|
end
|
71
150
|
end
|
72
151
|
end
|
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.3.0
|
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-
|
12
|
+
date: 2012-04-30 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
|
-
requirement: &
|
16
|
+
requirement: &70298496271040 !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: *70298496271040
|
25
25
|
description: Framework to aid in handrolling mock/spy objects.
|
26
26
|
email:
|
27
27
|
- josh.cheek@gmail.com
|