rspec-fire 0.5.0 → 1.0.0

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/Gemfile CHANGED
@@ -1,3 +1,4 @@
1
1
  source :rubygems
2
2
 
3
3
  gemspec
4
+
data/HISTORY CHANGED
@@ -24,3 +24,7 @@
24
24
  0.5.0 - 4 July 2012
25
25
  * Performance improvements, overhead is now roughly 10% down from 100%
26
26
  * Allow both instance and class doubles for unloaded classes.
27
+
28
+ 1.0.0 - 9 July 2012
29
+ * RSpec 2.11 compatibility, no longer compatible with earlier versions.
30
+ * Removed `stub_const`, it is now in `rspec-mocks`.
data/README.md CHANGED
@@ -144,25 +144,6 @@ collaborators (a technique that can sometimes be cumbersome).
144
144
  This will probably become the default behaviour once we figure out a better
145
145
  name for it.
146
146
 
147
- ### Stubbing Constants
148
-
149
- The constant stubbing logic used when doubling class constants can be
150
- used for any constant.
151
-
152
- class MapReduceRunner
153
- ITEMS_PER_BATCH = 1000
154
- end
155
-
156
- describe MapReduceRunner, "when it has too many items for one batch" do
157
- it "breaks the items up into smaller batches" do
158
- # the test would be really slow if we had to make more than 1000 items,
159
- # so let's change the threshold for this one test.
160
- stub_const("MapReduceRunner::ITEMS_PER_BATCH", 10)
161
-
162
- MapReduceRunner.run_with(twenty_items)
163
- end
164
- end
165
-
166
147
  ### Transferring nested constants to doubled constants
167
148
 
168
149
  When you use `fire_replaced_class_double` to replace a class or module
@@ -186,9 +167,6 @@ to deal with this:
186
167
  # ...or give it a list of constants to transfer
187
168
  fire_class_double("MyCoolGem").as_replaced_constant(:transfer_nested_constants => [:Widget])
188
169
 
189
- # You can also use this when using #stub_const directly
190
- stub_const("MyCoolGem", :transfer_nested_constants => true)
191
-
192
170
  ### Doubling class methods
193
171
 
194
172
  Particularly handy for `ActiveRecord` finders. Use `fire_class_double`. If you
@@ -207,7 +185,7 @@ refactor or use a non-isolated test.
207
185
  Compatibility
208
186
  -------------
209
187
 
210
- Only RSpec 2 is supported. Tested on all the rubies thanks to [Travis
188
+ Only RSpec 2.11+ is supported. Tested on all the rubies thanks to [Travis
211
189
  CI][build-link].
212
190
 
213
191
  [build-link]: http://travis-ci.org/xaviershay/rspec-fire
data/lib/rspec/fire.rb CHANGED
@@ -135,7 +135,7 @@ module RSpec
135
135
  end
136
136
 
137
137
  def with_doubled_class
138
- ConstantStubber.find_original_value_for(@__doubled_class_name) do |value|
138
+ ::RSpec::Fire.find_original_value_for(@__doubled_class_name) do |value|
139
139
  yield value if value
140
140
  return
141
141
  end
@@ -230,7 +230,9 @@ module RSpec
230
230
  end
231
231
 
232
232
  def self.as_replaced_constant(options = {})
233
- @__original_class = ConstantStubber.stub!(@__doubled_class_name, self, options)
233
+ RSpec::Mocks::ConstantStubber.stub(@__doubled_class_name, self, options)
234
+ @__original_class = RSpec::Mocks::Constant.original(@__doubled_class_name).original_value
235
+
234
236
  extend AsReplacedConstant
235
237
  self
236
238
  end
@@ -256,161 +258,9 @@ module RSpec
256
258
  end
257
259
  end
258
260
 
259
- class ConstantStubber
260
- extend RecursiveConstMethods
261
-
262
- class DefinedConstantReplacer
263
- include RecursiveConstMethods
264
- attr_reader :original_value, :full_constant_name
265
-
266
- def initialize(full_constant_name, stubbed_value, transfer_nested_constants)
267
- @full_constant_name = full_constant_name
268
- @stubbed_value = stubbed_value
269
- @transfer_nested_constants = transfer_nested_constants
270
- end
271
-
272
- def stub!
273
- context_parts = @full_constant_name.split('::')
274
- @const_name = context_parts.pop
275
- @context = recursive_const_get(context_parts.join('::'))
276
- @original_value = @context.const_get(@const_name)
277
-
278
- constants_to_transfer = verify_constants_to_transfer!
279
-
280
- @context.send(:remove_const, @const_name)
281
- @context.const_set(@const_name, @stubbed_value)
282
-
283
- transfer_nested_constants(constants_to_transfer)
284
- end
285
-
286
- def rspec_reset
287
- if recursive_const_get(@full_constant_name).equal?(@stubbed_value)
288
- @context.send(:remove_const, @const_name)
289
- @context.const_set(@const_name, @original_value)
290
- end
291
- end
292
-
293
- def transfer_nested_constants(constants)
294
- constants.each do |const|
295
- @stubbed_value.const_set(const, original_value.const_get(const))
296
- end
297
- end
298
-
299
- def verify_constants_to_transfer!
300
- return [] unless @transfer_nested_constants
301
-
302
- { @original_value => "the original value", @stubbed_value => "the stubbed value" }.each do |value, description|
303
- unless value.respond_to?(:constants)
304
- raise ArgumentError,
305
- "Cannot transfer nested constants for #{@full_constant_name} " +
306
- "since #{description} is not a class or module and only classes " +
307
- "and modules support nested constants."
308
- end
309
- end
310
-
311
- if @transfer_nested_constants.is_a?(Array)
312
- @transfer_nested_constants = @transfer_nested_constants.map(&:to_s) if RUBY_VERSION == '1.8.7'
313
- undefined_constants = @transfer_nested_constants - @original_value.constants
314
-
315
- if undefined_constants.any?
316
- available_constants = @original_value.constants - @transfer_nested_constants
317
- raise ArgumentError,
318
- "Cannot transfer nested constant(s) #{undefined_constants.join(' and ')} " +
319
- "for #{@full_constant_name} since they are not defined. Did you mean " +
320
- "#{available_constants.join(' or ')}?"
321
- end
322
-
323
- @transfer_nested_constants
324
- else
325
- @original_value.constants
326
- end
327
- end
328
- end
329
-
330
- class UndefinedConstantSetter
331
- include RecursiveConstMethods
332
-
333
- attr_reader :full_constant_name
334
-
335
- def initialize(full_constant_name, stubbed_value)
336
- @full_constant_name = full_constant_name
337
- @stubbed_value = stubbed_value
338
- end
339
-
340
- def original_value
341
- # always nil
342
- end
343
-
344
- def stub!
345
- context_parts = @full_constant_name.split('::')
346
- const_name = context_parts.pop
347
-
348
- remaining_parts = context_parts.dup
349
- @deepest_defined_const = context_parts.inject(Object) do |klass, name|
350
- break klass unless klass.const_defined?(name)
351
- remaining_parts.shift
352
- klass.const_get(name)
353
- end
354
-
355
- context = remaining_parts.inject(@deepest_defined_const) do |klass, name|
356
- klass.const_set(name, Module.new)
357
- end
358
-
359
- @const_to_remove = remaining_parts.first || const_name
360
- context.const_set(const_name, @stubbed_value)
361
- end
362
-
363
- def rspec_reset
364
- if recursive_const_get(@full_constant_name).equal?(@stubbed_value)
365
- @deepest_defined_const.send(:remove_const, @const_to_remove)
366
- end
367
- end
368
- end
369
-
370
- def self.stub!(constant_name, value, options = {})
371
- stubber = if recursive_const_defined?(constant_name)
372
- DefinedConstantReplacer.new(constant_name, value, options[:transfer_nested_constants])
373
- else
374
- UndefinedConstantSetter.new(constant_name, value)
375
- end
376
-
377
- stubbers << stubber
378
-
379
- stubber.stub!
380
- ensure_registered_with_rspec_mocks
381
- stubber.original_value
382
- end
383
-
384
- def self.ensure_registered_with_rspec_mocks
385
- return if @registered_with_rspec_mocks
386
- ::RSpec::Mocks.space.add(self)
387
- @registered_with_rspec_mocks = true
388
- end
389
-
390
- def self.rspec_reset
391
- @registered_with_rspec_mocks = false
392
-
393
- # We use reverse order so that if the same constant
394
- # was stubbed multiple times, the original value gets
395
- # properly restored.
396
- stubbers.reverse.each { |s| s.rspec_reset }
397
-
398
- stubbers.clear
399
- end
400
-
401
- def self.stubbers
402
- @stubbers ||= []
403
- end
404
-
405
- def self.find_original_value_for(constant_name)
406
- stubber = stubbers.find { |s| s.full_constant_name == constant_name }
407
- yield stubber.original_value if stubber
408
- self
409
- end
410
- end
411
-
412
- def stub_const(name, value, options = {})
413
- ConstantStubber.stub!(name, value, options)
261
+ def self.find_original_value_for(constant_name)
262
+ const = ::RSpec::Mocks::Constant.original(constant_name)
263
+ yield const.original_value if const.stubbed?
414
264
  end
415
265
 
416
266
  def fire_double(*args)
data/rspec-fire.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'rspec-fire'
3
- s.version = '0.5.0'
3
+ s.version = '1.0.0'
4
4
  s.summary = 'More resilient test doubles for RSpec.'
5
5
  s.platform = Gem::Platform::RUBY
6
6
  s.authors = ["Xavier Shay"]
@@ -18,6 +18,6 @@ Gem::Specification.new do |s|
18
18
  rspec-fire.gemspec
19
19
  )
20
20
 
21
+ s.add_dependency 'rspec', '~> 2.11'
21
22
  s.add_development_dependency 'rake'
22
- s.add_development_dependency 'rspec', '~> 2.5'
23
23
  end
@@ -3,8 +3,6 @@ require 'spec_helper'
3
3
  def use; end
4
4
  private :use
5
5
 
6
- TOP_LEVEL_VALUE_CONST = 7
7
-
8
6
  module TestMethods
9
7
  def defined_method
10
8
  raise "Y U NO MOCK?"
@@ -26,11 +24,6 @@ class TestClass
26
24
  M = :m
27
25
  N = :n
28
26
 
29
- class Nested
30
- class NestedEvenMore
31
- end
32
- end
33
-
34
27
  def self.use
35
28
  raise "Y U NO MOCK?"
36
29
  end
@@ -294,248 +287,6 @@ describe '#fire_replaced_class_double (for a non-existant class)' do
294
287
  end
295
288
  end
296
289
 
297
- shared_examples_for "loaded constant stubbing" do |const_name|
298
- include RSpec::Fire::RecursiveConstMethods
299
- let!(:original_const_value) { const }
300
- after { change_const_value_to(original_const_value) }
301
-
302
- define_method :const do
303
- recursive_const_get(const_name)
304
- end
305
-
306
- define_method :parent_const do
307
- recursive_const_get("Object::" + const_name.sub(/(::)?[^:]+\z/, ''))
308
- end
309
-
310
- define_method :last_const_part do
311
- const_name.split('::').last
312
- end
313
-
314
- def change_const_value_to(value)
315
- parent_const.send(:remove_const, last_const_part)
316
- parent_const.const_set(last_const_part, value)
317
- end
318
-
319
- it 'allows it to be stubbed' do
320
- const.should_not eq(7)
321
- stub_const(const_name, 7)
322
- const.should eq(7)
323
- end
324
-
325
- it 'resets it to its original value when rspec clears its mocks' do
326
- original_value = const
327
- original_value.should_not eq(:a)
328
- stub_const(const_name, :a)
329
- reset_rspec_mocks
330
- const.should be(original_value)
331
- end
332
-
333
- it 'does not reset the value to its original value when rspec clears its mocks if the example modifies the value of the constant' do
334
- stub_const(const_name, :a)
335
- change_const_value_to(new_const_value = Object.new)
336
- reset_rspec_mocks
337
- const.should be(new_const_value)
338
- end
339
-
340
- it 'returns the original value' do
341
- orig_value = const
342
- returned_value = stub_const(const_name, 7)
343
- returned_value.should be(orig_value)
344
- end
345
- end
346
-
347
- shared_examples_for "unloaded constant stubbing" do |const_name|
348
- include RSpec::Fire::RecursiveConstMethods
349
- before { recursive_const_defined?(const_name).should be_false }
350
-
351
- define_method :const do
352
- recursive_const_get(const_name)
353
- end
354
-
355
- define_method :parent_const do
356
- recursive_const_get("Object::" + const_name.sub(/(::)?[^:]+\z/, ''))
357
- end
358
-
359
- define_method :last_const_part do
360
- const_name.split('::').last
361
- end
362
-
363
- def change_const_value_to(value)
364
- parent_const.send(:remove_const, last_const_part)
365
- parent_const.const_set(last_const_part, value)
366
- end
367
-
368
- it 'allows it to be stubbed' do
369
- stub_const(const_name, 7)
370
- const.should eq(7)
371
- end
372
-
373
- it 'removes the constant when rspec clears its mocks' do
374
- stub_const(const_name, 7)
375
- reset_rspec_mocks
376
- recursive_const_defined?(const_name).should be_false
377
- end
378
-
379
- it 'does not remove the constant when the example manually sets it' do
380
- begin
381
- stub_const(const_name, 7)
382
- stubber = RSpec::Fire::ConstantStubber.stubbers.first
383
- change_const_value_to(new_const_value = Object.new)
384
- reset_rspec_mocks
385
- const.should equal(new_const_value)
386
- ensure
387
- change_const_value_to(7)
388
- stubber.rspec_reset
389
- end
390
- end
391
-
392
- it 'returns nil since it was not originally set' do
393
- stub_const(const_name, 7).should be_nil
394
- end
395
-
396
- it 'ignores the :transfer_nested_constants if passed' do
397
- stub = Module.new
398
- stub_const(const_name, stub, :transfer_nested_constants => true)
399
- stub.constants.should eq([])
400
- end
401
- end
402
-
403
- describe "#stub_const" do
404
- context 'for a loaded unnested constant' do
405
- it_behaves_like "loaded constant stubbing", "TestClass"
406
-
407
- it 'can be stubbed multiple times but still restores the original value properly' do
408
- orig_value = TestClass
409
- stub1, stub2 = Module.new, Module.new
410
- stub_const("TestClass", stub1)
411
- stub_const("TestClass", stub2)
412
-
413
- reset_rspec_mocks
414
- TestClass.should be(orig_value)
415
- end
416
-
417
- it 'allows nested constants to be transferred to a stub module' do
418
- tc_nested = TestClass::Nested
419
- stub = Module.new
420
- stub_const("TestClass", stub, :transfer_nested_constants => true)
421
- stub::M.should eq(:m)
422
- stub::N.should eq(:n)
423
- stub::Nested.should be(tc_nested)
424
- end
425
-
426
- it 'allows nested constants to be selectively transferred to a stub module' do
427
- stub = Module.new
428
- stub_const("TestClass", stub, :transfer_nested_constants => [:M, :N])
429
- stub::M.should eq(:m)
430
- stub::N.should eq(:n)
431
- defined?(stub::Nested).should be_false
432
- end
433
-
434
- it 'raises an error if asked to transfer nested constants but given an object that does not support them' do
435
- original_tc = TestClass
436
- stub = Object.new
437
- expect {
438
- stub_const("TestClass", stub, :transfer_nested_constants => true)
439
- }.to raise_error(ArgumentError)
440
-
441
- TestClass.should be(original_tc)
442
-
443
- expect {
444
- stub_const("TestClass", stub, :transfer_nested_constants => [:M])
445
- }.to raise_error(ArgumentError)
446
-
447
- TestClass.should be(original_tc)
448
- end
449
-
450
- it 'raises an error if asked to transfer nested constants on a constant that does not support nested constants' do
451
- stub = Module.new
452
- expect {
453
- stub_const("TOP_LEVEL_VALUE_CONST", stub, :transfer_nested_constants => true)
454
- }.to raise_error(ArgumentError)
455
-
456
- TOP_LEVEL_VALUE_CONST.should eq(7)
457
-
458
- expect {
459
- stub_const("TOP_LEVEL_VALUE_CONST", stub, :transfer_nested_constants => [:M])
460
- }.to raise_error(ArgumentError)
461
-
462
- TOP_LEVEL_VALUE_CONST.should eq(7)
463
- end
464
-
465
- it 'raises an error if asked to transfer a nested constant that is not defined' do
466
- original_tc = TestClass
467
- defined?(TestClass::V).should be_false
468
- stub = Module.new
469
-
470
- expect {
471
- stub_const("TestClass", stub, :transfer_nested_constants => [:V])
472
- }.to raise_error(/cannot transfer nested constant.*V/i)
473
-
474
- TestClass.should be(original_tc)
475
- end
476
- end
477
-
478
- context 'for a loaded nested constant' do
479
- it_behaves_like "loaded constant stubbing", "TestClass::Nested"
480
- end
481
-
482
- context 'for a loaded deeply nested constant' do
483
- it_behaves_like "loaded constant stubbing", "TestClass::Nested::NestedEvenMore"
484
- end
485
-
486
- context 'for an unloaded unnested constant' do
487
- it_behaves_like "unloaded constant stubbing", "X"
488
- end
489
-
490
- context 'for an unloaded nested constant' do
491
- it_behaves_like "unloaded constant stubbing", "X::Y"
492
-
493
- it 'removes the root constant when rspec clears its mocks' do
494
- defined?(X).should be_false
495
- stub_const("X::Y", 7)
496
- reset_rspec_mocks
497
- defined?(X).should be_false
498
- end
499
- end
500
-
501
- context 'for an unloaded deeply nested constant' do
502
- it_behaves_like "unloaded constant stubbing", "X::Y::Z"
503
-
504
- it 'removes the root constant when rspec clears its mocks' do
505
- defined?(X).should be_false
506
- stub_const("X::Y::Z", 7)
507
- reset_rspec_mocks
508
- defined?(X).should be_false
509
- end
510
- end
511
-
512
- context 'for an unloaded constant nested within a loaded constant' do
513
- it_behaves_like "unloaded constant stubbing", "TestClass::X"
514
-
515
- it 'removes the unloaded constant but leaves the loaded constant when rspec resets its mocks' do
516
- defined?(TestClass).should be_true
517
- defined?(TestClass::X).should be_false
518
- stub_const("TestClass::X", 7)
519
- reset_rspec_mocks
520
- defined?(TestClass).should be_true
521
- defined?(TestClass::X).should be_false
522
- end
523
- end
524
-
525
- context 'for an unloaded constant nested deeply within a deeply nested loaded constant' do
526
- it_behaves_like "unloaded constant stubbing", "TestClass::Nested::NestedEvenMore::X::Y::Z"
527
-
528
- it 'removes the first unloaded constant but leaves the loaded nested constant when rspec resets its mocks' do
529
- defined?(TestClass::Nested::NestedEvenMore).should be_true
530
- defined?(TestClass::Nested::NestedEvenMore::X).should be_false
531
- stub_const("TestClass::Nested::NestedEvenMore::X::Y::Z", 7)
532
- reset_rspec_mocks
533
- defined?(TestClass::Nested::NestedEvenMore).should be_true
534
- defined?(TestClass::Nested::NestedEvenMore::X).should be_false
535
- end
536
- end
537
- end
538
-
539
290
  describe RSpec::Fire::SupportArityMatcher do
540
291
  def support_arity(arity)
541
292
  RSpec::Fire::SupportArityMatcher.new(arity)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-fire
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 1.0.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,30 +9,30 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-07-04 00:00:00.000000000Z
12
+ date: 2012-07-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- name: rake
16
- requirement: &2159223000 !ruby/object:Gem::Requirement
15
+ name: rspec
16
+ requirement: &2156163500 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
- - - ! '>='
19
+ - - ~>
20
20
  - !ruby/object:Gem::Version
21
- version: '0'
22
- type: :development
21
+ version: '2.11'
22
+ type: :runtime
23
23
  prerelease: false
24
- version_requirements: *2159223000
24
+ version_requirements: *2156163500
25
25
  - !ruby/object:Gem::Dependency
26
- name: rspec
27
- requirement: &2159222320 !ruby/object:Gem::Requirement
26
+ name: rake
27
+ requirement: &2156162900 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
- - - ~>
30
+ - - ! '>='
31
31
  - !ruby/object:Gem::Version
32
- version: '2.5'
32
+ version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *2159222320
35
+ version_requirements: *2156162900
36
36
  description:
37
37
  email:
38
38
  - hello@xaviershay.com
@@ -68,7 +68,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
68
68
  version: '0'
69
69
  requirements: []
70
70
  rubyforge_project:
71
- rubygems_version: 1.8.10
71
+ rubygems_version: 1.8.6
72
72
  signing_key:
73
73
  specification_version: 3
74
74
  summary: More resilient test doubles for RSpec.