Define_method için bağımsız değişkenleri nasıl iletirsiniz?


155

Define_method kullanılarak tanımlanmış bir yönteme bir argüman (lar) iletmek istiyorum, nasıl yaparım?

Yanıtlar:


198

Define_method dosyasına ilettiğiniz blok bazı parametreler içerebilir. Tanımlanmış yönteminiz bu şekilde argümanları kabul eder. Bir yöntem tanımladığınızda, gerçekten sadece bloğu takma ve sınıfta bir referans tutma. Parametreler blok ile birlikte gelir. Yani:

define_method(:say_hi) { |other| puts "Hi, " + other }

Bu sadece katkısız bir beaty meselesi. İyi iş çıkardın Kevin Costner.
Darth Egregious

90

... ve isteğe bağlı parametreler istiyorsanız

 class Bar
   define_method(:foo) do |arg=nil|                  
     arg                                                                                          
   end   
 end

 a = Bar.new
 a.foo
 #=> nil
 a.foo 1
 # => 1

... istediğiniz kadar argüman

 class Bar
   define_method(:foo) do |*arg|                  
     arg                                                                                          
   end   
 end

 a = Bar.new
 a.foo
 #=> []
 a.foo 1
 # => [1]
 a.foo 1, 2 , 'AAA'
 # => [1, 2, 'AAA']

...kombinasyonu

 class Bar
   define_method(:foo) do |bubla,*arg|
     p bubla                  
     p arg                                                                                          
   end   
 end

 a = Bar.new
 a.foo
 #=> wrong number of arguments (0 for 1)
 a.foo 1
 # 1
 # []

 a.foo 1, 2 ,3 ,4
 # 1
 # [2,3,4]

... hepsi

 class Bar
   define_method(:foo) do |variable1, variable2,*arg, &block|  
     p  variable1     
     p  variable2
     p  arg
     p  block.inspect                                                                              
   end   
 end
 a = Bar.new      
 a.foo :one, 'two', :three, 4, 5 do
   'six'
 end

Güncelleme

Ruby 2.0 **( alıntı yaptığım ) yaptığı çift ​​uyarıyı (iki yıldız) tanıttı :

Ruby 2.0 anahtar kelime bağımsız değişkenlerini tanıttı ve **, * gibi davranıyor, ancak anahtar kelime bağımsız değişkenleri için. Anahtar / değer çiftleri içeren bir Hash döndürür.

... ve elbette bunu tanımlama yönteminde de kullanabilirsiniz :)

 class Bar 
   define_method(:foo) do |variable1, variable2,*arg,**options, &block|
     p  variable1
     p  variable2
     p  arg
     p  options
     p  block.inspect
   end 
 end 
 a = Bar.new
 a.foo :one, 'two', :three, 4, 5, ruby: 'is awesome', foo: :bar do
   'six'
 end
# :one
# "two"
# [:three, 4, 5]
# {:ruby=>"is awesome", :foo=>:bar}

Adlandırılmış öznitelikler örneği:

 class Bar
   define_method(:foo) do |variable1, color: 'blue', **other_options, &block|
     p  variable1
     p  color
     p  other_options
     p  block.inspect
   end
 end
 a = Bar.new
 a.foo :one, color: 'red', ruby: 'is awesome', foo: :bar do
   'six'
 end
# :one
# "red"
# {:ruby=>"is awesome", :foo=>:bar}

Ben hepsi bir arada anahtar kelime argümanı, uyarısı ve çift uyarısı ile örnek oluşturmaya çalışıyordu:

 define_method(:foo) do |variable1, variable2,*arg, i_will_not: 'work', **options, &block|
    # ...

veya

 define_method(:foo) do |variable1, variable2, i_will_not: 'work', *arg, **options, &block|
    # ...

... ama bu işe yaramayacak, bir sınırlama var gibi görünüyor. Splat operatörü "kalan tüm argümanları yakalar" ve çift splat "kalan tüm anahtar kelime argümanlarını yakalar" olarak düşündüğünüzde, bunları karıştırmak beklenen mantığı bozacaktır. (Bu noktayı kanıtlamak için referansım yok doh!)

güncelleme Ağustos 2018:

Özet makale: https://blog.eq8.eu/til/metaprogramming-ruby-examples.html


İlginç - özellikle 4. blok: 1.8.7 üzerinde çalıştı! İlk blok 1.8.7'de çalışmadı ve ikinci blokta bir yazım hatası var ( a.foo 1yerine foo 1). Teşekkürler!
Sony Santos

1
Geri bildiriminiz için teşekkürler, yazım hatası düzeltildi, ... Yakut 1.9.3 ve 1.9.2'de tüm örnekler işe yarıyor ve 1.9.1'de de (ama denemedim)
eşdeğer8

Bu cevabı , isteğe bağlı argümanlar ve bir blok alan ve yine de orijinal metodu argümanlar ile çağırabilen çalışma zamanında bir yöntemin üzerine nasıl yazılacağını (geçersiz kılmayacağını) anlamak için stackoverflow.com/questions/4470108/… adresindeki kabul edilen cevapla birleştirdim. ve engelle. Ah, yakut. Özellikle, sadece üretimde erişebildiğim bir ana bilgisayara tek bir API çağrısı için dev envimimde Savon :: Client.request'in üzerine yazmam gerekiyordu. Şerefe!
pduey

59

Kevin Conner'in cevabına ek olarak: blok argümanları yöntem argümanlarıyla aynı anlambilimi desteklemez. Varsayılan bağımsız değişkenleri tanımlayamaz veya bağımsız değişkenleri engelleyemezsiniz.

Bu sadece Ruby 1.9'da tam yöntem argüman semantiğini destekleyen yeni alternatif "stabby lambda" sözdizimi ile giderilmiştir.

Misal:

# Works
def meth(default = :foo, *splat, &block) puts 'Bar'; end

# Doesn't work
define_method :meth { |default = :foo, *splat, &block| puts 'Bar' }

# This works in Ruby 1.9 (modulo typos, I don't actually have it installed)
define_method :meth, ->(default = :foo, *splat, &block) { puts 'Bar' }

3
Aslında, define_method üzerindeki blok argümanlarının varsayılan argümanları da tanımlamak için yuvarlak bir yol sağlayabilen uyarıyı desteklediğine inanıyorum.
Chinasaur

1
Chinasaur, uyarılara izin veren blok argümanları konusunda haklıdır. Bunu Ruby 1.8.7 ve 1.9.1'de onayladım.
Peter Wagenet

Teşekkürler, bunu unuttum. Şimdi düzeltildi.
Jörg W Mittag

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.