Nouveau à Ruby et ROR et l’aimer chaque jour, alors voici ma question puisque je n’ai pas idée de comment google (et j’ai essayé :))
nous avons la 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 cherche un moyen de faire passer tous les arguments à la méthode, sans énumérer chacun. Puisque c’est Ruby, je suppose qu’il y a un moyen 🙂 si c’é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 parameters de cette méthode. Cela renverra une liste de paires indiquant le nom du paramètre et si elle est requirejse.
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 actuelle. Ainsi, dans une méthode, les noms de ses parameters 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(', ')
Remarque: cette réponse ayant été écrite à l’origine, les versions actuelles de Ruby ne peuvent plus être appelées avec un symbole. Pour y remédier, un to_s
explicite a été ajouté lors de la construction de la liste des noms de parameters, à savoir parameters.map { |arg| arg[1].to_s }
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 parameters de la méthode (arguments). Grâce à cela, vous pouvez améliorer la réponse acceptée pour é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 la suivante:
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 local_variables ? Mais il doit y avoir un moyen autre que d’utiliser eval. Je cherche dans le doc du kernel
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
Avant d’aller plus loin, vous transmettez trop d’arguments à foo. Il semble que tous ces arguments soient des atsortingbuts sur un modèle, n’est-ce pas? Vous devriez vraiment passer l’object lui-même. Fin du discours
Vous pouvez utiliser un argument “splat”. Il pousse 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, les arguments interpolés ou opts.values
seront un tableau, mais vous pouvez vous join
à une virgule. À votre santé
Il semble que ce que cette question essaie de faire pourrait être fait 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) à partir des exceptions récupérées. Peut-être vaut-il un coup d’oeil …
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 l’utiliser dans votre code comme:
args = eval(ARGS_TO_HASH) another_method_that_takes_the_same_arguments(**args)
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 des parameters, 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