---
title: 'Alan Özel Diller'
source: 'https://academia.sh/tr/kurslar/ruby-nesne-yonelimi/alan-ozel-diller'
course: 'Nesne Yönelimi ve Metaprogramlama'
language: tr
updated: '2026-10-21T05:03:42+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Bir bildirim satırının arkasında define_method ile yöntem doğurduğunu ve bu yöntemin yazanının kod olduğunu ölçer'
    - 'Sınıf düzeyindeki bildirim yönteminin tekil sınıf zincirinde arandığını ve yazanının ata olduğunu gösterir'
    - "instance_eval ile bloklu bir alan özel dil kurar ve bloğun self'ini ölçer"
    - 'Kursun dokuz gözlemini yazan kategorisine göre tabloda toplar'
---

# Alan Özel Diller

Bildirim satırının arkasında yöntemi kimin yazdığı ölçülür: define_method ile üretilen erişimci koddur, instance_eval ise self'i değiştirir ama yerel değişkenleri değiştirmez. Ders, kursun dokuz gözleminin kapanış tablosunu da verir.

Önceki ders, bir adın önce **kimse** sonra **kod** olabildiğini gösterdi. Bu ders aynı geçişi bilerek kullanır: `alan :fiyat, 0` gibi tek bir satır okunduğunda bir çağrıya benzer, ama çalıştığında sınıfa yeni bir yöntem ekler. **Alan özel dil (domain-specific language)**, belirli bir iş için küçültülmüş ve o işin sözcükleriyle konuşan bir yazım biçimidir. Ruby'de bunun bir kurulumu, sınıf gövdesinde çağrılan bildirim yöntemleridir. Satırın kısalığı, ölçülmesini gereksiz kılmaz; tersine, bu satırların arkasında yöntemi kimin yazdığı ilk bakışta belli değildir.

Eksen kursun başından beri aynı: **bu yöntemi kim yazdı?** Bu dersin yazanı **kod**. `alan :fiyat, 0` satırını programcı yazdı, ama bu satırın doğurduğu `fiyat` yöntemini yazan Ruby kodudur, yani bir `define_method` çağrısı. Aşağıdaki ölçümler bu ayrımı çizer; sonda bloklu biçimin nerede kırıldığı gösterilir. `yazan` yardımcısı önceki derslerdeki hâliyle 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

Gözlem iki sınıf üzerindedir. `Model`, bildirim yöntemini taşır; `Urun` onu kullanır.

```ruby
# model.rb — bildirim yontemi tasiyan taban sinif
require_relative "yazan"

class Model
  def self.alan(ad, varsayilan)
    define_method(ad) { instance_variable_get("@#{ad}") || varsayilan }
  end
end

class Urun < Model
  alan :ad, "adsiz"
  alan :fiyat, 0
end
```

Bu blok de kaynaktır. `alan`, adı ve bir varsayılan değeri alır; ad için bir okuyucu yöntem tanımlar. Okuyucu, örnek değişkeni doluysa onu, boşsa varsayılanı verir. `Urun` gövdesindeki iki satır çağrıdır, tanım değildir: sınıfta tek bir `def` yoktur.

## Bildirim Satırı Neyi Yazdı

Dersin gözlemi `Urun.new.fiyat` iletisidir. Önce yöntemin ne verdiği, sonra kimin yazdığı ve sınıfta nelerin göründüğü ölçülür.

```ruby
# olcum.rb — bildirim satirinin dogurdugu yontem
require_relative "model"

u = Urun.new
p u.fiyat
p u.ad
p yazan(u, :fiyat)
p Urun.instance_methods(false).sort
```
```
0
"adsiz"
["kod", "Urun, blok govdesi"]
[:ad, :fiyat]
```

Yöntem `0` verdi, çünkü örnek değişkeni boştu ve varsayılan devreye girdi. Yazan **kod** çıktı: `yazan` tanımı `Urun`'un kendi zincir halkasında buldu ve `iseq` etiketi bir blok gövdesine işaret etti. Sınıfın kendi yöntem listesi `[:ad, :fiyat]`; iki bildirim satırı iki yöntem doğurdu. Programcının yazdığı yalnız iki satırdır, ama sınıfın arayüzü iki yöntemdir. **MP30.** Bu ölçüm tek bir bildirim yöntemi ve iki alan içindir; `alan` başka bir gövdeyle yazılsaydı yazan değişebilirdi.

## Çağrı Ama Yazan Kod

Yöntemin gerçekten okuduğu şey örnek değişkenidir. Değişken doldurulunca varsayılan geride kalmalıdır.

```ruby
# deger.rb — varsayilan ve doldurulmus deger
require_relative "model"

u = Urun.new
u.instance_variable_set(:@fiyat, 40)
p u.fiyat
p Urun.new.fiyat
p yazan(Urun, :alan)
```
```
40
0
["ata", "#<Class:Model>"]
```

Dolu değişken varsayılanı geçti: `40`. Aynı sınıfın yeni nesnesi ise `0` verdi, çünkü varsayılan sınıfa, değer nesneye aittir. Son satır sahibi alıcıdan ayırır: `alan` yöntemini yazan **ata** çıktı ve yer olarak `Model`'in tekil sınıfı göründü. Alıcı olarak `Urun` sınıfı verildi; `alan` tanımı `Urun`'un kendi tekil sınıfında değil, `Model`'inkinde duruyor. Sahip alıcının tekil sınıfı olmadığı için kural onu atadan saydı; yani aynı bildirim satırında iki ayrı yazan çalışır. `alan` çağrısının yöntemini ata yazdı, o çağrının doğurduğu `fiyat` yöntemini kod yazdı. **MP31.** Bu ayrım `yazan` yardımcısının tekil sınıf kurallarına dayanır; başka bir yardımcı farklı sınıflandırabilir.

Bu, M08/K06'daki soruyla karıştırılmamalıdır. Orada bir davranışın kaynaktaki sebebi soruldu: çağrı mı, açıklama mı, varsayılan mı. Burada sebep sorulmaz, tanımın yazarı sorulur: `alan :fiyat, 0` bir çağrıdır, ama doğurduğu yöntemi yazan koddur.

## Okuma Durum Bırakmaz

Üretilen yöntemin bir yan etkisi olup olmadığı da ölçülebilir. Varsayılan, yöntemin içinde hesaplanır; nesneye yazılmaz.

```ruby
# okuma.rb — okuyucunun nesnede biraktigi iz
require_relative "model"

u = Urun.new
p u.fiyat
p u.instance_variables
p u.method(:fiyat).owner
p u.method(:fiyat).arity
```
```
0
[]
Urun
0
```

`fiyat` okundu ve `0` verdi, ama nesnenin örnek değişkenleri listesi boş kaldı: varsayılan bir değer olarak döndü, bir alan olarak saklanmadı. Yöntemin sahibi `Urun`, yani bildirim yöntemin tanımını alt sınıfa koydu; `Model`'e değil. Argüman sayısı sıfır: `define_method` ile verilen blok parametre almadığı için üretilen okuyucu da almaz. Bu üç gözlem, bildirimsel arayüzün sınıfa ne yazdığını tamamlar: yeni bir yöntem, sahibi alt sınıf, durumu yok. **MP32.** Bu ölçüm yalnız okuma yönündedir; değeri yazan bir yöntem bu `alan` tanımında yok, değer yalnız `instance_variable_set` ile verildi.

## Sınıf Yöntemi Nerede Aranır

`Urun.alan` çağrısının neden `Model`'e ulaştığı tekil sınıf zincirinden okunur.

```ruby
# zincir.rb — sinif yontemlerinin zinciri
require_relative "model"

p Urun.singleton_class.ancestors.take(3)
p Model.singleton_class.instance_methods(false)
p Urun.respond_to?(:alan)
p Urun.new.respond_to?(:alan)
```
```
[#<Class:Urun>, #<Class:Model>, #<Class:Object>]
[:alan]
true
false
```

Zincirin ilk halkası `Urun`'un kendi tekil sınıfı, ikincisi `Model`'inkidir. Sınıf yöntemleri kalıtımla gelir çünkü alt sınıfın tekil sınıfı, üst sınıfın tekil sınıfından türer. `Urun.alan` bu zincirde ikinci halkada bulundu. Bildirim yöntemini tabanda yazmak bu yüzden yeter: her alt sınıf onu kendi gövdesinde çağırabilir. `Model`'in tekil sınıfında tek yöntem var, `alan`. `Urun` sınıfı ona cevap verir (`true`), ama `Urun`'un bir nesnesi vermez (`false`): bildirim sınıfın arayüzüne aittir, nesnenin arayüzüne değil. Nesne yalnız bildirimin doğurduğu `ad` ve `fiyat` yöntemlerini görür. Bu ayrım alan özel dilin neden sınıf gövdesinde yaşadığını da söyler: bildirim yazılırken konuşulan şey nesne değil, sınıftır. **MP33.** Çıktı yalnız ilk üç halkayı gösterir; zincirin devamı bu derste ölçülmedi.

## Bloklu Alan Özel Dil

Bildirimleri sınıf gövdesinin dışına çıkarmak için başka bir kurulum vardır: bir blok verilir ve blok bir nesnenin bağlamında çalıştırılır.

```ruby
# form.rb — instance_eval ile bloklu biçim
class Form
  attr_reader :alanlar

  def self.kur(&blok)
    f = new
    f.instance_eval(&blok)
    f
  end

  def initialize
    @alanlar = []
  end

  def alan(ad)
    @alanlar << ad
  end
end

f = Form.kur do
  alan :ad
  alan :eposta
end
p f.alanlar
```
```
[:ad, :eposta]
```

Blok içindeki `alan` çağrılarının alıcısı yazılmadı; `instance_eval` bloğu `Form` nesnesinin bağlamında çalıştırdı, yani bloğun `self`'i o nesne oldu. Sonuç `[:ad, :eposta]`. Bu biçim okunaklıdır: kullanıcı nesne adı yazmadan yalnız sözcükleri yazar. Okunaklılığın bir bedeli var ve aşağıda ölçülür. **MP34.** Burada tek bir `alan` yöntemi ve iki çağrı vardı; bloğun içinde başka yöntem çağrıları bu ölçümde yok.

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

`instance_eval` bloğun `self`'ini değiştirir. Peki bloğun dışındaki değişkenlere ne olur? Üç değişkene bakılır: dışarıda tanımlı bir örnek değişkeni, bir yerel değişken ve `self`'in kendisi. Sonra aynı kurulumun `yield` ile yazılmış biçimi denenir.

```ruby
# sinir.rb — instance_eval ve dis degiskenler
@baslik = :kayit
yerel_ad = :yerel

class Form
  attr_reader :alanlar

  def self.kur(&blok)
    f = new
    f.instance_eval(&blok)
    f
  end

  def initialize
    @alanlar = []
  end

  def alan(ad)
    @alanlar << ad
  end
end

class Form2
  attr_reader :alanlar

  def self.kur
    f = new
    yield f
    f
  end

  def initialize
    @alanlar = []
  end

  def alan(ad)
    @alanlar << ad
  end
end

p Form.kur { alan @baslik }.alanlar
p Form.kur { alan yerel_ad }.alanlar
p Form.kur { alan self.class }.alanlar
p Form2.kur { |f| f.alan @baslik }.alanlar
```
```
[nil]
[:yerel]
[Form]
[:kayit]
```

Üç sonuç var. Dışarıdaki `@baslik` blok içinde `nil` verdi: örnek değişkenleri `self`'e bağlıdır ve `self` değişti. Yerel değişken `yerel_ad` ise `[:yerel]` verdi: yerel değişkenler bloğun kapanışıyla yakalanır, `self`'e bağlı değildir. `self.class` `Form` çıktı. Son satırdaki `yield` biçimi `self`'i korudu ve `@baslik` değeri `[:kayit]` olarak okundu. `instance_eval` böylece sözcük kazandırır ama dışarıdaki örnek değişkenlerini görünmez yapar. **MP35.** Bu fark yalnız örnek değişkenleri için ölçüldü; sabitlerin ve sınıf değişkenlerinin davranışı bu derste sınanmadı.

Bildirimin bir de sessiz bedeli vardır: aynı alanı iki kez bildirmek hata vermez.

```ruby
# tekrar.rb — ayni alanin iki kez bildirilmesi
require_relative "model"

class Etiket < Model
  alan :ad, "adsiz"
  alan :ad, "yeni"
end

p Etiket.new.ad
p Etiket.instance_methods(false)
```
```
"yeni"
[:ad]
```

İkinci bildirim birincinin üzerine yazdı: `ad` artık `"yeni"` veriyor ve sınıfta hâlâ tek `ad` yöntemi var. Hiçbir uyarı, hiçbir istisna yok. Bildirimsel arayüz bu yüzden kolay yazılır ve kolay yanlış yazılır; `define_method` aynı adı sessizce yeniden tanımlar. **MP36.** Bu ölçüm iki bildirimin aynı sınıfta olduğu durumdur; ikisi farklı kalıtım düzeylerinde olsaydı alt sınıf üst sınıfın yöntemini gölgelerdi.

## Özet

- `alan :fiyat, 0` satırı bir çağrıdır; doğurduğu `fiyat` yöntemini yazan **kod**dur, çünkü `define_method` bir blok gövdesi üretir.
- Bildirim yöntemi `alan` ise `Model`'de yazılmıştır ve sınıf yöntemi olduğundan `Urun`'un tekil sınıf zincirinde aranır; o yöntemin yazanı **ata**dır.
- `instance_eval` bloğun `self`'ini değiştirir; dış örnek değişkenleri `nil` olur, yerel değişkenler görünür kalır.
- `yield` ile aktarılan nesne `self`'i korur; sözcük kazancı için dış örnek değişkenlerinden vazgeçilir.
- Aynı alanın iki kez bildirilmesi hata vermez; sonraki bildirim sessizce önceki yöntemin yerine geçer.
- Bu dersin yazanı kod: bildirimsel arayüzün satırları programcıya, doğurdukları yöntemler koda aittir.

## Kurs Kapanışı

Kursun her dersi aynı soruyu sordu: bir yöntemi kim yazdı? Dokuz gözlem, dokuz kez bu soruyu bir ölçümle yanıtladı. Aşağıdaki tablo hepsini yazan kategorisine göre toplar.

| Ders | Ölçülen yöntem | Yazan | Sınırlayıcı ölçüm |
| --- | --- | --- | --- |
| Sınıf Tanımı ve Örnek Değişkenler | `hesap.bakiye_metni` | programcı | `attr_reader` aynı sınıfta ikinci yazan |
| Kalıtım ve `super` | `Vadeli.new("can", 50).bakiye_metni` | ata | `super` çağıran yeniden tanım programcı |
| Modüller ve Karışımlar | `hesap.rapor` | ata | sınıfın `def`'i karışımı gölgeler |
| Görünürlük | `komisyon` (`hesap.net` içinden) | programcı | `public :komisyon` tanımın sahibini alt sınıfa taşır |
| Yöntem Arama Zinciri | `Kasa.new.ac` | ata | tek nesnede tekil yöntem başa girer |
| Yansıma | `Nokta.new(3, 4).x` | kod | çekirdek yöntemleri de kod görünür |
| Dinamik Yöntem Tanımı | `Ayar.new.renk` | kod | `class_eval` dizgisi programcı çıkar |
| Eksik Yöntem Yakalama | `Vekil.new([3, 1, 2]).sort` | kimse | ilk çağrıda kimse koda dönüşür |
| Alan Özel Diller | `Urun.new.fiyat` | kod | `instance_eval` `self`'i değiştirir |

Yazanların dağılımı: **3 ata · 3 kod · 2 programcı · 1 kimse**. Tablo kursun bir bulgusunu taşır: yazan sınıf başına değil yöntem başına ölçüldü, ve bir yöntemin yazanı kaynak metinde nasıl göründüğüyle değil zincirde nasıl bulunduğuyla belirlendi. Aynı sınıfta iki yazan, aynı satırda iki yazan göründü.

İki çıkarım yapılabilir. Birincisi, yazanı bilmek yazım biçimini bilmeyi gerektirmez: `attr_reader` ve `define_method` ayrı sözcüklerdir ama ikisi de kodu yazan yapar; `def` ve `class_eval` dizgisi ayrı sözcüklerdir ama ikisi de programcıyı. İkincisi, yansıma yazanı söylemek için yeterli değildir: `source_location`, `owner` ve `respond_to?` ayrı ayrı yanıltıcı olabilir; kural bunları birlikte okudu. Kimse kategorisi tek örneğe düştü ve o da kalıcı olmadı. Üçüncü bir çıkarım dağılımın kendisinden gelir: dokuz gözlemin yalnız ikisinde yazan programcıdır. Ölçülen sınıflarda arayüzün büyük kısmı atadan, karışımdan ve kodun ürettiği tanımlardan geldi; sınıf gövdesine bakmak bu yüzden yazanı bulmak için tek başına yetmez, zincirin ve tanım biçiminin ölçülmesi gerekir.

**MP37.** Tablo yalnız dokuz ölçümün sınıflandırmasıdır; kategorilerin sayısı ölçülen yöntemlerin seçimini yansıtır, Ruby'deki yöntemlerin genel dağılımını değil. Yazan hücreleri her dersin Özet bölümündeki ifadeden alındı.

Kurs burada kapanır. Sıradaki kurs, Ruby ile yazılmış bir web uygulamasının dört katmanını sırayla ele alır: yönlendirme, denetleyici, model ve görünüm. Orada da aynı kural geçerli kalır: tahmin yürütülmez, ölçülür.
