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.