When to use self for Ruby Class

Viewed 151

Can somebody help me distinguish When we create methods inside class << self block and when we define normal methods.

I saw somewhere code like this, but I don't know concisely the use cases of them

class Foo
  def initialize
  end

  def bar
  end

  class << self
    def foobar
    end
  end
end
2 Answers

The methods defined right inside a class block are instance methods:

class Foo
  def bar
  end
end

Methods defined within class << self inside a class block are class methods:

class Foo
  class << self
    def baz
    end
  end
end

Instance methods become available to any instance of a given class:

foo = Foo.new
foo.bar

Whereas class methods can be called directly on the class:

Foo.baz

Attempting to call instance methods on the class or vice versa results in an error:

Foo.bar #=> NoMethodError: undefined method `bar' for Foo:Class
foo.baz #=> NoMethodError: undefined method `baz' for #<Foo:0x00007ffe20055a20>

Another way to define class methods is by prefixing the method name with self.:

class Foo
  def self.baz
  end
end

You could also define them outside the class block, although this is rarely seen:

def Foo.baz
end

Or likewise:

class << Foo
  def baz
  end
end

Note that defining methods this way is not limited to classes. You can add methods to arbitrary objects, e.g.:

o = Object.new

def o.hello
  "hello from o"
end

o.hello
#=> "hello from o"

Or via:

class << o
  def hello
    "hello from o"
  end
end

Internally, these methods are added to the object's singleton class. It's a special purpose class to hold methods for just that instance:

o.singleton_class.instance_methods(false)
#=> [:hello]

For the Foo class above:

Foo.instance_methods(false)                 #=> [:bar]
Foo.singleton_class.instance_methods(false) #=> [:baz]

So technically, a class method is just an instance method defined on the class' singleton class.

You may need to read up on Ruby's instance and class methods. But personally, I'd do

class Foo
  class << self
    def foobar
    end
  end
end

instead of

class Foo
  def self.foobar
  end
end

whenever I want to add some class level attributes, or make a method private etc as

class Foo
  private
  def self.foobar
  end
end

wouldn't work the same as

class Foo
  class << self
    private
    def foobar
    end
  end
end
Related