I'm trying to define a couple of modules to easily add in some instance and class methods to other classes, here's what I'm doing:
module Foo module Bar def speak puts "hey there" end end module Baz extend Foo::Bar def welcome puts "welcome, this is an instance method" end end end class Talker include Foo::Baz end Talker.new.welcome Talker.speak
The output of this is:
welcome, this is an instance method undefined method 'speak' for Talker.class (NoMethodError)
I was expecting Talker to have the 'speak' method since it includes Foo::Baz which itself extends Foo::Bar.
What am I missing?
Extend is also used to importing module code but extends import them as class methods. Ruby will throw an error when we try to access methods of import module with the instance of the class because the module gets import to the superclass just as the instance of the extended module.
With prepend, the module is added before the class in the ancestor chain. This means ruby will look at the module to see if an instance method is defined before checking if it is defined in the class. This is useful if you want to wrap some logic around your methods.
Available since Ruby 2, prepend is a bit less known to Rubyists than its two other friends. It actually works like include, except that instead of inserting the module between the class and its superclass in the chain, it will insert it at the bottom of the chain, even before the class itself.
As with class methods, you call a module method by preceding its name with the module's name and a period, and you reference a constant using the module name and two colons.
You can try this:
module Baz extend Foo::Bar def self.included(base) base.send :extend, Foo::Bar end def welcome puts "welcome, this is an instance method" end end
This will auto-extend all classes in wich Baz is included.
PS:
extend Foo::Bar
in module Baz
was in original snippet, this code do not influence on method def self.included(base)
.
try this:
class Talker extend Foo::Baz end
since you want to call Talker.speak as a class method and not as an instance method (like Talker.new.speak) you have to include the Foo:Baz in a way that the class will take the methods itself.
One possibility is to use 'extend' (as above) the other is modifying it's eigenclass:
class Talker class << self include Foo::Baz end end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With