Perhaps I will make explicitly clear what I feel is not fully and explicitly addressed Jorg's beautiful answer (with the utmost respect) to those not intimately familiar with Ruby's "Object Model":
module Country
def location
puts "location"
end
def self.included(base)
def cities
puts "cities"
end
end
def self.extended(base)
puts "#{self}" ## NOTICE THIS NEW LINE! NEW LINE
def animals
puts "animals"
end
end
end
class Test
include Country
end
class Test2
extend Country
end
Test.new.animals
What is the problem?
We are extending Test2, aren't we? How then is the animals method defined
in Test1?
The key is to add a puts "#{self}
line above the animals method.
We can see here that the animals method is defined in the the Country
module. So really, when you think you are extending, it, you are are in
fact making sure it's added as an instance method, rather than a
"static class method" (if you're coming from a c# / java background). That's not strictly speaking, accurate: when you are "extending" like this - and if you are doing it correctly - you are in fact adding the method
to Test2's singleton class. Ruby's object model is a little tricky in that regard. A static class method is a method ADDED to a class's singleton class. What's a singleton class? Now you are getting into ruby's object model. It's complicated and a bit of a brain drain, but once you get it, you can do some pretty powerful (and dangerous?) things like: monkey patching.
The Solution:
Jorg says it better than I could. you need to define animals like this: def base.animals
.
extended
, but not withdef
in the block there. You should dobase.define_method(...)
if you need to do this dynamically. – Clemmie