osa1 feed

CL-Mustache, Common Lisp için Mustache renderer

February 2, 2012 - Tagged as: lisp, tr.

Biraz eski bir olay ama yarım kalan yazı arşivimde kaybolmuş, şimdi ekleyeyim(tamamlanmayı bekleyen bir sürü yazı var, sıkı durun).

Mustache, “logic-less templates” diye bahsedilen bir template motoru(bu arada ben hala “logic-less” ne demek bilmiyorum ehehe). Şuradan örneklere bakabilirsiniz.

Common Lisp için Mustache kütüphanesi, en azındaın Google ile aratıp bulunabilecek bir yerde, yoktu. Ben de henüz öğrenme aşamasındaydım ve belki camiaya da bir katkım olur diye girişmiştim bu işe.

Github deposundan edinebilirsiniz. Arayüz olarak sadece tek bir fonksiyon sunuyor, mustache-render. Herhangi bir input stream’ı ve Common Lisp veri yapılarına dönüştürülmüş JSON verisi ile çağırdığınızda render edilmiş halini elde ediyorsunuz. Şu anda Mustache speclerinden çok satırlı yorumlar hariç hepsini geçiyor. comp.lang.lisp’e attığım maile de şuradan bakabilirsiniz.

Lambda desteği için speclerde yapmamız gereken değişiklikleri üşendiğim için bir türlü yapamamıştım, comp.lang.lisp’deki mailime cevap yazanlardan birisi ekleyip pull request yollamış. Eklenip JSON hali hazırlandığında lambda desteği de ekleyeceğim(bu arada Common Lisp için YAML parser’ı da yok şu anda, bu projeyi bitirene kadar ne kadar çok şey öğrendiğimi düşünüyoru da, o işe de girişebilirim aslında).

Şimdi hazır lafa girmişken teknik detaylardan bahsetmezsem ölürüm. Öncelikle kodu iyileştirmek için(ilk Common Lisp kütüphanem sonuçta), IRC’de comp.lang.lisp’de yardım istedim, ama pek bir cevap alamadım. Birkaç ihtimal var, ya Common Lisp camiasının pek umurunda değil, ya sayıca az olduğumuzdan ilgilenecke kimseye denk gelmedim(zaten kaç kişiyiz şurda), ya da kütüphane aslında iyi durumda.

Toplamda 291 satır. Mustache sayfasından diğer diller ile yapılmış implementasyonlar ile karşılaştırdığınızda gayet iyi olduğunu görebilirsiniz. Kodun küçük olması çok birşey ifade etmiyor olabilir tabii ama bir dilde binlerce satırda yaptığınız bir işi başka bir dilde 300 satırda yapabiliyorsanız, benim gözümde bu dil ifade gücü açısından daha güçlüdür(ya da diğer dil çok kötü hehe). En azından gündüz enterprise ortamında Java, gece Common Lisp yazan biri olarak ben böyle düşünüyorum hehe.

Neyse, kodda hala TODO yorumları duruyor. Düzenlenecek birkaç yer var. Onun dışında iyi bir durumda olduğunu düşünüyorum. Şu anda performans olarak aklımdaki bir iyileştirme şu:

Input stream’den girdiyi satır satır okuyorum ve okuduğum her satırı tokenlere ayırıp bir listeye kaydediyorum. Daha sonra renderer JSON verisini alıp gerekli etiketleri gerekli veriyle değiştiriyor.

Burda aslında tüm template’i tokenlara ayırıp bir listeye kaydetmek yerine, Common Lisp’de listeleri bir şekilde lazy bir şekilde oluşturabilseydim, kodda birkaç kelimelik değişiklik yaparak, hesaplamayı(yani tokenlere ayırma işlemini) render edilmiş metni okumanın gerektiği ana kadar erteleyebilirdim ve tüm tokenları bellekte tutmama gerek kalmazdı, sadece okumak istediğim yeri bellekte tutmuş olurdum.

Clojure bu açında iyi mesela. Lazy bir dil değil aslında ama listeleri lazy bir şekilde oluşturabiliyoruz lazy-seq ile. Tam olarak benim ihtiyacım olan şey.

Aslında Common Lisp gibi okuyucusunun(Lisp konseptini yapancı olanlar için, derleyicinin bir kısmı diyebiliriz sanırım) kolayca değiştirilebildiği bir dilde bu çok zor bir olay değil. Hatta aslında Lisp’in temelini düşündüğünüzde, sadece CONS, CAR ve CDRı lazy bir hale getirdiğinizde tüm listelerin lazy olmasını bekleyebilirsiniz(bekleyebilirsiniz diyorum çünkü muhtemelen bugün aktif olarak kullanılan Common Lisp implementasyonlarında tüm listeler CONS ile üretilmiyordur, performans vb. sebeplerden). Ama tabii böyle bir proje için bu tarz macrolar falan bana biraz abartı geldi, kodda da ciddi değişiklikler yapmak istemiyorum şu anda. Bir yolunu bulacağım artık.

Öyle işte, forklarınızı veya en azından yorumlarınızı bekliyorum(buralarda pek Lisper yok ama olsun ben şansımı deneyeyim hehe).