Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to access a (shadowed) global function in ruby

Tags:

scope

ruby

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.

like image 717
Yngve Hammersland Avatar asked Apr 21 '10 10:04

Yngve Hammersland


People also ask

What are global variables in Ruby?

However, the use of global variables is often considered "un-Ruby," and you will rarely see them. Global variables are defined and used like any other variable. To define them, simply assign a value to them and begin using them. But, as their name suggests, assigning to global variables from any point in the program has global implications.

What is the use of $in Ruby?

For instance, it is useful for keeping a GUI display up to date. There is a collection of special variables whose names consist of a dollar sign ( $) followed by a single character. For example, $$ contains the process id of the ruby interpreter, and is read-only.

What is the scope of a variable in Ruby?

Variable scope in Ruby is controlled by sigils to some degree. Variables starting with $ are global, variables with @ are instance variables, @@ means class variables, and names starting with a capital letter are constants. All other variables are locals.

Is there a prefix for global variables in a draw method?

Without a specific prefix for globals, given a statement pointNew = offset + point inside your draw method then offset refers to a local variable inside the method (and results in a NameError in this case). The same for @ used to refer to instance variables and @@ for class variables.


1 Answers

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.

like image 65
horseyguy Avatar answered Sep 24 '22 08:09

horseyguy