Skip to content

Blocks (Bloklar)

Blok olayı, bence Ruby'nin en çılgın özelliklerinden biri. Aslında bu konu, neredeyse başlı başına bir kitap konusu olabilir. Genelde Block, Proc, Lambda üçlemesi olarak anlatılır.

Kitabımız 101 yani giriş seviyesinde olduğu için, kafaları minimum karıştırma adına basit şekilde değineceğim.

Blok'lar, genelde [Closure](http://en.wikipedia.org/wiki/Closure_(computer_programming) ya da Anonim fonksiyonlar olarak tanımlanır. Sanki method içinde başka bir method’u işaret eden ya da değişkenleri method’lar arasında paylaşan kapalı bir ortam gibidirler.

Genelde ya { } ile ya da do/end ile sarmalanmışlardır.

family_members = ["Yeşim", "Ezel", "Uğur", "Ömer"]

family_members.each do |member_name|
  puts member_name
end

# Yeşim
# Ezel
# Uğur
# Ömer

Aynı kod:

family_members = ["Yeşim", "Ezel", "Uğur", "Ömer"]

family_members.each { |member_name| puts member_name }

# Yeşim
# Ezel
# Uğur
# Ömer

şeklinde de yazılabilirdi. do/end ya da {} arasında kalan kısım Block kısmıdır.

family_members bir Array yani dizidir. Eğer puts family_members.class dersek bize Array oldunu söyler. Array'in each method’u bize block işleme şansını sağlar.

Komut satırında ri Array#each dersek bize Array'in each method’uyla ilgili tüm bilgiler gelir.

do komutundan hemen sonra gelen |member_name| bizim kafamıza göre tanımladığımız bir değişkendir ve Array'in her elemanı bu değişkene atanır.

Enumeration bölümünde bunlardan sıkça bahsedeceğiz. Blockların esas gücü yield olayından gelir. Hemen bir örnek verelim:

def test_function
  yield
end

test_function {
  puts "Merhaba"
}

# Merhaba

test_function do
  puts "Ben block içinden geliyorum"
end

# Ben block içinden geliyorum

test_function do
  [1, 2, 3, 4].each do |n|
    puts "Sayı #{n}"
  end
end

# Sayı 1
# Sayı 2
# Sayı 3
# Sayı 4

test_function adında bir fonksiyonum var (yani method’um var) Hiç parametre almıyor! ama Block alıyor. İlkinde curly brace ile (yani { ve }), ikincisinde do/end ile, son örnekte do/end ile ve iç kısımda başka bir iterasyonla kullandım.

Kabaca, fonksiyona kod bloğu geçtim.

Peki, ya şu şekilde kullansaydım test_function ? yani hiçbir şey geçmeden? Alacağım hata mesajı:

no block given (yield)

olacaktı. Demek ki block geçilip geçilmediğini anlamanın bir yolu var :)

def test_function
  if block_given?
    yield
  else
    puts "Lütfen bana block veriniz!"
  end
end

block_given? ile bu kontrolü yapabiliyoruz. Şimdi biraz daha kafa karıştıralım :)

def numerator
  yield 10
  yield 4
  yield 8
end

numerator do |number|
  puts "Geçilen sayı #{number}"
end

Örnekte, yield block içinden gelen kod bloğunu bir fonksiyon gibi çağırıyor, çağırırken de bloğa parametre geçiyor. Dikkat ettiyseniz kaç tane yield varsa o kadar kez block çağırıldı (_call edildi__)

def print_users
  ["Uğur", "Yeşim", "Ezel"].each do |name|
    yield name
  end
end

print_users do |name|
  puts "Kullanıcı Adı: #{name}"
end

# Kullanıcı Adı: Uğur
# Kullanıcı Adı: Yeşim
# Kullanıcı Adı: Ezel

Fonksiyon içine fonksiyon geçtik gibi.

Enumeration / Number bölümünde de göreceğiz ama hemen hızlı bir-iki örnek vermek istiyorum blok kullanımıyla ilişkili.

5.times { puts "Merhaba" }
5.times { |i| puts "Sayı #{i}" }
5.times do |i|
  puts "Sayı #{i}"
end

Not: Aslında times sayılara ait bir method ve yukarıdaki örneklerde gördüğünüz gibi blok geçebiliyoruz kendisine.