2010-11-04 3 views
25

Il doit y avoir une manière intégrée de faire cela, non?Ruby: Comment enchaîner plusieurs appels de méthode avec "envoyer"

class Object 
    def send_chain(arr) 
    o=self 
    arr.each{|a| o=o.send(a) } 
    return o 
    end 
end 
+1

Je ne suis pas sûr, mais j'ai déjà pris des chemins comme celui-ci, et je trouve généralement qu'ils mènent à une mauvaise implémentation de quelque chose. Qu'est-ce que vous essayez réellement d'accomplir? Peut-être existe-t-il un modèle de programmation existant qui vous serait plus utile. –

+2

Eh, c'est juste une tâche rake pour sortir certaines colonnes de certains modèles ActiveRecord. Il accepte un tableau de chaînes, chaque chaîne représentant soit l'attribut/la méthode d'un modèle, soit l'attribut/la méthode d'un modèle associé. Donc, je veux lui donner quelque chose comme ["date", "title", "color", "author.name"] pour le modèle "Book" et lui faire imprimer les attributs et l'attribut du nom de l'auteur associé. Je suppose que je pourrais écrire des méthodes pour Book qui retournerait self.author.name, mais je voulais juste quelque chose de rapide pour cette tâche de sortie rake unique. – Zando

Répondre

48

Je viens couru à travers cela et on peut se poser vraiment inject:

def send_chain(arr) 
    arr.inject(self) {|o, a| o.send(a) } 
end 
+1

Nice. Bien mieux répondre. –

+23

Shorter: 'arr.inject (self,: send)' – Ajedi32

+11

Plus sûr: 'arr.inject (self,: try)' :) – Archonic

6

Non, il n'y est pas construit dans le moyen de le faire. Ce que vous avez fait est assez simple et concis, pour ne pas dire dangereux. Soyez prudent lorsque vous l'utilisez.

Sur une autre pensée, cela peut être étendu à accepter des arguments ainsi:

class Object 
    def send_chain(*args) 
    o=self 
    args.each do |arg| 
     case arg 
     when Symbol, String 
     o = o.send arg # send single symbol or string without arguments 
     when Array 
     o = o.send *arg # smash the inner array into method name + arguments 
     else 
     raise ArgumentError 
     end 
    end 
    return o 
    end 
end 

cela vous permettra de passer un nom de méthode avec ses arguments dans un tableau, comme;

test = MyObject.new 
test.send_chain :a_method, [:a_method_with_args, an_argument, another_argument], :another_method 
+2

Juste être nitpicky ici, mais en restant en ligne avec les idiomes Ruby, cela devrait vraiment être dactylographié. –

+0

@edgerunner. Cela n'a pas fonctionné pour moi sa.grade_accesses.send_chain (: except_grade_k,: except_grade_math_fact) NoMethodError: méthode indéfinie 'except_grade_k 'pour #

+0

@MohitJain toutes les méthodes devraient renvoyer l'individu. – thisismydesign

3

Se appuyant sur les réponses précédentes, dans le cas où vous avez besoin de passer des arguments à chaque méthode, vous pouvez utiliser ceci:

def send_chain(arr) 
    Array(arr).inject(self) { |o, a| o.send(*a) } 
end 

Vous pouvez ensuite utiliser la méthode comme ceci:

arr = [:to_i, [:+, 4], :to_s, [:*, 3]] 
'1'.send_chain(arr) # => "555" 

Cette méthode accepte également les arguments uniques.

Questions connexes