views:

182

answers:

1
module MyModule 
  def my_method; 'hello'; end
end

class MyClass 
  class << self
    include MyModule
  end 
end

MyClass.my_method   # => "hello

I'm unsure why "include MyModule" needs to be in the singleton class in order to be called using just MyClass.

Why can't I go:

X = MyClass.new
X.my_method
+6  A: 

include ModuleName adds the methods from the module as instance methods to the including class.

So if you write

class MyClass
  include MyModule
end

then my_method becomes an instance method on MyClass e.g.

m = MyClass.new
m.my_method # => "hello"

When you include the module inside the singleton class the methods are still being added as instance methods but to the instance of the class Class for your class. Therefore they appear as class methods on MyClass.

EDIT (Jörg W Mittag): However, you should never do that, since including in the singleton class is the same as extending the original object, which is preferred. So, this:

class MyClass
  class << self
    include MyModule
  end
end

is the same as this:

class MyClass
  extend MyModule
end

You should always use the latter form.

More generally, this:

foo = Object.new
class << foo
  include MyModule
end

is the same as this:

foo = Object.new
foo.extend MyModule

EDIT (MAL): If you want to have you method both as an instance method and a method, you can simply define your method as above, and either extend self which will bring all instance methods accessible to the module object itself, or alternatively use module_function :my_method.

mikej
Your question already covers all the bases, so I added my remarks as an edit instead of a separate answer.
Jörg W Mittag
@Jörg Thanks for doing this - I've always used `extend` myself as well so hadn't really thought about `including` in the singleton class until Dex's question.
mikej
I took the liberty of editing the answer to use the term `singleton class` as it is the official name. Indeed, Ruby 1.9.2 introduces `Object#singleton_class`
Marc-André Lafortune
I copied Jörg and edited your answer to mention `module_function` too.
Marc-André Lafortune
@Marc-André thanks for your improvements too.
mikej