<?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; framework</title>
	<atom:link href="http://weblog.destaquenet.com/tag/framework/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>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>Django For Mobile Devices</title>
		<link>http://weblog.destaquenet.com/2010/07/12/django-for-mobile-devices/</link>
		<comments>http://weblog.destaquenet.com/2010/07/12/django-for-mobile-devices/#comments</comments>
		<pubDate>Mon, 12 Jul 2010 11:00:00 +0000</pubDate>
		<dc:creator>Daniel Martins</dc:creator>
				<category><![CDATA[English]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[configuration]]></category>
		<category><![CDATA[deploy]]></category>
		<category><![CDATA[device]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[mobile]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[wsgi]]></category>

		<guid isPermaLink="false">http://weblog.destaquenet.com/?p=932</guid>
		<description><![CDATA[We are living what some people call the &#8220;mobile explosion&#8221;, a time where an increasing number of portable devices &#8212; like tablets and smartphones &#8212; are becoming a significant part of the Web. This is the reason why having your &#8230; <a href="http://weblog.destaquenet.com/2010/07/12/django-for-mobile-devices/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>We are living what some people call the &#8220;mobile explosion&#8221;, a time where an increasing number of portable devices &#8212; like tablets and smartphones &#8212; are becoming a significant part of the Web. This is the reason why having your website tailored for these devices is becoming increasingly important.</p>
<p>Fortunately, <a href="http://djangoproject.com/">Django</a> is one of the few web frameworks that makes this an easy problem to solve.</p>
<p><span id="more-932"></span></p>
<h3>How we solved it</h3>
<p>A simple way is to create a separate settings module for the mobile version. Doing this, we&#8217;re able to run two different webapps while reusing the existing codebase. Also, each version can have its own template directory, URL root configuration, etc.</p>
<p>Let&#8217;s do this. In the project root directory, create a file <code>m_settings.py</code> with the following content:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># File: myproject/m_settings.py</span>
&nbsp;
<span style="color: #483d8b;">&quot;&quot;&quot;Django settings for the mobile-specific website.
&quot;&quot;&quot;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Load the default settings</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;"># Domain &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;"># Used elsewhere to determine which version is running</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 for the mobile version</span>
ROOT_URLCONF  = <span style="color: #483d8b;">'myproject.m_urls'</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Templates for the mobile version</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;"># Other settings...</span></pre></div></div>

<p>These two webapps share the same codebase, but that doesn&#8217;t mean they have to use the same URL root configuration. In fact, websites suitable for mobile devices are usually simpler, with fewer URL mappings.</p>
<p>To define separate URL root configuration for the mobile version, create a file <code>m_urls.py</code> with the following content:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># File: myproject/m_urls.py</span>
&nbsp;
<span style="color: #483d8b;">&quot;&quot;&quot;Mobile-specific URL definition.
&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;
<span style="color: #808080; font-style: italic;"># Error page handlers</span>
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;"># Root URL patterns</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;"># Internal apps</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;"># Other settings...</span>
<span style="color: black;">&#41;</span></pre></div></div>

<p>Note that, in this particular example, the <a href="http://docs.djangoproject.com/en/dev/ref/contrib/admin/">Admin app</a> isn&#8217;t accessible from mobile version. This just shows that we can structure each webapp differently without too much trouble.</p>
<h3>Developing</h3>
<p>You already know how to run the development server for the default version. Most people don&#8217;t know, however, that it&#8217;s possible to choose a different port number and settings module, which allows us to launch one development server for each webapp version:</p>

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

<p>Just develop your stuff and see the results in both versions right away. Easy peasy.</p>
<h3>Testing</h3>
<p>You probably noticed that we have two settings that can be used to identify what webapp version is being run, <code>DEFAULT_VERSION</code> and <code>MOBILE_VERSION</code>. </p>
<p>So it&#8217;s just a matter of checking those settings when you need to do different things in each webapp version. This is particularly useful when you use an app in both versions and want to create separate tests for each version:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># File: myproject/myapp/tests/__init__.py</span>
&nbsp;
<span style="color: #483d8b;">&quot;&quot;&quot;Unit tests module for 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;"># Tests the default version</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;"># Tests the mobile version</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>We can run the tests for each version in a similar way we did before with the <code>runserver</code> command:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># Default version</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;"># Mobile version</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>Deploying</h3>
<p>Despite what you may think, this is the easy part.</p>
<p>Since <a href="http://docs.djangoproject.com/en/dev/howto/deployment/modwsgi/">deploying Django</a> with <a href="http://apache.org/">Apache</a> and <a href="http://code.google.com/p/modwsgi/">mod_wsgi</a> is the recommended way to get Django into production, it&#8217;s likely that you already have a WSGI file like this:</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;"># Third-party eggs</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>All we need to do is configure another WSGI-enabled subdomain on our server, e.g. m.mywebsite.com, that refers to another WSGI file like this one:</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;"># Third-party eggs</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;"># This line</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>The only difference between these two WSGI files is that each one points to a different settings module. And no, you don&#8217;t need to have a separate copy for each version. We are using the same codebase for both versions, remember? <img src='http://weblog.destaquenet.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<h3>Minimizing the traffic</h3>
<p>Amazingly, not everyone has access ultra-fast internet connections on their devices, so it&#8217;s very important to keep your sites as lightweight as possible.</p>
<p>There are several open source projects that try to address this problem. One of them is <a href="http://code.google.com/p/django-compress/">django-compress</a>, a Django app that provides an automated system for compressing CSS and JavaScript files.</p>
<p>In fact, doesn&#8217;t matter if your websites target mobile devices or not; you should <em>always</em> try to minimize the amount of traffic.</p>
<h3>What&#8217;s left?</h3>
<p>There&#8217;s one small problem though: when someone visit the regular website from a mobile device, or vice-versa, they are not redirected to the appropriate version. But this is a topic for another article!</p>
]]></content:encoded>
			<wfw:commentRss>http://weblog.destaquenet.com/2010/07/12/django-for-mobile-devices/feed/</wfw:commentRss>
		<slash:comments>1</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>Django e settings.py: dicas e boas práticas</title>
		<link>http://weblog.destaquenet.com/2009/04/13/django-e-settingspy-dicas-e-boas-praticas/</link>
		<comments>http://weblog.destaquenet.com/2009/04/13/django-e-settingspy-dicas-e-boas-praticas/#comments</comments>
		<pubDate>Tue, 14 Apr 2009 01:32:06 +0000</pubDate>
		<dc:creator>Daniel Martins</dc:creator>
				<category><![CDATA[Português]]></category>
		<category><![CDATA[Programação]]></category>
		<category><![CDATA[boas práticas]]></category>
		<category><![CDATA[configuração]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[dicas]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[testes]]></category>

		<guid isPermaLink="false">http://weblog.destaquenet.com/?p=415</guid>
		<description><![CDATA[Em vez de ficar rasgando elogios ao Django, como de costume, eu tentarei aproveitar o melhor o meu (e o seu) tempo e mostrar algo que é de fato útil. O assunto em questão envolve o módulo settings.py, cuja função &#8230; <a href="http://weblog.destaquenet.com/2009/04/13/django-e-settingspy-dicas-e-boas-praticas/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Em vez de ficar rasgando elogios ao <a href="http://djangoproject.com">Django</a>, como de costume, eu tentarei aproveitar o melhor o meu (e o seu) tempo e mostrar algo que é de fato útil. O assunto em questão envolve o módulo <code>settings.py</code>, cuja função é fornecer as configurações necessárias para que o projeto funcione. Apesar deste módulo ser uma peça importante em qualquer projeto Django, pouco se fala sobre ele, ou sobre boas práticas associadas a ele. Por isso, achei que seria interessante mostrar a minha visão pessoal sobre o assunto.</p>
<h3>O poder do Python</h3>
<p>Quem não está acostumado a trabalhar com Django pode estranhar o fato deste utilizar um script <a href="http://python.org">Python</a> para fazer a configuração do projeto: o famoso <code>settings.py</code>. E essa estranheza é justificada, afinal muitos desenvolvedores &#8212; principalmente os que vêm de outras linguagens &#8212; estão acostumados a trabalhar com ferramentas onde tal tarefa é feita com arquivos XML ou coisa assim.</p>
<p>O fato é que utilizar um script Python para tal é uma excelente idéia, pois você deixa de depender de algum tipo de estrutura estática (e muitas vezes inconveniente) para algo mais flexível e poderoso, que, no caso, é a própria linguagem de programação. Isso faz uma grande diferença em situações onde tal flexibilidade é necessária.</p>
<p>Quer exemplos?<span id="more-415"></span></p>
<h3>Ambientes de desenvolvimento/produção</h3>
<p>Eis como fizemos aqui. Primeiramente, defina a variável de ambiente <code>WORKSPACE</code>. No Linux, isso pode ser feito através do arquivo <code>~/.bashrc</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">export</span> <span style="color: #007800;">WORKSPACE</span>=<span style="color: #000000;">1</span></pre></div></div>

<p>A idéia é possibilitar a criação de perfis de configuração, cada qual correspondente a um ambiente de execução. A existência ou não da variável de ambiente é o que define o ambiente no qual a aplicação roda.</p>
<p>Continuando com o exemplo, no diretório raíz do seu projeto Django, crie o módulo <code>environment.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: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">os</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> production_mode<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #ff7700;font-weight:bold;">not</span> development_mode<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> development_mode<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #483d8b;">'WORKSPACE'</span> <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">environ</span></pre></div></div>

<p>Finalmente, modifique o módulo <code>settings.py</code> para que este utilize tais métodos onde for necessário definir configurações diferentes para ambientes de execução diferentes:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> environment <span style="color: #ff7700;font-weight:bold;">import</span> production_mode
&nbsp;
<span style="color: #808080; font-style: italic;"># Configurações padrão</span>
PREPEND_WWW = <span style="color: #008000;">False</span>
DEBUG = <span style="color: #008000;">True</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Configurações para ambiente de produção</span>
<span style="color: #ff7700;font-weight:bold;">if</span> production_mode<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    PREPEND_WWW = <span style="color: #008000;">True</span>
    DEBUG = <span style="color: #008000;">False</span>
&nbsp;
MIDDLEWARE_CLASSES = <span style="color: black;">&#40;</span>
    <span style="color: #483d8b;">'django.middleware.common.CommonMiddleware'</span>,
    <span style="color: #483d8b;">'django.contrib.sessions.middleware.SessionMiddleware'</span>,
    <span style="color: #483d8b;">'django.contrib.auth.middleware.AuthenticationMiddleware'</span>,
    <span style="color: #483d8b;">'django.middleware.doc.XViewMiddleware'</span>,
    <span style="color: #483d8b;">'pages.middleware.PageFallbackMiddleware'</span>,
    <span style="color: #483d8b;">'django.contrib.redirects.middleware.RedirectFallbackMiddleware'</span>,
<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Habilitando caching em modo de produção</span>
<span style="color: #ff7700;font-weight:bold;">if</span> production_mode<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    MIDDLEWARE_CLASSES += <span style="color: black;">&#40;</span>
        <span style="color: #483d8b;">'django.middleware.cache.UpdateCacheMiddleware'</span>,
        <span style="color: #483d8b;">'django.middleware.cache.FetchFromCacheMiddleware'</span>,
    <span style="color: black;">&#41;</span></pre></div></div>

<p>Não tenha medo de utilizar os recursos do Python onde eles se fizerem necessários, apenas tomando cuidado para não exagerar e acabar criando acidentalmente um <a href="http://en.wikipedia.org/wiki/Genetic_algorithm">Algoritmo Genético</a> para configurar seu projeto!</p>
<h3>Informações secretas (IPs, usernames, passwords, etc)</h3>
<p>Praticamente não há quem ignore a importância de um bom sistema de controle de revisões (<a href="http://subversion.tigris.org">Subversion</a>, <a href="http://git-scm.org">Git</a>, etc). O problema é que, muitas vezes, não tomamos o devido cuidado com o que colocamos dentro dos nossos repositórios. Sempre que possível, informações secretas &#8212; como endereços de IP, usernames e passwords &#8212; devem ser mantidas fora dos repositórios.</p>
<p>Em um projeto Django, as informações de acesso a servidores de e-mail e bancos de dados devem estar disponíveis através do módulo  <code>settings.py</code>. Felizmente, existe um jeito simples de manter essas informações separadas das outras configurações.</p>
<p>Primeiramente, abra o arquivo <code>settings.py</code> do seu projeto e remova todas as senhas e outras informações que você considere secretas. Em seguida, cole o seguinte trecho de código no final do arquivo:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">try</span>:
    <span style="color: #ff7700;font-weight:bold;">from</span> private <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span>
<span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">ImportError</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span></pre></div></div>

<p>Feito isso, crie o módulo <code>private.py</code> no diretório raíz do seu projeto Django. Coloque nele as configurações que você removeu do <code>settings.py</code> no passo anterior. Exemplo:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> environment <span style="color: #ff7700;font-weight:bold;">import</span> production_mode
&nbsp;
SECRET_KEY = <span style="color: #483d8b;">'secret_key_do_seu_projeto'</span>
&nbsp;
EMAIL_HOST = <span style="color: #483d8b;">'localhost'</span>
EMAIL_HOST_PASSWORD = <span style="color: #483d8b;">'senha_email_local'</span>
&nbsp;
DATABASE_HOST = <span style="color: #483d8b;">'localhost'</span>
DATABASE_USER = <span style="color: #483d8b;">'username_db_local'</span>
DATABASE_PASSWORD = <span style="color: #483d8b;">'senha_db_local'</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> production_mode<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    EMAIL_HOST = <span style="color: #483d8b;">'ip_email_producao'</span>
    EMAIL_HOST_PASSWORD = <span style="color: #483d8b;">'senha_email_producao'</span>
&nbsp;
    DATABASE_HOST = <span style="color: #483d8b;">'ip_db_producao'</span>
    DATABSE_USER = <span style="color: #483d8b;">'username_db_producao'</span>
    DATABASE_PASSWORD = <span style="color: #483d8b;">'senha_db_producao'</span></pre></div></div>

<p>Certifique-se de adicionar o arquivo <code>private.py</code> no <em>ignore</em> (<code>.cvsignore</code> para <a href="http://www.nongnu.org/cvs/">CVS</a>, <code>.gitignore</code> para Git, etc) correspondente ao sistema de controle de revisões sendo utilizado. Faça o commit e pronto.</p>
<p>Para finalizar, se o seu repositório já contém uma versão &#8220;insegura&#8221; do módulo <code>settings.py</code>, mude as senhas dos seus servidores.</p>
<h3>E você, o que recomenda?</h3>
<p>Tem alguma dica útil para compartilhar conosco? Nós adoraríamos ouvir o que você tem a dizer!</p>
]]></content:encoded>
			<wfw:commentRss>http://weblog.destaquenet.com/2009/04/13/django-e-settingspy-dicas-e-boas-praticas/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Seaside: um framework web de verdade</title>
		<link>http://weblog.destaquenet.com/2008/09/30/seaside-um-framework-web-de-verdade/</link>
		<comments>http://weblog.destaquenet.com/2008/09/30/seaside-um-framework-web-de-verdade/#comments</comments>
		<pubDate>Wed, 01 Oct 2008 01:44:39 +0000</pubDate>
		<dc:creator>Daniel Martins</dc:creator>
				<category><![CDATA[Português]]></category>
		<category><![CDATA[Programação]]></category>
		<category><![CDATA[Tutoriais]]></category>
		<category><![CDATA[aplicação]]></category>
		<category><![CDATA[componentes]]></category>
		<category><![CDATA[continuations]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[jogo]]></category>
		<category><![CDATA[seaside]]></category>
		<category><![CDATA[smalltalk]]></category>
		<category><![CDATA[squeak]]></category>
		<category><![CDATA[tutorial]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[workflow]]></category>

		<guid isPermaLink="false">http://weblog.destaquenet.com/?p=78</guid>
		<description><![CDATA[Provavelmente isso não é novidade para alguns de vocês, mas já faz algum tempo que eu venho me aventurando pelo incrível mundo do Smalltalk. Dando prosseguimento à esta saga, tenho o orgulho de anunciar a minha próxima vítima: o framework &#8230; <a href="http://weblog.destaquenet.com/2008/09/30/seaside-um-framework-web-de-verdade/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Provavelmente isso não é novidade para alguns de vocês, mas já faz algum tempo que eu venho me  aventurando pelo incrível mundo do <a href="http://en.wikipedia.org/wiki/Smalltalk">Smalltalk</a>. Dando prosseguimento à esta saga, tenho o orgulho de anunciar a minha próxima vítima: o <em>framework</em> <a href="http://seaside.st/">Seaside</a>!</p>
<p>O Seaside é um impressionante <em>framework web</em> escrito em Smalltalk focado no desenvolvimento de <del datetime="2008-10-01T00:58:21+00:00">sites</del> aplicações <em>stateful</em>. Mesmo conhecendo muito pouco a respeito do seu funcionamento &#8212; até então, nada além de um mísero <em>hello world</em> &#8212; resolvi tentar criar uma aplicação que realmente fizesse algo a mais do que simplesmente escrever um texto na tela.</p>
<p>A experiência foi muito boa, mas poderia ter sido melhor se o projeto contasse com uma documentação decente. O código do <em>framework</em> propriamente dito é muito bem documentado e é possível aprender bastante, mesmo tendo apenas o <em>Class Browser</em> do <a href="http://www.squeak.org/">Squeak</a> como recurso de pesquisa. Mas convenhamos: uma documentação <a href="http://djangobook.com/">como esta</a> ainda faz falta, principalmente para os aventureiros que, como eu, não fazem parte do <em>core team</em> do Seaside. <span id="more-78"></span></p>
<h3>Entendendo o exemplo</h3>
<p>Não mostrarei nada de muito complexo aqui, até porque eu também estou aprendendo. Mas o exemplo é interessante para conhecermos algumas das características principais do Seaside, que serão explicadas no decorrer deste <em>post</em>.</p>
<p><div id="attachment_79" class="wp-caption alignright" style="width: 215px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2008/09/state.png"><img src="http://weblog.destaquenet.com/wp-content/uploads/2008/09/state-205x300.png" alt="Diagrama de estados" title="Diagrama de estados" width="205" height="300" class="size-medium wp-image-79" /></a><p class="wp-caption-text">Diagrama de estados</p></div>Você conhece aquele jogo de &#8220;adivinhar o número&#8221;? Pois então&#8230; criaremos aqui algo parecido. Ao lado, você pode conferir uma imagem que ilustra como a aplicação deverá funcionar.</p>
<p>Ao abrir a aplicação, o usuário irá ver uma mensagem, que deverá confirmar para que o jogo comece. Quando o usuário confirma, o sistema gera um número aleatório entre 1 e 10 e mostra um formulário, que o usuário deve preencher com seu palpite. Em seguida, o sistema checa se o palpite do usuário corresponde ao número gerado aleatoriamente: se sim, o sistema mostra uma mensagem parabenizando o usuário; caso contrário, o sistema re-exibe o formulário, mostrando a contagem de &#8220;chutes&#8221; até o momento, além de uma mensagem com uma dica, para ajudar o usuário a adivinhar o número.</p>
<p>Esse ciclo continua até o usuário acertar. Por fim, o sistema pergunta se o usuário deseja jogar novamente: em caso afirmativo, um novo número é sorteado e o formulário re-exibido; senão, a mensagem de boas vindas é mostrada.</p>
<p>Ainda em relação ao diagrama, perceba que há um quadrado vermelho em torno de algumas atividades. Basicamente, isso quer dizer que a aplicação não deve permitir que o usuário volte (com o botão <em>back</em> do <em>browser</em>) e re-submeta um palpite após já tê-lo acertado. Em outras palavras, eu quero que as atividades dentro do quadrado vermelho representem um <em>workflow</em>, ou transação.</p>
<h3>Introdução</h3>
<p>O Seaside trabalha com o conceito de componentes. Neste exemplo, criaremos dois componentes para implementar a aplicação proposta. Um será responsável por controlar o fluxo de navegação do usuário pela aplicação, e o outro que receberá o <em>input</em> do usuário através de um formulário. Mas, antes de prosseguirmos, vamos aprender para que servem duas das mais importantes classes do Seaside: <code>WAComponent</code> e <code>WATask</code>.</p>
<p>A classe <code>WAComponent</code> será sua melhor amiga em um projeto Seaside, pois é através da criação de sub-classes de <code>WAComponent</code> que construímos a aplicação, pedaço por pedaço. Toda sub-classe de <code>WAComponent</code> deve implementar o método <code>#renderContentOn:</code>, pois é através deste que definimos como o componente deve ser renderizado no <em>browser</em> do usuário.</p>
<p>A classe <code>WATask</code>, por sua vez, é parecida com a classe <code>WAComponent</code> (de fato, ela a estende), com a diferença que ela não é usada para nada além de definir uma tarefa, ou melhor, a ordem com que outras tarefas e componentes devem ser chamados de modo a cumprir um determinado objetivo. Em poucas palavras: estenda <code>WATask</code> para definir <em>workflows</em>!</p>
<h3>Entendendo a interação entre os componentes</h3>
<p>Como pôde ser visto no diagrama de atividades mostrado anteriormente, o fluxo começa quando o usuário confirma que deseja jogar, passando o controle para o fomulário. O formulário é então renderizado no <em>browser</em> do usuário para que ele possa enviar um palpite. Em seguida, quando o usuário submete o formulário, o componente chamador (que é o próprio fluxo) recebe o palpite do usuário e o compara com o número gerado no início. Dependendo do resultado dessa comparação, o formulário é exibido novamente ou a mensagem de sucesso é mostrada.</p>
<p>Certo&#8230; talvez tenha ficado confusa a parte em que um componente &#8220;passa o controle&#8221; para outro. Esse é um conceito muito importante em um <em>framework</em> como o Seaside. Para entender essa coisa do &#8220;passa o controle&#8221;, imagine uma chamada de método comum:</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">void</span> main<span style="color: #009900;">&#40;</span><span style="color: #993333;">char</span><span style="color: #339933;">**</span> args<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    foo<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// chama o método (&quot;passa o controle&quot;)</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #993333;">void</span> foo<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #666666; font-style: italic;">// faz algo aqui</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Neste exemplo de código C, quando chamamos um método, o fluxo de execução é modificado, fazendo com que o método chamado assuma o controle. Então, quando o método termina, o fluxo retorna ao método chamador.</p>
<p>Simples não? Agora imagine isso <strong>funcionando na web</strong>. Imagine que o método <code>main</code> do exemplo fosse um componente da nossa aplicação, e que esse componente pudesse passar o controle para <strong>outros</strong> componentes, assim como a chamada de método no exemplo, só que com a possibilidade de manter essa pilha de execução entre as requisições HTTP! Isso resolveria um monte de problemas, não é?</p>
<p>Felizmente, é assim que o Seaside trabalha. O conceito por trás disso é chamado de <a href="http://en.wikipedia.org/wiki/Continuation">Continuation</a>. A imagem a seguir tenta ilustrar o funcionamento disso no contexto do nosso exemplo:</p>
<div id="attachment_80" class="wp-caption aligncenter" style="width: 310px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2008/09/sequence.png"><img src="http://weblog.destaquenet.com/wp-content/uploads/2008/09/sequence-300x189.png" alt="Sequência de requisições" title="Sequência de requisições" width="300" height="189" class="size-medium wp-image-80" /></a><p class="wp-caption-text">Sequência de requisições</p></div>
<p>Se desconsiderarmos por um momento o modelo (limitado) de <em>request/response</em> no qual o protocolo HTTP se baseia, a sequência de interações do usuário para com a aplicação se parece com o especificado no diagrama acima. No diagrama, é como se tivéssemos uma pilha de chamadas que não se perde entre as requisições!</p>
<p>O foco deste <em>post</em> não é explicar a teoria por trás desses conceitos todos, portanto, se você tem interesse em saber mais sobre o assunto, use o Google! <img src='http://weblog.destaquenet.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<h3>Definindo o fluxo da aplicação</h3>
<p>Vamos criar o componente responsável por controlar o fluxo de navegação da aplicação. O componente a seguir estende <code>WATask</code> e possui as variávies de instância <code>number</code> e <code>form</code> que servem, respectivamente, para armazenar o número gerado e o formulário usado para receber o <em>input</em> do usuário:</p>

<div class="wp_syntax"><div class="code"><pre class="smalltalk" style="font-family:monospace;"><span style="color: #0000ff;">WATask</span> subclass: <span style="color: #7f0000;">#GuessingAppComponent</span>
    instanceVariableNames: <span style="color: #7f0000;">'number form'</span>
    classVariableNames: <span style="color: #7f0000;">''</span>
    poolDictionaries: <span style="color: #7f0000;">''</span>
    category: <span style="color: #7f0000;">'GuessingApp'</span>
&nbsp;
<span style="color: #0000ff;">GuessingAppComponent</span> class&gt;&gt;canBeRoot
    ^true
&nbsp;
<span style="color: #007f00; font-style: italic;">&quot;Accessors for instance variables&quot;</span>
&nbsp;
<span style="color: #0000ff;">GuessingAppComponent</span>&gt;&gt;children
    ^ <span style="color: #0000ff;">Array</span> with: <span style="color: #7f007f;">self</span> form
&nbsp;
<span style="color: #0000ff;">GuessingAppComponent</span>&gt;&gt;initialize
    <span style="color: #007f00; font-style: italic;">&quot;Configure initial values&quot;</span>
&nbsp;
    <span style="color: #7f007f;">self</span> number: <span style="color: #00007f;">10</span> atRandom;
        form: <span style="">&#40;</span><span style="color: #0000ff;">GuessNumberForm</span> new<span style="">&#41;</span>
&nbsp;
<span style="color: #0000ff;">GuessingAppComponent</span>&gt;&gt;go
    <span style="color: #007f00; font-style: italic;">&quot;Start application workflow&quot;</span>
&nbsp;
    <span style="color: #7f007f;">self</span> inform: <span style="color: #7f0000;">'Start the game pushing the button below!!'</span>.
    <span style="">&#91;</span><span style="color: #7f007f;">self</span> initialize;
        <span style="">&#91;</span><span style="color: #7f007f;">self</span> call: <span style="color: #7f007f;">self</span> form.
            <span style="color: #7f007f;">self</span> form number &lt; <span style="color: #7f007f;">self</span> number
                ifTrue: <span style="">&#91;</span><span style="color: #7f007f;">self</span> form message: <span style="color: #7f0000;">'Try a higher value'</span><span style="">&#93;</span>
                ifFalse: <span style="">&#91;</span><span style="color: #7f007f;">self</span> form message: <span style="color: #7f0000;">'Try a lower value'</span><span style="">&#93;</span><span style="">&#93;</span>
                doWhileFalse: <span style="">&#91;</span><span style="color: #7f007f;">self</span> form number <span style="color: #000066; font-weight:bold;">=</span> <span style="color: #7f007f;">self</span> number<span style="">&#93;</span><span style="">&#93;</span>
        doWhileTrue: <span style="">&#91;</span><span style="color: #7f007f;">self</span> confirm: <span style="color: #7f0000;">'You won the game using '</span> , <span style="color: #7f007f;">self</span> form guesses asString , <span style="color: #7f0000;">' guess(es)!! Play again?'</span><span style="">&#93;</span></pre></div></div>

<p>Todo o código é bem simples de se entender, com exceção do método <code>#go</code>. Veja que o corpo do método não passa de uma transcrição dos diagramas mostrados anteriormente. Atenção especial para a chamada <code>self call:</code>, que é o equivalente ao exemplo de chamada de método, com a diferença que estamos transferindo o controle para que outro componente possa executar no lugar do componente corrente. Perceba também que este método <strong>ainda não está pronto</strong>, pois, do jeito que está, a aplicação não está preparada para caso o usuário queira re-submeter um palpite após já tê-lo acertado&#8230; faremos isso depois! </p>
<h3>Recebendo o <em>input</em> do usuário</h3>
<p>Abaixo segue o código do componente usado para receber o palpite do usuário. O componente estende <code>WAComonent</code> e tem as variáveis de instância <code>number</code>, <code>message</code> e <code>guesses</code>. Essas variáveis servem, respectivamente, para: guardar o palpite do usuário quando o formulário é submetido; guardar a dica a ser exibida para o usuário (algo do tipo &#8220;chute um valor mais alto&#8221;, ou &#8220;mais baixo&#8221;); e guardar o número de vezes que o formulário foi submetido:</p>

<div class="wp_syntax"><div class="code"><pre class="smalltalk" style="font-family:monospace;"><span style="color: #0000ff;">WAComponent</span> subclass: <span style="color: #7f0000;">#GuessNumberForm</span>
    instanceVariableNames: <span style="color: #7f0000;">'message number guesses'</span>
    classVariableNames: <span style="color: #7f0000;">''</span>
    poolDictionaries: <span style="color: #7f0000;">''</span>
    category: <span style="color: #7f0000;">'GuessingApp'</span>
&nbsp;
<span style="color: #007f00; font-style: italic;">&quot;Accessors for instance variables&quot;</span>
&nbsp;
<span style="color: #0000ff;">GuessNumberForm</span>&gt;&gt;increment
    <span style="color: #007f00; font-style: italic;">&quot;Increments the number of guesses&quot;</span>
&nbsp;
    <span style="color: #7f007f;">self</span> guesses: <span style="color: #7f007f;">self</span> guesses + <span style="color: #00007f;">1</span>
&nbsp;
<span style="color: #0000ff;">GuessNumberForm</span>&gt;&gt;initialize
    <span style="color: #007f00; font-style: italic;">&quot;Configure initial values&quot;</span>
&nbsp;
    <span style="color: #7f007f;">self</span> number: <span style="color: #00007f;">1</span>;
        message: <span style="color: #7f0000;">'Try a number between 1 and 10'</span>;
        guesses: <span style="color: #00007f;">0</span>.
&nbsp;
<span style="color: #0000ff;">GuessNumberForm</span>&gt;&gt;renderContentOn: <span style="color: #00007f;">html</span>
    <span style="color: #007f00; font-style: italic;">&quot;Render component&quot;</span>
&nbsp;
    html heading: <span style="color: #7f007f;">self</span> message level: <span style="color: #00007f;">4</span>.
    <span style="color: #00007f;">html</span> heading: <span style="color: #7f0000;">'You did '</span> , <span style="color: #7f007f;">self</span> guesses asString , <span style="color: #7f0000;">' guess(es) until now'</span> level: <span style="color: #00007f;">5</span>.
    <span style="color: #00007f;">html</span> form
        with: <span style="">&#91;</span><span style="color: #00007f;">html</span> textInput value: <span style="color: #7f007f;">self</span> number;
                callback: <span style="">&#91;</span>:<span style="color: #00007f;">value</span> | <span style="color: #7f007f;">self</span> increment; number: <span style="color: #00007f;">value</span> asInteger; answer<span style="">&#93;</span>.
            <span style="color: #00007f;">html</span> submitButton value: <span style="color: #7f0000;">'check my guess!!'</span><span style="">&#93;</span></pre></div></div>

<p>Novamente, a simplicidade impera. <img src='http://weblog.destaquenet.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  A única coisa deste código que vale explicar é o método <code>#renderContentOn:</code>, que serve para que possamos definir o que deve ser retornado ao usuário quando o componente precisar ser renderizado. O método recebe um objeto <code>WAHtmlCanvas</code> por parâmetro, responsável por gerar código <acronym title="eXtended Hyper Text Markup Language">XHTML</acronym> automaticamente. Para quem tem conhecimentos em <acronym title="Hyper Text Markup Language">HTML</acronym>, o código é bem trivial, com exceção do método <code>#callback</code>, onde colocamos algum código para ser executado quando o formulário for submetido. Perceba a chamada a <code>self answer</code> no final da linha, que é responsável por devolver o controle ao componente chamador (o que executou <code>self call: form</code>).</p>
<h3>Demarcando uma transação</h3>
<p>Se lembra do quadrado vermelho no diagrama de atividades? Então&#8230; precisamos dar um jeito de impedir que o usuário volte a dar palpites após ter descoberto o número. Ou seja: precisamos definir uma <strong>transação</strong>.</p>
<p>Isso é feito utilizando o método <code>#isolate:</code>, conforme pode ser visto abaixo:</p>

<div class="wp_syntax"><div class="code"><pre class="smalltalk" style="font-family:monospace;"><span style="color: #0000ff;">GuessingAppComponent</span>&gt;&gt;go
    <span style="color: #007f00; font-style: italic;">&quot;Start application workflow&quot;</span>
&nbsp;
    <span style="color: #7f007f;">self</span> inform: <span style="color: #7f0000;">'Start the game pushing the button below!!'</span>.
    <span style="">&#91;</span><span style="color: #7f007f;">self</span> initialize;
        isolate: <span style="">&#91;</span><span style="">&#91;</span><span style="color: #7f007f;">self</span> call: <span style="color: #7f007f;">self</span> form.
            <span style="color: #7f007f;">self</span> form number &lt; <span style="color: #7f007f;">self</span> number
                ifTrue: <span style="">&#91;</span><span style="color: #7f007f;">self</span> form message: <span style="color: #7f0000;">'Try a higher value'</span><span style="">&#93;</span>
                ifFalse: <span style="">&#91;</span><span style="color: #7f007f;">self</span> form message: <span style="color: #7f0000;">'Try a lower value'</span><span style="">&#93;</span><span style="">&#93;</span>
                doWhileFalse: <span style="">&#91;</span><span style="color: #7f007f;">self</span> form number <span style="color: #000066; font-weight:bold;">=</span> <span style="color: #7f007f;">self</span> number<span style="">&#93;</span><span style="">&#93;</span><span style="">&#93;</span>
        doWhileTrue: <span style="">&#91;</span><span style="color: #7f007f;">self</span> confirm: <span style="color: #7f0000;">'You won the game using '</span> , <span style="color: #7f007f;">self</span> form guesses asString , <span style="color: #7f0000;">' guess(es)!! Play again?'</span><span style="">&#93;</span></pre></div></div>

<p>Não tem mais código, não! É só envolver o trecho desejado em um bloco e passá-lo ao método <code>#isolate:</code>! <img src='http://weblog.destaquenet.com/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /> </p>
<h3>O resultado</h3>
<p>Confira abaixo algumas <em>screenshots</em> da aplicação em funcionamento:</p>

<a href='http://weblog.destaquenet.com/2008/09/30/seaside-um-framework-web-de-verdade/attachment/02/' title='Tela inicial'><img width="150" height="150" src="http://weblog.destaquenet.com/wp-content/uploads/2008/09/02-150x150.png" class="attachment-thumbnail" alt="Tela inicial" title="Tela inicial" /></a>
<a href='http://weblog.destaquenet.com/2008/09/30/seaside-um-framework-web-de-verdade/attachment/03/' title='Lendo o palpite do usuário'><img width="150" height="150" src="http://weblog.destaquenet.com/wp-content/uploads/2008/09/03-150x150.png" class="attachment-thumbnail" alt="Lendo o palpite do usuário" title="Lendo o palpite do usuário" /></a>
<a href='http://weblog.destaquenet.com/2008/09/30/seaside-um-framework-web-de-verdade/attachment/04/' title='Tela de acerto'><img width="150" height="150" src="http://weblog.destaquenet.com/wp-content/uploads/2008/09/04-150x150.png" class="attachment-thumbnail" alt="Tela de acerto" title="Tela de acerto" /></a>
<a href='http://weblog.destaquenet.com/2008/09/30/seaside-um-framework-web-de-verdade/attachment/05/' title='Back button não permitido após término do jogo'><img width="150" height="150" src="http://weblog.destaquenet.com/wp-content/uploads/2008/09/05-150x150.png" class="attachment-thumbnail" alt="Back button não permitido após término do jogo" title="Back button não permitido após término do jogo" /></a>

<p>O que há de errado com a última <em>screenshot</em>? Nada&#8230; é isso que acontece quando o usuário, após já ter adivinhado o número secreto, volta algumas telas com o botão <em>back</em> do <em>browser</em> e tenta re-submeter um formulário. Não cheguei a pesquisar, mas acredito que esta página seja customizável.</p>
<h3>Desafio</h3>
<p>Mesmo em uma aplicação simples como a que foi descrita aqui, fica evidente o quanto o Seaside é produtivo e simples (embora eu ainda não saiba usá-lo direito). <img src='http://weblog.destaquenet.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' /> </p>
<p>Portanto, proponho aos leitores deste <em>blog</em> que pensem no que deve ser feito para se criar uma aplicação <strong>igual</strong> (com as <strong>mesmas funcionalidades</strong>) a mostrada aqui (com a sua linguagem e <em>framework</em> preferidos). Tirando um ou outro, imagino que dê para contar nos dedos de uma só mão os <em>frameworks</em> capazes de fazer tanto com tão pouco. Enfim, sintam-se a vontade para expressar suas opiniões a respeito disso.</p>
<h3>Conclusão</h3>
<ul>
<li>Não precisei apelar para <em>frameworks</em> externos só para definir o <em>workflow</em> da aplicação;</li>
<li>Não precisei fazer gambiarras para controlar o estado da aplicação (lembrando que a aplicação <strong>suporta diversas instâncias</strong> do <em>browser</em> acessando a mesma aplicação <strong>concorrentemente</strong>);</li>
<li>Não precisei fazer gambiarras para tratar o botão <em>back</em> do <em>browser</em>;</li>
<li>Não precisei fazer gambiarras para que o código <acronym title="eXtended Hyper Text Markup Language">XHTML</acronym> gerado fosse válido;</li>
<li>Não precisei ficar reiniciando o servidor web ou fazendo <em>re-deploy</em> o tempo todo;</li>
<li>Não precisei pagar para conseguir um bom ambiente de desenvolvimento, pois o Squeak sozinho faz muito bem o serviço;</li>
</ul>
<p>É&#8230; acho que esses motivos já são o suficiente para que você dê uma olhada no Seaside. Se não for, santo Deus, o que mais você quer?! <img src='http://weblog.destaquenet.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://weblog.destaquenet.com/2008/09/30/seaside-um-framework-web-de-verdade/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

