map, proc ve ampersand

Ampesand yani & işareti, Ruby’de bazı özel şeyler yapmamızı sağlıyor. Bir dizi içindeki sayıların çift olanları almak istesek;

[1, 2, 3, 4, 5, 6, 7, 8].select(&:even?) # => [2, 4, 6, 8]

şeklinde bir ifade kullanabiliriz. Burada &:even? sihirli işi yapan şey. Sayıların yani Integer’ların (eski haliyle Fixnum) even? method’u bize o sayının tek mi? yoksa çift mi? olduğunu söyler. Yaptığımız iş aslında select method’una parametre olarak bir proc geçmektir. & burada Array’deki elemanın kendisini ifade eder. & yardımıyla elemana yani Interger’a erişip even? method’unu çağırmış oluruz.

Aynı mantıkla, şöyle bir örnek yapalım:

# ruby 2.4.0

"merhaba dünya".scan(/[[:alpha:]]+/).map(&:upcase).map(&:reverse).join(" ")
# => "ABAHREM AYNÜD"

İki kez map kullandık ve string’in upcase ve reverse method’larını çağırdık. Peki, belli durumlarda koleksiyonun her elemanını bir fonksiyondan geçirmek gerekse? İşte bu durumda proc geçerek işlemi yapacağız. Elimizdeki listede e-posta adresleri var ve bize kullanıcı adı gerekiyor. Yani @ işaretinden öncesi:

username_extractor = proc{ |email| email.gsub(/([[:alpha:]])@.+/, '\1') }
email_list = ['vigo@example.com',
              'user_kool1972@hotmail.com',
              'Fo+bar@geemail.com']

email_list.map(&username_extractor) 
# => ["vigo", "user_kool1972@hotmail.com", "Fo+bar"]

Listenin her elemanını username_extractor proc’undan geçirdik, regex yardımıyla kullanıcı adını çıkarttık.

& ile ilgili elemanın method’unu çağırabildiğimiz gibi dış dünyadaki bir fonksiyonu proc şeklinde geçerek filtreleme yapabiliriz. Unutmamamız gereken şey map türevi method’lar fonksiyonel işler için proc alırlar.