İçeriğe atla

Ruby/Temeller

Vikikitap, özgür kütüphane

←Nesnelere giriş | Veri tipleri→

Bu öğreticinin devam eden bölümlerinde programlama dili konseptlerini (örn. If yapısı, while döngüsü) biraz bilmek ve nesne-yönelimli programlama hakkında biraz bilgi sahibi olmak sizlerden beklentimiz olacaktır.


Değişkenlerle çalışmak

[düzenle]

Değişkenlerle çalışmayı sınıflar ve nesneleri konuşurken daha derinlemesine inceleyeceğiz. Şimdilik basit yerel değişkenlerin küçük harf ya da alt çizgi ile başlaması gerektiğini, içinde büyük ya da küçük harfler, sayılar ve alt çizgiler olması gerektiğini bilelim yeter. Global değişken isimleri de $ işareti ile başlar.


Program akışı

[düzenle]

Ruby'de oldukça standart döngü ve dallanma yapıları vardır: if, while ve case

Örneğin, burada if yapısı kullanımı görülüyor:

a = 10 * rand

if a < 5
  puts "#{a}, 5'ten küçük"
elsif a > 7
  puts "#{a}, 7'den büyük"
else
  puts "Peynirli sandwiç!"
end

[Diğer birçok programlama dili gibi rand fonksiyonu 0 ile 1 arasında rastgele sayı üretir]

Koşullu dallanma yapıları hakkında ilerideki bölümlerde oldukça tartışacak zamanımız olacak. Yukarıdaki örnek oldukça anlaşılabilir yazıldı.

Ruby ayrıca if yapısının ters mantığıyla çalışan unless yapısına da sahiptir, şöyle ki:

unless a > 5
    puts "a değeri 5'ten küçük ya da eşit"
else
    puts "a değeri 5'ten büyük"
end


Geneli konuşursak Ruby if yapısı kullanılırken (if ...) ve bağlı kod bloğu ayrı satırlarda yazılır. Eğer her şeyi tek bir satırda birleştirmek zorundaysanız, koşuldan sonra then kelimesi kullanarak bloğu arkasına yazarsınız.

if a < 5 then puts "#{a} değeri 5'ten küçük" end 
if a < 5 then puts "#{a} değeri 5'ten küçük" else puts "#{a} değeri 5'ten büyük" end

Şunu da söyleyelim if deyimi aynı zamanda bir eşitliktir; ve değeri de kodun son satırı işlendiğinde oluşan değerdir. Bu yüzden yukarıdaki kod şöyle yazılabilir:

puts(if a < 5 then "#{a} değeri 5'ten küçük" else "#{a} değeri 5'ten büyük" end)


Ayrıca Ruby'nin Perl'den almış olduğu şeylerden biri de, if ve unless ifadeleri başka bir ifadeden sonra ona koşul bağlamak için kullanılabilir. Örneğin:

puts "#{a} değeri 5'ten küçük" if a < 5
puts "Peynirli sandviç" unless a == 4


while ifadesi diğer dillerdeki gibi davranır — takip eden kod bloğu koşulun doğru olduğu müddetçe sıfır ya da daha fazla kere tekrar çalıştırılır

a = 10

while a > 5
    puts a
    a = a - 1
end

Ve aynı if gibi, while ifadesinin de ters mantıkla çalışan versiyonu vardır, o da until ifadesidir ve koşul doğru olana kadar tekrarlar.


Son olarak burada kısa bir örnekle açıklayacağımız case ifadesi var. case aslında if ... elsif... sisteminin kolaylaştırılmış bir halidir.

a = rand(11) # 0 ile 10 arasında bir rastgele tamsayı üretir

case a
when 0..5
  puts "#{a}: Düşük"
when 6
  puts "#{a}: Altı"
else
  puts "#{a}: Peynirli tost!"
end

Bu örnekte henüz görmediğimiz başka ilginç şeyler de var ama biz burada case ifadesini dikkatimize alıyoruz.


Fonksiyon tanımlamak

[düzenle]

Ruby'nin her-zaman-tamamı-nesne-yönelinli tasarımını korumak için fonksiyonlar, nesne metodları gibi düşünülür, fark yoktur. Nesneler ve sınıflara gelidğimizde metodları çok daha ayrınıtılı inceleyeceğiz. Şimdilik temel metod tanımlaması şuna benzer (aşağıdaki kodu func1.rb isimli betik dosyası olarak kaydediniz):

# metod tanımlaması
def my_function( a )
    puts "Merhaba #{a}"
    return a.length
end
  
# metod kullanımı
len = my_function( "Zürafa" )
puts "Sihirli kelimemiz #{len} karakter uzunluğunda"

şimdi betiği çalıtıralım:

$ ruby func1.rb
Merhaba Zürafa
Sihirli kelimemiz 6 karakter uzunluğunda

Metodlar def deyimi ile tanımlanır, arkasından metod adı gelir. Değişkenler gibi yerel ve sınıf metodların isimleri de küçük harfle başlamalıdır.

Bu örnekte fonksiyonumuz sadece bir argüman alır (a), ve bir değer döner. Dikkat ederseniz argümanın tipi belirtilmedi (a string değer olmak zorunda değil)... bu bize çok esneklik kazandırması dışında çok fazla soruna da sebep olabilir. Ayrıca fonksiyon return ifadesi ile bir değer dönüyor. Teknik olarak değer dönmeye gerek yoktur — son satırdaki oluşan değer fonksiyondan dönen değer olur — fakat return satırını kullanmak kodun okunurluğu bakımından daha iyi bir görsel oluşturur.

Diğer diller gibi Ruby de hem argümanlar için default değerleri hem de değişken uzunlukta argüman listesini destekler, ilerledikçe hepsini göreceğiz. Ayrıca kod blokları da aşağıda göreceğimiz gibi desteklenmektedir.


Bloklar

[düzenle]

Ruby'nin en önemli konseptlerinden biri de kod bloklarıdır. Aslında bu devrim niteliğinde bir konsept değil — C veya Perl gibi dillerde ne zaman if ... { ... } yapısı kullanırsanız aslında bir kod bloğu oluşturuyorsunuz, ama Ruby'de kod bloklarının bazı gizli süper güçleri var....

Ruby'de kod blokları ya do..end ya da süslü parantez içinde {..} yapısıyla ifade edillir.

do
    print "Kod bloklarını "
    print "çok severim!"
end
  
{
    print "Ben de!"
}

Bu kod çalışan bir kod değil, sedece blok yapısının nasıl olduğunu göstermek için böyle verdik. Kod bloklarının en etkili kullanıldığı yerlerden biri, metodların bloğu parametre olarak alması ve metoda verilen tanıma göre bloğu çalıştırmasıdır.

[editör notu: the Pragmatic Programmers kitabı bu şekilde açıklamayı kullanışlı bulmuyor. Yerine kod bloğunu metodun zaman zaman kontrolü devrettiği bir ortak olarak anlatır]

Konsept ilk bakışta anlaşılması zor gelebilir. Bir örnekle devam edelim:

$ irb --simple-prompt
>> 3.times { puts "Hi!" }
Hi!
Hi!
Hi!
=> 3

Süpriiiz! , 3 değerinin bir sayı olduğunu düşünüyordunuz, ama aslında bir nesne ( Fixnum veri tipinde). Bir nesne olduğu için times adında parametresinde bir blok alan bir üye metodu var. Metod parametresinde verilen kod bloğunu 3 defa çalıştırır.

Bloklar da aslında parametre alabilir, özel bir notasyon kullanarak (|..|). Bu durumda times metodu dökümanına kısa bir bakış attığımızda bloğa tek bir değer aktardığını görürüz, hangi turda olduğu sayısı:

$ irb --simple-prompt
>> 4.times { |x| puts "Döngü #{x}" }
Döngü 0
Döngü 1
Döngü 2
Döngü 3
=> 4

times metodu her turda bloğa bir sayı gönderiyor. Blok bu sayıyı x değişkeni içine alıyor (|x| olarak ifade edildiği için), ve sonra blok içindeki kodu çalıştırıyor.

Metodlar bloklarla yield deyimiyle de iletişim kurabilir. Metod yield ifadesine her geldiğinde kontrol bloğa devredilir. Blok kodu işini bitirince kontrol tekrar metoda döner ve kaldığı yerden devam eder. Basit bir örnek verelim:

# block2.rb
 
def simpleFunction
    yield 
    yield
end
  
simpleFunction { puts "Hello!" }
$ block2.rb
Hello!
Hello!

simpleFunction metodunda sadece iki defa kontrol bloğa devrediliyor — yani bloğa iki defa girildiği için çıktı da iki defa yazılıyor. Şimdi de bloğa bir argüman gönderen metod görelim:

# block1.rb
 
def hayvanlar
    yield "Kaplan"
    yield "Zürafa"
end
  
hayvanlar { |x| puts "Merhaba, #{x}" }
$ block1.rb
Merhaba, Kaplan
Merhaba, Zürafa

Burada olanları anlamak için birkaç defa okumak gerekebilir. Bir "hayvanlar" metodu tanımladık — bşr kod bloğu alıyor. Çalıştırıldığında metod iki defa kontrolü kod bloğuna devrediyor, ilkinde argüman değeri "Kaplan" ve ikincide "Zürafa" olarak bloğa geçiyor. Dikkat ederseniz yield metoduna verilen argümanlar kod bloğuna geçiriliyor. Bu örnekte sadece hayvanlara selam ceren basit bir kod bloğu kullandık. Farklı bir blok da yazabilirdik, örneğin:

hayvanlar { |x| puts "#{x} kelimesi #{x.length} karakter uzunluğunda" }
Kaplan kelimesi 6 karakter uzunluğunda
Zürafa kelimesi 6 karakter uzunluğunda

Aynı metodu iki değişik blokla çalıştırdık ve tamamen farklı iki sonuç aldık.

Blokların birçok etkili kullanımı var. En başta gelenlerden biri array'ler üzerinde each metodu uygulanmasıdır — array içindeki her eleman için kod bloğunu bir kez çalıştırır — listeler üzerinde iterasyon için çok etkili bir yöntemdir.


Ruby gerçekten - ama gerçekten nesne yönelimlidir

[düzenle]

Ruby tamamıyla nesne yönelimlidir. Herşey bir nesnedir — hatta sabit zannettiğiniz şeyler bile. Bu aynı zamanda "standart fonksiyonlar" olarak düşünebileceğiniz şeylerin büyük çoğunluğunun bir kütüphanede ortalıkta dolaşmadığı, bunun yerine belirli bir değişkenin metodları olduğu anlamına gelir.

Şu örneği görmüştük:

 3.times { puts "Hi!" }

Her ne kadar 3 sabit bir sayı olarak görünse de, aslında Fixnum sınıfının bir oluşum nesnesidir (Fixnum sınıfı Numeric sınıfından, o da Object sınıfından kalıtım yoluyla türetilmiştir). Bu times metodu da Fixnum sınıfından gelir ve kendisine tanımlanan işleri yapar.

işte bazı diğer örnekler

$ irb --simple-prompt
>> 3.abs
=> 3
>> -3.abs
=> 3
>> "giraffe".length
=> 7
>> a = "giraffe"
=> "giraffe"
>> a.reverse
=> "effarig"

İlerleyen bölümlerde Ruby'nin nesne-yönelimli çalışması hakkında öğrenmeye devam edeceğimiz çok zamanımız olacak.