Zacząłem myśleć nad nowym projektem aplikacji, której frontend to w większości strony WWW. Postanowiłem poszukać nowego systemu szablonów, który mógłbym zastosować. Pierwszymi kandydatami (z którymi mam obycie) były Genshi i Kid,jednakże jako samodzielny wytwórca szablonów szukałem czegoś co pozwoli na stworzenie kodu HTML dość szybko. Zacząłem przeszukiwać projekty znanych frameworków1 WWW w poszukiwaniu nowego rozwiązania. Bardzo dobre wrażenie wywarł na mnie HAML. Posiadał wszystko czego potrzebowałem - prostą składnię, dzięki której szablony będą łatwiejsze do utrzymania. Dodatkowo nie przypomina kodu upstrzonego tagami zamykającymi.
Szczęśliwie udało mi się znaleźć pythonowy odpowiednik, który nazywa się GHRML i jest oparty na Genshi2. Sam projekt znajduje się jeszcze w stanie alphy, jednak - jak zobaczycie później - wydaje się całkiem użyteczny.
Stawiając pierwsze kroki, postanowiłem przerobić parę przykładów użycia GRHML. Zacznijmy od instalacji; w moim przypadku wyglądała ona tak:
d:\work>easy_install ghrml
Searching for ghrml
Reading http://pypi.python.org/simple/ghrml/
[...]
Best match: GHRML 0.10
Downloading http://www.ghrml.org/download/GHRML-0.10.tar.gz
Processing GHRML-0.10.tar.gz
Running GHRML-0.10\setup.py -q bdist_egg --dist-dir c:\windows\temp\easy_install-kqdgnb\GHRML-0.10\egg-dist-tmp-teqbdg
zip_safe flag not set; analyzing archive contents...
ghrml.ghrml_django: module references __file__
Adding ghrml 0.10 to easy-install.pth file
Installed c:\python25\lib\site-packages\ghrml-0.10-py2.5.egg
Processing dependencies for ghrml
Finished processing dependencies for ghrml |
Ostatni komunikat mówi o tym, że udało się szczęśliwie zainstalować GRHML. Warto dodać, iż po zainstalowaniu GHRML domyślnie współpracuje z Genshi w wersji 0.4.4. Developerzy umieścili w komentarzach informację jak przeportować projekt do nowszej wersji Genshi. Nie wydał mi się on jednak wyjątkowo mądry, więc dla pewności pobrałem aktualną wersją znajdującą się na repozytorium GHRML. Okazało się, że wygląda to tam o wiele lepiej.
Aby dostosować projekt do uruchomienia zarówno Genshi 0.4.4 jak i nowszych trzeba zmienić metodę inicjalizacyjną3 klasy GHRMLTemplate na:
def __init__(self, source, default_namespace=None, **kwargs):
if default_namespace is None:
default_namespace = self.DEFAULT_NAMESPACE
self.default_namespace = default_namespace
MarkupTemplate.__init__(self, source, **kwargs) |
Niestety nie udało mi się odpalić tej klasy bez żadnych poprawek. Zaraz po wywołaniu parsowania prostego przykładu wyrzucało wyjątek o braku ustawionej zmiennej default_tag w swojej instancji. Stworzyłem mały patch, który rozwiązuje ten problem:
--- a/ghrml/parser.py Tue Sep 02 19:39:32 2008 +0100
+++ b/ghrml/parser.py Sun Nov 16 23:45:19 2008 +0100
@@ -177,6 +177,7 @@
self.filename = filename
self.lineno = self.indentation = self.offset = 0
self.line = None
+ self.default_tag = default_tag
self.basedir = basedir
self.lookup = lookup
self.inline_directives = inline_directives |
Po zaaplikowaniu GHRML zaczęła zachowywać się poprawnie.
Jak w przypadku każdego nowego oprogramowania warto wykonać prosty przykład i przywitać się ze światem. W tym przypadku przykład wygląda tak:
# -*- encoding: utf-8 -*-
import ghrml
template_string = u"""%html
%head
%title Witaj świecie!
%body
#header
%h1 Witaj świecie
#contents
Witaj świecie?
"""
template = ghrml.GHRMLTemplate(template_string)
stream = template.generate()
print stream.render('xhtml') |
Po wykonaniu programu otrzymujemy output w postaci dokumentu HTML:
Witaj świecie!
<div id="header">
<h1>Witaj świecie</h1>
</div>
<div id="contents">
Witaj świecie?</div> |
Czyli to, o co nam chodziło :) Spróbujmy wykonać trochę bardziej zaawansowany przykład, i przywitać się z osobą wykonującą program, oraz wypisać dla niej wszystkie liczby od 1 do 5. Dodamy także zmienną zawierającą obiekt typu bool, dzięki czemu przetestujemy wyrażenia logiczne w znacznikach. Po zmodyfikowaniu poprzedniego przykładu wygląda on tak:
# -*- encoding: utf-8 -*-
import ghrml
template_string = u"""%html
%head
%title Witaj $user_name!
%body
%h1[ if welcome ] $user_name
#content
%ul.numbers
%li[ for number in test_list]
%span $number
"""
template = ghrml.GHRMLTemplate(template_string)
# Metoda generate klasy GRMTL zajmuje się przekazywaniem danych do szablonu.
#Jest ona dziedziczona z Genshi, nazwa przekazywanego parametru jest równa nazwie
#zmiennej przekazywanej do szablonu.
test_list = range(1, 6)
stream = template.generate(welcome=True, user_name="jarek", test_list=test_list)
print stream.render('xhtml') |
Po uruchomieniu wyświetlił mi kod HTML:
Witaj jarek!
<h1>jarek</h1>
<div id="content">
<ul class="numbers">
<li>
<span>1</span></li>
<li>
<span>2</span></li>
<li>
<span>3</span></li>
<li>
<span>4</span></li>
<li>
<span>5</span></li>
</ul>
</div> |
Mam nadzieję że te proste przykłady zachęciły was do poznania GHRML. Dla mnie stanowczo skrócił pracę jeśli chodzi o pilnowanie struktury dokumentu.
Jeśli pracujecie/znacie webdesignerów, którzy podążają za najnowszymi trendami, sądzę że im także się to spodoba.
edit: Richard Davies - opiekun projektu, zaaplikował mój jedno-linijkowy patch :)