30 Haziran 2014 Pazartesi

Ruby'de Kontrol Yapıları

  1. Kontrol Yapıları

Normal bir programın çalışması komutların ard arda sıralı işletilmesi ile gerçekleşir. Ancak genelde programın bu sıralı çalışma akışını değiştiren yapılara ihtiyaç duyulur. Ruby dilinde bu gibi kontrol yapılarını içeren aşağıdaki ifadeler bulunmaktadır [1,2]:
  • Şart ifadeleri (Conditionals)
  • Döngüler
  • Yineleyiciler (Iterators)
  • Akışı Değiştiren İfadeler (return & break vb.)


  1. Şart İfadeleri

Programlama dillerindeki en yaygın ifadelerden biri de şart ifadeleridir. Bu şekilde bazı kodların ancak bazı durumlar sağlandığında çalıştırılması sağlanabilir.


    • if
Ruby’de “if”den sonra bir şart ifadesi yazılır. Şart ifadesinin parantez içine alınmasına gerek yoktur. Şart ifadesi false veya nil değil ise doğrudur. Şart ifadesinden sonra, koşula bağlı kod yazılır. En son ise “end” ile koşul ifadesi bitirilir. Şart ifadesiyle, koşula bağlı kod birbirinden satır başı, noktalı virgül  (Ruby 1.8) veya “then” ifadesi ile ayrılmalıdır [1]. Aşağıdaki kod örneklerinin hepsi, farklı şekilde yazılmalarına rağmen aynı işi yapar:


if x < 10
  x += 1
end


if x < 10 then x += 1 end


if x < 10 ; x += 1 end


if x < 10 then
  x += 1
end


      • else
Bir “if” ifadesi, koşul doğru olmadığında işletilecek ifadeyi belirtecek bir “else” ifadesi içerebilir. Şart ifadesi false veya nil ise “else” ifadesine bağlı kod çalıştırılır [1].


if value
  value << x
else
  value = x;
end


      • elsif
Eğer çoklu durumları kontrol etmek istiyorsak “if” ifadesinden sonra bir ya da daha fazla “elsif” ifadesi ile yeni durumlar sırasıyla kontrol edilebilir. En sona bir “else” ifadesi yazmak zorunlu değildir [1].


if sayi == 1
yazi = "bir"
elsif sayi == 2
yazi = "iki"
elsif sayi == 3 then name = "uc"
elsif sayi == 4; name = "dort"
else
yazi = "diger"
end


      • Dönüş Değeri
Ruby dilinde “if” ifadesinin de bir dönüş değeri vardır. Bu değer en son işletilen kod ya da hiç kod işletilmediği durumda nil’dir [1]. Ruby’nin bu özelliği aşağıdaki gibi bir kod yazmayı mümkün kılar.


yazi = if sayi == 1 then "bir"
elsif sayi == 2 then "iki"
elsif sayi == 3 then "uc"
elsif sayi == 4 "dort"
else "diger"
end


    • Tümleyen olarak if

“if” ifadesi tek satırlık bir kontrol ifadesi olarak yazıldığında “if” ile başlayıp “end” ile başlayan normal bir kontrol yapısından farklı bir yapı alır. Bu defa “if” aynı satırda olmak üzere, bir kodun hangi kontrole bağlı çalıştırılacağını belirtir [1]. Aslında bu bir ayrıştırma (parse) problemidir. Çalıştırılacak kod if ifadesinden önce gelen ifadenin tümüdür.


puts message if message # tanımlıysa message değerini yaz


Ayrıca “if” tümleyen olarak ard arda yazılabilir. Örneğin:


puts message if message if defined? puts


    • unless

“if” ifadesinin tam zıttı anlama gelir. Yani şart ifadesi sağlanmadığında kod işletilir. Aynı “if” gibi “else” ve “elsif” ifadeleriyle birlikte kullanılabilir. Diğer özellikleri de “if” ile tamamen aynıdır [1].

    • case

“case” ifadesi çok yönlü bir kontrol yapısıdır. Bu kontrol yapısı iki farklı şekilde kullanılır. Birinci kullanımı if/elsif/else yapısına alternatif bir söz dizimi sunar [1]. Örneğin aşağıda verilen iki örnek birbirine eştir.


name = case
      when x == 1 then "one"
      when x == 2 then "two"
      when x == 3 then "three"
      when x == 4 then "four"
      else "many"
      end


name = if x == 1 then "one"
      elsif x == 2 then "two"
      elsif x == 3 then "three"
      elsif x == 4 then "four"
      else "many"
      end


Burada “if” ifadesindeki gibi “then” yerine satır başı veya noktalı virgül (Ruby 1.8) kullanılabilir. “else” ifadesi zorunlu değildir [1].


İkinci kullanımında, “case” ifadesi kendinden sonra gelen değişkenin değerini farklı koşullarla kıyaslar, yani şartlı ifadenin sol tarafı hep aynıdır [1]. Örneğin,


name = case x
when 1
   "one"
when 2 then "two"
when 3; "three"
else "many"
end


Burada kontrol “===” ifadesi ile yapılır. Bu kontrol Class için tip kontrolü, Range için aralık kontrolü, Regexp için şablon kontrolü sağlar. Diğer çoğu sınıfta “==” gibi davranır [1].


“case” ifadesinde birden fazla durum tek bir “when” ile veya şartıyla kontrol edilebilir. Örneğin:


case x
 when nil, [], "", 0
   false
 else #
   true
end


“case” ifadesinde kontrol edilen değer Java ve C gibi dillerde olduğu gibi sabit bir değer olmak zorunda değildir. Bu nedenle performansı biraz düşse de esneklik kazandırır [1].


    • ? : Operatörü

<koşul> ? <kod-1> : <kod-2> şeklinde kullanılır. Burada “?” işareti “then” gibi, “:” ise “else” gibi davranır.


puts ( n==1 ? " message." : " messages.” )


  1. Döngüler

Belirli kod bloklarının, tekrarlı olarak çalıştırılmasını sağlayan döngü yapıları Ruby’de “while”, “until” ve “for” ifadeleri ile desteklenmektedir [1].

    • while & until
Bir kod bloğunu, “while” ifadesi bir koşul sağlandıkça, “until” ifadesi ise bir koşul sağlanana kadar çalıştırır [1].


sayi = 10
while sayi >= 0 do
puts sayi
sayi = sayi - 1
end


sayi = 10
until sayi < 0 do
puts sayi
sayi = sayi - 1
end


Buradaki “do” ifadesi “if” ifadesindeki “then” gibidir. Yerine satır başı veya noktalı virgül kullanılabilir.

    • Tümleyici Olarak while & until
“while” ve “until” ifadesi tek satırlık bir kontrol ifadesi olarak yazıldığında,  aynı satırda olmak üzere, bir kodun hangi kontrol sağlandıkça veya sağlanana dek çalıştırılacağını belirtir [1]. Aslında bu bir ayrıştırma (parse) problemidir. Çalıştırılacak kod “while” veya “until” ifadesinden önce gelen kısmın tümüdür. Kontrol ifadesi, çalıştırılacak koddan sonra yazılsa bile önce sınanır.


sayi = 10
puts sayi-- while sayi>=0


sayi = 10
puts sayi-- until sayi<0

    • for .. in

“for/in” ifadesi for’un özelleşmiş bir şeklidir. Dizi gibi sayılabilir yapıların tek tek dolaşılmasını sağlar [1]. Örneğin aşağıdaki kod sizideki elemanları tek tek ekrana yazar.


dizi = [1,2,3,4,5]
for eleman in dizi
puts eleman
end


Hash gibi yapılarda dolaşılırken, hem anahtar kelimeye hem de değere tek tek erişilebilir.


hash = {:a=>1, :b=>2, :c=>3}
for key,value in hash
puts "#{key} => #{value}"
end


  1. İlerletici (Iterator) & Sayılabilir İfadeler

“for”, “while”, “until” gibi döngü yapıları çoğu programlama dilindeki standart yapılardandır. Ancak döngü amacıyla ilerletici denilen özel metodlar Ruby’de daha sık kullanılmaktadır [1].


    • Sayısal İlerleticiler

Ruby dilindeki sayısal ilerleticiler belirli sayıda çalışacak döngüler oluşturmada kullanılır [1].
Tablo 1 Sayısal İlerleticiler
İLERLETİCİ
AÇIKLAMA
ÖRNEK
times
Belirtilen sayıda tekrarı sağlar
2.times { puts "selam!" }
upto
Küçükten büyüğe belirli sayıya kadar döngü sağlar
factoriyel = 1
2.upto(n) {|x| factoriyel *= x }
downto
Büyükten küçüğe belirli sayıya kadar döngü sağlar
10.upto(0) { |x| puts x }
step
Belirli sayıya kadar adım adım sayar
0.step(10,0.1) {|x| puts x }

    • Sayılabilir İlerleticiler

Ruby dilinde Array, Hash, Range gibi sayılabilir veriler üzerinde işlem yapan çeşitli ilerleticiler vardır [1].
Tablo 2 Sayılabilir Verilerde Kullanılan İlerleticiler
İLERLETİCİ
AÇIKLAMA
ÖRNEK
each
Verinin her birine tek tek erişimi sağlar
veri.each {|x| puts x }
map
Verinin her birine erişir
[1,2,3].map {|x| x*x }
select
Verinin elemanlarını bir şarta bağlı seçer
tekler = (1..10).select{|x| x%2==1 }
reject
Verinin elemanlarını bir şarta bağlı eler
tekler = (1..10).reject{|x| x%2==0 }
inject
Verinin elemanlarını tek tek belirtilen işleme sokar
toplm = data.inject {|toplm, x| toplm + x }

    • Harici İlerleticiler

Ruby’de ilerletici (iterator) yapısı bir değişkene atanıp, buna next gibi metodlarla dışarıdan erişmeyi mümkün kılar [1].


iterator = 10.downto(1)
loop do
print iterator.next
end
puts "...bomba patladı!"


  1. Akışı Değiştiren İfadeler

Birçok programlama dilinde olduğu gibi, Ruby’de de programın normal akışını kesen veya akışı başka bir yöne değiştiren ifadeler mevcuttur.

    • return

“return” ifadesi bir metoddan çıkmaya ve kendisini çağırana bir değer dönmeyi sağlar [1].


def double(x)
  return x, x.dup
end


    • break

“break” ifadesi bir döngü veya ilerleticiden çıkılmasını sağlar [1].


sayi = 0
while sayi >= 0 do
 sayi = sayi + 1
 break if sayi==10
end


    • next

“next” ifadesi bir döngü veya ilerleticinin sonuna gelinmişçesine bir sonraki aşamaya geçmesini sağlar [1].

    • redo

“redo” ifadesi bir döngü veya ilerleticideki en son çalışmanın başına döner [1].


sayi = 0
while sayi < 3 do
 # redo dendiğinde buradan başlar
 sayi = sayi + 1
 redo if sayi==3
end
# sayi burada 3 yerine 4 değerini almış oldu


    • retry

“retry” ifadesi bir ilerleticinin tekrar başlamasını sağlar ve tüm ifadenin tekrar işletilmesine yol açar [1].


sayi = 0
# retry dendiğinde buraya döner
while sayi < 10 do
 puts sayi;
 sayi = sayi + 1
 if sayi==3
   sayi=4
   retry
 end
end
# Ekrana 0,1,2,4,5,6,7,8,9 basılır. Yani 3 hariç.


    • throw/catch

“throw/catch” yapıları Ruby’de birden fazla iç içe döngüden çıkmak için kullanılabilir.


a=0; b=0; c=0; d=0;
while a < 3 do
 catch :etiket do

   while b < 3 do
      while c < 3 do
         while d < 3 do
            throw :etiket if d=2
            d=d+1
         end
      end
   end

 end

 # throw sonrası buraya düşülür

end

  1. BEGIN ve END İfadeleri

Ruby’de BEGIN ve END isimli iki özel kelime vardır. (“begin .. end” ifadesinden farklı) BEGIN ve END sonrası köşeli parantezlerle ayrılmış bir blok gelmesi zorunludur. BEGIN ile işaretli kod programın en başında çalışır, END ise programdan çıkarken ve bir kere çalışır. Döngü içine yazılsa bile durum böyledir [1].


  1. Değerlendirme

Ruby direk olarak go-to komutunu desteklemese de dildeki yapılar kullanarak go-to fonksiyonu sağlanabilir [1,3]. Ayrıca daha önceki bölümlerde anlatılan “catch/throw”, “retry”, “redo” gibi yapılar ile kısmen goto benzeri atlama yapılabilmektedir.



[1] Flanagan D., Matsumoto Y., The Ruby Programming Language, O'Reilly Media, 2008.


[2] M. Slagell and P. Yanardağ, "Ruby Kullanıcı Kılavuzu," 22 Nisan 2003, http://pdf.belgeler.org/uygulamalar/ruby/ruby-ug.pdf. [Erişim Tarihi: 15 Mayıs 2014].


[3] Benjamin Bock, Goto for Ruby, https://rubygems.org/gems/goto. [Erişim Tarihi: 15 Mayıs 2014].



NOT: YTÜ - İleri Programlama Dili Dersi 2014 1. Dönem Ödevi Çerçevesinde Hazırlanmıştır.

NOT 2: Ruby 1.9 baz alınmıştır.


Hiç yorum yok: