---
title: 'Eksik Yöntem Yakalama'
source: 'https://academia.sh/tr/kurslar/ruby-nesne-yonelimi/eksik-yontem-yakalama'
course: 'Nesne Yönelimi ve Metaprogramlama'
language: tr
updated: '2026-10-21T05:03:42+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'method_missing ile tanımı olmayan bir iletiyi yakalayan vekil nesne yazar'
    - 'Yakalanan yöntemin yansıma sorularında neden görünmediğini ölçer'
    - 'respond_to_missing? ile yansımayı yakalama davranışıyla uyumlu hale getirir'
    - 'Yakalanan ilk çağrıda yöntem tanımlayan vekilde kimse yazanının kalıcı olmadığını gösterir'
---

# Eksik Yöntem Yakalama

Hiçbir tanımı olmayan bir iletiyi method_missing ile yakalayan vekil nesnenin ölçümü ve bu yakalamanın yansıma sorularında bıraktığı boşluklar.

Önceki ders, bir yöntemin `define_method` ile çalışma zamanında tanımlandığını ve yazanının **kod** olduğunu ölçtü. Orada her ad, çağrılmadan önce tanımlanmıştı. Bu ders tersini sorar: çağrılan ada hiçbir tanım yoksa Ruby ne yapar? Varsayılan cevap `NoMethodError`'dır. Ama bir sınıf bu boşluğu kendisi doldurabilir. **Eksik yöntem yakalama (method_missing)**, bir nesneye gönderilen ve yöntem arama zincirinde hiçbir tanım bulamayan iletinin, hata vermeden önce nesnenin kendi `method_missing` yöntemine teslim edilmesidir. Ruby'de bu yöntemin adı koddur ve olduğu gibi yazılır.

Eksen yine aynı: **bu yöntemi kim yazdı?** Bu dersin yazanı **kimse**. Çağrılan ada bir tanım yoktur; ileti yine de cevap alır, çünkü bir başka yöntem onu yakalar. Yazan yardımcısı için bu, dört kategorinin sonuncusudur ve aşağıda neden burada kullanıldığı görülecek. Önce yardımcı, önceki derslerle aynı biçimde verilir.

```ruby
# yazan.rb — bir yontemi kimin yazdigini siniflandiran yardimci

# Siniflandirma sirayla sorar: once alicinin zincirinde bir tanim var mi,
# sonra tanimi alicinin kendi sinifi mi tasiyor, sonra tanim nasil uretildi.
def yazan(alici, ad)
  zincir = alici.singleton_class
  unless zincir.method_defined?(ad) || zincir.private_method_defined?(ad)
    return ["kimse", "tanim yok"]
  end

  tanim = zincir.instance_method(ad)
  sahip = tanim.owner
  yer = sahip == zincir ? "tekil sinif" : sahip.to_s
  return ["ata", yer] unless sahip == alici.class || sahip == zincir

  iz = RubyVM::InstructionSequence.of(tanim)
  return ["kod", "#{yer}, ruby govdesi yok"] if iz.nil?
  return ["kod", "#{yer}, blok govdesi"] if iz.label.start_with?("block")

  ["programci", "#{yer}, def govdesi"]
end
```

Bu blok kaynaktır; dosya diske yazılır ve `require_relative` ile çekilir.

## Ölçülen Sınıf

Bu dersin gözlemi bir **vekil nesne (proxy)** üzerindedir: başka bir nesneyi sarmalayan ve ona gelen iletileri o nesneye ileten nesne. `Vekil`, sarmaladığı nesnenin yöntemlerinin hiçbirini kendisi tanımlamaz.

```ruby
# yazanlar.rb — bu dersin gozlemi icin gereken tanim
require_relative "yazan"

class Vekil
  def initialize(hedef)
    @hedef = hedef
  end

  def method_missing(ad, *argumanlar, &blok)
    return super unless @hedef.respond_to?(ad)

    @hedef.public_send(ad, *argumanlar, &blok)
  end

  def respond_to_missing?(ad, ozel = false) = @hedef.respond_to?(ad, ozel) || super
end
```

Bu blok de kaynaktır. `method_missing` üç şey alır: iletinin adı, argümanlar ve varsa blok. İlk satır, sarmalanan nesne o iletiyi anlamıyorsa `super` ile Ruby'nin varsayılan davranışına, yani `NoMethodError`'a bırakır. Anlıyorsa iletiyi aynı argümanlarla ve aynı blokla `public_send` ile ona iletir. `respond_to_missing?` ikinci yöntemdir; ne işe yaradığı birazdan ölçülecek.

## Tanımsız Yöntemi Kim Yazdı

Bu dersin gözlemi `Vekil` nesnesinin `sort` yöntemidir. Nesne bir diziyi sarmalar; `Vekil` sınıfında `sort` adlı bir tanım yoktur.

```ruby
# vekil.rb — Vekil#sort yontemini kim yazdi
require_relative "yazanlar"

vk = Vekil.new([3, 1, 2])
p yazan(vk, :sort)
p vk.sort
```
```
["kimse", "tanim yok"]
[1, 2, 3]
```

Yazan **kimse**: `yazan` yardımcısı alıcının zincirinde `sort` için bir tanım bulamadı ve ilk soruda durdu. Yine de `vk.sort` çalıştı ve `[1, 2, 3]` verdi. Yani çalışan bir yöntem var, ama yöntem arama zincirinde yok. Çalıştıran şey `method_missing`'dir; o, iletiyi dizinin kendi `sort` yöntemine iletir. Bu çelişki dersin konusudur: yazan kimse olabilir ve yanıt yine de gelir. **MP19.** Bu ölçüm tek bir ileti içindir; `Vekil`'in diğer iletileri aşağıda ayrıca ölçülür.

## Yakalanan İletiler

Vekil yalnız `sort`'a değil, zincirinde tanımı olmayan ve sarmalanan dizinin genel yöntemi olan iletilere cevap verir. Aşağıdaki ölçüm üç ileti dener: biri argümansız, biri başka bir türde sonuç veren, biri blok alan.

```ruby
# yakala.rb — vekilin iletisi yakalamasi
require_relative "yazanlar"

vk = Vekil.new([3, 1, 2])
p vk.sort
p vk.size
p vk.map { |x| x * 10 }
```
```
[1, 2, 3]
3
[30, 10, 20]
```

`sort` sıralı diziyi, `size` uzunluğu verdi. `map` blok aldı: `method_missing` bloğu `&blok` ile yakaladı ve `public_send`'e geçirdi, böylece dizi her elemanı on ile çarptı. Vekil, bu üç iletinin hiçbirini tanımlamadan cevap verdi. **MP20.** Bu ölçüm yalnız üç ileti içindir; zincirde tanımı olmayan dizi yöntemleri aynı şekilde geçer, ama bu üçünden fazlası burada görülmedi; zincirde tanımı olan adlar aşağıda ayrıca ölçülür.

## Argümanlar ve Blok

Üç ileti `method_missing` imzasının yarısını gösterdi. Argümanların ve bloğun birlikte aktarılması ayrıca ölçülmeli, çünkü `*argumanlar` ve `&blok` yazılmazsa iletinin parçaları sessizce düşer.

```ruby
# aktar.rb — argumanlarin ve blogun aktarilmasi
require_relative "yazanlar"

vk = Vekil.new([3, 1, 2])
p vk.first(2)
p vk.inject(10) { |toplam, x| toplam + x }
p vk.each_slice(2).to_a
```
```
[3, 1]
16
[[3, 1], [2]]
```

`first(2)` argümanı, `inject(10) { ... }` hem argümanı hem bloğu, `each_slice(2)` ise blok olmadan bir sayaç nesnesi döndürdü ve `to_a` onu açtı. Üçü de dizinin kendi çağrısıyla aynı sonucu verdi: vekil iletiyi bozmadan taşıdı. Taşıma `public_send(ad, *argumanlar, &blok)` satırının işi; o satırda `*argumanlar` ya da `&blok` eksik olsaydı bu çağrılarda argüman ya da blok iletiye ulaşmaz, sonuç ya da hata değişirdi; bu derste denenmedi. **MP21.** Üç çağrı ölçüldü; anahtar sözcük argümanları bu derste denenmedi.

## Yansıma Ne Görür

Yansıma dersi, nesneye yöntemlerini sormanın yollarını verdi. Aşağıda vekile dört soru sorulur: `respond_to?`, `defined?`, `method(:sort).owner` ve sınıfın `method_defined?` sorusu.

```ruby
# sorgu.rb — vekile yansima ile sormak
require_relative "yazanlar"

vk = Vekil.new([3, 1, 2])
p vk.respond_to?(:sort)
p defined?(vk.sort)
p vk.method(:sort).owner
p Vekil.method_defined?(:sort)
p yazan(vk, :size)
```
```
true
"method"
Vekil
false
["kimse", "tanim yok"]
```

Cevaplar tutarsız görünür ve bunun gerekçesi `respond_to_missing?`'tir. Vekil yazılırken bu yöntem tanımlandığından `respond_to?` `true` verdi, `defined?` `"method"` döndürdü ve `method(:sort)` bir yöntem nesnesi üretti. Üretilen nesnenin sahibi `Vekil` çıktı, ama sınıfın tanım tablosuna sorulduğunda `Vekil.method_defined?(:sort)` `false` verdi. Yani `respond_to_missing?` yansımaya yakalamayı bildirir, ama tanım tablosuna bir kayıt eklemez. Yardımcı tanım tablosuna baktığı için `size` için de **kimse** dedi. Yansıma bir yönteme iki yoldan bakar: ileti cevaplanır mı, ve tanım var mı. Bu iki soru vekilde ayrışır. **MP22.** `respond_to_missing?` vekil tarafından tanımlandığı için bu cevaplar verildi; tanımlanmasaydı sonuç `Yansımaya Bildirmek` bölümünde ölçülür.

## Vekil Dizi Değildir

Vekil bir diziyi sarmalar, ama dizi değildir. Dizi gibi davranan bir nesnenin dizi olduğunu varsaymak tehlikelidir; aşağıdaki ölçüm bunun sınırlarını çizer.

```ruby
# kimlik.rb — vekil ve kimlik
require_relative "yazanlar"

vk = Vekil.new([3, 1, 2])
begin
  vk.sortt
rescue NoMethodError => e
  puts e.class
end
p vk.is_a?(Array)
p vk == [3, 1, 2]
p vk.class
p yazan(vk, :class)
```
```
NoMethodError
false
false
Vekil
["ata", "Kernel"]
```

Yanlış yazılmış `sortt` iletisi `NoMethodError` verdi: `method_missing` sarmalanan dizinin o iletiyi anlamadığını gördü ve `super` ile Ruby'nin varsayılanına bıraktı. `is_a?(Array)` `false` çıktı; vekil dizi değil, diziyi tutan bir nesne. `vk == [3, 1, 2]` de `false` verdi, çünkü `==` zincirde tanımı olan bir yöntemdir ve vekil onu yakalamaz: yakalama yalnız zincirde bulunmayan adlar için çalışır. `class` iletisi de bu yüzden yakalanmadı, `Vekil` döndü; yazanı Ruby 4.0.7'de **ata**, `Kernel`. Vekilin yakaladığı iletiler, zincirde hiç tanımı olmayanlardır. **MP23.** Bu bölümde yalnız `==`, `is_a?` ve `class` ölçüldü; `to_s` ayrı bir bölümde sınanır.

## Zincirdeki Adlar Yakalanmaz

Vekil Dizi Değildir bölümü `==` ve `class` için yakalamanın çalışmadığını gösterdi. Aynı kural `to_s` gibi her nesnede bulunan başka adlar için de geçerli olmalı. Yanında, zincirde olmayan `to_a` ile karşılaştırılır.

```ruby
# zincirdeki.rb — to_s ve to_a karsilastirmasi
require_relative "yazanlar"

vk = Vekil.new([3, 1, 2])
p vk.to_a
p vk.to_s == [3, 1, 2].to_s
p yazan(vk, :to_s)
p yazan(vk, :to_a)
```
```
[3, 1, 2]
false
["ata", "Kernel"]
["kimse", "tanim yok"]
```

`to_a` zincirde bulunmadığı için yakalandı ve diziyi verdi. `to_s` ise Ruby 4.0.7'de `Kernel`'den geldiği için yakalanmadı: vekilin metni dizinin metni değildir ve yazanı **ata**. İki ad dizi için aynı derecede olağan, ama vekil için biri **kimse**, öbürü **ata** çıktı. Bu fark vekilin sınırını çizer: sarmalanan nesnenin davranışını kopyalamak istiyorsanız, her nesnede hazır bulunan adlar ayrıca ele alınmalıdır. **MP24.** Ölçüm `to_s` ve `to_a` içindir; `inspect` ve `hash` gibi öbür hazır adlar aynı kurala uyar, ama ölçülmedi.

## Yakalayıcının Kendi Yazanı

Şimdiye kadar yakalanan ada baktık. Yakalayan yöntemin kendisi için de aynı soru sorulabilir: `method_missing` kimin?

```ruby
# yakalayici.rb — method_missing ve respond_to_missing? yazanlari
require_relative "yazanlar"

vk = Vekil.new([3, 1, 2])
p yazan(vk, :method_missing)
p yazan(vk, :respond_to_missing?)
p yazan(Object.new, :method_missing)
p BasicObject.private_method_defined?(:method_missing)
```
```
["programci", "Vekil, def govdesi"]
["programci", "Vekil, def govdesi"]
["ata", "BasicObject"]
true
```

Yakalanan `sort` kimse çıktı; yakalayan `method_missing` ise **programcı**: `Vekil` içinde `def` ile yazılmış, sahibi alıcının kendi sınıfı. Aynı soru sıradan bir `Object.new` için sorulunca Ruby 4.0.7'de yazan **ata**, `BasicObject` çıktı, ve son satır bu tanımın özel olduğunu söyledi. Yani her nesnenin zaten bir `method_missing` yöntemi vardır ve işi `NoMethodError` fırlatmaktır; `Vekil` bu yöntemi gölgeleyip kendi sürümünü koydu. Kimse yazanı bu yüzden bir boşluk değil, bir devir teslimdir: tanımı olmayan ad, tanımı olan bir yakalayıcıya düşer ve onun yazanı bellidir. **MP25.** Ölçüm yalnız `Vekil` ve `Object` için yapıldı; zincirde birden çok `method_missing` olduğunda `super`'ın hangisine ineceği bu derste sınanmadı.

## Özel Yöntem Aktarılmaz

Vekil iletiyi `public_send` ile taşıdığı ve önce `respond_to?` ile sorduğu için sarmalanan nesnenin özel yöntemleri vekilden çağrılamaz. Bu bir tasarım sonucudur ve ölçülebilir.

```ruby
# ozel.rb — ozel yontemin vekil uzerinden cagrilmasi
require_relative "yazanlar"

class Kutu
  def acik = "acik"

  private

  def sir = "sir"
end

vk = Vekil.new(Kutu.new)
p vk.acik
begin
  vk.sir
rescue NoMethodError => e
  puts e.class
end
p vk.respond_to?(:sir)
p vk.respond_to?(:sir, true)
```
```
"acik"
NoMethodError
false
true
```

Genel `acik` yöntemi geçti, özel `sir` `NoMethodError` verdi. Son iki satır birbirinden ayrılır. `respond_to?(:sir)` `false` verdi, çünkü `respond_to_missing?` ikinci argümanı hedefe aktarır ve varsayılan hâlde hedefin yalnız genel yöntemleri sayılır. `respond_to?(:sir, true)` ise `true` verdi: özel yöntemler de sorulunca `Kutu` nesnesi `sir`'i tanıdı. Yine de `vk.sir` çalışmadı. Yansıma ile çağrı burada ayrışır: yansıma "bu ada cevap verilebilir" diyebilir, ama çağrıyı taşıyan `public_send` özel yöntemi yine reddeder. Vekil sarmaladığı nesnenin genel yüzünü taşır, tamamını değil; bu bazen istenen sonuçtur, çünkü sarmalama özel ayrıntıları dışarıya sızdırmaz. **MP26.**

## Sessiz Yutma

`method_missing` yazarken `super` çağrısı unutulursa her ileti yakalanır ve hataya dönüşmez. Aşağıdaki sınıf `super` çağırmaz ve her iletiye `nil` döndürür.

```ruby
# sessiz.rb — super cagirmayan method_missing
class Sessiz
  def method_missing(*) = nil
end

s = Sessiz.new
p s.yazim_hatasi
p s.respond_to?(:yazim_hatasi)
```
```
nil
false
```

`yazim_hatasi` adı diye bir yöntem hiçbir yerde yok, ama çağrı `nil` döndürdü ve hata vermedi. Hata bildirimi, adı doğru yazdığımıza dair son güvencemizdi ve burada yutuldu. Bu yüzden `method_missing` yazarken tanımadığı iletiyi `super`'a bırakmak bir kuraldır, bir tercih değil. Ayrıca `respond_to?` `false` verdi: bu sınıf iletiyi cevaplıyor, ama yansımaya bunu bildirmiyor. **MP27.** Bu sınıf her iletiyi yuttuğundan hiçbir ad hata vermez; gerçek bir sınıfta yakalama bir önek ya da sarmalanan nesne gibi bir koşula bağlanır.

## Yansımaya Bildirmek

Yakalama koşullu olduğunda yansımayı da bilgilendirmek gerekir. Aşağıdaki sınıf `bul_` öneki ile başlayan adları yakalar; önce `respond_to_missing?` olmadan, sonra onunla ölçülür.

```ruby
# bulucu.rb — respond_to_missing? olmadan ve ile
class Bulucu
  def method_missing(ad, *)
    return super unless ad.start_with?("bul_")

    ad.to_s.delete_prefix("bul_")
  end
end

b = Bulucu.new
p b.bul_ece
p b.respond_to?(:bul_ece)
begin
  b.method(:bul_ece)
rescue NameError => e
  puts e.class
end

class Bulucu
  def respond_to_missing?(ad, ozel = false) = ad.start_with?("bul_") || super
end

p b.respond_to?(:bul_ece)
p b.method(:bul_ece).call
```
```
"ece"
false
NameError
true
"ece"
```

`bul_ece` iletisi `"ece"` verdi, ama `respond_to?` `false` çıktı ve `method(:bul_ece)` `NameError` fırlattı. Yani iletiyi cevaplayan bir nesne, yansımaya göre o yöntemi tanımıyordu. Sınıf `respond_to_missing?` ile yeniden açılınca iki soru da düzeldi: `respond_to?` `true`, `method(:bul_ece).call` ise `"ece"` verdi. Kural şudur: `method_missing` yazan, `respond_to_missing?` da yazmalıdır. Aksi hâlde nesne yansımadan saklanır. **MP28.** Önek koşulu yalnız `bul_` ile ölçüldü; `respond_to_missing?` ile yakalama koşulu aynı biçimde yazıldı, ayrı yazılırsa tutarsızlık doğabilir.

## Sınırlayıcı Ölçüm

Kimse yazanı kalıcı mı? Aşağıdaki sınıf yakaladığı her adı ilk çağrıda `define_method` ile gerçek bir yönteme çevirir. Böylece yakalama yalnız bir kez çalışır.

```ruby
# sinir.rb — kendini tanimlayan vekil
require_relative "yazanlar"

class Puan
  attr_reader :sayac

  def initialize
    @sayac = 0
  end

  def method_missing(ad, *)
    return super unless ad.start_with?("kare_")

    @sayac += 1
    n = ad.to_s.delete_prefix("kare_").to_i
    self.class.define_method(ad) { n * n }
    n * n
  end

  def respond_to_missing?(ad, ozel = false) = ad.start_with?("kare_") || super
end

pn = Puan.new
p [pn.kare_4, pn.kare_4, pn.kare_5, pn.sayac]
p yazan(pn, :kare_4)
p yazan(pn, :kare_9)
```
```
[16, 16, 25, 2]
["kod", "Puan, blok govdesi"]
["kimse", "tanim yok"]
```

`kare_4` iki kez çağrıldı ama `method_missing` yalnız bir kez çalıştı: ilk çağrıda yöntem tanımlandı, ikincisi doğrudan tanıma ulaştı. `sayac` iki oldu, çünkü `kare_4` ve `kare_5` birer kez yakalandı. Sonra `yazan` `kare_4`'ü **kod** olarak sınıflandırdı; artık yöntem bir bloktan üretilmiş gerçek bir tanımdır. Hiç çağrılmamış `kare_9` ise hâlâ **kimse**. Yani kimse yazanı kalıcı değil: aynı ad bir çağrıdan sonra koda dönüşebilir. Kategori adın değil, o anki tanım tablosunun özelliğidir. **MP29.** Tek bir sınıf ölçüldü; `define_method`'un `self.class` üzerinden çağrılması bir tasarım tercihidir ve tek örnek için tek yöntem tanımlamak da mümkündür.

## Özet

- Zincirde tanımı olmayan bir ileti nesnenin `method_missing` yöntemine teslim edilir; `Vekil` bu yolla sarmaladığı diziye gelen iletiyi iletir.
- Yakalanan adların yazanı kimsedir: `yazan` yardımcısı tanım tablosunda ad bulamaz, ama ileti yine cevaplanır; yakalayan `method_missing` ise programcıdır ve `BasicObject`'teki özel varsayılanı gölgeler.
- `respond_to_missing?` yansımaya yakalamayı bildirir; `Vekil.method_defined?` ise yine `false` kalır.
- `super` çağrısı olmayan `method_missing` her iletiyi yutar ve yazım hatalarını gizler.
- Vekil, sarmaladığı türün yerine geçmez: `is_a?(Array)`, `==` ve `to_s` zincirdeki tanımlar olduğundan yakalanmaz; özel yöntemler de `public_send` ile aktarılmaz.
- Kimse yazanı kalıcı değildir: ilk çağrıda `define_method` ile kendini tanımlayan vekilde aynı ad koda dönüşür.

## Sonraki Adım

Bu dersin son gözlemi, bir adın önce kimse sonra kod olabildiğini gösterdi. Kursun kapanış dersi bu geçişi bilerek kurar: `alan :fiyat, 0` gibi tek bir bildirim satırı, arkasında yöntem doğurur. Alan Özel Diller, bu bildirimin hangi yazanı gizlediğini sorar.
