Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Methods specific only to an instance? What are they called in Ruby?

Tags:

ruby

singleton

I know there are "instance methods", "class methods" but what are these types of methods called, for eg:

s1 = "This is my STRING!"

def s1.m1
  downcase
end

p s1     # => "This is my STRING!"
p s1.m1   # => "this is my string!"

What type of method is the "m1" method called on the s1 "instance" of the "string" class? It's really weird because I didn't know this was possible at all if I try:

s2 = "This is ANOTHER string"
s2.m1 # => Won't work!

Which kind of makes sense, but not sure why defining methods like m1 on instances on a class are useful at all.

like image 692
daremkd Avatar asked Mar 22 '23 19:03

daremkd


1 Answers

They are called singleton methods, and can be defined as follows:

class Person
  def favorite_meal
    "Big Mac"
  end
end

Fred, Joe = 2.times.map { Person.new }

def Fred.favorite_meal
  "Le Big Mac"
end

Joe.favorite_meal #=> Big Mac
Fred.favorite_meal #=> Le Big Mac

Other ways to define the same singleton method would be:

Fred.define_singleton_method :favorite_meal do "Le Big Mac" end

And:

class << Fred
  def favorite_meal
    "Le Big Mac"
  end
end

May the force be with you.


UPDATE: Answering the 2 questions from the comment.

Let me start by the 2nd one. It is up to you, whether you use a constant or a variable. It is perfectly OK to write fred = Person.new. But:

  1. Objects with distinct properties often deserve proper names, which are properly capialized.

  2. There is a useful gem I wrote, y_support/name_magic, that works by assigning to constants.

Install it by gem install y_support, and try:

require 'y_support/name_magic'

class Dog
  include NameMagic
  def speak; puts "Bow wow!" end
end

Spot, Rover = 2.times.map { Dog.new }

Now the Dog class knows its instances, and the instances know their names.

Dog.instances.map { |dog| dog.name } #=> :Spot, :Rover
Dog.instances.names # the simpler way to say the same

This is not useful in this particular example (and extremely useful elsewhere), but in any case, it gave me a habit of giving objects with personalities capitlized proper names.

As for the 1st question, def Fred.foobar is the most basic, one-off singleton method definition. If you want to define several singleton methods, or alias, or include a module in the singleton class, use class << Fred:

module Foo
  def bar; "Fretbar!" end
end

class << Fred
  include Foo
  alias le_favorite favorite_meal
end

Fred.bar #=> Fretbar!
Fred.le_favorite #=> "Le Big Mac"

The most advanced things are possible with Fred.define_singleton_method syntax, and with the 4th way, which I have not mentioned earlier:

local_var = 42

Fred.singleton_class.class_exec do
  define_method :baz do local_var + 1 end
end

Fred.baz #=> 43

This way uses closures, which retain binding to the variable local_var. Try it out

local_var = 32
Fred.baz #=> 33

So this is what's special about the syntax with closures, and it is often a godsend that magically solves nasty programming problems.

like image 192
Boris Stitnicky Avatar answered Apr 26 '23 02:04

Boris Stitnicky