<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

 <title>Dev blog af83 | This is the developers blog @ af83</title>
 <link href="http://dev.af83.com/atom.xml" rel="self"/>
 <link href="http://dev.af83.com/"/>
 <updated>2012-05-03T12:16:54+02:00</updated>
 <id>http://dev.af83.com/</id>

 
 <entry>
   <title type="html">Ruby tricks: Array syntax</title>
   <link href="http://dev.af83.com/2012/05/02/ruby-array-syntax.html"/>
   <updated>2012-05-02T00:00:00+02:00</updated>
   <id>http://dev.af83.com/2012/05/02/ruby-array-syntax</id>
   <author><name>chatgris</name><email>contact@af83.com</email></author>
   <content type="html">&lt;p&gt;How many times have you seen those ruby code examples?&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;my_array&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;present?&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;my_array&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Or the ternary version:&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;my_array&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;present?&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;my_array&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Or even the &amp;#39;or&amp;#39; version:&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;my_array&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;In those examples, a presence check is made on &lt;code&gt;my_array&lt;/code&gt;, otherwise, it will
return an empty list. It's valid ruby code, but there's a simpler way to
achieve that:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# Just:&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;my_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;With &lt;code&gt;nil&lt;/code&gt; or an empty array, &lt;a href=&quot;http://www.ruby-doc.org/core-1.9.3/Kernel.html#method-i-Array&quot;&gt;&lt;code&gt;Array&lt;/code&gt;&lt;/a&gt;
will return an empty array, and with an array of values, it will return the same array of values.&lt;/p&gt;

&lt;p&gt;It can also be used if you don't know if you have only one item or an array.
This syntax removes useless verifications, and always returns an array.&lt;/p&gt;

&lt;p&gt;Another nice trick is about &lt;code&gt;each&lt;/code&gt; and &lt;code&gt;map&lt;/code&gt; (and theirs aliases).&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# Calling save on all items in this collection&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;collections&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;save&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;The same result can be achieved this way&amp;nbsp;:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# Calling save on all items in this collection&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;collections&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:save&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
</content>
 </entry>
 
 <entry>
   <title type="html">Quelques conseils pour tenir bon lors d'une soirée électorale</title>
   <link href="http://dev.af83.com/2012/04/23/quelques-conseils-pour-tenir-bon-lors-d-une-soiree-electorale.html"/>
   <updated>2012-04-23T00:00:00+02:00</updated>
   <id>http://dev.af83.com/2012/04/23/quelques-conseils-pour-tenir-bon-lors-d-une-soiree-electorale</id>
   <author><name>Bruno Michel</name><email>contact@af83.com</email></author>
   <content type="html">&lt;p&gt;Comme vous le savez, hier s'est tenue la soirée électorale pour le premier
tour des élections présidentielles française. À cette occasion, j'étais dans
les locaux de France Télévisions avec l'équipe de rédaction dédiée à
l'information sur Internet. En effet, af83 a développé &lt;a href=&quot;http://www.francetv.fr/info/elections&quot;&gt;la plateforme de
résultats pour France Télévisions&lt;/a&gt; et
j'étais là pour parer à toute éventualité.&lt;/p&gt;

&lt;p&gt;Je profite donc de cette expérience pour vous donner quelques conseils pour
gérer ce genre de situations.&lt;/p&gt;

&lt;h2 id=&quot;toc_172&quot;&gt;1. La préparation&lt;/h2&gt;

&lt;p&gt;Il est important d'arriver bien préparé parce que vous pouvez être sûr qu'il va y avoir
des problèmes. Pas forcément des bugs graves, mais on va vous remonter des
problèmes. Je vous conseille donc de prendre un peu de temps pour réfléchir
aux problèmes qui pourraient vous arriver et prévoir un plan de secours pour
chacun.&lt;/p&gt;

&lt;p&gt;L'exemple typique est que le serveur web n'arrive plus à traiter les requêtes
assez vite. Pour cela, la réponse est tout aussi classique&amp;nbsp;: utiliser un
cache devant le serveur web (Varnish, Akamai, etc.) et pouvoir facilement
enclencher un code rouge, un mode dégradé qui va mettre tous les fichiers
principaux en cache avec un TTL très long. Le site va donc être bien moins
dynamique mais au moins, il s'affichera, vous laissant ainsi un peu de temps
pour trouver une meilleure solution.&lt;/p&gt;

&lt;p&gt;Cette préparation doit aussi se matérialiser sous la forme d'une documentation
sur l'administration et l'exploitation de l'application. On y trouvera, par
exemple, comment relancer les différents services et les conséquences
associées (est-ce que cela va entrainer un &lt;em&gt;downtime&lt;/em&gt;&amp;nbsp;?).&lt;/p&gt;

&lt;p&gt;Cette documentation va sûrement vous donner des séquences de commandes qui
vont bien ensemble&amp;nbsp;: aller dans tel répertoire, lancer telle commande pour
regénerer tel fichier puis flusher Varnish. Dans ces cas là, il est souvent
intéressant de se préparer un moyen pour lancer la séquence en une commande
(script ruby, alias ou fonction shell, etc.). Ça vous fera gagner un peu de
temps, mais surtout ça vous évitera d'oublier une étape dans la séquence ou de
la faire dans le mauvais ordre…&lt;/p&gt;

&lt;h2 id=&quot;toc_173&quot;&gt;2. L'action&lt;/h2&gt;

&lt;p&gt;La préparation est importante, mais même en étant très bien préparé, on n'est
pas à l'abri d'une mauvaise surprise. À ce moment là, il est important de garder
la tête froide. Il est très tentant de vouloir corriger le plus vite possible
le problème, quitte à coder directement sur les serveurs de production. Et
pourtant ce n'est pas une bonne idée&amp;nbsp;: vous risquez d'aggraver la situation.&lt;/p&gt;

&lt;p&gt;Une fausse commande est très vite arrivée. Des exemples&amp;nbsp;? Oublier le &lt;code&gt;WHERE&lt;/code&gt;
d'une commande SQL&amp;nbsp;? Vous avez modifié le mot de passe de tous les
utilisateurs. Une variable mal initialisée&amp;nbsp;? Vous venez d'écraser un fichier
très important. Remonter l'historique du shell et prendre la mauvaise commande
? Vous êtes bon pour refaire cet import de données qui prend 3h. Bref, si vous
cédez à la panique, vous aurez à peu près autant de chances d'améliorer le
service que l'empirer.&lt;/p&gt;

&lt;p&gt;Il convient donc de garder son calme, de respirer un grand coup et de tester
sur un autre environnement les modifications que vous allez faire. Puis, quand
vous serez connecté sur les serveurs de production, prenez deux secondes avant
d'appuyer sur Entrée. Ce n'est pas parce que des gens courent dans tous les
sens les bras levés que vous devez faire n'importe quoi. Là, plus que jamais,
il convient de prendre un peu de recul.&lt;/p&gt;

&lt;p&gt;Essayez aussi de vous protéger. Par exemple, si vous allez modifier un
fichier, faites une copie du fichier avant. Si vous lancez un script qui va
régénerer une page HTML, appelez d'abord l'URL de cette page pour qu'elle soit
dans le cache, ce qui vous laissera un peu de temps pour vérifier le fichier
généré avant qu'il ne soit en ligne. Et s'il n'est pas bon, vous avez fait une
copie, non&amp;nbsp;? Si vous devez refaire un import, est-ce que vous pouvez le faire
sur un autre serveur et juste importer un dump SQL ou un tarball des fichiers
mis à jour&amp;nbsp;? Bref, limitez ce qui pourrait mal se passer.&lt;/p&gt;

&lt;p&gt;Dernière chose, soyez concentré. À partir du moment où vous commencez à avoir
une demande, vous allez très rapidement en avoir d'autres. Et vous allez donc
essayer de les traiter en même temps. Ce script va au moins prendre 30
secondes, j'ai le temps d'aller jeter un coup d'oeil au code source pour cet
autre bug&amp;nbsp;: c'est une très mauvaise idée. Faire du multi-tâches est le meilleur
moyen pour faire des erreurs.&lt;/p&gt;

&lt;h2 id=&quot;toc_174&quot;&gt;TL;DR&lt;/h2&gt;

&lt;p&gt;Pour résumer, soyez bien préparé, ne cédez pas à la panique, gardez la tête
froide, vérifiez plutôt deux fois qu'une tout ce que vous faites sur le
serveur et ne faites qu'une seule chose à la fois. Ces conseils ne sont que
des conseils, pas une méthode magique pour éviter tout problème. Mais ils
devraient vous aider à réduire fortement les ennuis.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title type="html">Gem money</title>
   <link href="http://dev.af83.com/2012/04/11/gemmoney.html"/>
   <updated>2012-04-11T00:00:00+02:00</updated>
   <id>http://dev.af83.com/2012/04/11/gemmoney</id>
   <author><name>Laurent Arnoud</name><email>contact@af83.com</email></author>
   <content type="html">&lt;p&gt;Money est une gem qui sert à gérer les devises en Ruby. Elle est utilisée
notamment par shopify pour activemerchant.&lt;/p&gt;

&lt;p&gt;Elle permet de faire des comparaisons de devises, de créer des objets Money
simplement et de les convertir avec des taux soit saisis manuellement, soit
avec une autre gem qui le fait pour vous.&lt;/p&gt;

&lt;p&gt;Par défaut, elle ne gère pas les taux de conversion, mais la page du
&lt;a href=&quot;https://github.com/RubyMoney/money&quot;&gt;projet&lt;/a&gt; liste plusieurs gems que vous
pourrez utilisez pour ça. Je vais vous parler de
&lt;a href=&quot;https://github.com/spk/money-open-exchange-rates&quot;&gt;money-open-exchange-rates&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;L'avantage de cette dernière, c'est qu'elle utilise le JSON mis à jour toute les
heures par le &lt;a href=&quot;http://currencybot.github.com/&quot;&gt;currencybot&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;La gem reprend pratiquement la même base de code que
&lt;a href=&quot;https://github.com/RubyMoney/eu_central_bank&quot;&gt;eu_central_bank&lt;/a&gt; mais en
utilisant le JSON du projet
&lt;a href=&quot;http://openexchangerates.org/latest.json&quot;&gt;open-exchange-rates&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Nous avons donc, grâce à
&lt;a href=&quot;http://josscrowcroft.github.com/open-exchange-rates/&quot;&gt;open-exchange-rates&lt;/a&gt;,
accès aux taux de plus de 158 devises au lieu des 32 de la gem
&lt;a href=&quot;https://github.com/RubyMoney/eu_central_bank&quot;&gt;eu_central_bank&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title type="html">Écrire un service web en C</title>
   <link href="http://dev.af83.com/2012/04/11/ecrire-un-service-web-en-c.html"/>
   <updated>2012-04-11T00:00:00+02:00</updated>
   <id>http://dev.af83.com/2012/04/11/ecrire-un-service-web-en-c</id>
   <author><name>Arnaud Berthomier</name><email>contact@af83.com</email></author>
   <content type="html">&lt;p&gt;Récemment Bruno expliquait comment &lt;a href=&quot;http://dev.af83.com/2012/04/07/ecrire-un-service-web-en-golang.html&quot;&gt;utiliser Go pour écrire des services
web&lt;/a&gt;. Go est un langage puissant, conçu autant pour les
performances, que pour faciliter la vie des développeurs. Je vous
conseille de relire ses deux premiers articles sur le sujet, &lt;a href=&quot;http://dev.af83.com/2012/04/02/premiers-pas-avec-golang.html&quot;&gt;le
premier&lt;/a&gt; vous donnera les bases, et le &lt;a href=&quot;http://dev.af83.com/2012/04/07/ecrire-un-service-web-en-golang.html&quot;&gt;second&lt;/a&gt; vous
donnera envie d'en savoir plus.&lt;/p&gt;

&lt;p&gt;Néanmoins, en y repensant, je me suis demandé à quoi pourrait ressembler
un service web équivalent écrit en C. Faire du web en C est une idée
saugrenue et dangereuse dans (presque) tous les cas. Enfin, si le
langage lui même est moins amical que Go, il a derrière lui les années
de développeurs barbus, et il lui reste encore de beaux jours…&amp;nbsp;:)&lt;/p&gt;

&lt;p&gt;Il y a mille manières de faire du web en C. Pour aller au plus vite,
j'ai pris le parti d'utiliser &lt;a href=&quot;https://github.com/AlexBio/Tofu&quot;&gt;Tofu&lt;/a&gt; d'Alessandro Ghedini.
Le projet est récent, purement expérimental, mais démontre le type d'API
que peut proposer une bibliothèque C pour des applications web.&lt;/p&gt;

&lt;p&gt;Tofu est un projet qui me semble intéressant dans la mesure où il
supporte plusieurs backends, pour n'en citer que deux&amp;nbsp;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.zeromq.org/&quot;&gt;zmq&lt;/a&gt;, qui lui permet de tourner derrière un certain
&lt;a href=&quot;http://mongrel2.org/&quot;&gt;mongrel2&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;ou, plus simplement, la &lt;a href=&quot;http://libevent.org/&quot;&gt;libevent&lt;/a&gt;, qu'on va sagement
utiliser pour notre petit PoC.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Dans d'autres contextes que celui-ci, ce ne serait donc pas une brique
monolithique déterminant toute une architecture, mais bien un élément
qui pourrait s'intégrer avec d'autres. C'est un détail qui mérite d'être
souligné.&lt;/p&gt;

&lt;p&gt;Nous allons construire un service HTTP simplissime. Ce dernier va
répondre sur une URL du type &lt;code&gt;http://server/hello/af83&lt;/code&gt;, avec le JSON
&lt;code&gt;{&amp;quot;hello&amp;quot;: &amp;quot;af83&amp;quot;}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Commençons par créer un fichier &lt;code&gt;hello.c&lt;/code&gt;. Pour utiliser les fonctions
de Tofu, on doit inclure le header &lt;code&gt;tofu.h&lt;/code&gt;, et pour parler JSON sans
bégayer, &lt;code&gt;jansson.h&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;c&quot;&gt;&lt;span class=&quot;cp&quot;&gt;#include &amp;lt;tofu.h&amp;gt;&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#include &amp;lt;jansson.h&amp;gt;&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;argc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Pour récupérer la dernière version de Tofu, un rapide &lt;code&gt;git clone
&lt;a href=&quot;https://github.com/AlexBio/Tofu.git&quot;&gt;https://github.com/AlexBio/Tofu.git&lt;/a&gt;&lt;/code&gt; devra faire l'affaire. Après quoi
il faudra suivre le &lt;a href=&quot;https://github.com/AlexBio/Tofu#readme&quot;&gt;README&lt;/a&gt; de la bibliothèque pour la
compiler avec vos petites mimines, et finalement soit l'installer sur
votre système, soit jouer avec les flags &lt;code&gt;-I&lt;/code&gt; et &lt;code&gt;-L&lt;/code&gt; de gcc pour linker
votre programme…&lt;/p&gt;

&lt;p&gt;C'est là qu'un outil comme &lt;code&gt;go get&lt;/code&gt; nous faciliterait bien la vie&amp;nbsp;!&lt;/p&gt;

&lt;p&gt;Pour initialiser Tofu, dans notre fonction &lt;code&gt;main&lt;/code&gt;, on fera&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;c&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// Initialise le serveur HTTP sur le port TCP 8080.&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;opts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;0.0.0.0&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;8080&amp;quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;tofu_ctx_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tofu_ctx_init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TOFU_EVHTTP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;opts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Lance le serveur HTTP, et bloque le programme.&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;tofu_loop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Si vous compilez votre programme en l'état, vous obtiendrez un serveur
HTTP des plus inutiles qui ne répondra que par des erreurs 404 quelle
que soit l'URL accédée. C'est pas encore ça.&lt;/p&gt;

&lt;p&gt;Tofu permet d'assigner des callbacks à des URL statiques, ou
dynamiques. Dans cet exemple, on aimerait, lorsqu'on accède à
&lt;code&gt;/hello/af83&lt;/code&gt;, obtenir le JSON &lt;code&gt;{&amp;quot;hello&amp;quot;: &amp;quot;af83&amp;quot;}&lt;/code&gt;. On peut d'ores et
déjà relier l'URL attendue à une tierce fonction en utilisant
&lt;code&gt;tofu_handle_with&lt;/code&gt;&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;c&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// à placer *avant* l&amp;#39;appel bloquant à tofu_loop, hein ;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;tofu_handle_with&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;/hello/:name&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hello&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Pour répondre sur cette URL, il nous faut définir le callback &lt;code&gt;hello&lt;/code&gt;
mentionné dans le code. Il doit renvoyer un pointeur du type
&lt;code&gt;tofu_rep_t&lt;/code&gt;, et accepter deux arguments&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;c&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// voilà un callback &amp;quot;hello&amp;quot; minimal...&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;tofu_rep_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;hello&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tofu_req_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;tofu_rep_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rep&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tofu_rep_init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Notre serveur HTTP ne renvoie plus d'erreur 404 sur &lt;code&gt;/hello/af83&lt;/code&gt;, mais
répond avec &lt;em&gt;rien&lt;/em&gt;, ce qui est bien mais pas top. Pour bien faire, on va
récupérer le paramètre &lt;code&gt;name&lt;/code&gt; qu'on a créé avec &lt;code&gt;tofu_handle_with&lt;/code&gt;&amp;nbsp;: Tofu
a le bon goût de fournir &lt;code&gt;tofu_param&lt;/code&gt; pour ça.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;c&quot;&gt;&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;param&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tofu_param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;On pourrait alors construire une réponse JSON «&amp;nbsp;à la main&amp;nbsp;» avec les
informations qu'on a récupérées. Mais pourquoi se priver d'utiliser la
lib &lt;a href=&quot;http://www.digip.org/jansson/doc/&quot;&gt;Jansson&lt;/a&gt; qui sait échapper les caractères spéciaux, et
construire du JSON propre&amp;nbsp;?&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;c&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// `obj` est un objet JSON vide, soit : {}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;json_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;json_object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// obj a désormais une clef &amp;quot;hello&amp;quot;, qui reprend la valeur de param.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Par exemple: {&amp;quot;hello&amp;quot;: &amp;quot;af83&amp;quot;}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;json_object_set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;hello&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;json_string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// `json_dumps` encode `obj` pour en faire une chaîne de caractères.&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reply&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;json_dumps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;JSON_ENSURE_ASCII&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Il nous reste à mettre tout ça en forme pour répondre, à l'aide de
&lt;code&gt;tofu_head&lt;/code&gt;, et de &lt;code&gt;tofu_write&lt;/code&gt;. L'exemple complet est disponible sur un
&lt;a href=&quot;https://gist.github.com/2355431&quot;&gt;Gist&lt;/a&gt;. Si vous êtes assez curieux pour y jeter un œil,
vous vous rendrez compte qu'en à peine quelques lignes de C, on peut
faire pas mal de choses…&lt;/p&gt;

&lt;p&gt;Ce court billet pourrait illustrer une question que se posent souvent
les développeurs (du moins on l'espère)&amp;nbsp;: est-ce que j'utilise le bon
outil pour ce boulot&amp;nbsp;?&lt;/p&gt;

&lt;p&gt;Le C par exemple est un langage formidable pour écrire des programmes
qu'on dit de «&amp;nbsp;bas-niveau&amp;nbsp;» (un serveur DNS, un kernel, une machine
virtuelle, …), Go en est un autre. Pour du web en revanche, vous serez
beaucoup mieux servis par des langages dynamiques comme Ruby, ou
Javascript. S'il est donc facile (et surtout divertissant&amp;nbsp;:p) d'écrire
des petites applications web comme celle-ci en C, ça n'est que rarement
souhaitable.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title type="html">Écrire un service web en Go</title>
   <link href="http://dev.af83.com/2012/04/07/ecrire-un-service-web-en-golang.html"/>
   <updated>2012-04-07T00:00:00+02:00</updated>
   <id>http://dev.af83.com/2012/04/07/ecrire-un-service-web-en-golang</id>
   <author><name>Bruno Michel</name><email>contact@af83.com</email></author>
   <content type="html">&lt;p&gt;Après avoir fait &lt;a href=&quot;/2012/04/02/premiers-pas-avec-golang.html&quot;&gt;nos premiers pas avec
Go&lt;/a&gt;, il est temps de passer à
l'écriture d'un vrai programme. Je vous propose de faire un service web
vraiment simple&amp;nbsp;: il reçoit des requêtes HTTP et y répond un Hello world en
JSON.&lt;/p&gt;

&lt;p&gt;Commençons par créer un fichier &lt;code&gt;hello.go&lt;/code&gt;. Tout fichier contenant du code Go
doit indiquer de quel &lt;em&gt;package&lt;/em&gt; il fait partie. Dans notre cas, nous allons
utiliser le package &lt;code&gt;main&lt;/code&gt;, qui est un package particulier&amp;nbsp;: la fonction
&lt;code&gt;main&lt;/code&gt; définie dans ce package sera exécutée lorsque l'on lance le programme.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;go&quot;&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Ensuite, nous importons deux packages provenant de la bibliothèque standard de
Go&amp;nbsp;: &lt;code&gt;io&lt;/code&gt; et &lt;code&gt;net/http&lt;/code&gt;. Le premier sert pour toutes les opérations
d'entrées/sorties et le second pour faire des clients et des serveurs HTTP.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;go&quot;&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&amp;quot;io&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&amp;quot;net/http&amp;quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Nous avons indiqué plus haut que la fonction &lt;code&gt;main&lt;/code&gt; de notre package serait
exécutée au lancement du programme… Il est temps de l'écrire. En go, la
déclaration d'une fonction se fait avec le mot clé &lt;code&gt;func&lt;/code&gt; et la syntaxe
ressemble au C ou au JavaScript&amp;nbsp;: les arguments sont listés entre parenthèses,
et le corps de la fonction entre accolades.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;go&quot;&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Le corps de la fonction&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Dans notre cas, nous voulons faire deux choses dans la fonction &lt;code&gt;main&lt;/code&gt;&amp;nbsp;:
démarrer un serveur HTTP et lui dire que l'on reçoit une requête - celle-ci
devra être traitée par la fonction &lt;code&gt;HelloWorld&lt;/code&gt;. Le &lt;a href=&quot;http://golang.org/pkg/net/http/&quot;&gt;module
&lt;code&gt;net/http&lt;/code&gt;&lt;/a&gt; nous fournit de quoi faire cela
simplement en deux lignes&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;go&quot;&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HandleFunc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HelloWorld&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ListenAndServe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;127.0.0.1:8000&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Il ne reste plus qu'à écrire la fonction &lt;code&gt;HelloWorld&lt;/code&gt;. Pour le moment, nous
allons renvoyer une chaîne de caractères en dur, la version évoluée sera pour
plus tard. Les chaînes de caractères peuvent être délimitées par des &lt;em&gt;doubles
quotes&lt;/em&gt; ou par des &lt;em&gt;backquotes&lt;/em&gt;. Nous allons préférer la seconde forme pour
pouvoir mettre facilement des doubles quotes à l'intérieur&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;go&quot;&gt;&lt;span class=&quot;s&quot;&gt;`{&amp;quot;hello&amp;quot;:&amp;quot;world&amp;quot;}`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Mais revenons à notre fonction &lt;code&gt;HelloWorld&lt;/code&gt;. Pour être compatible avec le
module &lt;code&gt;net/http&lt;/code&gt;, elle doit prendre deux paramètres, le premier étant du type
&lt;code&gt;http.ResponseWriter&lt;/code&gt; et le second du type &lt;code&gt;*http.Request&lt;/code&gt; (la petite étoile
sert à indiquer que c'est un pointeur). Les personnes qui ont fait du C
ou du Java risquent d'être surprises mais, en Go, le type vient toujours après
le nom de la variable.&lt;/p&gt;

&lt;p&gt;À l'intérieur de notre fonction, nous allons simplement utiliser
&lt;code&gt;io.WriteString&lt;/code&gt; pour écrire la réponse dans le &lt;code&gt;http.ResponseWriter&lt;/code&gt;&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;go&quot;&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HelloWorld&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ResponseWriter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;req&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;WriteString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;`{&amp;quot;hello&amp;quot;:&amp;quot;world&amp;quot;}`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Voilà, nous avons un programme fonctionnel. Il peut se lancer avec &lt;code&gt;go run
hello.go&lt;/code&gt; (ça compile le programme puis exécute la version compilée). Et on
peut vérifier avec &lt;code&gt;curl&lt;/code&gt; qu'il fonctionne&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;% curl -v &lt;a href=&quot;http://localhost:8000/&quot;&gt;http://localhost:8000/&lt;/a&gt;
* About to connect() to localhost port 8000 (#0)
*   Trying 127.0.0.1... connected
* Connected to localhost (127.0.0.1) port 8000 (#0)
&amp;gt; GET / HTTP/1.1
&amp;gt; User-Agent: curl/7.21.6 (i686-pc-linux-gnu) libcurl/7.21.6 OpenSSL/1.0.0e zlib/1.2.3.4
&amp;gt; Host: localhost:8000
&amp;gt; Accept: */*
&amp;gt;
&amp;lt; HTTP/1.1 200 OK
&amp;lt; Date: Sat, 07 Apr 2012 18:35:14 GMT
&amp;lt; Transfer-Encoding: chunked
&amp;lt; Content-Type: text/plain; charset=utf-8
&amp;lt;
* Connection #0 to host localhost left intact
* Closing connection #0
{&amp;quot;hello&amp;quot;:&amp;quot;world&amp;quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Maintenant que vous avez pu constater qu'il est très facile de créer un
serveur HTTP en Go, nous allons voir comment l'améliorer et ainsi découvrir de
nouvelles fonctionnalités de Go. Il pourrait par exemple être pratique de
pouvoir spécifier l'interface et le port sur lequel notre serveur écoute.&lt;/p&gt;

&lt;p&gt;Pour extraire des arguments de la ligne de commande, la bibliothèque standard
de Go propose le module &lt;code&gt;flag&lt;/code&gt;. Nous allons déclarer une variable &lt;code&gt;addr&lt;/code&gt; de
type &lt;code&gt;string&lt;/code&gt;, puis utiliser le module flag pour la remplir à partir de la
ligne de commande ou, à défaut, avec une valeur par défaut. Cela donne ces
quelques lignes&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;go&quot;&gt;&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;addr&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StringVar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;addr&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;127.0.0.1:8000&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;Bind to this address:port&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ListenAndServe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Nous pouvons maintenant compiler notre programme et le lancer en lui passant
l'option &lt;code&gt;-addr&lt;/code&gt;. Au passage, notez que notre programme dispose aussi de
l'option &lt;code&gt;-h&lt;/code&gt; pour afficher l'aide&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;% go build hello.go
% ./hello -h
Usage of ./hello:
  -addr=&amp;quot;127.0.0.1:8000&amp;quot;: Bind to this address:port
% ./hello -addr=:7000
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Étape suivante&amp;nbsp;: la gestion des erreurs. La fonction &lt;code&gt;ListenAndServe&lt;/code&gt; peut
échouer pour différentes raisons. Si on lance notre programme en simple
utilisateur en lui demandant d'écouter sur un port inférieur à 1024, cet appel
échouera parce que nous n'avons pas les droits suffisants.&lt;/p&gt;

&lt;p&gt;En go, la gestion des erreurs se fait principalement en retournant une erreur
ou &lt;code&gt;nil&lt;/code&gt; quand tout va bien. Nous allons utiliser le module &lt;code&gt;log&lt;/code&gt; (n'oubliez
pas de l'ajouter à l'&lt;code&gt;import&lt;/code&gt;) pour afficher l'erreur et mettre fin au
programme&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;go&quot;&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ListenAndServe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Fatal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;ListenAndServe: &amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Cela donne cette sortie&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;% ./hello -addr=:1
2012/04/07 20:51:21 ListenAndServe: listen tcp &amp;lt;nil&amp;gt;:1: permission denied
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Il nous reste encore deux choses à voir&amp;nbsp;: la première est de remplacer la
chaîne de caractères en dur qui représente le JSON et la seconde de faire du
routage dynamique sur les URL. Pour le JSON, la bibliothèque standard de Go
répond une fois de plus à nos attentes en fournissant un &lt;a href=&quot;http://golang.org/pkg/encoding/json/&quot;&gt;module
&lt;code&gt;encoding/json&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Mais avant de l'utiliser, nous allons voir comment déclarer un nouveau type.
Nous allons créer un type &lt;code&gt;Response&lt;/code&gt; qui permettra d'avoir notre réponse sous
forme structurée avant d'être encodée en JSON. Le mot-clé &lt;code&gt;type&lt;/code&gt; prend d'abord
le nom du nouveau type puis la définition du type. Cette définition peut être
un type simple, comme &lt;code&gt;int&lt;/code&gt;, ou un type composé. Dans notre cas, ce sera un
&lt;code&gt;struct&lt;/code&gt; avec un seul champ&amp;nbsp;: &lt;code&gt;Hello&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;go&quot;&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Response&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Hello&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Nous modifions maintenant notre fonction &lt;code&gt;HelloWorld&lt;/code&gt; pour créer une variable
de type &lt;code&gt;Response&lt;/code&gt; puis l'encoder en JSON&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;go&quot;&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HelloWorld&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ResponseWriter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;req&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Response&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Hello&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;world&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Marshal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;WriteString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Notons que les fonctions en Go peuvent renvoyer plusieurs éléments. C'est le
cas de la fonction &lt;code&gt;json.Marshall&lt;/code&gt; qui renvoie un tableau de bytes et une
erreur. C'est très pratique car cela évite de devoir faire comme en C pour un
retour qui peut à la fois être le résultat de la fonction et indiquer une erreur.&lt;/p&gt;

&lt;p&gt;Quand une erreur se présente, nous la traitons en renvoyant une erreur 500
avec le message de l'erreur grâce à la fonction &lt;code&gt;http.Error&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;D'autre part, &lt;code&gt;WriteString&lt;/code&gt; attend en deuxième paramètre une chaîne de
caractères, pas un tableau de bytes. Nous faisons donc la conversion avec
&lt;code&gt;string(b)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Nous pouvons donc passer à la dernière évolution de notre programme&amp;nbsp;: gérer
des URL dynamiques. Plutôt que de répondre toujours Hello world, nous
pourrions passer le nom en paramètre dans l'URL. Par exemple, un GET sur
&lt;code&gt;/hello/Bruno&lt;/code&gt; renverrait &lt;code&gt;{&amp;quot;Hello&amp;quot;:&amp;quot;Bruno&amp;quot;}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Pour cela, nous utilisons un module externe,
&lt;a href=&quot;https://github.com/bmizerany/pat&quot;&gt;pat&lt;/a&gt;, écrit par Keith Rarick et Blake
Mizerany (si ce nom vous est familier, c'est probablement car il est aussi
l'auteur de &lt;a href=&quot;http://www.sinatrarb.com/&quot;&gt;Sinatra&lt;/a&gt;). Go permet d'utiliser très
simplement des modules provenant de diverses sources. L'installation du module
se fait d'un simple appel à &lt;code&gt;go get github.com/bmizerany/pat&lt;/code&gt;. Ensuite, nous
pouvons importer notre module en l'ajoutant à la liste des &lt;code&gt;import&lt;/code&gt;s&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;go&quot;&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&amp;quot;encoding/json&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&amp;quot;flag&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&amp;quot;github.com/bmizerany/pat&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&amp;quot;io&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&amp;quot;log&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&amp;quot;net/http&amp;quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Nous déclarons ensuite notre route dans la fonction &lt;code&gt;main&lt;/code&gt;, à la place du
&lt;code&gt;http.HandleFunc&lt;/code&gt;&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;go&quot;&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;/hello/:name&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HandlerFunc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HelloWorld&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Handle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Et il ne reste plus qu'à récupérer le paramètre &lt;code&gt;:name&lt;/code&gt; dans la fonction
&lt;code&gt;HelloWorld&lt;/code&gt; et à l'injecter dans notre variable &lt;code&gt;response&lt;/code&gt;&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;go&quot;&gt;&lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Hello&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;URL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Query&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;:name&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Et voilà, nous pouvons maintenant tester le tout&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;$ go run hello.go -addr=:7000
$ curl &lt;a href=&quot;http://localhost:7000/hello/Bruno&quot;&gt;http://localhost:7000/hello/Bruno&lt;/a&gt;
{&amp;quot;Hello&amp;quot;:&amp;quot;Bruno&amp;quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;J'espère que ce billet vous aura permis d'apprécier la simplicité de Go et
vous aura donné envie d'aller plus loin avec. En attendant, vous pouvez
consulter le code complet sur &lt;a href=&quot;https://gist.github.com/2332143&quot;&gt;ce gist&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title type="html">Faire ses premiers pas avec Go</title>
   <link href="http://dev.af83.com/2012/04/02/premiers-pas-avec-golang.html"/>
   <updated>2012-04-02T00:00:00+02:00</updated>
   <id>http://dev.af83.com/2012/04/02/premiers-pas-avec-golang</id>
   <author><name>Bruno Michel</name><email>contact@af83.com</email></author>
   <content type="html">&lt;p&gt;On entend régulièrement parler de langages de programmation qui sont présentés
comme des remplaçants du bon vieux C… Go est l'un de ces langages.
Initialement commencé comme un projet interne à Google par une équipe
notamment composée de &lt;a href=&quot;http://fr.wikipedia.org/wiki/Rob_Pike&quot;&gt;Rob Pike&lt;/a&gt; et
&lt;a href=&quot;http://fr.wikipedia.org/wiki/Ken_Thompson&quot;&gt;Ken Thomson&lt;/a&gt; (excusez du peu), il
a rapidement dépassé ce cadre et est maintenant soutenu par une importante communauté
Open-Source.&lt;/p&gt;

&lt;p&gt;La sortie d'une première version stable, Go 1, va permettre à de nombreux
développeurs d'envisager plus facilement l'utilisation de Go au regard des
contraintes de production. Ça ne veut pas dire que le langage n'était pas
utilisé en production jusque là, mais ses évolutions engendraient un coût pour maintenir les
applications. D'ailleurs, Go peut d'ores
et déjà se prévaloir de quelques très belles références&amp;nbsp;: Google utilise Go au
coeur de l'infrastructure de Youtube, sous la forme d'un proxy/multiplexer SQL
nommé &lt;a href=&quot;http://code.google.com/p/vitess/&quot;&gt;vitess&lt;/a&gt; (publié sous licence BSD). On
peut également citer Heroku, Canonical et
&lt;a href=&quot;http://go-lang.cat-v.org/organizations-using-go&quot;&gt;d'autres&lt;/a&gt; qui font confiance
à Go pour des services importants de leurs infrastructures.&lt;/p&gt;

&lt;p&gt;Ces exemples montrent que Go peut effectivement s'avancer comme un
successeur du C, mais il serait trompeur de croire qu'il va entièrement
remplacer le C et tous ses cas d'usage. Typiquement, je ne pense pas que Go
soit particulièrement intéressant pour développer le noyau d'un système
d'exploitation ou faire des systèmes embarqués avec des contraintes temps-réel
et des ressources fortement limitées. Par contre, Go me paraît être
extrêmement pertinent pour faire des daemons réseaux ou des services nécessitant
fiabilité et performances&amp;nbsp;; en particulier, la combinaison des &lt;em&gt;goroutines&lt;/em&gt; et
&lt;em&gt;channels&lt;/em&gt; semble très efficace pour construire des systèmes concurrents sans
s'arracher les cheveux.&lt;/p&gt;

&lt;p&gt;Mais le mieux est encore de vous montrer ce à quoi ressemblent des programmes
en Go. Après tout, le titre de ce billet est «&amp;nbsp;Faire ses premiers pas avec Go&amp;nbsp;»…&lt;/p&gt;

&lt;p&gt;La première étape consiste à &lt;a href=&quot;http://golang.org/doc/install&quot;&gt;installer Go&lt;/a&gt;. Si
vous utilisez une distribution Linux, il y a fort à parier qu'elle fournit des
paquets pour Go (c'est le cas d'&lt;a href=&quot;https://wiki.ubuntu.com/Go&quot;&gt;Ubuntu&lt;/a&gt; par
exemple). Dans le cas contraire, pas d'inquiétude, vous pourrez trouver des
&lt;a href=&quot;http://code.google.com/p/go/downloads/list&quot;&gt;exécutables&lt;/a&gt; pour Windows, Linux,
OSX et FreeBSD, ainsi que &lt;a href=&quot;http://golang.org/doc/install/source&quot;&gt;les sources&lt;/a&gt;.
Et pour finir l'installation, il faudra définir quelques variables
d'environnement (à ajouter à &lt;code&gt;~/.zshrc&lt;/code&gt; si vous utilisez zsh, ou son équivalent
si vous utilisez un autre shell)&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;GOROOT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;/usr/lib/go&amp;quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;GOPATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;$HOME/go&amp;quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;$PATH:$GOPATH/bin:$GOROOT/bin&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;La première variable, &lt;code&gt;GOROOT&lt;/code&gt;, sert aux outils de compilation pour savoir où
Go est installé (notamment la bibliothèque standard). Par défaut, cela
devrait être &lt;code&gt;/usr/local/go&lt;/code&gt; mais, dans mon cas, le paquet Ubuntu a installé
ça dans &lt;code&gt;/usr/lib/go&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Ensuite, vient &lt;code&gt;GOPATH&lt;/code&gt;. Cette variable va permettre d'aller chercher le code
de diverses bibliothèques pour la compilation. Le premier répertoire listé
joue un rôle particulier&amp;nbsp;: il accueillera les bibliothèques installées avec la
commande &lt;code&gt;go install&lt;/code&gt; (je n'en dirais pas plus aujourd'hui, cela mérite un
billet de blog à part).&lt;/p&gt;

&lt;p&gt;Enfin, on ajoute nos chemins au &lt;code&gt;$PATH&lt;/code&gt; pour pouvoir lancer les commandes Go
sans avoir à taper les chemins complets.&lt;/p&gt;

&lt;p&gt;L'étape suivante consiste à configurer son éditeur de texte favori. Vous avez
le droit de sauter ce passage mais, pour moi, prendre 5 minutes pour faire
cela permet de gagner bien plus de temps ensuite. Pour Vim, cela peut se
limiter à ajouter ces 3 lignes à son &lt;code&gt;~/.vimrc&lt;/code&gt; dans un premier temps&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;vim&quot;&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;rtp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;+=&lt;/span&gt;$GOROOT&lt;span class=&quot;sr&quot;&gt;/misc/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;vim&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;filetype&lt;/span&gt; plugin indent &lt;span class=&quot;k&quot;&gt;on&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;syntax&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;on&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Comme vous pouvez le constater, Go est fourni de base avec des plugins pour
différents outils. Vous pouvez en faire le tour dans le répertoire
&lt;code&gt;$GOROOT/misc&lt;/code&gt;. Et pour aller plus loin,
&lt;a href=&quot;http://go-lang.cat-v.org/text-editors/&quot;&gt;http://go-lang.cat-v.org/text-editors/&lt;/a&gt; est une ressource incontournable.&lt;/p&gt;

&lt;p&gt;Il est maintenant temps de tester notre installation avec le très célèbre
Hello World. Nous allons donc créer un fichier &lt;code&gt;hello.go&lt;/code&gt; avec les 5 lignes
suivantes&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;go&quot;&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;fmt&amp;quot;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;Hello world\n&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Puis, nous allons compiler et lancer le programme en une seule commande&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;go run hello.go
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Si vous voyez &lt;code&gt;Hello world&lt;/code&gt;, félicitations, votre installation de Go
fonctionne et vous avez fait tourner votre premier programme dans ce langage.
Pour continuer, je vous conseille de faire &lt;a href=&quot;http://code.google.com/p/go-tour/&quot;&gt;Le tour de
Go&lt;/a&gt; ou de passer à &lt;a href=&quot;/2012/04/07/ecrire-un-service-web-en-golang.html&quot;&gt;l'écriture d'un service
web en Go&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title type="html">Les espaces insécables pour les codeurs</title>
   <link href="http://dev.af83.com/2012/03/20/les-espaces-insecables-pour-les-codeurs.html"/>
   <updated>2012-03-20T00:00:00+01:00</updated>
   <id>http://dev.af83.com/2012/03/20/les-espaces-insecables-pour-les-codeurs</id>
   <author><name>Bruno Michel</name><email>contact@af83.com</email></author>
   <content type="html">&lt;p&gt;Il m'est arrivé une mésaventure avec les espaces insécables. Ce n'est pas la
première fois, mais à chaque fois, je me dis que je ne me laisserais plus
avoir.&lt;/p&gt;

&lt;p&gt;Commençons par le début&amp;nbsp;: qu'est-ce qu'une espace insécable&amp;nbsp;? C'est un
caractère qui s'affiche comme une espace normale mais qui empêche de faire un
retour à la ligne à cet endroit. Par exemple, en bon français, on met une
espace insécable avant des «&amp;nbsp;:&amp;nbsp;», et ainsi ceux-ci se trouvent attachés avec
le mot juste avant et ne peuvent pas se retrouver en début de ligne. Je vous
conseille la lecture de &lt;a href=&quot;http://fr.wikipedia.org/wiki/Espace_ins%C3%A9cable&quot;&gt;l'article wikipédia sur ce
sujet&lt;/a&gt; si vous souhaitez
en savoir plus.&lt;/p&gt;

&lt;p&gt;En pratique, il est facile d'en mettre dans du HTML&amp;nbsp;: c'est la fameuse entité
&lt;code&gt;&amp;amp;nbsp;&lt;/code&gt; (pour &lt;em&gt;non-breaking space&lt;/em&gt;). Les traitements de texte savent aussi
les insérer au bon endroit pour vous. Et il est possible d'en insérer
manuellement avec une combinaison du clavier, qui dépend du système
d'exploitation et de la disposition du clavier. Sous GNU/Linux, la combinaison
souvent utilisée pour ça est &lt;code&gt;Alt gr&lt;/code&gt; + &lt;code&gt;espace&lt;/code&gt;. Ainsi, lorsque l'on est en
train de taper une suite de commandes avec des pipes, on peut se retrouver
très facilement avec une espace insécable si on a le malheur de garder le
doigt appuyé sur la touche &lt;code&gt;Alt gr&lt;/code&gt;un poil trop longtemps. On se retrouve
alors avec un message qui a de quoi laisser perplexe&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;% ls | grep foo
command not found:  grep
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Je me suis fait avoir un paquet de fois, jusqu'à désactiver la saisie des
espaces insécables en ajoutant cette ligne au fichier &lt;code&gt;~/.xmodmaprc&lt;/code&gt;&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;keycode 65 = space space space space space
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Ça suffit pour éviter que je ne saisisse des espaces insécables, mais je me
suis alors rendu compte que d'autres développeurs pouvaient eux aussi saisir
des espaces insécables dans du code. J'ai donc configuré mon éditeur, vim,
pour afficher les espaces insécables&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;vim&quot;&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;listchars&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;trail:◃&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;nbsp:•
&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;list&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Et malgré ça, je me suis encore laissé avoir. J'ai récupéré un fichier CSV
avec des villes, avec diverses informations sur chaque ville dont la
population. J'importe les données et je me rends alors compte que Bordeaux
fait 448 habitants. Un rapide coup d'oeil au fichier CSV avec &lt;code&gt;less&lt;/code&gt; et je
découvre que des espaces sont utilisées comme séparateur des milliers pour la
population. Je remplace alors mon code par&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;population&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;last&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gsub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/\s/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_i&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Ça supprime les espaces, tabulations et retours à la ligne avant de convertir
en entier. Confiant, je relance mon script et, surprise, ça ne marche toujours
pas&amp;nbsp;! J'ai fait un petit tour des erreurs classiques&amp;nbsp;: vérifier que j'ai bien
la bonne valeur dans &lt;code&gt;row.last&lt;/code&gt;, bien vider la base de données avant de
réessayer, etc. Rien n'y fait. Je lance un interpréteur Ruby et je tape&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;448 144&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gsub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/\s/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_i&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; 448144&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Ça devrait bien marcher, et pourtant ça ne marche pas. Alors, vous avez deviné
d'où venait le problème&amp;nbsp;? Le séparateur des milliers n'était pas une simple
espace mais une espace insécable… Une fois la source trouvée, la correction
fut simple&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;population&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;last&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gsub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/[[:blank:]]/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_i&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Mais, amis codeurs, méfiez-vous des espaces insécables&amp;nbsp;!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title type="html">Découvrons le module Shellwords pour Ruby</title>
   <link href="http://dev.af83.com/2012/03/14/decouvrons-le-module-shellwords-pour-ruby.html"/>
   <updated>2012-03-14T00:00:00+01:00</updated>
   <id>http://dev.af83.com/2012/03/14/decouvrons-le-module-shellwords-pour-ruby</id>
   <author><name>Bruno Michel</name><email>contact@af83.com</email></author>
   <content type="html">&lt;p&gt;La bibliothèque standard de Ruby comporte pas mal de modules vieillissants,
dont le code aurait plus sa place dans des gems à part. Mais on peut aussi y
trouver quelques perles. Je vous ai déjà parlé des
&lt;a href=&quot;http://dev.af83.com/2012/02/03/ruby-set.html&quot;&gt;Set&lt;/a&gt; et des
&lt;a href=&quot;http://dev.af83.com/2012/02/20/ruby-structs.html&quot;&gt;Struct&lt;/a&gt;. Aujourd'hui, je
vais compléter cette liste, en y ajoutant
&lt;a href=&quot;http://www.ruby-doc.org/stdlib-1.9.3/libdoc/shellwords/rdoc/Shellwords.html&quot;&gt;Shellwords&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;La description de Shellwords dit&amp;nbsp;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This module manipulates strings according to the word parsing rules of the
UNIX Bourne shell.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ce que l'on pourrait traduire en français par&amp;nbsp;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Ce module manipules des chaînes de caractères en respectant les règles des
shells Bourne UNIX pour découper les mots.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;La première utilisation de ce module est de pouvoir construire des lignes de
commande pour le shell. Par exemple, si on veut compter le nombre de lignes
d'un fichier, on peut faire&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;/path/to/my/file&amp;quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;nb_lines&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sb&quot;&gt;`wc -l &amp;lt; &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_i&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Mais, si pour une raison ou une autre, le nom de fichier comporte une espace,
cela ne va plus marcher. Dans la ligne de commande, l'espace se comportera
comme un séparateur de mots et le shell va chercher deux fichiers au lieu
d'un. Pour corriger le problème, on peut faire appel à Shellwords de cette
façon&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;shellwords&amp;quot;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;/path/to/my/file&amp;quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;nb_lines&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sb&quot;&gt;`wc -l &amp;lt; &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Shellwords&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;escape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_i&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;&amp;nbsp;: l'espace n'est pas le seul caractère à poser problème dans les
lignes de commande du shell. On peut également citer les retours à la ligne,
les guillemets, l'anti-slash, le point-virgule (qui sert à séparer des
instructions) ou encore le dollar (pour référencer des variables).&lt;/p&gt;

&lt;p&gt;Si vous avez un tableau, il existe également une petite méthode utilitaire
pour vous aidez, &lt;code&gt;Shellwords.join&lt;/code&gt;. Voici un exemple&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;shellwords&amp;quot;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;pattern&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;foo bar&amp;quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;files&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;%w(some files)&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;|&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Shellwords&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;grep&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;files&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# ...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Cette méthode applique &lt;code&gt;Shellwords.escape&lt;/code&gt; sur chaque élément du tableau, puis
fais un &lt;code&gt;join(&amp;#39; &amp;#39;)&lt;/code&gt; pour construire cette partie de la ligne de commande
finale.&lt;/p&gt;

&lt;p&gt;On a vu comment construire une ligne de commande à partir de mots, mais la
réciproque est également valable&amp;nbsp;: Shellwords peut aussi nous aider à découper
en mots une ligne de commande. Exemple&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;shellwords&amp;quot;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Shellwords&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;here are &amp;quot;two words&amp;quot;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; [&amp;quot;here&amp;quot;, &amp;quot;are&amp;quot;, &amp;quot;two words&amp;quot;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Cette méthode peut s'avérer bien pratique, même en dehors du contexte du
shell. Imaginer que vous ayez un système qui permette de saisir des tags
séparés par des espaces&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;tags&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;gets&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Si l'utilisateur saisit la ligne &lt;code&gt;Ruby Shell Tips&lt;/code&gt;, &lt;code&gt;tags&lt;/code&gt; sera le tableau
avec les 3 tags&amp;nbsp;: &lt;code&gt;[&amp;quot;Ruby&amp;quot;, &amp;quot;Shell&amp;quot;, &amp;quot;Tips&amp;quot;]&lt;/code&gt;. Puis, un utilisateur vous
remonte son besoin de saisir des tags avec des espaces dedans, comme &lt;code&gt;Open
Source&lt;/code&gt; ou &lt;code&gt;Free Software&lt;/code&gt;. Vous ne voulez pas changer le séparateur, juste
avoir un moyen d'indiquer si l'espace fait parti du tag ou non. Le shell a
déjà résolu ce problème pour vous. Il propose deux façons de saisir un mot
avec des espaces&amp;nbsp;: soit le mettre entre des guillemets, soit utiliser le
caractère d'échappement &lt;code&gt;\&lt;/code&gt;. Et avec Shellwords, c'est très facile de proposer
le même mécanisme&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;shellwords&amp;quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;tags&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Shellwords&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;gets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Et maintenant, si l'utilisateur saisit la ligne
&lt;code&gt;&amp;quot;Free Software&amp;quot; Open\ Source&lt;/code&gt;, nous obtenons bien un tableau avec deux tags&amp;nbsp;:
&lt;code&gt;[&amp;quot;Free Software&amp;quot;, &amp;quot;Open Source&amp;quot;]&lt;/code&gt;. Ne trouvez-vous pas que c'est une
utilisation bien pratique de Shellwords&amp;nbsp;?&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title type="html">Vagrant with Rails + ES + Redis</title>
   <link href="http://dev.af83.com/2012/03/05/vagrant.html"/>
   <updated>2012-03-05T00:00:00+01:00</updated>
   <id>http://dev.af83.com/2012/03/05/vagrant</id>
   <author><name>Laurent Arnoud</name><email>contact@af83.com</email></author>
   <content type="html">&lt;p&gt;Nous utilisons pour plusieurs projets une stack rails + ElasticSearch + Redis.&lt;/p&gt;

&lt;p&gt;Pour avoir rapidement une machine virtuelle sur un projet, nous avons choisi
vagrant avec chef-solo.&lt;/p&gt;

&lt;p&gt;La première chose à faire est d'installer VirtualBox, sur une Debian&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;aptitude install virtualbox virtualbox-dkms virtualbox-qt \
    virtualbox-source linux-headers-2.6-amd64 module-assistant 

modprobe vboxdrv
adduser YOU vboxusers
/etc/init.d/virtualbox restart
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Puis on configure la box&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;gem install vagrant chef

vagrant box add debian-squeeze-64-rvm &lt;a href=&quot;https://s3-eu-west-1.amazonaws.com/rosstimson-vagrant-boxes/debian-squeeze-64-rvm.box&quot;&gt;https://s3-eu-west-1.amazonaws.com/rosstimson-vagrant-boxes/debian-squeeze-64-rvm.box&lt;/a&gt;

vagrant init debian-squeeze-64-rvm
vagrant up
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Pour utiliser chef-solo, il faut également avoir un fichier de configuration
knife&amp;nbsp;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;.chef/knife.rb&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;# encoding: UTF-8
cookbook_path [ File.expand_path(&amp;#39;../../cookbooks&amp;#39;, __FILE__) ]
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;On peut maintenant installer des cookbooks&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;knife cookbook site install nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Que l'on ajoute ensuite au Vagrantfile&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;config.vm.provision :chef_solo do |chef|
  chef.cookbooks_path = &amp;quot;cookbooks&amp;quot;
  chef.add_recipe &amp;quot;nginx&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Finalement, on relance l'ajout de recettes avec&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;vagrant provision
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Les recettes utiles&amp;nbsp;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/fnichol/chef-rvm&quot;&gt;chef-rvm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://community.opscode.com/cookbooks/elasticsearch&quot;&gt;elasticsearch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://community.opscode.com/cookbooks/redis2&quot;&gt;redis2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://community.opscode.com/cookbooks/networking_basic&quot;&gt;networking_basic&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title type="html">How to extend the Redcarpet 2 Markdown library?</title>
   <link href="http://dev.af83.com/2012/02/27/howto-extend-the-redcarpet2-markdown-lib.html"/>
   <updated>2012-02-27T00:00:00+01:00</updated>
   <id>http://dev.af83.com/2012/02/27/howto-extend-the-redcarpet2-markdown-lib</id>
   <author><name>Bruno Michel</name><email>contact@af83.com</email></author>
   <content type="html">&lt;p&gt;As you may now, this blog is &lt;a href=&quot;http://dev.af83.com/2012/01/02/new-year-new-devblog.html&quot;&gt;powered by
Jekyll&lt;/a&gt;, and the
posts on it are written in Markdown (by the way, you should adopt &lt;a href=&quot;http://www.hiltmon.com/blog/2012/02/20/the-markdown-mindset/&quot;&gt;the Markdown
Mindset&lt;/a&gt;). But
by default, the markdown parser for Jekyll doesn't understand the fenced code
blocks that &lt;a href=&quot;http://github.github.com/github-flavored-markdown/&quot;&gt;Github Flavored
Markdown&lt;/a&gt; introduced. And
as a daily user of Github, it was something that I really wanted.&lt;/p&gt;

&lt;p&gt;So I wrote a &lt;a href=&quot;https://github.com/nono/Jekyll-plugins&quot;&gt;plugin for Jekyll&lt;/a&gt;
based on the &lt;a href=&quot;https://github.com/tanoku/redcarpet&quot;&gt;redcarpet&lt;/a&gt; library which
adds this feature and some others. Redcarpet is a very nice library for parsing
Markdown and rendering HTML from it. Since the version 2 Vicent Martí, its author, 
has decoupled the parser and the renderer, making it fairly easy to extend.&lt;/p&gt;

&lt;p&gt;This post explains how to do that and sidestep some traps. But, first, let's
see the basic usage of Redcarpet. It works in two steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a &lt;code&gt;markdown&lt;/code&gt; object, with a given renderer.&lt;/li&gt;
&lt;li&gt;Give it a markdown text with the &lt;code&gt;render&lt;/code&gt; method and it will return you an
HTML document.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For example, if you want to use the &lt;code&gt;Redcarpet::Render::HTML&lt;/code&gt; renderer (it's
one of the renderers that came out of the box with Redcarpet), you can do:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;markdown&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Redcarpet&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Markdown&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Redcarpet&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Render&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;HTML&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:fenced_code_blocks&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;markdown&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;This is *bongos*, indeed.&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; &amp;quot;&amp;lt;p&amp;gt;This is &amp;lt;em&amp;gt;bongos&amp;lt;/em&amp;gt;, indeed&amp;lt;/p&amp;gt;&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;The first level of personalization of Redcarpet is the extensions that you can
give to the &lt;code&gt;Redcarpet::Markdown&lt;/code&gt; constructor. In the previous example, we
enabled the &lt;code&gt;:fenced_code_blocks&lt;/code&gt; extension that makes it parse blocks of code
delimited with 3+ &lt;code&gt;~&lt;/code&gt; or backticks. These extensions modify the way Redcarpet
parses the markdown input.&lt;/p&gt;

&lt;p&gt;For the output, you can change the first argument: the renderer. In our
example, we used a class, but you can also give an instance instead. And this is
particullary useful, as &lt;code&gt;Redcarpet::Render::HTML&lt;/code&gt; accepts options for its
constructor.&lt;/p&gt;

&lt;p&gt;Let's see an example:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Redcarpet&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Render&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;HTML&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:no_links&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:hard_wrap&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;markdown&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Redcarpet&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Markdown&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;markdown&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;This is foo.&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;That is bar.&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; &amp;quot;&amp;lt;p&amp;gt;This is foo.&amp;lt;br&amp;gt;\nThat is bar.&amp;lt;/p&amp;gt;\n&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;One of the available options, &lt;code&gt;:with_toc_data&lt;/code&gt;, is not that obvious to use. If you want to generate an HTML
document with its table of contents, you'll have to render your document 2
times:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;html_toc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Redcarpet&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Markdown&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Redcarpet&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Render&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;HTML_TOC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;markdown&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Redcarpet&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Markdown&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Redcarpet&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Render&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;HTML&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:with_toc_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;toc&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;html_toc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;html&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;markdown&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;full&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;toc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;html&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;So, how does it work? The first time, we use a special renderer, &lt;code&gt;Redcarpet::Render::HTML_TOC&lt;/code&gt;,
which renders only the table of contents. Then, we do a second pass to
generate the body of the document with anchors on the titles (this is what the
&lt;code&gt;:with_toc_data&lt;/code&gt; option does).&lt;/p&gt;

&lt;p&gt;You can go further with a renderer tailored for your fancy needs. It's not
complicated, all you have to do is inheriting from &lt;code&gt;Redcarpet::Render::Base&lt;/code&gt; and
implementing the callbacks listed on the
&lt;a href=&quot;https://github.com/tanoku/redcarpet/blob/master/README.markdown&quot;&gt;README&lt;/a&gt;. An
example of this is given &lt;a href=&quot;https://github.com/tanoku/redcarpet/blob/master/lib/redcarpet/render_man.rb&quot;&gt;to render
Manpages&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;However, there is a faster way to render HTML: you can inherit from
&lt;code&gt;Redcarpet::Render::HTML&lt;/code&gt; and just overload some callbacks! The canonical
example is highlighting code:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;HTMLwithAlbino&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Redcarpet&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Render&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;HTML&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;block_code&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;language&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;Albino&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;safe_colorize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;language&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;markdown&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Redcarpet&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Markdown&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;HTMLwithAlbino&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:fenced_code_blocks&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;But let's try another example: you want to use the headers from &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt;, not
&lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt;. So let's do with our own &lt;code&gt;header&lt;/code&gt; method:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OurHTML&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Redcarpet&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Render&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;HTML&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;level&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;h&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;/h&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;gt;&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Our implementation doesn't seem to be optimal. You may be tempted to use &lt;code&gt;super&lt;/code&gt;
like this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OurHTML&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Redcarpet&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Render&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;HTML&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# WON&amp;#39;T WORK&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;                &lt;span class=&quot;c1&quot;&gt;# WON&amp;#39;T WORK&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;level&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;               &lt;span class=&quot;c1&quot;&gt;# WON&amp;#39;T WORK&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;                                    &lt;span class=&quot;c1&quot;&gt;# WON&amp;#39;T WORK&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;                                      &lt;span class=&quot;c1&quot;&gt;# WON&amp;#39;T WORK&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Please be warned that you can't do that. To offer the maximum performances, the
readcarpet library is coded mostly in C with some optimizations. One of these
optimization is the way the &lt;code&gt;Redcarpet::Render::HTML&lt;/code&gt; methods are called from
the library and it has the nasty side-effects that &lt;code&gt;super&lt;/code&gt; won't work. &lt;a href=&quot;https://github.com/tanoku/redcarpet/issues/51&quot;&gt;An
issue&lt;/a&gt; is opened if you want to
discuss about that.&lt;/p&gt;

&lt;p&gt;Still, it's possible to use &lt;code&gt;super&lt;/code&gt; on the constructor, for enabling an option by default
 - for example:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;HardWrappedHTML&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Redcarpet&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Render&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;HTML&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{})&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;super&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;merge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:hard_wrap&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;To conclude, &lt;a href=&quot;https://github.com/tanoku/redcarpet&quot;&gt;Redcarpet&lt;/a&gt; is my favourite
library for manipulating Markdown: it offers some options for common
customizations and can be extended easily.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title type="html">Structurez votre code Ruby</title>
   <link href="http://dev.af83.com/2012/02/20/ruby-structs.html"/>
   <updated>2012-02-20T00:00:00+01:00</updated>
   <id>http://dev.af83.com/2012/02/20/ruby-structs</id>
   <author><name>Bruno Michel</name><email>contact@af83.com</email></author>
   <content type="html">&lt;p&gt;Pour continuer avec les structures de données présentes dans la bibliothèque
standard de Ruby, après
&lt;a href=&quot;http://dev.af83.com/2012/02/03/ruby-set.html&quot;&gt;les Sets&lt;/a&gt;, je souhaite vous
présenter les &lt;a href=&quot;http://www.ruby-doc.org/core-1.9.3/Struct.html&quot;&gt;Struct&lt;/a&gt;. Cette
structure permet de créer une sorte de classe légère avec quelques attributs.&lt;/p&gt;

&lt;p&gt;Voyons un exemple&amp;nbsp;:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;Struct&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Customer&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;customer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Struct&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Customer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Dave&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;123 Main&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;customer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;         &lt;span class=&quot;c1&quot;&gt;# -&amp;gt; &amp;quot;Dave&amp;quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;customer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;address&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;# -&amp;gt; &amp;quot;123 Main&amp;quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;customer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Joe&amp;quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;customer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;         &lt;span class=&quot;c1&quot;&gt;# -&amp;gt; &amp;quot;Joe&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;À la première ligne, on définit notre structure, avec d'abord son nom, suivi
de la liste des attributs. Cette structure sera ensuite accessible via
&lt;code&gt;Struct::Customer&lt;/code&gt;. À la ligne suivante, on instancie un objet en lui passant
les paramètres dans le même ordre que les attributs lors de la définition de
la structure. Enfin, on peut utiliser les attributs sur cet objet comme pour
une classe normale où ils auraient été définis avec un &lt;code&gt;attr_accessor&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Une première propriété bien sympatique des &lt;code&gt;Struct&lt;/code&gt; est de pouvoir accéder aux
attributs comme si cet objet était un &lt;code&gt;Hash&lt;/code&gt;&amp;nbsp;:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;Struct&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Customer&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;customer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Struct&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Customer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Dave&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;123 Main&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;customer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;          &lt;span class=&quot;c1&quot;&gt;# -&amp;gt; &amp;quot;Dave&amp;quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;customer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Joe&amp;quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;customer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;            &lt;span class=&quot;c1&quot;&gt;# -&amp;gt; &amp;quot;Joe&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Et l'autre caractérisque que j'apprécie particulièrement chez les &lt;code&gt;Struct&lt;/code&gt; est
que le constructeur renvoie la classe. Cela permet, par exemple, de l'assigner
à une autre constante sans le &lt;em&gt;namespace&lt;/em&gt; &lt;code&gt;Struct::&lt;/code&gt;&amp;nbsp;:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;Customer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Struct&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Customer&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;customer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Customer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Dave&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;123 Main&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Dans ce cas, on peut également se passer de passer le nom de la structure en
premier paramètre&amp;nbsp;:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;Customer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Struct&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;customer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Customer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Dave&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;123 Main&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Mais surtout, je l'utilise souvent pour hériter d cette classe. Voici un exemple
&lt;a href=&quot;https://github.com/nono/guide-em-up/blob/master/lib/guide-em-up/index.rb#L2&quot;&gt;pris depuis ma gem &lt;code&gt;guide-em-up&lt;/code&gt;&lt;/a&gt;&amp;nbsp;:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Struct&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:root&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:current_dir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:data_dir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:themes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;html&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data_dir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;/browser.erb&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;tmpl&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;Erubis&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Eruby&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tmpl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# ...&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Dans le même style, Ruby possède des
&lt;a href=&quot;http://www.ruby-doc.org/stdlib-1.9.3/libdoc/ostruct/rdoc/OpenStruct.html&quot;&gt;&lt;code&gt;OpenStruct&lt;/code&gt;&lt;/a&gt;,
qui sont un mélange entre les &lt;code&gt;Struct&lt;/code&gt; et les &lt;code&gt;Hash&lt;/code&gt;. Voici un exemple
d'utilisation&amp;nbsp;:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;ostruct&amp;#39;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;person&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;OpenStruct&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:first_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;John&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:last_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Doe&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;person&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;age&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;42&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;person&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first_name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;person&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;last_name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; a &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;person&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;age&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; ans.&amp;quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# -&amp;gt; &amp;quot;John Doe a 42 ans.&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;&amp;nbsp;: par contre, il n'est pas possible d'utiliser la syntaxe de type
&lt;code&gt;Hash&lt;/code&gt; pour accéder aux attributs d'un &lt;code&gt;OpenStruct&lt;/code&gt;. Dommage…&lt;/p&gt;

&lt;p&gt;Au final, on ne rencontre pas souvent &lt;code&gt;Struct&lt;/code&gt; et &lt;code&gt;OpenStruct&lt;/code&gt; quand on lit
du code Ruby. Mais ils peuvent être bien pratiques, et c'est pourquoi, je
pense que c'est une bonne idée de les connaître. Ils m'ont déjà rendu bien des
services par le passé et j'espère que vous pourrez en dire autant dans
quelques temps.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title type="html">Remplacez Resque par Sidekiq</title>
   <link href="http://dev.af83.com/2012/02/16/intro-a-sidekiq.html"/>
   <updated>2012-02-16T00:00:00+01:00</updated>
   <id>http://dev.af83.com/2012/02/16/intro-a-sidekiq</id>
   <author><name>Bruno Michel</name><email>contact@af83.com</email></author>
   <content type="html">&lt;p&gt;Lorsque l'on développe des applications web, il est souvent recommandé
de répondre rapidement aux requêtes HTTP. En particulier, il faut éviter que
les traitements lourds, comme l'encodage d'une vidéo ou la génération de
vignettes, bloquent les réponses. Pour cela, la solution classique est
d'utiliser un &lt;em&gt;message queue&lt;/em&gt;. Le plus populaire dans le monde Rails est
&lt;a href=&quot;https://github.com/defunkt/resque&quot;&gt;Resque&lt;/a&gt; (avec la base de données
clé-valeur &lt;a href=&quot;http://redis.io/&quot;&gt;Redis&lt;/a&gt; comme stockage).&lt;/p&gt;

&lt;p&gt;Le principe est simple&amp;nbsp;: on définit des traitements à faire et quand
l'application Rails souhaite faire un de ces traitements, elle place dans
Redis un ordre. D'autres processus, les &lt;em&gt;workers&lt;/em&gt;, prennent un ordre dans
Redis, l'effectuent, puis passent à l'ordre suivant.&lt;/p&gt;

&lt;p&gt;Chez af83, nous utilisons Resque sur plusiers projets et nous en sommes très
satisfaits. Toutefois, Resque a un défaut&amp;nbsp;: chaque worker traite un seul ordre
à la fois et consomme pas mal de mémoire. Dans la pratique, cela veut souvent
dire que l'on ne pourra pas traiter plus d'une dizaine d'ordres simultanément.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://mperham.github.com/sidekiq/&quot;&gt;Sidekiq&lt;/a&gt; a été écrit spécialement pour
dépasser cette contrainte. C'est un remplaçant de Resque écrit avec
&lt;a href=&quot;http://celluloid.github.com&quot;&gt;Celluloid&lt;/a&gt;, une bibliothèque d'&lt;em&gt;Actors&lt;/em&gt; en Ruby.
Dans Sidekiq, les &lt;em&gt;workers&lt;/em&gt; sont des threads et non plus des processus,
permettant de consommer beaucoup moins de mémoire par worker et donc d'en
faire fonctionner beaucoup plus en parallèle.&lt;/p&gt;

&lt;p&gt;En pratique, si on souhaite utiliser Sidekiq sur un projet Rails, on commence
par l'ajouter au &lt;code&gt;Gemfile&lt;/code&gt;&amp;nbsp;:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;sidekiq&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Puis, on écrit un &lt;em&gt;worker&lt;/em&gt; (dans le répertoire &lt;code&gt;app/workers&lt;/code&gt;), avec une
méthode &lt;code&gt;perform&lt;/code&gt;&amp;nbsp;:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MetricsWorker&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Sidekiq&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Worker&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;perform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;Metrics&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;increment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Enfin, on peut utiliser ce worker depuis un contrôleur ou un modèle, en
utilisant la méthode &lt;code&gt;perform_async&lt;/code&gt;&amp;nbsp;:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;Metrics&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;perform_async&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;start&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Il ne reste plus qu'à lancer &lt;code&gt;sidekiq&lt;/code&gt; depuis la racine de Rails pour que
celui-ci commence à récupérer les ordres et les traiter.&lt;/p&gt;

&lt;p&gt;Bref, Sidekiq peut remplacer avantageusement Resque et ce d'autant plus
facilement qu'il utilise le même stockage. Il est même possible d'utiliser
resque-ui avec Sidekiq (il suffit d'indiquer à sidekiq d'utiliser le namespace
&lt;code&gt;resque&lt;/code&gt; pour redis en le lançant de cette façon&amp;nbsp;: &lt;code&gt;sidekiq -n resque&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Dernière chose, Sidekiq est distribuée sous 2 licences&amp;nbsp;:
&lt;a href=&quot;http://www.gnu.org/licenses/gpl-3.0.html&quot;&gt;GPLv3&lt;/a&gt; et commerciale. Si la
licence GPL vous convient, tant mieux, utilisez-là. Dans le cas contraire,
vous pouvez &lt;a href=&quot;http://www.pledgie.com/campaigns/16623&quot;&gt;payer 50$ à Mike Perham&lt;/a&gt;
pour pouvoir utiliser Sidekiq (ça doit lui permettre de passer plus de temps
sur ses projets Open Source).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mise à jour&lt;/strong&gt;&amp;nbsp;: attention, Mongoid 2.x n'est pas thread-safe et il est donc
très fortement déconseillé de l'utiliser avec Sidekiq. La version 3 de Mongoid
est en cours de développement et sera thread-safe. Source&amp;nbsp;:
&lt;a href=&quot;https://github.com/mongoid/mongoid/issues/1291&quot;&gt;https://github.com/mongoid/mongoid/issues/1291&lt;/a&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title type="html">Présentation de 45 projets en 45 minutes aux TechDays</title>
   <link href="http://dev.af83.com/2012/02/07/techdays.html"/>
   <updated>2012-02-07T00:00:00+01:00</updated>
   <id>http://dev.af83.com/2012/02/07/techdays</id>
   <author><name>Bruno Michel</name><email>contact@af83.com</email></author>
   <content type="html">&lt;p&gt;Comme annoncé &lt;a href=&quot;http://dev.af83.com/2012/02/06/events.html&quot;&gt;hier&lt;/a&gt;, j'ai fait
une présentation intitulée «&amp;nbsp;45 projets en 45 minutes&amp;nbsp;». L'idée de cette
présentation est de parler d'un large éventail de projets web ou dans des
langages de programmation Open Source pour inspirer les auditeurs, leur donner
de nouvelles idée, l'envie d'utiliser ces projets, voir d'y contribuer.&lt;/p&gt;

&lt;p&gt;Vous pouvez regarder &lt;a href=&quot;http://nono.github.com/Presentations/20120207_45_projects/&quot;&gt;les slides&lt;/a&gt;
ou juste consulter la liste des projets présentés&amp;nbsp;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://twitter.github.com/bootstrap/&quot;&gt;Twitter Bootstrap&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://foundation.zurb.com/&quot;&gt;Foundation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://jekyllbootstrap.com/&quot;&gt;Jekyll Bootstrap&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/AF83/c3po&quot;&gt;c3po&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://masonry.desandro.com/&quot;&gt;Masonery&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://sharejs.org/&quot;&gt;ShareJS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.sharelatex.com/&quot;&gt;ShareLaTeX&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://tommoor.github.com/tinycon/&quot;&gt;Tinycon&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://cssrefresh.frebsite.nl/&quot;&gt;CSS Refresh&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/cameronmcefee/plax&quot;&gt;Plax&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://luvit.io/&quot;&gt;Luvit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.rust-lang.org/&quot;&gt;Rust&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://webrocket.io/&quot;&gt;Webrocket&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://codemirror.net/&quot;&gt;CodeMirror&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://ditaa.sourceforge.net/&quot;&gt;ditaa&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://dochub.io&quot;&gt;Dochub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/PharkMillups/beautiful-docs&quot;&gt;beautiful-docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://documentup.com/&quot;&gt;documentup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://mailtrap.io/&quot;&gt;MailTrap&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://trello.com/&quot;&gt;Trello&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://gitlabhq.com/&quot;&gt;Gitlab&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://owncloud.org/&quot;&gt;ownCloud&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.sonian.com/cloud-monitoring-sensu/&quot;&gt;Sensu&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tatsuhiro-t/spdylay&quot;&gt;spdylay&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.elasticsearch.org/&quot;&gt;Elastic Search&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/linkedin/indextank-engine&quot;&gt;IndexTank&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/joelmoss/strano&quot;&gt;Strano&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/racker/dreadnot&quot;&gt;dreadnot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://gatling-tool.org/&quot;&gt;Gatling&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://amon.cx/&quot;&gt;Amon&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/paulasmuth/fnordmetric&quot;&gt;fnordmetric&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/steelThread/redmon&quot;&gt;Redmon&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://cloudfoundry.org/&quot;&gt;Cloud Foundry&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rstacruz/js2coffee&quot;&gt;js2coffee&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://sugarjs.com/&quot;&gt;Sugar&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://emberjs.com/&quot;&gt;Ember.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/Yaffle/EventSource&quot;&gt;EventSource&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://mbostock.github.com/d3/&quot;&gt;d3.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://socialitejs.com/&quot;&gt;Socialite&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://leaflet.cloudmade.com/&quot;&gt;Leaflet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://blackberry.github.com/Alice/&quot;&gt;Alice&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.kendoui.com/&quot;&gt;KendoUI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://geekli.st/&quot;&gt;Geeklist&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/nono/slide-em-up&quot;&gt;Slide-em-up&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://linuxfr.org&quot;&gt;LinuxFr.org&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title type="html">Quelques événements où vous pourrez nous rencontrer</title>
   <link href="http://dev.af83.com/2012/02/06/events.html"/>
   <updated>2012-02-06T00:00:00+01:00</updated>
   <id>http://dev.af83.com/2012/02/06/events</id>
   <author><name>Bruno Michel</name><email>contact@af83.com</email></author>
   <content type="html">&lt;p&gt;Comme vous le savez sûrement déjà, af83 a une participation très active dans
les communautés, et notamment dans les événements qu'elle organise, sponsorise
ou prend part d'une façon ou d'une autre. Voici quelques événements où vous
pourrez nous rencontrer si vous le souhaitez.&lt;/p&gt;

&lt;p&gt;Ce soir, quelqu'uns d'entre nous iront au &lt;a href=&quot;http://meetup.rubyparis.org/events/46593752/?eventId=46593752&amp;amp;action=detail&quot;&gt;meetup
Paris.rb&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Demain, je serai présent au &lt;a href=&quot;http://www.microsoft.com/france/mstechdays/&quot;&gt;Microsoft
TechDays&lt;/a&gt; pour présenter &lt;a href=&quot;http://www.microsoft.com/france/mstechdays/programmes/parcours.aspx#DomID=da849abd-78d5-4e54-b92d-f83b038f5b2f&amp;amp;SessionID=d786fe84-bfda-4d7b-a99c-9870101e08d2&amp;amp;fbid=Pxuxvza0XoJ&quot;&gt;45
projets en 45 minutes&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Ensuite, nous participerons au prochain &lt;a href=&quot;http://parisjs.org/&quot;&gt;Paris.js&lt;/a&gt;
et au &lt;a href=&quot;http://parisopadevcamp.eventbrite.com/&quot;&gt;Paris Opa Devcamp #1&lt;/a&gt; organisé
par &lt;a href=&quot;http://mlstate.com/&quot;&gt;MLState&lt;/a&gt;, &lt;a href=&quot;http://placeloop.com/&quot;&gt;Placeloop&lt;/a&gt; et
&lt;a href=&quot;http://geekli.st/&quot;&gt;Geeklist&lt;/a&gt; (au fait, vous pouvez &lt;a href=&quot;http://geekli.st/search?q=af83&amp;amp;type=all&amp;amp;facet=all&quot;&gt;nous
rejoindre&lt;/a&gt; sur geeklist).&lt;/p&gt;

&lt;p&gt;Au mois d'avril, rien de sûr, mais nous avons proposé des talks à
&lt;a href=&quot;http://devoxx.com/&quot;&gt;Devoxx&lt;/a&gt; et &lt;a href=&quot;http://www2012.wwwconference.org/&quot;&gt;www2012&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Enfin, nous ne manquerons pas les &lt;a href=&quot;http://2012.rmll.info/&quot;&gt;Rencontres Mondiales du Logiciel
Libre&lt;/a&gt; à Genève. Et il se murmure que nous pourrions
organiser un prochain Web Workers Camp&amp;nbsp;;-)&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title type="html">Soyez unique, utilisez des Sets</title>
   <link href="http://dev.af83.com/2012/02/03/ruby-set.html"/>
   <updated>2012-02-03T00:00:00+01:00</updated>
   <id>http://dev.af83.com/2012/02/03/ruby-set</id>
   <author><name>Bruno Michel</name><email>contact@af83.com</email></author>
   <content type="html">&lt;p&gt;En Ruby, on utilise très souvent les deux structures composites que sont les
tableaux et les hashs. Mais la bibliothèque standard ne se limite pas à ces
deux là.&lt;/p&gt;

&lt;p&gt;Je fais toujours une grimace quand je vois du code qui ressemble à ça&amp;nbsp;:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;foos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;foos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foos&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;include?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;do_something_with&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;foos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Ce code construit un tableau d'objets sans doublon. Pour cela, avant d'insérer
un élément dans le tableau, il vérifie que celui-ci n'est pas déjà présent
dans le code.&lt;/p&gt;

&lt;p&gt;Or, pour ce besoin précis, Ruby propose des Sets, c'est-à-dire un ensemble non
ordonné d'éléments uniques. L'exemple précédent devient&amp;nbsp;:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;set&amp;quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;foos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;foos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;do_something_with&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;foos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Les Sets sont des Enumerables qui s'utilisent un peu comme des tableaux, mais
qui évitent tout doublon&amp;nbsp;:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;set&amp;quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;foos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_set&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;foos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;foos&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# ~&amp;gt; #&amp;lt;Set: {3, 2, 1}&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;En dehors de l'aspect pratique, les Sets sont également plus performants que
les tableaux pour ce cas d'usage. Dans le cas du tableau, avant d'ajouter un
élément, il faut parcourir tout le tableau pour vérifier que l'élément n'est
pas déjà présent. Par contre, les Sets utilisent des Hashs pour le stockage et
le temps d'insertion d'un élément ne dépendra pas du nombre d'éléments dans le
Set.&lt;/p&gt;

&lt;p&gt;Une variante intéressante des Sets sont les SortedSets. Ils sont similaires
aux Sets mais garantissent que l'on accède à leurs éléments dans l'ordre. Ce
sera sûrement plus clair sur un exemple&amp;nbsp;:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;set&amp;quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;foos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;SortedSet&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;foos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;foos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;foos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;foos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;foos&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_a&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# ~&amp;gt; [1, 2, 3]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Voilà, j'espère que la prochaine fois que vous aurez besoin d'une collection
d'éléments uniques, vous penserez à utiliser les Sets pour m'éviter une
grimace le jour où j'irais lire votre code sur github&amp;nbsp;;-)&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title type="html">Writing a blog post – 101 Introductory Class</title>
   <link href="http://dev.af83.com/2012/02/01/writing-a-blog-post.html"/>
   <updated>2012-02-01T00:00:00+01:00</updated>
   <id>http://dev.af83.com/2012/02/01/writing-a-blog-post</id>
   <author><name>Marie Ailloud</name><email>contact@af83.com</email></author>
   <content type="html">&lt;p&gt;Recently I was asked to contribute to the devblog… Since I don’t code, Bruno
suggested I’d talk about how to write nice content. So here are a few pieces of
advice for your blog articles:&lt;/p&gt;

&lt;p&gt;Find something to talk about where you actually have something to say – yes, you
do have one: feedback on tools, languages, events you attended, opinion on
methodologies, cool stuff you just coded, questions for the community…&lt;/p&gt;

&lt;p&gt;Start with an MVP, that is to say your idea plus the main points, and only then
begin writing up. Don’t be afraid of refactoring, you probably won’t say it the
way you want to on the first draft.&lt;/p&gt;

&lt;p&gt;KISS and DRY doesn’t only apply only to code. You’re not writing a novel, and
there’s no reward for the longest post on the internet. So go straight to the
point, and don’t lose your reader in phrases that look like paragraphs.&lt;/p&gt;

&lt;p&gt;If it keeps being too long, maybe you’re trying to fit too much information in
your message: use packets, and break it in smaller parts with indications for
the reader to retrieve the other parts of the message.&lt;/p&gt;

&lt;p&gt;Respect the language conventions so your post will be parsed correctly: grammar,
syntax, spelling… You do it for programs why not for your visitor?&lt;/p&gt;

&lt;p&gt;Run tests with willing proofreaders, there’s always bugs you won’t have
spotted.&lt;/p&gt;

&lt;p&gt;Keep practicing; you didn’t become a code ninja in a single night…&lt;/p&gt;

&lt;p&gt;These best practices may seem obvious… But unfortunately they are not always
implemented (yes, we all have some bad reading experiences in mind…), so let’s
try and use them.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title type="html">Redis as a protocol</title>
   <link href="http://dev.af83.com/2012/01/27/redis-as-a-protocol.html"/>
   <updated>2012-01-27T00:00:00+01:00</updated>
   <id>http://dev.af83.com/2012/01/27/redis-as-a-protocol</id>
   <author><name>Mathieu Lecarme</name><email>contact@af83.com</email></author>
   <content type="html">&lt;p&gt;HTTP is the king of communication protocols, and it just won the internet war.
Everything else is details; I love details.&lt;/p&gt;

&lt;h2 id=&quot;toc_169&quot;&gt;Distant APIs&lt;/h2&gt;

&lt;p&gt;It has become almost indisputably common sense that non local services have to expose their APIs as REST APIs.
From small private services to large cloud services, everybody speaks HTTP, the new &lt;em&gt;lingua franca&lt;/em&gt;.
You can debug with &lt;em&gt;curl&lt;/em&gt;, handling authentification, compression,
content negociation, caching and all other http wonders. But it has a cost,
an overhead, and I don't even speak about SOAP here.&lt;/p&gt;

&lt;p&gt;However there is a challenger for doing RPC without language restrictions.&lt;/p&gt;

&lt;p&gt;Thrift was created by FaceBook for exposing services to different languages.
It uses a neutral grammar to generate code for your language.
The protocol specifies different communication layers (like TCP), rpc and errors;
just like SOAP without XML and HTTP. It's a nice thing for class oriented developers.&lt;/p&gt;

&lt;p&gt;You can do similar things with Google's Protobuf, albeit with more work, because only
serialization and grammar are specified. There's also Avro, which is an attempt to simplify Thrift
while cutting the link with Facebook. And it's more geared towards dynamic languages, 
&lt;a href=&quot;http://www.igvita.com/2011/08/01/protocol-buffers-avro-thrift-messagepack/&quot;&gt;Ilya Grigoric explains it&lt;/a&gt; better than me.&lt;/p&gt;

&lt;h3 id=&quot;toc_170&quot;&gt;Minimalism&lt;/h3&gt;

&lt;p&gt;I wanted to try something distinct from HTTP. Something connected, with a simple
message protocol, similar to communications between actors in the actor pattern.&lt;/p&gt;

&lt;p&gt;Such a protocol is the memcache protocol.
It's used to silently replace a memcache server (see &lt;a href=&quot;http://www.couchbase.com/membase&quot;&gt;CouchBase&lt;/a&gt;),
or to expose a simple persistant connection (&lt;a href=&quot;http://www.elasticsearch.org/guide/reference/modules/memcached.html&quot;&gt;ElasticSearch&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;When implementing a protocol used by many servers, you can use handcrafted and optimized client implementations…&lt;/p&gt;

&lt;p&gt;So, if it works with Memcached, why not try Redis?
The number of clients is huge, most of them based on hiredis, the official C client.
And the protocol is extensible.&lt;/p&gt;

&lt;p&gt;You can put a real Redis in your stack and mix Redis' patterns (queue, pubsub, incremental counter, cache…).
All that while using a single protocol between application services and Redis services.&lt;/p&gt;

&lt;h3 id=&quot;toc_171&quot;&gt;Expose your services as a Redis server&lt;/h3&gt;

&lt;p&gt;I chose nodejs to make some tests. Node is asynchronous and the king of POC;
I could have chosen Erlang or EventMachine, but I wanted to see something running quickly.&lt;/p&gt;

&lt;p&gt;The server is simple: a TCP server feeding a Redis parser.
The parser is a hidden API, but node is not so strict.
When a command is complete, a &lt;em&gt;reply&lt;/em&gt; event is thrown,
and you can handle the reply with the simple types available in Redis.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;redisd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;redisd&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;server&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;redisd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createServer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;info&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;encode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;redis_version:2.4.5&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;// I&amp;#39;m a liar&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;singleLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;OK&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;listen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4242&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;server listening on port 4242&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;You can test this server with redis-cli and your favorite language API.
This project is small, it's just glue between well tested products.
But now you can go ahead and build your own, with gevent, eventmachine, erlang … or implementing the MULTI/EXEC patterns…&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title type="html">Simple like Hello 2012</title>
   <link href="http://dev.af83.com/2012/01/26/TuxCam.html"/>
   <updated>2012-01-26T00:00:00+01:00</updated>
   <id>http://dev.af83.com/2012/01/26/TuxCam</id>
   <author><name>Ori Pekelman</name><email>contact@af83.com</email></author>
   <content type="html">&lt;p&gt;&lt;img src=&quot;/upload/tuxcamlive.png&quot; alt=&quot;&quot; title=&quot;&quot;  /&gt; If you are interested in how we made this year's new year greeting (which you can find here &lt;a href=&quot;http://2012.af83.com&quot;&gt;2012.af83.com&lt;/a&gt;), here is a simplified architectural view:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/upload/TuxCamPres.001.png&quot; alt=&quot;&quot; title=&quot;&quot;  /&gt;   &lt;/p&gt;

&lt;p&gt;Basically a simple Sinatra based server, serving the static content. When you submit the form it repeates the message on an irc channel using Cinch. There are two other IRC bots on the same channel, one is on the EEEpc controlling the Fux that Controls the Tux, which makes it speak and move. The other is on the laptop that is connected to the camera, adding the text from the IRC channel to the video which is then encoded and streamed to the Wowza which reencodes it for Flash and HTML5 video.&lt;/p&gt;

&lt;p&gt;Sounds complicated?&lt;/p&gt;

&lt;p&gt;Well it ain't, basically all of the server side code can be resumed to&amp;nbsp;: &lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;cinch&amp;#39;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;sinatra&amp;#39;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;eventmachine&amp;#39;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:public_directory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Proc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;public&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;/&amp;#39;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
 &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;public&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;index.html&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;post&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;/form&amp;#39;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;vg&quot;&gt;$bot&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;#af83-2012&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;tux speak &amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;vg&quot;&gt;$bot&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;#af83-2012&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;tux mouth &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; close&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;vg&quot;&gt;$bot&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;#af83-2012&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;tux flippers 2 down&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;vg&quot;&gt;$bot&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Cinch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Bot&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;configure&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;server&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;irc.freenode.org&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;channels&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;#af83-2012&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nick&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;TuxCamBot&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;EM&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;defer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;vg&quot;&gt;$bot&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
</content>
 </entry>
 
 <entry>
   <title type="html">99Lime HTML KickStart : test réussi !</title>
   <link href="http://dev.af83.com/2012/01/25/99Lime.html"/>
   <updated>2012-01-25T00:00:00+01:00</updated>
   <id>http://dev.af83.com/2012/01/25/99Lime</id>
   <author><name>Nancy GERBI</name><email>contact@af83.com</email></author>
   <content type="html">&lt;p&gt;Après le célèbre Twitter Bootstrap que l'on ne présente plus (&lt;a href=&quot;http://dev.af83.com/2011/09/06/jai-essay-twitter-bootstrap.html&quot;&gt;voir l’avis de François&lt;/a&gt;), 99Lime HTML Kickstart fait son apparition, il s'agit d'un framework html / css / jquery qui permet de produire plus facilement et rapidement le layout de votre site.&lt;/p&gt;

&lt;p&gt;Framework assez complet, documentation accessible, il commence déjà à plaire à beaucoup de développeurs et intégrateurs si l'on en croit les tweets récents. Au premier abord je le trouve d’ailleurs plus facile à prendre en main que Twitter Bootstrap.&lt;/p&gt;

&lt;p&gt;Simple à installer et à utiliser, il vous réconciliera avec le html / css, on y retrouve tout ce qu'il faut pour démarrer rapidement un projet sans que les maquettes soient finalisées&amp;nbsp;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Listes&lt;/li&gt;
&lt;li&gt;Menu/Navigation vertical gauche ou droite / horizontal avec des effets js pour les sous-menus&lt;/li&gt;
&lt;li&gt;Tableaux&lt;/li&gt;
&lt;li&gt;Des choix de boutons, avec ou sans couleur, avec ou sans pictos  (même si je reste réservée pour les images dans les boutons)&lt;/li&gt;
&lt;li&gt;Onglets positionnés à gauche, au centre ou à droite&lt;/li&gt;
&lt;li&gt;Fil d'ariane&lt;/li&gt;
&lt;li&gt;Plusieurs dispositions en colonnes (taille et nombre)&lt;/li&gt;
&lt;li&gt;Différents designs, formats et placement de l'image, sans oublier une galerie d'images&lt;/li&gt;
&lt;li&gt;Slideshow&lt;/li&gt;
&lt;li&gt;Formulaires&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pour finir, oubliez les différences d'interprétation des navigateurs car le framework est compatible avec tous… enfin mention &quot;dégradé&quot; sur IE6&amp;nbsp;!   &lt;/p&gt;

&lt;p&gt;À votre tour&amp;nbsp;: &lt;a href=&quot;http://www.99lime.com&quot;&gt;99LimeHTMLKickStart&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ori Pekelman rajoutera sa Pekelman's Touch&amp;nbsp;:&lt;/p&gt;

&lt;p&gt;Autre petit intérêt, la grille proposée est fluide, à la différence de bootstrap orienté largeur fixe. &lt;/p&gt;

&lt;p&gt;Par contre quelques bémols assez importants… lime n'as pas du tout été pensé comme bootstrap pour être une mince couche modifiable par la suite. Nulle variable. Pas de  Mixins. Ni Less, ni SCSS, ni SASS.. Donc l'utiliser c'est de le forker… &lt;/p&gt;

&lt;p&gt;Démarrage rapide mais maintenabilité très basse. D'ailleurs le fait qu'il propose un lien de téléchargement d'archive plutôt qu'un lien vers le dépôt github démontre bien qu'il s'agit d'un projet qui n'est pas vraiment orienté vers les développeurs structurés. &lt;/p&gt;

&lt;p&gt;Le JS embarqué est de la même nature, plusieurs librairies ensemble dans le même fichier, et qui tapent en dur sur des sélecteurs comme &lt;em&gt;ul.menu&lt;/em&gt; (d'ailleurs voir de nos jours &amp;lt;div id=&quot;nav&quot;&amp;gt; et &amp;lt;div id=&quot;footer&quot;&amp;gt; ça fait un peu mal, pas très HTML5 tout ça).&lt;/p&gt;

&lt;p&gt;Sinon, si pour vous l'intérêt principal c'est la grille fluide, allez voir le très sympatique &lt;a href=&quot;http://semantic.gs&quot;&gt;http://semantic.gs&lt;/a&gt; (qui d'ailleurs par la magie de Mixins, peut très bien fonctionner avec bootstrap).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ajout&lt;/strong&gt;&amp;nbsp;: il existe maintenant &lt;a href=&quot;https://github.com/vshvedov/htmlkickstart-rails&quot;&gt;htmlkickstart-rails&lt;/a&gt; pour utiliser HTML Kickstart avec l'asset pipeline de Rails.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title type="html">Autocomplete with tire</title>
   <link href="http://dev.af83.com/2012/01/19/autocomplete-with-tire.html"/>
   <updated>2012-01-19T00:00:00+01:00</updated>
   <id>http://dev.af83.com/2012/01/19/autocomplete-with-tire</id>
   <author><name>Mathieu Lecarme</name><email>contact@af83.com</email></author>
   <content type="html">&lt;p&gt;Full-text databases can do more than full text search.
&lt;a href=&quot;http://www.elasticsearch.org/&quot;&gt;Elastic Search&lt;/a&gt; provides a full toolbox for indexing and manipulating text and data.
&lt;a href=&quot;https://github.com/karmi/tire&quot;&gt;Tire&lt;/a&gt; provides a nice and rubyish interface for using this tool.&lt;/p&gt;

&lt;p&gt;Autocomplete is one of its basic features.
Autocomplete suggests words starting with letters that you have just typed, and refining suggestions as you type.&lt;/p&gt;

&lt;h2 id=&quot;toc_164&quot;&gt;Iterate and filter&lt;/h2&gt;

&lt;p&gt;Most databases handle that feature with a filter (with &lt;code&gt;LIKE&lt;/code&gt; keyword in SQL, regular expression search with mongoDB).
The strategy is simple: iterate on all results and keep only words which match the filter.
This is brutal and hurts the hard drive. Elastic Search can do it too, with the &lt;a href=&quot;http://www.elasticsearch.org/guide/reference/query-dsl/prefix-query.html&quot;&gt;prefix query&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With a small index, it plays well. For large indexes it will be more slow and painful.&lt;/p&gt;

&lt;h2 id=&quot;toc_165&quot;&gt;Look for what you want&lt;/h2&gt;

&lt;p&gt;Elastic search is an index, iterating over an index is a bit paradoxical.
The main feature of an index  is finding quickly something and giving back a reference to the complete information.
Just like an index in a book: your eyes scan quickly a list of alphabetically sorted words,
and you have the page number for reading the information.&lt;/p&gt;

&lt;p&gt;It's hard to build an index, but when it's done, it's very fast to find something.
Usually, data are not modified very often, there is far more reading than writing, the cost of indexing is cheap when you compare it with the searching speed benefit.&lt;/p&gt;

&lt;p&gt;Elastic Search indexes document with tokens extracted from properties.
Prefix search is a specific need and is handled with &lt;em&gt;edge ngram&lt;/em&gt;, a variant of &lt;em&gt;ngram&lt;/em&gt;.
&lt;em&gt;Ngram&lt;/em&gt; is a group a contiguous letters extracted from a word.
&lt;em&gt;Edge ngram&lt;/em&gt; is a &lt;em&gt;ngram&lt;/em&gt; built from the start or the end of a word.&lt;/p&gt;

&lt;p&gt;For example, you are a biologist and want to index the word &lt;em&gt;Heterastridium&lt;/em&gt;, with a min size of 3 and max size of 6.
Too few letter is not enough deterministic, too many is a waste.&lt;/p&gt;

&lt;p&gt;This word  &lt;em&gt;Heterastridium&lt;/em&gt; is tokenized as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;het&lt;/li&gt;
&lt;li&gt;hete&lt;/li&gt;
&lt;li&gt;heter&lt;/li&gt;
&lt;li&gt;hetera&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Like any &lt;em&gt;elastic search&lt;/em&gt; query, I can add more criteria, filters or facets.&lt;/p&gt;

&lt;h2 id=&quot;toc_166&quot;&gt;Tire in action&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Edge ngram&lt;/em&gt; tokenization is very specific, it can't be used for full search,
or even sorting, but one property can be indexed more than one time, and elastic search handles that nicely.&lt;/p&gt;

&lt;h3 id=&quot;toc_167&quot;&gt;Code example&lt;/h3&gt;

&lt;p&gt;Boilerplate.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;#encoding: utf-8&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;rubygems&amp;#39;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;tire&amp;#39;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;json&amp;#39;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;active_support/core_ext/object/to_query&amp;#39;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;active_support/core_ext/object/to_param&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;One analyzer for starting, one for sorting.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;conf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;settings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;analysis&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;analyzer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;my_start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;tokenizer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;whitespace&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#I know it&amp;#39;s a title, with no ponctuation&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;%w{asciifolding lowercase my_edge}&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#no accent, downcase&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;my_sort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;tokenizer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;keyword&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#cut nothing, it&amp;#39;s just for sorting&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;%w{asciifolding lowercase}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;my_edge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;nb&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;edgeNGram&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#1 to 10 letters, from the start&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;min_gram&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;max_gram&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;side&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;front&amp;#39;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;mappings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;coral&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;properties&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;string&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;not_analyzed&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;include_in_all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;multi_field&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fields&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# this property needs multiple index&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nb&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;string&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;analyzer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;my_start&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;include_in_all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nb&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;string&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;analyzer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;my_sort&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;include_in_all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Some data&amp;nbsp;: scientific name of corals stolen from Wikipedia.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;corals&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;s1&quot;&gt;&amp;#39;Hydractinia echinata&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s1&quot;&gt;&amp;#39;Heterastridium&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s1&quot;&gt;&amp;#39;Hydractinia symbiolongicarpus&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s1&quot;&gt;&amp;#39;Hydrichthys&amp;#39;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Feeding an empty index with corals.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;Tire&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;corals&amp;#39;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;delete&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;create&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;conf&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;cpt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;corals&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;coral&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;cpt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_posts&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2012&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mo&quot;&gt;01&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;autocomplete&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tire&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;md1&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cpt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;coral&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;coral&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;refresh&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Most of tire's job is to provide a complex JSON to elastic search.&lt;/p&gt;

&lt;p&gt;Searching and sorting. Which words start with &quot;hydr&quot;.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Tire&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;search&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;corals&amp;#39;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;query&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;name.start:hydr&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;sort&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;by&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:&amp;#39;name.sort&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;asc&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;results&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;The code example prints the list of words in the standard output, quickly and sorted.&lt;/p&gt;

&lt;h2 id=&quot;toc_168&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Brute force is alway an option, ad hoc tools can do more, with less.&lt;/p&gt;

&lt;p&gt;Elastic search provides specialized tools for common needs, use them!&lt;/p&gt;
</content>
 </entry>
 

</feed>

