tags:

views:

44

answers:

3

I want to add a foo method to Ruby's Kernel module, so I can write foo(obj) anywhere and have it do something to obj. Sometimes I want a class to override foo, so I do this:

module Kernel
  private  # important; this is what Ruby does for commands like 'puts', etc.
  def foo x
    if x.respond_to? :foo
      x.foo  # use overwritten method.
    else
      # do something to x.
    end
  end
end

this is good, and works. but, what if I want to use the default Kernel::foo in some other object that overwrites foo? Since I've got an instance method foo, I've lost the original binding to Kernel::foo.

class Bar
  def foo  # override behaviour of Kernel::foo for Bar objects.
    foo(3) # calls Bar::foo, not the desired call of Kernel::foo.
    Kernel::foo(3)  # can't call Kernel::foo because it's private.
    # question: how do I call Kernel::foo on 3?
  end
end

Is there any clean way to get around this? I'd rather not have two different names, and I definitely don't want to make Kernel::foo public.

+2  A: 

You can use the super keyword to call the superclass's implementation from a overridden method.

class Bar
  def foo  # override behaviour of Kernel::foo for Bar objects.
    super
    # do something else here
  end
end
Chuck
yep, you're absolute right. thanks. got distracted by the obscurity of `Kernel`.
Peter
A: 

Just use alias or alias_method before you redefine Kernel.foo to keep a reference to the original version.

x1a4
I'd already tried this and it doesn't work, since `Kernel::foo` hasn't been mixed in at the point of code definition.
Peter
Ah, got it. Yeah, this way doesn't work in your case.
x1a4
this can also pollute your namespace.
rampion
It *does* pollute the namespace in every case, but it answers the question that was asked.
x1a4
+3  A: 

For a more general solution than just super (super wont always work), also see this thread:

How to access a shadowed global function in Ruby?

banister