401

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.

Andrew Grimm
  • 78,473
  • 57
  • 200
  • 338
Peter
  • 127,331
  • 53
  • 180
  • 211

9 Answers9

642

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
Mark Rushakoff
  • 249,864
  • 45
  • 407
  • 398
  • 9
    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 – phoet Dec 28 '11 at 11:22
  • 7
    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.... – Matt Connolly Jan 11 '12 at 11:18
  • 24
    @MattConnolly, it's relative, if your class name is is `SalesforceSyncJob` then it's shorter ;) – drewish Feb 27 '13 at 21:00
  • 30
    @MattConnolly, also using `self.class` eliminates the need for search/replacing if you happen to rename the class. – Gus Shortz May 24 '13 at 17:24
  • 10
    @GusShortz true. Also, self.class works better if there is a subclass. – Matt Connolly May 25 '13 at 01:24
  • 1
    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? – David West Aug 01 '13 at 15:10
  • @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? – PhilT Dec 07 '14 at 17:31
  • If you're in Rails and hate writing `self.class` everywhere, then try this: `delegate : some_class_method, to: :class`. – Seth Jeffery Nov 02 '18 at 15:07
  • 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. – Chris Harrison Nov 17 '20 at 11:10
214

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" 
JasonMArcher
  • 14,195
  • 22
  • 56
  • 52
Mark B
  • 2,165
  • 1
  • 12
  • 2
25

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
Harish Shetty
  • 64,083
  • 21
  • 152
  • 198
  • 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 Dec 28 '11 at 11:21
  • 8
    @phoet The make word denotes the make of a car(as in Toyota, BMW etc.) http://www.englishforums.com/English/AMakeOfCar/crcjb/post.htm. The nomenclature is based on user's requirement – Harish Shetty Dec 28 '11 at 20:56
12

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.

tmr08c
  • 77
  • 1
  • 8
bbozo
  • 7,075
  • 3
  • 30
  • 56
7
self.class.default_make
yfeldblum
  • 65,165
  • 12
  • 129
  • 169
4

You're doing it the right way. Class methods (similar to 'static' methods in C++ or Java) aren't part of the instance, so they have to be referenced directly.

On that note, in your example you'd be better served making 'default_make' a regular method:

#!/usr/bin/ruby

class Truck
    def default_make
        # Class method.
        "mac"
    end

    def initialize
        # Instance method.
        puts default_make  # gets the default via the class's method.
    end
end

myTruck = Truck.new()

Class methods are more useful for utility-type functions that use the class. For example:

#!/usr/bin/ruby

class Truck
    attr_accessor :make

    def default_make
        # Class method.
        "mac"
    end

    def self.buildTrucks(make, count)
        truckArray = []

        (1..count).each do
            truckArray << Truck.new(make)
        end

        return truckArray
    end

    def initialize(make = nil)
        if( make == nil )
            @make = default_make()
        else
            @make = make
        end
    end
end

myTrucks = Truck.buildTrucks("Yotota", 4)

myTrucks.each do |truck|
    puts truck.make
end
Jason Machacek
  • 994
  • 1
  • 8
  • 18
  • 3
    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. – Peter Mar 27 '10 at 06:26
  • 1
    @Peter would you care to explain that in simpler terms? I'm just learning Ruby and Maha's answers seems perfect to me. – Marlen T. B. Mar 26 '12 at 03:04
  • 1
    @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! :) – Peter Mar 29 '12 at 06:57
  • 2
    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 – vish Jul 11 '13 at 04:47
3

One more:

class Truck
  def self.default_make
    "mac"
  end

  attr_reader :make

  private define_method :default_make, &method(:default_make)

  def initialize(make = default_make)
    @make = make
  end
end

puts Truck.new.make # => mac
Alexey
  • 3,843
  • 6
  • 30
  • 44
1

Here's an approach on how you might implement a _class method that works as self.class for this situation. Note: Do not use this in production code, this is for interest-sake :)

From: Can you eval code in the context of a caller in Ruby? and also http://rubychallenger.blogspot.com.au/2011/07/caller-binding.html

# Rabid monkey-patch for Object
require 'continuation' if RUBY_VERSION >= '1.9.0'
class Object
  def __; eval 'self.class', caller_binding; end
  alias :_class :__
  def caller_binding
    cc = nil; count = 0
    set_trace_func lambda { |event, file, lineno, id, binding, klass|
      if count == 2
        set_trace_func nil
        cc.call binding
      elsif event == "return"
        count += 1
      end
    }
    return callcc { |cont| cc = cont }
  end
end

# Now we have awesome
def Tiger
  def roar
    # self.class.roar
    __.roar
    # or, even
    _class.roar
  end
  def self.roar
    # TODO: tigerness
  end
end

Maybe the right answer is to submit a patch for Ruby :)

Community
  • 1
  • 1
captainpete
  • 6,162
  • 3
  • 28
  • 26
-7

Similar your question, you could use:

class Truck
  def default_make
    # Do something
  end

  def initialize
    super
    self.default_make
  end
end
Daniel
  • 567
  • 6
  • 20