Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to determine the class a method was defined in?

I would like to dynamically determine the class the current method was defined in.

Here's a static example of what I'm trying to do:

class A
  def foo
    puts "I was defined in A"
  end
end

class B < A
  def foo
    puts "I was defined in B"
    super
  end
end

A.new.foo
# I was defined in A

B.new.foo
# I was defined in B
# I was defined in A  <- this is the tricky one

How can I replace A and B in the strings above with a dynamic expression?

Apparently, #{self.class} does not work. (it would print I was defined in B twice for B)

I suspect that the answer is "you can't", but maybe I'm overlooking something.

like image 514
Stefan Avatar asked Jan 12 '16 11:01

Stefan


3 Answers

What about this?

class A
  def foo
    puts "I was defined in #{Module.nesting.first}"
  end
end

class B < A
  def foo
    puts "I was defined in #{Module.nesting.first}"
    super
  end
end

Corrected following WandMaker's suggestion.

like image 192
sawa Avatar answered Nov 18 '22 13:11

sawa


You could use Module.nesting.first.

However, note that this works purely lexically, the same way constants resolution works, so it won't cut it if you have more dynamic needs:

Foo = Class.new do
  def foo
    Module.nesting
  end  
end

Foo.new.foo # => []
like image 3
ndnenkov Avatar answered Nov 18 '22 14:11

ndnenkov


I have this nagging feeling that if you could do this, it would violate object-orientated encapsulation, although I can't quite place my finger on exactly why. So, it shouldn't come as a surprise that it's hard.

I can see a way if you are open to modifying the method definitions:

class A
  this = self
  define_method(:foo) do
    puts "I was defined in #{this}"
  end
end

class B < A
  this = self
  define_method(:foo) do
    puts "I was defined in #{this}"
    super()
  end
end

A.new.foo
# I was defined in A

B.new.foo
# I was defined in B
# I was defined in A
like image 3
Jörg W Mittag Avatar answered Nov 18 '22 14:11

Jörg W Mittag