Home > Software design >  How to get a class name given that self could be a class or an instance?
How to get a class name given that self could be a class or an instance?

Time:06-10

I have a module that provides logging functionality. Some classes extend it, others include it. As part of the logging, I pass in a class name.

If I do this:

global_logger.call(level, self, msg)

It could log either:

WARN -- Some::Class: some msg

OR

WARN -- #<Some::OtherClass:0x00007fdc04907710>: some msg

based on if the module was extended or included. I can call self.class instead, but then the the other one turns into Class.

Is there a way to get a class name(without the #<...:0x00007fdc04907710>), given that you don't know if self is a class or an instance?

CodePudding user response:

There are a number of things you could do, but one of the easiest is probably to see if the passed object is a class before trying to extract other information about it. For example:

Object.kind_of? Class #=> true
Object.new.kind_of? Class #=> false

You can then decide what methods are appropriate to call based on whether or not it's a class. For example:

p Object.new.class.name #=> "Object"
P Object.name #=> "Object"

CodePudding user response:

We know that, for a given module M, you can determine if a class C has included M by writing

C.included_modules.include?(M)

To determine if a class C has extended M you may execute

C.singleton_class.included_modules.include?(M)

because extending a module to a class is equivalent to including the same module to the class' singleton class.

See Module#included_modules and Object#singleton_class.

Here is an example.

module M
  def m; end
end
class C
  extend M
end
a = C.singleton_class.included_modules
  #=> [M, Kernel] 
a.include?(M)
  #=> true
  •  Tags:  
  • ruby
  • Related