<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>DestaqueBlog &#187; Tutoriais</title>
	<atom:link href="http://weblog.destaquenet.com/category/pt-br/tutoriais/feed/" rel="self" type="application/rss+xml" />
	<link>http://weblog.destaquenet.com</link>
	<description>Blog da equipe Destaquenet.</description>
	<lastBuildDate>Tue, 23 Nov 2010 17:06:50 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>Emacs e Slime: Seu Laboratório Lisp</title>
		<link>http://weblog.destaquenet.com/2010/11/18/emacs-e-slime-seu-laboratorio-lisp/</link>
		<comments>http://weblog.destaquenet.com/2010/11/18/emacs-e-slime-seu-laboratorio-lisp/#comments</comments>
		<pubDate>Thu, 18 Nov 2010 12:50:40 +0000</pubDate>
		<dc:creator>Daniel Martins</dc:creator>
				<category><![CDATA[Português]]></category>
		<category><![CDATA[Tutoriais]]></category>
		<category><![CDATA[clojure]]></category>
		<category><![CDATA[dicas]]></category>
		<category><![CDATA[emacs]]></category>
		<category><![CDATA[lisp]]></category>
		<category><![CDATA[slime]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://weblog.destaquenet.com/?p=1175</guid>
		<description><![CDATA[Esse post vai para quem está estudando Clojure (ou outro Lisp qualquer) e está tendo dificuldades para configurar o Emacs. Não é, Ronaldo?! Esteja preparado para uma enorme quantidade de gambiarras. ELPA A primeira coisa que faço numa nova instalação &#8230; <a href="http://weblog.destaquenet.com/2010/11/18/emacs-e-slime-seu-laboratorio-lisp/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Esse post vai para quem está estudando <a href="http://clojure.org">Clojure</a> (ou outro <a href="http://en.wikipedia.org/wiki/Lisp_(programming_language)">Lisp</a> qualquer) e está tendo dificuldades para configurar o <a href="http://www.gnu.org/software/emacs/">Emacs</a>. Não é, <a href="http://twitter.com/rferraz">Ronaldo</a>?! <img src='http://weblog.destaquenet.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>Esteja preparado para uma enorme quantidade de gambiarras.</p>
<h3>ELPA</h3>
<p>A primeira coisa que faço numa nova instalação do Emacs é configurar o <a href="http://tromey.com/elpa">ELPA</a>, ou <em>Emacs Lisp Package Archive</em>. Para quem não conhece, pense no ELPA como se fosse um <code>apt-get</code> da vida, guardadas as devidas proporções (como veremos a seguir).</p>
<p>As instruções para instalação podem ser vistas <a href="http://tromey.com/elpa/install.html">nesta página</a>. Se tudo der certo, agora deve ser possível rodar o comando <code>M-x package-list-packages &lt;ENTER&gt;</code>. Leia <a href="http://sean.wenzel.net/docs/emacs/quick_reference/">este documento</a> caso tenha dificuldades para usar atalhos e comandos do Emacs.</p>
<p>Após alguns instantes, a lista de pacotes disponíveis para instalação via ELPA deve ser exibida num buffer secundário.</p>
<p><span id="more-1175"></span></p>
<h3>Clojure-Mode</h3>
<p>Coloque o cursor sobre a linha do pacote <code>swank-clojure</code> e pressione a tecla <code>I</code> para marcá-lo para instalação. Faça o mesmo com o pacote <a href="http://www.emacswiki.org/ParEdit"><code>paredit</code></a>. Se outros pacotes foram marcados acidentalmente, mova o cursor para as linhas correspondentes e pressione <code>U</code> para desfazer a marcação. Pressione <code>X</code> para prosseguir com a instalação.</p>
<p>Feito isso, ao rodar o comando <code>M-x slime &lt;ENTER&gt;</code>, o Emacs irá perguntar se você deseja que ele faça o download dos JARs de Clojure. Não adianta dizer que sim, pois não irá funcionar. <img src='http://weblog.destaquenet.com/wp-includes/images/smilies/icon_sad.gif' alt=':-(' class='wp-smiley' /> </p>
<p>Para resolver isso, baixe manualmente os <a href="http://clojure.org/downloads">JARs de Clojure</a> e os coloque no diretório <code>~/.clojure/</code>. Em seguida, baixe o <a href="http://clojars.org/repo/swank-clojure/swank-clojure/">JAR mais recente</a> projeto <a href="https://github.com/technomancy/swank-clojure">swank-clojure</a> e o coloque no diretório <code>~/.swank-clojure/</code>.</p>
<p>Pronto. Reinicie o Emacs e rode o comando <code>M-x slime &lt;ENTER&gt;</code> para iniciar um REPL Clojure dentro do Emacs!</p>
<div id="attachment_1363" class="wp-caption aligncenter" style="width: 310px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2010/11/clj-repl.png"><img src="http://weblog.destaquenet.com/wp-content/uploads/2010/11/clj-repl-300x168.png" alt="REPL Clojure" title="clj-repl" width="300" height="168" class="size-medium wp-image-1363" /></a><p class="wp-caption-text">Clojure no Emacs Slime</p></div>
<p>Vale lembrar que o Slime fornece vários recursos para edição de código, como auto-completion, exibição de docstrings, entre outras coisas. Consulte o <a href="http://common-lisp.net/project/slime/">site do projeto</a> para mais informações.</p>
<h3>Outros Lisps</h3>
<p>Rode o comando abaixo para instalar duas das principais implementações open source do ANSI Common Lisp, <a href="http://www.gnu.org/software/clisp">CLISP</a> e <a href="http://www.sbcl.org/">SBCL</a>:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">apt-get</span> <span style="color: #c20cb9; font-weight: bold;">install</span> clisp sbcl</pre></div></div>

<p>Finalmente, abra o arquivo <code>~/.emacs</code> e cole o código a seguir na última linha:</p>

<div class="wp_syntax"><div class="code"><pre class="lisp" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">;; paredit + lisp modes</span>
<span style="color: #66cc66;">&#40;</span>defvar *lisp-modes* '<span style="color: #66cc66;">&#40;</span>clojure-mode-hook lisp-mode-hook emacs-lisp-mode-hook
                       lisp-interaction-mode-hook slime-repl-mode-hook<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;">;; config used in all lisp modes</span>
<span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">defun</span> lisp-config <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>
  <span style="color: #66cc66;">&#40;</span>paredit-mode t<span style="color: #66cc66;">&#41;</span>
  <span style="color: #66cc66;">&#40;</span>show-paren-mode t<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
&nbsp;
<span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">mapc</span> <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">lambda</span> <span style="color: #66cc66;">&#40;</span>mode<span style="color: #66cc66;">&#41;</span>
        <span style="color: #66cc66;">&#40;</span>add-hook mode 'lisp-config<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> *lisp-modes*<span style="color: #66cc66;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;">;; other lisp implementations</span>
<span style="color: #66cc66;">&#40;</span>eval-after-load <span style="color: #ff0000;">&quot;slime&quot;</span>
  '<span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">progn</span> <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">setq</span> slime-lisp-implementations
                '<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>sbcl <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;/usr/bin/sbcl&quot;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
                  <span style="color: #66cc66;">&#40;</span>clisp <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;/usr/bin/clisp&quot;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span></pre></div></div>

<h3>Swank</h3>
<p>As últimas versões do Slime já trazem servidores Swank para diversas implementações Lisp, mas curiosamente essa parte do código não é baixada quando se instala o Slime via ELPA.</p>
<p>Certifique-se de que um cliente CVS esteja instalado e rode o comando abaixo para fazer o download da última versão do Slime:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #c20cb9; font-weight: bold;">cvs</span> <span style="color: #660033;">-d</span> :pserver:anonymous:anonymous<span style="color: #000000; font-weight: bold;">@</span>common-lisp.net:<span style="color: #000000; font-weight: bold;">/</span>project<span style="color: #000000; font-weight: bold;">/</span>slime<span style="color: #000000; font-weight: bold;">/</span>cvsroot <span style="color: #c20cb9; font-weight: bold;">co</span> slime</pre></div></div>

<p>Em seguida, vá até o diretório <code>slime</code> recém-criado e copie todos os arquivos deste diretório por cima dos arquivos instalados via ELPA em <code>~/.emacs.d/elpa/slime-&lt;VERSION&gt;</code>. Aproveite e remova o arquivo <code>slime.elc</code> deste último diretório, já que tal arquivo é uma versão compilada de um arquivo que acabamos de sobrescrever.</p>
<p>Reinicie o Emacs. O comando <code>M-x slime &lt;ENTER&gt;</code> continua servindo para iniciar um REPL Clojure. Para iniciar um REPL SBCL, por exemplo, rode o comando <code>M-- M-x slime &lt;ENTER&gt;</code>, digite <code>sbcl</code> e pressione <code>&lt;ENTER&gt;</code>.</p>
<div id="attachment_1364" class="wp-caption aligncenter" style="width: 310px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2010/11/sbcl-repl.png"><img src="http://weblog.destaquenet.com/wp-content/uploads/2010/11/sbcl-repl-300x168.png" alt="REPL SBCL" title="sbcl-repl" width="300" height="168" class="size-medium wp-image-1364" /></a><p class="wp-caption-text">SBCL no Emacs Slime</p></div>
<h4><em>&#8220;Nunca vi tanta gambiarra num lugar só&#8230;&#8221;</em></h4>
<p>Tudo seria mais fácil se o ELPA disponibilizasse versões minimamente atualizadas &#8212; e não-&#8221;capadas&#8221; &#8212; de certos pacotes, por isso creio que essa complicação deva ser temporária. Atualizarei este texto quando a coisa mudar. Para melhor, espero.</p>
]]></content:encoded>
			<wfw:commentRss>http://weblog.destaquenet.com/2010/11/18/emacs-e-slime-seu-laboratorio-lisp/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Crie seu próprio pendrive USB multi-boot salvador da pátria</title>
		<link>http://weblog.destaquenet.com/2010/08/02/crie-seu-proprio-pendrive-usb-multi-boot-salvador-da-patria/</link>
		<comments>http://weblog.destaquenet.com/2010/08/02/crie-seu-proprio-pendrive-usb-multi-boot-salvador-da-patria/#comments</comments>
		<pubDate>Mon, 02 Aug 2010 11:20:50 +0000</pubDate>
		<dc:creator>Daniel Martins</dc:creator>
				<category><![CDATA[Português]]></category>
		<category><![CDATA[Tutoriais]]></category>
		<category><![CDATA[backup]]></category>
		<category><![CDATA[boot]]></category>
		<category><![CDATA[clonezilla]]></category>
		<category><![CDATA[drive]]></category>
		<category><![CDATA[ferramentas]]></category>
		<category><![CDATA[flash]]></category>
		<category><![CDATA[gparted]]></category>
		<category><![CDATA[grub]]></category>
		<category><![CDATA[kernel]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[memtest]]></category>
		<category><![CDATA[mint]]></category>
		<category><![CDATA[multi-boot]]></category>
		<category><![CDATA[pendrive]]></category>
		<category><![CDATA[ubuntu]]></category>
		<category><![CDATA[usb]]></category>

		<guid isPermaLink="false">http://weblog.destaquenet.com/?p=1060</guid>
		<description><![CDATA[Não preciso convencê-lo de que carregar algumas distribuições Linux com você pode fazer a diferença entre a vida e a morte. Bem, é claro que eu estou sendo um pouco dramático, mas é realmente muito bom poder rodar um teste &#8230; <a href="http://weblog.destaquenet.com/2010/08/02/crie-seu-proprio-pendrive-usb-multi-boot-salvador-da-patria/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Não preciso convencê-lo de que carregar algumas distribuições Linux com você pode fazer a diferença entre a vida e a morte. Bem, é claro que eu estou sendo um pouco dramático, mas é realmente muito bom poder rodar um teste de memória numa máquina que insiste em jogar erros estranhos na sua cara, ou mesmo copiar discos ou partições importantes quando você está por aí.</p>
<p>Para mim, algumas ferramentas e distribuições são particularmente úteis:</p>
<ul>
<li><a href="http://clonezilla.org/">Clonezilla</a>. Ferramenta muito boa para clonagem de disco/partição. Leva algum tempo para iniciantes se acostumarem com ela, mas vale o esforço. Já fui salvo por esta ferramenta mais de uma vez.</li>
<li><a href="http://gparted.sourceforge.net/">GParted</a>. Excelente ferramenta para particionamento de disco.</li>
<li><a href="http://linuxmint.com/">Linux Mint</a>. Distribuição Linux baseada no Ubuntu muito fácil de usar. Eu gosto muito da edição Live-DVD, que inclui softwares como <a href="http://www.videolan.org/vlc/">VLC</a>, <a href="http://www.openoffice.org/">OpenOffice</a> e <a href="http://java.com/">Java</a>.</li>
<li><a href="http://ubuntu.com/">Ubuntu</a>. Uma das distribuições Linux mais populares hoje em dia.</li>
<li><a href="http://www.memtest.org/">Memtest86+</a>. Ferramenta para teste de memória incluída na maioria das distribuições Linux modernas. Indispensável.</li>
</ul>
<p>Agora, em vez de queimar um CD/DVD com cada uma dessas ferramentas, nós iremos usar um pendrive USB multi-boot.</p>
<p><span id="more-1060"></span></p>
<h3>Preparando a pendrive</h3>
<p>O primeiro passo é instalar um bootloader na pendrive para possamos escolher qual distribuição carregar quando bootando a partir dela. Sorte minha que a distribuição Linux que uso, Ubuntu, já vem com o Grub2 pré-instalado. Esta versão do <a href="http://www.gnu.org/software/grub/">Grub</a> em particular é necessária, já que ela nos permite montar e bootar imagens .ISO.</p>
<p>Uma vez que você esteja com o Grub2 instalado, plugue sua pendrive e se certifique de que sua partição principal seja bootável, e que ela esteja formatada com FAT32 (<code>vfat</code>).</p>
<p>Então, rode este comando para instalar o Grub2 no pendrive:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #c20cb9; font-weight: bold;">sudo</span> grub-install <span style="color: #660033;">--no-floppy</span> <span style="color: #660033;">--root-directory</span>=<span style="color: #000000; font-weight: bold;">/</span>media<span style="color: #000000; font-weight: bold;">/</span>PENDRIVE <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>sdX</pre></div></div>

<p>Lembre de fazer com que <code>root-directory</code> aponte para o caminho onde o pendrive está montado, e <code>/dev/sdX</code> para o dispositivo em si. Por favor, verifique os parâmetros duas vezes antes de rodar o comando, ou você corre o risco de fazer algo de que se arrependerá depois!</p>
<h3>Configurando o Grub2</h3>
<p>Agora é hora de baixar as imagens .ISO das distribuições mencionadas anteriormente e colocá-las no diretório <code>/boot/iso</code> dentro da pendrive. Então, crie o arquivo <code>/boot/grub/grub.cfg</code> com o seguinte conteúdo:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">menuentry <span style="color: #ff0000;">&quot;Linux Mint 9 x86&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">set</span> <span style="color: #007800;">isofile</span>=<span style="color: #ff0000;">&quot;/boot/iso/linuxmint-9-gnome-dvd-i386.iso&quot;</span>
  loopback loop <span style="color: #007800;">$isofile</span>
  linux <span style="color: #7a0874; font-weight: bold;">&#40;</span>loop<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #000000; font-weight: bold;">/</span>casper<span style="color: #000000; font-weight: bold;">/</span>vmlinuz <span style="color: #007800;">boot</span>=casper iso-scan<span style="color: #000000; font-weight: bold;">/</span><span style="color: #007800;">filename</span>=<span style="color: #007800;">$isofile</span> noeject noprompt <span style="color: #660033;">--</span>
  initrd <span style="color: #7a0874; font-weight: bold;">&#40;</span>loop<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #000000; font-weight: bold;">/</span>casper<span style="color: #000000; font-weight: bold;">/</span>initrd.lz
<span style="color: #7a0874; font-weight: bold;">&#125;</span>
&nbsp;
menuentry <span style="color: #ff0000;">&quot;Ubuntu 10.04 Desktop x86&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">set</span> <span style="color: #007800;">isofile</span>=<span style="color: #ff0000;">&quot;/boot/iso/ubuntu-10.04-desktop-i386.iso&quot;</span>
  loopback loop <span style="color: #007800;">$isofile</span>
  linux <span style="color: #7a0874; font-weight: bold;">&#40;</span>loop<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #000000; font-weight: bold;">/</span>casper<span style="color: #000000; font-weight: bold;">/</span>vmlinuz <span style="color: #007800;">boot</span>=casper iso-scan<span style="color: #000000; font-weight: bold;">/</span><span style="color: #007800;">filename</span>=<span style="color: #007800;">$isofile</span> noeject noprompt <span style="color: #660033;">--</span>
  initrd <span style="color: #7a0874; font-weight: bold;">&#40;</span>loop<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #000000; font-weight: bold;">/</span>casper<span style="color: #000000; font-weight: bold;">/</span>initrd.lz
<span style="color: #7a0874; font-weight: bold;">&#125;</span>
&nbsp;
menuentry <span style="color: #ff0000;">&quot;Clonezilla Live 1.2.5-17 x86&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">set</span> <span style="color: #007800;">isofile</span>=<span style="color: #ff0000;">&quot;/boot/iso/clonezilla-live-1.2.5-17-i686.iso&quot;</span>
  loopback loop <span style="color: #007800;">$isofile</span> 
  linux <span style="color: #7a0874; font-weight: bold;">&#40;</span>loop<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #000000; font-weight: bold;">/</span>live<span style="color: #000000; font-weight: bold;">/</span>vmlinuz <span style="color: #007800;">boot</span>=live <span style="color: #007800;">union</span>=aufs nolocales noprompt <span style="color: #007800;">ip</span>=frommedia <span style="color: #007800;">toram</span>=filesystem.squashfs <span style="color: #007800;">findiso</span>=<span style="color: #007800;">$isofile</span> 
  initrd <span style="color: #7a0874; font-weight: bold;">&#40;</span>loop<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #000000; font-weight: bold;">/</span>live<span style="color: #000000; font-weight: bold;">/</span>initrd.img
<span style="color: #7a0874; font-weight: bold;">&#125;</span>
&nbsp;
menuentry <span style="color: #ff0000;">&quot;GParted Live 0.5.2-9 x86&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">set</span> <span style="color: #007800;">isofile</span>=<span style="color: #ff0000;">&quot;/boot/iso/gparted-live-0.5.2-9.iso&quot;</span>
  loopback loop <span style="color: #007800;">$isofile</span> 
  linux <span style="color: #7a0874; font-weight: bold;">&#40;</span>loop<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #000000; font-weight: bold;">/</span>live<span style="color: #000000; font-weight: bold;">/</span>vmlinuz <span style="color: #007800;">boot</span>=live <span style="color: #007800;">union</span>=aufs nolocales noprompt <span style="color: #007800;">ip</span>=frommedia <span style="color: #007800;">toram</span>=filesystem.squashfs <span style="color: #007800;">findiso</span>=<span style="color: #007800;">$isofile</span> 
  initrd <span style="color: #7a0874; font-weight: bold;">&#40;</span>loop<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #000000; font-weight: bold;">/</span>live<span style="color: #000000; font-weight: bold;">/</span>initrd.img
<span style="color: #7a0874; font-weight: bold;">&#125;</span>
&nbsp;
menuentry <span style="color: #ff0000;">&quot;Memory test (memtest86+)&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#123;</span>
  linux16 <span style="color: #000000; font-weight: bold;">/</span>boot<span style="color: #000000; font-weight: bold;">/</span>iso<span style="color: #000000; font-weight: bold;">/</span>memtest86+.bin
<span style="color: #7a0874; font-weight: bold;">&#125;</span></pre></div></div>

<p>Não se esqueça de alterar o valor as variáveis <code>isofile</code>, se necessário.</p>
<h3>Ressalva</h3>
<p>Esse negócio todo é novo, e existem apenas algumas  distribuições que podem ser bootadas dessa forma. Caso queira testar outras distribuições, você provavelmente terá que descobrir quais opções de Kernel usar em cada uma delas.</p>
]]></content:encoded>
			<wfw:commentRss>http://weblog.destaquenet.com/2010/08/02/crie-seu-proprio-pendrive-usb-multi-boot-salvador-da-patria/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Django Para Dispositivos Móveis</title>
		<link>http://weblog.destaquenet.com/2010/07/12/django-para-dispositivos-moveis/</link>
		<comments>http://weblog.destaquenet.com/2010/07/12/django-para-dispositivos-moveis/#comments</comments>
		<pubDate>Mon, 12 Jul 2010 11:10:21 +0000</pubDate>
		<dc:creator>Daniel Martins</dc:creator>
				<category><![CDATA[Português]]></category>
		<category><![CDATA[Programação]]></category>
		<category><![CDATA[Tutoriais]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[configuração]]></category>
		<category><![CDATA[deploy]]></category>
		<category><![CDATA[dispositivo]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[móvel]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[wsgi]]></category>

		<guid isPermaLink="false">http://weblog.destaquenet.com/?p=944</guid>
		<description><![CDATA[Estamos vivendo o que alguns chamam de &#8220;explosão mobile&#8221;, um tempo onde um número cada vez maior de dispositivos móveis &#8212; como tablets e smartphones &#8212; se tornam parte significante da Web. Esta é a razão pela qual ter seu &#8230; <a href="http://weblog.destaquenet.com/2010/07/12/django-para-dispositivos-moveis/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Estamos vivendo o que alguns chamam de &#8220;explosão mobile&#8221;, um tempo onde um número cada vez maior de dispositivos móveis &#8212; como tablets e smartphones &#8212; se tornam parte significante da Web. Esta é a razão pela qual ter seu website preparado para tais dispositivos é cada vez mais importante.</p>
<p>Felizmente, <a href="http://djangoproject.com/">Django</a> é um dos poucos frameworks web que tornam este um problema simples de solucionar.</p>
<p><span id="more-944"></span></p>
<h3>Como resolvemos este problema</h3>
<p>Um jeito simples é criar um módulo <code>settings.py</code> separado para a versão &#8220;mobile&#8221;. Isso nos permite rodar dois sites diferentes reusando a mesma base de código. Além disso, cada versão pode ter seu próprio diretório de templates, configurações de URL, etc.</p>
<p>Vamos fazer isso. No diretório-raíz do projeto, crie um arquivo <code>m_settings.py</code> com o seguinte conteúdo:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># Arquivo: myproject/m_settings.py</span>
&nbsp;
<span style="color: #483d8b;">&quot;&quot;&quot;Configurações para a versão &quot;mobile&quot; do website.
&quot;&quot;&quot;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Carrega as configurações padrão</span>
<span style="color: #ff7700;font-weight:bold;">from</span> settings <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Domínio &quot;m.mydomain.com&quot;</span>
SITE_ID = <span style="color: #ff4500;">2</span>
PREPEND_WWW = <span style="color: #008000;">False</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Usado em outras partes do código para determinar qual versão está rodando</span>
DEFAULT_VERSION = <span style="color: #008000;">False</span>
MOBILE_VERSION  = <span style="color: #008000;">True</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># URLs para a versão mobile</span>
ROOT_URLCONF  = <span style="color: #483d8b;">'myproject.m_urls'</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Templates para a versão mobile</span>
TEMPLATE_DIRS = <span style="color: black;">&#40;</span>
    <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">normpath</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">dirname</span><span style="color: black;">&#40;</span>__file__<span style="color: black;">&#41;</span> + <span style="color: #483d8b;">'/template/mobile'</span><span style="color: black;">&#41;</span>,
<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Outras configurações...</span></pre></div></div>

<p>O fato de os dois sites compartilharem a mesma base de código não significa que eles devem ter as mesmas configurações de URL. Aliás, o normal é que versões próprias para dispositivos móveis sejam mais simples, com uma quantidade reduzida de mapeamentos de URLs.</p>
<p>Para definir as configurações de URL da versão mobile, crie um arquivo <code>m_urls.py</code> com o seguinte conteúdo:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># Arquivo: myproject/m_urls.py</span>
&nbsp;
<span style="color: #483d8b;">&quot;&quot;&quot;Mapeamentos de URL para a versão &quot;mobile&quot;.
&quot;&quot;&quot;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">conf</span> <span style="color: #ff7700;font-weight:bold;">import</span> settings
<span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">conf</span>.<span style="color: black;">urls</span>.<span style="color: black;">defaults</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span>
<span style="color: #808080; font-style: italic;"># from django.contrib import admin</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># admin.autodiscover()</span>
&nbsp;
handler404 = <span style="color: #483d8b;">'website.views.error_404_handler'</span>
handler500 = <span style="color: #483d8b;">'website.views.error_500_handler'</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># URLs</span>
urlpatterns = patterns<span style="color: black;">&#40;</span><span style="color: #483d8b;">''</span>,
    <span style="color: #808080; font-style: italic;"># I18N</span>
    <span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'^i18n/'</span>, include<span style="color: black;">&#40;</span><span style="color: #483d8b;">'django.conf.urls.i18n'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>,
&nbsp;
    <span style="color: #808080; font-style: italic;"># Apps internas</span>
    <span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'^contact/'</span>, include<span style="color: black;">&#40;</span><span style="color: #483d8b;">'contact.urls'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>,
&nbsp;
    <span style="color: #808080; font-style: italic;"># (r'^admin/doc/', include('django.contrib.admindocs.urls')),</span>
    <span style="color: #808080; font-style: italic;"># (r'^admin/', include(admin.site.urls)),</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Outras configurações...</span>
<span style="color: black;">&#41;</span></pre></div></div>

<p>Perceba que, neste exemplo em particular, a <a href="http://docs.djangoproject.com/en/dev/ref/contrib/admin/">app Admin</a> não é acessível através da versão mobile. Isso apenas serve para mostrar que temos total liberdade para estruturar ambas as versões de diferentes formas, sem muitas dificuldades.</p>
<h3>Desenvolvendo</h3>
<p>Você certamente já sabe como rodar o servidor de desenvolvimento para a versão padrão. O que a maioria dos desenvolvedores desconhece, entretanto, é que é possível escolher qual a porta e/ou módulo <code>settings.py</code> deve ser usado pelo script, o que nos permite rodar um servidor para cada versão do nosso site:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># Terminal 1: versão padrão</span>
$ python manage.py runserver <span style="color: #000000;">8000</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># Terminal 2: versão mobile</span>
$ python manage.py runserver <span style="color: #660033;">--settings</span>=m_settings <span style="color: #000000;">8001</span></pre></div></div>

<p>Pronto, agora é só continuar com o desenvolvimento da forma que você já está acostumado.</p>
<h3>Testando</h3>
<p>Você provavelmente notou que temos duas configurações que podem ser usadas para determinar qual versão do site está rodando, <code>DEFAULT_VERSION</code> e <code>MOBILE_VERSION</code>. </p>
<p>Por isso, é só uma questão de checar tais configurações quando for necessário fazer coisas diferentes em cada uma das versões do site. Isso é particularmente útil quando você tem uma app usada em ambas as versões e quer criar testes para cada uma das versões:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># Arquivo: myproject/myapp/tests/__init__.py</span>
&nbsp;
<span style="color: #483d8b;">&quot;&quot;&quot;Testes para MyApp.
&quot;&quot;&quot;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">conf</span> <span style="color: #ff7700;font-weight:bold;">import</span> settings
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">getattr</span><span style="color: black;">&#40;</span>settings, <span style="color: #483d8b;">'DEFAULT_VERSION'</span>, <span style="color: #008000;">False</span><span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># Testa a versão padrão</span>
    <span style="color: #ff7700;font-weight:bold;">from</span> default_models_tests <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span>
    <span style="color: #ff7700;font-weight:bold;">from</span> default_navigation_tests <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">getattr</span><span style="color: black;">&#40;</span>settings, <span style="color: #483d8b;">'MOBILE_VERSION'</span>, <span style="color: #008000;">False</span><span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># Testa a versão mobile</span>
    <span style="color: #ff7700;font-weight:bold;">from</span> mobile_models_tests <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span>
    <span style="color: #ff7700;font-weight:bold;">from</span> mobile_navigation_tests <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span></pre></div></div>

<p>Você pode rodar os testes para cada versão de uma forma semelhante a que fizemos com o comando <code>runserver</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># Versão padrão</span>
$ python manage.py <span style="color: #7a0874; font-weight: bold;">test</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span>appname...<span style="color: #7a0874; font-weight: bold;">&#93;</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># Versão mobile</span>
$ python manage.py <span style="color: #7a0874; font-weight: bold;">test</span> <span style="color: #660033;">--settings</span>=m_settings <span style="color: #7a0874; font-weight: bold;">&#91;</span>appname...<span style="color: #7a0874; font-weight: bold;">&#93;</span></pre></div></div>

<h3>Colocando em produção</h3>
<p>Apesar do que você possa achar, esta é a parte fácil.</p>
<p>Uma vez que a forma recomendada de <a href="http://docs.djangoproject.com/en/dev/howto/deployment/modwsgi/">colocar Django em produção</a> é com <a href="http://apache.org">Apache</a> e <a href="http://code.google.com/p/modwsgi/">mod_wsgi</a>, é possível que você já tenha um arquivo WSGI parecido com o seguinte:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">os</span>, <span style="color: #dc143c;">sys</span>
&nbsp;
APPS_PATH   = <span style="color: #483d8b;">'/home/user/wsgi_apps'</span>
MYPROJECT_PATH = <span style="color: #483d8b;">'%s/myproject'</span> <span style="color: #66cc66;">%</span> APPS_PATH
&nbsp;
<span style="color: #808080; font-style: italic;"># Eggs de terceiros</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">site</span>
<span style="color: #dc143c;">site</span>.<span style="color: black;">addsitedir</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/home/user/.python/lib'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #dc143c;">sys</span>.<span style="color: black;">path</span> += <span style="color: black;">&#91;</span>APPS_PATH, MYPROJECT_PATH<span style="color: black;">&#93;</span>
<span style="color: #dc143c;">os</span>.<span style="color: black;">environ</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'DJANGO_SETTINGS_MODULE'</span><span style="color: black;">&#93;</span> = <span style="color: #483d8b;">'myproject.settings'</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">import</span> django.<span style="color: black;">core</span>.<span style="color: black;">handlers</span>.<span style="color: black;">wsgi</span>
application = django.<span style="color: black;">core</span>.<span style="color: black;">handlers</span>.<span style="color: black;">wsgi</span>.<span style="color: black;">WSGIHandler</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Tudo que precisamos fazer é configurar um outro sub-domínio WSGI no nosso servidor (ex: m.mywebsite.com) que referencia o seguinte arquivo de configurações WSGI:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">os</span>, <span style="color: #dc143c;">sys</span>
&nbsp;
APPS_PATH   = <span style="color: #483d8b;">'/home/user/wsgi_apps'</span>
MYPROJECT_PATH = <span style="color: #483d8b;">'%s/myproject'</span> <span style="color: #66cc66;">%</span> APPS_PATH
&nbsp;
<span style="color: #808080; font-style: italic;"># Eggs de terceiros</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">site</span>
<span style="color: #dc143c;">site</span>.<span style="color: black;">addsitedir</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/home/user/.python/lib'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #dc143c;">sys</span>.<span style="color: black;">path</span> += <span style="color: black;">&#91;</span>APPS_PATH, MYPROJECT_PATH<span style="color: black;">&#93;</span>
<span style="color: #dc143c;">os</span>.<span style="color: black;">environ</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'DJANGO_SETTINGS_MODULE'</span><span style="color: black;">&#93;</span> = <span style="color: #483d8b;">'myproject.m_settings'</span> <span style="color: #808080; font-style: italic;"># Esta linha</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">import</span> django.<span style="color: black;">core</span>.<span style="color: black;">handlers</span>.<span style="color: black;">wsgi</span>
application = django.<span style="color: black;">core</span>.<span style="color: black;">handlers</span>.<span style="color: black;">wsgi</span>.<span style="color: black;">WSGIHandler</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>A única diferença entre esses dois arquivos WSGI é que cada um aponta para um módulo <code>settings.py</code> diferente. E não, você não precisa ter uma cópia do site para cada versão, afinal estamos usando a mesma base de código para ambas as versões, lembra? <img src='http://weblog.destaquenet.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<h3>Minimizando o tráfego</h3>
<p>Por incrível que pareça, nem todo mundo dispõe de conexões ultra-rápidas. Por isso, é muito importante que você mantenha seus sites tão leves quanto possível.</p>
<p>Existem vários projetos open source que podem ajudar nessa parte. Um deles é o <a href="http://code.google.com/p/django-compress/">django-compress</a>, uma app Django que fornece um sistema automatizado para compressão de arquivos CSS e JavaScript.</p>
<p>Aliás, não importa se seus websites são para dispositivos móveis ou não; você deve <em>sempre</em> tentar minimizar o tráfego.</p>
<h3>O que falta?</h3>
<p>Ainda temos um pequeno problema: quando alguém visita a versão padrão do site através de um dispositivo móvel, ou vice-versa, eles não são redirecionados para a versão apropriada. Mas isso é assunto para um próximo artigo!</p>
]]></content:encoded>
			<wfw:commentRss>http://weblog.destaquenet.com/2010/07/12/django-para-dispositivos-moveis/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Servidor De Email Local No Ubuntu Com Exim</title>
		<link>http://weblog.destaquenet.com/2010/06/25/servidor-de-email-local-no-ubuntu-com-exim/</link>
		<comments>http://weblog.destaquenet.com/2010/06/25/servidor-de-email-local-no-ubuntu-com-exim/#comments</comments>
		<pubDate>Fri, 25 Jun 2010 11:10:07 +0000</pubDate>
		<dc:creator>Daniel Martins</dc:creator>
				<category><![CDATA[Português]]></category>
		<category><![CDATA[Tutoriais]]></category>
		<category><![CDATA[ambiente]]></category>
		<category><![CDATA[configuração]]></category>
		<category><![CDATA[desenvolvimento]]></category>
		<category><![CDATA[email]]></category>
		<category><![CDATA[exim]]></category>
		<category><![CDATA[gmail]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[sendmail]]></category>
		<category><![CDATA[servidor]]></category>
		<category><![CDATA[smtp]]></category>
		<category><![CDATA[telnet]]></category>
		<category><![CDATA[ubuntu]]></category>

		<guid isPermaLink="false">http://weblog.destaquenet.com/?p=981</guid>
		<description><![CDATA[Vimos em um post anterior como criar testes para código Java que envia e-mails. Agora o assunto é outro. Exim é um MTA open source que pode ser usado como alternativa ao Sendmail em sistemas operacionais Unix. Eu não tenho &#8230; <a href="http://weblog.destaquenet.com/2010/06/25/servidor-de-email-local-no-ubuntu-com-exim/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Vimos em um post anterior como criar testes para <a href="http://weblog.destaquenet.com/2008/09/20/2-boas-formas-de-testar-clientes-javamail/">código Java que envia e-mails</a>. Agora o assunto é outro.</p>
<p><a href="http://www.exim.org/">Exim</a> é um <acronym title="Mail Transfer Agent">MTA</acronym> open source que pode ser usado como alternativa ao <a href="http://www.sendmail.org/">Sendmail</a> em sistemas operacionais Unix. Eu não tenho idéia de qual é a melhor alternativa disponível, mas se você procura por um servidor de relay para instalar na sua configuração de desenvolvimento, Exim é provavelmente a opção mais simples para começar.</p>
<p>Neste artigo, veremos como configurar o Exim para enviar mensagens através do <a href="http://gmail.com/">Gmail</a>.</p>
<p><span id="more-981"></span></p>
<h3>Instalando o Exim</h3>
<p>Primeiro precisamos instalar o Exim e suas dependências, o que é algo bastante trivial em distribuições Linux modernas como <a href="http://www.ubuntu.com/">Ubuntu</a>/<a href="http://www.debian.org/">Debian</a>:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">apt-get</span> <span style="color: #c20cb9; font-weight: bold;">install</span> exim4</pre></div></div>

<h3>Usando Exim como servidor de relay</h3>
<p>Existe um assistente que nos ajuda a fazer as configurações básicas; rode o comando abaixo para abrí-lo e preencha cada tela como segue:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #c20cb9; font-weight: bold;">sudo</span> dpkg-reconfigure exim4-config</pre></div></div>

<ol>
<li><strong>General type of mail configuration:</strong> mail sent by smarthost; received via SMTP or fetchmail</li>
<li><strong>System mail name:</strong> seudominio.com</li>
<li><strong>IP-addresses to listen on for incoming connections:</strong> 127.0.0.1 ; ::1</li>
<li><strong>Other destinations for which mail is accepted:</strong> Deixe em branco</li>
<li><strong>Machines to relay mail for:</strong> Deixe em branco</li>
<li><strong>Host name for the outgoing smarthost:</strong> smtp.gmail.com:587</li>
<li><strong>Hide local mail name in outgoing mail:</strong> Yes</strong></li>
<li><strong>Visible domain name for local users:</strong> seudominio.com</li>
<li><strong>Keep number of DNS-queries minimal:</strong> No</li>
<li><strong>Delivery method for local mail:</strong> mbox format in /var/mail/</li>
<li><strong>Split configuration into small files:</strong> Yes</li>
<li><strong>Root and postmaster mail recipient:</strong> Deixe em branco</li>
</ol>
<p>Agora precisamos configurar as credenciais do usuário no arquivo <code>/etc/exim4/passwd.client</code> adicionando a seguinte linha:</p>
<pre>
# Troque [username] e [password] pelos dados corretos
*.google.com:[username]:[password]
</pre>
<p>Agora basta rodar o comando abaixo para terminar as configurações:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #c20cb9; font-weight: bold;">sudo</span> update-exim4.conf</pre></div></div>

<h3>Testando o servidor</h3>
<p>Um jeito simples &#8212; e nerd &#8212; de testar se as configurações estão corretas é usar o comando <code>telnet</code>:</p>
<pre>
$ telnet localhost 25
    Trying ::1...
    Connected to localhost.
    Escape character is '^]'.
    220 localhost ESMTP Exim 4.71 Wed, 23 Jun 2010 22:28:56 -0300
HELO localhost
    250 localhost Hello localhost [::1]
MAIL FROM: usuario@seudominio.com
    250 OK
RCPT TO: destino@email.com
    250 Accepted
DATA
    354 Enter message, ending with "." on a line by itself
SUBJECT: Assunto da mensagem
Testando Exim via Telnet. Massa!
.
    250 OK id=1ORbG5-0005uh-EF
QUIT
    221 localhost closing connection
    Connection closed by foreign host.
</pre>
<p>Abra os arquivos de log em <code>/var/log/exim4</code> para ver se a mensagem foi transmitida sem erros. Uma tentativa bem sucedida se parece com o seguinte:</p>
<pre>
2010-06-23 22:29:47 1ORbG5-0005uh-EF <= local@seudominio.com H=localhost [::1] P=smtp S=345
2010-06-23 22:29:50 1ORbG5-0005uh-EF => destino@email.com R=smarthost T=remote_smtp_smarthost H=gmail-smtp-msa.l.google.com [74.125.45.109] ..."
2010-06-23 22:29:50 1ORbG5-0005uh-EF Completed
</pre>
<p>Caso você não receba a mensagem e os logs não acusem nenhum erro, verifique se a mensagem não foi parar na caixa de spam antes que você mude quaisquer configurações.</p>
]]></content:encoded>
			<wfw:commentRss>http://weblog.destaquenet.com/2010/06/25/servidor-de-email-local-no-ubuntu-com-exim/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>JSP e tag files: criando templates em 10 minutos</title>
		<link>http://weblog.destaquenet.com/2009/12/17/jsp-e-tag-files-criando-templates-em-10-minutos/</link>
		<comments>http://weblog.destaquenet.com/2009/12/17/jsp-e-tag-files-criando-templates-em-10-minutos/#comments</comments>
		<pubDate>Thu, 17 Dec 2009 12:30:41 +0000</pubDate>
		<dc:creator>Daniel Martins</dc:creator>
				<category><![CDATA[Português]]></category>
		<category><![CDATA[Programação]]></category>
		<category><![CDATA[Tutoriais]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[jsp]]></category>
		<category><![CDATA[layout]]></category>
		<category><![CDATA[servlet]]></category>
		<category><![CDATA[tag]]></category>
		<category><![CDATA[tagfiles]]></category>
		<category><![CDATA[taglib]]></category>
		<category><![CDATA[template]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://weblog.destaquenet.com/?p=801</guid>
		<description><![CDATA[Este mês têm sido bastante curioso pelo fato de três pessoas terem me feito a mesma pergunta: &#8220;- Você largou o Java de vez?&#8221;. A resposta é não, mas, para não deixar dúvidas, eu resolvi voltar a escrever sobre Java. &#8230; <a href="http://weblog.destaquenet.com/2009/12/17/jsp-e-tag-files-criando-templates-em-10-minutos/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Este mês têm sido bastante curioso pelo fato de três pessoas terem me feito a mesma pergunta: &#8220;- Você largou o Java de vez?&#8221;. A resposta é <strong>não</strong>, mas, para não deixar dúvidas, eu resolvi voltar a escrever sobre Java. O assunto foge um pouco do que costumo escrever, mas é algo que considero importante.</p>
<p>Ultimamente, tenho visto a forma como certos desenvolvedores escrevem seus JSPs, e o que me preocupou foi ver o quanto eles desconhecem a tecnologia. Não é raro achar páginas cheias de <a href="http://java.sun.com/javaee/5/docs/tutorial/doc/bnaou.html">scriptlets</a>, includes malucos, código du-tri-quadri-plicado e nenhuma taglib além da fornecida pelo framework web em uso.</p>
<p>É muito fácil escrever JSPs da forma errada, mas fazer as coisas de um jeito melhor é mais fácil ainda. Ao contrário do que muitos pensam, é possível sim criar JSPs limpos sem o uso de qualquer framework de layout (como <a href="http://www.opensymphony.com/sitemesh/">Sitemesh</a>) ou biblioteca (com exceção da <a href="http://java.sun.com/products/jsp/jstl/reference/docs/index.html">JSTL</a>, é claro).</p>
<p><span id="more-801"></span></p>
<h3>Um exemplo</h3>
<p>O primeiro passo é definir o template base para as páginas da aplicação. Considere o seguinte exemplo de XHTML e sua representação gráfica:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #00bbdd;">&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot;</span>
<span style="color: #00bbdd;">    &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;</span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;html</span> <span style="color: #000066;">xmlns</span>=<span style="color: #ff0000;">&quot;http://www.w3.org/1999/xhtml&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;head<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;meta</span> <span style="color: #000066;">http-equiv</span>=<span style="color: #ff0000;">&quot;content-type&quot;</span> <span style="color: #000066;">content</span>=<span style="color: #ff0000;">&quot;text/html; charset=UTF-8&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;meta</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;keywords&quot;</span>    <span style="color: #000066;">content</span>=<span style="color: #ff0000;">&quot;keyword1, keyword2, keyword3&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;meta</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;description&quot;</span> <span style="color: #000066;">content</span>=<span style="color: #ff0000;">&quot;Page description&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;title<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Page title<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/title<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
&nbsp;
        <span style="color: #808080; font-style: italic;">&lt;!-- Essential scripts --&gt;</span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;link</span> <span style="color: #000066;">rel</span>=<span style="color: #ff0000;">&quot;stylesheet&quot;</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;text/css&quot;</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;css/style.css&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;script</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;text/javascript&quot;</span> <span style="color: #000066;">src</span>=<span style="color: #ff0000;">&quot;js/query.js&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/script<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
&nbsp;
        <span style="color: #808080; font-style: italic;">&lt;!-- Extra header --&gt;</span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;script</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;text/javascript&quot;</span> <span style="color: #000066;">src</span>=<span style="color: #ff0000;">&quot;js/util.js&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/script<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/head<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #808080; font-style: italic;">&lt;!-- Main --&gt;</span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;div</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;wrapper&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;div</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;header&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/div<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;div</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;content&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/div<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;div</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;footer&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/div<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> <span style="color: #808080; font-style: italic;">&lt;!-- Main --&gt;</span>
&nbsp;
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;script</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;text/javascript&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
            // Other scripts (e.g. Google Analytics)
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/script<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/html<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<div id="attachment_803" class="wp-caption aligncenter" style="width: 310px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2009/12/layout.gif"><img src="http://weblog.destaquenet.com/wp-content/uploads/2009/12/layout-300x156.gif" alt="Representação gráfica do layout" title="layout" width="300" height="156" class="size-medium wp-image-803" /></a><p class="wp-caption-text">Representação gráfica do layout</p></div>
<p>O que costuma acontecer, mesmo em um layout simples como esse, é o alto índice de duplicação de código entre as diferentes páginas, principalmente em função do uso de <a href="http://en.wikipedia.org/wiki/Copy_and_paste_programming">Copy and Paste Programming</a>. Muitos desenvolvedores por aí escreveriam o seguinte JSP para representar o layout proposto:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #00bbdd;">&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot;</span>
<span style="color: #00bbdd;">    &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;</span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;html</span> <span style="color: #000066;">xmlns</span>=<span style="color: #ff0000;">&quot;http://www.w3.org/1999/xhtml&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;head<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;meta</span> <span style="color: #000066;">http-equiv</span>=<span style="color: #ff0000;">&quot;content-type&quot;</span> <span style="color: #000066;">content</span>=<span style="color: #ff0000;">&quot;text/html; charset=UTF-8&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;meta</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;keywords&quot;</span>    <span style="color: #000066;">content</span>=<span style="color: #ff0000;">&quot;keyword1, keyword2, keyword3&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;meta</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;description&quot;</span> <span style="color: #000066;">content</span>=<span style="color: #ff0000;">&quot;Page description&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;title<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Page title<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/title<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
&nbsp;
        <span style="color: #808080; font-style: italic;">&lt;!-- Essential scripts --&gt;</span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;jsp:include</span> <span style="color: #000066;">page</span>=<span style="color: #ff0000;">&quot;scripts.jsp&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
&nbsp;
        <span style="color: #808080; font-style: italic;">&lt;!-- Extra header --&gt;</span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;script</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;text/javascript&quot;</span> <span style="color: #000066;">src</span>=<span style="color: #ff0000;">&quot;js/util.js&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/script<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/head<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #808080; font-style: italic;">&lt;!-- Main --&gt;</span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;div</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;wrapper&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;jsp:include</span> <span style="color: #000066;">file</span>=<span style="color: #ff0000;">&quot;header.jsp&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;div</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;content&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>Page content here<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;jsp:include</span> <span style="color: #000066;">page</span>=<span style="color: #ff0000;">&quot;footer.jsp&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> <span style="color: #808080; font-style: italic;">&lt;!-- Main --&gt;</span>
&nbsp;
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;script</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;text/javascript&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
            // Other scripts
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/script<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/html<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>Viu o problema? De nada adianta separar os pedaços com <jsp:include> e continuar duplicando código. O ideal seria traduzir o layout em algo assim:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;">&lt;%@ taglib <span style="color: #000066;">tagdir</span>=<span style="color: #ff0000;">&quot;/WEB-INF/tags/layout&quot;</span> <span style="color: #000066;">prefix</span>=<span style="color: #ff0000;">&quot;layout&quot;</span> %<span style="color: #000000; font-weight: bold;">&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;layout:page</span> <span style="color: #000066;">title</span>=<span style="color: #ff0000;">&quot;Title&quot;</span> <span style="color: #000066;">description</span>=<span style="color: #ff0000;">&quot;Page description&quot;</span> <span style="color: #000066;">keywords</span>=<span style="color: #ff0000;">&quot;keyword1, keyword2, keyword3&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;jsp:attribute</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;extraHeader&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;script</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;text/javascript&quot;</span> <span style="color: #000066;">src</span>=<span style="color: #ff0000;">&quot;js/util.js&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/script<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/jsp:attribute<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;jsp:attribute</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;extraBottom&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
        // Other scripts (e.g. Google Analytics)
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/jsp:attribute<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;jsp:body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        Page content here
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/jsp:body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/layout:page<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>A boa notícia é que isso é possível, através de tag files.</p>
<h3>Reúso de conteúdo com tag files</h3>
<p>Existem pelo menos três formas de se criar custom tags em JSP, cada qual com seu propósito: <a href="http://java.sun.com/javaee/5/docs/tutorial/doc/bnaow.html#bnaoy">classic tag handlers</a>, <a href="http://java.sun.com/javaee/5/docs/tutorial/doc/bnann.html">simple tag handlers</a> e <a href="http://java.sun.com/javaee/5/docs/tutorial/doc/bnama.html">tag files</a>. Neste post tratarei somente das tag files, mas saber como e quando utilizar simple tag handlers também é extremamente recomendado a todos que usam JSP no dia-a-dia.</p>
<p>A primeira coisa a fazer é criar o diretório <code>WEB-INF/tags/layout</code>. É nesse diretório que as tag files referentes ao template devem ficar. Agora, crie dois arquivos neste diretório, um para o cabeçalho e outro para o rodapé:</p>
<p><strong>header.tag</strong></p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;">&lt;%@ tag <span style="color: #000066;">body-content</span>=<span style="color: #ff0000;">&quot;empty&quot;</span> <span style="color: #000066;">description</span>=<span style="color: #ff0000;">&quot;Header tag file&quot;</span> %<span style="color: #000000; font-weight: bold;">&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;div</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;header&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
    <span style="color: #808080; font-style: italic;">&lt;!-- Header section here --&gt;</span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p><strong>footer.tag</strong></p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;">&lt;%@ tag <span style="color: #000066;">body-content</span>=<span style="color: #ff0000;">&quot;empty&quot;</span> <span style="color: #000066;">description</span>=<span style="color: #ff0000;">&quot;Footer tag file&quot;</span> %<span style="color: #000000; font-weight: bold;">&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;div</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;footer&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
    <span style="color: #808080; font-style: italic;">&lt;!-- Footer section here --&gt;</span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>Como podemos ver, as tag files são como JSPs, mas com algumas propriedades especiais.</p>
<p>A última tag file, <strong>page.tag</strong>, define o esqueleto das páginas da aplicação:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;">&lt;%@ tag <span style="color: #000066;">description</span>=<span style="color: #ff0000;">&quot;Page layout&quot;</span> %<span style="color: #000000; font-weight: bold;">&gt;</span></span>
&nbsp;
<span style="color: #009900;">&lt;%@ attribute <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;title&quot;</span>       <span style="color: #000066;">required</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">description</span>=<span style="color: #ff0000;">&quot;Page title&quot;</span> %<span style="color: #000000; font-weight: bold;">&gt;</span></span>
<span style="color: #009900;">&lt;%@ attribute <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;keywords&quot;</span>    <span style="color: #000066;">required</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">description</span>=<span style="color: #ff0000;">&quot;Page keywords to improve SEO&quot;</span> %<span style="color: #000000; font-weight: bold;">&gt;</span></span>
<span style="color: #009900;">&lt;%@ attribute <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;description&quot;</span> <span style="color: #000066;">required</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">description</span>=<span style="color: #ff0000;">&quot;Page description&quot;</span> %<span style="color: #000000; font-weight: bold;">&gt;</span></span>
&nbsp;
<span style="color: #009900;">&lt;%@ attribute <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;extraHeader&quot;</span> <span style="color: #000066;">fragment</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">description</span>=<span style="color: #ff0000;">&quot;Extra code to put before &lt;/head&gt;</span></span>&quot; %&gt;
<span style="color: #009900;">&lt;%@ attribute <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;extraBottom&quot;</span> <span style="color: #000066;">fragment</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">description</span>=<span style="color: #ff0000;">&quot;Extra code to put before &lt;/body&gt;</span></span>&quot; %&gt;
&nbsp;
<span style="color: #009900;">&lt;%@ taglib <span style="color: #000066;">tagdir</span>=<span style="color: #ff0000;">&quot;/WEB-INF/tags/layout&quot;</span> <span style="color: #000066;">prefix</span>=<span style="color: #ff0000;">&quot;layout&quot;</span> %<span style="color: #000000; font-weight: bold;">&gt;</span></span>
&nbsp;
<span style="color: #00bbdd;">&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot;</span>
<span style="color: #00bbdd;">    &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;</span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;html</span> <span style="color: #000066;">xmlns</span>=<span style="color: #ff0000;">&quot;http://www.w3.org/1999/xhtml&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;head<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;meta</span> <span style="color: #000066;">http-equiv</span>=<span style="color: #ff0000;">&quot;content-type&quot;</span> <span style="color: #000066;">content</span>=<span style="color: #ff0000;">&quot;text/html; charset=UTF-8&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
&nbsp;
        <span style="color: #808080; font-style: italic;">&lt;!-- Displaying the attributes using EL --&gt;</span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;meta</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;keywords&quot;</span>    <span style="color: #000066;">content</span>=<span style="color: #ff0000;">&quot;${keywords}&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;meta</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;description&quot;</span> <span style="color: #000066;">content</span>=<span style="color: #ff0000;">&quot;${description}&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;title<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>${title}<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/title<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
&nbsp;
        <span style="color: #808080; font-style: italic;">&lt;!-- Essential scripts --&gt;</span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;link</span> <span style="color: #000066;">rel</span>=<span style="color: #ff0000;">&quot;stylesheet&quot;</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;text/css&quot;</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;css/style.css&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;script</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;text/javascript&quot;</span> <span style="color: #000066;">src</span>=<span style="color: #ff0000;">&quot;js/query.js&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/script<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
&nbsp;
        <span style="color: #808080; font-style: italic;">&lt;!-- Process the given input fragment --&gt;</span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;jsp:invoke</span> <span style="color: #000066;">fragment</span>=<span style="color: #ff0000;">&quot;extraHeader&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/head<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #808080; font-style: italic;">&lt;!-- Main --&gt;</span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;div</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;wrapper&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
            <span style="color: #808080; font-style: italic;">&lt;!-- Renders the page header --&gt;</span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;layout:header</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
&nbsp;
            <span style="color: #808080; font-style: italic;">&lt;!-- Renders the tag body inside a DIV --&gt;</span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;div</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;content&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;jsp:doBody</span><span style="color: #000000; font-weight: bold;">/&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/div<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
&nbsp;
            <span style="color: #808080; font-style: italic;">&lt;!-- Renders the page footer --&gt;</span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;layout:footer</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> <span style="color: #808080; font-style: italic;">&lt;!-- Main --&gt;</span>
&nbsp;
        <span style="color: #808080; font-style: italic;">&lt;!-- Process the given input fragment --&gt;</span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;jsp:invoke</span> <span style="color: #000066;">fragment</span>=<span style="color: #ff0000;">&quot;extraBottom&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/html<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>Esta última tag file é mais complexa que as anteriores, pois recebe dados e blocos de código (através de <a href="http://java.sun.com/javaee/5/docs/tutorial/doc/bnaln.html#bnalq">fragments</a>). Além disso, ela aceita um corpo, que é executado com <code>&lt;jsp:doBody/&gt;</code>.</p>
<p>O exemplo usado aqui é razoavelmente simples e, por isso, não precisamos apelar para outros recursos mais avançados como <a href="http://java.sun.com/javaee/5/docs/tutorial/doc/bnaln.html#bnaly">variables</a> e <a href="http://java.sun.com/javaee/5/docs/tutorial/doc/bnaln.html#bnaly">dynamic attributes</a>. De qualquer forma, procure conhecer bem a tecnologia, pois você nunca sabe quando um ou outro recurso lhe pode ser útil.</p>
<h3>Exemplo de uso</h3>
<p>Novamente, um exemplo de uso das tags que criamos:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;">&lt;%@ taglib <span style="color: #000066;">tagdir</span>=<span style="color: #ff0000;">&quot;/WEB-INF/tags/layout&quot;</span> <span style="color: #000066;">prefix</span>=<span style="color: #ff0000;">&quot;layout&quot;</span> %<span style="color: #000000; font-weight: bold;">&gt;</span></span>
<span style="color: #009900;">&lt;%@ taglib <span style="color: #000066;">uri</span>=<span style="color: #ff0000;">&quot;http://java.sun.com/jsp/jstl/core&quot;</span> <span style="color: #000066;">prefix</span>=<span style="color: #ff0000;">&quot;c&quot;</span> %<span style="color: #000000; font-weight: bold;">&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;layout:page</span> <span style="color: #000066;">title</span>=<span style="color: #ff0000;">&quot;Index page&quot;</span> <span style="color: #000066;">description</span>=<span style="color: #ff0000;">&quot;This is the index page of my amazing app&quot;</span> <span style="color: #000066;">keywords</span>=<span style="color: #ff0000;">&quot;amazing, app&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;jsp:attribute</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;extraHeader&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;script</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;text/javascript&quot;</span> <span style="color: #000066;">src</span>=<span style="color: #ff0000;">&quot;js/util.js&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/script<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;script</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;text/javascript&quot;</span> <span style="color: #000066;">src</span>=<span style="color: #ff0000;">&quot;js/some_jquery_plugin.js&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/script<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/jsp:attribute<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;jsp:attribute</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;extraBottom&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
        $(function() {
            // Call some JQuery function here, specific for this page
        });
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/jsp:attribute<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;jsp:body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        Welcome to my amazing app!<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;br</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        1+1 = ${1+1}
&nbsp;
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;ul<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;c:forEach</span> <span style="color: #000066;">items</span>=<span style="color: #ff0000;">&quot;${objects}&quot;</span> <span style="color: #000066;">var</span>=<span style="color: #ff0000;">&quot;obj&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>${obj.attr}<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/c:forEach<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/ul<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/jsp:body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/layout:page<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>Embora a aplicação como um todo siga um mesmo padrão visual, cada página pode necessitar de recursos adicionais (JavaScript, CSS, etc). Isso não chega a ser um problema, pois nosso template contempla a inclusão de conteúdo extra, se necessário.</p>
<p>Outra vantagem é que as tag files permitem o uso de custom tags e <a href="http://java.sun.com/javaee/5/docs/tutorial/doc/bnahq.html">unified EL</a>, mas <strong>proíbem o uso de scriptlets</strong>, o que já é meio caminho andado rumo a um JSP mais limpo.</p>
<h3>Leitura recomendada</h3>
<ul>
<li><a href="http://java.sun.com/javaee/5/docs/tutorial/doc/">The Java EE 5 Tutorial</a>;</li>
<li><a href="http://www.amazon.com/Head-First-Servlets-JSP-Certified/dp/0596516681/ref=sr_1_1?ie=UTF8&#038;s=books&#038;qid=1260993372&#038;sr=8-1">Head First Servlets &#038; JSP</a>;</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://weblog.destaquenet.com/2009/12/17/jsp-e-tag-files-criando-templates-em-10-minutos/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>JsHamcrest: um alívio à dor de se testar código JavaScript</title>
		<link>http://weblog.destaquenet.com/2009/07/13/jshamcrest-um-alivio-a-dor-de-se-testar-codigo-javascript/</link>
		<comments>http://weblog.destaquenet.com/2009/07/13/jshamcrest-um-alivio-a-dor-de-se-testar-codigo-javascript/#comments</comments>
		<pubDate>Mon, 13 Jul 2009 14:10:21 +0000</pubDate>
		<dc:creator>Daniel Martins</dc:creator>
				<category><![CDATA[Português]]></category>
		<category><![CDATA[Programação]]></category>
		<category><![CDATA[Tutoriais]]></category>
		<category><![CDATA[destaquenet]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[jshamcrest]]></category>
		<category><![CDATA[jstestdriver]]></category>
		<category><![CDATA[jsunittest]]></category>
		<category><![CDATA[jsunity]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[projeto]]></category>
		<category><![CDATA[qunit]]></category>
		<category><![CDATA[teste]]></category>
		<category><![CDATA[yuitest]]></category>

		<guid isPermaLink="false">http://weblog.destaquenet.com/?p=584</guid>
		<description><![CDATA[Há não muito tempo atrás, escrever testes automatizados era coisa para poucos. Nem tanto por obstáculos técnicos, mas porque, na verdade, ninguém se importava muito com isso. A boa notícia é que a importância dos testes automatizados vem aumentando com &#8230; <a href="http://weblog.destaquenet.com/2009/07/13/jshamcrest-um-alivio-a-dor-de-se-testar-codigo-javascript/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Há não muito tempo atrás, escrever testes automatizados era coisa para poucos. Nem tanto por obstáculos técnicos, mas porque, na verdade, ninguém se importava muito com isso.</p>
<p>A boa notícia é que a importância dos testes automatizados vem aumentando com o tempo e hoje, felizmente, já não é mais necessário &#8220;vender&#8221; a idéia. O aumento absurdo de ferramentas destinadas a facilitar a aplicação desta prática é uma prova disso.</p>
<p>Falando em ferramentas, neste texto mostrarei o <a href="http://jshamcrest.destaquenet.com/">JsHamcrest</a>, um projeto <em>open source</em> desenvolvido pela <a href="http://www.destaquenet.com/">Destaquenet</a> cujo objetivo é fornecer uma versão incrementada, em JavaScript, da biblioteca <a href="http://code.google.com/p/hamcrest/">Hamcrest</a>. Para quem não conhece, Hamcrest é  uma <a href="http://code.google.com/p/hamcrest/wiki/Tutorial">biblioteca de <em>matchers</em></a> que permite que regras sejam definidas declarativamente para uso em outros <em>frameworks</em> e bibliotecas.</p>
<p><span id="more-584"></span></p>
<h3>Para apreciar é preciso antes viver sem</h3>
<p>Para dar uma idéia do quão útil JsHamcrest pode ser, segue abaixo um exemplo de suite de testes criado com <a href="http://docs.jquery.com/QUnit">QUnit</a>, ainda sem apoio do JsHamcrest, onde testamos o funcionamento de algumas funcionalidades da classe <a href="https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Global_Objects/Array">Array</a>:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">$<span style="color: #009900;">&#40;</span>document<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">ready</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    test<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;Literal&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #003366; font-weight: bold;">var</span> arr <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
        ok<span style="color: #009900;">&#40;</span>arr <span style="color: #000066; font-weight: bold;">instanceof</span> Array<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        equals<span style="color: #009900;">&#40;</span>arr.<span style="color: #660066;">length</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    test<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;Reverse&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #003366; font-weight: bold;">var</span> arr <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">2</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">3</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">4</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">5</span><span style="color: #009900;">&#93;</span>.<span style="color: #660066;">reverse</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        equals<span style="color: #009900;">&#40;</span>arr.<span style="color: #660066;">length</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">5</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #006600; font-style: italic;">// This assertion fails</span>
        <span style="color: #006600; font-style: italic;">// equals(arr, [5, 4, 3, 2, 1]);</span>
&nbsp;
        <span style="color: #006600; font-style: italic;">// These assertions work, but in an ideal world you shouldn't do such a thing</span>
        <span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> i <span style="color: #339933;">=</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">,</span> j <span style="color: #339933;">=</span> <span style="color: #CC0000;">5</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> arr.<span style="color: #660066;">length</span><span style="color: #339933;">;</span> i<span style="color: #339933;">++,</span> j<span style="color: #339933;">--</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            equals<span style="color: #009900;">&#40;</span>arr<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> j<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    test<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;Slice&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #003366; font-weight: bold;">var</span> arr <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">2</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">3</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">4</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">5</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">6</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">7</span><span style="color: #009900;">&#93;</span>.<span style="color: #660066;">slice</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">2</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">5</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        equals<span style="color: #009900;">&#40;</span>arr.<span style="color: #660066;">length</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">3</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #006600; font-style: italic;">// This assertion fails</span>
        <span style="color: #006600; font-style: italic;">// equals(arr, [3, 4, 5]);</span>
&nbsp;
        <span style="color: #006600; font-style: italic;">// These assertions work, but in an ideal world you shouldn't do such a thing</span>
        <span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> i <span style="color: #339933;">=</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> arr.<span style="color: #660066;">length</span><span style="color: #339933;">;</span> i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            equals<span style="color: #009900;">&#40;</span>arr<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> i<span style="color: #339933;">+</span><span style="color: #CC0000;">3</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
&nbsp;
        <span style="color: #006600; font-style: italic;">// Another example of complex assertion</span>
        <span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> i <span style="color: #339933;">=</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> arr.<span style="color: #660066;">length</span><span style="color: #339933;">;</span> i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            ok<span style="color: #009900;">&#40;</span>arr<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span> <span style="color: #339933;">&gt;=</span> <span style="color: #CC0000;">3</span> <span style="color: #339933;">&amp;&amp;</span> arr<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span> <span style="color: #339933;">&lt;=</span> <span style="color: #CC0000;">5</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>O código, mesmo sendo feio e confuso, funciona:</p>
<div id="attachment_591" class="wp-caption aligncenter" style="width: 315px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2009/07/test_suite_qunit1.png"><img class="size-full wp-image-591 " title="Primeira versão da suite de testes" src="http://weblog.destaquenet.com/wp-content/uploads/2009/07/test_suite_qunit1.png" alt="Primeira versão da suite de testes" width="305" height="314" /></a><p class="wp-caption-text">Primeira versão da suite de testes</p></div>
<p>O código desta suite de testes está <a href="http://weblog.destaquenet.com/wp-content/uploads/2009/07/qunit_testsuite.zip">disponível para download</a>.</p>
<h3>(Muitas) Limitações</h3>
<p>O primeiro teste, que verifica o funcionamento do literal <code>[]</code>, foi muito simples de implementar até porque não há praticamente nada a ser testado. Mas não fique feliz; no mundo real, as chances de seus testes serem assim tão simples são muito baixas.</p>
<p>Isso começa a ficar evidente à partir do segundo teste, onde é preciso apelar para o bom (?) e velho <code>for</code> para conferir o conteúdo do array, uma vez que QUnit não os suporta em comparações de igualdade.</p>
<p>Obviamente a mesma coisa também acontece no terceiro teste. E para mostrar que a a sitiuação só tende a piorar, ainda no terceiro teste temos um outro exemplo de asserção (tão feio quanto) que verifica  se todos os elementos do array estão num determinado intervalo.</p>
<p>Infelizmente, a &#8220;feiura&#8221; não é a única coisa que incomoda nesse código. Para ilustrar, suponha que o terceiro teste estivesse quebrado:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">test<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;Slice&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #003366; font-weight: bold;">var</span> arr <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">2</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">3</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">4</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">5</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">6</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">7</span><span style="color: #009900;">&#93;</span>.<span style="color: #660066;">slice</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">2</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">5</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    equals<span style="color: #009900;">&#40;</span>arr.<span style="color: #660066;">length</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">3</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #006600; font-style: italic;">// ...</span>
&nbsp;
    <span style="color: #006600; font-style: italic;">// Another example of complex assertion</span>
    <span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> i <span style="color: #339933;">=</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;=</span> arr.<span style="color: #660066;">length</span><span style="color: #339933;">;</span> i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        ok<span style="color: #009900;">&#40;</span>arr<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span> <span style="color: #339933;">&gt;=</span> <span style="color: #CC0000;">3</span> <span style="color: #339933;">&amp;&amp;</span> arr<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span> <span style="color: #339933;">&lt;=</span> <span style="color: #CC0000;">5</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Como esperado, ao rodar os testes, o relatório mostra a ocorrência de um erro. O problema é que esse relatório faz um <em>péssimo</em> trabalho ao tentar mostrar o que de fato falhou:</p>
<div id="attachment_592" class="wp-caption aligncenter" style="width: 317px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2009/07/test_suite_qunit_error1.png"><img class="size-full wp-image-592 " title="Relatório de erro não muito amigável" src="http://weblog.destaquenet.com/wp-content/uploads/2009/07/test_suite_qunit_error1.png" alt="Relatório de erro não muito amigável" width="307" height="248" /></a><p class="wp-caption-text">Relatório de erro não muito amigável</p></div>
<p>Uma forma de se amenizar este problema é passar um texto descritivo aos métodos <code>ok()</code> e <code>equals()</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">ok<span style="color: #009900;">&#40;</span>num1 <span style="color: #339933;">&gt;=</span> <span style="color: #CC0000;">3</span> <span style="color: #339933;">&amp;&amp;</span> num1 <span style="color: #339933;">&lt;=</span> <span style="color: #CC0000;">5</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;Expected num1 between 3 and 5&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
equals<span style="color: #009900;">&#40;</span>num2<span style="color: #339933;">,</span> <span style="color: #CC0000;">10</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;Checking value of num2&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>O problema é que, ao fazer isso, passa a ser necessário um certo cuidado para manter os textos descritivos em sincronia com o código das asserções.</p>
<h4>Se QUnit é assim tão ruim&#8230;</h4>
<p>&#8230;por que não o trocar por outra coisa?</p>
<p>Apesar de existirem várias alternativas ao QUnit, nenhuma delas parece ser capaz de resolver problemas como os mostrados aqui. Portanto, trocar de <em>framework</em>, por enquanto, não é a solução.</p>
<p>Mas nem tudo está perdido.</p>
<h3>Viva melhor  com JsHamcrest</h3>
<p>O código mostrado anteriormente pode ser facilmente adaptado para usar JsHamcrest:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #006600; font-style: italic;">// Integrates JsHamcrest with QUnit</span>
JsHamcrest.<span style="color: #660066;">Integration</span>.<span style="color: #660066;">QUnit</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
$<span style="color: #009900;">&#40;</span>document<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">ready</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    test<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;Literal&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #003366; font-weight: bold;">var</span> arr <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
        assertThat<span style="color: #009900;">&#40;</span>arr<span style="color: #339933;">,</span> <span style="color: #000066; font-weight: bold;">instanceOf</span><span style="color: #009900;">&#40;</span>Array<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        assertThat<span style="color: #009900;">&#40;</span>arr<span style="color: #339933;">,</span> empty<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    test<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;Reverse&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #003366; font-weight: bold;">var</span> arr <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">2</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">3</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">4</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">5</span><span style="color: #009900;">&#93;</span>.<span style="color: #660066;">reverse</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        assertThat<span style="color: #009900;">&#40;</span>arr<span style="color: #339933;">,</span> hasSize<span style="color: #009900;">&#40;</span><span style="color: #CC0000;">5</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        assertThat<span style="color: #009900;">&#40;</span>arr<span style="color: #339933;">,</span> equalTo<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#91;</span><span style="color: #CC0000;">5</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">4</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">3</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">2</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    test<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;Slice&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #003366; font-weight: bold;">var</span> arr <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">2</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">3</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">4</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">5</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">6</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">7</span><span style="color: #009900;">&#93;</span>.<span style="color: #660066;">slice</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">2</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">5</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        assertThat<span style="color: #009900;">&#40;</span>arr<span style="color: #339933;">,</span> hasSize<span style="color: #009900;">&#40;</span><span style="color: #CC0000;">3</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        assertThat<span style="color: #009900;">&#40;</span>arr<span style="color: #339933;">,</span> equalTo<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#91;</span><span style="color: #CC0000;">3</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">4</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">5</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        assertThat<span style="color: #009900;">&#40;</span>arr<span style="color: #339933;">,</span> everyItem<span style="color: #009900;">&#40;</span>between<span style="color: #009900;">&#40;</span><span style="color: #CC0000;">3</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">and</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">5</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Gostou? <img src='http://weblog.destaquenet.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>A primeira coisa que salta aos olhos é a simplicidade do código. Basta uma olhada rápida para saber exatamente o que ele faz. Note que mesmo asserções mais complexas como as mostradas nos dois últimos testes são implementadas com facilidade.</p>
<p>O resultado:</p>
<div id="attachment_588" class="wp-caption aligncenter" style="width: 315px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2009/07/test_suite_qunit_jshamcrest.png"><img class="size-full wp-image-588  " title="Relatório com dados detalhados das asserções" src="http://weblog.destaquenet.com/wp-content/uploads/2009/07/test_suite_qunit_jshamcrest.png" alt="Testes com dados detalhados das asserções" width="305" height="239" /></a><p class="wp-caption-text">Relatório com dados detalhados das asserções</p></div>
<p>O código desta suite de testes está <a href="http://weblog.destaquenet.com/wp-content/uploads/2009/07/qunit_jshamcrest_testsuite.zip">disponível para download</a>.</p>
<p>E não é só isso. Ao mesmo tempo em que temos um vocabulário <em>riquíssimo</em> de asserções, JsHamcrest também fornece informações detalhadas sobre as mesmas, numa linguagem fácil de entender. E isso tudo isso sem <em>nenhum</em> esforço!</p>
<p>Mais informações sobre a  API podem ser encontradas no pacote de documentação do projeto, também <a href="http://github.com/danielfm/jshamcrest/downloads">disponível para download</a>.</p>
<p>Mas, e quanto ao problema do relatório de erro? Vamos quebrar uma asserção e  ver o que acontece:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">test<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;Slice&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #003366; font-weight: bold;">var</span> arr <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">2</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">3</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">4</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">5</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">6</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">7</span><span style="color: #009900;">&#93;</span>.<span style="color: #660066;">slice</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">2</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">5</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    assertThat<span style="color: #009900;">&#40;</span>arr<span style="color: #339933;">,</span> hasSize<span style="color: #009900;">&#40;</span><span style="color: #CC0000;">3</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    assertThat<span style="color: #009900;">&#40;</span>arr<span style="color: #339933;">,</span> equalTo<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#91;</span><span style="color: #CC0000;">3</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">4</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">5</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    assertThat<span style="color: #009900;">&#40;</span>arr<span style="color: #339933;">,</span> everyItem<span style="color: #009900;">&#40;</span>between<span style="color: #009900;">&#40;</span><span style="color: #CC0000;">3</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">and</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">4</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>O resultado:</p>
<div id="attachment_590" class="wp-caption aligncenter" style="width: 319px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2009/07/test_suite_qunit_jshamcrest_error.png"><img class="size-full wp-image-590 " title="Mensagem de erro amigável" src="http://weblog.destaquenet.com/wp-content/uploads/2009/07/test_suite_qunit_jshamcrest_error.png" alt="Mensagem de erro amigável" width="309" height="202" /></a><p class="wp-caption-text">Mensagem de erro amigável</p></div>
<p>Muito melhor! Basta olhar a mensagem de erro para descobrir o que está errado.</p>
<h3>Posso usar JsHamcrest com outro <em>framework</em>?</h3>
<p>Atualmente, JsHamcrest integra com cinco <em>frameworks</em>: <a href="http://code.google.com/p/js-test-driver/">JsTestDriver</a>, <a href="http://jsunittest.com/">JsUnitTest</a>, <a href="http://jsunity.com/">jsUnity</a>, <a href="http://developer.yahoo.com/yui/yuitest/">YUITest</a> e QUnit.</p>
<p>Outra coisa legal é que integração feita pelo JsHamcrest leva em conta as convenções definidas pelo <em>framework</em> escolhido. Veja, por exemplo, como ficaria o código se tivéssemos optado pelo YUITest em vez do QUnit:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #006600; font-style: italic;">// Integrates JsHamcrest and YUITest</span>
JsHamcrest.<span style="color: #660066;">Integration</span>.<span style="color: #660066;">YUITest</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
YAHOO.<span style="color: #003366; font-weight: bold;">namespace</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;array&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
YAHOO.<span style="color: #660066;">array</span>.<span style="color: #660066;">TestCase</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">new</span> YAHOO.<span style="color: #660066;">tool</span>.<span style="color: #660066;">TestCase</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span>
    <span style="color: #000066;">name</span> <span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Array tests&quot;</span><span style="color: #339933;">,</span>
&nbsp;
    testLiteral<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #003366; font-weight: bold;">var</span> arr <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
        Assert.<span style="color: #660066;">that</span><span style="color: #009900;">&#40;</span>arr<span style="color: #339933;">,</span> <span style="color: #000066; font-weight: bold;">instanceOf</span><span style="color: #009900;">&#40;</span>Array<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        Assert.<span style="color: #660066;">that</span><span style="color: #009900;">&#40;</span>arr<span style="color: #339933;">,</span> empty<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
&nbsp;
    testReverse<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #003366; font-weight: bold;">var</span> arr <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">2</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">3</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">4</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">5</span><span style="color: #009900;">&#93;</span>.<span style="color: #660066;">reverse</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        Assert.<span style="color: #660066;">that</span><span style="color: #009900;">&#40;</span>arr<span style="color: #339933;">,</span> hasSize<span style="color: #009900;">&#40;</span><span style="color: #CC0000;">5</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        Assert.<span style="color: #660066;">that</span><span style="color: #009900;">&#40;</span>arr<span style="color: #339933;">,</span> equalTo<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#91;</span><span style="color: #CC0000;">5</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">4</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">3</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">2</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
&nbsp;
    testSlice<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #003366; font-weight: bold;">var</span> arr <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">2</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">3</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">4</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">5</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">6</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">7</span><span style="color: #009900;">&#93;</span>.<span style="color: #660066;">slice</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">2</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">5</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        Assert.<span style="color: #660066;">that</span><span style="color: #009900;">&#40;</span>arr<span style="color: #339933;">,</span> hasSize<span style="color: #009900;">&#40;</span><span style="color: #CC0000;">3</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        Assert.<span style="color: #660066;">that</span><span style="color: #009900;">&#40;</span>arr<span style="color: #339933;">,</span> equalTo<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#91;</span><span style="color: #CC0000;">3</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">4</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">5</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        Assert.<span style="color: #660066;">that</span><span style="color: #009900;">&#40;</span>arr<span style="color: #339933;">,</span> everyItem<span style="color: #009900;">&#40;</span>between<span style="color: #009900;">&#40;</span><span style="color: #CC0000;">3</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">and</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">5</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<h4>Mas meu <em>framework</em> predileto não está nessa lista&#8230;</h4>
<p>JsHamcrest pode vir a suportar outros <em>frameworks</em> no futuro. Se seu <em>framework</em> predileto não está na lista dos atualmente suportados, entre em contato conosco.</p>
<h3>E aí, o que achou?</h3>
<p>Gostou? Odiou? Tem sugestões de melhorias? Gostaríamos muito de ouvir sua opinião!</p>
]]></content:encoded>
			<wfw:commentRss>http://weblog.destaquenet.com/2009/07/13/jshamcrest-um-alivio-a-dor-de-se-testar-codigo-javascript/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Fabric + VirtualEnv: uma combinação explosiva (no bom sentido)</title>
		<link>http://weblog.destaquenet.com/2009/07/01/fabric-virtualenv-uma-combinacao-explosiva-no-bom-sentido/</link>
		<comments>http://weblog.destaquenet.com/2009/07/01/fabric-virtualenv-uma-combinacao-explosiva-no-bom-sentido/#comments</comments>
		<pubDate>Wed, 01 Jul 2009 04:20:01 +0000</pubDate>
		<dc:creator>Daniel Martins</dc:creator>
				<category><![CDATA[Português]]></category>
		<category><![CDATA[Programação]]></category>
		<category><![CDATA[Tutoriais]]></category>
		<category><![CDATA[automatização]]></category>
		<category><![CDATA[debian]]></category>
		<category><![CDATA[django-flash]]></category>
		<category><![CDATA[fabric]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[pypi]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[setuptools]]></category>
		<category><![CDATA[teste]]></category>
		<category><![CDATA[ubuntu]]></category>
		<category><![CDATA[virtualenv]]></category>

		<guid isPermaLink="false">http://weblog.destaquenet.com/?p=554</guid>
		<description><![CDATA[Escreveu uma super-hiper-biblioteca ou aplicação em Python mas quer se certificar de que ela funciona em diferentes versões do interpretador? Embora isso possa ser resolvido através da execução manual dos testes com os vários interpretadores, isso é chato e improdutivo. &#8230; <a href="http://weblog.destaquenet.com/2009/07/01/fabric-virtualenv-uma-combinacao-explosiva-no-bom-sentido/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Escreveu uma super-hiper-biblioteca ou aplicação em <a href="http://python.org">Python</a> mas quer se certificar de que ela funciona em diferentes versões do interpretador? Embora isso possa ser resolvido através da execução <em>manual</em> dos testes com os vários interpretadores, isso é chato e improdutivo. Além do mais, cada versão do Python pode ter diferentes bibliotecas instaladas, o que pode acabar influenciando no resultado dos testes.</p>
<p>Temos portanto dois problemas a serem resolvidos. O primeiro problema, relacionado a automatização de tarefas repetitivas, pode ser facilmente solucionado com <a href="http://docs.fabfile.org/">Fabric</a>, uma ferramenta muito útil para criação de scripts de build e deployment de aplicações. Já escrevemos <a href="http://weblog.destaquenet.com/2008/10/05/deployment-de-aplicacoes-python-com-fabric/">um texto introdutório</a> sobre a mesma, não deixe de conferir.</p>
<p>O segundo problema, entretanto, é um pouco mais complicado de se resolver, mas não é nenhum bicho de sete cabeças. Com <a href="http://pypi.python.org/pypi/virtualenv/">VirtualEnv</a>, é possível criar ambientes Python isolados com o objetivo de testar e executar aplicações em uma espécie de sandbox onde temos total controle sobre as bibliotecas ali instaladas.</p>
<p><span id="more-554"></span></p>
<h3>Instalando as diferentes versões do Python</h3>
<p>O primeiro passo é instalar as versões do Python a serem usadas nos testes. Rode o comando abaixo para instalar os diferentes interpretadores, supondo que você utilize <a href="http://www.debian.org/">Debian</a> e sua aplicação precise funcionar nas versões 2.4, 2.5 e 2.6 do Python:</p>
<pre>$ sudo apt-get install python2.4 python2.4-dev \
    python2.5 python2.5-dev \
    python2.6 python2.6-dev</pre>
<p>A versão atual do Ubuntu já inclui o Python 2.6 por padrão. Veja também que aproveitamos para instalar os arquivos de desenvolvimento para cada versão, pois eventualmente precisamos deles para compilar bibliotecas com extensões escritas em C.</p>
<h3>Instalando Fabric e VirtualEnv</h3>
<p>Da mesma forma:</p>
<pre>$ sudo apt-get install python-setuptools</pre>
<p>Após a instalação do <a href="http://pypi.python.org/pypi/setuptools/">SetupTools</a>, execute o seguinte comando para instalar o Fabric e o VirtualEnv:</p>
<pre>$ sudo easy_install Fabric virtualenv</pre>
<h3>Configurando ambientes isolados para sua aplicação</h3>
<p>O próximo passo é criar ambientes de execução isolados para sua aplicação, sendo que cada ambiente deve usar uma versão diferente do interpretador do Python. Para fazer isso, execute os comandos abaixo, substituindo o <code>APP</code> pelo nome da sua aplicação ou biblioteca:</p>
<pre>$ mkdir ~/.virtualenvs
$ cd ~/.virtualenvs
$ virtualenv --python=/usr/bin/python2.6 --no-site-packages APP-py2.6
$ virtualenv --python=/usr/bin/python2.5 --no-site-packages APP-py2.5
$ virtualenv --python=/usr/bin/python2.4 --no-site-packages APP-py2.4</pre>
<p>Primeiramente criamos o diretório <code>~/.virtualenvs</code>, que é por convenção o diretório padrão para armazenamento dos ambientes. Em seguida, criamos três ambientes para nossa aplicação <code>APP</code>. A flag <code>--no-site-packages</code> é <em>opcional</em> e indica que as bibliotecas instaladas no diretório <code>site-packages</code> do Python em questão não devem ser visíveis ao ambiente sendo criado.</p>
<p>Finalmente, não esqueça de instalar, em cada um dos ambientes, as dependências exigidas pela sua aplicação:</p>
<pre>$ source ~/.virtualenvs/APP-py2.6/bin/activate
(APP-py2.6) $ easy_install biblioteca1 biblioteca2 ... bibliotecaN
(APP-py2.6) $ source ~/.virtualenvs/APP-py2.5/bin/activate
(APP-py2.5) $ easy_install biblioteca1 biblioteca2 ... bibliotecaN
(APP-py2.5) $ source ~/.virtualenvs/APP-py2.4/bin/activate
(APP-py2.4) $ easy_install biblioteca1 biblioteca2 ... bibliotecaN</pre>
<p>Supondo que sua aplicação utilize o SetupTools para a configuração dos metadados do projeto (através do script <code>setup.py</code>), os comandos abaixo devem indicar se a aplicação funciona nos ambientes que criamos:</p>
<pre>$ source ~/.virtualenvs/APP-py2.6/bin/activate
(APP-py2.6) $ python setup.py test
...
(APP-py2.6) $ source ~/.virtualenvs/APP-py2.5/bin/activate
(APP-py2.5) $ python setup.py test
...
(APP-py2.5) $ source ~/.virtualenvs/APP-py2.4/bin/activate
(APP-py2.4) $ python setup.py test
...</pre>
<h3>Automatizando!</h3>
<p>Se tudo funcionou até aqui, estamos prontos para criar um script que nos permita rodar os testes de forma automática, nos diferentes ambientes.</p>
<p>Supondo que sua aplicação utilize o SetupTools para a configuração dos metadados do projeto, o exemplo abaixo resolve o problema:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># -*- coding: utf-8 -*-</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Environment info</span>
config.<span style="color: black;">project</span> = <span style="color: #483d8b;">'APP'</span>
config.<span style="color: black;">virtualenv_dir</span> = <span style="color: #483d8b;">'~/.virtualenvs'</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Supported Python versions</span>
config.<span style="color: black;">versions</span> = <span style="color: black;">&#40;</span><span style="color: #483d8b;">'2.4'</span>, <span style="color: #483d8b;">'2.5'</span>, <span style="color: #483d8b;">'2.6'</span>,<span style="color: black;">&#41;</span>
config.<span style="color: black;">default_version</span> = <span style="color: #483d8b;">'2.6'</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> setup<span style="color: black;">&#40;</span>command, version=config.<span style="color: black;">default_version</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;Executes the given setup command with a virtual Python installation.
    &quot;&quot;&quot;</span>
    local<span style="color: black;">&#40;</span><span style="color: #483d8b;">'%s/%s-py%s/bin/python setup.py %s'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>config.<span style="color: black;">virtualenv_dir</span>, config.<span style="color: black;">project</span>, version, command<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #dc143c;">test</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;Runs all tests in different Python versions.
    &quot;&quot;&quot;</span>
    <span style="color: #ff7700;font-weight:bold;">for</span> version <span style="color: #ff7700;font-weight:bold;">in</span> config.<span style="color: black;">versions</span>:
        setup<span style="color: black;">&#40;</span><span style="color: #483d8b;">'test'</span>, version<span style="color: black;">&#41;</span></pre></div></div>

<p>Agora é só alegria:</p>
<pre>$ fab test
Fabric v. 0.1.1.
Running test...
[localhost] run: ~/.virtualenvs/APP-py2.4/bin/python setup.py test
...
[localhost] run: ~/.virtualenvs/APP-py2.5/bin/python setup.py test
...
[localhost] run: ~/.virtualenvs/APP-py2.6/bin/python setup.py test
...</pre>
<p>Devo lembrar que o script mostrado é só um exemplo. Você pode (e <strong>deve</strong>) modificá-lo para que este atenda às suas necessidades.</p>
<h3>(Bônus!) Distribuindo sua aplicação para diferentes versões do Python</h3>
<p>Com mais algumas linhas de código, podemos criar tasks que nos permitam gerar arquivos para distribuição da aplicação para diferentes versões do Python:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> dist_src<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;Create source archive.
    &quot;&quot;&quot;</span>
    setup<span style="color: black;">&#40;</span><span style="color: #483d8b;">'sdist'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> dist_eggs<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;Create binary archives, one for each Python version.
    &quot;&quot;&quot;</span>
    <span style="color: #ff7700;font-weight:bold;">for</span> version <span style="color: #ff7700;font-weight:bold;">in</span> config.<span style="color: black;">versions</span>:
        setup<span style="color: black;">&#40;</span><span style="color: #483d8b;">'bdist_egg'</span>, version<span style="color: black;">&#41;</span></pre></div></div>

<h3>(Bônus!) Automatizando geração de documentação e upload para o PyPI</h3>
<p>Ainda acha pouco? <a href="http://github.com/danielfm/django-flash/blob/master/fabfile.py">Este outro exemplo</a> de script vai além e mostra, numa aplicação real, como automatizar o registro e upload dos pacotes para o <a href="http://pypi.python.org/pypi/">PyPI</a>, atualizar site de documentação, entre outras coisas.</p>
]]></content:encoded>
			<wfw:commentRss>http://weblog.destaquenet.com/2009/07/01/fabric-virtualenv-uma-combinacao-explosiva-no-bom-sentido/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>VPN PPTP no Ubuntu Intrepid</title>
		<link>http://weblog.destaquenet.com/2008/12/02/vpn-pptp-no-ubuntu-intrepid/</link>
		<comments>http://weblog.destaquenet.com/2008/12/02/vpn-pptp-no-ubuntu-intrepid/#comments</comments>
		<pubDate>Wed, 03 Dec 2008 02:51:35 +0000</pubDate>
		<dc:creator>Daniel Martins</dc:creator>
				<category><![CDATA[Português]]></category>
		<category><![CDATA[Tutoriais]]></category>
		<category><![CDATA[conectividade]]></category>
		<category><![CDATA[configuração]]></category>
		<category><![CDATA[dicas]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[network manager]]></category>
		<category><![CDATA[pptp]]></category>
		<category><![CDATA[rede]]></category>
		<category><![CDATA[ubuntu]]></category>
		<category><![CDATA[vpn]]></category>

		<guid isPermaLink="false">http://weblog.destaquenet.com/?p=304</guid>
		<description><![CDATA[Um dia após o lançamento do Intrepid (versão 8.10) do Ubuntu Linux, eu já tinha feito o download e a instalação na minha máquina de trabalho, um notebook Dell. Vou poupar elogios, até porque eu utilizo o Ubuntu diariamente desde &#8230; <a href="http://weblog.destaquenet.com/2008/12/02/vpn-pptp-no-ubuntu-intrepid/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Um dia após o lançamento do Intrepid (versão 8.10) do <a href="http://www.ubuntu.com/">Ubuntu Linux</a>, eu já tinha feito o <em>download</em> e a instalação na minha máquina de trabalho, um notebook Dell. Vou poupar elogios, até porque eu utilizo o Ubuntu diariamente desde o lançamento da release Dapper Drake (versão 6.06), de Julho de 2006. De lá para cá, muito trabalho vem sendo feito para tornar o Ubuntu o sistema ideal para uso em desktops e laptops.</p>
<p>Um dos aspectos que se encontram em constante evolução é a parte de conectividade. O <a href="http://projects.gnome.org/NetworkManager/">Network Manager</a>, gerenciador de conexões utilizado nas versões mais recentes do Ubuntu, torna simples a tarefa de se conectar com praticamente qualquer tipo de rede, inclusive com as recém chegadas redes 3G.</p>
<p>Apesar de facilitar a vida na maioria dos casos, o Network Manager presente na última versão do Ubuntu parece não funcionar do jeito que deveria, principalmente quando tentamos conectar numa VPN PPTP (Point-to-Point Tunneling Protocol). Na versão anterior do Ubuntu, eu conseguia conectar em VPNs PPTP sem problemas, coisa que deixou de acontecer após a instalação da última versão do Ubuntu.</p>
<p>A boa notícia é que, depois de perder algumas horas pesquisando, eu consegui resolver o meu problema. E é isso que mostrarei a seguir! <span id="more-304"></span></p>
<h3>Atualizando o Network Manager</h3>
<p>A primeira coisa que fiz foi tentar substituir a versão pré-instalada do Network Manager pela <a href="http://launchpad.net/network-manager">versão distribuída</a> pelos próprios desenvolvedores.</p>
<p>Para isso, abra o Synaptic e selecione o menu <em>Settings &#8211; Repositories</em>. Em seguida, selecione a aba <em>Third-Party Software</em> e clique no botão <em>Add</em>. Finalmente, cole a linha abaixo e confirme:</p>
<pre>deb http://ppa.launchpad.net/network-manager/ubuntu intrepid main</pre>
<p>Feche a tela e pressione CTRL+R para baixar as informações atualizadas dos repositórios. Após o término, pressione CTRL+G para iniciar o processo de atualização dos pacotes. Quando a instalação terminar, o Ubuntu irá pedir que você faça o reboot. Obedeça. <img src='http://weblog.destaquenet.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<h3>Configurando a VPN</h3>
<p>Após o reboot, o sistema já deve estar funcionando com a nova versão do Network Manager. Clique no Applet do Network Manager e selecione o menu <em>VPN Connections &#8211; Configure VPN</em>. Aqui, basta configurar de acordo com as instruções que você deve ter recebido do pessoal responsável pela parte de redes da sua empresa.</p>
<p>Para não terminar o post aqui, eu vou mostrar como eu fiz para configurar a conexão VPN que estou utilizando atualmente. É obvio que cada empresa configura sua VPN de um jeito diferente, por isso o que segue abaixo é apenas um exemplo de configuração.</p>
<h4>Informações básicas</h4>
<p>Na primeira tela você deve informar os dados para conexão com a VPN, como IP do servidor da VPN, usuário e senha:</p>
<div id="attachment_308" class="wp-caption aligncenter" style="width: 230px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2008/12/vpn01.png"><img class="size-medium wp-image-308" title="Informações básicas da VPN" src="http://weblog.destaquenet.com/wp-content/uploads/2008/12/vpn01-220x300.png" alt="Informações básicas" width="220" height="300" /></a><p class="wp-caption-text">Informações básicas</p></div>
<p>Clique no botão <em>Advanced</em> para configurar em detalhes como deverá ser a comunicação entre seu computador e a VPN:</p>
<div id="attachment_309" class="wp-caption aligncenter" style="width: 239px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2008/12/vpn02.png"><img class="size-medium wp-image-309" title="Opções avançadas" src="http://weblog.destaquenet.com/wp-content/uploads/2008/12/vpn02-229x300.png" alt="Opções avançadas" width="229" height="300" /></a><p class="wp-caption-text">Opções avançadas</p></div>
<p>No meu caso, o servidor da VPN foi configurado para fazer autenticação via CHAP; marque ou desmarque as opções disponíveis na tela, se necessário.</p>
<h4>Configurando as rotas</h4>
<p>Prosseguindo, na aba <em>IPv4 Settings</em> você poderá configurar o seu IP na VPN. No meu caso, o IP local, juntamente com o servidor DNS e Gateway, são fornecidos automaticamente pelo servidor. Por isso eu optei por manter a opção <em>Automatic (VPN)</em> no campo <em>Method</em>.</p>
<p>Neste ponto você já deve ter a VPN funcionando, mas com um pequeno inconveniente: pelo menos aqui, a VPN passou a ser acessível através da rota padrão (IP 0.0.0.0). Isso significa que <strong>todo</strong> o tráfego é direcionado para a VPN!</p>
<p>Para solucionar esta questão, é preciso configurar uma rota através da qual a VPN possa ser acessada, mantendo inalterada a rota padrão. Para isso, basta clicar no botão <em>Routes&#8230;</em> e configurar a(s) rota(s):</p>
<div id="attachment_316" class="wp-caption aligncenter" style="width: 310px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2008/12/vpn03.png"><img class="size-medium wp-image-316" title="Declarando rotas" src="http://weblog.destaquenet.com/wp-content/uploads/2008/12/vpn03-300x166.png" alt="Declarando rotas" width="300" height="166" /></a><p class="wp-caption-text">Declarando rotas</p></div>
<p>Aqui, eu substituí as rotas obtidas automaticamente pelas rotas informadas na tabela. No meu caso, a faixa de IP da VPN é 192.168.0.X, por isso o <em>Prefix</em> foi configurado como 24 (<a href="http://linux-ip.net/html/routing-intro.html">aprenda aqui</a> o que esse número significa). O campo <em>Gateway</em> foi configurado para o &#8220;IP remoto virtual&#8221; da VPN, fazendo com que os pacotes destinados a IPs 192.168.0.X sejam redirecionados para a VPN. O campo <em>Metric</em> foi <a href="http://linux.about.com/od/lna_guide/a/gdelna23t04.htm">deixado como zero</a>.</p>
<h3>Feito!</h3>
<p>Isso deve bastar. Tente conectar com a VPN:</p>
<div id="attachment_313" class="wp-caption aligncenter" style="width: 310px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2008/12/vpn04.png"><img class="size-medium wp-image-313" title="Conectando na VPN" src="http://weblog.destaquenet.com/wp-content/uploads/2008/12/vpn04-300x150.png" alt="Conectando na VPN" width="300" height="150" /></a><p class="wp-caption-text">Conectando na VPN</p></div>
<p>Não conectou? Confira os dados de conexão e modifique os parâmetros avançados de conexão (métodos de autentiação, encriptação, etc). Tente encontrar o motivo nos logs <code>/var/log/messages</code> e <code>/var/log/syslog</code>. Conectou? Ótimo, agora faça o seguinte teste:</p>
<ol>
<li>Dispare um ping contra algum computador da VPN;</li>
<li>Dispare um ping contra algum computador da sua rede local;</li>
<li>Dispare um ping contra algum computador da Internet (ex: google.com);</li>
</ol>
<p>O teste falhou? Com certeza tem algo errado com a(s) sua(s) rota(s). Ainda conectado na VPN, utilize os comandos <code>ip route</code> e/ou <code>route -n</code> para ver como ficaram as rotas; faça os ajustes necessários, reze e tente novamente. O teste foi um sucesso? Parabéns, você conseguiu! <img src='http://weblog.destaquenet.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><strong>Update</strong>: Aos usuários do Fedora 10, o procedimento de configuração é praticamente o mesmo. O que muda é a configuração das rotas:</p>
<p style="text-align: center;">
<div id="attachment_343" class="wp-caption aligncenter" style="width: 310px"><img class="size-medium wp-image-343" title="rotas_fedora10" src="http://weblog.destaquenet.com/wp-content/uploads/2008/12/rotas_fedora10-300x182.png" alt="Declarando as rotas (Fedora 10)" width="300" height="182" /><p class="wp-caption-text">Declarando rotas (Fedora 10)</p></div>
]]></content:encoded>
			<wfw:commentRss>http://weblog.destaquenet.com/2008/12/02/vpn-pptp-no-ubuntu-intrepid/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Integração Contínua de aplicações Python com Hudson</title>
		<link>http://weblog.destaquenet.com/2008/10/27/integracao-continua-de-aplicacoes-python-com-hudson/</link>
		<comments>http://weblog.destaquenet.com/2008/10/27/integracao-continua-de-aplicacoes-python-com-hudson/#comments</comments>
		<pubDate>Mon, 27 Oct 2008 12:00:24 +0000</pubDate>
		<dc:creator>Daniel Martins</dc:creator>
				<category><![CDATA[Português]]></category>
		<category><![CDATA[Programação]]></category>
		<category><![CDATA[Tutoriais]]></category>
		<category><![CDATA[build]]></category>
		<category><![CDATA[configuração]]></category>
		<category><![CDATA[hudson]]></category>
		<category><![CDATA[integração contínua]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[projeto]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[testes]]></category>
		<category><![CDATA[tutorial]]></category>
		<category><![CDATA[unittest]]></category>

		<guid isPermaLink="false">http://weblog.destaquenet.com/?p=166</guid>
		<description><![CDATA[No começo deste mês eu dei dicas sobre como usar o Fabric para automatizar o build e o deployment de aplicações Python. Essa automatização por si só já quebra uma árvore, mas ela possibilita ainda o uso de Integração Contínua, &#8230; <a href="http://weblog.destaquenet.com/2008/10/27/integracao-continua-de-aplicacoes-python-com-hudson/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>No começo deste mês <a href="http://weblog.destaquenet.com/2008/10/05/deployment-de-aplicacoes-python-com-fabric/">eu dei dicas</a> sobre como usar o <a href="http://www.nongnu.org/fab/">Fabric</a> para automatizar o <em>build</em> e o <em>deployment</em> de aplicações <a href="http://python.org/">Python</a>.</p>
<p>Essa automatização por si só já quebra uma árvore, mas ela possibilita ainda o uso de Integração Contínua, uma prática extremamente importante que costuma ajudar muitas equipes a manter seus projetos nos trilhos. Para mais informações sobre Integração Contínua, eu recomendo a leitura <a href="http://martinfowler.com/articles/continuousIntegration.html">deste artigo</a>, até porque este <em>post</em> terá um enfoque mais prático.</p>
<p>Neste texto será mostrado como configurar um projeto Python no <a href="http://hudson.dev.java.net/">Hudson</a>, um servidor de Integração Contínua muito simples de configurar e utilizar. O sistema de controle de versões que eu utilizo aqui é o <a href="http://git.or.cz/">Git</a>, mas usuários de outros sistemas também poderão achar este texto útil.<span id="more-166"></span></p>
<h3>Baixando o Hudson</h3>
<p>Acesse o site do <a href="http://hudson.dev.java.net/">Hudson</a> e baixe o arquivo <code>.war</code> através do link disponível na página principal. Quando o download terminar, basta rodar o comando abaixo para subir o servidor na porta <code>8080</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">java <span style="color: #660033;">-jar</span> hudson.war</pre></div></div>

<div id="attachment_185" class="wp-caption aligncenter" style="width: 310px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2008/10/hudson01.png"><img src="http://weblog.destaquenet.com/wp-content/uploads/2008/10/hudson01-300x187.png" alt="Tela inicial do Hudson" title="Tela inicial do Hudson" width="300" height="187" class="size-medium wp-image-185" /></a><p class="wp-caption-text">Tela inicial do Hudson</p></div>
<p>Perca uns cinco minutos dando uma navegada no Hudson para ter uma idéia melhor do que é possível de ser feito com ele.</p>
<h3>Hudson e plugins</h3>
<p>O Hudson vem com suporte a <a href="http://maven.apache.org/">Maven</a> e <a href="http://ant.apache.org/">Ant</a>, duas das mais populares ferramentas para <em>build</em> de aplicações Java. Mas não se engane: o Hudson pode ser aproveitado em praticamente qualquer projeto, independente da linguagem e dos <em>frameworks</em> utilizados.</p>
<p>As funcionalidades do Hudson podem ser estendidas através de <em>plugins</em>, sendo que neste artigo utilizaremos dois deles: o <em>Git Plugin</em>, necessário para que o Hudson consiga trabalhar com repositórios Git, e o <em>Violations</em>, que consegue interpretar a saída de diferentes verificadores de código (dentre eles o <a href="http://www.logilab.org/857">pylint</a>, um analisador de código Python!) e exibir informações a respeito da qualidade do código-fonte.</p>
<p>Para instalar esses plugins, basta acessar a tela de gerenciamento de plugins, marcar o <em>Git Plugin</em> e o <em>Violations</em>, e confirmar:</p>
<div id="attachment_186" class="wp-caption aligncenter" style="width: 310px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2008/10/hudson02.png"><img src="http://weblog.destaquenet.com/wp-content/uploads/2008/10/hudson02-300x187.png" alt="Instalando os plugins" title="Instalando os plugins" width="300" height="187" class="size-medium wp-image-186" /></a><p class="wp-caption-text">Instalando os plugins</p></div>
<p>Assim que a instalação terminar, reinicie o Hudson.</p>
<h3>Integrando testes escritos com PyUnit ao Hudson</h3>
<p>Apesar de existirem várias opções para criação e execução de testes unitários para Python, o <a href="http://pyunit.sourceforge.net/">PyUnit</a> costuma ser o mais usado pelo fato de já estar incluído na distribuição padrão do Python.</p>
<p>Quem já fuçou no código do PyUnit sabe que ele define <strong>apenas um</strong> <code>TestRunner</code>, o <a href="http://pyunit.sourceforge.net/pyunit.html#RUNNING_INT"><code>TextTestRunner</code></a>. O que este <code>TestRunner</code> basicamente faz é gerar em um fluxo qualquer (geralmente no <code>sys.stderr</code>) uma saída parecida com a seguinte:</p>
<pre>.....
----------------------------------------------------------------------
Ran 5 tests in 0.067s</pre>
<p>Apesar de eu me contentar com essa saída mais simples, bom, ferramentas como o próprio Hudson <strong>não se contentam</strong>; elas preferem algo como o bom e velho XML, que, convenhamos, é muito mais fácil de parsear.</p>
<p>Perdi algumas horas na Internet procurando por um <code>TestRunner</code> que conseguisse gerar arquivos XML no mesmo formato que os gerados pelo Ant e Maven, mas não encontrei nenhuma opção que fosse minimamente confiável. Por isso, eu tomei a liberdade de escrever meu próprio <code>TestRunner</code>: <a href="http://github.com/danielfm/unittest-xml-reporting/tree">XMLTestRunner</a>. O código deste &#8220;projeto&#8221;, disponibilizado no <a href="http://github.com/">Github</a>, contém instruções de uso e scripts de exemplo. <strong>Clonem e forkem à vontade!</strong></p>
<p>Antes de prosseguirmos, baixe o módulo <code>xmlrunner.py</code> do <a href="http://github.com/danielfm/unittest-xml-reporting/tree">site do projeto</a> e o copie em algum lugar dentro do seu <code>PYTHONPATH</code>.</p>
<h3>Integrando um projeto Python no Hudson</h3>
<p>Para não perdermos tempo criando do zero um projeto de exemplo em Python, eu mostrarei como fazer para integrar o próprio <code>XMLTestRunner</code> com o Hudson.</p>
<p>Abra o console administrativo do Hudson e clique no link <em>New Job</em>:</p>
<div id="attachment_214" class="wp-caption aligncenter" style="width: 310px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2008/10/hudson03.png"><img src="http://weblog.destaquenet.com/wp-content/uploads/2008/10/hudson03-300x172.png" alt="Criando um projeto &quot;free-style&quot;" title="Criando um projeto &quot;free-style&quot;" width="300" height="172" class="size-medium wp-image-214" /></a><p class="wp-caption-text">Criando um projeto &quot;free-style&quot;</p></div>
<p>Na próxima tela, precisamos configurar o Job com os dados necessários:</p>
<div id="attachment_215" class="wp-caption aligncenter" style="width: 310px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2008/10/hudson04.png"><img src="http://weblog.destaquenet.com/wp-content/uploads/2008/10/hudson04-300x172.png" alt="Configuração de projeto" title="Configuração de projeto" width="300" height="172" class="size-medium wp-image-215" /></a><p class="wp-caption-text">Configuração de projeto</p></div>
<div id="attachment_216" class="wp-caption aligncenter" style="width: 310px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2008/10/hudson05.png"><img src="http://weblog.destaquenet.com/wp-content/uploads/2008/10/hudson05-300x172.png" alt="Configuração de projeto" title="Configuração de projeto" width="300" height="172" class="size-medium wp-image-216" /></a><p class="wp-caption-text">Configuração de projeto</p></div>
<p>Isso é tudo! Confirme as alterações e clique no link <em>Build now</em>. Aguarde alguns segundos enquanto o projeto é baixado do repositório Git e testado:</p>
<div id="attachment_220" class="wp-caption aligncenter" style="width: 310px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2008/10/hudson06.png"><img src="http://weblog.destaquenet.com/wp-content/uploads/2008/10/hudson06-300x172.png" alt="Exemplos de builds feitos pelo Hudson" title="Exemplos de builds feitos pelo Hudson" width="300" height="172" class="size-medium wp-image-220" /></a><p class="wp-caption-text">Exemplos de builds feitos pelo Hudson</p></div>
<div id="attachment_238" class="wp-caption aligncenter" style="width: 310px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2008/10/hudson07.png"><img src="http://weblog.destaquenet.com/wp-content/uploads/2008/10/hudson07-300x172.png" alt="Relatório de execução de testes" title="Relatório de execução de testes" width="300" height="172" class="size-medium wp-image-238" /></a><p class="wp-caption-text">Relatório de execução de testes</p></div>
<div id="attachment_239" class="wp-caption aligncenter" style="width: 310px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2008/10/hudson08.png"><img src="http://weblog.destaquenet.com/wp-content/uploads/2008/10/hudson08-300x172.png" alt="Análise de código feita pelo pylint" title="Análise de código feita pelo pylint" width="300" height="172" class="size-medium wp-image-239" /></a><p class="wp-caption-text">Análise de código feita pelo pylint</p></div>
<h3>Como disparar o <em>build</em> de forma automática?</h3>
<p>Uma vez que o projeto tenha sido configurado corretamente, basta um clique do mouse para que o Hudson faça todo o trabalho sujo. O problema agora é lembrar de fazer o <em>build</em> sempre que alguém modificar código no repositório.</p>
<p>Felizmente, temos duas opções para nos livrar de mais essa tarefa manual: a primeira seria configurar, nas propriedades do Job, uma expressão Cron que indique de quanto em quanto tempo o <em>build</em> deve ser feito; a segunda alternativa é apenas disparar o <em>build</em> quando alguém modificar código no repositório.</p>
<p>Como acontece com outros sistemas de controle de revisão, o Git possui <em>hooks</em> que nos permite executar ações em determinados momentos. Esses <em>hooks</em> nada mais são do que scripts executáveis localizados no diretório <code>.git/hooks</code>.</p>
<p>Mas enfim, quando disparar o <em>build</em>? Se o repositório Git e o servidor Hudson não são capazes de se comunicar diretamente, talvez a única alternativa seja disparar o <em>build</em> periodicamente. Para isso, você deve configurar um ou mais <em>Build Triggers</em>, na tela de configuração do Job.</p>
<p>Entretanto,  se você mantém o repositório Git e o servidor Hudson na mesma máquina, ou mesmo em máquinas diferentes mas capazes de se comunicar via rede, podemos considerar a utilização dos <em>hooks</em> como ferramenta de integração entre o repositório Git e o Hudson.</p>
<p>Agora a pergunta que não quer calar: <strong>como integrar o Git e o Hudson?</strong> Bem, isso ficará como exercício para o leitor.</p>
<p>Dicas:</p>
<ul>
<li>O Hudson <a href="http://hudson.gotdns.com/wiki/display/HUDSON/Remote+access+API">disponibiliza uma API</a> através da qual se pode agendar <em>builds</em>, alterar as configurações do Job, criar Jobs, entre outras coisas.</li>
<li>Para conhecer os <em>hooks</em> oferecidos pelo Git, consulte a <a href="http://www.kernel.org/pub/software/scm/git/docs/githooks.html">documentação</a>.</li>
</ul>
<h3>Conclusão</h3>
<p>Já faz algum tempo que eu venho utilizando o Hudson para integrar projetos Java, e esta ferramenta vem se mostrando muito útil no meu dia-a-dia. Só quem pratica Integração Contínua sabe o quanto é complicado não contar com a segurança que ela proporciona ao desenvolvimento.</p>
<p>O problema, no entanto, começou quando eu optei pelo Python em vez do Java em certos projetos. Obviamente, eu queria aproveitar o ambiente de Integração Contínua que eu já utilizava, o que foi bastante complicado já que o PyUnit, <em>framework</em> de testes que eu costumo utilizar, não oferece uma forma de gerar relatórios XML, da mesma forma que Ant e Maven fazem.</p>
<p>Depois de estudar o funcionamento interno do PyUnit, eu decidi implementar um <code>TestRunner</code> que fosse capaz de gerar arquivos XML no formato esperado pelo Hudson. Deu um bocado de trabalho, é verdade, mas pelo menos agora eu consigo utilizar os excelentes relatórios gerados pelo Hudson para acompanhar a execução dos meus testes PyUnit.</p>
<p>Como o Brasil é grande, seria burrice achar que eu fui o único a enfrentar esse tipo de dificuldade. Por esse motivo, eu resolvi escrever este texto e, quem sabe, ajudar àqueles que enfrentam um problema semelhante.</p>
]]></content:encoded>
			<wfw:commentRss>http://weblog.destaquenet.com/2008/10/27/integracao-continua-de-aplicacoes-python-com-hudson/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Deployment de aplicações Python com Fabric</title>
		<link>http://weblog.destaquenet.com/2008/10/05/deployment-de-aplicacoes-python-com-fabric/</link>
		<comments>http://weblog.destaquenet.com/2008/10/05/deployment-de-aplicacoes-python-com-fabric/#comments</comments>
		<pubDate>Sun, 05 Oct 2008 10:00:05 +0000</pubDate>
		<dc:creator>Daniel Martins</dc:creator>
				<category><![CDATA[Português]]></category>
		<category><![CDATA[Programação]]></category>
		<category><![CDATA[Tutoriais]]></category>
		<category><![CDATA[capistrano]]></category>
		<category><![CDATA[deployment]]></category>
		<category><![CDATA[dicas]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[fabric]]></category>
		<category><![CDATA[ferramenta]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://weblog.destaquenet.com/?p=101</guid>
		<description><![CDATA[Uma coisa é fato: subir uma nova versão de uma aplicação é um procedimento que, se feito manualmente, costuma demandar tempo precioso, independente do tamanho da aplicação e dos frameworks utilizados no projeto. Não há o que discutir. Na verdade, &#8230; <a href="http://weblog.destaquenet.com/2008/10/05/deployment-de-aplicacoes-python-com-fabric/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Uma coisa é fato: subir uma nova versão de uma aplicação é um procedimento que, se feito manualmente, costuma demandar tempo precioso, independente do tamanho da aplicação e dos <em>frameworks</em> utilizados no projeto. Não há o que discutir.</p>
<p>Na verdade, ninguém parecia se importar em automatizar tarefas &#8220;mecânicas&#8221; como o <em>deployment</em>, coisa que mudou de figura ao passo que <a href="http://en.wikipedia.org/wiki/Agile_software_development">metodologias ágeis</a> &#8212; juntamente com técnicas como <a href="http://martinfowler.com/articles/continuousIntegration.html">Integração Contínua</a> &#8212; passaram a se tornar populares. Desde então, algum esforço vem sendo investido para criar ferramentas para automatização de muitas dessas tarefas.</p>
<p><strong>Atualização:</strong> Trechos de código adaptados para as versões mais recentes do Fabric (22/06/2010).</p>
<p><span id="more-101"></span></p>
<h3>Fabric: ferramenta Python para deployment</h3>
<p>Apesar de já ter utilizado algumas dessas <a href="http://maven.apache.org/">ferramentas</a> no desenvolvimento de projetos em <a href="http://java.sun.com/">Java</a>, plataforma na qual eu possuo uma experiência maior, eu ainda não conhecia nenhuma ferramenta em <a href="http://python.org/">Python</a> que me permitisse automatizar o <em>deployment</em> de uma aplicação.</p>
<p>Como eu estava começando a ficar de saco cheio de ter que atualizar os arquivos de uma aplicação <a href="http://djangoproject.org/">Django</a> via SCP, eu resolvi que já era hora de ir atrás de alguma ferramenta que me ajudasse a automatizar esse processo. Finalmente, depois de muita procura, eu encontrei <a href="http://www.nongnu.org/fab/index.html">Fabric</a>, uma ferramenta mais ou menos parecida com um <a href="http://www.capify.org/">Capistrano</a> &#8220;capado&#8221;.</p>
<p>A instalação do Fabric é bem simples para quem costuma usar o <a href="http://peak.telecommunity.com/DevCenter/EasyInstall">easy_install</a>:</p>
<pre>$ sudo easy_install Fabric</pre>
<p>Basta executar esse comando para que os fontes da última versão do Fabric (0.0.9 no momento da publicação deste texto) sejam baixados e instalados.</p>
<p><strong>Atenção</strong>: Quem utiliza máquinas Windows, provavelmente precisará do <a href="http://www.cygwin.com/">Cygwin</a>, já que o Fabric assume o uso de ambientes Unix.</p>
<h3>Fabric a 3.000 pés</h3>
<p>Neste momento você já deve conseguir executar o comando <code>fab</code> no terminal. Se tudo correu bem até aqui, estamos prontos continuar.</p>
<p>Vamos começar criando o arquivo <code>fabfile.py</code> no diretório-raíz da aplicação. Coloque o seguinte conteúdo neste arquivo:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> fabric.<span style="color: black;">api</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span>
&nbsp;
env.<span style="color: black;">project</span> = <span style="color: #483d8b;">'project_name'</span>,
env.<span style="color: black;">package</span> = <span style="color: #483d8b;">'$(project).zip'</span>,
&nbsp;
<span style="color: #808080; font-style: italic;"># Remote servers</span>
env.<span style="color: #dc143c;">user</span>  = <span style="color: #483d8b;">'usuario_ssh'</span>,
env.<span style="color: black;">hosts</span> = <span style="color: black;">&#91;</span><span style="color: #483d8b;">'servidor1.com'</span>, <span style="color: #483d8b;">'servidor2.com'</span><span style="color: black;">&#93;</span>,
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> deploy<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;Deploys the application to the production servers.&quot;</span>
    build<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> build<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;Builds the application.&quot;</span>
    prepare<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> prepare<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;Prepares the build directory.&quot;</span>
    clean<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> clean<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;Removes the build directory.&quot;</span>
    <span style="color: #ff7700;font-weight:bold;">pass</span></pre></div></div>

<p>Cada método definido no arquivo é equivalente a uma <em>task</em> do Capistrano. No início temos as variáveis <code>env.*</code> necessárias para o <em>script</em>. Destaque para a variável <code>env.hosts</code>, que indica os servidores nos quais os comandos remotos devem ser executados.</p>
<p>Ok, tente executar o comando <code>fab -l</code> no terminal, no mesmo diretório onde se encontra o arquivo <code>fabfile.py</code>. Se tudo correr bem, você receberá a seguinte saída:</p>
<pre>
$  fab -l
Available commands:
   build      Build the application.
   clean      Remove the build directory.
   deploy     Deploy the application to the production servers.
   help       Display Fabric usage help, or help for a given command.
   license    Display the Fabric distribution license text.
   list       Display a list of commands with descriptions.
   prepare    Prepare the build directory.
   set        Set a Fabric variable.
   shell      Start an interactive shell connection to the specified hosts.
   warranty   Display warranty information for the Fabric software.
</pre>
<p>Veja que as <em>tasks</em> que criamos estão disponíveis para serem executadas via linha de comando. Para executar as <em>tasks</em> <code>clean</code> e <code>deploy</code>, por exemplo, utilizaríamos o seguinte comando:</p>
<pre>$  fab clean deploy</pre>
<p>Simples, não é? Antes de vermos um exemplo de script completo, vamos conhecer os três principais métodos utilizados em <em>scripts</em> Fabric: <code>local</code>, <code>run</code> e <code>put</code>:</p>
<ul>
<li><code>local</code>: Serve para executar comandos na máquina local. Ex: <code>local('mkdir build')</code>;</li>
<li><code>run</code>: Igual ao <code>local</code>, mas executa os comandos nas máquinas remotas (indicadas na variável <code>env.hosts</code>);</li>
<li><code>put</code>: Envia um arquivo para as máquinas remotas. Ex: <code>put('arquivo.zip', '/home/user/app.zip')</code>.</li>
</ul>
<h3>Finalmente, o script completo!</h3>
<p>Antes de mostrar o <em>script</em> que eu venho utilizando para fazer o deployment <a href="http://www.destaquenet.com/">de uma aplicação</a> Django, veja como seus arquivos e diretórios estão organizados: (isso deve ajudar a entender melhor o <em>script</em>)</p>
<div id="attachment_131" class="wp-caption aligncenter" style="width: 214px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2008/10/destaqueweb_structure.png"><img src="http://weblog.destaquenet.com/wp-content/uploads/2008/10/destaqueweb_structure-204x300.png" alt="Estrutura do projeto" title="Estrutura do projeto" width="204" height="300" class="size-medium wp-image-131" /></a><p class="wp-caption-text">Estrutura do projeto</p></div>
<p>E, finalmente, o <em>script</em>:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">#!/usr/bin/env python</span>
<span style="color: #808080; font-style: italic;"># -*- coding: utf-8 -*-</span>
&nbsp;
<span style="color: #483d8b;">&quot;&quot;&quot;Build script.
&quot;&quot;&quot;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">from</span> fabric.<span style="color: black;">api</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span>
&nbsp;
&nbsp;
env.<span style="color: black;">project</span> = <span style="color: #483d8b;">'destaqueweb'</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Build output directory</span>
env.<span style="color: black;">build_path</span> = <span style="color: #483d8b;">'build'</span>
env.<span style="color: black;">package</span>    = <span style="color: #483d8b;">'%s.zip'</span> <span style="color: #66cc66;">%</span> env.<span style="color: black;">project</span>
env.<span style="color: black;">local_path</span> = <span style="color: #483d8b;">'%s/%s'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>env.<span style="color: black;">build_path</span>, env.<span style="color: black;">package</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Media</span>
env.<span style="color: black;">media_src</span>   = <span style="color: #483d8b;">'media'</span>
env.<span style="color: black;">media_root</span>  = <span style="color: #483d8b;">'public_html'</span>
env.<span style="color: black;">media_path</span>  = <span style="color: #483d8b;">'%s/%s/%s'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>env.<span style="color: black;">media_root</span>, env.<span style="color: black;">project</span>, env.<span style="color: black;">media_src</span><span style="color: black;">&#41;</span>
env.<span style="color: black;">media_build</span> = <span style="color: #483d8b;">'%s/%s'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>env.<span style="color: black;">build_path</span>, env.<span style="color: black;">media_path</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Application code</span>
env.<span style="color: black;">app_root</span>  = <span style="color: #483d8b;">'wsgi_apps'</span>
env.<span style="color: black;">app_path</span>  = <span style="color: #483d8b;">'%s/%s'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>env.<span style="color: black;">app_root</span>, env.<span style="color: black;">project</span><span style="color: black;">&#41;</span>
env.<span style="color: black;">app_build</span> = <span style="color: #483d8b;">'%s/%s'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>env.<span style="color: black;">build_path</span>, env.<span style="color: black;">app_path</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Remote servers</span>
env.<span style="color: black;">hosts</span>       = <span style="color: black;">&#91;</span><span style="color: #483d8b;">'destaquenet.com'</span><span style="color: black;">&#93;</span>
env.<span style="color: black;">destination</span> = <span style="color: #483d8b;">'/home/destaquenet'</span>
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> clean<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;Removes the build directory.
    &quot;&quot;&quot;</span>
    local<span style="color: black;">&#40;</span><span style="color: #483d8b;">'rm -fR %s'</span> <span style="color: #66cc66;">%</span> env.<span style="color: black;">build_path</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> prepare<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;Prepares the build directory.
    &quot;&quot;&quot;</span>
    clean<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    local<span style="color: black;">&#40;</span><span style="color: #483d8b;">'mkdir -p %s'</span> <span style="color: #66cc66;">%</span> env.<span style="color: black;">media_build</span><span style="color: black;">&#41;</span>
    local<span style="color: black;">&#40;</span><span style="color: #483d8b;">'mkdir -p %s'</span> <span style="color: #66cc66;">%</span> env.<span style="color: black;">app_build</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> build<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;Builds the application.
    &quot;&quot;&quot;</span>
    local<span style="color: black;">&#40;</span><span style="color: #483d8b;">'cp -R %s/* %s/%s'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>env.<span style="color: black;">project</span>, env.<span style="color: black;">build_path</span>, env.<span style="color: black;">app_path</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
    local<span style="color: black;">&#40;</span><span style="color: #483d8b;">'cp -R %s/* %s/%s'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>env.<span style="color: black;">media_src</span>, env.<span style="color: black;">build_path</span>, env.<span style="color: black;">media_path</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
    local<span style="color: black;">&#40;</span><span style="color: #483d8b;">'find %s -name *.pyc -delete'</span> <span style="color: #66cc66;">%</span> env.<span style="color: black;">build_path</span><span style="color: black;">&#41;</span>
    local<span style="color: black;">&#40;</span><span style="color: #483d8b;">'find %s -path *upload* -delete'</span> <span style="color: #66cc66;">%</span> env.<span style="color: black;">build_path</span><span style="color: black;">&#41;</span>
    local<span style="color: black;">&#40;</span><span style="color: #483d8b;">'find %s -path *fixtures* -delete'</span> <span style="color: #66cc66;">%</span> env.<span style="color: black;">build_path</span><span style="color: black;">&#41;</span>
    local<span style="color: black;">&#40;</span><span style="color: #483d8b;">'cd %s;zip -r %s %s %s'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>env.<span style="color: black;">build_path</span>, env.<span style="color: black;">package</span>, env.<span style="color: black;">media_root</span>, env.<span style="color: black;">app_root</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> reload_app<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;Reloads the app.
    &quot;&quot;&quot;</span>
    run<span style="color: black;">&#40;</span><span style="color: #483d8b;">'touch %s/%s/%s/index.wsgi'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>env.<span style="color: black;">destination</span>, env.<span style="color: black;">media_root</span>, env.<span style="color: black;">project</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
    run<span style="color: black;">&#40;</span><span style="color: #483d8b;">'python %s/%s/manage.py ping_google /sitemap.xml'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>env.<span style="color: black;">destination</span>, env.<span style="color: black;">app_path</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> deploy<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;Deploys the application to the production server.
    &quot;&quot;&quot;</span>
    build<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    put<span style="color: black;">&#40;</span>env.<span style="color: black;">local_path</span>, env.<span style="color: black;">destination</span><span style="color: black;">&#41;</span>
    run<span style="color: black;">&#40;</span><span style="color: #483d8b;">'cd %s; unzip -uo %s; rm %s'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>env.<span style="color: black;">destination</span>, env.<span style="color: black;">package</span>, env.<span style="color: black;">package</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
    reload_app<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Este código deve ser facilmente entendido por quem tem trabalha com uma certa facilidade no terminal.</p>
<p>Basicamente o que o código faz é organizar os arquivos da aplicação para que estes fiquem dispostos da mesma forma utilizada pelo servidor de produção, enviar os arquivos dentro de um pacote ZIP para os servidores e descompactá-los no local correto, além de executar um <code>touch</code> no <em>script</em> <acronym title="Web Server Gateway Interface">WSGI</acronym> para que o <a href="http://apache.org/">Apache</a> recarregue a aplicação.</p>
<p>Tudo pronto. Agora basta executar <code>fab deploy</code> no terminal para subir a aplicação para o(s) servidor(es) desejado(s).</p>
<h3>Fabric e ambiente de homologação</h3>
<p>Uma coisa que vem se tornando comum é o uso de diferentes ambientes onde uma aplicação costuma ser implantada (ex: ambiente de homologação). Se sua empresa costuma trabalhar dessa forma, o Fabric ainda pode te ajudar.</p>
<p>Por exemplo, vamos supor que sua empresa possua um servidor de produção e um servidor de homologação. Podemos, então, adequar o <em>script</em> para que ele possa trabalhar com ambos os ambientes:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># ...</span>
env.<span style="color: #dc143c;">user</span>  = <span style="color: #483d8b;">'production'</span>,
env.<span style="color: black;">hosts</span> = <span style="color: black;">&#91;</span><span style="color: #483d8b;">'app.com'</span><span style="color: black;">&#93;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> staging<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># deploy to staging servers</span>
    env.<span style="color: #dc143c;">user</span>  = <span style="color: #483d8b;">'staging'</span>
    env.<span style="color: black;">hosts</span> = <span style="color: black;">&#91;</span><span style="color: #483d8b;">'staging.app.com'</span><span style="color: black;">&#93;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># other tasks...</span></pre></div></div>

<p>Fazendo as mudanças mostradas acima, para executar o <em>deployment</em> no ambiente de homologação basta rodar o comando <code>fab staging deploy</code>; o deployment em ambiente de produção continua disponível através do comando <code>fab deploy</code>.</p>
<p>Isso é possível pois podemos substituir o valor de uma variável (ou configurar novas variáveis) a qualquer momento. Então, quando executamos o comando <code>fab staging deploy</code>, o Fabric executa a <em>task</em> <code>staging</code>, substituindo o valor das variáveis <code>env.user</code> e <code>env.hosts</code>, fazendo com que os comandos contidos na <em>task</em> <code>deploy</code> sejam executados nos servidores de homologação em vez de nos servidores de produção.</p>
]]></content:encoded>
			<wfw:commentRss>http://weblog.destaquenet.com/2008/10/05/deployment-de-aplicacoes-python-com-fabric/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
	</channel>
</rss>

