rspec-fire 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e86bfffbe18d293983737f7d60713a010565fd33
4
+ data.tar.gz: 544afff69dfe86663b90a805108e0ddcbfa74d75
5
+ SHA512:
6
+ metadata.gz: 509aaa64ac7fababd932c9aeae28b935702866eb58efc8232d248c7c399c2594931f71c8217efa38cdbf0e2639c81320d7d335c2a05aea593e7486bf32ad3646
7
+ data.tar.gz: f0d73156a6f2dc1429a84a3ef0148847cfc58c61e4bba52b8b96fa8f496df084b9549f414db69a5f079b8ad2ddfe325bd0008a1d022910ad1237305fa1c85fcb
data/HISTORY CHANGED
@@ -46,3 +46,7 @@
46
46
  * Support `expect` syntax.
47
47
  * Better naming in the API: `instance_double` and `class_double`. Deprecate
48
48
  `fire_double` and `fire_class_double`.
49
+
50
+ 1.3.0 - 7 November 2013
51
+ * Support for RSpec 3. When it is loaded, this library is now a no-op since
52
+ all the functionality (and more!) was ported.
data/README.md CHANGED
@@ -1,7 +1,8 @@
1
1
  rspec-fire
2
2
  ==========
3
3
 
4
- Making your test doubles more resilient.
4
+ Checks that stubbed methods on your test double exist, but still allow you to run in isolation
5
+ when you choose. A failure will be triggered if an invalid method is being stubbed.
5
6
 
6
7
  Once,
7
8
  a younger brother came to him,
@@ -72,7 +73,7 @@ Specify the class being doubled in your specs:
72
73
  describe User, '#suspend!' do
73
74
  it 'sends a notification' do
74
75
  # Only this one line differs from how you write specs normally
75
- notifier = fire_double("EmailNotifier")
76
+ notifier = instance_double("EmailNotifier")
76
77
 
77
78
  notifier.should_receive(:notify).with("suspended as")
78
79
 
@@ -117,7 +118,7 @@ A workaround is to explicitly define the methods you are mocking:
117
118
  ### Doubling constants
118
119
 
119
120
  A particularly excellent feature. You can stub out constants using
120
- `fire_replaced_class_double`, removing the need to dependency inject
121
+ `class_double`, removing the need to dependency inject
121
122
  collaborators (a technique that can sometimes be cumbersome).
122
123
 
123
124
  class User
@@ -129,10 +130,7 @@ collaborators (a technique that can sometimes be cumbersome).
129
130
  describe User, '#suspend!' do
130
131
  it 'sends a notification' do
131
132
  # Only this one line differs from how you write specs normally
132
- notifier = fire_replaced_class_double("EmailNotifier")
133
-
134
- # Alternately, you can use this fluent interface
135
- notifier = fire_class_double("EmailNotifier").as_replaced_constant
133
+ notifier = class_double("EmailNotifier").as_stubbed_const
136
134
 
137
135
  notifier.should_receive(:notify).with("suspended as")
138
136
 
@@ -146,7 +144,7 @@ name for it.
146
144
 
147
145
  ### Transferring nested constants to doubled constants
148
146
 
149
- When you use `fire_replaced_class_double` to replace a class or module
147
+ When you use `class_double` to replace a class or module
150
148
  that also acts as a namespace for other classes and constants, your
151
149
  access to these constants is cut off for the duration of the example
152
150
  (since the doubled constant does not automatically have all of the
@@ -159,23 +157,23 @@ to deal with this:
159
157
  end
160
158
 
161
159
  # once you do this, you can no longer access MyCoolGem::Widget in your example...
162
- fire_replaced_class_double("MyCoolGem")
160
+ class_double("MyCoolGem")
163
161
 
164
162
  # ...unless you tell rspec-fire to transfer all nested constants
165
- fire_class_double("MyCoolGem").as_replaced_constant(:transfer_nested_constants => true)
163
+ class_double("MyCoolGem").as_stubbed_const(:transfer_nested_constants => true)
166
164
 
167
165
  # ...or give it a list of constants to transfer
168
- fire_class_double("MyCoolGem").as_replaced_constant(:transfer_nested_constants => [:Widget])
166
+ class_double("MyCoolGem").as_stubbed_const(:transfer_nested_constants => [:Widget])
169
167
 
170
168
  ### Doubling class methods
171
169
 
172
- Particularly handy for `ActiveRecord` finders. Use `fire_class_double`. If you
170
+ Particularly handy for `ActiveRecord` finders. Use `class_double`. If you
173
171
  dig into the code, you'll find you can create subclasses of `FireDouble` to
174
172
  check for *any* set of methods.
175
173
 
176
174
  ### Preventing Typo'd Constant Names
177
175
 
178
- `fire_double("MyClas")` will not verify any mocked methods, even when
176
+ `instance_double("MyClas")` will not verify any mocked methods, even when
179
177
  `MyClass` is loaded, because of the typo in the constant name. There's
180
178
  an option to help prevent these sorts of fat-finger errors:
181
179
 
@@ -1,362 +1,11 @@
1
1
  require 'rspec/mocks'
2
2
  require 'rspec/expectations'
3
- require 'delegate'
4
3
 
5
- module RSpec
6
- module Fire
7
- class Configuration
8
- attr_accessor :verify_constant_names
9
- alias verify_constant_names? verify_constant_names
10
-
11
- def initialize
12
- self.verify_constant_names = false
13
- end
14
- end
15
-
16
- def self.configuration
17
- @configuration ||= Configuration.new
18
- end
19
-
20
- def self.configure
21
- yield configuration
22
- end
23
-
24
- Error = Class.new(StandardError)
25
- UndefinedConstantError = Class.new(Error)
26
-
27
- class SupportArityMatcher
28
- def initialize(arity)
29
- @arity = arity
30
- end
31
-
32
- attr_reader :arity, :method
33
-
34
- def matches?(method)
35
- @method = method
36
- min_arity <= arity && arity <= max_arity
37
- end
38
-
39
- def failure_message_for_should
40
- "Wrong number of arguments for #{method.name}. " +
41
- "Expected #{arity_description}, got #{arity}."
42
- end
43
-
44
- private
45
-
46
- INFINITY = 1/0.0
47
-
48
- if method(:method).respond_to?(:parameters)
49
- def max_arity
50
- params = method.parameters
51
- return INFINITY if params.any? { |(type, name)| type == :rest } # splat
52
- params.count { |(type, name)| type != :block }
53
- end
54
- else
55
- # On 1.8, Method#parameters does not exist.
56
- # There's no way to distinguish between default and splat args, so
57
- # there's no way to have it work correctly for both default and splat args,
58
- # as far as I can tell.
59
- # The best we can do is consider it INFINITY (to be tolerant of splat args).
60
- def max_arity
61
- method.arity < 0 ? INFINITY : method.arity
62
- end
63
- end
64
-
65
- def min_arity
66
- return method.arity if method.arity >= 0
67
- # ~ inverts the one's complement and gives us the number of required args
68
- ~method.arity
69
- end
70
-
71
- def arity_description
72
- return min_arity if min_arity == max_arity
73
- return "#{min_arity} or more" if max_arity == INFINITY
74
- "#{min_arity} to #{max_arity}"
75
- end
76
- end
77
-
78
- module RecursiveConstMethods
79
- # We only want to consider constants that are defined directly on a
80
- # particular module, and not include top-level/inherited constants.
81
- # Unfortunately, the constant API changed between 1.8 and 1.9, so
82
- # we need to conditionally define methods to ignore the top-level/inherited
83
- # constants.
84
- #
85
- # Given `class A; end`:
86
- #
87
- # On 1.8:
88
- # - A.const_get("Hash") # => ::Hash
89
- # - A.const_defined?("Hash") # => false
90
- # - Neither method accepts the extra `inherit` argument
91
- # On 1.9:
92
- # - A.const_get("Hash") # => ::Hash
93
- # - A.const_defined?("Hash") # => true
94
- # - A.const_get("Hash", false) # => raises NameError
95
- # - A.const_defined?("Hash", false) # => false
96
- if Module.method(:const_defined?).arity == 1
97
- def const_defined_on?(mod, const_name)
98
- mod.const_defined?(const_name)
99
- end
100
-
101
- def get_const_defined_on(mod, const_name)
102
- if const_defined_on?(mod, const_name)
103
- return mod.const_get(const_name)
104
- end
105
-
106
- raise NameError, "uninitialized constant #{mod.name}::#{const_name}"
107
- end
108
- else
109
- def const_defined_on?(mod, const_name)
110
- mod.const_defined?(const_name, false)
111
- end
112
-
113
- def get_const_defined_on(mod, const_name)
114
- mod.const_get(const_name, false)
115
- end
116
- end
117
-
118
- def recursive_const_get name
119
- name.split('::').inject(Object) {|klass,name| get_const_defined_on(klass, name) }
120
- end
121
-
122
- def recursive_const_defined? name
123
- !!name.split('::').inject(Object) {|klass,name|
124
- if klass && const_defined_on?(klass, name)
125
- get_const_defined_on(klass, name)
126
- end
127
- }
128
- end
129
- end
130
-
131
- class ShouldProxy < SimpleDelegator
132
- include RecursiveConstMethods
133
-
134
- AM = RSpec::Mocks::ArgumentMatchers
135
-
136
- def initialize(double, method_finder, backing)
137
- @double = double
138
- @method_finder = method_finder
139
- @backing = backing
140
- @sym = backing.respond_to?(:sym) ? @backing.sym : @backing.message
141
- super(backing)
142
- end
143
-
144
- def with(*args, &block)
145
- unless AM::AnyArgsMatcher === args.first
146
- expected_arity = if AM::NoArgsMatcher === args.first
147
- 0
148
- elsif args.length > 0
149
- args.length
150
- elsif block
151
- block.arity
152
- else
153
- raise ArgumentError.new("No arguments nor block given.")
154
- end
155
- ensure_arity(expected_arity)
156
- end
157
- __getobj__.with(*args, &block)
158
- end
159
-
160
- protected
161
-
162
- def expect(value)
163
- ::RSpec::Expectations::ExpectationTarget.new(value)
164
- end
165
-
166
- def ensure_arity(actual)
167
- @double.with_doubled_class do |klass|
168
- expect(klass.__send__(@method_finder, @sym)).to support_arity(actual)
169
- end
170
- end
171
-
172
- def support_arity(arity)
173
- SupportArityMatcher.new(arity)
174
- end
175
- end
176
-
177
- module FireDoublable
178
- include RecursiveConstMethods
179
-
180
- def should_receive(method_name)
181
- ensure_implemented(method_name)
182
- ShouldProxy.new(self, @__method_finder, super)
183
- end
184
-
185
- def should_not_receive(method_name)
186
- ensure_implemented(method_name)
187
- super
188
- end
189
-
190
- def stub(method_name)
191
- ensure_implemented(method_name) unless method_name.is_a?(Hash)
192
- super
193
- end
194
-
195
- def stub!(method_name)
196
- stub(method_name)
197
- end
198
-
199
- def with_doubled_class
200
- ::RSpec::Fire.find_original_value_for(@__doubled_class_name) do |value|
201
- yield value if value
202
- return
203
- end
204
-
205
- if recursive_const_defined?(@__doubled_class_name)
206
- yield recursive_const_get(@__doubled_class_name)
207
- end
208
- end
209
-
210
- protected
211
-
212
- # This cache gives a decent speed up when a class is doubled a lot.
213
- def implemented_methods(doubled_class, checked_methods)
214
- @@_implemented_methods_cache ||= {}
215
-
216
- # to_sym for non-1.9 compat
217
- @@_implemented_methods_cache[[doubled_class, checked_methods]] ||=
218
- doubled_class.__send__(checked_methods).map(&:to_sym)
219
- end
220
-
221
- def unimplemented_methods(doubled_class, expected_methods, checked_methods)
222
- expected_methods.map(&:to_sym) -
223
- implemented_methods(doubled_class, checked_methods)
224
- end
225
-
226
- def ensure_implemented(*method_names)
227
- with_doubled_class do |doubled_class|
228
- methods = unimplemented_methods(
229
- doubled_class,
230
- method_names,
231
- @__checked_methods
232
- )
233
-
234
- if methods.any?
235
- implemented_methods =
236
- Object.public_methods -
237
- implemented_methods(doubled_class, @__checked_methods)
238
-
239
- msg = "%s does not implement:\n%s" % [
240
- doubled_class,
241
- methods.sort.map {|x|
242
- " #{x}"
243
- }.join("\n")
244
-
245
- ]
246
- raise RSpec::Expectations::ExpectationNotMetError, msg
247
- end
248
- end
249
- end
250
-
251
- def verify_constant_name
252
- return if recursive_const_defined?(@__doubled_class_name)
253
-
254
- raise UndefinedConstantError, "#{@__doubled_class_name} is not a defined constant."
255
- end
256
- end
257
-
258
- class FireObjectDouble < RSpec::Mocks::Mock
259
- include FireDoublable
260
-
261
- def initialize(doubled_class, *args)
262
- args << {} unless Hash === args.last
263
-
264
- @__doubled_class_name = doubled_class
265
- verify_constant_name if RSpec::Fire.configuration.verify_constant_names?
266
-
267
- # __declared_as copied from rspec/mocks definition of `double`
268
- args.last[:__declared_as] = 'FireDouble'
269
-
270
- @__checked_methods = :public_instance_methods
271
- @__method_finder = :instance_method
272
-
273
- super
274
- end
275
- end
276
-
277
- class FireClassDouble < Module
278
- include FireDoublable
279
-
280
- def initialize(doubled_class, stubs = {})
281
- @__doubled_class_name = doubled_class
282
- @__checked_methods = :public_methods
283
- @__method_finder = :method
284
-
285
- verify_constant_name if RSpec::Fire.configuration.verify_constant_names?
286
-
287
- ::RSpec::Mocks::TestDouble.extend_onto self,
288
- doubled_class, stubs.merge(:__declared_as => "FireClassDouble")
289
-
290
- # This needs to come after `::RSpec::Mocks::TestDouble.extend_onto`
291
- # so that it gets precedence...
292
- extend StringRepresentations
293
- end
294
-
295
- def as_stubbed_const(options = {})
296
- RSpec::Mocks::ConstantStubber.stub(@__doubled_class_name, self, options)
297
- @__original_class = RSpec::Mocks::Constant.original(@__doubled_class_name).original_value
298
-
299
- extend AsReplacedConstant
300
- self
301
- end
302
-
303
- def as_replaced_constant(*args)
304
- RSpec::Fire::DEPRECATED["as_replaced_constant is deprecated, use as_stubbed_const instead."]
305
- as_stubbed_const(*args)
306
- end
307
-
308
- def name
309
- @__doubled_class_name
310
- end
311
-
312
- module StringRepresentations
313
- def to_s
314
- @__doubled_class_name + " (fire double)"
315
- end
316
-
317
- def inspect
318
- to_s
319
- end
320
- end
321
-
322
- module AsReplacedConstant
323
- def with_doubled_class
324
- yield @__original_class if @__original_class
325
- end
326
- end
327
- end
328
-
329
- def self.find_original_value_for(constant_name)
330
- const = ::RSpec::Mocks::Constant.original(constant_name)
331
- yield const.original_value if const.stubbed?
332
- end
333
-
334
- def instance_double(*args)
335
- FireObjectDouble.new(*args)
336
- end
337
-
338
- def class_double(*args)
339
- FireClassDouble.new(*args)
340
- end
341
-
342
- def fire_double(*args)
343
- DEPRECATED["fire_double is deprecated, use instance_double instead."]
344
- instance_double(*args)
345
- end
346
-
347
- def fire_class_double(*args)
348
- DEPRECATED["fire_class_double is deprecated, use class_double instead."]
349
- class_double(*args)
350
- end
351
-
352
- def fire_replaced_class_double(*args)
353
- DEPRECATED["fire_replaced_class_double is deprecated, use class_double with as_stubbed_const instead."]
354
- class_double(*args).as_stubbed_const
355
- end
356
-
357
- DEPRECATED = lambda do |msg|
358
- Kernel.warn caller[2] + ": " + msg
359
- end
360
-
361
- end
4
+ if RSpec::Mocks::Version::STRING.to_f >= 3
5
+ warn "rspec-fire functionality is now provided by rspec-mocks and is " +
6
+ "no longer required. You can remove it from your dependencies."
7
+ else
8
+ require 'rspec/fire/legacy'
362
9
  end
10
+
11
+ require 'rspec/fire/configuration'
@@ -0,0 +1,20 @@
1
+ module RSpec
2
+ module Fire
3
+ class Configuration
4
+ attr_accessor :verify_constant_names
5
+ alias verify_constant_names? verify_constant_names
6
+
7
+ def initialize
8
+ self.verify_constant_names = false
9
+ end
10
+ end
11
+
12
+ def self.configuration
13
+ @configuration ||= Configuration.new
14
+ end
15
+
16
+ def self.configure
17
+ yield configuration
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,343 @@
1
+ require 'delegate'
2
+
3
+ module RSpec
4
+ module Fire
5
+ Error = Class.new(StandardError)
6
+ UndefinedConstantError = Class.new(Error)
7
+
8
+ class SupportArityMatcher
9
+ def initialize(arity)
10
+ @arity = arity
11
+ end
12
+
13
+ attr_reader :arity, :method
14
+
15
+ def matches?(method)
16
+ @method = method
17
+ min_arity <= arity && arity <= max_arity
18
+ end
19
+
20
+ def failure_message_for_should
21
+ "Wrong number of arguments for #{method.name}. " +
22
+ "Expected #{arity_description}, got #{arity}."
23
+ end
24
+
25
+ private
26
+
27
+ INFINITY = 1/0.0
28
+
29
+ if method(:method).respond_to?(:parameters)
30
+ def max_arity
31
+ params = method.parameters
32
+ return INFINITY if params.any? { |(type, name)| type == :rest } # splat
33
+ params.count { |(type, name)| type != :block }
34
+ end
35
+ else
36
+ # On 1.8, Method#parameters does not exist.
37
+ # There's no way to distinguish between default and splat args, so
38
+ # there's no way to have it work correctly for both default and splat args,
39
+ # as far as I can tell.
40
+ # The best we can do is consider it INFINITY (to be tolerant of splat args).
41
+ def max_arity
42
+ method.arity < 0 ? INFINITY : method.arity
43
+ end
44
+ end
45
+
46
+ def min_arity
47
+ return method.arity if method.arity >= 0
48
+ # ~ inverts the one's complement and gives us the number of required args
49
+ ~method.arity
50
+ end
51
+
52
+ def arity_description
53
+ return min_arity if min_arity == max_arity
54
+ return "#{min_arity} or more" if max_arity == INFINITY
55
+ "#{min_arity} to #{max_arity}"
56
+ end
57
+ end
58
+
59
+ module RecursiveConstMethods
60
+ # We only want to consider constants that are defined directly on a
61
+ # particular module, and not include top-level/inherited constants.
62
+ # Unfortunately, the constant API changed between 1.8 and 1.9, so
63
+ # we need to conditionally define methods to ignore the top-level/inherited
64
+ # constants.
65
+ #
66
+ # Given `class A; end`:
67
+ #
68
+ # On 1.8:
69
+ # - A.const_get("Hash") # => ::Hash
70
+ # - A.const_defined?("Hash") # => false
71
+ # - Neither method accepts the extra `inherit` argument
72
+ # On 1.9:
73
+ # - A.const_get("Hash") # => ::Hash
74
+ # - A.const_defined?("Hash") # => true
75
+ # - A.const_get("Hash", false) # => raises NameError
76
+ # - A.const_defined?("Hash", false) # => false
77
+ if Module.method(:const_defined?).arity == 1
78
+ def const_defined_on?(mod, const_name)
79
+ mod.const_defined?(const_name)
80
+ end
81
+
82
+ def get_const_defined_on(mod, const_name)
83
+ if const_defined_on?(mod, const_name)
84
+ return mod.const_get(const_name)
85
+ end
86
+
87
+ raise NameError, "uninitialized constant #{mod.name}::#{const_name}"
88
+ end
89
+ else
90
+ def const_defined_on?(mod, const_name)
91
+ mod.const_defined?(const_name, false)
92
+ end
93
+
94
+ def get_const_defined_on(mod, const_name)
95
+ mod.const_get(const_name, false)
96
+ end
97
+ end
98
+
99
+ def recursive_const_get name
100
+ name.split('::').inject(Object) {|klass,name| get_const_defined_on(klass, name) }
101
+ end
102
+
103
+ def recursive_const_defined? name
104
+ !!name.split('::').inject(Object) {|klass,name|
105
+ if klass && const_defined_on?(klass, name)
106
+ get_const_defined_on(klass, name)
107
+ end
108
+ }
109
+ end
110
+ end
111
+
112
+ class ShouldProxy < SimpleDelegator
113
+ include RecursiveConstMethods
114
+
115
+ AM = RSpec::Mocks::ArgumentMatchers
116
+
117
+ def initialize(double, method_finder, backing)
118
+ @double = double
119
+ @method_finder = method_finder
120
+ @backing = backing
121
+ @sym = backing.respond_to?(:sym) ? @backing.sym : @backing.message
122
+ super(backing)
123
+ end
124
+
125
+ def with(*args, &block)
126
+ unless AM::AnyArgsMatcher === args.first
127
+ expected_arity = if AM::NoArgsMatcher === args.first
128
+ 0
129
+ elsif args.length > 0
130
+ args.length
131
+ elsif block
132
+ block.arity
133
+ else
134
+ raise ArgumentError.new("No arguments nor block given.")
135
+ end
136
+ ensure_arity(expected_arity)
137
+ end
138
+ __getobj__.with(*args, &block)
139
+ end
140
+
141
+ protected
142
+
143
+ def expect(value)
144
+ ::RSpec::Expectations::ExpectationTarget.new(value)
145
+ end
146
+
147
+ def ensure_arity(actual)
148
+ @double.with_doubled_class do |klass|
149
+ expect(klass.__send__(@method_finder, @sym)).to support_arity(actual)
150
+ end
151
+ end
152
+
153
+ def support_arity(arity)
154
+ SupportArityMatcher.new(arity)
155
+ end
156
+ end
157
+
158
+ module FireDoublable
159
+ include RecursiveConstMethods
160
+
161
+ def should_receive(method_name)
162
+ ensure_implemented(method_name)
163
+ ShouldProxy.new(self, @__method_finder, super)
164
+ end
165
+
166
+ def should_not_receive(method_name)
167
+ ensure_implemented(method_name)
168
+ super
169
+ end
170
+
171
+ def stub(method_name)
172
+ ensure_implemented(method_name) unless method_name.is_a?(Hash)
173
+ super
174
+ end
175
+
176
+ def stub!(method_name)
177
+ stub(method_name)
178
+ end
179
+
180
+ def with_doubled_class
181
+ ::RSpec::Fire.find_original_value_for(@__doubled_class_name) do |value|
182
+ yield value if value
183
+ return
184
+ end
185
+
186
+ if recursive_const_defined?(@__doubled_class_name)
187
+ yield recursive_const_get(@__doubled_class_name)
188
+ end
189
+ end
190
+
191
+ protected
192
+
193
+ # This cache gives a decent speed up when a class is doubled a lot.
194
+ def implemented_methods(doubled_class, checked_methods)
195
+ @@_implemented_methods_cache ||= {}
196
+
197
+ # to_sym for non-1.9 compat
198
+ @@_implemented_methods_cache[[doubled_class, checked_methods]] ||=
199
+ doubled_class.__send__(checked_methods).map(&:to_sym)
200
+ end
201
+
202
+ def unimplemented_methods(doubled_class, expected_methods, checked_methods)
203
+ expected_methods.map(&:to_sym) -
204
+ implemented_methods(doubled_class, checked_methods)
205
+ end
206
+
207
+ def ensure_implemented(*method_names)
208
+ with_doubled_class do |doubled_class|
209
+ methods = unimplemented_methods(
210
+ doubled_class,
211
+ method_names,
212
+ @__checked_methods
213
+ )
214
+
215
+ if methods.any?
216
+ implemented_methods =
217
+ Object.public_methods -
218
+ implemented_methods(doubled_class, @__checked_methods)
219
+
220
+ msg = "%s does not implement:\n%s" % [
221
+ doubled_class,
222
+ methods.sort.map {|x|
223
+ " #{x}"
224
+ }.join("\n")
225
+
226
+ ]
227
+ raise RSpec::Expectations::ExpectationNotMetError, msg
228
+ end
229
+ end
230
+ end
231
+
232
+ def verify_constant_name
233
+ return if recursive_const_defined?(@__doubled_class_name)
234
+
235
+ raise UndefinedConstantError, "#{@__doubled_class_name} is not a defined constant."
236
+ end
237
+ end
238
+
239
+ class FireObjectDouble < RSpec::Mocks::Mock
240
+ include FireDoublable
241
+
242
+ def initialize(doubled_class, *args)
243
+ args << {} unless Hash === args.last
244
+
245
+ @__doubled_class_name = doubled_class
246
+ verify_constant_name if RSpec::Fire.configuration.verify_constant_names?
247
+
248
+ # __declared_as copied from rspec/mocks definition of `double`
249
+ args.last[:__declared_as] = 'FireDouble'
250
+
251
+ @__checked_methods = :public_instance_methods
252
+ @__method_finder = :instance_method
253
+
254
+ super
255
+ end
256
+ end
257
+
258
+ class FireClassDouble < Module
259
+ include FireDoublable
260
+
261
+ def initialize(doubled_class, stubs = {})
262
+ @__doubled_class_name = doubled_class
263
+ @__checked_methods = :public_methods
264
+ @__method_finder = :method
265
+
266
+ verify_constant_name if RSpec::Fire.configuration.verify_constant_names?
267
+
268
+ ::RSpec::Mocks::TestDouble.extend_onto self,
269
+ doubled_class, stubs.merge(:__declared_as => "FireClassDouble")
270
+
271
+ # This needs to come after `::RSpec::Mocks::TestDouble.extend_onto`
272
+ # so that it gets precedence...
273
+ extend StringRepresentations
274
+ end
275
+
276
+ def as_stubbed_const(options = {})
277
+ RSpec::Mocks::ConstantStubber.stub(@__doubled_class_name, self, options)
278
+ @__original_class = RSpec::Mocks::Constant.original(@__doubled_class_name).original_value
279
+
280
+ extend AsReplacedConstant
281
+ self
282
+ end
283
+
284
+ def as_replaced_constant(*args)
285
+ RSpec::Fire::DEPRECATED["as_replaced_constant is deprecated, use as_stubbed_const instead."]
286
+ as_stubbed_const(*args)
287
+ end
288
+
289
+ def name
290
+ @__doubled_class_name
291
+ end
292
+
293
+ module StringRepresentations
294
+ def to_s
295
+ @__doubled_class_name + " (fire double)"
296
+ end
297
+
298
+ def inspect
299
+ to_s
300
+ end
301
+ end
302
+
303
+ module AsReplacedConstant
304
+ def with_doubled_class
305
+ yield @__original_class if @__original_class
306
+ end
307
+ end
308
+ end
309
+
310
+ def self.find_original_value_for(constant_name)
311
+ const = ::RSpec::Mocks::Constant.original(constant_name)
312
+ yield const.original_value if const.stubbed?
313
+ end
314
+
315
+ def instance_double(*args)
316
+ FireObjectDouble.new(*args)
317
+ end
318
+
319
+ def class_double(*args)
320
+ FireClassDouble.new(*args)
321
+ end
322
+
323
+ def fire_double(*args)
324
+ DEPRECATED["fire_double is deprecated, use instance_double instead."]
325
+ instance_double(*args)
326
+ end
327
+
328
+ def fire_class_double(*args)
329
+ DEPRECATED["fire_class_double is deprecated, use class_double instead."]
330
+ class_double(*args)
331
+ end
332
+
333
+ def fire_replaced_class_double(*args)
334
+ DEPRECATED["fire_replaced_class_double is deprecated, use class_double with as_stubbed_const instead."]
335
+ class_double(*args).as_stubbed_const
336
+ end
337
+
338
+ DEPRECATED = lambda do |msg|
339
+ Kernel.warn caller[2] + ": " + msg
340
+ end
341
+
342
+ end
343
+ end
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'rspec-fire'
3
- s.version = '1.2.0'
3
+ s.version = '1.3.0'
4
4
  s.summary = 'More resilient test doubles for RSpec.'
5
5
  s.platform = Gem::Platform::RUBY
6
6
  s.authors = ["Xavier Shay"]
@@ -19,6 +19,6 @@ Gem::Specification.new do |s|
19
19
  rspec-fire.gemspec
20
20
  )
21
21
 
22
- s.add_dependency 'rspec', '~> 2.11'
22
+ s.add_dependency 'rspec', ['>= 2.11', '< 4']
23
23
  s.add_development_dependency 'rake'
24
24
  end
@@ -166,25 +166,6 @@ shared_examples_for 'a fire-enhanced double' do
166
166
  let(:method_under_test) { :should_not_receive }
167
167
  it_should_behave_like 'a fire-enhanced double method'
168
168
  end
169
-
170
- [ :stub, :stub! ].each do |stubber|
171
- describe "##{stubber}" do
172
- let(:method_under_test) { stubber }
173
- it_should_behave_like 'a fire-enhanced double method'
174
-
175
- context "RSpec's hash shortcut syntax" do
176
- context 'doubled class is not loaded' do
177
- let(:doubled_object) { instance_double("UnloadedObject") }
178
- should_allow(:undefined_method => 123)
179
- end
180
-
181
- context 'doubled class is loaded' do
182
- should_allow(:defined_method => 456)
183
- should_not_allow(:undefined_method => 789)
184
- end
185
- end
186
- end
187
- end
188
169
  end
189
170
 
190
171
  describe '#instance_double' do
metadata CHANGED
@@ -1,46 +1,47 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-fire
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
5
- prerelease:
4
+ version: 1.3.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Xavier Shay
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-06-03 00:00:00.000000000 Z
11
+ date: 2013-11-07 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: rspec
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ~>
17
+ - - '>='
20
18
  - !ruby/object:Gem::Version
21
19
  version: '2.11'
20
+ - - <
21
+ - !ruby/object:Gem::Version
22
+ version: '4'
22
23
  type: :runtime
23
24
  prerelease: false
24
25
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
26
  requirements:
27
- - - ~>
27
+ - - '>='
28
28
  - !ruby/object:Gem::Version
29
29
  version: '2.11'
30
+ - - <
31
+ - !ruby/object:Gem::Version
32
+ version: '4'
30
33
  - !ruby/object:Gem::Dependency
31
34
  name: rake
32
35
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
36
  requirements:
35
- - - ! '>='
37
+ - - '>='
36
38
  - !ruby/object:Gem::Version
37
39
  version: '0'
38
40
  type: :development
39
41
  prerelease: false
40
42
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
43
  requirements:
43
- - - ! '>='
44
+ - - '>='
44
45
  - !ruby/object:Gem::Version
45
46
  version: '0'
46
47
  description:
@@ -52,6 +53,8 @@ extra_rdoc_files: []
52
53
  files:
53
54
  - spec/fire_double_spec.rb
54
55
  - spec/spec_helper.rb
56
+ - lib/rspec/fire/configuration.rb
57
+ - lib/rspec/fire/legacy.rb
55
58
  - lib/rspec/fire.rb
56
59
  - Gemfile
57
60
  - README.md
@@ -61,26 +64,26 @@ files:
61
64
  homepage: http://github.com/xaviershay/rspec-fire
62
65
  licenses:
63
66
  - MIT
67
+ metadata: {}
64
68
  post_install_message:
65
69
  rdoc_options: []
66
70
  require_paths:
67
71
  - lib
68
72
  required_ruby_version: !ruby/object:Gem::Requirement
69
- none: false
70
73
  requirements:
71
- - - ! '>='
74
+ - - '>='
72
75
  - !ruby/object:Gem::Version
73
76
  version: '0'
74
77
  required_rubygems_version: !ruby/object:Gem::Requirement
75
- none: false
76
78
  requirements:
77
- - - ! '>='
79
+ - - '>='
78
80
  - !ruby/object:Gem::Version
79
81
  version: '0'
80
82
  requirements: []
81
83
  rubyforge_project:
82
- rubygems_version: 1.8.23
84
+ rubygems_version: 2.0.3
83
85
  signing_key:
84
- specification_version: 3
86
+ specification_version: 4
85
87
  summary: More resilient test doubles for RSpec.
86
88
  test_files: []
89
+ has_rdoc: false