How to access a (shadowed) global function in ruby

2019-01-23 05:28发布

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.

标签: ruby scope
1条回答
爱情/是我丢掉的垃圾
2楼-- · 2019-01-23 05:32

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.

查看更多
登录 后发表回答