---
title: Bloklar
source: 'https://academia.sh/tr/kurslar/ruby-temelleri/bloklar'
course: 'Ruby Temelleri'
language: tr
updated: '2026-10-21T05:03:42+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Bir yöntemin kendisine verilen bloğu yield ile çağırdığını gösterir'
    - 'block_given? ve defined?(yield) ile bloğun varlığını sorgular'
    - 'Aynı map iletisinin iki blokla iki sonuç verdiğini ölçer'
    - 'Blok sonucunun each için dönüş değerini değiştirmediğini ölçer'
---

# Bloklar

Aynı map iletisinin iki farklı blokla iki farklı sonuç verdiği, yöntemin bloğu yield ile çağırdığı ve bloğun sonucu belirlerken sınıfın dönüş kuralını değiştirmediği ölçülür.

Önceki ders, `Hash.new { 0 }[:x]` ile `Hash.new { |_, k| k.to_s }[:x]` ifadelerinin iki farklı sonuç verdiğini ve farkı iletiyi alan nesnenin değil, verilen bloğun belirlediğini gösterdi. Bloğun kendisi o derste yalnız yazıldı. Bu ders onu konu yapar: **blok (block)**, süslü parantez ya da `do ... end` ile yazılan ve bir yönteme iletiyle birlikte verilen kod parçasıdır. Blok başlı başına bir değer değildir; yöntem onu çağırdığında koşar. M10/K03, PHP'de bir kapanışın kaç kez koştuğunu ölçmüştü; burada o soru sorulmuyor, soru yine kimin yanıtladığıdır.

Kursun yanıtlayanları **sınıf**, **modül**, **blok** ve **sözdizimi**dir. Bu dersin yanıtlayanı **blok**tur, ama sınırlayıcı ölçüm bloğun her sonucu belirlemediğini gösterecek.

## Aynı İleti, İki Blok

Aşağıdaki ölçüm aynı dizide aynı `map` iletisini iki farklı bloğa verir. Dizi değişmez, ileti değişmez; yalnız blok değişir. Çekirdek de aynı sonucu sınıflandırır: `yanit.rb` iki sonuç farklıysa yanıtlayanı **blok** sayar.

```ruby
# yanit.rb — bir iletiyi kimin yanitladigini siniflandiran yardimcilar

# Siniflandirma sirayla sorar: once ifade bir ileti mi (defined?),
# sonra iki farkli blok iki farkli sonuc veriyor mu, sonra yontemin sahibi kim.
def yanitlayan(tanim, sahip: nil, sonuc: nil, bloklu: nil)
  return ["sozdizimi", "defined? #{tanim}"] unless tanim == "method"

  if bloklu
    birinci, ikinci = bloklu.call
    return ["blok", "#{birinci.inspect} / #{ikinci.inspect}"] unless birinci == ikinci
  end

  tur = sahip.instance_of?(Class) ? "sinif" : "modul"
  [tur, "#{sahip}, sonuc #{sonuc.inspect}"]
end
```

```ruby
# blok.rb — ayni map iletisi iki blokla
require_relative "yanit"

sayilar = [1, 2, 3]
iki_kat = sayilar.map { |n| n * 2 }
metin = sayilar.map { |n| n.to_s }

tur, kanit = yanitlayan(defined?(sayilar.map), bloklu: -> { [iki_kat, metin] })
puts "#{tur}  #{kanit}"
puts sayilar.inspect
```
```
blok  [2, 4, 6] / ["1", "2", "3"]
[1, 2, 3]
```

İlk satır çekirdeğin `eleman donusumu` gözlemidir: yanıtlayan **blok**. İkinci satır dizinin değişmediğini gösterir; `map` yeni bir dizi kurdu. **KB3.** Ölçüm dizi üzerindedir; `map` karma yapıda `Enumerable`'dan gelir ve aynı blok mantığıyla çalışır, ama bu ders onu ayrıca ölçmez.

## Yöntem Bloğu Nasıl Çağırır

Bir yöntem tanımı, çağrıldığında blok verilip verilmediğini sorabilir. `block_given?` bunu doğrudan söyler; yöntem gövdesinde `defined?(yield)` aynı bilgiyi verir: bloklu çağrıda bir dizgi, bloksuz çağrıda `nil`. `yield`, verilen bloğu çağırır ve argümanlarını bloğun parametrelerine aktarır. Üst düzeyde, bir yöntemin dışında `yield` yazılmaz; her ölçüm bir yöntemin içindedir.

```ruby
# yield.rb — yontem blogu yield ile cagirir
def iki_kez
  puts "bloklu=#{block_given?} yield=#{defined?(yield).inspect}"
  return unless block_given?

  yield 1
  yield 2
end

iki_kez
iki_kez { |n| puts "blok #{n}" }
```
```
bloklu=false yield=nil
bloklu=true yield="yield"
blok 1
blok 2
```

Bloksuz çağrıda `block_given?` `false`, `defined?(yield)` `nil` döndü ve yöntem erken çıktı. Bloklu çağrıda ikisi `true` ve `"yield"` oldu; blok `1` ve `2` ile iki kez koştu. **KB4.** `defined?(yield)` `"method"` değil `"yield"` döndürür; `yield` bir yöntem çağrısı değil dilin kendi yapısıdır.

Bloksuz çağrılan `map` ve `each` hata vermez, bir **yineleyici (Enumerator)** döndürür. Bloklu çağrıda `defined?` ise `"expression"` verir; çekirdek bu yüzden iletiyi bloksuz sorgular, daha önce görüldüğü gibi.

```ruby
# bloksuz.rb — bloksuz cagri yineleyici dondurur
puts [1, 2, 3].map.class
puts [1, 2, 3].each.class
puts defined?([1, 2, 3].map)
puts defined?([1, 2, 3].map { |n| n })
```
```
Enumerator
Enumerator
method
expression
```

## Bloğun Değeri ve Çevresi

`yield` bir ifadedir ve bloğun son ifadesinin değerini döndürür. Yöntem bu değeri kullanabilir; `map` tam olarak bunu yapar. Blok ayrıca tanımlandığı yerdeki yerel değişkenleri görür: bu, M01/K02'de anlatılan **kapanış (closure)** davranışıdır ve burada yeniden tanımlanmaz, yalnız ölçülür.

```ruby
# deger.rb — yield blogun degerini dondurur, blok cevresini gorur
def uc_kat
  sonuc = yield 3
  "yield dondu: #{sonuc}"
end

carpan = 5
puts uc_kat { |n| n * carpan }
carpan = 7
puts uc_kat { |n| n * carpan }

toplam = 0
[1, 2, 3].each { |n| toplam += n }
puts "toplam=#{toplam}"
```
```
yield dondu: 15
yield dondu: 21
toplam=6
```

İki çağrıda blok aynı yazılmıştı, ama `carpan` değişkeninin o anki değerini gördü: önce `15`, sonra `21`. Blok tanımlandığında değeri kopyalamadı; çağrıldığı anda değişkenin o anki değerini okudu. `each` bloğu içinde `toplam` dışarıdaki değişkeni artırdı. **KB6.** Bu ders yalnız bloğun tanımlandığı kapsamdaki değişkenleri gördüğünü ölçer, başka kapsam kurallarını ölçmez.

## İki Yazım, Çok Parametre

Süslü parantez tek satırlık bloklarda, `do ... end` çok satırlı bloklarda tercih edilir; ikisi aynı bloğu kurar. Blok birden çok parametre alabilir ve `yield` kaç değer verirse parametreler onlara sırayla bağlanır.

```ruby
# yazim.rb — iki yazim ayni blogu kurar, cok parametre
def cift
  yield 1, 2
end

kisa = cift { |a, b| a + b }
uzun = cift do |a, b|
  a + b
end
puts "kisa=#{kisa} uzun=#{uzun}"

{ ad: "Ayse", yas: 30 }.each do |anahtar, deger|
  puts "#{anahtar}=#{deger}"
end
```
```
kisa=3 uzun=3
ad=Ayse
yas=30
```

İki yazım da `3` verdi. Karma yapının `each` bloğu anahtarı ve değeri iki ayrı parametre olarak aldı. **KB7.** İki yazımın yalnız bu çağrılarda aynı sonucu verdiği ölçüldü; parantezsiz çağrıda bloğun hangi yönteme bağlandığı Hangi Yönteme Bağlanır bölümünde ayrıca ölçülür.

## Kısa Biçimler

Ruby 3.4'ten beri tek parametreli bir blokta `it` yazılabilir; `_1` ise Ruby 2.7'den beri vardır. İkisi de aynı sonucu verir.

```ruby
# kisa.rb — tek parametreli blokta it ve _1
puts [1, 2].map { it * 3 }.inspect
puts [1, 2].map { _1 * 3 }.inspect
```
```
[3, 6]
[3, 6]
```

## Parametre Açma ve Sıra

Blok birden çok parametre alırsa, yöntemin ilettiği tek bir dizi parametrelere dağıtılır. `|a, b|` bir çifti açar, `|a, (b, c)|` iç içe diziyi de açar. `each_with_index` ise elemanla birlikte sırayı da iletir.

```ruby
# acma.rb — blok parametrelerinde dizi acma
[[1, 2], [3, 4]].each { |a, b| puts "#{a}+#{b}=#{a + b}" }
%w[x y].each_with_index { |harf, sira| puts "#{sira}:#{harf}" }
[[1, [2, 3]]].each { |a, (b, c)| puts "a=#{a} b=#{b} c=#{c}" }
puts [[1, 2], [3, 4]].map { |cift| cift }.inspect
```
```
1+2=3
3+4=7
0:x
1:y
a=1 b=2 c=3
[[1, 2], [3, 4]]
```

`[[1, 2], [3, 4]]` üzerinde `|a, b|` her çifti iki parametreye böldü: `1+2=3` ve `3+4=7`. `each_with_index` elemanı ve sırayı ayrı iki parametre olarak verdi. Parantezli `(b, c)` iç diziyi açtı. Tek parametreli `map { |cift| cift }` ise diziyi bölmeden olduğu gibi aldı. **KB23.** Açma yalnız dizi elemanlarında ve bu dört çağrıda ölçüldü.

## Bloğun Dış Yereli

Blok, tanımlandığı yerdeki yerel değişkenleri görür ve değiştirebilir. Bu, yukarıda ölçülen kapanış davranışıdır. Blok parametresi dıştaki bir değişkenle aynı adı taşırsa ne olduğu da aşağıda ölçülür; `|x; y|` yazımı ise noktalı virgülden sonraki adı bloğa yerel yapar.

```ruby
# dis_yerel.rb — blok dis degiskeni gorur ve degistirir
toplam = 0
[1, 2, 3].each { |n| toplam += n }
puts toplam
n = 100
[1, 2].each { |n| n }
puts n
y = 1
[5].each { |x; y| y = x }
puts y
```
```
6
100
1
```

`toplam` bloğun dışında tanımlıydı ve blok her turda onu artırdı: sonuç `6`. İkinci örnekte blok parametresi `n`, dıştaki `n` ile aynı ada sahipti; blok içindeki `n` ayrı bir değişken oldu ve dıştaki `n` `100` olarak kaldı. Üçüncüde `|x; y|` ile bloğa yerel bir `y` tanımlandı; blok `y = x` yazsa da dıştaki `y` `1` kaldı. Blok dıştaki yereli değiştirebilir; bu değiştirme yalnız ad bloğa yerel olarak bildirilmediyse olur. **KB24.**

## Hangi Yönteme Bağlanır

İki blok yazımı bu dersin başında aynı sonucu verdi. Fark parantezsiz çağrıda ortaya çıkar: süslü parantez en yakın yönteme bağlanır, `do` ve `end` ise aşağıdaki ölçümde dıştaki yönteme bağlandı. Aşağıdaki `sor` yöntemi yalnız kendisine blok verilip verilmediğini bildirir.

```ruby
# oncelik.rb — blogun hangi yonteme baglandigi
def sor(*) = "blok=#{block_given?}"
puts sor(1) { }
puts sor 1 do end
```
```
blok=true
blok=false
```

`sor(1) { }` bloğu `sor`'a verdi ve `blok=true` basıldı. `puts sor 1 do end` bloğu `puts`'a bağladı; `sor` blok almadı ve `blok=false` basıldı. Parantezsiz çağrıda `do` ve `end` bloğu dıştaki yönteme götürür. **KB25.** Yalnız bu iki çağrı ölçüldü; zincirleme çağrılardaki bağlanma ayrıca ölçülmedi.

## Bloktan Değer Döndürmek

Blok içinde `next`, bloğu o turda bitirir ve verilen değeri bloğun değeri yapar. `break` ise yöntemin kendisini bitirir ve verilen değer yöntem çağrısının sonucu olur.

```ruby
# sonraki.rb — next ve break ile deger
puts [1, 2, 3, 4].map { |n| next 0 if n.even?; n * 10 }.inspect
puts [1, 2, 3].each { |n| break n * 5 if n == 2 }
```
```
[10, 0, 30, 0]
10
```

`next 0 if n.even?` çift sayılarda bloğun değerini `0` yaptı ve `map` `[10, 0, 30, 0]` döndürdü. `each` içinde `break n * 5`, `n == 2` olduğunda döngüyü kesti ve `each` çağrısının değeri `10` oldu. **KB26.** `next` ve `break` yalnız `map` ve `each` ile ölçüldü.

## Esnek Parametre Sayısı

Blok, yöntemin ilettiği değer sayısıyla parametre sayısının eşit olmasını şart koşmaz. Fazla iletilen değerler atılır, eksik kalan parametre `nil` olur. Tek bir dizi iletildiğinde ise birden çok parametre onu açar.

```ruby
# esnek.rb — blok parametre sayisi ile iletilen deger sayisi
def iki
  yield 1, 2
end
iki { |a| puts "a=#{a.inspect}" }
iki { |a, b, c| puts "c=#{c.inspect}" }
def tek
  yield [1, 2]
end
tek { |a, b| puts "a=#{a} b=#{b}" }
tek { |a| puts "a=#{a.inspect}" }
```
```
a=1
c=nil
a=1 b=2
a=[1, 2]
```

`yield 1, 2` iki değer iletti. Tek parametreli blok yalnız ilkini aldı, üç parametreli blokta üçüncü `nil` kaldı ve hata çıkmadı. `yield [1, 2]` tek bir dizi iletti: iki parametreli blok onu açtı, tek parametreli blok diziyi bütün olarak aldı. Bu gevşeklik blokta ve proc'ta görülür; Proc ve Lambda dersi aynı sınamayı lambda ile yapar. **KB39.**

## Bloğun Değerini Yöntemde Kullanmak

`yield` bir ifadedir ve değeri bloğun son ifadesidir. Yöntem bu değeri biriktirebilir ya da bir koşul olarak kullanabilir; ne yapılacağını bu durumda yöntem değil, verilen blok belirler.

```ruby
# yield_deger.rb — yield ifadesinin degeri
def donustur(liste)
  sonuc = []
  liste.each { |x| sonuc << yield(x) }
  sonuc
end
puts donustur([1, 2, 3]) { |x| x * 2 }.inspect
def say(liste) = liste.count { |x| yield x }
puts say([1, 2, 3, 4]) { |x| x.even? }
```
```
[2, 4, 6]
2
```

`donustur` her `yield(x)` değerini sonuca ekledi ve `[2, 4, 6]` verdi. `say` bloğun doğru döndürdüğü elemanları saydı ve `2` verdi. İki yöntemde de sonucu blok belirledi; `donustur` iki katına almayı, `say` da çift sayıyı seçmeyi bilmiyor; ikisi yalnız bloğun değerini kullanıyor. Yanıtlayan bu yüzden bloktur. **KB40.**

## Blok Parametresi ve Sembol

Bir yöntem `&blok` parametresi tanımlarsa, verilen bloğu bir nesne olarak alır; blok verilmediyse bu parametre `nil` olur. `&:ad` yazımı ise bir sembolü blok yerine geçirir.

```ruby
# blok_nesnesi.rb — &blok parametresi ve sembol
def al(&b) = b
puts al.inspect
puts al { }.class
puts %w[a b].map(&:upcase).inspect
puts :upcase.to_proc.call("x")
```
```
nil
Proc
["A", "B"]
X
```

`al` bloksuz çağrılınca `nil`, bloklu çağrılınca bir `Proc` döndürdü. `map(&:upcase)` her elemana `upcase` iletisini gönderdi ve `["A", "B"]` verdi; `:upcase.to_proc.call("x")` da `X` döndürdü. Sembolün kendisi blok değildir, `to_proc` ile bir `Proc`'a dönüşür. **KB41.** Proc nesneleri Proc ve Lambda dersinde ayrıntılanır.

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

Blok her zaman sonucu belirler mi? `each` iletisi bloğu her eleman için koşturur, ama dönüş değeri bloğun sonucu değildir. İki farklı blok aynı dönüş değerini verir ve yanıtlayan blok değil, `each`'in sahibi olan sınıftır.

```ruby
# donus.rb — each icin blok sonucu donusu degistirmez
sayilar = [1, 2]
a = sayilar.each { |n| n * 10 }
b = sayilar.each { |n| n * 99 }
puts a.inspect
puts b.inspect
puts "sahip=#{sayilar.method(:each).owner}"
```
```
[1, 2]
[1, 2]
sahip=Array
```

İki blok farklı değerler hesapladı, ama ikisi de `each`'ten `[1, 2]` döndü. Dönüş değerini bloklar değil, `Array` sınıfındaki `each` tanımı belirliyor. Yani `map` için blok sonucu belirler, `each` için belirlemez; aynı blok sözdizimi iki iletide iki farklı iş görür. **KB5.** Bu fark yalnız bu iki yöntemde ölçüldü, diğer yineleme yöntemlerine genellenmez.

## Özet

- Blok, bir yönteme iletiyle verilen kod parçasıdır; yöntem onu `yield` ile çağırır.
- Bu dersin yanıtlayanı **blok**tur: aynı `map` iletisi `{ |n| n * 2 }` ile `[2, 4, 6]`, `{ |n| n.to_s }` ile `["1", "2", "3"]` verdi.
- `block_given?` ve `defined?(yield)` bloğun varlığını sorar; bloksuz `map` ve `each` bir yineleyici döndürür.
- `it` Ruby 3.4'ten beri, `_1` Ruby 2.7'den beri tek parametreli blokta kullanılır.
- Sınırlayıcı ölçüm: `each` iki farklı blokla da `[1, 2]` döndürür; dönüş değerini bu durumda `Array` sınıfı belirler.

## Sonraki Adım

`map` dizide `Array`'in, karma yapıda `Enumerable`'ın yöntemiydi. Sonraki ders bu modülün kendisine bakar: dizinin kendisinde olmayan bir yöntem nereden geliyor ve kendi sınıfınıza aynı yetenek tek bir `each` ile nasıl verilir.
