2015-08-02 1 views
2

Je développe une application Ruby où j'appelle dynamiquement des méthodes basées sur des données JSON. Librement:Détermination de l'arithme de la méthode avec les arguments du mot-clé

def items 
    # do something 
end 

def createItem(name:, data:nil) 
    # do something that requires a name keyword argument 
end 

def receive_json(json) # e.g. { "cmd":"createItem", "name":"jim" } 
    hash = JSON.parse(json) 
    cmd = hash.delete('cmd') 
    if respond_to?(cmd) 
    params = Hash[ hash.map{ |k,v| [k.to_sym, v } ] 
    method(cmd).arity==0 ? send(cmd) : send(cmd,params) 
    end 
end 

Comme indiqué ci-dessus, certaines méthodes ne prennent pas d'arguments, et certains prennent des arguments clés. Sous Ruby 2.1.0 (où je développe) le arity des deux méthodes ci-dessus est 0. Cependant, si je send(cmd,params) toujours, j'obtiens une erreur pour les méthodes qui ne prennent aucun paramètre.

Comment puis-je utiliser send pour transmettre correctement les arguments du mot-clé lorsque cela est souhaité, mais les omettre dans le cas contraire?

Répondre

5

En utilisant parameters au lieu de arity semble travailler pour mes besoins:

method(cmd).parameters.empty? ? send(cmd) : send(cmd,opts) 

Plus un aperçu de la richesse des parameters valeurs de retour:

def foo; end 
method(:foo).parameters 
#=> [] 

def bar(a,b=nil); end 
method(:bar).parameters 
#=> [[:req, :a], [:opt, :b]] 

def jim(a:,b:nil); end 
method(:jim).parameters 
#=> [[:keyreq, :a], [:key, :b]] 

Voici une méthode générique qui choisit uniquement les les valeurs nommées que votre méthode prend en charge, dans le cas où vous avez des clés supplémentaires dans votre hachage qui ne font pas partie des arguments de mots clés utilisés par la méthode:

module Kernel 
    def dispatch(name,args) 
    keyargs = method(name).parameters.map do |type,name| 
     [name,args[name]] if args.include?(name) 
    end.compact.to_h 
    keyargs.empty? ? send(name) : send(name,keyargs) 
    end 
end 

h = {a:1, b:2, c:3} 

def no_params 
    p :yay 
end 

def few(a:,b:99) 
    p a:a, b:b 
end 

def extra(a:,b:,c:,z:17) 
    p a:a, b:b, c:c, z:z 
end 

dispatch(:no_params,h) #=> :yay 
dispatch(:few,h)  #=> {:a=>1, :b=>2} 
dispatch(:extra,h)  #=> {:a=>1, :b=>2, :c=>3, :z=>17} 
+2

Ce. 'arity' a été obscure depuis que l'introduction de paramètres optionnels avec des arguments par défaut, est devenue obsolète avec l'introduction de' parameters' et est maintenant complètement inutile après l'introduction de paramètres de mot-clé. –

0

Au début, je pensais que params est censé devenir un vide lorsque la valeur :cmd est "items", auquel cas la réponse de Jesse Sielaff serait correct. Mais puisque vous semblez prétendre que ce n'est pas le cas, je pense que c'est votre défaut de conception. Au lieu d'essayer d'envoyer de cette façon, vous devriez plutôt avoir ces méthodes juste avaler les arguments:

def items(name:nil, data:nil) 
    ... 
end 
+0

Il existe actuellement plus de 20 méthodes différentes, avec des arguments variables. Je ne veux pas éliminer le surensemble de tous les arguments inutilisés. Au lieu de cela, je veux transmettre des arguments le cas échéant, et ne pas les transmettre lorsque la méthode n'en a pas besoin. Avec 'parameters', je peux maintenant réduire l'ensemble des commandes à celles qui correspondent. – Phrogz