Ruby'de metotların üç görünürlük düzeyi vardır. public varsayılandır ve metot her yerden çağrılabilir. private metot yalnızca sınıfın içinden, alıcı yazmadan ya da alıcı olarak doğrudan self yazılarak çağrılabilir. protected metot ise aynı sınıftan (ya da alt sınıflarından) bir nesnenin, başka bir nesne üzerinde çağırabileceği metottur. Kurala uymayan her çağrı NoMethodError verir.
Bu yazıda üç düzeyi, Ruby 2.7 ile değişen self.metot kuralını, sabitleri gizleyen private_constant'ı, yapıcıyı gizleyen private_class_method'u ve görünürlüğü atlayan send ile atlamayan public_send farkını Ruby 4.0.9'da çalıştırılmış örneklerle anlatıyoruz. Sınıf ve modül temelleri için Ruby class yazısına ve Ruby module yazısına bakabilirsiniz.
private: üç yazım biçimi

Argümansız private yazdığınızda ondan sonra tanımlanan bütün metotlar private olur. private :ad var olan bir metodu private yapar. def ifadesi metot adını sembol olarak döndürdüğü için private def ad biçimi de çalışır.
class Sifreleyici
def kaydet(parola)
"kaydedildi: #{ozet(parola)}"
end
private
def ozet(metin)
metin.reverse
end
end
s = Sifreleyici.new
p s.kaydet("abc123") # çıktı: "kaydedildi: 321cba"
s.ozet("abc")
# NoMethodError: private method 'ozet' called for an instance of Sifreleyici
p Sifreleyici.private_instance_methods(false) # çıktı: [:ozet]
p Sifreleyici.public_instance_methods(false) # çıktı: [:kaydet]
class Rapor
private def hesapla = 42
def sonuc = hesapla
end
p Rapor.new.sonuc # çıktı: 42private metot ve self: hangi çağrı geçerli?
Belgelerdeki kural şu: private metot alıcı olmadan ya da alıcı olarak doğrudan yazılmış self ile çağrılabilir. Ruby 2.7 NEWS dosyası, private metodu self.metot biçiminde çağırmaya izin verilmesinin o sürümde geldiğini belirtiyor. Ancak self'i bir değişkene atayıp o değişken üzerinden çağırmak ya da aynı sınıftan başka bir nesne üzerinde çağırmak hâlâ yasak:
class A
def receiversiz = m
def self_ile = self.m
def baska_nesne = A.new.m
def kopya_ile
kopya = self
kopya.m
end
private
def m = 1
end
a = A.new
p a.receiversiz # çıktı: 1
p a.self_ile # çıktı: 1
a.baska_nesne
# NoMethodError: private method 'm' called for an instance of A
a.kopya_ile
# NoMethodError: private method 'm' called for an instance of ABu kural private yazıcılar için de önemlidir. Bir metodun içinde mod = "test" yazarsanız Ruby bunu yerel değişken ataması sayar; private mod= yazıcısını çağırmak için self.mod = "test" yazmanız gerekir. attr_accessor tanımladığı metot adlarını dizi olarak döndürdüğü için private attr_accessor :mod yazımı da çalışır:
class Ayarlar
def initialize
self.mod = "test"
end
def goster = mod
private attr_accessor :mod
end
p Ayarlar.new.goster # çıktı: "test"
p Ayarlar.private_instance_methods(false).sort # çıktı: [:initialize, :mod, :mod=]Çıktıda initialize metodunun da listelendiğine dikkat edin: Ruby bu metodu kendiliğinden private yapar, bu yüzden nesne.initialize diye çağrılamaz.
Alt sınıflar private metotları görebilir
Java gibi dillerden gelenler için şaşırtıcı bir nokta: Ruby'de alt sınıf, üst sınıfın private metotlarını alıcı yazmadan çağırabilir. Module#protected belgesi bunu açıkça belirtiyor. Yani Ruby'deki private, sınıf hiyerarşisini değil alıcıyı sınırlar.
class Ebeveyn
private
def gizli = "ebeveynin private metodu"
end
class Cocuk < Ebeveyn
def goster = gizli
end
p Cocuk.new.goster # çıktı: "ebeveynin private metodu"protected: aynı türden nesneler arasında

protected metot, metodu çağıran kod aynı sınıfın (ya da bir alt sınıfın) içindeyse başka bir nesne üzerinde de çağrılabilir. En yaygın kullanımı, iç durumu herkese açmadan iki nesneyi karşılaştırmaktır. Aşağıda bakiye dışarıdan okunamıyor ama > metodu içinde diger.bakiye çağrısı geçerli:
class Hesap
attr_reader :bakiye
protected :bakiye
def initialize(bakiye)
@bakiye = bakiye
end
def >(diger)
bakiye > diger.bakiye
end
end
h1 = Hesap.new(100)
h2 = Hesap.new(50)
p h1 > h2 # çıktı: true
h1.bakiye
# NoMethodError: protected method 'bakiye' called for an instance of Hesap
class Musteri
def zengin_mi?(hesap) = hesap.bakiye > 75
end
Musteri.new.zengin_mi?(h1)
# NoMethodError: protected method 'bakiye' called for an instance of HesapMusteri sınıfı Hesap'tan türemediği için onun içinden yapılan çağrı reddedildi. Belgeler ayrıca protected metotların satır içi önbelleği kullanamadığı için diğerlerinden yavaş olduğunu not ediyor; bu yüzden yalnızca gerçekten gerektiğinde tercih edilmesi mantıklı.
| Görünürlük | Alıcısız çağrı | self.metot | Başka nesne üzerinde | Sınıf dışından |
|---|---|---|---|---|
| public | Evet | Evet | Evet | Evet |
| protected | Evet | Evet | Aynı sınıf ailesinin içinden evet | Hayır |
| private | Evet | Evet (Ruby 2.7 ve sonrası) | Hayır | Hayır |
private_class_method ve private_constant
Görünürlük yalnızca instance metotları için değildir. private_class_method :new sınıfın yapıcısını gizler; nesneyi yalnızca sizin yazdığınız bir fabrika metodu üretebilir. private_constant ise bir sabite sınıf dışından Sinif::SABIT biçiminde erişilmesini engeller; sınıfın içindeki kod sabiti kullanmaya devam eder.
class Baglanti
private_class_method :new
def self.ac(adres)
new(adres)
end
def initialize(adres)
@adres = adres
end
end
p Baglanti.ac("db.local").instance_variable_get(:@adres) # çıktı: "db.local"
Baglanti.new("x")
# NoMethodError: private method 'new' called for class Baglanti
class Odeme
API_ANAHTARI = "sk_test_123"
private_constant :API_ANAHTARI
SURUM = "v2"
def self.baslik = "Bearer #{API_ANAHTARI}"
end
p Odeme.baslik # çıktı: "Bearer sk_test_123"
p Odeme::SURUM # çıktı: "v2"
p Odeme.constants # çıktı: [:SURUM]
Odeme::API_ANAHTARI
# NameError: private constant Odeme::API_ANAHTARI referencedsend ve public_send farkı
send metot adını sembol ya da string olarak alıp o metodu çağırır ve görünürlüğe bakmaz. public_send ise yalnızca public metotları çağırır; private bir metoda ulaşmaya çalışırsa normal çağrıdaki gibi NoMethodError verir. Metot adı kullanıcıdan ya da dışarıdan gelen bir veriden üretiliyorsa public_send kullanmak, private metotların istemeden açılmasını önler.
class Kasa
def bakiye = 500
private
def sifre = "1234"
end
k = Kasa.new
p k.send(:bakiye) # çıktı: 500
p k.send(:sifre) # çıktı: "1234"
p k.public_send(:bakiye) # çıktı: 500
k.public_send(:sifre)
# NoMethodError: private method 'sifre' called for an instance of Kasa
p k.respond_to?(:sifre) # çıktı: false
p k.respond_to?(:sifre, true) # çıktı: true
p k.__send__("bakiye") # çıktı: 500respond_to? varsayılan olarak private ve protected metotları saymaz; ikinci argümana true verirseniz onları da hesaba katar. Belgeler, nesnenin kendi send adlı bir metodu olabileceği durumlar için BasicObject'in tanımladığı __send__ adını daha güvenli seçenek olarak gösteriyor.
Sık yapılan hatalar

- private yazıcıyı self olmadan çağırmak:
mod = 1yerel değişken oluşturur;self.mod = 1yazın. - private'ı Java'daki gibi düşünmek: Alt sınıflar private metotları çağırabilir; sınırlanan şey alıcıdır.
- Dış veriyle send kullanmak:
nesne.send(params[:islem])gibi bir çağrı private metotları da açar;public_sendve bir izin listesi kullanın. - private'ın sınıf metotlarını etkilediğini sanmak: Argümansız
privatesatırıdef self.xile tanımlanan sınıf metotlarını private yapmaz. Bunun içinprivate_class_methodkullanılır.
Sık Sorulan Sorular
private metodu test etmek için nasıl çağırırım?
send görünürlüğe bakmadığı için private metodu doğrudan çağırabilir. Yine de genellikle private metotları onları kullanan public metotlar üzerinden test etmek daha sağlıklıdır.
Görünürlüğü sonradan değiştirebilir miyim?
Evet. public :ad, private :ad ve protected :ad var olan metotların görünürlüğünü değiştirir. Belgelere göre tek argüman verildiğinde aynı argüman, birden fazla verildiğinde dizi döndürülür.
Modül fonksiyonları neden private görünüyor?
module_function ile tanımlanan metotların mixin kopyası private yapılır. Ayrıntılar Ruby module yazısında.
Karşılaştırma metotlarında protected yerine ne kullanılabilir?
Karşılaştırma için çoğu zaman <=> tanımlayıp Comparable eklemek yeterlidir. Bu yaklaşım Comparable ve Enumerable 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 class ve nesneler · Ruby modülleri · Ruby metot tanımlama · Comparable ve Enumerable · begin, rescue, ensure