有没有办法在Ruby中访问方法参数?

Har*_*ina 94 ruby ruby-on-rails

Ruby和ROR的新手并且每天都喜欢它,所以这是我的问题,因为我不知道如何谷歌它(我已经尝试:))

我们有方法

def foo(first_name, last_name, age, sex, is_plumber)
    # some code
    # error happens here
    logger.error "Method has failed, here are all method arguments #{SOMETHING}"    
end
Run Code Online (Sandbox Code Playgroud)

所以我正在寻找方法将所有参数传递给方法,而不列出每一个.因为这是Ruby我假设有一种方式:)如果它是java我会列出它们:)

输出将是:

Method has failed, here are all method arguments {"Mario", "Super", 40, true, true}
Run Code Online (Sandbox Code Playgroud)

mik*_*kej 151

在Ruby 1.9.2及更高版本中,您可以在parameters方法上使用该方法来获取该方法的参数列表.这将返回一个对列表,指示参数的名称以及是否需要它.

例如

如果你这样做

def foo(x, y)
end
Run Code Online (Sandbox Code Playgroud)

然后

method(:foo).parameters # => [[:req, :x], [:req, :y]]
Run Code Online (Sandbox Code Playgroud)

您可以使用特殊变量__method__来获取当前方法的名称.因此,在方法中,可以通过获取其参数的名称

args = method(__method__).parameters.map { |arg| arg[1].to_s }
Run Code Online (Sandbox Code Playgroud)

然后,您可以显示每个参数的名称和值

logger.error "Method failed with " + args.map { |arg| "#{arg} = #{eval arg}" }.join(', ')
Run Code Online (Sandbox Code Playgroud)

注意:由于这个答案最初编写,因此在当前版本的Ruby eval中不能再使用符号调用.为了解决这个问题,to_s在构建参数名称列表时添加了显式,即parameters.map { |arg| arg[1].to_s }

  • 与此同时,我的技能越来越好,现在也能理解这段代码. (5认同)
  • 我需要一些时间来破译这个:) (4认同)
  • 我尝试使用Ruby 1.9.3,您必须执行#{eval arg.to_s}才能使其工作,否则会出现TypeError:无法将Symbol转换为String (4认同)
  • 让我知道哪些位需要解密,我会添加一些解释:) (3认同)
  • +1这真是太棒了,很优雅; 绝对是最好的答案. (3认同)

Jak*_*tka 51

从Ruby 2.1开始,您可以使用binding.local_variable_get读取任何局部变量的值,包括方法参数(参数).多亏了你可以改善已接受的答案以避免邪恶 EVAL.

def foo(x, y)
  method(__method__).parameters.map do |_, name|
    binding.local_variable_get(name)
  end
end

foo(1, 2)  # => 1, 2
Run Code Online (Sandbox Code Playgroud)


Aru*_*nan 17

解决这个问题的一种方法是:

def foo(*args)
    first_name, last_name, age, sex, is_plumber = *args
    # some code
    # error happens here
    logger.error "Method has failed, here are all method arguments #{args.inspect}"    
end
Run Code Online (Sandbox Code Playgroud)

  • 工作,除非有更好的答案,否则将被投票接受。我唯一的问题是我不想失去方法签名,有些人会有Inteli的感觉,我不想失去它。 (2认同)

Raf*_*ele 7

这是个有趣的问题.也许使用local_variables?但除了使用eval之外,必须有其他方法.我正在寻找内核文档

class Test
  def method(first, last)
    local_variables.each do |var|
      puts eval var.to_s
    end
  end
end

Test.new().method("aaa", 1) # outputs "aaa", 1
Run Code Online (Sandbox Code Playgroud)

  • 这不是最优雅和最安全的方法 - 如果在方法中定义局部变量然后调用`local_variables`,它将返回方法参数+所有局部变量.这可能会导致您的代码出错. (6认同)

gre*_*ack 7

如果您需要参数作为哈希,并且您不想通过棘手的参数提取来污染方法的主体,请使用以下命令:

def mymethod(firstarg, kw_arg1:, kw_arg2: :default)
  args = MethodArguments.(binding) # All arguments are in `args` hash now
  ...
end
Run Code Online (Sandbox Code Playgroud)

只需将此类添加到您的项目中即可:

class MethodArguments
  def self.call(ext_binding)
    raise ArgumentError, "Binding expected, #{ext_binding.class.name} given" unless ext_binding.is_a?(Binding)
    method_name = ext_binding.eval("__method__")
    ext_binding.receiver.method(method_name).parameters.map do |_, name|
      [name, ext_binding.local_variable_get(name)]
    end.to_h
  end
end
Run Code Online (Sandbox Code Playgroud)


Jon*_*ger 5

这可能会有所帮助...

  def foo(x, y)
    args(binding)
  end

  def args(callers_binding)
    callers_name = caller[0][/`.*'/][1..-2]
    parameters = method(callers_name).parameters
    parameters.map { |_, arg_name|
      callers_binding.local_variable_get(arg_name)
    }    
  end
Run Code Online (Sandbox Code Playgroud)