Sony Santos
Sony Santos

Reputation: 5545

Ruby - Calling another Class method in super class

class A
  def self.a
    puts "self: #{self}; superclass: #{superclass}"
  end
end

class B < A
  class << self; undef_method(:a); end  # I'm not allowed to use B.a
  def self.b
    # here I want to call A.a with B as self.
  end
end  

A.a  #=> self: A; superclass: Object
B.b  #=> self: B; superclass: A (expected)

I don't want an alias_method solution. I'm looking for something like this.

UPDATE

The solution doesn't need to be any similar to the link above; it's only a suggestion. For example, I tried to do:

class B < A
  def self.b
    instance_eval(&A.method(:a).to_proc)
  end
end

but this way I get an weird ArgumentError on Ruby 1.8.7.

Upvotes: 1

Views: 2922

Answers (3)

Sony Santos
Sony Santos

Reputation: 5545

Only solution here is to use B.a.

class B < A
  def self.b
    a #=> self: B; superclass: A
  end
end  

Upvotes: 1

DigitalRoss
DigitalRoss

Reputation: 146053

When calling a method in the derived class B, with respect to instances of the derived class there is absolutely no difference between the A instance object and the B instance object. They are exactly the same object.

So when considering instance methods, there is only one single object. It's conceptually possible if slightly tricky, as you noted, to call a method defined in the parent class but with, of course, the derived class as the self instance. There is no way to distinguish between an "A" object and a "B" object, there is but a single instance and they are the "same" for A and B. But for class methods, the parallel with the rebound instance method you referred to simply does not exist.

Now, you are talking about class methods. For class methods, as you know, self is the class. Instances are meaningless. You cannot call class method A.whatever without having class A or its metaclass be self.

In other words, the reason your referenced trick works is because there is only one object, and for a derived instance it's named from the derived class. There is no way to do the opposite without creating a second instance of the underived parent class. But now that we are calling class methods they are .. well .. class methods, so there is no hope of referring to a derived class. How, exactly, could what you want even be defined?

Upvotes: 2

C. K. Young
C. K. Young

Reputation: 223003

I don't think it's doable using the SuperProxy approach you linked to.

In this case, A.method(:a) is a singleton method. Singleton methods can only be bound to the object it was created with. In particular, it cannot be rebound to B.

Here's the first non-working approach I tried:

class B < A
  def self.b
    A.method(:a).unbind.bind(self).call
  end
end

Second non-working approach:

class B < A
  class << self
    define_method :b, A.method(:a)
  end
end

Both generate a "TypeError: singleton method bound for a different object" exception.

Upvotes: 2

Related Questions