thehoooplehead thehoooplehead - 1 month ago 6
Ruby Question

Accessing Calling Scope in Module Method

I'm making a little debug tool to get the arguments passed into a method as follows:

Class bar
def foo(a,b,c)
Debug.get_arguments()
### do stuff
end
end

module Debug
def get_arguments
method(__method__).parameters.map { |arg| [arg[1],eval(arg[1].to_s)] }.to_h
end
end


Currently, it returns and empty hash '{}' while I'd like it to return {a: x, b: y, c: z} (the arguments of foo along with the values).

Is there something like __calling_method__ or __parent_method__? Otherwise, I'd have to put this debugging code in every method.

Answer

You can get this done by using eval to evaluate a string of code in the current scope.

Note that there were some errors with your code that I've fixed:

  • in Class bar, the capitalization was wrong
  • you're calling Debug.get_arguments, so get_arguments should be a class method

Note that I'm loading awesome_print just to show the output more clearly; the code is not dependent on it.

The script (test.rb):

require 'awesome_print'

class Bar
  def foo(a,b,c)
    eval Debug.get_arguments
  end
end

module Debug
  def self.get_arguments
    "method(__method__).parameters.map { |arg| [arg[1],eval(arg[1].to_s)] }.to_h"
  end
end

ap Bar.new.foo 1,2,3

Calling the script:

$ ruby test.rb

Prints:

{
    :a => 1,
    :b => 2,
    :c => 3
}

This shows that eval works even when nested, which is cool.

Comments