Created
March 16, 2015 22:27
-
-
Save fledman/66b37c0a532617bc57e3 to your computer and use it in GitHub Desktop.
Mocha Callable Returns
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
=begin | |
Extends Mocha to support dynamic return values. | |
Now you can set the return value of your stub or | |
expectation to a proc; the proc is evaluated each | |
time the method is called. For example, you can | |
now do Foo.stubs(:when).returns(->{Time.now}) and | |
each call to Foo.when will return the current time. | |
Note that this behaviour is only available while inside | |
of a block passed to Mocha.with_callable_returns. | |
Otherwise, passing a proc to an expectation will | |
return the the proc itself, as it would any object. | |
Since we evaluate the proc each time the method is | |
called it can be slow; don't overuse this functionality. | |
This behavior is useful when used in metaprogramming. | |
Additionally, we can use this functionality to | |
create expectations that stub their results: | |
Mocha.with_callable_returns do | |
Customer.any_instance.stubs(:compute_foo).returns(->{ | |
Foo.new.tap{ |f| f.stubs(thing_1: 'a', thing_2: 'b') } | |
}) | |
end | |
foo = Customer.find(some_id).compute_foo | |
assert_equal foo.thing_1, 'a' | |
If we want we can remove the stub on Customer; doing so | |
does not change the stubs on the existing foo instance. | |
This may be useful for preventing code pollution. | |
Customer.any_instance.unstub(:compute_foo) | |
assert_equal foo.thing_2, 'b' | |
Finally, please note that the arity of your procs must | |
be zero e.g. they cannot expect any arguments. | |
=end | |
module Mocha | |
def self.callable_returns? | |
!!@callable_returns | |
end | |
def self.with_callable_returns | |
was = callable_returns? | |
@callable_returns = true | |
yield | |
ensure | |
@callable_returns = was | |
end | |
class SingleReturnValue | |
def is_callable? | |
@value.respond_to?(:call) && | |
@value.respond_to?(:arity) && @value.arity.zero? | |
end | |
end | |
module CallableReturnBuilder | |
def build(*values) | |
super.tap do |rets| | |
if Mocha.callable_returns? | |
rets.values.each do |val| | |
def val.evaluate | |
is_callable? ? @value.call : @value | |
end | |
end | |
end | |
end | |
end | |
end | |
ReturnValues.singleton_class.send(:prepend, CallableReturnBuilder) | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment