Ruby: what's the difference with these self extensions?

47 views Asked by At

So I have three different ways I can have class level methods on a module:

I usually do it this way if I have 3 or fewer:

module Foo
  def self.speak
    "Foo"
  end
end

If I have more, I've traditionally done it this way:

module Bar
  class << self
    def speak
      "Bar"
    end
  end
end

But recently, I came across this nifty way and have started using this more often:

module FooBar
  extend self 

  def speak
    "FooBar"
  end
end

They all work:

Foo.speak => "Foo"
Bar.speak => "Bar"
FooBar.speak => "FooBar"

So, is there any material differences or gotchas to be aware of, esp. with the last form? The only real gotcha I can think of is that once you "extend self" all method defs following are class-level.

I've tried to think of some edge cases where one form works, but the other doesn't. Are there any?

1

There are 1 answers

0
Cary Swoveland On

The third form, unlike the first two, creates both an instance method :speak and a module method :speak:

module Foo
  def self.speak
    "Foo"
  end
end
Foo.methods.include?(:speak)             #=> true
Foo.instance_methods.include?(:speak)    #=> false

class A
  include FooBar
end
A.instance_methods.include?(:speak)      #=> false

module Bar
  class << self
    def speak
      "Bar"
    end
  end
end
Bar.methods.include?(:speak)             #=> true
Bar.instance_methods.include?(:speak)    #=> false

class A
  include Bar
end
A.instance_methods.include?(:speak)      #=> false

module FooBar
  extend self 
  def speak
    "FooBar"
  end
end

FooBar.methods.include?(:speak)          #=> true
FooBar.instance_methods.include?(:speak) #=> true

class A
  include FooBar
end

A.instance_methods.include?(:speak)      #=> true