17-3-2011, 6:21 ö.ö. //
//
python
, vim
// 478
Bloguma vim ile yazı yazma projemin bir parçası(aslında vim ile python scripti çağırmak ile alakalı yaptığım deneylerin bir sonucu olan) olan vim-markdown-preview scriptin sayesinde birkaç şey farkettim.
Vim için bir script yazacaksanız ve bu scriptin tek yapacağı buffer'daki metini alıp onunla birşeyler yapmaksa, bunun en basit yolu bir vimscriptiyle buffer'ı başka bir python scriptine göndermek sanırım. En azından ben öyle yaptım. Şu kadar basit:
function! MarkdownPreview()
python << EOF
import vim
import subprocess
gr = "/home/osa1/Desktop/vim-markdown-preview/GeckoRenderer.py"
subprocess.Popen(["python", gr, "\n".join(vim.current.buffer[:])])
EOF
endfunction
Burda farkedebileceğiniz gibi bufferı çekip, subprocess.Popen ile istediğiniz Python scriptine gönderebiliyorsunuz. Çok kolay, bundan sonrası da normal Python zaten.
Fakat burda şöyle bir problem oluşuyor, bu fonksiyonu her çağırdığınızda Python scripti bir daha çalışıyor. Benim yapmak istediğim, eğer script zaten çalışıyorsa onu güncellemek.
Burda iki problem var, birincisi, programın zaten çalışıp çalışmadığını tespit etmek, ikincisi de eğer zaten çalışıyorsa ona mesaj göndermek. İkisi hakkında da nette bir sürü çözüm var(dbus, pid, multiprocess, pipe, alakalı SO mesajları: 1, 2, 3, 4).
Fakat benim uyguladığım ve sanırım en basit yöntem, programın çalışmadan önce bir dosyayı kontrol etmesi, o varsa çalışmak yerine gerekli sunucunun(localhost) gerekli portuna mesaj göndermesi. Mesajlaşma olayını socketlerle hallettim yani. Çok kolay ve anlaşılır oldu. Fakat işin içine arayüz girince bir problem daha ortaya çıktı: bir socket dinlerken arayüzü güncellemek.
Aşağıdaki program herşeyi özetliyor:
import os
import gtk
import socket
import gobject
from sys import argv
# dosya adi farketmez, programimiza ait oldugu belli olsun
PIDFILE = "ohnoes.pid"
PORT = 8081 # dinleyecegimiz port, musait bir port olsun yeter
DELAY = 1
def run(text):
# burda birseyler yapilacak
port = PORT
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # udp
s.bind(("", port)) # localhost'da 8081'i dinleyecegiz
# burasi onemli, DELAY surede bir dinlemeyi birakip,
# arayuzu guncellenmeye zorlayacagiz
s.settimeout(DELAY)
while True:
try:
data, addr = s.recvfrom(1024) # dinleme
except socket.timeout: # delay sure bekledik, birsey yok
print "timeout"
else:
print "got data", str(data) # veriyi aldik
update(data) # guncelleme fonksiyonumuzu cagirdik
# bu sekilde gtk'yi guncellenmeye zorluyoruz
while gtk.events_pending():
gtk.main_iteration()
# surekli True dondurerek gtk'ya islemin bitmedigini soyluyoruz
# musait oldugunda yine bu fonksiyonu cagirsin
yield True
def is_running():
# Pid'e falan hic gerek yok,
# bir dosya olusturup, onu kontrol edecegiz
# program acilirken o dosyayi olusturacak,
# kapanirken silecek, sorun yok
if os.path.isfile(PIDFILE):
return True # program zaten calisiyor
with file(PIDFILE, "w") as f:
f.write("running") # dosyanin icerigi onemli degil
return False
if __name__ == "__main__":
text = argv[1]
if is_running(): # program calisiyor
port = PORT
host = "localhost"
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # udp
s.bind(("", 0))
s.sendto(text, (host, port)) # veriyi gonder
else:
# bu asamaya gelindiginde, is_running() zaten gerekli
# dosyayi olusturmus oluyor
task = run(text) # program calistiriliyor
gobject.idle_add(task.next) # gtk musait oldugunda bunu cagiracak
gtk.main()
Kodda bulunmayan ama dikkat edilmesi gerek bir nokta da, gui'nin kapanma fonksiyonuna(close sinyali gönderildiğinde çağırılan fonksiyon) os.remove(PIDFILE) satırını eklenmesi. Ha unutmadan, dosya konumu değiştirilmeli tabii ki, bu halde program halgi dizinden çağırılıyorsa oraya bakıyor ve gerekiyorsa dosyayı oluşturuyor.
15-3-2011, 9 ö.ö. //
//
vim
// 417
Vim ile uğraştığım son birkaç ayda kendime çok sağlam bir .vimrc dosyası hazırladım. Bir sürü ayar var ama benim için en önemli kısımları, sistem genelinde ihtiyaç duyduğum map ğ [ map ü ] map Ğ { ve map Ü } kısımları. Dizüstü bilgisyarımın klavyesi ingilizce ve ordan farkettim, ingilizce klavyede ğ ve ü'nün olduğu yerlerde [ ] var ve çok daha kullanışlı.
Kod yazarken türkçe karakterleri hiçbir şekilde kullanmadığımıza göre, bunları bir şekilde [] ile değiştirebilirsem çok daha kullanışlı olacak. Türkçe klavyede []{} karakterlerinin yerleri çok kötü. (vim'de { } karakterleri normal mode'da bloklar arasında gezinmeyi de sağlıyor.)
Küçük bir araştırmayla nasıl olacağını buldum. Not olsun, buraya yazıyorum(diğer bilgisayarda da yapılacak).
Klavye düzenleri /usr/share/X11/xkb/symbols adresinde tutuluyor. Burdaki tr bizim kullandığımız türkçe klavye. Bizim yapmak istediğimiz ondaki sadece 2 satırı değiştirmek olduğundan, tüm dosyayı kopyalayıp adını istediğimiz bir şekilde değiştiriyoruz(ben t1 yaptım). Daha sonra içini açıp şu satırları buluyoruz.
key <AD11> {[gbreve, Gbreve ]};
key <AD12> {[udiaeresis, Udiaeresis, asciitilde, dead_macron]};
Bu iki satır ğ ve ü harflerini temsil ediyor, [] arasındaki ikinci kısım, shift+tuş şeklinde basıldığında vereceği karakter. Şu şekilde değiştiriyoruz:
key <AD11> {[bracketleft, braceleft ]};
key <AD12> {[bracketright, braceright, asciitilde, dead_macron]};
Bu kadar. Kaydedip çıktıktan sonra başka bir dosyada daha değişiklik yapacağız. /usr/share/X11/xkb/rules/evdav.xml dosyasını açıyoruz. Herhangi bir </layout> sonuna şunu ekliyoruz:
<layout> <!-- custom -->
<configItem>
<name>t1</name> <!-- buraya dosyanizin adi gelecek -->
<shortDescription>t1</shortDescription> <!-- bu satir gnome panelde de gozukecek -->
<description>My Custom Layout 1</description>
<languageList><iso639Id>tur</iso639Id></languageList>
</configItem>
<variantList/>
</layout>
Bu kadar. Bundan sonra gnome-keyboard-propertiesi çalıştırıp klavye düzenimizi ekliyoruz. Burda klavye düzenlerini hızlıca değiştirmek için ayar ekranından shift + ctrl vb. şeyler seçebilirsiniz.
13-3-2011, 2:12 ö.s. //
//
python
, java
// 604
Çarşamba ve perşembe günleri kardan dolayı tatildi, cuma günü 2 saat derse girdim, cumartesi ve pazarla beraber 5 gün tatil yapmış gibi oldum. Birkaç fikrimi koda dökmek için fazlasıyla zamanım vardı.
Arşiv düzenleyiciye klasör dinleme özelliğini sonunda ekledim. Bir süredir üzerinde düşünüyordum ama birkaç şeyden dolayı bir türlü başlayamamıştım. Birincisi, kaynak kod aşırı derecede karışık, yeniden geliştirilebilir bir şekilde yazılmamıştı. Birşey eklemeyi bırak, birkaç gün sonra kendim okuduğumda kodda ne olup bittiğini anlamıyordum. Tüm programı neredeyse yeniden yazdım.
Çok daha esnek ve anlaşılabilir bir yapı oluşturdum. Büyük ihtimalle bundan sonraki güncellemeler çok daha kolay olacak. Tüm yapıyı değiştirmemin bir sebebi de klasör dinleme özelliğinin bazı şeylere ihtiyaç duymasıydı.
Klasör dinleme demişken, bu konuda şaşırtıcı derecede fazla alternatif var. inotify, fam, gamin, watchdog, fsmonitor, pyfilesystem .. Bunların hepsini az çok kurcaladım. En son istediğim basitlikte/yeterlilikte fsmonitor kullandım.(FF'de yardımcı olan herkese teşekkürler. İlgili feed.)
Yeni sürümde henüz arayüz yok, tüm yapıyı değiştirince arayüz kısmı problem oldu bu sefer. Eğer arayüz yaparsam, gtk ile değil de wx ile yapacağım sanırım. gtk'da arkaplanda bir işlem yaparken arayüzü güncelleme konusunda çok sıkıntı yaşadım. Çalışan fonksiyon arayüzü güncellemek için başka fonksiyonları çağırsa bile, fonksiyon çalışmasını bitirmeden arayüz güncellenmiyor. Arayüzü güncellemek için, belirli aralıklarla fonksiyonu durdurmak gerekiyor(örneğin döngüdeki her bir adımda, yield ile bir değer döndürüp, gobject.idle_add(task) ile döngünün ilerlemesi sağlanabilir). Belki wx'de daha kolaydır.
Github alanımdan indirebilirsiniz. System tray'de duracak basit bir arayüzden sonraki adım, yanlış etiketleri düzenlemek ve eksik etiketleri tamamlamak olacak sanırım.
Design patterns
Öğrenmek istediğim birkaç konu, başlamak istediğim birkaç kitap vardı. Hazır esnek, geliştirilebilir, anlaşılabilir program yazmakta sıkıntı yaşıyorken, Head First Design Patterns'a başladım ve şunu farkettim, OOP belki yeni başlayanlar için FP kadar zor değil fakat yeterince esnek/anlaşılır/geliştirilebilir bir yapı kurmak zor bir olay. Design patterns ile ilgilendikçe şunu farkettim, bu patternlar OOP'de çok karşılaşılan problemler için üretilmiş* ve aslında heryerdeler(böyle mi yazılıyor). Örneğin daha önce birkaç blog/feed'de sövdüğüm java.io decorator dolu. Twisted factory/reactor kullanıyor vs. Ben de son arşiv düzenleyicinin dosya izleme ve gerekli sinyalleri gönderme kısmında observer kullandım(daha çok öğrenme amaçlıydı ama güzel oldu).
Fonksiyonel programlamaya karşı sebebini açıklayamadığım bir ilgim var. Neredeyse her gün OO programlama yapmama rağmen(dersler gereği, halbuki hiç FP yapmıyoruz) OOP bilmiyormuşuz bunu farkettim. Aynı FP gibi, prensipleri vs. varmış. C ile uğraştığımız bu dönem OOP'in bir teknoloji değil, teknik olduğunun az da olsa farkına varmıştım ama design patterns ile küçük çaplı bir aydınlanma yaşadım resmen.
Design patterns, oop vs. demişken, python'da tip kontrolleri ver encapsulation ile alakalı: differences between isinstance() and type() in python, what is the best way to check the type of a python variable?, alex martelli'nin design patterns in python sunumu.
Vim için markdown önizleme
Vim için python ile eklenti yazma olayını biraz kurcalamıştım, geçen aklıma geldi, bloga vim ile yazı nasıl ekleyebilirim?
Aslında genel olarak, vim ile subprocess.Popen() fonksiyonunu çağırabildikten ve vim.current.buffer[:] ile buffer'ı alabildikten sonra, gerisi Python. Şimdilik yazı eklemeyi yapamadım ama markdown için önizleme eklentisi yaptım.
Henüz kurulum için hazır değil ama, so: markdownpreview.vim ile ekledikten sonra, :call MarkdownPreview() ile önizlemeyi görebilirsiniz. Birkaç problem var, birincisi, buffer'dan türkçe karakterler garip bir şekilde geliyor. Onunla uğraşmak lazım. İkincisi de, bir preview ekranını kapatmadan bir daha çalıştırırsanız, bir ekran daha açılıyor. Bir ara düzelteceğim. Önizleme ekranı gtk ile yapıldı.
Kaynak kod github alanımda. Bu arada, vim'e python ile eklenti yazma hakkında resmi kaynak.
Bunların dışında blogda da birkaç iyileştirme yaptım ama önemli bir değişiklik yok.
Bundan sonra yazmayı planladıklarım: Editor(vim) vs. IDE muhabbeti ve Pardus pisi paket yapımı ile alakalı birkaç şey.
Okunacaklar: A Curious Course on Coroutines and Concurrency(evet hala okuyamadım), Before you start learning Lisp, Code like a pythonista: Idiomatic Pytohn, Intermediate and Advanced Software Carpentry in Python, Why why functional programming matters matters.
5-3-2011, 7:12 ö.s. //
//
// 736
Beni çok uğraştırdı, belki aynı şey için uğraşanlar vardır, bir süredir iki bilgisayar kullanıyorum(okulda dizüstü bilgisayar, evde masaüstü) ve genelde çalışmalarımın çoğunu okulda yaptığımdan, dosyalarım dizüstü bilgisayarımda bulunuyor ve çok dağınık olduğumdan, bu dosyalar çoğu zaman 5-6 farklı klasörün içinde bir yerlerde bulunuyor.
Tartıştığımız şu feed'e de bakabilirsiniz. İlgilenen herkese teşekkürler
Dropbox senkronizasyon için mükemmel. Son derece basit, sadece tek iş yapıyor ve süper yapıyor: tek bir klasörü senkronize etmek. Hiçbir ayar yok. Hesap alıp programı kuruyorsunuz, gerekli klasörü gösteriyorsunuz(ya da kendisi oluşturuyor), ve gerisini dropbox hallediyor. İki bilgisayar da açıkken, anlık olarak senkronize yapabiliyor.
Fakat dropbox'ın sorunu, birden fazla klasör seçemiyorsunuz. Örneğin benim durumumda, masaüstü klasörüm, dökümanlarımın(kitaplar vs.) bulunduğu klasör, eclipseworkspace, ve birkaç klasör daha gerekliydi ve dropbox ile bunu çözememiştim. Çözüm symlinkmis.
Çok basit bir çözüm ve tüm problemi çözüyor. Örneğin benim durmumda, senkronize etmek istediğim tüm klasörleri dropbox klasörünün altına linkledim. Şu şekil:
ln -s ~/Desktop ~/Dropbox/Desktop
ln -s ~/Documents ~/Dropbox/Documents
ln -s ~/.vimrc ~/Dropbox/.vimrc
ln -s ~/.vim ~/Dropbox/.vim
...
İlk bilgisayardan bu şekilde gerekli klasörler ve dosyaları bağladıktan sonra ikinci bilgisayardan senkronizasyona başlamadan önce bu adımları uygulamak gerek. Ya da tüm senkronizasyon bittikten sonra. Burda ln -s komutunun ilk parametresi kaynak, yani eğer senkronizasyon yaptınız, sonra onu Desktop klasörüne bağlamak istiyorsanız ln -s ~/Dropbox/Desktop ~/Desktop yapmanız gerekir. Tek detay bu. Daha pratik bir yol yok(alternatifler için yukarıda bahsettiğim feed'e bakabilirsiniz).
Şu anda bu çözümde benim dikkatimi çeken tek bir problem var, senkronize etmek istemediğimiz dosya/formatları belirleyemiyoruz. .gitignore gibi bir .dropboxignore dosyası olsa mesela, ona göre istenmeyen doslayı senkronize etmese süper olurdu. Yoksa bir sürü .pyc, .o, .class dosyası senkronize edeceğim her gün.
5-3-2011, 5:52 ö.s. //
//
ödev
// 383
Aslında yeni birşey yok, bildiğim bazı şeyler, silmek zorunda kaldığım ~400 satır kodla beraber yeniden aklıma geldi. Ödevin gözüme kolay gelmesiyle, fantastik işler peşinde koştum, kimsenin yapmayacağı bir şekilde, farklı yapmaya çalıştım ve C'de bunun bedeli segfault oldu. O yüzden, kendime not:
-
Her zaman mümkün olan en basit çözümü yap. Bu büyüklükte çalışmalar performans falan önemli değil, kod ne kadar açık, basit olursa debug o kadar kolay olacak. Deadline'ın olduğunda fantastik işlere girişme.
-
Programı birbirinden bağımsız parçalara böl, kendini tekrar etme, parçalar yeterince esnek olursa, yeniden kullanılabilirlikleri artar.
-
Ödevi/işi/projeyi, bir bütün olarak tüm hatlarıyla düşün. Şu kısmını halledeyim, gerisini ona göre yaparım deme. Kaba hatlarıyla tüm özellikleri canlandır. Detayları bunlara göre hallet.
-
Test edebileceğin şeyler yaz. Test edemedikten sonra doğru çalıştığının bir garantisi olamyabiliyor. Parçaların birbirine mümkün olduğunda az bağımlı olması test edilebilirliği kolaylaştırır.
-
Bir parçayı test etmeden onun üzerine başka bir parça inşa edip, sonra bir de onu test etmeye kalkma. Acele etme.
Yeni birşey yok yani. Kendime not olsun. gdb ile geçen birkaç saatten sonra tüm kodu yeniden yazacağım. 1 saati geçmeyecek gibi.
0 ,
1 ,
2 ,
3 ,
4 ,
5 ,
6 ,
7 ,
8 ,
9 ,
10 ,
11 ,
12