Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby: Is it possible to determine the class that my Ruby method is executing in without hardcoding the classname?

Tags:

ruby

I am a Nuby to Ruby. I am looking for a way to get the containing Class object of the method of the current line of execution. Is this possible without hardcoding the classname?

# hardcoded example
class A
  def to_s
    "I am a " + A.to_s   # Class "A" is hardcoded here. Is there another way to reference the class A?
  end
end

I thought that maybe self.class would work, but it didn't give me what I was looking for when the class is subclassed.

# Following Outputs=> I am a Camel I am a Camel I am a Camel
# but I want       => I am a Camel I am a Mammal I am a Animal

class Animal
  def to_s
    "I am a " + self.class.to_s
  end
end

class Mammal < Animal
  def to_s
    "I am a " + self.class.to_s + " " + super
  end
end

class Camel < Mammal
  def to_s
    "I am a " + self.class.to_s + " " + super
  end
end

puts Camel.new()

So, is there a keyword, method or something that allows accessing the containing class?

like image 486
successhawk Avatar asked Jan 08 '17 21:01

successhawk


People also ask

How do I find the class of an object in Ruby?

Find out how to get an object's class name in Ruby To get the name of an object's class in Ruby, you can simply use object.class.name , for example, like so: print []. class.name #=> Array print "".

How do you define a class method in Ruby?

There are two standard approaches for defining class method in Ruby. The first one is the “def self. method” (let's call it Style #1), and the second one is the “class << self” (let's call it Style #2). Both of them have pros and cons.


2 Answers

You'll need Class#ancestors :

Camel.ancestors
#=> [Camel, Mammal, Animal, Object, Kernel, BasicObject]

You'll get more classes than you defined, so you'll need to stop at Object :

class Animal
  def to_s
    "I am a " + self.class.ancestors.take_while{|klass| klass != Object}.join(' and a ')
  end
end

class Mammal < Animal
end

class Camel < Mammal
end

puts Animal.new
# => I am a Animal
puts Mammal.new
# => I am a Mammal and a Animal
puts Camel.new
# => I am a Camel and a Mammal and a Animal

ancestors can be Modules or Classes, so if you just want Classes, you can use :

def to_s
  "I am a " + self.class.ancestors.take_while{|klass| klass < Object}.join(' and a ')
end

So, is there a keyword, method or something that allows accessing the containing class?

I couldn't find one. Adding

puts method(__method__).owner

to Animal#to_s or Mammal#to_s still returns Camel.

like image 64
Eric Duminil Avatar answered Oct 12 '22 13:10

Eric Duminil


Try this

Class.nesting.first

This gives you the defining class of a method.

class A
  def example
    { defining_class: Class.nesting.first, self_class: self.class }
  end
end

class B < A
end

B.new.example
# => {:defining_class=>A, :self_class=>B}
like image 34
akuhn Avatar answered Oct 12 '22 14:10

akuhn