2010-11-04 8 views
25

Bunu yapmanın yerleşik bir yolu olmalı, değil mi?Ruby: "Gönder" ile birlikte birden çok yöntem çağrısını zincirleme nasıl yapılır

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

Emin değilim, ama daha önce böyle bir yoldan aşağı gittim ve genellikle bir şeyin kötü bir şekilde uygulanmasına yol açtıklarını gördüm. Gerçekte ne yapmaya çalışıyorsun? Belki de size daha fazla fayda sağlayacak mevcut bir programlama modeli vardır. –

+2

Eh, sadece bazı ActiveRecord modellerinden bazı sütunları çıkarmak için bir komisyon görevi. Her dizgenin bir modelin özniteliğini/yöntemini veya modelin ilişkili modelinin özniteliğini/yöntemini temsil ettiği bir dizi dizeyi kabul eder. Bu yüzden, "Kitap" modeli için ["tarih", "başlık", "renk", "yazar.adı"] gibi bir şey vermek ve özellikleri ve ilişkili yazarın ad özniteliğini yazdırmak istiyorum. Self.author.name döndürecek Kitap için yöntemler yazabilirim, ama bu tek seferlik komisyon çıkış görevi için hızlı bir şey istedim. – Zando

cevap

48

Sadece bu karşılaştım ve gerçekten inject için yalvarır: Her yönteme argüman geçmesi gerekiyor durumunda, önceki cevaplar üzerine

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

Güzel. Daha iyi cevap. –

+23

Daha kısa: 'arr.inject (self,: gönder)' – Ajedi32

+11

Daha güvenli: 'arr.inject (self,: try)' :) – Archonic

6

Hayır, bir bunu yapmanın yolu inşa yoktur. Yaptığınız şey, basit ve özlü, tehlikeli değil. Kullanırken dikkatli olun.

başka düşündüm de

, bu yanı argümanları kabul etmek uzatılabilir: Bu Bir dizide bir bağımsız değişkenler ile, böyle bir yöntem adı geçmesine izin verecek

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 

;

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

Sadece burada nitpicky olmak, ancak Ruby deyimleriyle uyumlu olmak, bu gerçekten ördek-yazılmalıdır. –

+0

@edgerunner. Benim için çalışmadı sa.grade_accesses.send_chain (: except_grade_k,: except_grade_math_fact) NoMethodError: # tanımsız yöntem "except_grade_k"> –

+0

@MohitJain tüm yöntemler kendi kendine geri dönmelidir. – thisismydesign

3

Building, bunu kullanabilirsiniz:

arr = [:to_i, [:+, 4], :to_s, [:*, 3]] 
'1'.send_chain(arr) # => "555" 
:
def send_chain(arr) 
    Array(arr).inject(self) { |o, a| o.send(*a) } 
end 

sonra böyle bir yöntemi kullanabilirsiniz

Bu yöntem, tek bağımsız değişkenleri de kabul eder.