DVG
DVG

Reputation: 17470

Using a module inside another module with the same name

I have a module like this

module A
  module ClassMethods
    def a
      "a"
    end
    def b
      a
    end
  end
  def self.included(klass)
    klass.extend ClassMethods
  end
end

I want to factor b into it's own module because Bs are clearly not As. The b method depends on A, and I would like the methods defined in A to be available to B.

Doing this:

module B
  module ClassMethods
    extend A
    def b
      a
    end
  end
  def self.included(klass)
    klass.extend(ClassMethods)
  end
end

It does not work. Nor does include. I tried moving include or extend as well as the how constants are references. What am I missing here?

Upvotes: 0

Views: 82

Answers (2)

Rafa Paez
Rafa Paez

Reputation: 4870

Add the extend A action in the included callback of the module B instead of adding it in the ClassMethod definition, like the following code does:

module A
  module ClassMethods
    def a
      "a"
    end
  end
  def self.included(klass)
    klass.extend ClassMethods
  end
end

module B
  module ClassMethods
    def b
      a
    end
  end
  def self.included(klass)
    klass.extend(ClassMethods)
    klass.extend(A)
  end
end

class C 
  include B
end

C.b
# => "a"

Upvotes: 1

Daniël Knippers
Daniël Knippers

Reputation: 3055

I hope I understood what you wanted. I split up module A and module B. When I include those in a new class Klass, I have access to both method a and method b, whereas method b from module B depends on method a from module A:

module A
  module ClassMethods
    def a
      "a"
    end
  end

  def self.included(klass)
    klass.extend(ClassMethods)
  end
end

module B
  module ClassMethods
    # include A::ClassMethods here and you can do only 'include B' inside Klass
    def b
      "Called from B: %s" % a
    end
  end

  def self.included(klass)
    klass.extend(ClassMethods)
  end
end

class Klass
  include A, B
end

p Klass.a # => "a"
p Klass.b # => "Called from B: a"

As I understand you can define the same Module in different places, no need to say include, extend or anything. As you see neither Module A nor Module B uses those keywords, they both just define ClassMethods.

Of course, you will have to include module A wherever you use method b of module B or else the method call to a will fail. You can also do include A::ClassMethods inside B::ClassMethods, that way you only need to include B inside Klass.

Upvotes: 2

Related Questions