Intrepidd
Intrepidd

Reputation: 20948

Add class methods to an existing module in ruby

I have a module that add class methods when included into a class.

I would like to force this module to extend new methods by writing another module that will be included by the first one.

The following code gives an example of what i want to do that does not work : It would be great to be able to override the "self.included" function of the first module to extend the base with my methods.

So far I was able to override the self.included function of the first module but calling super does not work so I loose the class methods of the first module :

module SomeModule

  def self.included(base)
    base.send(:extend, ClassMethods)
  end

  module ClassMethods

    # Some methods

  end

end


module MyNewModule

 def self.included(base)
    base.class_eval do
      def self.included(base)
        base.send(:extend, ClassMethods)
        super(base)
      end
    end
  end

  module ClassMethods

    def my_method
    end

  end

end

SomeModule.send(:include, MyNewModule)

class Pouet

  include SomeModule

  my_method # undefined local variable or method `my_method' for Pouet:Class (NameError)

end

Is this possible?

Upvotes: 2

Views: 2775

Answers (2)

Intrepidd
Intrepidd

Reputation: 20948

Finally managed to make it work by myself.

Please tell me if this is a good or a bad practice :

module SomeModule

  def self.included(base)
    base.send(:extend, ClassMethods)
  end

  module ClassMethods

    def my_original_method
    end

    # Some methods

  end

end


module MyNewModule

  def self.included(base)
    base.class_eval do

      class << self

        alias_method :old_included, :included

        def included(base)
          old_included(base)
          base.send(:extend, ClassMethods)
        end

      end

    end
  end

  module ClassMethods

    def my_method
    end

  end

end

SomeModule.send(:include, MyNewModule)

class Pouet

  include SomeModule

  my_original_method
  my_method

end

Upvotes: 0

Joe Pym
Joe Pym

Reputation: 1836

Use instance_eval inside your included block.

Inside the instance_eval block, you have access to the object that are you including it in, so you should then be able to include your extra modules there.

EDIT:

You have to pass a string to instance_eval, because the block will store your current context.

For an example of where I've done similar: https://github.com/JoePym/UndergroundFootball/blob/master/app/models/player.rb#L14

Upvotes: 1

Related Questions