Ruby/Temeller
←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üzenleDeğ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üzenleRuby'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üzenleRuby'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üzenleRuby'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üzenleRuby 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.