Nouveau sur Ruby et ROR et l’aimer tous les jours), alors voici ma question car je ne sais pas comment le rechercher sur Google (et j’ai essayé :))
nous avons méthode
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
Donc, ce que je recherche un moyen d’obtenir tous les arguments passés à la méthode, sans les lister tous. Puisqu'il s'agit de Ruby, je suppose qu'il existe un moyen :) s'il était Java, je les énumérerais simplement :)
La sortie serait:
Method has failed, here are all method arguments {"Mario", "Super", 40, true, true}
Dans Ruby 1.9.2 et versions ultérieures, vous pouvez utiliser la méthode parameters
sur une méthode pour obtenir la liste des paramètres de cette méthode. Cela renverra une liste de paires indiquant le nom. du paramètre et s'il est requis.
par exemple.
Si tu fais
def foo(x, y)
end
puis
method(:foo).parameters # => [[:req, :x], [:req, :y]]
Vous pouvez utiliser la variable spéciale __method__
pour obtenir le nom de la méthode en cours. Ainsi, dans une méthode, les noms de ses paramètres peuvent être obtenus via
args = method(__method__).parameters.map { |arg| arg[1].to_s }
Vous pouvez ensuite afficher le nom et la valeur de chaque paramètre avec
logger.error "Method failed with " + args.map { |arg| "#{arg} = #{eval arg}" }.join(', ')
Note: puisque cette réponse a été écrite à l'origine, dans les versions actuelles de Ruby eval
ne peut plus être appelé avec un symbole. Pour y remédier, un explicite to_s
a été ajouté lors de la construction de la liste des noms de paramètres, à savoir parameters.map { |arg| arg[1].to_s }
Depuis Ruby 2.1, vous pouvez utiliser binding.local_variable_get pour lire la valeur de toute variable locale, y compris les paramètres de méthode (arguments). Grâce à cela, vous pouvez améliorer la réponse acceptée à éviter mal eval.
def foo(x, y)
method(__method__).parameters.map do |_, name|
binding.local_variable_get(name)
end
end
foo(1, 2) # => 1, 2
Une façon de gérer cela est:
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
C'est une question intéressante. Peut-être en utilisant variables_locales ? Mais il doit y avoir un autre moyen que d'utiliser eval. Je cherche dans le noyau doc
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
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
Vous pouvez définir une constante telle que:
ARGS_TO_HASH = "method(__method__).parameters.map { |arg| arg[1].to_s }.map { |arg| { arg.to_sym => eval(arg) } }.reduce Hash.new, :merge"
Et utilisez-le dans votre code comme:
args = eval(ARGS_TO_HASH)
another_method_that_takes_the_same_arguments(**args)
Il semble que ce que cette question tente d'accomplir puisse être réalisé avec un joyau que je viens de publier, https://github.com/ericbeland/exception_details . Il listera les variables locales et vlaues (et les variables d'instance) des exceptions sauvées. Ça vaut peut-être le coup d'oeil ...
Avant d’aller plus loin, vous passez trop d’arguments à foo. Il semble que tous ces arguments sont des attributs d'un modèle, n'est-ce pas? Vous devriez vraiment passer l'objet lui-même. Fin du discours.
Vous pouvez utiliser un argument "splat". Il met tout dans un tableau. Cela ressemblerait à:
def foo(*bar)
...
log.error "Error with arguments #{bar.joins(', ')}"
end
Si vous voulez changer la signature de la méthode, vous pouvez faire quelque chose comme ceci:
def foo(*args)
# some code
# error happens here
logger.error "Method has failed, here are all method arguments #{args}"
end
Ou:
def foo(opts={})
# some code
# error happens here
logger.error "Method has failed, here are all method arguments #{opts.values}"
end
Dans ce cas, interpolée args
ou opts.values
sera un tableau, mais vous pouvez join
si vous utilisez une virgule. À votre santé
Si vous avez besoin d'arguments en tant que hachage et que vous ne voulez pas polluer le corps de la méthode avec une extraction délicate de paramètres, utilisez ceci:
def mymethod(firstarg, kw_arg1:, kw_arg2: :default)
args = MethodArguments.(binding) # All arguments are in `args` hash now
...
end
Ajoutez simplement cette classe à votre projet:
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
Si la fonction est dans une classe, vous pouvez faire quelque chose comme ceci:
class Car
def drive(speed)
end
end
car = Car.new
method = car.method(:drive)
p method.parameters #=> [[:req, :speed]]