Ruby'de bir metodu def anahtar kelimesi, bir metot adı, isteğe bağlı parametre listesi, gövde ve end ile tanımlarsınız. Metot, gövdede en son değerlendirilen ifadenin sonucunu kendiliğinden döndürür; bu yüzden çoğu zaman return yazmanız gerekmez. Parametrelere varsayılan değer verebilir, *args ile sınırsız sayıda argüman toplayabilir ve tek ifadeden oluşan metotları def kare(x) = x * x biçiminde tek satırda yazabilirsiniz.
Bu yazıda metot tanımlamanın temel kurallarını, dönüş değerinin nasıl belirlendiğini ve konumsal (positional) parametre türlerini örneklerle anlatıyoruz. Tüm örnekler Ruby 4.0 ile çalıştırıldı; yorumlardaki # çıktı: satırları gerçek çıktıdır. Keyword argümanları ayrı bir konu olduğu için anahtar kelime argümanları yazısında, bloklar ise blok ve yield yazısında işleniyor. Ruby'yi genel olarak tanımak isterseniz Ruby nedir? yazısıyla başlayabilirsiniz.
def ile ilk metot

En basit metot, parametre almayan ve tek bir ifade döndüren metottur. Parametreler metot adından sonra parantez içinde virgülle ayrılarak yazılır ve gövdede yerel değişken gibi kullanılır. Çağırırken argümanları tanımdaki sırayla vermeniz gerekir; Ruby bunlara konumsal argüman der. Tanımda parantezler isteğe bağlıdır (def ekle deger da geçerlidir), ancak okunabilirlik için parametre varken parantez kullanmak yaygın bir alışkanlıktır.
def selamla(ad)
"Merhaba, #{ad}!"
end
def bolum(a, b)
return "sıfıra bölünemez" if b.zero?
a / b
end
p selamla("Ayşe") # çıktı: "Merhaba, Ayşe!"
p bolum(10, 2) # çıktı: 5
p bolum(10, 0) # çıktı: "sıfıra bölünemez"Dönüş değeri: örtük return ve erken çıkış
Ruby belgelerine göre bir metot, varsayılan olarak gövdesinde değerlendirilen son ifadeyi döndürür. Yukarıdaki selamla metodunda son ifade metin şablonudur, dolayısıyla dönüş değeri de odur. return anahtar kelimesi iki durumda işe yarar: dönüşü açıkça göstermek istediğinizde ve metottan son satıra gelmeden çıkmak istediğinizde. bolum metodundaki return ... if b.zero? satırı, bölen sıfırsa metodu hemen bitirir; altındaki a / b hiç çalışmaz.
Atama metotlarında (adı = ile bitenler) bir istisna vardır: nesne.deger = 5 biçiminde çağırdığınızda metodun döndürdüğü değer yok sayılır ve ifadenin sonucu her zaman verdiğiniz argüman olur. Metodu send ile doğrudan çağırırsanız gerçek dönüş değerini görürsünüz:
class Sayac
def deger=(v)
@deger = v
return 99
end
end
s = Sayac.new
p(s.deger = 5) # çıktı: 5
p s.send(:deger=, 5) # çıktı: 99Metot adları: ?, ! ve = ile biten adlar
Metot adları küçük harfle ya da alt çizgiyle başlar, kelimeler alt çizgiyle ayrılır (toplam_tutar). Belgeler üç özel son eki tanımlar. ? ile biten metotlar gelenek olarak doğru/yanlış sorusuna cevap verir; ama her zaman yalnızca true ya da false döndürmek zorunda değildir, doğru kabul edilen başka bir nesne de dönebilir. ! ile biten metotlar "tehlikeli" sürüm kabul edilir; çekirdek kütüphanede bu genellikle alıcı nesneyi yerinde değiştirdiği anlamına gelir ve çoğunun ünlemsiz, nesneyi değiştirmeyen bir eşi vardır. = ile bitenler ise yukarıda gördüğünüz atama metotlarıdır.
kelime = "merhaba"
p kelime.upcase # çıktı: "MERHABA"
p kelime # çıktı: "merhaba"
kelime.upcase!
p kelime # çıktı: "MERHABA"Ayrıca +, ==, <=>, [] gibi operatörleri de metot olarak tanımlayabilirsiniz. Belgeler, operatörlere beklenmedik anlamlar yüklemenin kafa karıştıracağı uyarısını yapar ve operatör önceliğinin değiştirilemeyeceğini belirtir. Operatörlerin sırası için Ruby operatörleri ve öncelik yazısına bakabilirsiniz.
Varsayılan değerli parametreler

Bir parametreye = ile varsayılan değer verirseniz çağıran o argümanı atlayabilir. Varsayılan değer, kendisinden önce gelen parametrelere başvurabilir, çünkü parametreler soldan sağa değerlendirilir. Varsayılanlı parametrelerin listenin sonunda olması gerekmez, ancak hepsinin yan yana durması gerekir: def f(a = 1, b, c = 1) gibi bölünmüş bir tanım SyntaxError verir.
def fiyat(tutar, kdv = 20)
tutar + tutar * kdv / 100
end
p fiyat(100) # çıktı: 120
p fiyat(100, 10) # çıktı: 110
def ekle(a = 1, b = a)
a + b
end
p ekle # çıktı: 2
p ekle(5) # çıktı: 10
def dizi(a, b = 2, c = 3, d)
[a, b, c, d]
end
p dizi(1, 4) # çıktı: [1, 2, 3, 4]
p dizi(1, 5, 6) # çıktı: [1, 5, 3, 6]Son örnek ilk bakışta şaşırtabilir. Ruby önce zorunlu parametreleri doldurur: 1 değeri a'ya, son argüman d'ye gider. Geriye kalan argümanlar varsayılanlı parametrelere soldan sağa dağıtılır; bu yüzden üç argümanlı çağrıda 5 değeri b'ye gider ve c varsayılan 3 değerinde kalır.
Splat: *args ile değişken sayıda argüman
Bir parametrenin önüne * koyarsanız, geri kalan konumsal argümanların hepsi o parametrede bir Array olarak toplanır. Bu parametre listenin başında, ortasında ya da sonunda olabilir; ama keyword argümanlarından önce gelmelidir. Çağrı tarafında da * kullanarak bir diziyi ayrı argümanlara açabilirsiniz. Ekstra parantezle yazılan bir parametre ise gelen diziyi parçalarına ayırır (array decomposition).
def topla(*sayilar)
sayilar.sum
end
p topla # çıktı: 0
p topla(1, 2, 3) # çıktı: 6
def orta(ilk, *ara, son)
ara
end
p orta(1, 2, 3, 4) # çıktı: [2, 3]
liste = [4, 5, 6]
p topla(*liste) # çıktı: 15
p topla(*nil) # çıktı: 0
def ayir((ad, *diger))
[ad, diger]
end
p ayir(["Ali", "Can", "Ece"]) # çıktı: ["Ali", ["Can", "Ece"]]Yalnızca * yazıp ad vermezseniz argümanlar yok sayılır ya da (Ruby 3.2 ve sonrasında) başka bir metoda aynen aktarılabilir. Bu anonim yönlendirme ayrıntısı keyword argümanları yazısında anlatılıyor.
Endless metot tanımı: tek satırlık def
Belgelere göre Ruby 3.0 ile, tek bir ifadeden oluşan metotlar için kısa bir yazım geldi: def ad(parametre) = ifade. Ruby 3.0 NEWS dosyası bu özelliği eklendiği sürümde deneysel olarak işaretlemişti. Ruby 3.1 NEWS dosyası ise bu yazımda komut biçiminin de kullanılabildiğini, yani def foo = puts "Hello" yazılabildiğini, buna karşın private def foo = puts "Hello" satırının ayrıştırılamadığını not eder.
def kare(x) = x * x
def bos? = true
p kare(7) # çıktı: 49
p bos? # çıktı: trueBu yazımın iki kuralı var. Birincisi, parametre varsa parantez zorunludur: def ekle(deger) = deger + 1 geçerlidir, def ekle deger = deger + 1 ise SyntaxError verir. İkincisi, atama metotları (deger=) bu kısa yazımla tanımlanamaz.
Tekil metotlar ve metot içinde rescue
Metodu belirli bir nesneye de ekleyebilirsiniz. def nesne.ad yazımı yalnızca o nesneye ait bir "singleton method" üretir; aynı sınıftaki diğer nesnelerde bu metot olmaz. Sınıf metodu dediğimiz def self.ad da aslında bunun özel bir durumudur. Ayrıca her metot gövdesi örtük bir hata yakalama bloğu gibi davranır: begin yazmadan doğrudan rescue, else ve ensure ekleyebilirsiniz.
metin = "Ruby"
def metin.cerceve
"[#{self}]"
end
p metin.cerceve # çıktı: "[Ruby]"
p "Python".respond_to?(:cerceve) # çıktı: false
def guvenli_bol(a, b)
a / b
rescue ZeroDivisionError
:hata
ensure
puts "bitti"
end
p guvenli_bol(6, 3) # çıktı: bitti
# çıktı: 2
p guvenli_bol(6, 0) # çıktı: bitti
# çıktı: :hataensure bölümü her durumda çalışır ama metodun dönüş değerini değiştirmez; dönüş değeri gövdeden ya da rescue bölümünden gelir. Hata yönetiminin ayrıntıları için begin, rescue ve ensure yazısına bakın. Sınıf içindeki metotlar ve görünürlük için de class ve nesneler ile public, private ve protected yazıları var.
Parametre türleri bir bakışta

| Yazım | Anlamı | Çağrı örneği |
|---|---|---|
| def f(a) | Zorunlu konumsal parametre | f(1) |
| def f(a = 1) | Varsayılan değerli parametre | f veya f(5) |
| def f(*a) | Kalan konumsal argümanları dizi olarak toplar | f(1, 2, 3) |
| def f((a, b)) | Gelen diziyi parçalarına ayırır | f([1, 2]) |
| def f(*) | Adsız splat, yok sayar veya aktarır | f(1, 2) |
| def f(a:) | Zorunlu keyword (ayrı yazıda) | f(a: 1) |
| def f(&b) | Bloğu Proc olarak alır (ayrı yazıda) | f { } |
| def f(x) = x * 2 | Endless (tek satırlık) tanım | f(3) |
Sık yapılan hatalar
- Eksik argümanla çağırmak. Zorunlu parametre sayısı tutmazsa
ArgumentErroralırsınız; mesajda kaç argüman verildiği ve kaç tane beklendiği yazar. - Varsayılan değerde sonraki parametreye başvurmak. Parametreler soldan sağa değerlendirildiği için
def ters(a = b, b = 1)çağrıldığındabhenüz tanımlı değildir veNameErroroluşur. - Varsayılanlı parametreleri bölmek.
def f(a = 1, b, c = 1)sözdizimi hatasıdır; varsayılanlılar bir arada durmalıdır. - Endless tanımda parantezi unutmak.
def ekle deger = deger + 1geçersizdir. - Atama metodunun dönüş değerine güvenmek.
nesne.x = 5ifadesi her zaman 5 değerini verir.
def iki(a, b) = a + b
begin
iki(1)
rescue ArgumentError => e
puts "#{e.class}: #{e.message}"
end
# çıktı: ArgumentError: wrong number of arguments (given 1, expected 2)
def ters(a = b, b = 1)
a + b
end
begin
ters
rescue NameError => e
puts "#{e.class}: #{e.message}"
end
# çıktı: NameError: undefined local variable or method 'b' for mainRuby 4.0 NEWS dosyasına göre ArgumentError oluştuğunda ErrorHighlight artık hem çağrının yapıldığı satırı hem de metodun tanımlandığı satırı kod parçası olarak gösteriyor. Bu sayede yanlış sayıda argümanla yapılan çağrıları terminalde daha kolay bulursunuz.
Sık Sorulan Sorular
Ruby'de return yazmak zorunlu mu?
Hayır. Metot son değerlendirilen ifadeyi döndürür. return yalnızca metottan erken çıkmak ya da dönüşü açıkça göstermek istediğinizde gereklidir.
Metot çağırırken parantez kullanmalı mıyım?
Çoğu durumda parantez isteğe bağlıdır. Ancak iç içe çağrılarda belirsizlik oluşabilir; belgeler method_one argument1, method_two argument2, argument3 gibi bir satırın SyntaxError verdiğini gösterir. Argüman varken parantez kullanmak bu tür sorunları önler.
Endless metot ne zaman kullanılmalı?
Gövdesi tek bir ifade olan kısa metotlarda, örneğin hesaplama ya da basit sorgu metotlarında. Birden fazla adım, rescue ya da atama metodu gerekiyorsa klasik def ... end yazımı gerekir veya daha okunur olur.
Bir metot birden fazla değer döndürebilir mi?
Doğrudan değil, ama bir dizi döndürüp çoklu atamayla açabilirsiniz: ad, diger = ayir([...]). Çoklu atamanın ayrıntıları için değişkenler ve sabitler yazısına bakabilirsiniz.
Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.
İlgili içerikler: Ruby öğrenme rehberi · Keyword argümanları · Blok ve yield · Proc ve lambda farkı · Hata yönetimi · Ruby nedir?