surrogate 0.3.2 → 0.4.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.
data/Rakefile CHANGED
@@ -1 +1,13 @@
1
1
  require "bundler/gem_tasks"
2
+
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new :rspec do |t|
6
+ t.rspec_opts = [
7
+ '--fail-fast',
8
+ '--colour',
9
+ '--format', 'documentation',
10
+ ]
11
+ end
12
+
13
+ task default: :rspec
data/Readme.md CHANGED
@@ -64,13 +64,14 @@ end
64
64
  MockClient.new.request 3 # => ["result1", "result2", "result3"]
65
65
  ```
66
66
 
67
- You don't need a **default if you set the ivar** of the same name
67
+ You don't need a **default if you set the ivar** of the same name (replace `?` with `_p` for predicates, since you can't have question marks in ivar names)
68
68
 
69
69
  ```ruby
70
70
  class MockClient
71
71
  Surrogate.endow self
72
- define(:initialize) { |id| @id = id }
72
+ define(:initialize) { |id| @id, @connected_p = id, true }
73
73
  define :id
74
+ define :connected?
74
75
  end
75
76
  MockClient.new(12).id # => 12
76
77
  ```
@@ -318,7 +319,7 @@ end
318
319
  # doesn't matter that real user has a name as long as it has initialize and id
319
320
  MockUser.should substitute_for User, subset: true
320
321
 
321
- # but now it fails b/c it has no addres
322
+ # but now it fails b/c it has no address
322
323
  MockUser.define :address
323
324
  MockUser.should_not substitute_for User, subset: true
324
325
  ```
@@ -332,7 +333,7 @@ the initializer, you can pass a factory to your class, you can give the class th
332
333
  setter and then override it whenever you feel it is necessary, you can use RSpec's `#stub` method to put
333
334
  it into place.
334
335
 
335
- Personally, I use [Deject](https://rubygems.org/gems/deject) another gem I wrote. For more on why I feel
336
+ Personally, I use [Deject](https://rubygems.org/gems/deject), another gem I wrote. For more on why I feel
336
337
  it is a better solution than the above methods, see it's [readme](https://github.com/JoshCheek/deject/tree/938edc985c65358c074a7c7b7bbf18dc11e9450e#why-write-this).
337
338
 
338
339
 
@@ -346,6 +347,7 @@ Special Thanks
346
347
  ==============
347
348
 
348
349
  * [Kyle Hargraves](https://github.com/pd) for changing the name of his internal gem so that I could take Surrogate
350
+ * [David Chelimsky](http://blog.davidchelimsky.net/) for pairing with me to make Surrogate integrate better with RSpec
349
351
  * [Corey Haines](http://coreyhaines.com/) for pairing on substitutability with me
350
352
  * [Enova](http://www.enovafinancial.com/) for giving me time and motivation to work on this during Enova Labs.
351
353
  * [8th Light](http://8thlight.com/) for giving me time to work on this during our weekly Wazas, and the general encouragement and interest
@@ -361,7 +363,6 @@ TODO
361
363
  Future Features
362
364
  ---------------
363
365
 
364
- * Support all RSpec matchers (hash_including, anything, etc. see them in RSpec::Mocks::ArgumentMatchers)
365
366
  * have some sort of reinitialization that can hook into setup/teardown steps of test suite
366
367
  * Support arity checking as part of substitutability
367
368
  * Support for blocks
@@ -55,7 +55,7 @@ class Surrogate
55
55
  @hijacking_initialize = false
56
56
  end
57
57
  initialize = klass.instance_method :initialize
58
- klass.send :define_method, :initialize do |*args, &block|
58
+ klass.__send__ :define_method, :initialize do |*args, &block|
59
59
  initialize.bind(self).call(*args, &block)
60
60
  end
61
61
  end
@@ -65,7 +65,7 @@ class Surrogate
65
65
  end
66
66
 
67
67
  def remember_invocations_for_instances_of(klass)
68
- klass.send :define_method, :invocations do |method_name|
68
+ klass.__send__ :define_method, :invocations do |method_name|
69
69
  @hatchling.invocations method_name
70
70
  end
71
71
  end
@@ -30,11 +30,11 @@ class Surrogate
30
30
  private
31
31
 
32
32
  def klass_can_define_api_methods
33
- klass.singleton_class.send :define_method, :define, &method(:define)
33
+ klass.singleton_class.__send__ :define_method, :define, &method(:define)
34
34
  end
35
35
 
36
36
  def add_api_method_for(method_name)
37
- klass.send :define_method, method_name do |*args, &block|
37
+ klass.__send__ :define_method, method_name do |*args, &block|
38
38
  @hatchling.invoke_method method_name, args, &block
39
39
  end
40
40
  end
@@ -48,7 +48,7 @@ class Surrogate
48
48
  end
49
49
 
50
50
  def add_helpers_for(method_name, helper_name)
51
- klass.send :define_method, helper_name do |*args, &block|
51
+ klass.__send__ :define_method, helper_name do |*args, &block|
52
52
  @hatchling.prepare_method method_name, args, &block
53
53
  self
54
54
  end
@@ -31,19 +31,28 @@ class Surrogate
31
31
 
32
32
  # maybe these four should be extracted into their own class
33
33
  def has_ivar?(method_name)
34
- instance.instance_variable_defined? "@#{method_name}"
34
+ instance.instance_variable_defined? ivar_for method_name
35
35
  end
36
36
 
37
37
  def set_ivar(method_name, value)
38
- instance.instance_variable_set "@#{method_name}", value
38
+ instance.instance_variable_set ivar_for(method_name), value
39
39
  end
40
40
 
41
41
  def get_ivar(method_name)
42
- instance.instance_variable_get "@#{method_name}"
42
+ instance.instance_variable_get ivar_for method_name
43
43
  end
44
44
 
45
45
  def unset_ivar(method_name)
46
- instance.send :remove_instance_variable, "@#{method_name}"
46
+ instance.__send__ :remove_instance_variable, ivar_for(method_name)
47
+ end
48
+
49
+ def ivar_for(method_name)
50
+ case method_name
51
+ when /\?$/
52
+ "@#{method_name.to_s.chop}_p"
53
+ else
54
+ "@#{method_name}"
55
+ end
47
56
  end
48
57
 
49
58
  private
@@ -50,14 +50,14 @@ class Surrogate
50
50
  end
51
51
 
52
52
  def inspect_arguments(arguments)
53
- inspected_arguments = arguments.map { |argument| MessagesFor.inspect_argument argument }
54
- inspected_arguments << 'no_args' if inspected_arguments.empty?
55
- %Q(`#{inspected_arguments.join ", "}')
53
+ inspected_arguments = arguments.map { |argument| inspect_argument argument }
54
+ inspected_arguments << 'no args' if inspected_arguments.empty?
55
+ "`" << inspected_arguments.join(", ") << "'"
56
56
  end
57
57
 
58
58
  def inspect_argument(to_inspect)
59
- if to_inspect.kind_of? ::RSpec::Mocks::ArgumentMatchers::NoArgsMatcher
60
- "no_args"
59
+ if RSpec.rspec_mocks_loaded? && to_inspect.respond_to?(:description)
60
+ to_inspect.description
61
61
  else
62
62
  to_inspect.inspect
63
63
  end
@@ -67,8 +67,9 @@ class Surrogate
67
67
  end
68
68
 
69
69
 
70
+ # sigh, surely there is a better name!
70
71
  class Handler < Struct.new(:subject, :language_type)
71
- attr_accessor :instance, :message_type
72
+ attr_accessor :instance
72
73
 
73
74
  def message_for(message_category, message_type)
74
75
  MessagesFor.message_for(language_type, message_category, message_type, binding)
@@ -79,7 +80,7 @@ class Surrogate
79
80
  end
80
81
 
81
82
  def message_type
82
- @message_type || :default
83
+ :default
83
84
  end
84
85
 
85
86
  def invocations
@@ -105,23 +106,45 @@ class Surrogate
105
106
  def failure_message_for_should_not
106
107
  message_for :should_not, message_type
107
108
  end
108
- end
109
109
 
110
+ def times(times_invoked)
111
+ # is there a good way to remove these conditionals?
112
+ extend (kind_of?(MatchWithArguments) ? MatchNumTimesWith : MatchNumTimes)
113
+ self.expected_times_invoked = times_invoked
114
+ self
115
+ end
110
116
 
111
- module MatchWithArguments
112
- def self.extended(klass)
113
- klass.message_type = :with
117
+ def with(*arguments)
118
+ extend (kind_of?(MatchNumTimes) ? MatchNumTimesWith : MatchWithArguments)
119
+ self.expected_arguments = arguments
120
+ self
114
121
  end
122
+ end
115
123
 
116
- attr_accessor :expected_arguments
117
124
 
118
- def match? # eventually this will need to get a lot smarter
119
- if expected_arguments.size == 1 && expected_arguments.first.kind_of?(::RSpec::Mocks::ArgumentMatchers::NoArgsMatcher)
120
- invocations.include? []
125
+ module ArgumentComparer
126
+ def args_match?(actual_arguments)
127
+ if RSpec.rspec_mocks_loaded?
128
+ rspec_arg_expectation = ::RSpec::Mocks::ArgumentExpectation.new *expected_arguments
129
+ rspec_arg_expectation.args_match? *actual_arguments
121
130
  else
122
- invocations.include? expected_arguments
131
+ expected_arguments == actual_arguments
123
132
  end
124
133
  end
134
+ end
135
+
136
+ module MatchWithArguments
137
+ include ArgumentComparer
138
+
139
+ attr_accessor :expected_arguments
140
+
141
+ def message_type
142
+ :with
143
+ end
144
+
145
+ def match?
146
+ invocations.any? { |invocation| args_match? invocation }
147
+ end
125
148
 
126
149
  def actual_invocation
127
150
  return message_for :other, :not_invoked if times_invoked.zero?
@@ -132,8 +155,8 @@ class Surrogate
132
155
 
133
156
 
134
157
  module MatchNumTimes
135
- def self.extended(klass)
136
- klass.message_type = :times
158
+ def message_type
159
+ :times
137
160
  end
138
161
 
139
162
  attr_accessor :expected_times_invoked
@@ -145,14 +168,16 @@ class Surrogate
145
168
 
146
169
 
147
170
  module MatchNumTimesWith
148
- def self.extended(klass)
149
- klass.message_type = :with_times
171
+ include ArgumentComparer
172
+
173
+ def message_type
174
+ :with_times
150
175
  end
151
176
 
152
177
  attr_accessor :expected_times_invoked, :expected_arguments
153
178
 
154
179
  def times_invoked_with_expected_args
155
- invocations.select { |invocation| invocation == expected_arguments }.size
180
+ invocations.select { |invocation| args_match? invocation }.size
156
181
  end
157
182
 
158
183
  def match?
@@ -166,75 +191,37 @@ class Surrogate
166
191
  end
167
192
 
168
193
 
194
+ surrogate_matcher = lambda do |use_case, matcher, morphable=false|
195
+ if morphable
196
+ matcher.chain(:times) { |number| use_case.times number }
197
+ matcher.chain(:with) { |*arguments| use_case.with *arguments }
198
+ end
169
199
 
170
-
171
-
172
- # have_been_told_to
173
- ::RSpec::Matchers.define :have_been_told_to do |verb|
174
- use_case = Handler.new verb, :verb
175
-
176
- match do |mocked_instance|
200
+ matcher.match do |mocked_instance|
177
201
  use_case.instance = mocked_instance
178
202
  use_case.match?
179
203
  end
180
204
 
181
- chain :times do |number|
182
- use_case.extend (use_case.kind_of?(MatchWithArguments) ? MatchNumTimesWith : MatchNumTimes)
183
- use_case.expected_times_invoked = number
184
- end
205
+ matcher.failure_message_for_should { use_case.failure_message_for_should }
206
+ matcher.failure_message_for_should_not { use_case.failure_message_for_should_not }
207
+ end
185
208
 
186
- chain :with do |*arguments|
187
- use_case.extend (use_case.kind_of?(MatchNumTimes) ? MatchNumTimesWith : MatchWithArguments)
188
- use_case.expected_arguments = arguments
189
- end
190
209
 
191
- failure_message_for_should { use_case.failure_message_for_should }
192
- failure_message_for_should_not { use_case.failure_message_for_should_not }
210
+ # have_been_told_to
211
+ ::RSpec::Matchers.define :have_been_told_to do |verb|
212
+ surrogate_matcher[Handler.new(verb, :verb), self, true]
193
213
  end
194
214
 
195
215
 
196
216
  # have_been_asked_for_its
197
217
  ::RSpec::Matchers.define :have_been_asked_for_its do |noun|
198
- use_case = Handler.new noun, :noun
199
-
200
- match do |mocked_instance|
201
- use_case.instance = mocked_instance
202
- use_case.match?
203
- end
204
-
205
- chain :times do |number|
206
- use_case.extend (use_case.kind_of?(MatchWithArguments) ? MatchNumTimesWith : MatchNumTimes)
207
- use_case.expected_times_invoked = number
208
- end
209
-
210
- chain :with do |*arguments|
211
- use_case.extend (use_case.kind_of?(MatchNumTimes) ? MatchNumTimesWith : MatchWithArguments)
212
- use_case.expected_arguments = arguments
213
- end
214
-
215
- failure_message_for_should { use_case.failure_message_for_should }
216
- failure_message_for_should_not { use_case.failure_message_for_should_not }
218
+ surrogate_matcher[Handler.new(noun, :noun), self, true]
217
219
  end
218
220
 
219
221
 
220
222
  # have_been_initialized_with
221
223
  ::RSpec::Matchers.define :have_been_initialized_with do |*init_args|
222
- use_case = Handler.new :initialize, :verb
223
- use_case.extend MatchWithArguments
224
- use_case.expected_arguments = init_args
225
-
226
- match do |mocked_instance|
227
- use_case.instance = mocked_instance
228
- use_case.match?
229
- end
230
-
231
- failure_message_for_should do
232
- use_case.failure_message_for_should
233
- end
234
-
235
- failure_message_for_should_not do
236
- use_case.failure_message_for_should_not
237
- end
224
+ surrogate_matcher[Handler.new(:initialize, :verb).with(*init_args), self]
238
225
  end
239
226
  end
240
227
  end
@@ -1,4 +1,25 @@
1
1
  # Maybe I should be my own gem?
2
+
3
+ class Surrogate
4
+ module RSpec
5
+ class << self
6
+ def rspec_mocks_loaded?
7
+ return @mocks_loaded if @alrady_checked_mocks
8
+ @alrady_checked_mocks = true
9
+ require 'rspec/mocks' # can't figure out a way to do this lazily
10
+ @mocks_loaded = true
11
+ rescue LoadError
12
+ @mocks_loaded = false
13
+ end
14
+
15
+ def rspec_mocks_loaded=(bool)
16
+ @alrady_checked_mocks = true
17
+ @mocks_loaded = bool
18
+ end
19
+ end
20
+ end
21
+ end
22
+
2
23
  require 'surrogate'
3
24
  require 'surrogate/rspec/api_method_matchers'
4
25
  require 'surrogate/rspec/substitutability_matchers'
@@ -7,8 +7,13 @@ class Surrogate
7
7
  # convert raw arguments into a value
8
8
  def self.factory(*args, &block)
9
9
  arg = args.first
10
+ # if arg.kind_of? Exception
11
+ # Raiseable.new arg
12
+ # else
13
+ # MethodQueue.new args
14
+ # end
10
15
  if args.size > 1
11
- MethodQueue.new args
16
+ ValueQueue.new args
12
17
  elsif arg.kind_of? Exception
13
18
  Raisable.new arg
14
19
  elsif arg.kind_of? Value
@@ -45,7 +50,7 @@ class Surrogate
45
50
  end
46
51
 
47
52
 
48
- class MethodQueue < Value
53
+ class ValueQueue < Value
49
54
  QueueEmpty = Class.new StandardError
50
55
 
51
56
  def value(hatchling, method_name)
@@ -1,3 +1,3 @@
1
1
  class Surrogate
2
- VERSION = "0.3.2"
2
+ VERSION = "0.4.2"
3
3
  end
@@ -1,6 +1,9 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe 'define' do
4
+ let(:mocked_class) { Surrogate.endow Class.new }
5
+ let(:instance) { mocked_class.new }
6
+
4
7
  describe 'in the block' do
5
8
  it 'is an api method for the class' do
6
9
  pristine_klass = Class.new do
@@ -18,248 +21,253 @@ describe 'define' do
18
21
 
19
22
 
20
23
  describe 'out of the block' do
21
- let(:mocked_class) { Surrogate.endow Class.new }
22
- let(:instance) { mocked_class.new }
23
-
24
24
  it 'is an api method for the instance' do
25
25
  mocked_class.define(:book) { 'book' }
26
26
  instance.book.should == 'book'
27
27
  end
28
+ end
28
29
 
29
- describe 'declaring the behaviour' do
30
- describe 'for verbs' do
31
- before { mocked_class.define :wink }
32
-
33
- describe 'will_<api_method>' do
34
- it 'overrides the default value for the api method' do
35
- mock1 = mocked_class.new
36
- mock2 = mocked_class.new
37
- mock1.will_wink :quickly
38
- mock2.will_wink :slowly
39
- mock1.wink.should == :quickly
40
- mock2.wink.should == :slowly
41
- mock1.wink.should == :quickly
42
- end
30
+ describe 'declaring the behaviour' do
43
31
 
44
- it 'returns the object' do
45
- instance = mocked_class.new
46
- instance.will_wink(:quickly).should equal instance
47
- end
32
+ describe 'for verbs' do
33
+ before { mocked_class.define :wink }
34
+
35
+ describe 'will_<api_method>' do
36
+ it 'overrides the default value for the api method' do
37
+ mock1 = mocked_class.new
38
+ mock2 = mocked_class.new
39
+ mock1.will_wink :quickly
40
+ mock2.will_wink :slowly
41
+ mock1.wink.should == :quickly
42
+ mock2.wink.should == :slowly
43
+ mock1.wink.should == :quickly
48
44
  end
49
45
 
50
- describe 'will_<api_method> with multiple arguments' do
51
- it 'returns the object' do
52
- instance = mocked_class.new
53
- instance.will_wink(1, 2, 3).should equal instance
54
- end
46
+ it 'returns the object' do
47
+ instance = mocked_class.new
48
+ instance.will_wink(:quickly).should equal instance
49
+ end
50
+ end
55
51
 
56
- context 'it creates a queue of things to find then returns to normal behaviour' do
57
- specify 'when there is no default block' do
58
- mock = mocked_class.new
59
- mock.will_wink :quickly, :slowly
60
- mock.wink.should == :quickly
61
- mock.wink.should == :slowly
62
- expect { mock.wink }.to raise_error Surrogate::UnpreparedMethodError
63
- end
52
+ describe 'will_<api_method> with multiple arguments' do
53
+ it 'returns the object' do
54
+ instance = mocked_class.new
55
+ instance.will_wink(1, 2, 3).should equal instance
56
+ end
64
57
 
65
- specify 'when there is a default block' do
66
- mocked_class = Surrogate.endow(Class.new)
67
- mocked_class.define(:connect) { :default }
68
- mock = mocked_class.new
69
- mock.will_connect 1, 2
70
- mock.connect.should == 1
71
- mock.connect.should == 2
72
- mock.connect.should == :default
73
- end
58
+ context 'it creates a queue of things to find then returns to normal behaviour' do
59
+ specify 'when there is no default block' do
60
+ mock = mocked_class.new
61
+ mock.will_wink :quickly, [:slowly]
62
+ mock.wink.should == :quickly
63
+ mock.wink.should == [:slowly]
64
+ expect { mock.wink }.to raise_error Surrogate::UnpreparedMethodError
74
65
  end
75
- end
76
66
 
77
- describe 'when an argument is an error' do
78
- it 'raises the error on method invocation' do
67
+ specify 'when there is a default block' do
79
68
  mocked_class = Surrogate.endow(Class.new)
80
- mocked_class.define :connect
69
+ mocked_class.define(:connect) { :default }
81
70
  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
71
+ mock.will_connect 1, 2
90
72
  mock.connect.should == 1
91
- expect { mock.connect }.to raise_error StandardError, "some message"
92
73
  mock.connect.should == 2
74
+ mock.connect.should == :default
93
75
  end
94
76
  end
95
77
  end
96
78
 
79
+ describe 'when an argument is an error' do
80
+ it 'raises the error on method invocation' do
81
+ mocked_class = Surrogate.endow(Class.new)
82
+ mocked_class.define :connect
83
+ mock = mocked_class.new
84
+ error = StandardError.new("some message")
85
+
86
+ # for single invocation
87
+ mock.will_connect error
88
+ expect { mock.connect }.to raise_error StandardError, "some message"
89
+
90
+ # for queue
91
+ mock.will_connect 1, error, 2
92
+ mock.connect.should == 1
93
+ expect { mock.connect }.to raise_error StandardError, "some message"
94
+ mock.connect.should == 2
95
+ end
96
+ end
97
+ end
97
98
 
98
- describe 'for nouns' do
99
- before { mocked_class.define :age }
100
99
 
101
- describe 'will_have_<api_method>' do
102
- it 'defines will_have_<api_method> which overrides the default block' do
103
- mock1 = mocked_class.new
104
- mock2 = mocked_class.new
105
- mock1.will_have_age 12
106
- mock2.will_have_age 34
107
- mock1.age.should == 12
108
- mock2.age.should == 34
109
- mock1.age.should == 12
110
- end
100
+ describe 'for nouns' do
101
+ before { mocked_class.define :age }
111
102
 
112
- it 'returns the object' do
113
- instance = mocked_class.new
114
- instance.will_have_age(123).should equal instance
115
- end
103
+ describe 'will_have_<api_method>' do
104
+ it 'defines will_have_<api_method> which overrides the default block' do
105
+ mock1 = mocked_class.new
106
+ mock2 = mocked_class.new
107
+ mock1.will_have_age 12
108
+ mock2.will_have_age 34
109
+ mock1.age.should == 12
110
+ mock2.age.should == 34
111
+ mock1.age.should == 12
116
112
  end
117
113
 
118
- describe 'wil_have_<api_method> with multiple arguments' do
119
- it 'returns the object' do
120
- instance = mocked_class.new
121
- instance.will_have_age(1,2,3).should equal instance
122
- end
114
+ it 'returns the object' do
115
+ instance = mocked_class.new
116
+ instance.will_have_age(123).should equal instance
117
+ end
118
+ end
123
119
 
124
- context 'it creates a queue of things to find then returns to normal behaviour' do
125
- specify 'when there is no default block' do
126
- mock = mocked_class.new
127
- mock.will_have_age 12, 34
128
- mock.age.should == 12
129
- mock.age.should == 34
130
- expect { mock.age }.to raise_error Surrogate::UnpreparedMethodError
131
- end
120
+ describe 'wil_have_<api_method> with multiple arguments' do
121
+ it 'returns the object' do
122
+ instance = mocked_class.new
123
+ instance.will_have_age(1,2,3).should equal instance
124
+ end
132
125
 
133
- specify 'when there is a default block' do
134
- mocked_class = Surrogate.endow(Class.new)
135
- mocked_class.define(:name) { 'default' }
136
- mock = mocked_class.new
137
- mock.will_have_name 'a', 'b'
138
- mock.name.should == 'a'
139
- mock.name.should == 'b'
140
- mock.name.should == 'default'
141
- end
126
+ context 'it creates a queue of things to find then returns to normal behaviour' do
127
+ specify 'when there is no default block' do
128
+ mock = mocked_class.new
129
+ mock.will_have_age 12, 34
130
+ mock.age.should == 12
131
+ mock.age.should == 34
132
+ expect { mock.age }.to raise_error Surrogate::UnpreparedMethodError
133
+ end
134
+
135
+ specify 'when there is a default block' do
136
+ mocked_class = Surrogate.endow(Class.new)
137
+ mocked_class.define(:name) { 'default' }
138
+ mock = mocked_class.new
139
+ mock.will_have_name 'a', 'b'
140
+ mock.name.should == 'a'
141
+ mock.name.should == 'b'
142
+ mock.name.should == 'default'
142
143
  end
143
144
  end
144
145
  end
145
146
  end
147
+ end
146
148
 
147
149
 
148
150
 
149
- context 'the api method' do
150
- it 'takes any number of arguments' do
151
- mocked_class.define(:meth) { 1 }
152
- mocked_class.new.meth.should == 1
153
- mocked_class.new.meth(1).should == 1
154
- mocked_class.new.meth(1, 2).should == 1
155
- end
151
+ context 'the api method' do
152
+ it 'takes any number of arguments' do
153
+ mocked_class.define(:meth) { 1 }
154
+ mocked_class.new.meth.should == 1
155
+ mocked_class.new.meth(1).should == 1
156
+ mocked_class.new.meth(1, 2).should == 1
157
+ end
156
158
 
157
- it 'raises an UnpreparedMethodError when it has no default block' do
158
- mocked_class.define :meth
159
- expect { mocked_class.new.meth }.to raise_error(Surrogate::UnpreparedMethodError, /meth/)
160
- end
159
+ it 'raises an UnpreparedMethodError when it has no default block' do
160
+ mocked_class.define :meth
161
+ expect { mocked_class.new.meth }.to raise_error(Surrogate::UnpreparedMethodError, /meth/)
162
+ end
161
163
 
162
- it 'considers ivars of the same name to be its default' do
163
- mocked_class.define :meth
164
- mocked = mocked_class.new
165
- mocked.instance_variable_set :@meth, 123
166
- mocked.meth.should == 123
167
- end
164
+ it 'considers ivars of the same name to be its default when it has no suffix' do
165
+ mocked_class.define :meth
166
+ mocked = mocked_class.new
167
+ mocked.instance_variable_set :@meth, 123
168
+ mocked.meth.should == 123
169
+ end
170
+
171
+ it 'considers ivars ending in _p to be its default when it ends in a question mark' do
172
+ mocked_class.define :meth?
173
+ mocked = mocked_class.new
174
+ mocked.instance_variable_set :@meth_p, 123
175
+ mocked.meth?.should == 123
176
+ end
177
+
178
+ it 'reverts to the default block if invoked and having no ivar' do
179
+ mocked_class.define(:meth) { 123 }
180
+ mocked = mocked_class.new
181
+ mocked.instance_variable_get(:@meth).should be_nil
182
+ mocked.meth.should == 123
183
+ end
168
184
 
169
- it 'reverts to the default block if invoked and having no ivar' do
170
- mocked_class.define(:meth) { 123 }
171
- mocked = mocked_class.new
172
- mocked.instance_variable_get(:@meth).should be_nil
173
- mocked.meth.should == 123
185
+ describe 'initialization' do
186
+ specify 'api methods can be an initialize method' do
187
+ mocked_class.define(:initialize) { @abc = 123 }
188
+ mocked_class.new.instance_variable_get(:@abc).should == 123
174
189
  end
175
190
 
176
- describe 'initialization' do
177
- specify 'api methods can be an initialize method' do
178
- mocked_class.define(:initialize) { @abc = 123 }
179
- mocked_class.new.instance_variable_get(:@abc).should == 123
180
- end
191
+ specify 'initialize exsits even if error is raised' do
192
+ mocked_class.define(:initialize) { raise "simulate runtime error" }
193
+ expect { mocked_class.new }.to raise_error(RuntimeError, /simulate/)
194
+ expect { mocked_class.new }.to raise_error(RuntimeError, /simulate/)
195
+ end
181
196
 
182
- specify 'initialize exsits even if error is raised' do
183
- mocked_class.define(:initialize) { raise "simulate runtime error" }
184
- expect { mocked_class.new }.to raise_error(RuntimeError, /simulate/)
185
- expect { mocked_class.new }.to raise_error(RuntimeError, /simulate/)
186
- end
197
+ specify 'receives args' do
198
+ mocked_class.define(:initialize) { |num1, num2| @num = num1 + num2 }
199
+ mocked_class.new(25, 75).instance_variable_get(:@num).should == 100
200
+ end
187
201
 
188
- specify 'receives args' do
189
- mocked_class.define(:initialize) { |num1, num2| @num = num1 + num2 }
190
- mocked_class.new(25, 75).instance_variable_get(:@num).should == 100
191
- end
202
+ specify 'even works with inheritance' do
203
+ superclass = Class.new
204
+ superclass.send(:define_method, :initialize) { @a = 1 }
205
+ subclass = Surrogate.endow Class.new superclass
206
+ subclass.define :abc
207
+ subclass.new.instance_variable_get(:@a).should == 1
208
+ end
192
209
 
193
- specify 'even works with inheritance' do
194
- superclass = Class.new
195
- superclass.send(:define_method, :initialize) { @a = 1 }
196
- subclass = Surrogate.endow Class.new superclass
197
- subclass.define :abc
198
- subclass.new.instance_variable_get(:@a).should == 1
210
+ context 'when not an api method' do
211
+ it 'respects arity (this is probably 1.9.3 only)' do
212
+ expect { mocked_class.new 1 }.to raise_error ArgumentError, 'wrong number of arguments(1 for 0)'
199
213
  end
200
214
 
201
- context 'when not an api method' do
202
- it 'respects arity (this is probably 1.9.3 only)' do
203
- expect { mocked_class.new 1 }.to raise_error ArgumentError, 'wrong number of arguments(1 for 0)'
204
- end
205
-
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
211
- end
212
- klass.new(1).should have_been_initialized_with 1
213
- klass.new(1).instance_variable_get(:@a).should == 1
215
+ describe 'invocations are recorded anyway' do
216
+ specify 'even when initialize is defined after surrogate block' do
217
+ klass = Class.new do
218
+ Surrogate.endow self
219
+ def initialize(a) @a = a end
214
220
  end
221
+ klass.new(1).should have_been_initialized_with 1
222
+ klass.new(1).instance_variable_get(:@a).should == 1
223
+ end
215
224
 
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
- end
221
- klass.new(1).should have_been_initialized_with 1
222
- klass.new(1).instance_variable_get(:@a).should == 1
225
+ specify 'even when initialize is defined before surrogate block' do
226
+ klass = Class.new do
227
+ def initialize(a) @a = a end
228
+ Surrogate.endow self
223
229
  end
230
+ klass.new(1).should have_been_initialized_with 1
231
+ klass.new(1).instance_variable_get(:@a).should == 1
224
232
  end
225
233
  end
226
234
  end
235
+ end
227
236
 
228
- describe 'it takes a block whos return value will be used as the default' do
229
- specify 'the block is instance evaled' do
230
- mocked_class.define(:meth) { self }
231
- instance = mocked_class.new
232
- instance.meth.should equal instance
233
- end
234
-
235
- specify 'arguments passed to the method will be passed to the block' do
236
- mocked_class.define(:meth) { |*args| args }
237
- instance = mocked_class.new
238
- instance.meth(1).should == [1]
239
- instance.meth(1, 2).should == [1, 2]
240
- end
237
+ describe 'it takes a block whos return value will be used as the default' do
238
+ specify 'the block is instance evaled' do
239
+ mocked_class.define(:meth) { self }
240
+ instance = mocked_class.new
241
+ instance.meth.should equal instance
241
242
  end
242
243
 
243
- it 'remembers what it was invoked with' do
244
- mocked_class.define(:meth) { nil }
245
- mock = mocked_class.new
246
- mock.meth 1
247
- mock.meth 1, 2
248
- mock.meth [1, 2]
249
- mock.invocations(:meth).should == [
250
- [1],
251
- [1, 2],
252
- [[1, 2]],
253
- ]
244
+ specify 'arguments passed to the method will be passed to the block' do
245
+ mocked_class.define(:meth) { |*args| args }
246
+ instance = mocked_class.new
247
+ instance.meth(1).should == [1]
248
+ instance.meth(1, 2).should == [1, 2]
254
249
  end
250
+ end
255
251
 
256
- it 'raises an error if asked about invocations for api methods it does not know' do
257
- mocked_class.define :meth1
258
- mocked_class.define :meth2
259
- mock = mocked_class.new
260
- expect { mock.invocations(:meth1) }.to_not raise_error
261
- expect { mock.invocations(:meth3) }.to raise_error Surrogate::UnknownMethod, /doesn't know "meth3", only knows "initialize", "meth1", "meth2"/
262
- end
252
+ it 'remembers what it was invoked with' do
253
+ mocked_class.define(:meth) { nil }
254
+ mock = mocked_class.new
255
+ mock.meth 1
256
+ mock.meth 1, 2
257
+ mock.meth [1, 2]
258
+ mock.invocations(:meth).should == [
259
+ [1],
260
+ [1, 2],
261
+ [[1, 2]],
262
+ ]
263
+ end
264
+
265
+ it 'raises an error if asked about invocations for api methods it does not know' do
266
+ mocked_class.define :meth1
267
+ mocked_class.define :meth2
268
+ mock = mocked_class.new
269
+ expect { mock.invocations(:meth1) }.to_not raise_error
270
+ expect { mock.invocations(:meth3) }.to raise_error Surrogate::UnknownMethod, /doesn't know "meth3", only knows "initialize", "meth1", "meth2"/
263
271
  end
264
272
  end
265
273
 
@@ -60,12 +60,17 @@ describe 'RSpec matchers', 'have_been_asked_for_its' do
60
60
  end
61
61
 
62
62
  describe 'integration with rspec argument_matchers' do
63
- it 'works with no_args' do
63
+ it 'works with rspec matchers' do
64
64
  instance.should_not have_been_asked_for_its(:size).with(no_args)
65
65
  instance.size(1)
66
66
  instance.should_not have_been_asked_for_its(:size).with(no_args)
67
67
  instance.size
68
68
  instance.should have_been_asked_for_its(:size).with(no_args)
69
+
70
+ instance.should_not have_been_asked_for_its(:size).with(hash_including all: true)
71
+ instance.size any: false, all: true
72
+ instance.should have_been_asked_for_its(:size).with(hash_including all: true)
73
+ instance.should_not have_been_asked_for_its(:size).with(hash_including all: false)
69
74
  end
70
75
  end
71
76
  end
@@ -11,8 +11,9 @@ describe messages_for, 'argument inspection' do
11
11
  messages_for.inspect_argument([/a/]).should == "[/a/]"
12
12
  end
13
13
 
14
- it 'inspects no_args matcher' do
15
- messages_for.inspect_argument(no_args).should == 'no_args'
14
+ it 'inspects rspec matchers' do
15
+ messages_for.inspect_argument(no_args).should == 'no args'
16
+ messages_for.inspect_argument(hash_including abc: 123).should == 'hash_including(:abc=>123)'
16
17
  end
17
18
  end
18
19
 
@@ -23,11 +24,11 @@ describe messages_for, 'argument inspection' do
23
24
  end
24
25
 
25
26
  it "joins arguments with commas" do
26
- messages_for.inspect_arguments(['x', no_args]).should == "`\"x\", no_args'"
27
+ messages_for.inspect_arguments(['x', no_args]).should == "`\"x\", no args'"
27
28
  end
28
29
 
29
30
  it 'returns no_args when the array is empty' do
30
- messages_for.inspect_arguments([]).should == "`no_args'"
31
+ messages_for.inspect_arguments([]).should == "`no args'"
31
32
  end
32
33
  end
33
34
  end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'integration with rspec-mocks' do
4
+
5
+ let(:mp3) { Surrogate.endow(Class.new).define(:play) { }.new }
6
+
7
+ it 'knows that rspec-mocks is loaded' do
8
+ Surrogate::RSpec.rspec_mocks_loaded?.should equal true
9
+ end
10
+
11
+ context 'when rspec-mocks is loaded' do
12
+ it 'uses their matchers' do
13
+ mp3.play "Emily Wells"
14
+ mp3.should have_been_told_to(:play).with(/emily/i)
15
+ mp3.should_not have_been_told_to(:play).with(/emily/)
16
+
17
+ mp3.play /regex/
18
+ mp3.should have_been_told_to(:play).with(/regex/)
19
+ mp3.should_not have_been_told_to(:play).with(/xeger/)
20
+ end
21
+ end
22
+
23
+ context 'when rspec-mocks is not loaded' do
24
+ it 'does straight #== comparisons on each argument' do
25
+ begin
26
+ Surrogate::RSpec.rspec_mocks_loaded = false
27
+
28
+ mp3.play "Emily Wells"
29
+ mp3.should_not have_been_told_to(:play).with(/emily/i)
30
+
31
+ mp3.play /regex/
32
+ mp3.should have_been_told_to(:play).with(/regex/)
33
+ mp3.should_not have_been_told_to(:play).with(/xeger/)
34
+ rescue Exception
35
+ Surrogate::RSpec.rspec_mocks_loaded = true
36
+ end
37
+ end
38
+ end
39
+ 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.3.2
4
+ version: 0.4.2
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-05-03 00:00:00.000000000 Z
12
+ date: 2012-05-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
16
- requirement: &70198239716160 !ruby/object:Gem::Requirement
16
+ requirement: &70344532950860 !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: *70198239716160
24
+ version_requirements: *70344532950860
25
25
  description: Framework to aid in handrolling mock/spy objects.
26
26
  email:
27
27
  - josh.cheek@gmail.com
@@ -51,6 +51,7 @@ files:
51
51
  - spec/rspec/have_been_initialized_with_spec.rb
52
52
  - spec/rspec/have_been_told_to_spec.rb
53
53
  - spec/rspec/messages_spec.rb
54
+ - spec/rspec/rspec_mocks_integration_spec.rb
54
55
  - spec/rspec/substitute_for_spec.rb
55
56
  - spec/spec_helper.rb
56
57
  - spec/unit/api_comparer_spec.rb
@@ -86,6 +87,7 @@ test_files:
86
87
  - spec/rspec/have_been_initialized_with_spec.rb
87
88
  - spec/rspec/have_been_told_to_spec.rb
88
89
  - spec/rspec/messages_spec.rb
90
+ - spec/rspec/rspec_mocks_integration_spec.rb
89
91
  - spec/rspec/substitute_for_spec.rb
90
92
  - spec/spec_helper.rb
91
93
  - spec/unit/api_comparer_spec.rb