Ruby'de bir sınıf class Ad ... end bloğuyla tanımlanır; Ad.new(...) çağrısı yeni bir nesne oluşturur ve ona verdiğiniz argümanlarla initialize metodunu çalıştırır. Nesnenin verisi @ad gibi instance değişkenlerinde durur. Bu değişkenleri dışarıya açmak için attr_reader (okuma), attr_writer (yazma) ve attr_accessor (ikisi birden) kullanılır. Bir sınıf başka bir sınıftan < ile türetilir ve üst sınıftaki aynı adlı metot super ile çağrılır.
Bu yazıda sınıf tanımlamayı, instance metodu ile sınıf metodu farkını, kalıtımı, super kullanımının üç biçimini ve nesnenin ekranda nasıl göründüğünü belirleyen to_s ile inspect metotlarını Ruby 4.0.9 ile çalıştırılmış örneklerle anlatıyoruz. Ruby'nin ne olduğunu ve nerede kullanıldığını merak ediyorsanız önce Ruby nedir yazısına, metot tanımlamanın temelleri için Ruby metot tanımlama rehberine bakabilirsiniz.
Sınıf tanımlamak, initialize ve attr metotları

Aşağıdaki Urun sınıfı üç bilgi tutuyor. initialize içinde argümanları instance değişkenlerine yazıyoruz. attr_reader :ad yalnızca ad okuyucusunu, attr_accessor :fiyat hem fiyat hem fiyat= metotlarını, attr_writer :stok ise yalnızca stok= yazıcısını üretir.
class Urun
attr_reader :ad
attr_accessor :fiyat
attr_writer :stok
def initialize(ad, fiyat, stok = 0)
@ad = ad
@fiyat = fiyat
@stok = stok
end
def stokta_var_mi?
@stok > 0
end
end
klavye = Urun.new("Klavye", 750)
p klavye.ad # çıktı: "Klavye"
klavye.fiyat = 690
p klavye.fiyat # çıktı: 690
p klavye.stokta_var_mi? # çıktı: false
klavye.stok = 3
p klavye.stokta_var_mi? # çıktı: true
p klavye.instance_variables # çıktı: [:@ad, :@fiyat, :@stok]
klavye.ad = "Fare"
# NoMethodError: undefined method 'ad=' for an instance of Urun
klavye.stok
# NoMethodError: undefined method 'stok' for an instance of UrunHata mesajları bu üç metodun farkını özetliyor: ad için yazıcı, stok için okuyucu üretilmediği için çağrılar NoMethodError veriyor. Instance değişkenleri dışarıdan doğrudan görülmez; nesnenin verisine yalnızca tanımladığınız metotlar üzerinden erişilir.
Ruby 3.0'dan beri attr_accessor, attr_reader ve attr_writer tanımladıkları metot adlarını bir dizi olarak döndürür. Bu küçük ayrıntı, ileride göreceğiniz private attr_accessor :x yazımını mümkün kılar:
class Ornek
p attr_accessor(:a, :b) # çıktı: [:a, :a=, :b, :b=]
p attr_reader(:c) # çıktı: [:c]
end| Metot | Ürettiği metotlar | Ne zaman |
|---|---|---|
| attr_reader :ad | ad | Değer dışarıdan okunacak ama değiştirilmeyecekse |
| attr_writer :stok | stok= | Değer yalnızca dışarıdan atanacaksa (seyrek) |
| attr_accessor :fiyat | fiyat ve fiyat= | Hem okunup hem yazılacaksa |
| attr :ad | ad | attr_reader ile aynı (tek argümanlı biçim) |
Instance metodu ve sınıf metodu
def ad ile tanımlanan metot o sınıftan üretilen her nesnede çalışır; buna instance metodu denir. def self.ad ile tanımlanan metot ise sınıf nesnesinin kendisine aittir ve Siparis.ad biçiminde çağrılır. Ruby'de sınıflar da birer nesnedir: Urun.class ifadesi Class döndürür. Birden fazla sınıf metodunu bir arada yazmak isterseniz class << self bloğunu kullanabilirsiniz; bu blok sınıfın singleton sınıfını açar.
class Siparis
KDV = 20
@adet = 0
class << self
attr_reader :adet
def olustur(tutar)
@adet += 1
new(tutar)
end
end
def self.kdv_dahil(tutar)
tutar + tutar * KDV / 100
end
attr_reader :tutar
def initialize(tutar)
@tutar = tutar
end
def toplam
self.class.kdv_dahil(tutar)
end
end
s1 = Siparis.olustur(100)
s2 = Siparis.olustur(250)
p Siparis.adet # çıktı: 2
p Siparis.kdv_dahil(50) # çıktı: 60
p s2.toplam # çıktı: 300
p Siparis.singleton_methods.sort # çıktı: [:adet, :kdv_dahil, :olustur]
s1.olustur(10)
# NoMethodError: undefined method 'olustur' for an instance of SiparisBurada dikkat edilecek nokta, sınıf gövdesinde yazılan @adet = 0 satırının nesnelere değil sınıf nesnesine ait bir instance değişkeni oluşturmasıdır. Instance metodu içinden sınıf metoduna ulaşmak için self.class.kdv_dahil yazıyoruz. Sınıf metodu nesne üzerinden çağrılamaz; son satırdaki hata bunu gösteriyor.
Kalıtım ve super
class VadeliHesap < Hesap yazdığınızda VadeliHesap, Hesap sınıfındaki metotları ve sabitleri devralır. Üst sınıf belirtmezseniz sınıf Object'ten türer. Alt sınıfta aynı adla bir metot yazarsanız üsttekinin yerine o çalışır; üsttekini de kullanmak istediğinizde super çağırırsınız.
class Hesap
attr_reader :sahip, :bakiye
def initialize(sahip, bakiye)
@sahip = sahip
@bakiye = bakiye
end
def ozet
"#{sahip}: #{bakiye} TL"
end
end
class VadeliHesap < Hesap
def initialize(sahip, bakiye, faiz)
super(sahip, bakiye)
@faiz = faiz
end
def ozet
super + " (yıllık faiz %#{@faiz})"
end
end
v = VadeliHesap.new("Ayşe", 1000, 40)
puts v.ozet # çıktı: Ayşe: 1000 TL (yıllık faiz %40)
p VadeliHesap.superclass # çıktı: Hesap
p VadeliHesap.ancestors # çıktı: [VadeliHesap, Hesap, Object, Kernel, BasicObject]
p v.is_a?(Hesap) # çıktı: true
p v.instance_of?(Hesap) # çıktı: false
p Hesap.subclasses # çıktı: [VadeliHesap]is_a? kalıtım zincirinin tamamına bakarken instance_of? yalnızca nesnenin doğrudan sınıfını kontrol eder. ancestors listesi, Ruby'nin bir metodu ararken hangi sırayla sınıflara ve modüllere baktığını gösterir. Bu listeye modüllerin nasıl girdiğini Ruby module, include, extend ve prepend yazısında ayrıntılı anlatıyoruz.
super, super() ve super(arg) farkı
Belgelere göre parantezsiz super, alt sınıf metoduna gelen argümanların aynısını üst sınıfa iletir. super() hiç argüman göndermez, super(2) ise yalnızca sizin yazdığınızı gönderir. Bu fark, üst ve alt metodun parametre sayısı farklı olduğunda önem kazanır:
class A
def selam(ad)
"Merhaba #{ad}"
end
end
class B < A
def selam(ad)
super + "!" # ad otomatik olarak iletilir
end
end
class C < A
def selam(ad)
super() # hiç argüman gönderilmez
end
end
p B.new.selam("Can") # çıktı: "Merhaba Can!"
C.new.selam("Can")
# ArgumentError: wrong number of arguments (given 0, expected 1)Yukarıdaki VadeliHesap#initialize örneğinde üç parametre alıp üst sınıfa yalnızca ikisini göndermemiz gerektiği için super(sahip, bakiye) yazdık. Parantezsiz super kullansaydık üç argüman iletilir ve ArgumentError oluşurdu.
to_s ve inspect: nesne nasıl görünür?
puts ve string içine gömme ("#{nesne}") nesnenin to_s metodunu, p ise inspect metodunu kullanır. Varsayılan inspect sınıf adını, bellek adresini temsil eden bir değeri ve instance değişkenlerini gösterir. Kendi sınıflarınızda bu iki metodu ezerek daha okunur bir çıktı elde edebilirsiniz.
class Musteri
def initialize(ad, sehir)
@ad = ad
@sehir = sehir
end
def to_s
"#{@ad} (#{@sehir})"
end
def inspect
"#<Musteri #{@ad}>"
end
end
m = Musteri.new("Elif", "İzmir")
puts m # çıktı: Elif (İzmir)
puts "Müşteri: #{m}" # çıktı: Müşteri: Elif (İzmir)
p m # çıktı: #<Musteri Elif>
p [m, m] # çıktı: [#<Musteri Elif>, #<Musteri Elif>]Ruby 4.0 ile gelen bir yenilik, varsayılan inspect çıktısına hangi instance değişkenlerinin gireceğini seçebilmenizdir. NEWS dosyasına göre Kernel#inspect artık nesnede instance_variables_to_inspect metodu olup olmadığına bakıyor. Parola gibi hassas alanları günlüklerden uzak tutmak için kullanışlı:
class Ayar
def initialize(host, kullanici, parola)
@host = host
@kullanici = kullanici
@parola = parola
end
private
def instance_variables_to_inspect = [:@host, :@kullanici]
end
p Ayar.new("localhost", "root", "s3cr3t")
# çıktı: #<Ayar:0x... @host="localhost", @kullanici="root">Sık yapılan hatalar

- Yazıcı yerine yerel değişken oluşturmak: Metot içinde
deger = 5yazmakdeger=metodunu çağırmaz, yeni bir yerel değişken oluşturur. Yazıcıyı çağırmak içinself.deger = 5yazmanız gerekir. - initialize metodunu dışarıdan çağırmaya çalışmak:
initializeprivate bir metottur;nesne.initializeçağrısıNoMethodErrorverir. Nesne oluşturmak için her zamannewkullanılır. - Yeniden açılan sınıfa farklı üst sınıf vermek: Sınıflar sonradan yeniden açılabilir, ama ilk tanımdan farklı bir üst sınıf yazarsanız
TypeError: superclass mismatchalırsınız. - Sahibi olmadığınız sınıfları yeniden açmak: Belgeler bunun ad çakışmalarına ve zor bulunan hatalara yol açabileceği konusunda uyarıyor. Daha güvenli bir yol için Ruby refinements yazısına bakın.
class Sayac
attr_accessor :deger
def initialize
@deger = 0
end
def hatali_artir
deger = deger.to_i + 1 # yerel değişken, @deger değişmez
end
def dogru_artir
self.deger += 1
end
end
s = Sayac.new
s.hatali_artir
p s.deger # çıktı: 0
s.dogru_artir
p s.deger # çıktı: 1
s.initialize
# NoMethodError: private method 'initialize' called for an instance of Sayac
class C; end
class D < C; end
class D < String; end
# TypeError: superclass mismatch for class DSık Sorulan Sorular
Ruby'de her şey nesne mi?
Belgelerdeki tanımla, Ruby'de sınıflar da Class sınıfının örnekleridir; yani sınıfın kendisi de bir nesnedir. Bu yüzden sınıflara metot tanımlayabilir, onları değişkene atayabilir ve Class.new ile isimsiz sınıflar oluşturabilirsiniz.
Sınıf adı neden büyük harfle başlıyor?
class Urun yazdığınızda oluşan sınıf nesnesi Urun adlı bir sabite atanır. Ruby'de sabitler büyük harfle başlar; sabit kuralları için değişkenler ve sabitler yazısına bakabilirsiniz.
Sadece tek bir nesneye metot ekleyebilir miyim?
Evet. def nesne.metot ya da class << nesne yazdığınızda metot o nesnenin singleton sınıfına eklenir ve aynı sınıftaki diğer nesnelerde bulunmaz. Denememizde o.singleton_methods yalnızca bu metodu listeledi.
Çoklu kalıtım var mı?
Hayır, bir sınıfın tek bir üst sınıfı olur. Birden fazla yerden davranış almak için modüller include edilir. Sınıflar da modüldür ama bir sınıf başka bir sınıfa mixin olarak eklenemez.
Metotları gizlemek için ne yapmalıyım?
private ve protected anahtar sözcükleri metotların kimin tarafından çağrılabileceğini sınırlar. Kurallar ve tuzaklar Ruby public, private ve protected yazısında anlatılıyor.
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 · Ruby metot tanımlama · Ruby modülleri · public, private, protected · Struct ve Data · Ruby nedir