Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ruby - extend module inside another module

Tags:

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?

like image 865
codecraig Avatar asked Mar 30 '11 14:03

codecraig


People also ask

Can we extend a module in Ruby?

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.

What does prepend directive do in Ruby?

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.

What is prepend in Rails?

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.

How do you call a module in Ruby?

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.


2 Answers

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).

like image 80
Viacheslav Molokov Avatar answered Sep 30 '22 01:09

Viacheslav Molokov


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 
like image 29
ALoR Avatar answered Sep 30 '22 02:09

ALoR