Stefan
Stefan

Reputation: 114138

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.

Upvotes: 6

Views: 124

Answers (3)

sawa
sawa

Reputation: 168081

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.

Upvotes: 5

J&#246;rg W Mittag
J&#246;rg W Mittag

Reputation: 369428

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

Upvotes: 3

ndnenkov
ndnenkov

Reputation: 36101

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 # => []

Upvotes: 3

Related Questions