Selam, Ruby temellerini öğrenmeye devam ediyoruz.
Örtülü Alıcılar ve Self
-- Her zaman örtülü bir alıcı vardır
Ruby'de bir metod çağırdığımızda, o metodun mutlaka bir alıcısı (gönderildiği nesne) vardır. Eğer bu alıcı net olarak belirtilmiyorsa Ruby bu örtülü alıcıyı self değerinde saklar. class ve module deyimleri de self değerinin işaret ettiği nesneye göre değişir. Bu davranışları anlamak Ruby dilini anlamamızda çok yardımcı olacaktır.
Örneğin bir IRB oturumunu ilk açtığımızda,
Bu görünüşe göre metodların örtülü alıcısı main nesnesi. Bu noktada tanımlayacağımız metodlar main nesnesinin metodları olacaktır.
Bu kod foo metodunu main nesnesinde tanımlar.
Not olarak yerel değişkenler metod isimlerinden önce değerlendirilir. Eğer metod ile aynı isimde bir yerel değişken tanımlamışsak önce yerel değişkene bakılır. Önceki örnekten devam edelim.
Önce değişken sonra metod tanımlanmış olsa da farketmez, aynı isimlerde önce değişken var mı diye bakılır. Ama metod hala tanımlı duruyor.
Yani ille de metodu çağırmak istersek parantezli yazabiliriz. Bir dikkat ettiyseniz foo 2 şeklinde argümanla beraber yazınca yine metod olduğunu algıladı.
-- Örtülü alıcıyı değiştiren deyimler
Bir sınıf ya da modül tanımlarken , tanımlama bloğu içinde self kelimesi içinde bulunduğu sınıf ya da modülü ifade eder.
-- self ne zaman kullanılır?
Birçok Ruby programı örtülü alıcıyı kodlarında kullanır. Ruby'ye yeni başlayanlar için self değerini anlamak biraz karmaşık gelebilir. self kullanmanın iki temel nedeni vardır.
-- -- Alıcıyı değiştirmek
Bir sınıf ya da modül içinde düz def bloğu ile metod tanımlamak bir oluşum metodu tanımlar. Sınıf metodu tanımlamak için self deyimi kullanılır.
Sınıf kodunun root'unda self kelimesi sınıfı ifade ettiği için def self.bar satırı bir sınıf metodu tanımlaması yapar.
-- -- Alıcı belirsizliğini gidermek
Yerel değişken ile metod aynı ismi paylaşırsa, self ile örtülü alıcı netleştirilebilir.
Diğer bir alıcı belirsizliği giderme ihtiyacı da eşittir işareti ile biten metodlarda olabilir.
Monkey patching
Monkey patching bir kod parçasının davranışını çalışma zamanında dinamik olarak değiştirmek için kullanılan bir terimdir. Teknik olarak Ruby'de bir sınıfa sonradan bir metod ekleyebilir ya da mevcut bir metodun üzerine yazarak davranışını değiştirebiliriz.
-- Mevcut Ruby metodunu değiştirmek
Üzerine yazarak mevcut metodun davranışını değiştirebiliriz.
String sınıfını tekrar açıp reverse metodu üzerine yazıyoruz ve dönen cevabı değiştiriyoruz. Ama bu durumda tüm string değerler için aynı sonucu verir.
Sadece "Selam millet" değeri gelince değişik davransın, diğer string değerlerde normal çalışsın dersek.
Üzerine yazmadan önce orijinal metodu alias ile başka bir isimle yedeğe alıyoruz, sonra istersek orijinali çağırıyoruz.
-- Parametreli metodu değiştirmek
Üzerine yazdığımız metodla aynı kapsamı kullanırız.
-- Refinement ile güvenli monkey patch
Öncelikle ayar çekmek için bir modül tanımlıyoruz.
refine metodu yardımıyla verilen sınıfta yani String sınıfında reverse metodu davranışını değiştiriyoruz. Şimdi iki değişik sınıfta bu modülü kullanarak nelerin değiştiğine bakalım.
Kökten String#reverse metodu üzerine yazmayıp sadece ayar modülümüzü kullanan sınıf içinde davranışının değişmesini sağlıyoruz. MPolanSınıf sınıfı dışında String#reverse metodu hala orijinali olarak çalışmaya devam eder.
-- Herhangi bir metodu değiştirmek
Metod tanımını tekrar yazdığımız satırdan itibaren metodun davranışı değişir.
-- Mevcut sınıfa yeni metod eklemek
Mevcut bir sınıfa istediğimiz yeni bir metod da ekleyebiliriz.
gibi.
İç Gözlem
-- Metodlarını görmek
-- -- Bir nesneyi incelemek
Bir nesneye ait public metodları methods veya public_methods metod çağrılarına verdiği cevaptan görebiliriz. Metod isimlerini içeren bir array döner.
Diğer nesnelerle ortak olmayan metodları bulmak için.
Alternatif olarak methods ya da public_methods'a false argüman vererek de filtreleyebiliriz.
Bir nesnenin private metodlarını private_methods, protected metodlarını protected_methods ile görebiliriz.
Aynı methods ve public_methods gibi false argüman vererek private_methods ve protected_methods ile de kalıtımdan gelen metodları filtreleyebiliriz.
-- -- Sınıf ya da modülü incelemek
Sınıflar ve modüller yukarıda gördüğümüz metodlara karşılık gelen instance_methods, public_instance_methods, protected_instance_methods, ve private_instance_methods metodlarını kendilerinin oluşum nesnelerinin metodlarıni göstermek için kullanırlar. Aynı şekilde false argüman alabilirler.
Son olarak bu metodların isimlerini ilerde hatırlamak isterseniz bir regexp filtrelemesi yapabilirsiniz.
-- Bir nesnenin oluşum değişkenlerini görmek
Bir nesnenin oluşum değişkenlerini görmek için instance_variables, instance_variable_defined?, ve instance_variable_get metodları kullanılır. Değerlerini değiştirmek için de instance_variable_set ve remove_instance_variable metodları kullanılır.
Oluşum değişkeni işleme metodları oluşum değişkeni dışarıdan okunamasa bile çalışır. Mesela yukarıdaki kodda attr_reader :bar satırı olmasa p f.bar satırı oluşum değişkeni @bar'ı okuyamaz hata verir. Ancak p f.instance_variable_get(:@bar) hala @bar değişkenine erişebilir.
Metodlara oluşum değişkeni adını girerken başında @ olmasını unutmayın yoksa hata verir.
-- Global ve yerel değişkenleri görmek
Kernel modülü metodları global_variables ve local_variables global ve yerel değişkenleri görmek için kullanılır.
Oluşum değişkenlerinden farklı olarak global ve yerel değişkenlerin get/set metodları yok , standart yol olan okuma ve atama yapısı kullanılır. Ama ille de dolambaçlı yoldan gideyim derseniz eval metodunu kullanabilirsiniz.
Default olarak eval , değişkenleri bulunulan kapsamda değerlendirir. Eğer başka bir kapsamdan değerlendirmek istersek o kapsamın binding nesnesine ihtiyacımız var.
Bu örnekte test_1 metodu local_variable_get metodunu çağırırken kapsam belirtmediği için local_variable_get metodu kendi tanımındaki foo değişkenini geri dönüyor ve :içerdeki değeri dönüyor. Ancak test_2 metodu local_variable_get metodunu çağırırken kendi kapsamını binding metodu ile öğrenip gönderiyor ve metod test_2 metod tanımı içindeki foo değişkeni değeri olan :dışardaki2 değerini dönüyor.
-- Sınıf değişkenlerini görmek
Sınıflar ve modüller de diğer nesneler gibi oluşum değişkenlerini okuyan aynı metodlara sahiptir. Sınıflar ve modüller ayrıca sınıf değişkenlerine erişen metodlara da sahiptir ( @@böyle_isimliler ).
Aynı oluşum değişkeni metodlarında olduğu gibi sınıf değişkenlerinde de @@ koymadan isimi yazarsak hata verir.
Recursion
Rekürsiyon tekrarlama demek. Programcılıkta rekürsiyon belli bir amaca ulaşana kadar fonksiyonun kendi kendisini tekrar tekrar çağırması demek. Buna en uygun örnek olarak ya faktöriyel ya da fibonacci dizisi verilir hep. Faktöriyel örneğine bir bakalım.
Faktöriyel verilen sayıdan 1'e inene kadar tüm sayıların birbiri ile çarpımı demek. Yani
Buradan gördüğümüz bir başka şey de.
Metodumuz da tam bunu yapıyor 1'e ulaşana kadar kendini çağırıp duruyor. Şimdi olanları adım adım hayal edelim.
Ruby kodu işlerken aynı yukarıda gösterildiği gibi parantez içinde parantez işlem yapıyor. Her parantez içindeki işlem sonucu bir yığına atılarak devam ediliyor. Faktöriyelini aldığımız sayı büyüdükçe bu iç içe parantezlerin yani yığına atılan bilgilerin sayısı artıyor. Çok büyük sayılarda sistem yığını dolup SystemStackError hatası oluşabilir.
-- Tail recursion
Yukarıdaki hatanın oluşmaması için Tail recursion adı verilen bir teknik uygulanır. Ara değerleri bir yerde toplayarak hafıza kullanımını azaltabiliriz.
Bu döngünün kullandığı hafızayı incelersek.
şeklinde olduğunu görürüz. Bu teknik daha az hafıza harcıyor ama bu da her adımda yapılan metod çağrılarının sonuçlarını onu çağıran metoda dönebilmek için call stack adı verilen bir yığında takip için bulundurmaya devam ediyor.
Bana sorarsanız rekürsif metod çağrısı kullanmak yerine eynı işi yapacak bir standart döngü tanımlamak. Ama yine de çok isterseniz şu dokümanda anlatılıyor.
ERB
Erb - Embedded Ruby teriminden bir kısaltma. Şablonların içine Ruby kodu enjekte etmek için kullanılır. Bu şablonların en çok kullanılanı HTML ve YAML şablonlar. ERB bir kurala göre yazılmış yazılar içinde Ruby kodu çalıştıran bir Ruby sınıfıdır.
Bir şablon metin içinde ERB şu kurallara göre kullanılır:
- <% number = rand(10) %> - bu kod sadece çalıştırılır ama bir şey göstermez
- <%= number %> - Bu kod çalıştırılır ve sonucu o noktaya yazılır.
- <%# yorum yazısı %> - Bu bir yorum, kod olarak işlenmez de bir şey yazmaz da.
ERB kullanan şablon dosyalarında dosya uzantısına .erb eklenmesi bir gelenektir. Mesela .js.erb, .html.erb, .css.erb gibi.
Basit bir örnek.
ERB kullanımı en çok Rails gibi web uygulama geliştirme ortamlarında kullanılır. Örnek olarak bir liste yazan ve erb kullanan bir HTML kodu düşünelim.
2. ve 4. satırlar kod olarak işleniyor fakat çıktıya bir şey yazmıyor, onlar sadece döngüyü oluşturuyor. 3. satırda ise çıktıya yazan bir kod var. Şimdi çıktısını görelim
Çalıştırdığımızda konsola yazdığı çıktı.
Gördüğümüz üzere <li> tag'leri de yazıyor. Mesela ürünler listesi boş olsa çıkıtı.
Nasip olur da bir Rails dökümanı daha hazırlarsam bu konuda bir sürü örnek oluşacak mutlaka. Ama şimdilik bloğumda daha önce yazdığım RubyOnRails kategorisi yazılarda bir çok örnek kullanımları var.
Rastgele Sayılar
Ruby rand metodu 0.0 ile 1.0 arasında sayı üretilir (1.0 hariç). bazı kullanım örnekleri.
Sanırım oldukça sayıda Ruby teknikleri üzerinde durduk. Bana yardımcı olduğu kadar sizlere de yardımcı olmasını temenni ederim. Başka yazılarda buluşmak ümidiyle, şimdilik kalın sağlıcakla..
Hiç yorum yok:
Yorum Gönder