If you find yourself doing some meta-programming in ruby with module_eval (aka class_eval), you may want to take heed of this gotcha if you exercise string interpolation inside the evaluated block. This was tested on versions 1.8.7, 1.9.1 and 1.9.2.
Example
module Foo module_eval(<<-EVAL, __FILE__, __LINE__) def greet(name = nil) "Hello #{name}" end EVAL end class Bar include Foo end b = Bar.new puts b.greet("Willy") #=> produces "Hello Foo"
You get "Foo", because the code block with string interpolation in it, actually gets executed to create the following code:
def greet(name = nil) "Hello Foo" end
There are two ways to get around this gotcha. Concatenate or correctly escape string interpolation inside the eval block
With string concatenation...
module Foo module_eval(<<-EVAL, __FILE__, __LINE__) def greet(name = nil) "Hello " + name end EVAL end class Bar include Foo end b = Bar.new puts b.greet("Willy") #=> produces "Hello Willy"
Significant or not, there is always a performance penalty to pay with concatenation instead of interpolation. So the ideal fix for this error with interpolation will be as follows below.
Correctly escaping string interpolation...
module Foo module_eval(<<-EVAL, __FILE__, __LINE__) def greet(name = nil) "Hello \#{name}" end EVAL end class Bar include Foo end b = Bar.new puts b.greet("Willy") #=> produces "Hello Willy"
The key being escaping the interpolation with "\", so the string interpolation gets executed during runtime not creation time. The code generated looking like this:
def greet(name = nil) "Hello #{name}" end