Ruby: Calling class method from instance

212,877

Solution 1

Rather than referring to the literal name of the class, inside an instance method you can just call self.class.whatever.

class Foo
    def self.some_class_method
        puts self
    end

    def some_instance_method
        self.class.some_class_method
    end
end

print "Class method: "
Foo.some_class_method

print "Instance method: "
Foo.new.some_instance_method

Outputs:

Class method: Foo
Instance method: Foo

Solution 2

Using self.class.blah is NOT the same as using ClassName.blah when it comes to inheritance.

class Truck
  def self.default_make
    "mac"
  end

  def make1
    self.class.default_make
  end

  def make2
    Truck.default_make
  end
end


class BigTruck < Truck
  def self.default_make
    "bigmac"
  end
end

ruby-1.9.3-p0 :021 > b=BigTruck.new
 => #<BigTruck:0x0000000307f348> 
ruby-1.9.3-p0 :022 > b.make1
 => "bigmac" 
ruby-1.9.3-p0 :023 > b.make2
 => "mac" 

Solution 3

To access a class method inside a instance method, do the following:

self.class.default_make

Here is an alternative solution for your problem:

class Truck

  attr_accessor :make, :year

  def self.default_make
    "Toyota"
  end

  def make
    @make || self.class.default_make
  end

  def initialize(make=nil, year=nil)
    self.year, self.make = year, make
  end
end

Now let's use our class:

t = Truck.new("Honda", 2000)
t.make
# => "Honda"
t.year
# => "2000"

t = Truck.new
t.make
# => "Toyota"
t.year
# => nil

Solution 4

If you have access to the delegate method you can do this:

[20] pry(main)> class Foo
[20] pry(main)*   def self.bar
[20] pry(main)*     "foo bar"
[20] pry(main)*   end  
[20] pry(main)*   delegate :bar, to: 'self.class'
[20] pry(main)* end  
=> [:bar]
[21] pry(main)> Foo.new.bar
=> "foo bar"
[22] pry(main)> Foo.bar
=> "foo bar"

Alternatively, and probably cleaner if you have more then a method or two you want to delegate to class & instance:

[1] pry(main)> class Foo
[1] pry(main)*   module AvailableToClassAndInstance
[1] pry(main)*     def bar
[1] pry(main)*       "foo bar"
[1] pry(main)*     end  
[1] pry(main)*   end  
[1] pry(main)*   include AvailableToClassAndInstance
[1] pry(main)*   extend AvailableToClassAndInstance
[1] pry(main)* end  
=> Foo
[2] pry(main)> Foo.new.bar
=> "foo bar"
[3] pry(main)> Foo.bar
=> "foo bar"

A word of caution:

Don't just randomly delegate everything that doesn't change state to class and instance because you'll start running into strange name clash issues. Do this sparingly and only after you checked nothing else is squashed.

Solution 5

self.class.default_make
Share:
212,877
Peter
Author by

Peter

I am not actually called Peter. Sorry about that.

Updated on July 08, 2022

Comments

  • Peter
    Peter almost 2 years

    In Ruby, how do you call a class method from one of that class's instances? Say I have

    class Truck
      def self.default_make
        # Class method.
        "mac"
      end
    
      def initialize
        # Instance method.
        Truck.default_make  # gets the default via the class's method.
        # But: I wish to avoid mentioning Truck. Seems I'm repeating myself.
      end
    end
    

    the line Truck.default_make retrieves the default. But is there a way of saying this without mentioning Truck? It seems like there should be.

  • Peter
    Peter over 14 years
    I disagree that default_make should be an instance method. Even if it's simpler for these examples, it's not the right semantics - the default is a product of the class, not objects that belong to the class.
  • phoet
    phoet over 12 years
    make should not be an instance method. it's more a kind of factory, that should be bound to the class rather than an instance
  • phoet
    phoet over 12 years
    i would like to see some shortcut in ruby to call a class method from an instance. ie :>some_class_method instead of self.class.some_class_method
  • Harish Shetty
    Harish Shetty over 12 years
    @phoet The make word denotes the make of a car(as in Toyota, BMW etc.) englishforums.com/English/AMakeOfCar/crcjb/post.htm. The nomenclature is based on user's requirement
  • Matt Connolly
    Matt Connolly over 12 years
    while this is the right answer, it's a shame that "self.class" is more typing and less easy to read than the class name "Truck". oh well....
  • Marlen T. B.
    Marlen T. B. over 12 years
    @Peter would you care to explain that in simpler terms? I'm just learning Ruby and Maha's answers seems perfect to me.
  • Peter
    Peter about 12 years
    @MarlenT.B. looking back I'm not sure there's too much to be learned here - I was only arguing about where the best place to put the method was, and I don't buy my own argument as strongly anymore! :)
  • drewish
    drewish over 11 years
    @MattConnolly, it's relative, if your class name is is SalesforceSyncJob then it's shorter ;)
  • Gus Shortz
    Gus Shortz about 11 years
    @MattConnolly, also using self.class eliminates the need for search/replacing if you happen to rename the class.
  • Matt Connolly
    Matt Connolly about 11 years
    @GusShortz true. Also, self.class works better if there is a subclass.
  • vish
    vish almost 11 years
    I also disagree. Whether something is a class method has nothing to do with "utility". It is about whether the method conceptually applies to the class, or an object of that class. For example, every truck has a different serial number, so serial_number is an instance method (with corresponding instance variable). On the other vehicle_type (which returns "truck") should be a class method because that is a property of all trucks, not a particular truck
  • David West
    David West almost 11 years
    I noticed that when I was applying this, I had to define the method before I could call it later in the class. Why is that? Does anybody know if there is a reason the language is designed that way? I'm using Ruby 1.8.7 in this particular instance. Has this changed in the more recent versions?
  • zhon
    zhon over 10 years
    This seems to be a response to to the accepted answer rather than an answer to the question.
  • PhilT
    PhilT over 9 years
    @DavidWest The class is being evaluated so you can't call something before you define it. Are you calling a class method in the class rather than inside a method in the class?
  • Matt Sanders
    Matt Sanders over 8 years
    @zohn - true, but this is still useful context when considering what to use.
  • nandilugio
    nandilugio almost 8 years
    @MattSanders just use a comment in those cases.
  • Kaiser Shahid
    Kaiser Shahid over 6 years
    @hlcs self.class is correct to preserve inheritance. even though make1() is defined in Truck, it's referencing BigTruck's class method.
  • Seth Jeffery
    Seth Jeffery over 5 years
    If you're in Rails and hate writing self.class everywhere, then try this: delegate : some_class_method, to: :class.
  • Chris Harrison
    Chris Harrison over 3 years
    I don't understand what the advantage is to something being 'less typing' or 'shorter'. We are not in a famine where there's a shortage of characters. Something being shorter often means it's more ambiguous.