Reputation: 7172
I am extending a class to accept a DSL. The instance should always respond with a default value, but the code may change. The code below works fine when I call who_am_i
, which sets the i_am
method, but I can't figure out how to set a default method.
module Helper
def i_am
"Default code"
end
def who_am_i
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
def i_am
"This was executed in class: \#{self.class.to_s}"
end
EOS
end
end
class Test
extend Helper
end
t = Test.new
t.i_am
I can make this work by doing this:
class Test2
extend Helper
include Helper
end
t2 = Test2.new
t2.i_am
but this seems weird. Thoughts?
Upvotes: 2
Views: 1530
Reputation: 44685
You need to use included method/hook. It is being run every time given module is included into other class or module, with this class or module for a param. In your case you want:
module Helper
def i_am
"Default code"
end
def self.included mod
mod.extend ClassMethods
end
module ClassMethods
def who_am_i
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
def i_am
"This was executed in class: \#{self.class.to_s}"
end
EOS
end
end
end
class Tester
include Helper
end
Upvotes: 3
Reputation: 7172
Ah ha!
The answer is to use module.included() to cause it to extend the class. This way you can use "include Helper", and the "include" part will call "Helper.included" and that is passed the caller, and you use that to extend it!
reference: http://www.railstips.org/blog/archives/2009/05/15/include-vs-extend-in-ruby/
module Helper
def i_am
"Default code"
end
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def who_am_i
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
def i_am
"This was executed in class: \#{self.class.to_s}"
end
EOS
end
end
end
class Test
include Helper
end
Upvotes: 1