s2t2
s2t2

Reputation: 2696

Ruby Yield to Subclass Method from Superclass Method

In Ruby, is it possible to yield to a subclass method from a superclass method without affecting code in the subclass? I'm trying to avoid calling super in the subclass.

class SuperClass
  def do_something
    puts "getting ready..."
    # how to then yield back to the subclass do_something method?
    puts "done."
  end
end

class SubClass < SuperClass
  def do_something
    # how to first execute the superclass do_something method?
    puts "doing something ..."
  end
end

Desired functionality is to specifically call SubClass.do_something and receive the following output:

"getting ready..."

"doing something..."

"done."


EDIT:

Maybe the real question is: How to DRY-up the code below, removing calls to self.get_ready and self.finish_up from all subclasses, using any ruby meta-programming technique that keeps those classes DRY:

class SuperClass
  def self.get_ready
    puts "getting ready ..."
  end

  def self.finish_up
    puts "done."
  end
end

class SubClassA < SuperClass
  def self.do_something
    self.get_ready
    puts "doing something ..."
    self.finish_up
  end
end

class SubClassB < SuperClass
  def self.do_something
    self.get_ready
    puts "doing something else, a little differently..."
    self.finish_up
  end
end

class SubClassC < SuperClass
  def self.do_something
    self.get_ready
    puts "doing something crazy..."
    self.finish_up
  end
end

Upvotes: 3

Views: 2903

Answers (2)

Platinum Azure
Platinum Azure

Reputation: 46193

If you're really not open to using super, this is pretty much impossible.

With super, it's pretty simple:

class SuperClass
  def do_something
    puts "getting ready..."
    yield
    puts "done."
  end
end

class SubClass < SuperClass
  def do_something
    super.do_something do
      puts "doing something..."
    end
  end
end

On the other hand, without using super, this becomes simpler if you are open to multiple methods:

class SuperClass
  def do_something
    puts "getting ready..."
    self.actually_do_the_thing
    puts "done."
  end
  def actually_do_the_thing
    raise NotImplementedError
  end
end

class SubClass < SuperClass
  def actually_do_the_thing
    puts "doing something..."
  end
end

Upvotes: 6

daremkd
daremkd

Reputation: 8424

In Practical Object-Oriented Design in Ruby, what Sandi Metz recommend you do to overcome calling super is to define a "hook" method in the super-class, which only job would be to get over-written by the child methods. In your case, you could do something like this:

class SuperClass
  def self.do_something
    puts "getting ready..."
    do_something_child
    puts "done."
  end

  def self.do_something_child; end
end

class SubClass < SuperClass
  def self.do_something_child
    puts "doing something ..."
  end
end

SubClass.do_something

Upvotes: 8

Related Questions