Expectations do

expect 1 do

Object . expects ( : something ) . returns 1

Object . something

end

end



There's no (reasonable) way to extend all instances with a new module since the expects method is defined on Object.

method is defined on Object. I didn't want to unconditionally redefine the expects method. Within the framework I call Object#expects, and I don't want those calls to cause invalid warnings. I need a solution that prints a warning when you use Object#expects within an expectation block, but does not print a warning if Object#expects is called from anywhere else.

class Object

def say_hello

" hello "

end

end

say_hello

in_english do

say_hello end



in_spanish do

say_hello end



class Object

def say_hello

" hello "

end

end



class Object

def in_english ( & block )

instance_eval ( & block )

end



def in_spanish ( & block )

instance_eval ( & block )

end

end



in_english do

say_hello end



in_spanish do

say_hello end



say_hello

say_hello

class Object

def say_hello

" hello "

end

end



class Object

module InSpanish

def say_hello

" hola "

end

end

include InSpanish



remove_method : say_hello



def in_english ( & block )

instance_eval ( & block )

end



def in_spanish ( & block )

instance_eval ( & block )

end

end



in_english do

say_hello end



in_spanish do

say_hello end

in_english

class Object

def say_hello

" hello "

end

end



class Object

module InSpanish

def say_hello

" hola "

end

end

include InSpanish



module InEnglish

expects_method = Object . instance_method ( : say_hello )

define_method : say_hello do | * args |

expects_method . bind ( self ) . call ( * args )

end

end

include InEnglish



remove_method : say_hello



def in_english ( & block )

instance_eval ( & block )

end



def in_spanish ( & block )

instance_eval ( & block )

end

end



in_english do

say_hello end



in_spanish do

say_hello end

say_hello

say_hello

class Object

def say_hello

" hello "

end

end



class Object

module InSpanish

def say_hello

" hola "

end

end

include InSpanish



module InEnglish

expects_method = Object . instance_method ( : say_hello )

define_method : say_hello do | * args |

expects_method . bind ( self ) . call ( * args )

end

end

include InEnglish



def say_hello

( @ language || InEnglish ) . instance_method ( : say_hello ) . bind ( self ) . call

end



def in_english ( & block )

@ language = InEnglish

instance_eval ( & block )

end



def in_spanish ( & block )

@ language = InSpanish

instance_eval ( & block )

end

end



in_english do

say_hello end



in_spanish do

say_hello end

@language

say_hello

I was recently working on the integration between Mocha and expectations . Expectations promotes the idea that you should only have one expectation per test ; therefore, I wanted to display a warning if you call Object#expects within an expected block.For example, the following code will print a warning.Usually, I'd use one of the various Alternatives for Redefining Methods , but redefining the Object#expects method had two additional constraints that complicated matters.At first I attempted to solve this problem by aliasing methods and pointing to different method definitions based on the context in which the code was currently executing. This turned into a complicated mess, and also required me to define a few methods that could potentially collide with methods defined by applications using Expectations. After going down that path for a bit it became clear that it would be simpler to define modules and delegate the expects call to the appropriate module based on the context.The actual implementation involves several moving parts, so here's a much simpler example. Start with some behavior defined on Object. This behavior will have been defined by another framework so you cannot (easily) alter the original method definition.Next, you've decided to create a framework that says hello in Spanish also. You still want to be able to return "hello" when English is required, but you want themethod to return "hola" when you are expecting Spanish.Below is the output we are looking for.Currently our code returns "hello" both in English and Spanish.We can make themessage sent to Object return "hola" by removing themethod, defining an InSpanish module, and including the InSpanish module.Now we have Spanish working, but we've lost our English. Remember the actual implementation needed to preserve the original behavior in some circumstances. Themethod is our circumstance where we need to preserve original behavior. This can be done easily enough by Moving the say_hello definition from Object to an InEnglish module Now we have the original behavior of themethod, but we've lost our ability to speak Spanish.The final step is to define Object#say_hello in a way that delegates themessage to the appropriate module instead of removing the method.The final change was setting theinstance variable to the module who'smethod definition was required. As you can see from the printed output, our code works as desired.This isn't a technique that you'll use often, but it's a good trick to know when you need it. If you're interested in the actual application you can check out the expectations framework code