7

I have the following classes

class Animal
  def move
    "I can move"
  end
end

class Bird < Animal
  def move
    super + " by flying"
  end
end

class Penguin < Bird
  def move
    #How can I call Animal move here
    "I can move"+ ' by swimming'
  end
end

How can I call Animal's move method inside Penguin ? I can't use super.super.move. What are the options?

Thanks

Arup Rakshit
  • 116,827
  • 30
  • 260
  • 317
Toan Nguyen
  • 11,263
  • 5
  • 43
  • 59
  • 1
    Accepted solution is not the best way to go if you love _designs_. Best answer is - [How can we call parent's parent method in Ruby(elegant way) ?](http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/429729). – Arup Rakshit Jan 21 '15 at 10:17

4 Answers4

11

You can get the move instance method of Animal, bind it to self, then call it:

class Penguin < Bird
  def move
    m = Animal.instance_method(:move).bind(self)
    m.call
  end
end
August
  • 12,410
  • 3
  • 35
  • 51
6

If you are using Ruby 2.2.0, then you have something new in your plate. That something is : Method#super_method.

class Animal
  def move
    "I can move"
  end
end

class Bird < Animal
  def move
    super + " by flying"
  end
end

class Penguin < Bird
  def move
    method(__method__).super_method.super_method.call + ' by swimming'
  end
end

Penguin.new.move # => "I can move by swimming"

I completely agree with Robert Klemme's and his answer is best and clean.

Arup Rakshit
  • 116,827
  • 30
  • 260
  • 317
  • That's rather cool. If convenient, you could also do this: `class Method; def ancestor_method(n); n.times.reduce(self) { |m,_| m.super_method }; end; end`, then `method(__method__).ancestor_method(2).call + ' by swimming'`. – Cary Swoveland Feb 06 '15 at 02:29
1
class Penguin < Bird
  def move
    grandparent = self.class.superclass.superclass
    meth = grandparent.instance_method(:move)
    meth.bind(self).call + " by swimming"
  end
end

puts Penguin.new.move

For more details about this approach read this answer

Community
  • 1
  • 1
Higor Morais
  • 121
  • 1
  • 5
1

You could do this (which I suggested here):

class Penguin < Bird
  def move
    puts self.class.ancestors[2].instance_method(__method__).bind(self).call +
    ' by swimming'
  end
end

Penguin.new.move
  # I can move by swimming

[Edit: I see this is quite similar to @August's answer. This has the slight advantage that neither the class Animal nor method name move are hard-wired.]

Community
  • 1
  • 1
Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100