Selam, Ruby temel tekniklerine kaldığımız yerden devam ediyoruz.
Singleton Sınıflar
Singleton (tekil) sınıfların sadece bir tane oluşum nesnesi olabilir.
Ruby'de 3 çeşit nesne vardır
- Class ve Module sınıflarının oluşumu olan sınıflar ve modüller
- Sınıfların oluşum nesneleri
- Singleton sınıflar
Her nesne, onun metodlarını içeren bir sınıfa sahiptir.
Nesneler kendileri metod barındıramaz, sadece sınıfları barındırabilir. Fakat tekil sınıflar yardımıyla sadece o nesneye ait metodlar tanımlayabiliriz (yani metod gene nesne içnde değil , bir sınıf içinde tanımlanır).
foo metodu Ruby tarafından nesne nesnesinin singleton sınıfında tanımlanır. Diğer Örnek sınıfı oluşumları bu metod çağrısına cevap vermezler.
Ruby tekil sınıfları ihtiyaç olunca üretir. Onlara erişmeye kalkınca ya da yukarıdaki gibi metod eklemeye kalkınca Ruby otomatik olarak tekil sınıfını oluşturur.
-- Tekil sınıflarda kalıtım
-- -- Altsınıf üretme aynı zamanda tekil sınıfın alt sınıfını üretir
-- -- Bir modülü include ya da extend etmek tekil sınıfı genişletmez
-- Tekil sınıflar
Her nesne bir sınıfın oluşumudur. Ancak , tüm gerçek bu değil , Ruby'de her nesnenin ayrıca bir şekilde tekil sınıfı (singleton class) vardır.
Bu sayede sadece bir nesneye özel metodlar tanımlanabilir. Tekil sınıf nesne ve onun üretildiği sınıf arasında bir yerdedir. Bu yüzden tekil sınıfta tanımlanan metodlara sadece ve sadce o nesneden erişilebilir
Yukarıdaki örnekte metod tanımlamasını define_singleton_method metodunu kullanarak da yapabiliriz.
Ya da daha da dolambaçlı yoldan, nesnenin tekil sınıfına metod tanımlaması göndererek.
Singleton sınıf öncesinde Ruby'de metaclass adında bir yapı vardı ve ona erişmek için
deyim yapısı kullanılırdı.
-- Bir nesnenin tekil sınıfına erişmek
Aslında iki yöntemi de daha önceki örneklerde gördük
-- Ana sınıfın değişkenine tekil sınıftan erişmek
Tekil sınıflar bağlı oldukları nesnenin sınıf değişkenlerini sadece nesne içinde paylaşırlar. Bazı örnekler verelim.
Bloklar oluşum/sınıf değişkenlerine yakındır. Başka bir ortam içinde blok kullanarak oluşum veya sınıf değişkenine ulaşılamaz. class_eval'e bir string yollamak veya class_variable_get metodu kullanmak sorunu çözer.
Bu hatalı sonuç veriyor ama bu
doğru çalışıyor. Bu da sorunu çözer
-- Tekil sınıflarda mesaj yayılması
Oluşum nesneleri metod barındırmaz onlar sadece veri barındırırlar. Ancak bir sınıf oluşumu olan her nesne bir tekil sınıfa sahiptir.
Bi,r nesneye bir mesaj yollandığında (yani o nesnede bir metod çağrıldığında) Ruby ilk önce bu nesne için tanımlı bir tekil sınıf var mı? diye ve bu mesajı cevaplıyor mu? (yani orada bu metodun tanımı var mı) diye bakar. Bulamazsa nesnenin oluşturulduğu sınıf ve onun atalarına doğru mesaj yayılmaya devam eder.
-- Tekil sınıflarda monkey patching
Monkey patching bir kodun davranışını dinamik olarak değiştirmek anlamına geliyor. Bir tekil sınıfı tekrar açıp müdahale etmenin 3 yolu var:
- Tekil sınıf üzerinde class_eval kullanmak
- class << blok kullanmak
- Nesnede metod tanımlamak için direk def ifadesi ile tekil sınıfa erişmek
Her nesnenin kendi tekil sınıf vardır.
File I/O
-- Dosya ve giriş/çıkış işlemleri
-- -- Parametreler
Flag | Anlamı |
---|---|
"r" | Read-only, sadece okunabilir, dosyanın başından başlar (default mod) |
"r+" | Read-write, okuma-yazma, dosyanın başından başlar |
"w" | Write-only, sadece yazma, mevcut dosyayı sıfır uzunluğa çevirir, olmayanı yeni üretir ve yazmak için açar |
"w+" | Read-write, okuma yazma, mevcut dosyayı sıfır uzunluğa çevirir, olmayanı yeni üretir ve okumak-yazmak için açar |
"a" | Write-only, sadece yazma, mevcut dosyanın sonundan başlar, olmayanı yeni üretir ve yazmak için açar |
"a+" | Read-write, okuma yazma, mevcut dosyanın sonundan başlar, olmayanı yeni üretir ve okumak-yazmak için açar |
"b" | Binary dosya modu, Windows'ta EOL <-> CRLF dönüşmesini zorlar ve aksi belirtilmedikçe encoding'i ASCII-8bit yapar. (Bu flag sadece yukarıdaki flag'larla kullanılabilir. Örneğin File.new("test.txt", "rb") ile test.txt dosyası sadece okunabilir modda binary dosya olarak açılır.) |
"t" | Text dosya modu. (Bu flag sadece yukarıdaki flag'larla kullanılabilir. Örneğin File.new("test.txt", "wt") ile test.txt dosyası sadece yazılabilir modda text dosyası olarak açılır.) |
-- Bir dosya açmak, kapatmak
Dosyayı elle açıp kapatmak.
Blok kullanırsak dosya otomatik kapanır.
-- Dosya içine yazı yazmak
Bir string dosya içine File sınıfı oluşumu nesne kullanarak yazılabilir.
File sınıfı ayrıca new ve close operasyonlarını open sınıf metoduyla birleştirir.
Basit işlemlerde yazmak için direk olarak sınıf metodu olan File.write kullanılabilir. Not, bu default olarak dosyadakilerin üzerine yazar.
File.write sınıf metodunda dosya açma modunu belirtmek için mode isimli bir anahtar ile ilave argüman olarak belirtmeliyiz.
-- Tek karakter bir girdi almak
gerts.chomp ifadesinden farklı olarak bu yöntem Enter basılmasını beklemez. Öncelikle stdlib programımıza dahil edilmelidir.
Sonra bir yardımcı metod yazabiliriz.
Ctrl+c tuş kombinasyonunda programdan çıkmayı eklemezsek program içinde beklerken takılma ihtimali olacağını ve görev yöneticisi falan açmak zorunda olacağımızı unutmayalım.
-- STDIN'den değer okumak
-- ARGV ile argümanları okumak
Komut satırında programımızı çalıştırırken verilen argümanları ARGV özel değişkeninde görebiliriz.
Queue nesnesi
Queue nesnesi bir yığın nesnesi içine yerleştirilen nesneler, özellikle paralel işlemlerde veriye sağlıklı erişmek amacıyla kullanılır. Deyimleri şunlar:
-- Çok çalışan , tek gider
Birçok çalışandan gelen veriyi toplamak istiyoruz. Öncelikle bir Queue nesnesi tanımlarız.
Sonra 16 çalışan aynı gidere rastgele sayılar gönderir.
Veriyi almak için Queue nesnesini array'e çeviririz.
-- Bir Queue nesnesini Array nesnesine dönüştürmek
Ya da tek satır olarak
-- Çok çalışan , tek kaynak
Veriyi paralel işlemek istiyoruz. Önce biraz veri oluşturalım.
Sonra veriyi işleyecek bir kısım çalışanlar üretiyoruz.
Paralel çalışan prosesler veriye rastgele eriştiği halde işlenmemiş hiç bir veri kalmıyor.
-- Tek kaynak - Çalışanlar hattı - Tek gider
Verileri birçok paralel çalışan ile işleyip bir hedefe koyacağız.
Çalışanlar hem veriyi tüketip hem veri üreteceği için iki Queue nesnemiz olmalıdır.
Çalışanların ilk yaptığı ilk_giriş_kaynağı nesnesinden veriyi okumak, sonraki işi ise bu veriyi işleyip ilk_çıkış_gideri nesnesine koymak.
İkinci bir grup çalışansa ilk_çıkış_gideri'ni veri kaynağı olarak alıp elemanlarını işler ve ikinci_çıkış_gideri nesnesine kaydeder.
Şimdi ikinci_çıkış_gideri en son işlenmiş veriyi saklıyor onu da bir array'e dönüştürelim.
-- Bir Queue nesnesine veri basmak - push
- Üst sınır yok, Queue nesnesi sonsuza kadar büyüyebilir.
- #push asla engellenmez
-- Bir Queue nesnesinden veri çekmek - pop
- #pop kullanılabilir herhangi bir veri olana kadar engellenir
- #pop senkronizasyon için kullanılabilir.
Eğer Thread içinde kullanılırsa pop satırında bekler.
-- Senkronizasyon - Zamanlama yönetimi
Thread içinde pop metodunun bekletilmesini senkronizasyon amaçlı kullanabiliriz.
Çıktısı
İlk thread çalışmaya başlıyor ama senkroncu nesnesinde henüz bir veri olmadığı için pop metodunun çağrıldığı yerde bekletiliyor. Bu arada ikinci thread giriyor ve senkroncu nesnesine yeni bir veri ekliyor. Arkasından ilk thread pop satırında artık veri alabildiği için çalışmaya devam ediyor.
-- İki Queue nesnesini birleştirmek
- Sonsuz engellemeye mani olmak için birleştirme yapılan thread içinde okuma da yapılmamalıdır.
- Bir queue nesnesinde veri bitince diğerinin de okuması beklemesin diye birleşecek Queue nesnelerinden okumalar farklı Thread içinde yapılmalıdır.
Önce iki Queue nesnesi üreterek içlerine veri koyalım.
Yeni bir Queue nesnesi oluşturup diğerlerinin içindeki verileri ona aktaralım.
Eğer her iki Queue nesnesini de tamamen boşaltabileceğinizden eminseniz (tüketme hızı ekleme hızından yüksektir) daha basit bir yol da var.
Eğer paralelde başka thread'lerin q1 veya q2'ye daha hızlı veri yüklemediğinden eminseniz bu yöntem daha kısa .
Küme Dağıtma
Bir küme veriyi dağıtma işleminin çoğu sihirli * operatörü ile yapılır.
Örnek | Sonuç / yorum |
---|---|
a, b = [0,1] | a=0, b=1 |
a, *gerisi = [0,1,2,3] | a=0, gerisi=[1,2,3] |
a, * = [0,1,2,3] | a=0 .first metoduna eşdeğer |
*, z = [0,1,2,3] | z=3 .last metoduna eşdeğer |
-- Blok argümanlarını dağıtmak
Aşağıdaki yöntemlerle blok argümanlarını dağıtabiliriz.
IRB Kullanmak
IRB Interactive Ruby Shell demek. Normal bir terminalin işletim sistemi komutlarını canlı olarak işlemesi gibi IRB de Ruby komutlarını canlı olarak denemenize imkan tanır.
Ruby API ile çalışırken IRB vazgeçilemez bir araçtır. Küçük Ruby kodlarının nasıl tepki vereceklerini test etmek için idealdir.
IRB konsolunun en önemli özelliklerinden biri metod isimlerini yazarken size bir liste göstermesi ve listedeki seçenekler arasında Tab tuşu ile seçim yapabilmenizi sağlamasıdır.
Parametreleri
Opsiyon | Detaylar |
---|---|
-f | ~/.irbrc dosyasının okunmasını engeller |
-m | Bc mod (mathn kütüphanesi yüklenir, kesirler ve matrix kullanılabilir) |
-d | $DEBUG değerini true yapar ('ruby -d' ile aynı) |
-r load-module | 'ruby -r' ile aynı |
-I path | $LOAD_PATH klasörünü belirler |
-U | 'ruby -U' ile aynı |
-E enc | 'ruby -E' ile aynı |
-w | 'ruby -w' ile aynı |
-W[level=2] | 'ruby -W' ile aynı |
–-inspect | Çıktılar için "inspect" kullan (default - Bc mod harici) |
--noinspect | Çıktılar için "inspect" kullanma |
--readline | Readline genişleme modülünü kullan |
--noreadline | Readline genişleme modülünü kullanma |
--prompt prompt-mode | Prompt modu değiştir. Ön-tanımlı modlar 'default', 'simple', 'xmp' ve 'inf-ruby' |
–-inf-ruby-mode | emac'lerde prompt'u uygun olan "inf-ruby-mode" a geçirir --readline'ı baskılar |
–-simple-prompt | Basit kısa prompt modu |
–-noprompt | Prompt yok modu |
–-tracer | Her komut çalıştırılmasında trace göster |
–-back-trace-limit n | Back-trace gösterirken n tane geri git Default 16 |
–-irb_debug n | Dahili debug seviyesi n yap (popüler bir kullanım değil) |
-v, –-version | IRB versiyonunu yaz |
-- Temel irb kullanımı
Komut satırında irb yazarak programı çalıştırırız. Basit Ruby komutları girebiliriz.
Metodlar gibi karmaşık blokları da girebiliriz.
-- Ruby betiğinde IRB oturumu çalıştırmak
Ruby 2.4.0'dan itibaren Ruby programımız içinde IRB oturumu başlatabiliriz.
Bu programın bulunulan noktasında bir irb oturumu açar. Burada betiğimizde o andaki değişkenlere erişip kullanabiliriz. Debug işlemleri için çok faydalıdır.
Çıkmak için exit komutu girin ya da Ctrl+D tuşlarına basın. Betik kaldığı yerden devam eder.
Bu bölüme de bu kadar yeter, oldukça uzadı. Sonraki bölümde Enumerator sınıfı üzerinde duracağız inşallah. Şimdilik kalın sağlıcakla..
Hiç yorum yok:
Yorum Gönder