Ruby birçok platformda çalışan, açık kaynak, dinamik, nesne temelli, yorumlamalı bir dildir. Basit ve üretken olmak amaçlı geliştirilmiştir. 1995 yılında Yukihiro Matsumoto (Matz) tarafından geliştirilmiştir.
Bu yazıda Ruby'nin temel tekniklerini inceleyeceğiz. Ruby programlama dili hakkında bilgilendirme amaçlayan Wikibooks Ruby Tercümesi de tarafımdan büyük kısmı yapılmış bir tercüme olarak birçok bilgi içeriyor. Okumanızı tavsiye ederim.
Merhaba Dünya
Ruby programlama dilinin bilgisayarınızda kurulu olduğunu kabul ederek ilk programı yazmaya başlayalım. Ben genelde Ubuntu işletim sisteminde ve editör olarak da VSCode editör kullanıyorum.
Şimdi denemelerimizi yapacağımız bir klasör oluşturup içinde ilk programımız olan merhaba.rb dosyasını ekleyelim ve içine şu kodu yazalım:
Komut satırında (terminalde) bu programı çalıştırmak için,
Burada $ işareti terminal emülatör programınızdaki prompt'u ifade eder, herkesin sisteminde farklı birşey yazar, gösterim için genelde $ işareti kullanılır.
Terminalde bunu yazıp enter bastığımızda programımız çalışır ve şu çıktıyı verir:
Programı çalıştırdığımız anda bu çıktı ekrana hemen yazılır. Ruby program dosyaları çalışmadan önce derlenmeye gerek duymaz. Ruby yorumlayıcısı (interpreter) çalışma zamanında bu kodu derler ve çalıştırır.
Unix Benzeri Sistemlerde Kendiliğinden Çalışan Kod Dosyası Oluşturmak
Kod dosyamıza yorumlayıcı direktif satırı (shebang) ekleyebiliriz.
Betik dosyamıza (merhaba.rb) çalıştırılabilir özelliği vermek için terminalde :
Artık dosyamızı ismini vererek çalıştırabiliriz.
Bir ayrıntı verelim, ruby merhaba.rb
derken dosya ismini direk yazmıştık, niye dosyayı sisteme direk çalışır olarak tanıtınca merhaba.rb
deyince çalışmıyor da illa ./merhaba.rb
şeklinde aynı klasörde olduğumuz dosyaya yol gösteriyoruz? Sebebi sistemin güvenlik kaygıları, Unix sistemler çalıştırılabilir dosyaları sadece kendilerine tanımlı uygulama çalıştırma klasörlerinde ararlar, içinde bulunduğunuz klasörde dahi olsa çalıştırılabilir dosya aranmaz. Ancak ve ancak dosyanın PATH bilgisini vererek çalıştırabilirsiniz.
Shebang satırı, dosyada ilk satır olur, "#!" ile başlar ve Ruby yorumlayıcı uygulamasının yerini belirtir. Aslında yorumlayıcının yeri kullanıcı ya da sistem bazında kurulum yapmış olmanıza göre (mesela usr/bin/ruby veya usr/local/bin/ruby) değişir, ama burada gösterilen /usr/bin/env ruby
ruby programının olduğu yeri otomatik bulur.
Kod dosyanızı artık sisteme çalıştırılabilir olarak bildirdiğiniz için , içindeki kodu değiştirseniz bile en istteki shebang satırı değiştirmedikten sonra direk çalışır olmaya devam edecektir.
IRB Programında "Merhaba Dünya" Kodu
irb uygulaması Ruby kod satırlarınızı direk olarak yazıp denemek amaçlı kullanılır. Bir şeyler test etmek için faydalıdır. Terminalde bir irb oturumu açmak için :
Komutunu girdiğimizde karşımıza standart irb prompt'u çıkar.
Kısa prompt ile çalışmak için terminalde
Komutu girerseniz prompt şöyle olur:
Önce çıkmasını öğrenelim. Irb oturumunu sonlandırmak için prompt yanına exit
yazarsınız.
Şimdi irb satırına Ruby kodumuzu girelim :
Enter bastığımızda kodumuz hemen çalıştırılır ve ekrana şunu yazar:
İlk satır, kodumuz çalışınca gerçekleşen çıktı yazma işleminin sonucudur — ekrana Merhaba Dünya! yazar. İkinci satır ise satırda kullandığımız puts metodundan dönen değer olan nil'dir (ki dönen değer neymiş ileride göreceğiz).
puts deyimi ekrana yazı yazdıktan sonra alt satıra geçer, eğer alt satıra geçilmesini istemiyorsak (yani daha o satıra ileride eklemek istediklerimiz varsa) print deyimini kullanırız.
Kod Dosyası Olmadan Merhaba Dünya Kodunu Çalıştırmak
Terminalde bir Ruby kodunu direk olarak çalıştırmanın da bir yolu var. Şimdi şu minicik tek satırlık kodumuzu , dosya oluşturmadan çalıştırmak için terminalde şunu girelim:
Daha uzun programları Ruby yorumlayıcısına here döküman kullanarak girebiliriz.
Çıktısı :
İlk Metodumuz
Metodlar belirli işlerimizi tekrar tekrar yapabilmek için aynı kodları tekrar takrar yazmamak amacıyla, bir grup kodu bir blok içinde toplayıp ona bir isim vererek oluşturulur. Daha sonra bu isim kullanılarak aynı kodları defalarca çalıştırabiliriz.
Şimdi ilk_metodum.rb adında yeni bir kod dosyası üretip içine şunu yazalım:
def kelimesi Ruby'ye bir metod tanımlamakta olduğumuzu anlatıyor (def-ining). Metodumuzun adı ise merhaba.
puts "Merhaba Dünya!" , bildiğimiz gibi konsola Merhaba Dünya! yazar.
end deyimi tanımladığımız merhaba metodunun bittiğini ifade eder.
Bu programı bu haliyle çalıştırırsanız hiçbir şey yapmaz. Çünkü metodu sadece tanımladık, ama kullanmadık. Metodu kullanmak için onu çağırmalıyız. Çağırmak için metodun adını yazmamız gerekir.
merhaba() şeklinde parantezli kullanım hemen tüm diğer programlama dillerinde metod çağırma şeklidir. Ruby'de parantezleri kullanmadan da metod çağırabiliriz. Gerçi ileride parametreleri olan metodlarda mecburen parantezleri kullanmak gerekebilecektir. Ama Ruby şeklini kullanmaya özen göstersek daha iyi olacaktır.
Programımızı çalıştırırsak çıktısı şöyle olur :
Her iki kullanım şekli de sağlıklı çalışıyor.
Veri Tipi Dönüşümleri
Ruby'de bir veri tipinden diğerine dönüştürme yapmak için öntanımlı metodlar vardır.
-- Float değere dönüştürmek
Bir irb oturumu açın ve şunları deneyin :
Ruby kullanıyoruz Float metodunu parantez olmadan da kullanabiliriz.
to_f string nesnelere ait bir öntanımlı metod ve verilen string değeri kayan noktalı sayıya çeviriyor. Burada gördüğümüz "123.45" değeri bir string (karakter dizisi) nesnesidir, merak etmeyin onları da göreceğiz. Bir nesneye ait metodlar nesne arkasına nokta ve metod adı eklenerrek çağrılır, burada da "123.45".to_f şeklini görüyorsunuz.
Float ise kayan noktalı sayıların ifade edildiği nesnelerin üretildiği sınıf adı. Ruby dilinde her şey bir nesnedir ve 123.45 de aslında öyle düz bir değer değil bir nesnedir. Hangi sınıftan bir nesne olduğunu görmek için irb satırına
Gördüğümüz gibi bir basit sayı değil, bir Float nesnesi, ki bunu zaten .class metodunu çağırırken kabul ediyoruz, metodlar nesnelere uygulanır.
Ama ya sayıya dönüştürülemeyecek bir değer verirsek? Mesela
to_f metodu sayı olmayan değere karşılık 0.0 değerini üretirken Float() argüman değerinde hata mesajı vererek başarısız oldu.
-- String değere dönüştürmek
Hadi şimdi tersini yapalım.
Genelde String() çağrısı doğrudan verilen argümanın #to_s metodunu çağırır.
Kernel#sprintf ve String#% metodları davranışları C diline benzer:
-- Integer değere dönüştürmek
Tamsayı değere dönüşütürmek için kullanılan yöntemler :
Son örnekteki Integer deyimi bir float sayı string şeklinde verilirse dönüştürme yapmaz, tamsayı değeri string olarak yazılmalıdır.
İstersenin 123.45.to_i ifadesini daha anlaşılabilir olması için (123.45).to_i şeklinde yazabilirsiniz.
Bir tamsayı değerle başlayan her string değer tamsayıya dönüştürülebilir, ama sayı ile başlamıyorsa dönüştürülemez.
İki yöntem arasında float'da olduğu gibi fark vardır.
-- Float ve Integer
İki tamsayının bölümü yine tamsayı olmalıdır, örnekte sonuç 0.5 olamaz, tamsayı kısmı olan 0 alınır.
Eğer kayan noktalı sayı olarak sonuç istiyorsak en az bir sayıyı Float şeklinde ifade etmeliyiz.
Ya da değerleri Float'a dönüştürerek kullanabiliriz.
İkinci örnekte Float() metodunu parantezlerle ifade ettik, çünkü önce 2 sayısının Float yapılmasını , sonra bölme işlemi yapılmasını istiyoruz.
Alternatif olarak fdiv metodu değerleri dönüştürmeden float işlem yapmak için kullanılabilir.
Demek ki fdiv metodu Integer sınıfının bir oluşum metodu.
Array Değerler
Array , içinde birçok değer barındıran bir nesnedir. Ruby'de her şay bir nesne olduğu için array içinde birçok nesne barındıran bir nesne de denebilir.
Bir array şu şekillerde ifade edilebilir :
-- String elemanları olan array
Elemanları string değerler olan bir array,
Bu satırı Ruby %w operatörü kullanarak şöyle yazabiliriz.
%w() yapısında sınırlayıcı karakterler olarak eşleşmesi olan herhangi bir karakter çifti kullanılabilir, mesela %w{...} , %w[...] , %w<...>.
Ayrıca birbiri ile aynı alfanumerik olmayan karakterler de kullanılabilir. Mesela : %w!...! , %w#...# veya %w@...@.
String içinde enterpolasyon yapılacaksa (yani bir Ruby işlemin sonucu yazılacaksa), %w değil, büyük harf %W kullanmak gerekir.
Çok kelimeden oluşan değerler boşluk öncesine \ koyarak birleşik oldukları belirtilebilir.
-- Array.new ile yeni bir array üretmek
Boş bir array ([ ]), Array sınıfının sınıf metodu olan Array::new kullanarak üretilebilir.
Array eleman sayısını vereceğiniz ilk argümanla girebilirsiniz.
Bir array'i default değerlerle doldurmanın iki yolu vardır :
- İkinci argümanda sabit bir değer vermek
- Bir kod bloğu yardımıyla, index numarasını da alarak değiştirilebilir değerler vermek
Birinci yöntem tavsiye edilmez , çünkü tüm elemanları aynı değere sabitler.
Elemanın birini değiştirdik , hepsi değişti.
Mantıklı olan ilkinci yöntemi kullanmak.
Kod bloğu olayına da gireceğiz, merak etmeyin.
-- Sembol elemanları olan array
Elemanları sembol değerler olan bir array tanımlarken %i operatörü kullanılır.
%i(...) yerine, %i{...} veya %i[...] veya %i!...! da kullanılabilir.
Eğer enterpolasyon yapacaksanız %I kullanmalısınız.
-- Array elemanlarını işlemek
Eleman eklemek :
Eleman silmek :
Array'leri birleştirmek :
Ayrıca array ile çarpma da yapılabilir.
-- Array elemanlarına erişmek
Array elemanlarına köşeli parantez içinde index değerlerini kullanarak erişirsiniz, index numaraları sıfırdan başlar.
Range tanımları kullanarak array elemanlarından kesit alabilirsiniz.
Bu işlemler yeni array oluşturur, orjinal array elemanları etkilenmez. Ruby'de negatif array indexleri de desteklenir.
Negatif ve pozitif indexleri karışık kullanmak da mümkün.
diğer yararlı metodlar
first metodu ile array'in ilk elemanına erişilir.
first(n) ile ilk n sayıda elemana erişilir.
last ve last(n) ile de sondan itibaren elemanlara erişilir.
sample metodu ile array içinde rastgele bir elemana erişilir.
veya sample(n)
-- Değer ifadesi ile array oluşturma
Bir array, elemanları köşeli parantez içinde ([ ]) verilerek tanımlanabilir.
Array bir nesneler dizisidir, içerisinde değişik veri tiplerinde elemanlar olabilir.
-- Array elemanlarını ayrıştırmak
Bir array elemanlarını ayrıştırmak için çoklu değişken ataması yapılabilir.
Değişkenin birinin önüne yıldız operatörü ( * ) koymak o değişkene diğer değişkenlere atanmayan tüm elemanları saklar.
Ayrıştırma güvenli bir işlemdir ve asla hata vermez, [ ] yapısıyla sınırlar dışında bir index'e erişmeye çalışıp eleman bulunamadığında nil değer verilir.
Ayrıştırma işlemi array olmayan nesnelere uygulandığında otomatik olarak o nesnenin to_ary metodu çağrılır. Bu metodu kendi veri tiplerinize de uyarlayarak verilerinizin ayrıştırılabilir olmasını sağlayabilirsiniz.
Eğer ayrıştırılacak nesne to_ary metoduna cevap vermiyorsa, tek elemanlı bir array varmış gibi davranır.
Ayrıştırma işlemi parantezler yardımıyla iç içe de yapılabilir. Parantez içindeki ayrıştırma ifadesi aslında oraya konmasaydı karşı gelecek tek bir değerin yerini alır.
Biraz ayrıntılı düşünürsek.
x değişkenine gelen değer (b, *c) olarak ayrıştırılıyor.
Aslında herhangi bir ayrıştırma ifadesi parantez içinde yazılabilir. En üst seviyede bu opsiyoneldir.
Ayrıştırma paterni tek bir ifade içeriyorsa parantez içinde yazılmaz.
Ayrıştırma ifadesi eşitliğinin sağ tarafında bir array değer ifadesi varsa üst seviye köşeli parantezler gözardı edilebilir.
Buna paralel atama denir ve arkaplanda tamamen aynı işlemi yapar. Bu değişken içeriklerini harici bir geçici değişken kullanmadan değiştirmek için çok etkili bir yoldur.
Atama yapılırken eşit işaretinin sağıdaki değer ayrıca hesaplanır ve sonra atama yapılır. Bu sayede aynı değişken isimleri kullanılabilir.
-- Array'lerde bileşim, kesişim ve fark
İki tane array olsun.
Bileşim operatörü ( | ) her iki array'de olan elemanları aynı olanları elimine ederek birleştirir.
Kesişim operatörü ( & ) her iki array'de de mevcut olan elemanları bulur.
Fark operatörü ( - ) birinci array'de olup ikicide olmayan elemanları bulur.
-- İki boyutlu array
Array::new metodunu kullanarak her elemanda yeni bir array olacak şekilde bir yapı tanımlayabilirsiniz.
3x4 boyutlarında bir array'i değerler sıfır olacak şekilde tanımlamak istersek.
Bu iki boyutlu array elemanlarına okma ve yazma şöyle yapılır:
Dıştaki array'in 2 indexli elemanı olan array'in 3 indexli elemanı.
-- inject ve reduce
inject ve reduce aynı şey için iki farklı isim. Argümanında 2 argümanı olan bir kod bloğu alır ve bu bloğu tüm eleman çiftlerine iterasyonla uygular. Bunu yaparken ilk değer olarak argümanda verilen değerle başlar. Örnek
Başlangıç değerini farklı verirsek.
Başlangıç değeri default 0'dır, vermesek de olur.
Kod bloğu içinde tek bir işlem yapıldığı için Ruby'ye sadece bu işlemi (metodu) sembol olarak bildirsek , o ne istediğimizi anlar.
Sıfırdan başlarsak argüman vermeyebiliriz.
-- Array'lerde filtreleme
Bazen bir ihtiyacımızı karşılamak amacıyla belli koşullara uyan array elemanlarına işlem yapmak isteyebiliriz.
-- -- select metodu
Bu deyim belli koşulları karşılayan elemanları bulur.
-- -- reject metodu
Bu deyim belli koşulları karşılamayan elemanları bulur.
reject ve select metodları bir array döndüğü için zincirleme kullanılabilirler.
Parantezler olmadan Ruby yorumlayıcı bu satırı nasıl çözdü merak ediyorum.
-- Array'ler ve yıldız operatörü
Yıldız operatörü ( * ) Ruby'de değişkenleri ve array'leri açmak için kullanılabilir. Böylece metodlara bağımsız argümanlar (ya da çoklu argüman) göndermek için kullanılabilir.
Bu kullanımı örneğin bir nesneyi array içine konmuş şekle dönüştürme amaçlı kullanabiliriz.
Bu örnekte array_olarak_paketle metodu sadece bir parametre alır değer. Eğer değer bir array'se elemanlarına ayrılır ve yine bir array içinde toplanır.
Eğer değer tek bir nesneyse tek elemanı bu nesne olan bir array oluşturulur.
Eğer değer, nil ise boş bir array oluşturulur.
Yıldız operatörü metod parametresi tanımlarken bazen çok işimize yarar. Onu kullanarak tanımladığımız bir parametreye metod çağrılırken nil, tek bir değer, bir array ya da çoklu değer de verebiliriz.
-- Array'lerde map metodu
Array#map metodu arkasından verilen kod bloğunu array'in her elemanı için çalıştırarak iterasyon yapar, ve sonuçları toplar.
Orjinal array değiştirilmez yeni bir array aynı elemanların işlendiği sırayla dönen değer olarak üretilir. Eğer orjinal array'i değiştirmek istiyorsanız map! metodunu kullanınız.
map metodunda tüm elemanlara aynı metodu uygulayabilir ya da her biri için aynı Proc rutinini uygulayabilirsiniz.
map ve collect metodları eşdeğerdir.
& operatörü bir Proc nesnesini kod bloğuna çevirir, &:to_i ifadesinde to_i metodu önce otomatik olarak to_proc metodu ile Proc nesnesine dönüştürülerek kullanılır.
İkinci örnekteki Proc nesnesi üretme kodu genellikle daha uzun işlemler yapacağımızda kullanılır. Proc nesnesi dediğimize göre de bir değişkene konabilir. Örneğin:
ya da
gibi. Böylece map yanına uzun bloklar koymak zorunda kalmazsınız.
-- Çok boyutlu array'i tek boyutlu düz array haline getirmek
Oldu da gerekirse bu işlem için flatten metodunu kullanırız.
-- Array elemanlarının eşit olanlarından kurtulmak
Bir array'in elemanlarını tekrarlananlar olmadan elde etmek istersek uniq metodunu kullanırız.
Array içindeki tekrarlanan elemanları yok etmek istersek direk array'e işlem yapan uniq! metodunu kullanırız.
-- Bir array'in tüm kombinasyon ve permutasyonlarını bulmak
Array'in tüm permutasyonlarını bulmak için permutation metodu kullanılır, bu bize bir Enumarator nesnesi döner.
İçinde ne var olduğuna erişmek için map ile işlem yapabilir ya da to_a metodu ile sonuçları iki boyutlu array olarak alabiliriz.
2'li permutasyonlarını bulmak için, 2 değerini argüman olarak veririz.
4'lü istesek boş sonuç gelir.
Kombinasyon için combination metodu kullanılır. Bilindiği gibi kombinasyonlarda sıralama gereği yoktur, yani [1, 2, 3] ile [3, 2, 1] aynıdır.
Yine 2 boyutlu array'ler dönüyor. combination metodunun bir farkı , argüman vermek zorundasınız.
repeated_combination ve repeated_permutation metodları da benzer işler yaparlar ancak bulunan olasılıklarda aynı elemanlar defalarca kullanılabilir olarak düşünülür.
gibi. Sanki şifre çözme programı için yapılmış.
Bana sorsanız ben de derdim 0000'dan 9999'a kadar 10 bin olasılık vardır. Ama bunlar örnek, çok daha karmaşık array'ler üzerinde işlem yaparken lazım bu metodlar.
-- compact ile array içinde nil olan elemanları uzaklaştırmak
Bir array içindeki nil olan değerleri silmek için Array#compact ya da Array#compact! metodları kullanılır.
Son olarak bir not compact! metodlarını içinde nil değerli eleman olmayan bir array nesnesinde çağırırsanız, sonuç nil olur ama orjinali değiştirmez.
-- Sıralı sayı ya da harflerden array oluşturmak
Bu bir Range nesnesine Enumerable#to_a metodu uygulayarak yapılabilir.
(a..b) notasyonu iki uçtaki a ve b sayıları dahil tüm sayılar için kullanılır, sondaki sayıyı dışarıda bırakmak için üç noktalı (a...b) notasyonu kullanılır.
ya da harfler için
Türkçe karakterlerde aynı işi yapmanın hazır bir yolunu bulamadım kendim bir şeyler karaladım.
-- Sayılardan array oluşturmak
Sayılardan array oluşturmanın normal yolu
Range nesneleri de sıralı sayılardan array oluşturmak amaçlı kullanılır.
ya da
Range sayılarda istediğimiz koşulları empoze etmek için step ve map metodları kullanabiliriz.
-- Herhangi bir nesneyi array'e dönüştürmek
Kernel#Array fonksiyonu ile diğer nesneler array'e dönüştürülebilir.
Diyelim string_olarak_birleştir adında bir metod yazdınız.
bu metodu basitçe şöyle yazabilirsiniz.
Şimdilik bu kadar yeterli, bir sonraki bölümde sınıflara geçeceğiz nasipse.
Kalın sağlıcakla..
Hiç yorum yok:
Yorum Gönder