sexta-feira, 4 de janeiro de 2008

Usando modelos em Python

Quando trabalhamos com desenvolvimento web, uma coisa que facilita muito são os modelostemplates.

Modelo é um texto com o formato desejado da página – ou de um trecho dela – com «marcas» que indicam substituições – ou comandos, nos casos mais complexos.

Por exemplo:
tmpl = """<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="%(lang)s" lang="%(lang)s">
<head>
%(meta)s
<title>%(title)s</title>
%(css)s
<script>
%(javascript)s
</script>
</head>
<body %(bodyload)s>
<h1 class="title">%(title)s</h1>

<div id="body">
%(main)s
</div>
</body>
</html>"""


Esse modelo poderia ser processado assim:
html = tmpl % {
"lang": "pt-br",
"meta": """<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Cache Control" content="no-cache, must-revalidate" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
""",
"title": "Teste de modelos",
"css": "",
"javascript": "",
"bodyload": "",
"main": "Este &eacute; apenas um exemplo simples de uso de modelos"
}


No modelo, cada trecho %(…)s vai ser substituído pelo valor equivalente à chave entre parêntesis. Por exemplo, %(title)s será substituído por Teste de modelos.

Observação: como estamos usando %s, os valores precisam ser strings.

Template strings


O módulo string possui a classe Template, que oferece uma forma mais interessante de processar modelos.
from string import Template


No texto do modelo, os trechos a serem substituídos terão o formato aproximado de variáveis em shell, ou seja, $… ou ${…}.

O modelo anterior ficaria assim:
tmpl = Template("""<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="$lang" lang="$lang">
<head>
$meta
<title>$title</title>
$css
<script>
$javascript
</script>
</head>
<body $bodyload>
<h1 class="title">$title</h1>

<div id="body">
$main
</div>
</body>
</html>""")


E será processado assim:
html = tmpl.substitute(
lang = "pt-br",
meta = """<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Cache Control" content="no-cache, must-revalidate" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
""",
title = "Teste de modelos",
css = "",
javascript = "",
bodyload = "",
main = "Este &eacute; apenas um exemplo simples de uso de modelos"
)


Uma vantagem aqui é que não é preciso que o valor seja string. Será usada automaticamente a representação string do valor.

Um exemplo rápido:
>>> from string import Template
>>> tmpl = Template("numero = $num")
>>> print tmpl.substitute(num=2.3)
numero = 2.3
>>>


HTML::Template


Um módulo mais poderoso é HTML::Template.

Além de simples substituições, com esse módulo ainda é possível fazer pequenos loops e blocos condicionais.

Assim como em DTML, os comandos são identificados por tags especiais.

A simples substituição é feita pela tag <TMPL_VAR …> (ou <!-- TMPL_VAR … -->).

Então em vez de %(title)s ou $title, usaremos <TMPL_VAR title>.

Essa tag suporta um atributo ESCAPE, que altera o valor inserido:
  • <TMPL_VAR title ESCAPE="NONE"> – nenhuma alteração;
  • <TMPL_VAR title ESCAPE="HTML"> – caracteres não-ASCII serão «escapados» como em HTML – por exemplo, & vira &amp;;
  • <TMPL_VAR title ESCAPE="URL"> – caracteres não-ASCII serão «escapados» como em uma URL – por exemplo, & vira %26.


O padrão é HTML.

Uma lista completa dos comandos pode ser encontrada na página de referência.

Nosso modelo ficaria assim:
tmpl = """<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<TMPL_VAR lang>" lang="<TMPL_VAR lang>">
<head>
<TMPL_VAR meta ESCAPE="NONE">
<title><TMPL_VAR title></title>
<TMPL_VAR css ESCAPE="NONE">
<script>
<TMPL_VAR javascript ESCAPE="NONE">
</script>
</head>
<body <TMPL_VAR bodyload ESCAPE="NONE">>
<h1 class="title"><TMPL_VAR title></h1>

<div id="body">
<TMPL_VAR main>
</div>
</body>
</html>"""


E para processá-lo:
from htmltmpl import TemplateManager, TemplateProcessor

tproc = TemplateProcessor()

tproc.set("lang", "pt-br")
tproc.set("meta", """<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Cache Control" content="no-cache, must-revalidate" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
""")
tproc.set("title", "Teste de modelos")
tproc.set("css", "")
tproc.set("javascript", "")
tproc.set("bodyload", "")
tproc.set("main", "Este é apenas um exemplo simples de uso de modelos")

html = tproc.process(TemplateManager().prepare(tmpl))


No manual sobre a versão Python você pode encontrar alguns outros exemplos interessantes, inclusive usando MySQL-Python.

Observação: uma forma fácil de instalar MySQL-Python é usando EasyInstall:
bash$ easy_install -U python-mysql



Peço desculpas pelo artigo um tanto corrido, mas a ideia foi simplesmente demonstrar formas diversas de uso de modelos.

[]'s
Cacilhas, La Batalema

terça-feira, 1 de janeiro de 2008

Papel de parede aleatório

Este artigo é para aqueles que, como eu, usam gerenciadores de janela alternativos.

A maior parte das pessoas que entram no maravilhoso mundo livre do GNU/Linux ou fica nadando no rasinho da piscina – digo, KDE e Gnome – ou mergulha na escuridão negra da linha de comando…

Poucos são os que exploram saídas alteranativas, como ambientes desktop mais leves ou combinações de aplicações gráficas e gerenciadores de janela.

Nesses casos, há algumas aplicações que gerenciam papel de parede, como xv, xsetroot e wmsetbg.

Pessoalmente prefiro usar wmsetbg, que faz parte do pacote do Window Maker, mas pode ser usado com qualquer gerenciador de janela. Algumas vantagens são a flexibilidade para lidar com imagens e permitir recursos de transparência dos gerenciadores de menu.

Sabendo disso, uma coisa legal que podemos fazer com Shell é escolher um papel de parede aleatório a cada login.

Vamos aqui criar um script que faça isso.

O script deve começar indicando qual o interpretador a ser usado:
#!/bin/bash


Vamos agora listar as imagens que queremos em uma variável. Vamos chamá-la IMGLIST.

A ideia aqui é listar os diretórios onde estarão as imagens:
IMGLIST=$(
ls \
/home/Imagens/OndeEhOParaiso/*.jpg \
/home/Imagens/OndeEhOParaiso/*.png \
/home/Imagens/Virtual/*.jpg \
/home/Imagens/Virtual/*.png \
/home/Imagens/Wallpapers/*.jpg \
/home/Imagens/Wallpapers/*.png \
/home/Imagens/digitalblasphemy/*.jpg \
/home/Imagens/digitalblasphemy/*.png \
/home/Imagens/heise.de/*.jpg \
/home/Imagens/heise.de/*.png \
2>/dev/null
)


A estrutura $(…) levanta um sub-shell e retorna sua saída padrão.

Agora precisamos determinar o tamanho da lista para podermos escolher um índice:
LENGTH=$(wc -l <<< "$IMGLIST")


Temos novamente o sub-shell. O comando wc conta caracteres, palavras e linhas, com a opção -l, apenas linhas. Como cada linha em IMGLIST representa uma imagem, contanto as linhas, contamos as imagens.

Em bash, <<< retorna o conteúdo de uma string como um arquivo virtual, de forma semelhante a <<EOF.

Podemos agora escolher aleatoriamente um índice, maior ou igual a um e menor ou igual à quantidade de imagens.

Para isso usaremos dois recursos: o ambiente aritmético do bash, ((…)), e a variável especial RANDOM, que retorna um valor aleatório entre zero e 32767:
((IMGINDEX = (RANDOM * LENGTH / 32768) + 1))


Por final, podemos usar uma combinação dos comandos tail e head.

O comando tail seleciona todo o «arquivo» a partir de uma determinada linha, e o comando head seleciona n linhas do começo do «arquivo»:
IMGFILE=$(tail +$IMGINDEX <<< "$IMGLIST" | head -n1)


Tendo selecionado a imagem e armazenado seu path na variável IMGFILE, basta carregá-la como papel de parede:
wmsetbg -s "$IMGFILE"


E está pronto nosso script!

Para usá-lo podemos colocá-lo como parte do conteúdo de ~/.xinitrc, ou carregá-lo a partir de ~/.xinitrc com o comando source, ou ainda ajustar o arquivo como executável e chamá-lo a partir do startup do geranciador de janelas escolhido.

[]'s
Cacilhas, La Batalema