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 :)
我正在寻找的方法是将所有参数传递给method,而不列出每个参数。因为这是Ruby,所以我认为有一种方法:)如果是java,我就列出它们:)
Output would be:
输出是:
Method has failed, here are all method arguments {"Mario", "Super", 40, true, true}
10 个解决方案
#1
127
In Ruby 1.9.2 and later you can use the parameters
method 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 eval
can no longer be called with a symbol. To address this, an explicit to_s
has been added when building the list of parameter names i.e. parameters.map { |arg| arg[1].to_s }
注意:由于这个答案最初是编写的,所以在Ruby eval的当前版本中不能再使用符号来调用。为了解决这个问题,在构建参数名称列表(即参数)时添加了一个显式to_s。arg地图{ | | arg[1]。to_s }
#2
36
Since Ruby 2.1 you can use binding.local_variable_get to read value of any local variable, including method parameters (arguments). Thanks to that you can improve the accepted answer to avoid evil eval.
因为Ruby 2.1可以使用绑定。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
#3
16
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
#4
6
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
#5
3
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
#6
2
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
#7
2
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 args
or opts.values
will be an array, but you can join
if on comma. Cheers
在这种情况下,插入args或opts。值将是一个数组,但是可以在逗号上连接。干杯
#8
2
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(以及实例变量)。也许值得一看……
#9
2
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)
#10
0
If you need arguments as a Hash, and you don't want to pollute method's body with tricky extraction of parameters, use this:
如果您需要参数作为散列,并且您不希望使用复杂的参数提取来污染方法的主体,请使用以下方法:
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
#1
127
In Ruby 1.9.2 and later you can use the parameters
method 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 eval
can no longer be called with a symbol. To address this, an explicit to_s
has been added when building the list of parameter names i.e. parameters.map { |arg| arg[1].to_s }
注意:由于这个答案最初是编写的,所以在Ruby eval的当前版本中不能再使用符号来调用。为了解决这个问题,在构建参数名称列表(即参数)时添加了一个显式to_s。arg地图{ | | arg[1]。to_s }
#2
36
Since Ruby 2.1 you can use binding.local_variable_get to read value of any local variable, including method parameters (arguments). Thanks to that you can improve the accepted answer to avoid evil eval.
因为Ruby 2.1可以使用绑定。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
#3
16
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
#4
6
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
#5
3
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
#6
2
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
#7
2
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 args
or opts.values
will be an array, but you can join
if on comma. Cheers
在这种情况下,插入args或opts。值将是一个数组,但是可以在逗号上连接。干杯
#8
2
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(以及实例变量)。也许值得一看……
#9
2
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)
#10
0
If you need arguments as a Hash, and you don't want to pollute method's body with tricky extraction of parameters, use this:
如果您需要参数作为散列,并且您不希望使用复杂的参数提取来污染方法的主体,请使用以下方法:
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