In Ruby 1.9.3 I need to create a few class instances which each have similar instance- and class-methods but which vary only by a few fixed parameters. The distinction of their class type is also important so I cannot simply use separate instances of the same class.
A simplified example looks like this.
module Animal
private
def self.make_animal(name, legs, noise)
klass = Class.new
klass.const_set(:NUM_LEGS, legs)
klass.class.send(:define_method, :scream) { noise.upcase + '!' }
Animal.const_set(name, klass)
end
make_animal :Tiger, 4, 'roar'
make_animal :Human, 2, 'derp'
end
This seems to work fine except that the variables used in the block which dynamically defines the “scream” method are bound at runtime of the “scream” method instead of runtime of the “make_animal” method.
Animal::Human::NUM_LEGS # => 2 -- ok
Animal::Tiger::NUM_LEGS # => 4 -- ok
Animal::Human.scream # => "DERP!" -- ok
Animal::Tiger.scream # => "DERP!" -- fail!
How can I modify the above code so that the Tiger screams "ROAR!"?
[Note] I really do need to maintain the goofy OO structure in the example for reasons that are too involved to describe here. I’m interested only in learning how to programmatically define class methods on dynamically defined classes with parameterized method implementations.
klass.classis the same in both cases (Class): all classes are instances ofClass. As a result you’re defining scream and then redefining it.What are often thought of as class methods in ruby are actually singleton methods (there’s lots of stuff to read about eigenclasses etc if you are interested).
The
Construct creates singleton methods. Very often this will be inside a class definition, using self but you can do it on anything, for example if you do
Then x.bark will return woof, but bark won’t be defined on any other string.
Here your method needs to reference your
noisevariable, so you’ll need to usedefine_singleton_methodto define your method.If you’re still in ruby 1.8 you can’t use define_singleton_method – you need to use the fact that singleton methods are methods on the eigenclass.
Is equivalent to using define_singleton_method