tags:

views:

117

answers:

1

Hi,

I was wondering how to access a global function fn in ruby from a class which also defined a method fn. I have made a workaround by aliasing the function like so:

def fn
end

class Bar
    alias global_fn fn
    def fn
        # how to access the global fn here without the alias
        global_fn
    end
end

I'm looking for something along the lines of c++'s :: to access global scope but I can't seem to locate any information about it. I guess I don't know specifically what I'm looking for.

+5  A: 

At the top-level a def adds a private method to Object.

I can think of three ways to get the top-level function:

(1) Use send to invoke the private method on Object itself (only works if the method is not a mutator since Object will be the receiver)

Object.send(:fn)

(2) Get a Method instance of the top-level method and bind it to the instance you want to invoke it on:

class Bar
    def fn
        Object.instance_method(:fn).bind(self).call
    end
end

(3) Use super (assumes no super classes of Bar below Object redefine the function)

class Bar
    def fn
        super
    end
end

UPDATE:

Since solution (2) is the preferable one (in my opinion) we can try to improve the syntax by defining a utility method on Object called super_method:

class Object
    def super_method(base, meth, *args, &block)
        if !self.kind_of?(base) 
            raise ArgumentError, "#{base} is not a superclass of #{self}" 
        end

        base.instance_method(meth).bind(self).call(*args, &block)
    end
end

Use like the following:

class Bar
    def fn
        super_method Object, :fn
    end
end

Where the first argument to super_method must be a valid superclass of Bar, the second argument the method you want to invoke, and all remaining arguments (if any) are passed along as parameters to the selected method.

banister
I didn't know that global methods are actually added to Object. Does this mean that my alias approach, like your super approach will also break also if Bar has a superclass which also defines fn?
yngvedh
@yngvedh, exactly. It'll break in the same way. The most general approach IMO is to use the second solution.
banister
@banister, and there is no other way to accomplish that? I'm thinking of something more syntactically pleasing, like c++'s Object::fn.
yngvedh
@yngvedh, just updated with a method on `Object` that hopefully improves the syntax for you
banister
@yngvedh, it just occurred to me that a 'global function' should never really be a mutator method anyway, and so perhaps solution (1) is best for you. However, in the general case...i.e to invoke a method defined on an arbitrary baseclass somewhere in the inheritance chain, i think the `super_method` approach is a good one ;)
banister
Great, thanks for the input. :)
yngvedh