有没有办法在 Ruby 中访问方法参数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9211813/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is there a way to access method arguments in Ruby?
提问by Haris Krajina
New to Ruby and ROR and loving it each day, so here is my question since I have not idea how to google it (and I have tried :) )
Ruby 和 ROR 的新手并且每天都喜欢它,所以这是我的问题,因为我不知道如何搜索它(我已经尝试过 :))
we have method
我们有方法
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
So what I am looking for way to get all arguments passed to method, without listing each one. Since this is Ruby I assume there is a way :) if it was java I would just list them :)
所以我正在寻找将所有参数传递给方法的方法,而不列出每个参数。由于这是 Ruby,我认为有一种方法:) 如果是 Java,我会列出它们:)
Output would be:
输出将是:
Method has failed, here are all method arguments {"Mario", "Super", 40, true, true}
回答by mikej
In Ruby 1.9.2 and later you can use the parametersmethod on a method to get the list of parameters for that method. This will return a list of pairs indicating the name of the parameter and whether it is required.
在 Ruby 1.9.2 及更高版本中,您可以在parameters方法上使用方法来获取该方法的参数列表。这将返回一个对列表,指示参数的名称以及是否需要它。
e.g.
例如
If you do
如果你这样做
def foo(x, y)
end
then
然后
method(:foo).parameters # => [[:req, :x], [:req, :y]]
You can use the special variable __method__to get the name of the current method. So within a method the names of its parameters can be obtained via
您可以使用特殊变量__method__来获取当前方法的名称。所以在一个方法中,其参数的名称可以通过
args = method(__method__).parameters.map { |arg| arg[1].to_s }
You could then display the name and value of each parameter with
然后,您可以使用以下命令显示每个参数的名称和值
logger.error "Method failed with " + args.map { |arg| "#{arg} = #{eval arg}" }.join(', ')
Note:since this answer was originally written, in current versions of Ruby evalcan no longer be called with a symbol. To address this, an explicit to_shas been added when building the list of parameter names i.e. parameters.map { |arg| arg[1].to_s }
注意:由于这个答案最初是写的,在当前版本的 Rubyeval中不能再用符号调用。为了解决这个问题,to_s在构建参数名称列表时添加了一个显式,即parameters.map { |arg| arg[1].to_s }
回答by Jakub Jirutka
Since Ruby 2.1 you can use binding.local_variable_getto read value of any local variable, including method parameters (arguments). Thanks to that you can improve the accepted answerto avoid evileval.
从 Ruby 2.1 开始,您可以使用binding.local_variable_get读取任何局部变量的值,包括方法参数(参数)。因此,您可以改进已接受的答案以避免邪恶评估。
def foo(x, y)
method(__method__).parameters.map do |_, name|
binding.local_variable_get(name)
end
end
foo(1, 2) # => 1, 2
回答by Arun Kumar Arjunan
One way to handle this is:
处理这种情况的一种方法是:
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
回答by Raffaele
This is an interesting question. Maybe using local_variables? But there must be a way other than using eval. I'm looking in Kernel doc
这是个有趣的问题。也许使用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
回答by Jon Jagger
This may be helpful...
这可能会有所帮助...
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
回答by Al Johri
You can define a constant such as:
您可以定义一个常量,例如:
ARGS_TO_HASH = "method(__method__).parameters.map { |arg| arg[1].to_s }.map { |arg| { arg.to_sym => eval(arg) } }.reduce Hash.new, :merge"
And use it in your code like:
并在您的代码中使用它,例如:
args = eval(ARGS_TO_HASH)
another_method_that_takes_the_same_arguments(**args)
回答by ebeland
It seems like what this question is trying to accomplish could be done with a gem I just released, https://github.com/ericbeland/exception_details. It will list local variables and vlaues (and instance variables) from rescued exceptions. Might be worth a look...
似乎这个问题试图完成的事情可以用我刚刚发布的 gem 来完成,https://github.com/ericbeland/exception_details。它将列出来自获救异常的局部变量和 vlaues(和实例变量)。可能值得一看...
回答by Tom L
Before I go further, you're passing too many arguments into foo. It looks like all of those arguments are attributes on a Model, correct? You should really be passing the object itself. End of speech.
在我继续之前,您将太多参数传递给 foo。看起来所有这些参数都是模型的属性,对吗?你真的应该传递对象本身。演讲结束。
You could use a "splat" argument. It shoves everything into an array. It would look like:
您可以使用“splat”参数。它把所有东西都推到一个数组中。它看起来像:
def foo(*bar)
...
log.error "Error with arguments #{bar.joins(', ')}"
end
回答by Simon Bagreev
If you would change the method signature, you can do something like this:
如果要更改方法签名,可以执行以下操作:
def foo(*args)
# some code
# error happens here
logger.error "Method has failed, here are all method arguments #{args}"
end
Or:
或者:
def foo(opts={})
# some code
# error happens here
logger.error "Method has failed, here are all method arguments #{opts.values}"
end
In this case, interpolated argsor opts.valueswill be an array, but you can joinif on comma. Cheers
在这种情况下,内插args或opts.values将是一个数组,但您可以join使用逗号。干杯
回答by greenback
If you need arguments as a Hash, and you don't want to pollute method's body with tricky extraction of parameters, use this:
如果您需要将参数作为 Hash,并且您不想通过棘手的参数提取来污染方法的主体,请使用以下命令:
def mymethod(firstarg, kw_arg1:, kw_arg2: :default)
args = MethodArguments.(binding) # All arguments are in `args` hash now
...
end
Just add this class to your project:
只需将此类添加到您的项目中:
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

