Permalink
Browse files

Move `stub_chain` functionality out of `RSpec::Mocks::Methods`

...while maintaining the same API.

This allows us to remove the `format_chain` method from every object and
begins to prepare us for the future addition of a new expect-based syntax
to rspec-mocks (#153).
  • Loading branch information...
1 parent 512bbbf commit 14617943d371aa8992f08bad0cc654f390e62e6f @myronmarston myronmarston committed Mar 18, 2013
Showing with 55 additions and 25 deletions.
  1. +2 −0 lib/rspec/mocks/framework.rb
  2. +1 −24 lib/rspec/mocks/methods.rb
  3. +51 −0 lib/rspec/mocks/stub_chain.rb
  4. +1 −1 spec/rspec/mocks/methods_spec.rb
@@ -20,3 +20,5 @@
require 'rspec/mocks/serialization'
require 'rspec/mocks/any_instance'
require 'rspec/mocks/mutate_const'
+require 'rspec/mocks/stub_chain'
+
View
@@ -85,19 +85,7 @@ def unstub!(message)
# # Common use in Rails/ActiveRecord:
# Article.stub_chain("recent.published") { [Article.new] }
def stub_chain(*chain, &blk)
- chain, blk = format_chain(*chain, &blk)
- if chain.length > 1
- if matching_stub = __mock_proxy.__send__(:find_matching_method_stub, chain[0].to_sym)
- chain.shift
- matching_stub.invoke(nil).stub_chain(*chain, &blk)
- else
- next_in_chain = Mock.new
- stub(chain.shift) { next_in_chain }
- next_in_chain.stub_chain(*chain, &blk)
- end
- else
- stub(chain.shift, &blk)
- end
+ StubChain.stub_chain_on(self, *chain, &blk)
end
# Tells the object to respond to all messages. If specific stub values
@@ -146,17 +134,6 @@ def __mock_proxy
def __remove_mock_proxy
@mock_proxy = nil
end
-
- def format_chain(*chain, &blk)
- if Hash === chain.last
- hash = chain.pop
- hash.each do |k,v|
- chain << k
- blk = lambda { v }
- end
- end
- return chain.join('.').split('.'), blk
- end
end
end
end
@@ -0,0 +1,51 @@
+module RSpec
+ module Mocks
+ # @private
+ class StubChain
+ def self.stub_chain_on(object, *chain, &blk)
+ new(object, *chain, &blk).stub_chain
+ end
+
+ attr_reader :object, :chain, :block
+
+ def initialize(object, *chain, &blk)
+ @object = object
+ @chain, @block = format_chain(*chain, &blk)
+ end
+
+ def stub_chain
+ if chain.length > 1
+ if matching_stub = find_matching_stub
+ chain.shift
+ matching_stub.invoke(nil).stub_chain(*chain, &block)
+ else
+ next_in_chain = Mock.new
+ object.stub(chain.shift) { next_in_chain }
+ StubChain.stub_chain_on(next_in_chain, *chain, &block)
+ end
+ else
+ object.stub(chain.shift, &block)
+ end
+ end
+
+ private
+
+ def format_chain(*chain, &blk)
+ if Hash === chain.last
+ hash = chain.pop
+ hash.each do |k,v|
+ chain << k
+ blk = lambda { v }
+ end
+ end
+ return chain.join('.').split('.'), blk
+ end
+
+ def find_matching_stub
+ object.__send__(:__mock_proxy).
+ __send__(:find_matching_method_stub, chain.first.to_sym)
+ end
+ end
+ end
+end
+
@@ -15,7 +15,7 @@ def methods_added_to_all_objects
# we are hoping to cut down on the number of methods added to all objects
expect(methods_added_to_all_objects).to match_array([
:__mock_proxy, :__remove_mock_proxy, :as_null_object,
- :format_chain, :null_object?, :received_message?,
+ :null_object?, :received_message?,
:rspec_reset, :rspec_verify, :should_not_receive,
:should_receive, :stub, :stub!,
:stub_chain, :unstub, :unstub!

0 comments on commit 1461794

Please sign in to comment.