<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>L'actualité de Synbioz</title>
    <description>Des choses sur Synbioz, l'OSS, Ruby, Ruby on Rails, javascript…</description>
    <link>http://www.synbioz.com//blog.xml</link>
    <item>
      <title>L'utilisation de vim (suite)</title>
      <link>http://www.synbioz.com/blog/2012/02/21/l_utilisation_de_vim_2</link>
      <description>&lt;p&gt;Dans mon &lt;a href="http://www.synbioz.com/blog/2012/01/18/l_utilisation_de_vim"&gt;dernier article sur Vim&lt;/a&gt; j’ai introduit les bases de l’éditeur. Cette fois, j’aimerais vous présenter les fonctionnalités qui permettent à Vim de défendre sa place face à &lt;a href="http://macromates.com/"&gt;Mate&lt;/a&gt; ou à &lt;a href="http://www.sublimetext.com/"&gt;Sublime Text&lt;/a&gt;. C’est dans cet opus que vous découvrirez que la richesse des commandes de déplacement, d’insertion et de sélection n’est que la partie visible de l’iceberg.&lt;/p&gt;

&lt;h1 id="interactions-avec-la-console"&gt;Interactions avec la console&lt;/h1&gt;

&lt;p&gt;Lorsque vous êtes dans Vim vous pouvez exécuter des commandes classiques en les préfixant par &lt;code&gt;:!&lt;/code&gt;. Dans ce cas le résultat de la commande est affiché puis Vim reprend la main après une confirmation de votre part. Pour avoir un terminal fonctionnel et prêt à exécuter plusieurs commandes à la suite c’est &lt;code&gt;:sh&lt;/code&gt; qu’il faut utiliser.&lt;/p&gt;

&lt;p&gt;On peut également rediriger la sortie d’une commande dans un buffer. En utilisant la syntaxe Ex &lt;code&gt;:r !tree&lt;/code&gt; qui va écrire sous le curseur l’arborescence du répertoire courant. Comme toute commande Ex, on peut choisir une adresse, &lt;code&gt;.,+10r !tree&lt;/code&gt; remplace les 10 lignes suivant la ligne courante par le résultat de &lt;code&gt;tree&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Ce n’est pas terminé ! On peut aussi utiliser une partie d’un buffer comme entrée d’une commande avec &lt;code&gt;:w !cmd&lt;/code&gt; ou encore filtrer en place tout ou partie d’un buffer. On peut par exemple supprimer toutes les lignes d’un fichier débutant par un &lt;code&gt;#&lt;/code&gt; avec &lt;code&gt;:%!egrep -v "^[\t ]*\#"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Ce qui est intéressant c’est que Vim profite de la philosophie Unix au mieux en jouant la carte du « pipe ».&lt;/p&gt;

&lt;h1 id="buffers-de-copie"&gt;Buffers de copie&lt;/h1&gt;

&lt;p&gt;Imaginez que vous venez de supprimer un texte accidentellement à coup de commande &lt;code&gt;d&lt;/code&gt;. Vous pouvez annuler ou vous pouvez coller (la suppression de Vim agit plutôt comme un couper). Lorsque vous avez copié ou supprimé autre chose ou que vous n’avez pas envie de revenir en arrière sur les modifications que vous avez faites entre temps vous disposez d’un historique des 9 dernières copies / suppressions. La commande &lt;code&gt;"2p&lt;/code&gt; va coller après le curseur le contenu de ce qui à été supprimé ou copié en avant dernier et ainsi de suite. Le workflow typique pour rechercher dans cet historique est &lt;code&gt;"1pu.u.u.&lt;/code&gt; qui permet de remonter l’historique.&lt;/p&gt;

&lt;p&gt;Lorsque vous réalisez des opérations de suppression ou de copie de texte, il est possible de contrôler la zone dans laquelle Vim stocke ce texte. C’est une fonctionnalité offerte habituellement par des &lt;a href="http://en.wikipedia.org/wiki/Clipboard_manager"&gt;gestionnaires de presse-papier&lt;/a&gt;. Vim offre 26 buffers de copie, un pour chaque lettre minuscule. Pour copier 5 lignes dans le buffer &lt;code&gt;a&lt;/code&gt; on peut le faire grâce à la commande &lt;code&gt;:.,+4y a&lt;/code&gt; ou avec &lt;code&gt;"ay4&lt;/code&gt;. Lorsqu’on utilise des lettres majuscules, le contenu copié ou supprimé est ajouté au buffer portant la même lettre.&lt;/p&gt;

&lt;p&gt;On peut par exemple réorganiser les sections d’un fichier en les accumulant dans un buffer (&lt;code&gt;:24,31d X&lt;/code&gt;) dans l’ordre où l’on souhaite à la fin les voir. Lorsque c’est fait, on colle simplement le résultat avec &lt;code&gt;"xp&lt;/code&gt;.&lt;/p&gt;

&lt;h1 id="macros"&gt;Macros&lt;/h1&gt;

&lt;p&gt;Je distingue deux types d’automatisation, celle que l’on prévoit, que je qualifie de statique et celle que l’on utilise au fil de l’édition, que je qualifie de dynamique.&lt;/p&gt;

&lt;h2 id="statiques"&gt;Statiques&lt;/h2&gt;

&lt;h3 id="abrviations"&gt;Abréviations&lt;/h3&gt;

&lt;p&gt;Vim dispose d’une commande permettant de définir des &lt;em&gt;abréviations&lt;/em&gt; par exemple si je veux remplacer &lt;code&gt;pck&lt;/code&gt; par &lt;code&gt;parce que&lt;/code&gt; lorsque j’écris, la commande &lt;code&gt;:ab[breviate] pck parce que&lt;/code&gt; me le permet. Cette commande n’a d’effet que dans l’instance de Vim actuelle. Vim dispose d’un fichier de configuration, dont nous reparlerons plus tard, auquel peuvent être intégrées ces abréviations et ainsi en bénéficier dans toutes les futures instances de Vim.&lt;/p&gt;

&lt;p&gt;L’abréviation que l’on vient de définir s’applique aussi lorsque l’on essaye de taper une commande : la commande &lt;code&gt;:pck 34&lt;/code&gt; est étendue en &lt;code&gt;:parce que 34&lt;/code&gt;. C’est gênant. Vim permet de choisir le mode dans lequel on veut que nos abréviations fonctionnent. Les commandes &lt;code&gt;:ca[bbrev]&lt;/code&gt; et &lt;code&gt;:ia[bbrev]&lt;/code&gt; permettent de définir une abréviation uniquement pour le mode commande ou insertion.&lt;/p&gt;

&lt;p&gt;On peut bien entendu supprimer une abréviation avec les commandes &lt;code&gt;:una[bbreviate]&lt;/code&gt;, &lt;code&gt;cuna[bbrev]&lt;/code&gt; et &lt;code&gt;:iuna[bbrev]&lt;/code&gt; selon le type de l’abréviation à supprimer. C’est également une commande pratique pour corriger des fautes de frappe par exemple &lt;code&gt;:ia tihs this&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id="mapping"&gt;Mapping&lt;/h3&gt;

&lt;p&gt;Vim permet de faire correspondre des touches à des actions, au-delà de la simple abréviation textuelle. Par exemple si vous trouvez que faire &lt;code&gt;&amp;lt;Esc&amp;gt;:w&amp;lt;CR&amp;gt;a&lt;/code&gt; (voir la notation &lt;a href="http://vimdoc.sourceforge.net/htmldoc/intro.html#%3C%3E"&gt;&amp;lt;&amp;gt;&lt;/a&gt;) n’est pas pratique pour faire une sauvegarde en cours d’édition. Alors, vous pouvez ajouter un raccourci pour le faire en appuyant sur &lt;code&gt;F3&lt;/code&gt; : &lt;code&gt;imap &amp;lt;F3&amp;gt; &amp;lt;Esc&amp;gt;:w&amp;lt;CR&amp;gt;a&lt;/code&gt;. Dans cet exemple la commande &lt;code&gt;:imap&lt;/code&gt; n’intervient qu’en mode insertion. Comme pour les abréviations, il existe un grand nombre de versions de &lt;code&gt;:map&lt;/code&gt;. Ne pas hésiter à consulter la &lt;a href="http://vimdoc.sourceforge.net/htmldoc/map.html"&gt;documentation officielle de la commande map&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Un autre exemple pourrait être de rajouter la commande &lt;code&gt;Ctrl h&lt;/code&gt; en mode insertion pour insérer la date sous le curseur : &lt;code&gt;:imap &amp;lt;C-h&amp;gt; &amp;lt;C-R&amp;gt;=strftime("%Y/%m/%d")&amp;lt;CR&amp;gt;&lt;/code&gt;. Dans les deux exemples j’ai utilisé des touches spéciales comme &lt;code&gt;F2&lt;/code&gt; ou bien &lt;code&gt;Ctrl h&lt;/code&gt; en tant que raccourci. Il est tout à fait possible d’utiliser n’importe quelle combinaison de touches. J’oublis régulièrement de sortir du mode insertion pour faire un &lt;code&gt;:w&lt;/code&gt;, j’ai ajouté ce mapping : &lt;code&gt;:imap :w &amp;lt;Esc&amp;gt;:w&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Pour plus de détails sur la commande &lt;code&gt;&amp;lt;C-R&amp;gt;&lt;/code&gt; voir la &lt;a href="http://vimdoc.sourceforge.net/htmldoc/insert.html#i_CTRL-R"&gt;documentation de i Ctrl R&lt;/a&gt;. Cette commande permet d’évaluer des expressions diverses : opérations, fonctions, buffers, et autres puis d’écrire le résultat sous le curseur.&lt;/p&gt;

&lt;h3 id="fonctions"&gt;Fonctions&lt;/h3&gt;

&lt;p&gt;On peut déclencher des fonctions dans les macros, il devient donc possible d’écrire une fonction dans le langage Vim et de l’exécuter n’importe quand. Je ne rentrerai pas dans le détail de l’écriture des scripts Vim dans cet article mais sachez que c’est possible, simple et assez complet. On peut même utiliser du Ruby (voir la &lt;a href="http://vimdoc.sourceforge.net/htmldoc/if_ruby.html"&gt;documentation de if_ruby&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id="dynamiques"&gt;Dynamiques&lt;/h2&gt;

&lt;p&gt;On peut dynamiquement utiliser des macros grâce au mode &lt;em&gt;enregistrement&lt;/em&gt;. Ce mode permet d’enregistrer les actions que vous êtes en train de faire afin de les rappeler plus tard. Pour moi c’est vraiment une des principales killer features de Vim. Avec &lt;code&gt;qa&lt;/code&gt; je débute l’enregistrement d’une macro dans un buffer &lt;code&gt;a&lt;/code&gt;, lorsque j’appuie à nouveau sur &lt;code&gt;q&lt;/code&gt; je termine cette macro. Avec &lt;code&gt;@a&lt;/code&gt; j’exécute cette même série de commandes et d’insertions. Dès lors que l’on reformate des données complexes et répétitives, c’est indispensable.&lt;/p&gt;

&lt;h1 id="templates"&gt;Templates&lt;/h1&gt;

&lt;p&gt;Comme je le disais plus tôt Vim possède un fichier de configuration. Il se trouve &lt;code&gt;$HOME/.vimrc&lt;/code&gt; et contient en général les préférences des utilisateurs. On peut y ajouter des commandes Vim classiques et également associer des actions à des &lt;a href="http://vimdoc.sourceforge.net/htmldoc/autocmd.html#%7Bevent%7D"&gt;évènements&lt;/a&gt;, par exemple l’ouverture d’un fichier. Vim ne dispose pas d’un système de modèles lors de la création de nouveaux fichiers. Grâce au système d’évènements de Vim on peut en une ligne de configuration obtenir un tel système.&lt;/p&gt;

&lt;p&gt;Le système d’évènements de Vim va permettre de spécifier que sur l’ouverture d’un nouveau fichier on devra écrire le contenu du fichier modèle au début de ce nouveau fichier. C’est grâce à cette commande dans le fichier de configuration qu’on arrivera à ce résultat :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;  autocmd&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="nb"&gt;BufNewFile&lt;/span&gt; * &lt;span class="k"&gt;silent&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;r &lt;span class="p"&gt;~&lt;/span&gt;&lt;span class="sr"&gt;/.vim/&lt;/span&gt;templates/tmpl.%:&lt;span class="k"&gt;e&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Ici &lt;code&gt;BufNewFile&lt;/code&gt; est le nom de l’évènement, &lt;code&gt;*&lt;/code&gt; le motif du nom des fichiers devant être retenu (tous les fichiers ici) et &lt;code&gt;silent! 0r &amp;lt;filename&amp;gt;&lt;/code&gt; la commande qui va insérer le contenu du fichier &lt;code&gt;filename&lt;/code&gt; à la ligne zéro du fichier. L’utilisation de &lt;code&gt;%:e&lt;/code&gt; permet de récupérer l’extension du fichier courrant. Ainsi pour un nouveau fichier HTML on va rechercher le fichier &lt;code&gt;~/.vim/templates/tmpl.html&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Voilà, on a notre système de modèles ; à condition d’avoir préalablement enregistré les modèles nécessaires au bon endroit.&lt;/p&gt;

&lt;h1 id="les-replis"&gt;Les replis&lt;/h1&gt;

&lt;p&gt;Les replis sont une fonctionnalité qui permet de masquer une partie d’un fichier. Ces replis peuvent bien sûr être imbriqués. Dans Vim, la plus petite unité de replis est la ligne. Il existe différents modes pour contrôler ces replis : &lt;code&gt;syntax&lt;/code&gt;, &lt;code&gt;indent&lt;/code&gt;, &lt;code&gt;manual&lt;/code&gt; et &lt;code&gt;expr&lt;/code&gt;. Je n’ai pas grande expérience avec le mode de replis &lt;code&gt;syntax&lt;/code&gt;. Le mode &lt;code&gt;indent&lt;/code&gt; utilise uniquement l’indentation pour déterminer les niveaux de replis. Le mode &lt;code&gt;manual&lt;/code&gt; nécessite que l’utilisateur spécifie l’intervalle a être replié. Voici un condensé des commandes pour manipuler ces replis :&lt;/p&gt;

&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;Commande&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;zf&lt;/td&gt;
&lt;td&gt;Utilise le mode visuel ou un déplacement pour créer un repli&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;zo&lt;/td&gt;
&lt;td&gt;Ouvre le repli sous le curseur&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;zO&lt;/td&gt;
&lt;td&gt;Ouvre tous les replis sous le curseur&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;zc&lt;/td&gt;
&lt;td&gt;Ferme le repli sous le curseur&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;zR&lt;/td&gt;
&lt;td&gt;Ouvre tous les replis du fichier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;zM&lt;/td&gt;
&lt;td&gt;Ferme tous les replis du fichier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;zm&lt;/td&gt;
&lt;td&gt;Augmente le niveau de repli&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;zr&lt;/td&gt;
&lt;td&gt;Diminue le niveau de repli&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;zj&lt;/td&gt;
&lt;td&gt;Déplace le curseur au repli suivant&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;zk&lt;/td&gt;
&lt;td&gt;Déplace le curseur au repli précédent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;[z&lt;/td&gt;
&lt;td&gt;Déplace le curseur au début du repli&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;]z&lt;/td&gt;
&lt;td&gt;Déplace le curseur à la fin du repli&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Pour en savoir un peu plus sur les replis, je vous recommande cet &lt;a href="http://qanuq.com/index.php?post/2009/04/13/Utiliser-les-replis-%28folding%29-de-Vim"&gt;article dédié aux replis de Vim&lt;/a&gt;. L’article aborde entre autres la persistance des replis effectués d’une utilisation sur l’autre de Vim.&lt;/p&gt;

&lt;h2 id="personnaliser-les-replis"&gt;Personnaliser les replis&lt;/h2&gt;

&lt;p&gt;Il y a quelques semaines, Martin posait une question relative à TextMate et au folding. Il n’y avait pas dans le bundle &lt;a href="http://fr.wikipedia.org/wiki/Markdown"&gt;Markdown&lt;/a&gt; de replis prédéfinis concernant les sections. Voilà un petit script, qui placé dans un fichier &lt;code&gt;.vim/ftplugin/markdown.vim&lt;/code&gt; permettra d’avoir des replis sur les sections.&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="c"&gt;  " Retourne le nombre de '#' au dÃ©but de la ligne dont le numÃ©ro est en paramÃ¨tre&lt;/span&gt;
  &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; MDSectionLevel&lt;span class="p"&gt;(&lt;/span&gt;lnr&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;lc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; getline&lt;span class="p"&gt;(&lt;/span&gt;a:lnr&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; matchend&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'^#*'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;endfunction&lt;/span&gt;

&lt;span class="c"&gt;  " Fonction de folding pour les section markdown&lt;/span&gt;
  &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; MDFoldLevel&lt;span class="p"&gt;(&lt;/span&gt;lnr&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; lvl   &lt;span class="p"&gt;=&lt;/span&gt; MDSectionLevel&lt;span class="p"&gt;(&lt;/span&gt;a:lnr&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; lvlm1 &lt;span class="p"&gt;=&lt;/span&gt; MDSectionLevel&lt;span class="p"&gt;(&lt;/span&gt;a:lnr&lt;span class="m"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; lvl &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; lvl&lt;span class="m"&gt;-1&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; lvlm1 &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; lvlm1
      &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s1"&gt;'='&lt;/span&gt;
      &lt;span class="k"&gt;endif&lt;/span&gt;
    &lt;span class="k"&gt;endif&lt;/span&gt;
  &lt;span class="k"&gt;endfunction&lt;/span&gt;


  &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="nb"&gt;foldexpr&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;MDFoldLevel&lt;span class="p"&gt;(&lt;/span&gt;v:lnum&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="nb"&gt;foldmethod&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;expr
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Cet exemple est destiné à illustrer le mode de repli par expression. Pour utiliser ce mode, il faut donner une expression qui lors de son évaluation retourne le niveau d’indentation de la ligne numéro &lt;code&gt;lnum&lt;/code&gt;. C’est la fonction &lt;code&gt;MDFoldLevel&lt;/code&gt; qui est chargée de retourner ce niveau. Pour cela elle compte le nombre de &lt;code&gt;#&lt;/code&gt; présent en début de ligne, lorsqu’il n’y en a pas, on considère que l’on est au même niveau que les lignes qui précédent en retournant &lt;code&gt;'='&lt;/code&gt; qui saura être interprété par Vim. Lorsqu’au contraire il y a des &lt;code&gt;#&lt;/code&gt; en début de ligne on retourne un nombre.&lt;/p&gt;

&lt;h1 id="plug-ins"&gt;Plug-ins&lt;/h1&gt;

&lt;p&gt;Avec les derniers exemples sur les templates ou le fold, on se rend bien compte que l’on ne peut pas tout écrire. Vim utilise un système de scripts pour ajouter des fonctionnalités. Des gestionnaires de paquets existent comme &lt;a href="https://github.com/gmarik/vundle"&gt;Vundle&lt;/a&gt; afin de simplifier l’utilisation de ces différents scripts. Sur la toile vous trouverez beaucoup de plug-ins facilitant l’utilisation de &lt;a href="https://github.com/vim-ruby/vim-ruby"&gt;Ruby&lt;/a&gt;, &lt;a href="https://github.com/tpope/vim-rails"&gt;Rails&lt;/a&gt;, &lt;a href="https://github.com/tpope/vim-fugitive"&gt;Git&lt;/a&gt;, &lt;a href="https://github.com/vim-scripts/FuzzyFinder"&gt;la recherche et l’ouverture de fichiers&lt;/a&gt;, les &lt;a href="https://github.com/msanders/snipmate.vim"&gt;Snippets&lt;/a&gt;, &lt;a href="https://github.com/tpope/vim-pastie"&gt;Pastie&lt;/a&gt; et beaucoup d’autres choses. Sur le site officiel de Vim vous trouverez une &lt;a href="http://www.vim.org/scripts/"&gt;section scripts&lt;/a&gt; qui répertorie les différents ajouts existants. Vous trouverez sur github beaucoup de partages de &lt;a href="https://github.com/edgecase/vim-config"&gt;configuration Vim&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id="conclusion"&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;J’espère à travers cet article vous avoir un peu plus convaincu de l’intérêt de Vim. Et, j’espère aussi démystifier son utilisation, car beaucoup sont convaincu (à juste titre) que c’est un éditeur puissant mais très difficile à maitriser. Vim est complet, complexe, et plein de (bonnes) surprises. Pour une introduction plus complète que mes deux billets vous pouvez consulter les &lt;a href="https://github.com/runpaint/vim-recipes"&gt;Vim Recipes&lt;/a&gt; qui sont, non pas une référence mais une introduction plus douce que la &lt;a href="http://vimdoc.sourceforge.net/htmldoc/help.html"&gt;documentation officielle&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;L’équipe Synbioz.&lt;/p&gt;

&lt;p&gt;Libres d’être ensembles.&lt;/p&gt;</description>
      <pubDate>Tue, 21 Feb 2012 00:00:00 +0100</pubDate>
      <guid>http://www.synbioz.com/blog/2012/02/21/l_utilisation_de_vim_2</guid>
      <author>Nicolas Zermati</author>
      <category>alternatives</category>
      <category>productivité</category>
    </item>
    <item>
      <title>HockeyApp - A great service that lets you test your mobile or mac application.</title>
      <link>http://www.synbioz.com/blog/2012/02/14/hockey_app</link>
      <description>&lt;p&gt;When you’re developing an app, there always comes a time when you need to test your app. See how users react to your app idea, check its usability, determine if and when the app crashes and how to handle the crashes, discover if any new features could be implemented… The best way to see how your app behaves on its own and how it is handled by users is to release a beta version of your app.  That way, you have access to a whole community of users and developers that will test your app in every possible way.&lt;/p&gt;

&lt;p&gt;If you’re a serious reader of our &lt;a href="http://www.synbioz.com/blog"&gt;blog&lt;/a&gt; -– and we know you are -– , you already know we develop web apps through iteration, a concept stemming from &lt;a href="http://agilemanifesto.org/iso/fr/"&gt;agile web development&lt;/a&gt;. We apply the same process to mobile app development. So today, to show you how we test apps, let us introduce to you an outstanding app and great service: &lt;a href="http://www.hockeyapp.net/"&gt;Hockeyapp&lt;/a&gt;, a service that has only one goal in mind: help you perfect your apps.&lt;/p&gt;

&lt;p&gt;Quite frankly, we’re in love with Hockeyapp. It’s that great a service. Say you want to test your app but aren’t sure how to go about it or how to get people to give it a spin.  Hockeyapp lets you upload your app on its platform so it can be tested and then supplies you with a seriously good bunch of services for your app.  Crashreports, live reporting, bug reporting… You name it. Some of you may have heard of &lt;a href="https://testflightapp.com/"&gt;Testflight&lt;/a&gt; App: Testflight offers the same kind of services except Hockeyapp is also for Android apps and soon OSX apps.&lt;/p&gt;

&lt;p&gt;First, you’ll need to install Hockeyapp and integrate it with your app. This video by Andreas Zeitler (for Hockeyapp) explains to you in a clear and straightforward manner how it’s done:&lt;/p&gt;

&lt;object width="420" height="315"&gt;&lt;param name="movie" value="http://www.youtube.com/v/U6Jon0ombSk?version=3&amp;amp;hl=fr_FR&amp;amp;rel=0"&gt;
&lt;param name="allowFullScreen" value="true"&gt;
&lt;param name="allowscriptaccess" value="always"&gt;
&lt;embed src="http://www.youtube.com/v/U6Jon0ombSk?version=3&amp;amp;hl=fr_FR&amp;amp;rel=0" type="application/x-shockwave-flash" width="420" height="315" allowscriptaccess="always" allowfullscreen="true"&gt;&lt;/embed&gt;&lt;/object&gt;

&lt;p&gt;All integrated and ready to go? Here’s what you need to know about Hockeyapp’s handy features.&lt;/p&gt;

&lt;h2 id="live-crash-report"&gt;Live crash report&lt;/h2&gt;

&lt;p&gt;HockeyApp lets you know exactly when your app crashes in log like &lt;a href="https://developer.apple.com/library/ios/#technotes/tn2151/_index.html"&gt;apple format&lt;/a&gt;, tells you why and provides you with a variety of views and statistics so you can know everything you need to know about those snide little crashes, immediately after they happen.&lt;/p&gt;

&lt;p&gt;All you have to do is integrate an open source library (&lt;a href="http://quincykit.net/"&gt;QuincyKit&lt;/a&gt; for iOs and &lt;a href="http://hockeykit.net/"&gt;HockeyKit&lt;/a&gt; for Android) into your app and voilà! Crash reports are immediately delivered to HockeyApp and then “translated” in a language you’ll understand  – no more of that cryptic iOS and Android crash report language for you.&lt;/p&gt;

&lt;p&gt;Hockeyapp also helps you make sense of all the crashreports so you can fix the bugs in a timely and efficient way. First, when applicable, the crash reports are grouped together, per place where the crash occurred for instance. This makes bug fixing a lot easier.&lt;/p&gt;

&lt;p&gt;Second, you can filter your crashreports any way you like: say you only want to see crashes that occurred on a specific type of device, or just want to see a list of the crashes that haven’t been fixed yet: just create a filter and you’re good to go!&lt;/p&gt;

&lt;p&gt;Lastly, HockeyApp can also be integrated directly into your development process so you don’t have to waste anytime working on different systems at the same time. Lucky we are, it works like a charm with our Redmine. So, all you need to do is connect the App to your bug tracking system. This will then allow you to create and assign tickets from within HockeyApp for each group of crashes.&lt;/p&gt;

&lt;h2 id="distribution"&gt;Distribution&lt;/h2&gt;

&lt;p&gt;Hockeyapp also helps you with distribution, starting with helping you send out your app to the testers.  To distribute your beta versions directly onto the testers device, simply upload your application to the server. HockeyApp will then provide you with everything you need to get the app distributed easily, including automatically generated links to install your app on the testers’ devices.&lt;/p&gt;

&lt;p&gt;So thanks HockeyApp we won’t be annoyed anymore by sending the ipa file to each users.&lt;/p&gt;

&lt;p&gt;Worried about security? The platform offers an array of security measures to toggle with so you can keep out tester, prevent developers from adding their own certificates to your app. Conversely, worried about seeming too restrictive and uptight? Hockeyapp lets the testers you’ve allowed easily access your app. No need to sign up or create an account. Visiting config.hockeyapp.net on your iOS device will give you quick access to all your apps through a single webclip, whether you are a developer or tester.&lt;/p&gt;

&lt;h2 id="analytics"&gt;Analytics&lt;/h2&gt;

&lt;p&gt;Another major part of testing your device is getting feedback on it. Get an overview of the overall test coverage of your application, see how well each version of your beta app is tested, know exactly which device types the app is being tested on and how it’s performing. Get accurate measures of how long each tester has spent on your app, what they tested the most, who’s actually helping a lot in testing the app and who’s not really spending the required time on it to be useful to you. You know how test slots are precious!&lt;/p&gt;

&lt;p&gt;HockeyApp also provides detailed analytics on the different languages your application (status for each language…), as the developers behind this service know perfectly well that more languages your application supports, the more testing is required. By giving you detailed stats on the status for each language your app supports, HockeyApp lets you focus on the areas that need attention.&lt;/p&gt;

&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Like we saw in this article, HockeyApp helps you to deal with your beta version. All the features you need to test your app are in HockeyApp to release a perfect application. Maybe, you are a testflightapp user and happy with that. But if you want try out a new and stunning application, it’s worth giving a shot at HockeyApp.&lt;/p&gt;

&lt;p&gt;What is your point of view ? Testflightapp or HockeyApp ?&lt;/p&gt;</description>
      <pubDate>Tue, 14 Feb 2012 00:00:00 +0100</pubDate>
      <guid>http://www.synbioz.com/blog/2012/02/14/hockey_app</guid>
      <author>Jean-Rémi Laisne</author>
      <category>Mobile</category>
    </item>
    <item>
      <title>Adopter un modèle de versionnement efficace avec Git</title>
      <link>http://www.synbioz.com/blog/2012/02/07/git-adopter-un-modele-de-versionnement-efficace</link>
      <description>&lt;p&gt;Comme vous le savez peut-être, chez &lt;a href="http://www.synbioz.com"&gt;Synbioz&lt;/a&gt;, nous versionnons le code de nos projets à l’aide du &lt;a href="http://en.wikipedia.org/wiki/Distributed_revision_control"&gt;DSCM&lt;/a&gt; &lt;a href="http://git-scm.com/"&gt;Git&lt;/a&gt; dans le cadre de nos sessions de &lt;a href="http://fr.wikipedia.org/wiki/M%C3%A9thode_agile"&gt;développement agile&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;J’ai au départ été très critique vis-à-vis de Git, de sa relative complexité d’utilisation et de sa courbe d’apprentissage plutôt ardue dès qu’il s’agit de faire des choses un peu évoluées. En effet, je viens du monde de &lt;a href="http://mercurial.selenic.com/"&gt;Mercurial&lt;/a&gt; que j’utilise depuis plusieurs années et que je trouve beaucoup plus simple d’accès et d’utilisation.&lt;/p&gt;

&lt;p&gt;Je me suit donc beaucoup documenté à propos de Git, fais des essais, parcouru les manuels pour comprendre les commandes et leurs utilités puis j’ai cherché à trouver un modèle de travail en équipe satisfaisant, propre et surtout simple à suivre.&lt;/p&gt;

&lt;p&gt;Effectivement, si votre équipe ne suis pas une méthodologie de travail pré-déterminée, on se retrouve rapidement avec un historique fouillis, des merges inutiles, …&lt;/p&gt;

&lt;p&gt;Récemment, nous avons découvert une méthodologie particulièrement adaptée à notre façon de travailler et qui tire parti des points forts de Git. Pour ne rien gâcher, cette méthologie est accompagnée d’un ensemble de scripts qui étend Git et permettent de respecter facilement les guidelines de cette méthodologie.&lt;/p&gt;

&lt;p&gt;Avant de passer à la présentation de cette méthodologie, j’aimerai resituer le contexte. Nous travaillons à plusieurs, sur des projets qui peuvent durer plusieurs mois, voir plusieurs années. Des intervenants externes peuvent eux aussi contribuer au code. Nous avons besoin pour chaque projet d’une version de production, d’une version de développement et éventuellement de branches dédiées à de nouvelles fonctionnalités complexes qui doivent être isolées du reste du développement.&lt;/p&gt;

&lt;p&gt;Il faut donc qu’aucun développeur ne fasse l’erreur de travailler dans master qui est considéré comme un reflet du code en production, il faut également que chaque développeur gère correctement ses branches pour ne pas polluer la branche de développement. Si toute l’équipe respecte ces règles, on se retrouve avec un dépôt propre, un historique lisible et cohérent et donc un processus simplifié pour le déploiement en production ou la maintenance d’un serveur de pré-production tout en gardant la possibilité de faire évoluer le code très vite et dans diverses directions sans polluer le code stable.&lt;/p&gt;

&lt;h1 id="le-modle-adopt"&gt;Le modèle adopté&lt;/h1&gt;

&lt;p&gt;Nos recherches nous ont mené à &lt;a href="http://nvie.com/posts/a-successful-git-branching-model/"&gt;cet article&lt;/a&gt; qui décrit tout à fait la situation dans laquelle nous sommes et propose un workflow robuste.&lt;/p&gt;

&lt;p&gt;Première constatation, le choix de Git n’est pas anodin puisqu’il est particulièrement adapté à un modèle à base de branches. Tout notre worflow se reposera donc sur un système de branches.&lt;/p&gt;

&lt;p&gt;Lorsque nous commençons un projet, nous mettons toujours en place un dépôt central qui fait office de référence. Bien que Git soit un outil décentralisé, la mise en place d’un dépôt “maître” s’avère indispensable si vous travaillez à plusieurs. Chaque participant au projet va donc cloner le projet à partir de ce dépôt et c’est également sur ce dépôt que seront envoyées les modifications faîtes.&lt;/p&gt;

&lt;h2 id="une-branche-de-production-saine-et-cloisonne"&gt;Une branche de production saine et cloisonnée&lt;/h2&gt;

&lt;p&gt;Sur notre dépôt, nous avons besoin de pouvoir gérer le code en production ainsi que les développements en cours.&lt;/p&gt;

&lt;p&gt;Il est donc pertinent de considérer que la branche “master” représente l’état du code en production.&lt;/p&gt;

&lt;p&gt;Il nous suffit maintenant de créer une branche supplémentaire “develop” qui permet de gérer les développements pour les versions à venir, c’est ce qu’on appelle souvent la branche d’intégration :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; git branch develop
&lt;span class="gp"&gt;$&lt;/span&gt; git checkout develop
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;On peut donc dès maintenant contribuer au code et le commiter dans la branche “develop” sans que cela impacte notre code de production, voilà qui permet d’avancer en toute sérénité sans craindre que quelqu’un déploie du code non-testé ou validé.&lt;/p&gt;

&lt;h2 id="une-branche-pour-dvelopper-les-fonctionnalits-futures"&gt;Une branche pour développer les fonctionnalités futures&lt;/h2&gt;

&lt;p&gt;Dans “develop” nous allons donc faire de multiples commits pour agrémenter notre logiciel de nouvelles fonctionnalités. Cette branche peut d’ailleurs être utilisée en pré-production pour que vos testeurs et clients puissent profiter des avancements du projet et vous faire des retours.&lt;/p&gt;

&lt;p&gt;Mais attention, “develop” n’est pas un fourre-tout et ne devrait être utilisé que pour les petites modifications simples ayant peu d’impact et ne demandant pas plus de 30 min de travail. En effet si vous travaillez directement sur “develop” pour une fonctionnalité estimée à 1 mois de développement, il y a fort à parier que vous aller ennuyer vos collégues avec vos commits qui s’incrustent entre 2 commits légitimes sans pour autant apporter une fonctionnalité finalisée.&lt;/p&gt;

&lt;p&gt;Si vous êtes dans ce cas de figure, il vous faut créer une branche dédiée au développement de votre fonctionnalité.&lt;/p&gt;

&lt;h2 id="des-branches-spcifiques-pour-les-dveloppements-lourds"&gt;Des branches spécifiques pour les développements lourds&lt;/h2&gt;

&lt;p&gt;Ces branches de développement (feature) permettent de travailler de manière détachée du reste de l’équipe en onant vos modifications ce qui permet de ne les appliquer sur “develop” qu’une fois satisfait et par la même occasion de ne pas polluer les collègues.&lt;/p&gt;

&lt;p&gt;On peut vouloir commencer à développer une fonctionnalité qui ne sera appliquée qu’à la release N+1, la branche de feature est donc dans ce cas l’unique solution puisque tout ce qui est dans develop est considéré comme faisant partie intégrante de la prochaine release.&lt;/p&gt;

&lt;p&gt;Une branche de développement est créée à partir de “develop” et sera, une fois terminée, mergée dans “develop”. Ce type de branche reste généralement locale à la machine du développeur qui fini par la merger dans “develop” le moment voulu. Il reste toutefois des cas où ces branches de feature sont partagées sur le dépôt central pour une revue par les autres développeurs.&lt;/p&gt;

&lt;p&gt;Voici comment procéder :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; git checkout -b feature/foo develop
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;On a donc notre nouvelle branche “feature/foo” basée sur l’état actuel de “develop”. Nous pouvons donc coder et commiter autant de fois que nécessaire. Une fois fini, il faut intégrer cette branche dans “develop” :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; git checkout develop
&lt;span class="go"&gt;Switched to branch 'develop'&lt;/span&gt;

&lt;span class="gp"&gt;$&lt;/span&gt; git merge --no-ff feature/foo
&lt;span class="go"&gt;Updating ea1b82a..05e9557&lt;/span&gt;
&lt;span class="go"&gt;(Summary of changes)&lt;/span&gt;

&lt;span class="gp"&gt;$&lt;/span&gt; git branch -d feature/foo
&lt;span class="go"&gt;Deleted branch myfeature (was 05e9557).&lt;/span&gt;

&lt;span class="gp"&gt;$&lt;/span&gt; git push origin develop
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;On est donc retourné dans la branche “develop” dans laquelle on demande à git de merger notre branche de feature. L’option &lt;code&gt;--no-ff&lt;/code&gt; permet de forcer la création d’un commit même si les changements peuvent être intégrés en fast-forward. Ceci permet de garder une trace dans l’historique du développement dans une branche dédiée. Une fois mergée, nous supprimons la branche de feature devenue inutile et on push les modifications sur le serveur central.&lt;/p&gt;

&lt;h2 id="passage-en-production"&gt;Passage en production&lt;/h2&gt;

&lt;p&gt;Lorsque “develop” atteint un état satisfaisant pour créer un nouvelle release et déployer, il faut merger “develop” dans “master”, bumper la version, ajouter un tag de version, mettre à jour un README, … Enfin le code peut être déployé en production.&lt;/p&gt;

&lt;p&gt;On pourrait imaginer qu’à chaque commit dans “master”, un hook soit déclenché pour déployer en production.&lt;/p&gt;

&lt;p&gt;Nous allons donc, lors d’une release, créer une branche de support à la release. Les releases sont créées sur la base de la branche “develop” et doivent être mergées dans “master” et “develop”.&lt;/p&gt;

&lt;p&gt;Cette branche ne servira qu’à faire des modifications mineures liées à la création de la release :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; git checkout -b release/v1.2 develop
&lt;span class="go"&gt;Switched to a new branch "release/v1.2"&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;On peut maintenant bumper la version, mettre à jour le changelog, etc&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; git commit -a -m &lt;span class="s2"&gt;"Bumped version number to 1.2"&lt;/span&gt;
&lt;span class="go"&gt;[release/v1.1.2 74d9424] Bumped version number to 1.2&lt;/span&gt;
&lt;span class="go"&gt;1 files changed, 1 insertions(+), 1 deletions(-)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Il ne nous reste plus qu’à merger cette release dans master pour qu’elle prenne effet :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; git checkout master
&lt;span class="go"&gt;Switched to branch 'master'&lt;/span&gt;

&lt;span class="gp"&gt;$&lt;/span&gt; git merge --no-ff release/v1.2
&lt;span class="go"&gt;Merge made by recursive.&lt;/span&gt;
&lt;span class="go"&gt;(Summary of changes)&lt;/span&gt;

&lt;span class="gp"&gt;$&lt;/span&gt; git tag -a v1.2
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;On souhaite également récupérer ces informations de release dans “develop” :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; git checkout develop
&lt;span class="go"&gt;Switched to branch 'develop'&lt;/span&gt;

&lt;span class="gp"&gt;$&lt;/span&gt; git merge --no-ff release/v1.2
&lt;span class="go"&gt;Merge made by recursive.&lt;/span&gt;
&lt;span class="go"&gt;(Summary of changes)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Notre release est donc intégrée en production (master) et en intégration (develop), on peut supprimer la branche :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; git branch -d release/v1.2
&lt;span class="go"&gt;Deleted branch release/v1.2 (was ff452fe).&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;h2 id="dpanner-les-bugs-critiques-en-production"&gt;Dépanner les bugs critiques en production&lt;/h2&gt;

&lt;p&gt;Il vous arrivera certainement de faire face à un bug critique passé en production. Que faire dans ce cas ? Comment est-il géré dans le workflow ? Vous pensez peut-être qu’on doit nécessairement passer par une nouvelle release mais ce n’est pas le cas, ce n’est d’ailleurs même pas souhaitable puisque vous intégreriez au passage des fonctionnalités dans “develop” qui ne sont pas encore prête pour la production.&lt;/p&gt;

&lt;p&gt;Dans ce cas de figure, il s’agit de faire ce qu’on appelle un “hotfix”. Un hotfix est un patch qui va s’appliquer directement à la branche de production (master) et qui sera ensuite également appliqué sur la branche d’intégration (develop). On peut maintenant déployer la version de production corrigée mais aussi jouir de ces corrections dans “develop”.&lt;/p&gt;

&lt;p&gt;Pour se faire, comme toujours nous passerons par l’utilisation d’une branche pour avoir un historique sain :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; git checkout -b hotfix/v1.2.1 master
&lt;span class="go"&gt;Switched to a new branch "hotfix-1.2.1"&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;On crée une branche basée sur master et on bump la version du projet :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; git commit -a -m &lt;span class="s2"&gt;"Bumped version number to 1.2.1"&lt;/span&gt;
&lt;span class="go"&gt;[hotfix/v1.2.1 41e61bb] Bumped version number to 1.2.1&lt;/span&gt;
&lt;span class="go"&gt;1 files changed, 1 insertions(+), 1 deletions(-)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;On peut maintenant corriger le bug :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; git commit -m &lt;span class="s2"&gt;"Fix huge production bug"&lt;/span&gt;
&lt;span class="go"&gt;[hotfix/v1.2.1 abbe5d6] Fix huge production bug&lt;/span&gt;
&lt;span class="go"&gt;5 files changed, 32 insertions(+), 17 deletions(-)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Et intégrer la correction en production :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; git checkout master
&lt;span class="go"&gt;Switched to branch 'master'&lt;/span&gt;

&lt;span class="gp"&gt;$&lt;/span&gt; git merge --no-ff hotfix/v1.2.1
&lt;span class="go"&gt;Merge made by recursive.&lt;/span&gt;

&lt;span class="go"&gt;(Summary of changes)&lt;/span&gt;

&lt;span class="gp"&gt;$&lt;/span&gt; git tag -a v1.2.1
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;mais également en intégration pour ne pas perdre le fix au passage :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; git checkout develop
&lt;span class="go"&gt;Switched to branch 'develop'&lt;/span&gt;

&lt;span class="gp"&gt;$&lt;/span&gt; git merge --no-ff hotfix/v1.2.1
&lt;span class="go"&gt;Merge made by recursive.&lt;/span&gt;
&lt;span class="go"&gt;(Summary of changes)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Le patch étant intégré en production et en développement, on peut supprimer la branche de hotfix devenue inutile :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; git branch -d hotfix/v1.2.1
&lt;span class="go"&gt;Deleted branch hotfix/v1.2.1 (was abbe5d6).&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Tous les cas d’usages typiques ont été couverts et on voit qu’en suivant ce workflow, on peut maintenir un dépôt sain avec un historique clair et parfaitement adapté à la manipulation si d’aventure on devait revenir en arrière ou faire sauter une fonctionnalité.&lt;/p&gt;

&lt;p&gt;C’est propre et carré mais assez fastidieux n’est-ce pas ? Suivre ce modèle au quotidien demande concentration et discipline, pour tous les développeurs. Heureusement, une bonne âme nous simplifie le travail grâce à un ensemble d’extensions pour Git qui permettent de simplifier l’application de ce workflow.&lt;/p&gt;

&lt;h1 id="git-flow"&gt;Git-flow&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://github.com/nvie/gitflow"&gt;Git-flow&lt;/a&gt; est un ensemble d’extensions pour Git livré sous forme de shell-scripts très simples d’accès.&lt;/p&gt;

&lt;p&gt;Git-flow va permettre de suivre le workflow présenté précédemment sans avoir à tout retenir, surtout si comme moi vous êtes un peu perdu avec toutes les commandes et options de Git.&lt;/p&gt;

&lt;h2 id="initialisation"&gt;Initialisation&lt;/h2&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; git flow init
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;va permettre de paramétrer votre dépôt pour une utilisation via git-flow. Notez que tout ceci est local ce qui veut dire que vous pouvez très bien utiliser git-flow alors que vos collègues ne l’utilisent pas.&lt;/p&gt;

&lt;p&gt;Des questions sur la nomenclature vous seront posées, je vous conseille vivement d’utiliser les valeurs par défaut qui sont quasiment des conventions.&lt;/p&gt;

&lt;p&gt;Une fois terminé, vous êtes automatiquement positionné sur la branche “develop”, vous pouvez commencer à travailler.&lt;/p&gt;

&lt;h2 id="crer-une-branche-de-feature"&gt;Créer une branche de feature&lt;/h2&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; git flow feature start foo
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Vous êtes désormais dans la branche “feature/foo” dans laquelle vous pouvez développer tranquillement votre fonctionnalité. Vous pouvez bien évidemment repartir dans d’autres branches, créer plusieurs branches de feature en parallèle, etc.&lt;/p&gt;

&lt;p&gt;Une fois vos modifications terminées et prêtent à être intégrées dans “develop”, vous pouvez finaliser cette branche :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; git flow feature finish foo
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Votre branche “feature/foo” va être mergée dans “develop” puis effacée et vous vous retrouverez à nouveau sur la branche “develop”.&lt;/p&gt;

&lt;h2 id="mise-en-production"&gt;Mise en production&lt;/h2&gt;

&lt;p&gt;Lorsque “develop” représente l’état souhaité en production, vous pouvez passer à la release :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; git flow release start v1.0.0
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Une branche “release/v1.0.0” est créée, vous pouvez donc bumper la version de l’appli et faire les dernières modifications avant release. Une fois paré, vous pouvez finaliser la release :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; git flow release finish v1.0.0
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Ceci aura pour effet de merger “develop” dans “master”, de taguer la release, puis de back-merger ces modifications dans “develop”. La branche de release sera ensuite supprimée et vous retournerez sur la branche “develop”.&lt;/p&gt;

&lt;h2 id="hotfix"&gt;Hotfix&lt;/h2&gt;

&lt;p&gt;Si vous avez besoin de patcher urgemment la production, vous utiliserez la commande dédiée aux hotfixes :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; git flow hotfix start typo
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Une branche “hotfix/typo” est créée et vous pouvez commencer à patcher. Une fois fini, il suffira de finaliser la branche :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; git flow hotfix finish typo
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Ceci aura pour effet d’appliquer votre fix sur master et develop, d’ajouter un tag puis de supprimer la branche de hotfix. À ce propos, n’oubliez pas de bumper la version avant de finaliser le hotfix.&lt;/p&gt;

&lt;p&gt;J’espère avoir pu vous éclairer un peu sur la façon dont nous gérons le code source dans nos équipes et que celà vous donnera envie d’essayer ce worflow qui selon moi devrait permettre à vos dépôts de rester cohérents, de pouvoir gérer indépendamment les avancées fonctionnelles, les patchs et releases sans finir la journée avec un mal de tête !&lt;/p&gt;

&lt;p&gt;L’équipe Synbioz.&lt;/p&gt;

&lt;p&gt;Libres d’être ensembles.&lt;/p&gt;</description>
      <pubDate>Tue, 07 Feb 2012 00:00:00 +0100</pubDate>
      <guid>http://www.synbioz.com/blog/2012/02/07/git-adopter-un-modele-de-versionnement-efficace</guid>
      <author>Nicolas Cavigneaux</author>
      <category>git</category>
    </item>
    <item>
      <title>Le kit du bon développeur Rails, quelques gems à connaitre, partie 2</title>
      <link>http://www.synbioz.com/blog/2012/02/01/le_kit_du_bon_developpeur_rails_partie_2</link>
      <description>&lt;p&gt;Il est toujours bon pour un développeur de connaître quelques gems qui vont lui permettre de développer les fonctionnalités de base d’un site ou d’une application. Cet article est la suite du &lt;a href="http://www.synbioz.com/blog/2011/12/28/le_kit_du_bon_developpeur_rails_partie_1"&gt;kit du bon développeur rails&lt;/a&gt; publié il y a quelques semaines sur le blog. Nous avions pu explorer des sujets tels que le déploiement, l’authentification, les formulaires de recherche mais d’autres thèmes restent à voir, nous allons en explorer une autre partie dans cet article.&lt;/p&gt;

&lt;h2 id="internationalisation"&gt;Internationalisation&lt;/h2&gt;

&lt;p&gt;Un site multi-langue entraîne forcément l’utilisation de I18n qui est présent dans Rails. En effet, afin de pouvoir traduire vos contenus il est nécessaire de n’avoir aucun texte en dur dans votre code. Cependant, il est parfois nécessaire de ne traduire qu’une seule partie de la page et dans ce cas il existe des gems pour vous faciliter la tâche.&lt;/p&gt;

&lt;h3 id="i18n"&gt;I18n&lt;/h3&gt;

&lt;p&gt;I18n est donc utilisé dans Rails pour traduire tous vos textes. Vous pouvez par ailleurs obtenir plus d’informations sur la &lt;a href="http://guides.rubyonrails.org/i18n.html"&gt;page I18n&lt;/a&gt; sur le site de RubyOnRails. Pour cela, Rails se base sur la langue définie pour I18n. Il vous est possible de la définir via la ligne de commande suivante :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="no"&gt;I18n&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;locale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:fr&lt;/span&gt; &lt;span class="c1"&gt;# pour dÃ©finir franÃ§ais comme langue&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Il est également possible de définir une langue par défaut pour votre application dans le fichier config/environment.rb ou config/application.rb selon la version de Rails.&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;i18n&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;default_locale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:fr&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Pour ce qui est de la traduction en elle même il vous suffit de créer des fichier (.yml ou .rb) par langues dans le répertoire &lt;em&gt;config/locales&lt;/em&gt; de votre application. Il est également possible de prendre en compte d’autres fichiers en spécifiant où les trouver dans le fichier config/application.rb via la ligne suivante :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;i18n&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load_path&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'my'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'locales'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'*.{rb,yml}'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Il devient ensuite très simple d’avoir une application traduite dans plusieurs langues. On peut via le controller par exemple spécifier la langue.&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ApplicationController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActionController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="n"&gt;before_filter&lt;/span&gt; &lt;span class="ss"&gt;:set_locale&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;set_locale&lt;/span&gt;
    &lt;span class="no"&gt;I18n&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;locale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:locale&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Afin d’utiliser vos traductions, il faut utiliser la méthode &lt;em&gt;translate&lt;/em&gt; de I18n qui retourne le texte dans la langue spécifiée. Par exemple, dans une vue, si vous avez défini la langue à français vous pouvez reprendre l’exemple qui suit :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;  &lt;span class="o"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"views.home_title"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Ce code vous affiche le texte défini, en français, pour la clé &lt;em&gt;home_title&lt;/em&gt; dans votre fichier config/locales/fr.yml:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;fr:
  views:
    home_title: "Page d'accueil"
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Ce fichier vous permet également de définir les libellés des attributs des &lt;em&gt;models&lt;/em&gt; ou les messages d’erreurs.&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;fr:
  activerecord:
    attributes:
      category:
        title: "Titre de la catÃ©gorie"
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Il est parfois nécessaire de ne traduire qu’une seule partie de la page ou du contenu saisi en base et I18n n’offre pas ces possibilités, il existe donc des gems capables de le faire.&lt;/p&gt;

&lt;h3 id="globalize3"&gt;Globalize3&lt;/h3&gt;

&lt;p&gt;Globalize3 est une gem permettant de traduire du contenu dynamique (attributs d’un modèle). Elle succède à la gem Globalize. Il est possible d’obtenir des informations sur cette gem sur &lt;a href="https://github.com/svenfuchs/globalize3"&gt;la page Github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Pour installer cette gem, il vous suffit de l’ajouter à votre Gemfile puis de lancer la commande &lt;em&gt;bundle install&lt;/em&gt; :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;gem 'globalize3'
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Ensuite, il faut spécifier dans le &lt;em&gt;model&lt;/em&gt; les champs qui seront traduits :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Category&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="n"&gt;translates&lt;/span&gt; &lt;span class="ss"&gt;:title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:description&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Une migration est alors nécessaire afin de créer la table où seront stockées les traductions :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CreateCategories&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Migration&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;up&lt;/span&gt;
    &lt;span class="n"&gt;create_table&lt;/span&gt; &lt;span class="ss"&gt;:categories&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timestamps&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="no"&gt;Category&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_translation_table!&lt;/span&gt; &lt;span class="ss"&gt;:title&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:description&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:text&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;down&lt;/span&gt;
    &lt;span class="n"&gt;drop_table&lt;/span&gt; &lt;span class="ss"&gt;:categories&lt;/span&gt;
    &lt;span class="no"&gt;Category&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drop_translation_table!&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Attention, pour les projets utilisant Rails 3.1 ou plus, il ne faut pas utiliser la méthode &lt;em&gt;change&lt;/em&gt; mais continuer à utiliser &lt;em&gt;up&lt;/em&gt; et &lt;em&gt;down&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Pour une utilisation “basique” de votre application, c’est-à-dire, en utilisant une seule langue par page, vous n’aurez rien à faire dans vos vues. En effet, les champs seront affichés dans la langue du site (I18n.locale) et vous allez donc avoir les contenus stockés en base affichés suivant la locale, ce qui est le but pour des sites multi-langues où l’on veut juste avoir le contenu traduit suivant la langue choisie par l’utilisateur.&lt;/p&gt;

&lt;p&gt;Cependant, si vous souhaitez utiliser plusieurs langues sur une même page, ce qui est demandé dans certains cas, il vous faut utiliser les blocs définis par Globalize3. Dans les vues de votre projet Rails, ces derniers servent à traduire une partie de votre contenu dans une langue choisie auparavant :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="o"&gt;&amp;lt;%&lt;/span&gt;
  &lt;span class="n"&gt;my_locale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:fr&lt;/span&gt;
  &lt;span class="c1"&gt;# my_locale peut Ã©galement Ãªtre un helper ou une variable dÃ©finie dans le controller.&lt;/span&gt;
&lt;span class="sx"&gt;%&amp;gt;&lt;/span&gt;

&lt;span class="sx"&gt;&amp;lt;% Globalize.with_locale(my_locale) do %&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;% render &lt;/span&gt;&lt;span class="ss"&gt;:partial&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"my_partial_with_locale"&lt;/span&gt; &lt;span class="sx"&gt;%&amp;gt;&lt;/span&gt;
&lt;span class="sx"&gt;&amp;lt;% end %&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;On peut donc avoir le contenu des pages en anglais et uniquement la partie qui se trouve incluse dans le bloc Globalize traduite en français par exemple. Il est donc très simple d’utiliser plusieurs langues dans une même vue.&lt;/p&gt;

&lt;h2 id="gestion-de-fichiers"&gt;Gestion de fichiers&lt;/h2&gt;

&lt;p&gt;La gestion de fichiers est un autre point important lors de la création d’une application ou d’un site web. On peut avoir des images à stocker si on permet à l’utilisateur de les uploader par exemple. Différentes gems existent pour vous aider dans cette démarche.&lt;/p&gt;

&lt;h3 id="paperclip"&gt;Paperclip&lt;/h3&gt;

&lt;p&gt;Paperclip est une gem qui permet de gérer des fichiers suite à l’upload par un utilisateur. Il est possible d’obtenir des informations sur cette gem sur la &lt;a href="https://github.com/thoughtbot/paperclip"&gt;page Github de Paperclip&lt;/a&gt;. Afin de pouvoir utiliser cette dernière il est nécessaire d’avoir installé &lt;em&gt;imagemagick&lt;/em&gt;. Ensuite, pour installer Paperclip, il vvous suffit de l’ajouter dans votre Gemfile et lancer un &lt;em&gt;bundle install&lt;/em&gt; :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;gem "paperclip"
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Dans le &lt;em&gt;model&lt;/em&gt;, il faut spécifier le champ qui concerne le fichier à stocker :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Category&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="n"&gt;has_attached_file&lt;/span&gt; &lt;span class="ss"&gt;:logo&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Il est possible, si le fichier en question est une image de créer différentes versions du fichier, par exemple, stocker l’image dans différentes tailles :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Category&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="n"&gt;has_attached_file&lt;/span&gt; &lt;span class="ss"&gt;:logo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:styles&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;:large&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"600x300&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:medium&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"200x100"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:thumb&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"100x50&amp;gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;# dans ce cas l'image sera stockÃ©e quatre fois : l'image de base telle qu'elle est uploadÃ©e&lt;/span&gt;
  &lt;span class="c1"&gt;# ainsi que les trois formats dÃ©finis ci-dessus&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Ensuite, la migration vous permettra de créer les différents champs utilisés par Paperclip :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AddLogoToCategory&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Migration&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;up&lt;/span&gt;
    &lt;span class="n"&gt;change_table&lt;/span&gt; &lt;span class="ss"&gt;:categories&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;has_attached_file&lt;/span&gt; &lt;span class="ss"&gt;:logo&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;down&lt;/span&gt;
    &lt;span class="n"&gt;drop_attached_file&lt;/span&gt; &lt;span class="ss"&gt;:categories&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:logo&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Après avoir lancer un &lt;em&gt;rake db:migrate&lt;/em&gt; vos champs sont donc en base et vous pouvez donc uploader un logo pour vos catégories dans votre formulaire de création ou d’édition :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;%= form_for @category, :html =&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;:multipart&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="sx"&gt;%&amp;gt;&lt;/span&gt;
&lt;span class="sx"&gt;  &amp;lt;%= form.label :title %&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;%= form.text_field :title %&amp;gt;&lt;/span&gt;

&lt;span class="sx"&gt;  &amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;form&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt; &lt;span class="ss"&gt;:logo&lt;/span&gt; &lt;span class="sx"&gt;%&amp;gt;&lt;/span&gt;
&lt;span class="sx"&gt;  &amp;lt;%= form.file_field :logo %&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;% end &lt;/span&gt;&lt;span class="o"&gt;%&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Par la suite, vous pourrez afficher les images en question dans les formats souhaités :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="c1"&gt;# pour afficher l'image telle qu'elle a Ã©tÃ© uploadÃ©e&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;%= image_tag @category.logo.url %&amp;gt;&lt;/span&gt;

&lt;span class="sx"&gt;# pour afficher l'image en format 'medium'&lt;/span&gt;
&lt;span class="sx"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;image_tag&lt;/span&gt; &lt;span class="vi"&gt;@category&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:medium&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Pour supprimer un fichier uploader, il suffit de mettre la valeur du champ en question à &lt;em&gt;nil&lt;/em&gt; :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="vi"&gt;@category&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Il est possible de faire fonctionner Paperclip avec le service de stockage d’Amazon S3 via une autre gem, &lt;a href="http://rubydoc.info/gems/paperclip/Paperclip/Storage/S3"&gt;&lt;em&gt;aws-sdk&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;D’autres exemples d’utilisation de Paperclip sont disponibles dans &lt;a href="http://railscasts.com/episodes/134-paperclip"&gt;un Railscast&lt;/a&gt; de Ryan Bates.&lt;/p&gt;

&lt;p&gt;Encore une fois Paperclip n’est pas la seule gem disponible afin de vous aider dans la gestion des fichiers.&lt;/p&gt;

&lt;h3 id="dragonfly"&gt;Dragonfly&lt;/h3&gt;

&lt;p&gt;Tout comme Paperclip, Dragonfly est une gem permettant de gérer les fichiers dans votre application Rails. Des informations sont disponibles sur la &lt;a href="https://github.com/markevans/dragonfly"&gt;page Github de Dragonfly&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Afin d’installer Dragonfly, il vous faut l’ajouter à votre Gemfile :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;gem 'rack-cache', :require =&amp;gt; 'rack/cache'
gem 'dragonfly', '~&amp;gt;0.9.10'
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;La gem &lt;em&gt;rack-cache&lt;/em&gt; est nécessaire au fonctionnement de Dragonfly.&lt;/p&gt;

&lt;p&gt;Ensuite, ajoutez la ligne suivante dans le fichier config/initializers/dragonfly.rb (qu’il vous faudra créer auparavant si il n’existe pas) :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'dragonfly/rails/images'&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Vous pouvez maintenant créer la migration qui permettra de stocker le fichier :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AddLogoToCategory&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Migration&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;up&lt;/span&gt;
    &lt;span class="n"&gt;add_column&lt;/span&gt; &lt;span class="ss"&gt;:categories&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:logo_uid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:string&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;down&lt;/span&gt;
    &lt;span class="n"&gt;remove_column&lt;/span&gt; &lt;span class="ss"&gt;:categories&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:logo_uid&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Puis, dans le &lt;em&gt;model&lt;/em&gt; en question (dans notre cas &lt;em&gt;Category&lt;/em&gt;), vous devez ajouter un &lt;em&gt;image_accessor&lt;/em&gt; :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Category&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="n"&gt;image_accessor&lt;/span&gt; &lt;span class="ss"&gt;:logo&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Il vous est désormais possible d’uploader les logos de vos catégories via un formulaire, dans l’une des vues de votre projet :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;%= form_for @category, :html =&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;:multipart&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="sx"&gt;%&amp;gt;&lt;/span&gt;
&lt;span class="sx"&gt;  &amp;lt;%= form.label :title %&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;%= form.text_field :title %&amp;gt;&lt;/span&gt;

&lt;span class="sx"&gt;  &amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;form&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt; &lt;span class="ss"&gt;:logo&lt;/span&gt; &lt;span class="sx"&gt;%&amp;gt;&lt;/span&gt;
&lt;span class="sx"&gt;  &amp;lt;%= form.file_field :logo %&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;% end &lt;/span&gt;&lt;span class="o"&gt;%&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Afin de supprimer un fichier, vous pouvez utiliser une &lt;em&gt;checkbox&lt;/em&gt; dans votre formulaire :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="o"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;check_box&lt;/span&gt; &lt;span class="ss"&gt;:remove_logo&lt;/span&gt; &lt;span class="o"&gt;%&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Si cette dernière a pour valeur &lt;em&gt;true&lt;/em&gt; alors le fichier sera supprimé.&lt;/p&gt;

&lt;p&gt;Pour ce qui est de l’affichage d’une image, contrairement à Paperclip, on ne définit pas les formats d’une image lors de la sauvegarde mais lors de l’affichage.&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="c1"&gt;# pour afficher l'image telle qu'elle a Ã©tÃ© uploadÃ©e&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;%= image_tag @category.logo.url %&amp;gt;&lt;/span&gt;

&lt;span class="sx"&gt;# pour afficher l'image dans un autre format&lt;/span&gt;
&lt;span class="sx"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;image_tag&lt;/span&gt; &lt;span class="vi"&gt;@category&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;thumb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"200x100"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;%&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Dragonfly et Paperclip sont donc deux gems pour la gestion de fichier. Chacun peut choisir celui avec lequel il a le plus d’affinités et qu’il trouve le mieux adapté à ses besoins.&lt;/p&gt;

&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Ces deux articles offrent un bon tour d’horizon des solutions actuelles pour les besoins récurrents.
Dans la dernière partie nous évoquerons les tests et les outils annexes.&lt;/p&gt;

&lt;p&gt;Connaître ces gems peut s’avérer très pratique, c’est un gain de temps dans la plupart des cas, cela évite de repartir de zéro lors du développement de certaines fonctionnalités.&lt;/p&gt;

&lt;p&gt;Au delà des gems présentées, il existe des gems pour presque toutes les fonctionnalités, il vous est donc facile de trouver celle qui est la plus adaptée pour vous.&lt;/p&gt;

&lt;p&gt;De plus, la plupart des gems sont disponibles sur Github et il est donc très simple de remonter un bug ou de poser une question. En outre, ces gems sont utilisées par de très nombreux développeurs, on peut donc considérer qu’elles sont testées et approuvées par la communauté.&lt;/p&gt;

&lt;p&gt;Il n’y a donc aucune raison pour ne pas utiliser les gems existantes plutôt que de développer soi-même des fonctionnalités de base.&lt;/p&gt;

&lt;p&gt;L’équipe Synbioz.&lt;/p&gt;

&lt;p&gt;Libres d’être ensembles.&lt;/p&gt;</description>
      <pubDate>Wed, 01 Feb 2012 00:00:00 +0100</pubDate>
      <guid>http://www.synbioz.com/blog/2012/02/01/le_kit_du_bon_developpeur_rails_partie_2</guid>
      <author>Alexandre Salaün</author>
      <category>rails</category>
    </item>
    <item>
      <title>Le méconnu inverse_of</title>
      <link>http://www.synbioz.com/blog/2012/01/27/le_meconnu_inverse_of</link>
      <description>&lt;h1 id="rails-le-mconnu-inverseof"&gt;Rails: le méconnu inverse_of&lt;/h1&gt;

&lt;h2 id="active-record-le-patron-de-conception"&gt;Active record: le patron de conception&lt;/h2&gt;

&lt;p&gt;Active record, avant d’être le nom d’une célèbre gem inclue dans rails est
le nom d’un design pattern, permettant de faire du mapping objet - relationnel.&lt;/p&gt;

&lt;p&gt;C’est à dire qu’il vous permet de manipuler sous forme d’objets vos données
stockées dans une base de données.&lt;/p&gt;

&lt;h2 id="optimiser-la-communication-entre-les-objets-et-la-base-de-donne"&gt;Optimiser la communication entre les objets et la base de donnée&lt;/h2&gt;

&lt;p&gt;La gem ActiveRecord vous offre un maximum de confort en mettant à disposition
toutes les méthodes pour gérer les opérations basiques de CRUD mais aussi
les associations entre tables.&lt;/p&gt;

&lt;p&gt;Imaginons deux class product et category:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Category&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
    &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:products&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;div class="highlight"&gt;
&lt;pre&gt;  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Product&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
    &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:category&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Regardons quels sont les appels effectués à la base lorsque nous parcourons les objets:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;  &lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="mo"&gt;00&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Category&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:include&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:products&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="no"&gt;Category&lt;/span&gt; &lt;span class="no"&gt;Load&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="n"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="no"&gt;SELECT&lt;/span&gt; &lt;span class="s2"&gt;"categories"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;*&lt;/span&gt; &lt;span class="no"&gt;FROM&lt;/span&gt; &lt;span class="s2"&gt;"categories"&lt;/span&gt; &lt;span class="no"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="no"&gt;Product&lt;/span&gt; &lt;span class="no"&gt;Load&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="no"&gt;SELECT&lt;/span&gt; &lt;span class="s2"&gt;"products"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;*&lt;/span&gt; &lt;span class="no"&gt;FROM&lt;/span&gt; &lt;span class="s2"&gt;"products"&lt;/span&gt; &lt;span class="no"&gt;WHERE&lt;/span&gt; &lt;span class="s2"&gt;"products"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s2"&gt;"category_id"&lt;/span&gt; &lt;span class="no"&gt;IN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;#&amp;lt;Category id: 1, name: "TÃ©lÃ©phone", created_at: "2012-01-27 11:21:59", updated_at: "2012-01-27 11:21:59"&amp;gt;&lt;/span&gt;
  &lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="mo"&gt;00&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;products&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt;
    &lt;span class="no"&gt;Category&lt;/span&gt; &lt;span class="no"&gt;Load&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="no"&gt;SELECT&lt;/span&gt; &lt;span class="s2"&gt;"categories"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;*&lt;/span&gt; &lt;span class="no"&gt;FROM&lt;/span&gt; &lt;span class="s2"&gt;"categories"&lt;/span&gt; &lt;span class="no"&gt;WHERE&lt;/span&gt; &lt;span class="s2"&gt;"categories"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s2"&gt;"id"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="no"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;#&amp;lt;Category id: 1, name: "TÃ©lÃ©phone", created_at: "2012-01-27 11:21:59", updated_at: "2012-01-27 11:21:59"&amp;gt;&lt;/span&gt;
  &lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="mo"&gt;010&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;c2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_id&lt;/span&gt;
  &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;ActiveRecord n’est pas suffisamment malin pour comprendre que nous sommes en fait sur la même
catégorie quand nous demandons la catégorie d’un produit qui fait parti de la liste des produits
de cette même catégorie.&lt;/p&gt;

&lt;h2 id="le-rle-dinverseof"&gt;Le rôle d’inverse_of&lt;/h2&gt;

&lt;p&gt;Redéfinissons nos relations pour utiliser inverse_of:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Category&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
    &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:products&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:inverse_of&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:category&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;div class="highlight"&gt;
&lt;pre&gt;  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Product&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
    &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:inverse_of&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:products&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;div class="highlight"&gt;
&lt;pre&gt;  irb(main):004:0&amp;gt; c2 = Category.first(:include =&amp;gt; :products)
    Category Load (0.2ms)  SELECT "categories".* FROM "categories" LIMIT 1
    Product Load (0.2ms)  SELECT "products".* FROM "products" WHERE "products"."category_id" IN (1)
  =&amp;gt; #&amp;lt;Category id: 1, name: "TÃ©lÃ©phone", created_at: "2012-01-27 11:21:59", updated_at: "2012-01-27 11:21:59"&amp;gt;
  irb(main):005:0&amp;gt; c3 = c2.products.first.category
  =&amp;gt; #&amp;lt;Category id: 1, name: "TÃ©lÃ©phone", created_at: "2012-01-27 11:21:59", updated_at: "2012-01-27 11:21:59"&amp;gt;
  irb(main):006:0&amp;gt; c3.object_id == c2.object_id
  =&amp;gt; true
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;En explicitant la relation inverse ActiveRecord sait maintenant
retrouver ses petits et éviter d’inutiles requêtes SQL.&lt;/p&gt;

&lt;h2 id="les-formulaires-imbriqus"&gt;Les formulaires imbriqués&lt;/h2&gt;

&lt;p&gt;Imaginons que vous souhaitiez pouvoir créer directement une catégorie
avec un ou plusieurs produits et que vous produits doivent obligatoirement
avoir une catégorie.&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Category&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
    &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:products&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:inverse_of&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:category&lt;/span&gt;

    &lt;span class="n"&gt;accepts_nested_attributes_for&lt;/span&gt; &lt;span class="ss"&gt;:products&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;div class="highlight"&gt;
&lt;pre&gt;  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Product&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
    &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:inverse_of&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:products&lt;/span&gt;

    &lt;span class="n"&gt;validates_presence_of&lt;/span&gt; &lt;span class="ss"&gt;:category&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Sans inverse_of vous risquez d’avoir des soucis à cause de la validation.
En effet, le produit ayant une validation sur sa catégorie, il va chercher à la charger.&lt;/p&gt;

&lt;p&gt;Sans inverse_of il essayera de la charger depuis la base de donnée, alors qu’elle n’existe
pas encore. Avec, il sera capable de récupérer directement l’objet.&lt;/p&gt;

&lt;h2 id="identity-map"&gt;Identity map&lt;/h2&gt;

&lt;p&gt;Très franchement ActiveRecord nous a habitué à un peu plus de magie et d’automatisme
pour que l’on n’ait pas envie de définir manuellement tous ses inverse_of.&lt;/p&gt;

&lt;p&gt;D’autant plus qu’il semble assez simple de retrouver les associations concordantes
et que cette fonctionnalité est présente dans &lt;a href="http://datamapper.org/why.html"&gt;datamapper&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;C’est en fait le rôle de la fonction &lt;a href="http://api.rubyonrails.org/classes/ActiveRecord/IdentityMap.html"&gt;d’identity map&lt;/a&gt; introduite par rails 3.1
mais désactivée par défaut.&lt;/p&gt;

&lt;p&gt;L’objectif est de n’avoir jamais à recharger un objet depuis la base quand il est déjà en mémoire.&lt;/p&gt;

&lt;p&gt;L’activation de la fonctionnalité se fait dans application.rb&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;  &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;active_record&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;identity_map&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;div class="highlight"&gt;
&lt;pre&gt;  &lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="mo"&gt;005&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;IdentityMap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Category&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;c2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Category&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="no"&gt;Category&lt;/span&gt; &lt;span class="no"&gt;Load&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;57&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="n"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="no"&gt;SELECT&lt;/span&gt; &lt;span class="s2"&gt;"categories"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;*&lt;/span&gt; &lt;span class="no"&gt;FROM&lt;/span&gt; &lt;span class="s2"&gt;"categories"&lt;/span&gt; &lt;span class="no"&gt;WHERE&lt;/span&gt; &lt;span class="s2"&gt;"categories"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s2"&gt;"id"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="no"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;  &lt;span class="o"&gt;[[&lt;/span&gt;&lt;span class="s2"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;]]&lt;/span&gt;
    &lt;span class="no"&gt;Category&lt;/span&gt; &lt;span class="no"&gt;Loaded&lt;/span&gt;  &lt;span class="no"&gt;From&lt;/span&gt; &lt;span class="no"&gt;Identity&lt;/span&gt; &lt;span class="no"&gt;Map&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;#&amp;lt;Category id: 1, name: "TÃ©lÃ©phone", created_at: "2012-01-27 11:21:59", updated_at: "2012-01-27 11:21:59"&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;L’utilisation se fait dans un bloc et l’usage est encore limité.
Par exemple utiliser Category.first, même dans le bloc entrainera
tout de même 2 requêtes.&lt;/p&gt;

&lt;p&gt;De plus l’activation de la fonction ne permet pas pour le moment
de remplacer le inverse_of.&lt;/p&gt;

&lt;p&gt;C’est pourtant une fonctionnalité très importante car elle
permettra de fortement &lt;a href="http://merbist.com/2010/07/29/object-allocation-why-you-should-care/"&gt;limiter le nombre d’instanciation d’objets&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Pour autant elle n’est pas simple à mettre en place en conservant un comportement
tread-safe : on imagine bien deux morceaux de code entrain de mettre à jour le même objet en mémoire.&lt;/p&gt;

&lt;p&gt;En résumé, utilisez le inverse_of dès aujourd’hui si ce n’est pas encore le cas car Rails n’est
pas prêt de le faire automatiquement pour vous.&lt;/p&gt;

&lt;p&gt;L’équipe Synbioz.&lt;/p&gt;

&lt;p&gt;Libres d’être ensembles.&lt;/p&gt;</description>
      <pubDate>Fri, 27 Jan 2012 00:00:00 +0100</pubDate>
      <guid>http://www.synbioz.com/blog/2012/01/27/le_meconnu_inverse_of</guid>
      <author>Martin Catty</author>
      <category>rails</category>
    </item>
    <item>
      <title>L'utilisation de vim</title>
      <link>http://www.synbioz.com/blog/2012/01/18/l_utilisation_de_vim</link>
      <description>&lt;p&gt;Une part importante de l’activité des développeurs se résume à éditer de simples fichiers textuels. Ces fichiers permettent de communiquer des instructions aux machines chargées de les exécuter. Pour le confort et la productivité d’un développeur, l’interface qui lui permettra de saisir son code est primordiale.&lt;/p&gt;

&lt;p&gt;Je compte deux approches différentes. Les &lt;a href="http://fr.wikipedia.org/wiki/Environnement_de_d%C3%A9veloppement_int%C3%A9gr%C3%A9"&gt;Environnements de Développement Intégrés&lt;/a&gt; qui intègrent un maximum d’outils : la gestion des projets, l’édition des sources, la compilation, le débogage, le système de gestion de configuration (&lt;a href="http://fr.wikipedia.org/wiki/Gestion_de_configuration_logicielle"&gt;SCM&lt;/a&gt;), etc. Les EDIs que j’ai en tête : &lt;a href="http://www.eclipse.org/"&gt;Eclipse&lt;/a&gt;, &lt;a href="http://netbeans.org/"&gt;Netbeans&lt;/a&gt; ou &lt;a href="http://www.jetbrains.com/idea/"&gt;IDEA&lt;/a&gt; pèsent plusieurs centaines de mégaoctets en mémoire, sont associé à une interface d’édition dont les principales fonctionnalités sont l’autocomplétion, le surlignage des erreurs et les snippets de codes. Et, les manipulateurs de textes comme &lt;a href="http://macromates.com/"&gt;TextMate&lt;/a&gt;, &lt;a href="http://www.sublimetext.com/"&gt;Sublime Text&lt;/a&gt;, &lt;a href="http://www.gnu.org/software/emacs/"&gt;EMACS&lt;/a&gt; ou, dans notre cas, &lt;a href="http://www.vim.org/"&gt;Vim&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Je voudrai présenter les bases de la manipulation de texte. Vim est probablement l’éditeur qui embrasse le plus ce concept et je vais plutôt vous présenter les bases de celui-ci. Dans un prochain article, je présenterai quelques aspects plus avancés.&lt;/p&gt;

&lt;p&gt;Avant de commencer, je vous recommande de vous procurer Vim, de l’installer et de le tester pendant votre lecture. Peu importe votre plateforme, Vim existe certainement pour cette dernière. Rendez-vous sur cette page de &lt;a href="http://www.vim.org/download.php"&gt;téléchargement&lt;/a&gt; pour l’installer.&lt;/p&gt;

&lt;h1 id="un-diteur-modal"&gt;Un éditeur modal&lt;/h1&gt;

&lt;p&gt;Vim est un éditeur destiné à une utilisation en ligne de commande, il fonctionne donc tout à fait normalement à distance (en &lt;a href="http://fr.wikipedia.org/wiki/Secure_Shell"&gt;SSH&lt;/a&gt; par exemple). Il n’y a pas de menus classiques dans l’interface de Vim. Vim est un éditeur modal. C’est-à-dire que chaque touche va avoir un comportement différent en fonction du mode dans lequel on se trouve. Cela décuple les interactions et la complexité apparente de l’éditeur puisque chaque touche va être utilisée de façon différente selon le mode dans lequel on se trouve.&lt;/p&gt;

&lt;p&gt;Vous vous demandez peut-être « Quels sont donc ces différents modes et à quoi servent-ils ? », alors commençons la visite.&lt;/p&gt;

&lt;h2 id="dition--insertion-et-remplacement"&gt;Édition : insertion et remplacement&lt;/h2&gt;

&lt;p&gt;C’est le mode le plus rapide à présenter. En effet, chaque caractère est inséré dans le fichier sous le curseur ce qui est probablement le plus familier des comportements. Pour ceux qui expérimentent pendant leur lecture vous remarquerez que ce n’est pas le mode par défaut de Vim. En effet lorsque vous lancez Vim, vous êtes en mode commande dont on reparlera juste après.&lt;/p&gt;

&lt;p&gt;Passer dans le mode d’édition peut se faire d’un grand nombre de manières, j’en vois déjà plus d’une dizaine. Vous pouvez accompagner ce changement de mode par un déplacement prédéfini. Ce sont ces déplacements qui sont à l’origine de cette variété.&lt;/p&gt;

&lt;p&gt;Voici un petit récapitulatif des commandes que j’utilise :&lt;/p&gt;

&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;Commande&lt;/th&gt;
&lt;th&gt;Passage dans le mode insertion&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;a&lt;/td&gt;
&lt;td&gt;après le curseur&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A&lt;/td&gt;
&lt;td&gt;en fin de ligne&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;i&lt;/td&gt;
&lt;td&gt;sous le curseur&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I&lt;/td&gt;
&lt;td&gt;en début de ligne&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;o&lt;/td&gt;
&lt;td&gt;sur une nouvelle ligne au-dessous&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;td&gt;sur une nouvelle ligne au-dessus&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;R&lt;/td&gt;
&lt;td&gt;sous le curseur en mode remplacement&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Vous remarquerez qu’il est facile d’associer ces commandes à des mots : ajouter, insérer, ouvrir une ligne, remplacer. Le fait d’utiliser une majuscule ou une minuscule modifie légèrement le comportement tout en conservant l’idée de la commande originale.&lt;/p&gt;

&lt;p&gt;Une fois passé en mode insertion, on se retrouve un peu comme prisonnier dans un champ texte, sans menu, sans copier-coller, sans même un fichier à soi. Essayons de retrouver les autres fonctionnalités des éditeurs de textes classiques. Pour cela on repasse en mode commande en pressant &lt;em&gt;ESC&lt;/em&gt;.&lt;/p&gt;

&lt;h2 id="commande"&gt;Commande&lt;/h2&gt;

&lt;p&gt;Lorsque Vim se lance, on est dans ce mode dit de commande, c’est celui qui se rapproche le plus de ce que les menus peuvent fournir aux autres éditeurs. Il permet d’ouvrir un fichier, d’enregistrer, d’enregistrer-sous, de copier, de coller, etc.&lt;/p&gt;

&lt;p&gt;Vim permet d’utiliser les commandes de l’éditeur &lt;a href="http://en.wikipedia.org/wiki/Ex_%28text_editor%29"&gt;Ex&lt;/a&gt;, un éditeur de texte plus historique encore que Vim lui-même. Cependant l’utilisation d’x est transparente pour l’utilisateur. Je vais présenter les deux catégories de commandes succinctement grâce à quelques exemples.&lt;/p&gt;

&lt;h3 id="les-commandes-de-vim"&gt;Les commandes de Vim&lt;/h3&gt;

&lt;p&gt;Il n’y a pas de retour visuel m’indiquant la commande que je suis en train de taper. Pour afficher le texte de la commande en cours tapez en mode commande : &lt;code&gt;:set showcmd&lt;/code&gt;. Après ça vous devriez voir la commande en cours d’écriture en bas à droite de la zone de texte. On peut classer les commandes en deux catégories, les opérateurs et les déplacements. Les opérateurs modifient le texte et les déplacements, comme leur nom l’indique, déplacent le curseur d’un endroit à l’autre du fichier.&lt;/p&gt;

&lt;p&gt;Les opérateurs que j’utilise sont les suivants :&lt;/p&gt;

&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;Opérateur&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;c&lt;/td&gt;
&lt;td&gt;Changer du texte&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;cc&lt;/td&gt;
&lt;td&gt;Changer la ligne entière&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C&lt;/td&gt;
&lt;td&gt;Changer du texte jusqu'à la fin de la ligne&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;d&lt;/td&gt;
&lt;td&gt;Supprimer du texte&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dd&lt;/td&gt;
&lt;td&gt;Supprimer la ligne entière&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;D&lt;/td&gt;
&lt;td&gt;Supprimer du texte jusqu'à la fin de la ligne&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;y&lt;/td&gt;
&lt;td&gt;Copier du texte&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;yy, Y&lt;/td&gt;
&lt;td&gt;Copier la ligne entière&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;p&lt;/td&gt;
&lt;td&gt;Coller du texte supprimé ou copié après le curseur&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;P&lt;/td&gt;
&lt;td&gt;Coller du texte supprimé ou copié sous le curseur&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;r&lt;/td&gt;
&lt;td&gt;Remplacer le caractère sous le curseur&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;x&lt;/td&gt;
&lt;td&gt;Supprimer le caractère sous le curseur&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;Supprimer le caractère précédent le curseur&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;gt;, &amp;lt;&lt;/td&gt;
&lt;td&gt;Indenter, desindenter d'une tabulation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;u&lt;/td&gt;
&lt;td&gt;Défaire la dernière action&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CTRL + r&lt;/td&gt;
&lt;td&gt;Refaire la dernière action&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.&lt;/td&gt;
&lt;td&gt;Rapplique la dernière commande exécutée&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Les principaux déplacements que j’utilise sont les suivants :&lt;/p&gt;

&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;Déplacement&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;w, b&lt;/td&gt;
&lt;td&gt;Début du mot suivant ou précédent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;W, B&lt;/td&gt;
&lt;td&gt;Début du mot suivant ou précédent en ignorant la ponctuation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;e, E&lt;/td&gt;
&lt;td&gt;Fin du mot courant en ignorant ou non la ponctuation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;%&lt;/td&gt;
&lt;td&gt;Symbole ouvrant ou fermant correspondant (chevrons, parenthèses, accolades, if / end, balises XML, etc)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;h, j, k, l&lt;/td&gt;
&lt;td&gt;Gauche, Bas, Haut, Droite&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;g0, g$&lt;/td&gt;
&lt;td&gt;Début ou fin d'une ligne (g facultatif)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;^, _&lt;/td&gt;
&lt;td&gt;Premier caractère d'une ligne&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ENTER, +&lt;/td&gt;
&lt;td&gt;Premier caractère de la ligne suivante&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Premier caractère de la ligne précédente&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;fx&lt;/td&gt;
&lt;td&gt;Premier caractère x après le curseur sur la même ligne&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;tx&lt;/td&gt;
&lt;td&gt;Premier caractère suivi d'un x après le curseur sur la même ligne&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;nG&lt;/td&gt;
&lt;td&gt;Début de la ligne n&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;G&lt;/td&gt;
&lt;td&gt;Fin du fichier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gg&lt;/td&gt;
&lt;td&gt;Début du fichier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;nG&lt;/td&gt;
&lt;td&gt;Début de la ligne n dans le fichier&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Pour éditer occasionnellement des fichiers de configuration, ces commandes ne sont pas toutes utiles. Mais, pour celui qui commence à utiliser Vim régulièrement, intégrer ces dernières à son workflow peut s’avérer un gain de temps important.&lt;/p&gt;

&lt;p&gt;Voici quelques combinaisons possibles :&lt;/p&gt;

&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;Commande&lt;/th&gt;
&lt;th&gt;Résultat&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;c3w&lt;/td&gt;
&lt;td&gt;Supprime les 3 prochains mots et passe en mode insertion&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5dd&lt;/td&gt;
&lt;td&gt;Supprime les 5 lignes sous le curseur&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3p&lt;/td&gt;
&lt;td&gt;Colle 3 fois le contenu du presse papier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;df.&lt;/td&gt;
&lt;td&gt;Supprime le texte de la ligne jusqu'au prochain caractère « . »&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5u&lt;/td&gt;
&lt;td&gt;Défait les 5 dernières actions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5 CTRL + r&lt;/td&gt;
&lt;td&gt;Refait les 5 dernières actions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;y45G&lt;/td&gt;
&lt;td&gt;Copie de la ligne courante à la ligne 45&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;gt;%&lt;/td&gt;
&lt;td&gt;Indenter jusqu'au symbole fermant&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Les commandes de Vim sont généralement de la forme &lt;em&gt;[n] opérateur [m] déplacement&lt;/em&gt;. Il est important de pouvoir créer ses propres commandes à la volée. Cela évite par exemple les répétitions de raccourcis (&lt;code&gt;CTRL + v&lt;/code&gt;, dix fois de suite) ou encore l’utilisation intensive de la souris pour se déplacer.&lt;/p&gt;

&lt;h3 id="les-commandes-de-ex"&gt;Les commandes de ex&lt;/h3&gt;

&lt;p&gt;Les commandes Ex, commencent par « &lt;em&gt;:&lt;/em&gt; », une partie d’entre elles ont des équivalents Vim purs. Par exemple on peut fermer Vim et enregistrer le fichier courant par &lt;code&gt;:x&lt;/code&gt; ou bien avec &lt;code&gt;ZZ&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Voici donc les commandes « du style Ex » que j’utilise régulièrement :&lt;/p&gt;

&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;Commande&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:e&lt;/td&gt;
&lt;td&gt;Éditer un fichier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:w&lt;/td&gt;
&lt;td&gt;Enregistrer un fichier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:w FILENAME&lt;/td&gt;
&lt;td&gt;Enregistrer un fichier sous le chemin FILENAME&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:q&lt;/td&gt;
&lt;td&gt;Quitte la fenêtre vim&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:x, :wq&lt;/td&gt;
&lt;td&gt;Sauvegarde puis quitte vim&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:n&lt;/td&gt;
&lt;td&gt;Se déplace au début de la ligne n&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:bnext&lt;/td&gt;
&lt;td&gt;Affiche le prochain fichier ouvert (buffer)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:bprevious&lt;/td&gt;
&lt;td&gt;Affiche le précédent fichier ouvert&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:bdelete&lt;/td&gt;
&lt;td&gt;Ferme le buffer courrant&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:ls&lt;/td&gt;
&lt;td&gt;Affiche la liste des buffers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:wa&lt;/td&gt;
&lt;td&gt;Enregistre tous les fichiers ouverts&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id="visuel"&gt;Visuel&lt;/h2&gt;

&lt;p&gt;En mode commande, la touche « &lt;code&gt;v&lt;/code&gt; » permet de passer en mode visuel, où l’on va pouvoir réaliser des sélections, un peu comme à la souris. Les commandes « &lt;code&gt;V&lt;/code&gt; » et « &lt;code&gt;CTRL + v&lt;/code&gt; » permettent respectivement de passer en mode visuel par ligne ou par bloc. Testez-les pour en comprendre le fonctionnement ou bien consultez la &lt;a href="http://vimdoc.sourceforge.net/htmldoc/visual.html"&gt;documentation du mode visuel de vim&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Une fois dans ce mode les commandes de déplacement de Vim sont accessibles pour effectuer la sélection. Par exemple « &lt;code&gt;v55G&lt;/code&gt; » passera du mode commande au mode visuel, débutera la sélection à l’endroit du curseur puis ira se placer sur le début de la ligne 55. On peut passer d’un bout à l’autre de la sélection avec « &lt;code&gt;o&lt;/code&gt; » et donc déplacer n’importe quelle extrémité de celle-ci.&lt;/p&gt;

&lt;h1 id="se-dplacer-plus-vite"&gt;Se déplacer plus vite&lt;/h1&gt;

&lt;h2 id="marques-pages"&gt;Marques pages&lt;/h2&gt;

&lt;p&gt;On ne se rappelle pas forcément dans un fichier de log d’un millier de lignes quels sont les numéros de celles qui nous intéressent. Nombre d’éditeurs proposent de poser des marques sur les lignes qui ont de l’importance et auxquelles vous voulez revenir facilement. Vim propose cette fonctionnalité à travers les marques pages.&lt;/p&gt;

&lt;p&gt;Poser des marques pages dans un fichier se fait avec « mx » où &lt;em&gt;x&lt;/em&gt; est un identifiant. L’identifiant est une lettre minuscule. On peut se déplacer à la ligne de la marque avec « ‘x » ou bien directement au caractère marqué avec « `x ». Pour revenir à l’endroit où on était on peut utiliser « ‘’ » pour revenir à cette ligne ou « `` » pour revenir au caractère précis précédant le déplacement.&lt;/p&gt;

&lt;p&gt;La portée de ces marques se limite au fichier ouvert. Pas possible donc de poser une de ces marques dans un fichier et d’y faire appel depuis un autre fichier. Cependant il existe un autre type de marques pages qui ont une portée globale et qui se distinguent simplement par le fait qu’ils utilisent un lettre majuscule ou bien un chiffre comme identifiant.&lt;/p&gt;

&lt;h2 id="grer-plusieurs-fentres"&gt;Gérer plusieurs fenêtres&lt;/h2&gt;

&lt;p&gt;Parfois il est plus simple, plutôt que de se déplacer, d’avoir deux parties d’un même fichier visible en même temps. Vim propose un système de &lt;a href="http://vimdoc.sourceforge.net/htmldoc/windows.html"&gt;fenêtres&lt;/a&gt; pour cela. Une fenêtre c’est une vue sur une partie d’un fichier. Deux fenêtres peuvent afficher un même fichier, et le faire à des positions différentes. Voici une capture d’écran illustrant un exemple de session où il y a deux fenêtres :&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.synbioz.com/images/articles/vim-split.png" target="_blank"&gt;&lt;img src="http://www.synbioz.com/images/articles/vim-split_thumb_450.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bien sûr les fenêtres peuvent afficher des fichiers différents.&lt;/p&gt;

&lt;p&gt;Voici un récapitulatif des commandes permettant de manipuler ces fenêtres :&lt;/p&gt;

&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;Commande&lt;/th&gt;
&lt;th&gt;Résultat&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:split, CTRL + w s&lt;/td&gt;
&lt;td&gt;Sépare horizontalement la fenêtre courante en deux&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:vsplit, CTRL + w v&lt;/td&gt;
&lt;td&gt;Sépare verticalement la fenêtre courante en deux&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:close, CTRL + w c&lt;/td&gt;
&lt;td&gt;Ferme la fenêtre si ce n'est pas la dernière&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:resize n, zn, n CTRL + w _&lt;/td&gt;
&lt;td&gt;Définit le nombre de lignes visible à n&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:vertical resize n, n CTRL + |&lt;/td&gt;
&lt;td&gt;Définit le nombre de colonnes visible à n&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:only, CTRL + w o&lt;/td&gt;
&lt;td&gt;Conserve uniquement la fenêtre active et ferme toutes les autres&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CTRL + W DIR&lt;/td&gt;
&lt;td&gt;Se déplace dans la fenêtre suivante, dans la direction DIR (h, j, k, l, flêches)&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Il est également possible d’utiliser la souris pour redimensionner les fenêtres de Vim (voir l’option &lt;code&gt;mouse&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;En complément des fenêtres, il existe des onglets. Ils permettent d’avoir différents ensembles de fenêtres ouvertes et de passer de l’un à l’autre. Je n’utilise pas vraiment les onglets et donc je vous recommande de regarder la &lt;a href="http://vimdoc.sourceforge.net/htmldoc/tabpage.html"&gt;documentation&lt;/a&gt; pour en savoir plus.&lt;/p&gt;

&lt;h1 id="recherche-et-substitution"&gt;Recherche et substitution&lt;/h1&gt;

&lt;p&gt;Dans tout bon éditeur de texte, on dispose des fonctions rechercher et remplacer ; dans Vim aussi ces fonctions sont accessibles. On peut effectuer ces opérations sur une plage de ligne, sur une sélection, sur l’ensemble du fichier, etc. Je vais commencer par introduire les différentes commandes de recherches. Il faut savoir que ces commandes se combinent avec les autres comme un déplacement. On peut par exemple supprimer du texte jusqu’au prochain résultat de recherche avec &lt;code&gt;d/pattern&lt;/code&gt;.&lt;/p&gt;

&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;Commande&lt;/th&gt;
&lt;th&gt;Recherche&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;/pattern&lt;/td&gt;
&lt;td&gt;Recherche en avant le motif pattern&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;?pattern&lt;/td&gt;
&lt;td&gt;Recherche en arrière le motif pattern&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;n, N&lt;/td&gt;
&lt;td&gt;Saute au résultat suivant, précédent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;*, #&lt;/td&gt;
&lt;td&gt;Recherche le mot sous le curseur en avant, en arrière&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;g*, g#&lt;/td&gt;
&lt;td&gt;Recherche le mot sous le curseur autorisant son inclusion dans d'autres mots&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:nohlsearch&lt;/td&gt;
&lt;td&gt;Desactive le surlignage des résultats d'un recherche jusqu'à la prochaine&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Ces commandes permettent de faire de la recherche et des déplacements dans Vim. Il est possible de (des)activer la recherche incrémentale, la coloration des résultats, etc. Les patterns employés utilisent les expressions régulières avec &lt;a href="http://vimdoc.sourceforge.net/htmldoc/usr_27.html"&gt;une syntaxe spécifique à Vim&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Le remplacement dans Vim se fait grâce à la commande Ex &lt;em&gt;substitute&lt;/em&gt; : « &lt;code&gt;s&lt;/code&gt; ». Cette dernière fait partie de Ex et adopte la syntaxe suivante : &lt;em&gt;:[adresse] commande&lt;/em&gt;. Les adresses sont généralement de la forme &lt;em&gt;x,y&lt;/em&gt; où &lt;em&gt;x&lt;/em&gt; est la ligne de début et &lt;em&gt;y&lt;/em&gt; la ligne de fin. Il existe en plus des symboles spéciaux dans la description des adresses, essayons d’en faire le tour avec ces quelques exemples :&lt;/p&gt;

&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;Adresse&lt;/th&gt;
&lt;th&gt;Plage de sélection&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1,$&lt;/td&gt;
&lt;td&gt;L'ensemble du fichier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;%&lt;/td&gt;
&lt;td&gt;L'ensemble du fichier également&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.&lt;/td&gt;
&lt;td&gt;La ligne courante&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;+n&lt;/td&gt;
&lt;td&gt;n lignes après la ligne courante&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-n&lt;/td&gt;
&lt;td&gt;n lignes avant la ligne courante&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;/pattern/&lt;/td&gt;
&lt;td&gt;La première ligne en avant qui contient pattern&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;?pattern?&lt;/td&gt;
&lt;td&gt;La première ligne en arrière qui contient pattern&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Voici de nouveaux exemples pour comprendre l’usage des adresses et de la substitution :&lt;/p&gt;

&lt;table cellspacing="0"&gt;
&lt;tr&gt;
&lt;th&gt;Commande&lt;/th&gt;
&lt;th&gt;Substitution&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:s/old/new/&lt;/td&gt;
&lt;td&gt;Substitue sur la ligne courante la première occurence de « old » par « new »&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:s/old/new/g&lt;/td&gt;
&lt;td&gt;Idem avec toutes les occurences de la ligne (option g)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:s/old/new/gc&lt;/td&gt;
&lt;td&gt;Idem en demandant une confirmation pour chaque remplacement (option c)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:.,+15s/old/new/gc&lt;/td&gt;
&lt;td&gt;Idem pour les 16 lignes sous le curseur&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:.,/search/s/old/new/gc&lt;/td&gt;
&lt;td&gt;Idem pour les lignes du curseur jusqu'à search (en avant)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:%s/old/new/gc&lt;/td&gt;
&lt;td&gt;Idem pour toutes les lignes du fichier&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Dans ces exemples simples on retrouve la syntaxe des adresses Ex que l’on a vu plus tôt. Ces dernières permettent de spécifier une plage précise de remplacement.&lt;/p&gt;

&lt;table cellspacing="0"&gt;
&lt;tr&gt;
&lt;th&gt;Commande&lt;/th&gt;
&lt;th&gt;Substitution&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:%s/\\(.*\\)  */\\1/&lt;/td&gt;
&lt;td&gt;Supprime tout les espaces en fin de ligne&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:%s/[[=e=]]/e/g&lt;/td&gt;
&lt;td&gt;Remplace tout les éléments de la classe d'équivalence e (é, è, ê, etc) par des « e »&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:%s/todo/\U&amp;amp;/gi&lt;/td&gt;
&lt;td&gt;Remplace les occurences de « todo » quelque soit leur casse en « TODO » majuscules&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;À travers ces trois autres exemples on voit que Vim permet de délimiter des groupes dans ces recherches avec &lt;code&gt;\(&lt;/code&gt; et &lt;code&gt;\)&lt;/code&gt; et de les réutiliser dans les remplacements avec &lt;code&gt;\1&lt;/code&gt;, &lt;code&gt;\2&lt;/code&gt;, etc. Il est aussi possible d’utiliser les expressions à crochet de POSIX pour définir des intervalles (&lt;code&gt;[:alnum:]&lt;/code&gt;, &lt;code&gt;[:digit:]&lt;/code&gt;, etc.). Et, on voit qu’il existe des caractères spéciaux à utiliser dans les remplacements (&lt;code&gt;\U&lt;/code&gt;, &lt;code&gt;&amp;amp;&lt;/code&gt;, etc).&lt;/p&gt;

&lt;p&gt;La commande de substitution regorge d’autres astuces. Par exemple lorsque le motif recherché est vide (&lt;code&gt;:s//new/&lt;/code&gt;) alors c’est la dernière recherche qui est utilisée. Les caractères de séparations sont libres : &lt;code&gt;:s#old#new#gc&lt;/code&gt; est tout à fait valable. &lt;/p&gt;

&lt;h1 id="conclusion"&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;Avec ce que l’on a survolé, vous pouvez peut-être déjà vous rendre compte de ce que la manipulation de texte apporte par rapport à la simple édition de texte. Si vous n’êtes pas encore convaincu, je vous invite tout de même à lire le prochain article qui, au travers de plus d’exemples, saura mieux vous convaincre du gain apporté par la maitrise d’un tel outil.&lt;/p&gt;

&lt;p&gt;Jusque-là j’ai présenté de quoi s’en sortir avec Vim pour de l’édition occasionnelle, je n’ai pas parlé des macros, des replis, des interactions avec la console, de la configuration ou encore des plugins. Tout ceci sera dans le prochain article qui sera destiné à ceux d’entre vous qui souhaitent utiliser Vim au quotidien.&lt;/p&gt;

&lt;p&gt;L’équipe Synbioz.&lt;/p&gt;

&lt;p&gt;Libres d’être ensembles.&lt;/p&gt;

&lt;!-- Fin du premier article. --&gt;</description>
      <pubDate>Wed, 18 Jan 2012 00:00:00 +0100</pubDate>
      <guid>http://www.synbioz.com/blog/2012/01/18/l_utilisation_de_vim</guid>
      <author>Nicolas Zermati</author>
      <category>alternatives</category>
      <category>productivité</category>
    </item>
    <item>
      <title>rbenv pour les développeurs</title>
      <link>http://www.synbioz.com/blog/2012/01/16/rbenv_pour_les_developpeur</link>
      <description>&lt;p&gt;Il y a quelques jours, j’ai décidé d’essayer &lt;a href="https://github.com/sstephenson/rbenv"&gt;rbenv&lt;/a&gt; dont j’entendais beaucoup parler pour sa facilité de mise-en-œuvre côté serveur.&lt;/p&gt;

&lt;p&gt;rbenv est un gestionnaire de version de Ruby comparable à &lt;a href="http://beginrescueend.com/"&gt;RVM&lt;/a&gt; mais qui m’a rapidement séduit par sa légèreté et son élégance. C’est rapide, facile à mettre en œuvre, pratique à l’utilisation et tout à fait dans la philosophie des utilitaires Unix.&lt;/p&gt;

&lt;p&gt;J’ai donc supprimé RVM au profit de rbenv. N’allez pas croire que RVM est un mauvais outil, je me sens juste plus à l’aise avec rbenv qui correspond mieux à mes attentes.&lt;/p&gt;

&lt;h1 id="utilisation-quotidienne"&gt;Utilisation quotidienne&lt;/h1&gt;

&lt;p&gt;Voici un petit résumé des étapes à suivre et des pièges potentiels. Étant sous OS X, j’ai décidé d’installer rbenv via &lt;a href="http://mxcl.github.com/homebrew/"&gt;HomeBrew&lt;/a&gt;. il est également possible d’installer rbenv via git.&lt;/p&gt;

&lt;h2 id="installation"&gt;Installation&lt;/h2&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; brew update
&lt;span class="gp"&gt;$&lt;/span&gt; brew install rbenv
&lt;span class="gp"&gt;$&lt;/span&gt; brew install ruby-build
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Vous avez maintenant votre installation de base. Nous avons installé ruby-build qui va nous permettre de construire facilement nos versions de Ruby sans avoir à récupérer manuellement les sources. Rbenv ayant pour unique but de gérer la version de Ruby en cours d’utilisation, il préfère déléguer ses tâches à des paquets dédiés bien que vous le verrez, à l’utilisation c’est intégré de manière transparente.&lt;/p&gt;

&lt;p&gt;Il faut maintenant demander à votre shell d’utiliser rbenv, en ajoutant ceci à votre &lt;em&gt;.zsh_profil&lt;/em&gt; ou &lt;em&gt;.bash_profile&lt;/em&gt; :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;  &lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="s2"&gt;"$(rbenv init -)"&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Relancez un shell, rbenv est prêt à être utilisé.&lt;/p&gt;

&lt;h2 id="dfinition-des-versions"&gt;Définition des versions&lt;/h2&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; rbenv install 1.9.2-p290
&lt;span class="gp"&gt;$&lt;/span&gt; rbenv global 1.9.2-p290
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Vous avez maintenant Ruby 1.9.2 d’installé et défini comme version par défaut.&lt;/p&gt;

&lt;p&gt;Si pour un projet donné vous devez utiliser une autre version :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;Code/foo
&lt;span class="gp"&gt;$&lt;/span&gt; rbenv &lt;span class="nb"&gt;local &lt;/span&gt;ree-1.8.7-2011.03
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;&lt;code&gt;rbenv local&lt;/code&gt; a pour effet de créer un fichier &lt;em&gt;.rbenv-version&lt;/em&gt; qui définit la version de Ruby à utiliser dans ce répertoire.&lt;/p&gt;

&lt;p&gt;Il est également possible de passer d’une version à l’autre quand bon vous semble :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; rbenv shell 1.9.3-p0
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Pour finir, vous pouvez connaitre les versions installées :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; rbenv versions
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;et celles disponibles à l’installation :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; rbenv install
&lt;/pre&gt;
&lt;/div&gt;


&lt;h1 id="les-gemsets"&gt;Les gemsets&lt;/h1&gt;

&lt;p&gt;Les utilisateurs de rbenv ont tendance à penser que &lt;a href="http://gembundler.com/"&gt;Bundler&lt;/a&gt; est largement suffisant pour gérer les dépendances. Nul besoin de gemset quand le projet lui même peut être le gemset. Si votre projet contient un &lt;em&gt;Gemfile&lt;/em&gt; alors pourquoi ne pas faire :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; bundle install --path vendor/bundle
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Vos gems seront directement installés dans le répertoire &lt;em&gt;vendor/bundle&lt;/em&gt; de votre projet.&lt;/p&gt;

&lt;p&gt;Pensez à ne pas versionner ce répertoire, ce serait un non-sens dans le contexte de l’utilisation de Bundler.&lt;/p&gt;

&lt;p&gt;Il est possible d’automatiser ce comportement de Bundler en ajoutant ceci à votre &lt;em&gt;~/.bundle/config&lt;/em&gt; :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
  &lt;span class="l-Scalar-Plain"&gt;BUNDLE_PATH&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;vendor/bundle&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Pour ceux qui ne sont pas convaincus et qui continuent à penser que les gems d’un projet doivent être gérés par un “vrai” gemset, il reste l’extension &lt;a href="https://github.com/jamis/rbenv-gemset"&gt;rbenv-gemset&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id="rbenv-et-pow"&gt;rbenv et Pow&lt;/h1&gt;

&lt;p&gt;J’ai rencontré un problème avec &lt;a href="http://pow.cx/"&gt;Pow&lt;/a&gt; après avoir supprimé RVM, mes instances ne répondaient plus et les logs montraient clairement un problème de version de Ruby.&lt;/p&gt;

&lt;p&gt;Il s’avère que Pow n’a pas connaissance des chemins nécessaires au fonctionnement de rbenv de manière automatique même si votre shell fonctionne parfaitement.&lt;/p&gt;

&lt;p&gt;Le problème se règle en lui donnant les informations nécessaires via le fichier &lt;em&gt;~/.powconfig&lt;/em&gt; :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/Users/cavigneaux/.rbenv/shims:/Users/cavigneaux/.rbenv/bin:&lt;span class="nv"&gt;$PATH&lt;/span&gt;  
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;J’espère que ces quelques informations vous aideront et vous donneront envie de faire un petit essai de rbenv.&lt;/p&gt;

&lt;p&gt;L’équipe Synbioz.&lt;/p&gt;

&lt;p&gt;Libres d’être ensembles.&lt;/p&gt;</description>
      <pubDate>Mon, 16 Jan 2012 00:00:00 +0100</pubDate>
      <guid>http://www.synbioz.com/blog/2012/01/16/rbenv_pour_les_developpeur</guid>
      <author>Nicolas Cavigneaux</author>
      <category>ruby</category>
    </item>
    <item>
      <title>Rétrospective 2011</title>
      <link>http://www.synbioz.com/blog/2012/01/11/retrospective_2011</link>
      <description>&lt;h1 id="rtrospective-2011"&gt;Rétrospective 2011&lt;/h1&gt;

&lt;h2 id="blog"&gt;Blog&lt;/h2&gt;

&lt;h3 id="bilan"&gt;Bilan&lt;/h3&gt;

&lt;p&gt;Force est de constater qu’en 2011 nous avons su tenir nos bonnes résolutions.&lt;/p&gt;

&lt;p&gt;Nous nous étions fixé d’écrire un article par semaine
et nous l’avons fait (49 articles en 2011).&lt;/p&gt;

&lt;p&gt;Vous êtes de plus en plus nombreux à nous lire et nous nous en félicitons.&lt;/p&gt;

&lt;h3 id="perspectives"&gt;Perspectives&lt;/h3&gt;

&lt;p&gt;Des partenariats sont en cours afin d’élargir encore la diffusion
de notre contenu. Comptez sur nous pour en parler prochainement.&lt;/p&gt;

&lt;p&gt;Au fil de l’année nous nous sommes rendus compte que, selon les
mois, nous avions entre 15 et 20% de lecteurs anglophones.&lt;/p&gt;

&lt;p&gt;Même si le contenu français restera privilégié nous souhaitons répondre à ce besoin
et avons donc commencé dès à présent à diffuser du contenu en anglais avec notre
article sur le monitoring via &lt;a href="http://www.synbioz.com/blog/2012/01/04/monitoring_server_processes_with_god"&gt;god&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Enfin cette année a été l’occasion d’introduire quelques invités sur le blog.
Nous sommes très fiers de ce partage et allons continuer dans cette voie.&lt;/p&gt;

&lt;h2 id="microblogging"&gt;Microblogging&lt;/h2&gt;

&lt;p&gt;Twitter est un outil plus complexe qu’il n’y parait, au moins en terme de dosage.&lt;/p&gt;

&lt;p&gt;Il faut un subtil mélange entre diffusion de ses propres contenus, partage d’information
et interactions avec d’autres membres.&lt;/p&gt;

&lt;p&gt;Tout cela sans tomber dans l’excès ; au risque de noyer l’information pertinente.&lt;/p&gt;

&lt;p&gt;En 2012 nous souhaitons multiplier les échanges avec vous.&lt;/p&gt;

&lt;h2 id="faire-vivre-les-technologies-que-nous-aimons"&gt;Faire vivre les technologies que nous aimons&lt;/h2&gt;

&lt;p&gt;Ruby et rails sont nos technologies de prédilection, mais ce ne sont pas les seules
que nous utilisons et apprécions.&lt;/p&gt;

&lt;p&gt;Petit à petit d’autres technologies (&lt;a href="http://www.synbioz.com/blog/2011/08/16/introduction_a_html5"&gt;html5&lt;/a&gt;, &lt;a href="http://www.synbioz.com/blog/2011/12/20/jouons_un_peu_avec_les_websocket"&gt;websocket&lt;/a&gt;, &lt;a href="http://www.synbioz.com/blog/2011/11/23/le_svg_pour_quoi_faire"&gt;SVG&lt;/a&gt;, &lt;a href="http://www.synbioz.com/blog/2011/08/02/introduction_a_coffeescript"&gt;coffeescript&lt;/a&gt;…) sont venues agrémenter notre panel de compétences.&lt;/p&gt;

&lt;p&gt;En 2012 nous voulons continuer à diffuser notre connaissance de ces technologies,
qui n’ont malheureusement pas encore une place intégrante dans les cursus scolaire.&lt;/p&gt;

&lt;p&gt;Si vous souhaitez que nous venions assurer une présentation, comme nous avons pu le
faire à &lt;a href="http://www.synbioz.com/blog/2011/05/19/retour_sur_nos_presentations_de_rails_a_supinfo"&gt;Supinfo cette année&lt;/a&gt;,
n’hésitez pas à &lt;a href="http://www.synbioz.com/contact"&gt;nous contacter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Enfin, nous continuerons d’être des acteurs, voire organisateurs, des &lt;a href="https://groups.google.com/group/ruby-nord"&gt;apéros ruby du Nord&lt;/a&gt;
afin de contribuer à la communauté locale.&lt;/p&gt;

&lt;h2 id="cap-sur-2012"&gt;Cap sur 2012&lt;/h2&gt;

&lt;p&gt;En 2011, notre équipe s’est agrandie avec l’arrivée d’&lt;a href="http://www.synbioz.com/equipe"&gt;Alexandre et Nicolas&lt;/a&gt; ;
faisant de Synbioz une équipe à taille humaine capable de résoudre chacune de vos problématiques.&lt;/p&gt;

&lt;p&gt;Si vous avez une idée, un projet, un besoin, n’attendez pas, &lt;a href="http://www.synbioz.com/contact"&gt;contactez nous&lt;/a&gt;.
Nous serons heureux de vous conseiller et de vous accompagner.&lt;/p&gt;

&lt;p&gt;Nous avons été ravis de passer 2011, alors &lt;a href="http://www.synbioz.com/emailings/merci_pour_2011_a_bientot_en_2012.html"&gt;à très vite en 2012&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;L’équipe Synbioz.&lt;/p&gt;

&lt;p&gt;Libres d’être ensembles.&lt;/p&gt;</description>
      <pubDate>Wed, 11 Jan 2012 00:00:00 +0100</pubDate>
      <guid>http://www.synbioz.com/blog/2012/01/11/retrospective_2011</guid>
      <author>Martin Catty</author>
      <category>synbioz</category>
    </item>
    <item>
      <title>Monitoring server-side processes with God</title>
      <link>http://www.synbioz.com/blog/2012/01/04/monitoring_server_processes_with_god</link>
      <description>&lt;p&gt;Have you ever needed to put a critical website online? Ensure that it’s up &amp;amp; running 24/7? If you did, you know that it can be a real pain to check that everything is ok, that all services are running, that no process is eating too much resources (CPU / memory).&lt;/p&gt;

&lt;p&gt;Here at &lt;a href="http://www.synbioz.com"&gt;Synbioz&lt;/a&gt; we have to ensure services reliability for our customers. There are many ways to do that, you can write your own shell scripts, play with some crontabs, send email on failure, … But it is kind of difficult to write effective scripts, ensure it’s working well and more over, most of the time your homemade scripts will not be portable and will only work with a specific application. So what is the best way to handle this?&lt;/p&gt;

&lt;h1 id="god-is-upon-you"&gt;God is upon you!&lt;/h1&gt;

&lt;p&gt;Here comes &lt;a href="http://god.rubyforge.org/"&gt;God&lt;/a&gt; which is a monitoring framework you can rely on to keep your processes and tasks running well. God is written in Ruby and aims to be a simple, powerful and flexible way to write monitoring tasks.&lt;/p&gt;

&lt;p&gt;Before going deeper into God, you must know that it will only work on Unix-like systems. Sorry Windows users but hey I know you &lt;strong&gt;never&lt;/strong&gt; &lt;strong&gt;ever&lt;/strong&gt; want to deploy a production app on a Windows server…&lt;/p&gt;

&lt;p&gt;God config files are written in Ruby, so you can do basically everything Ruby allows you to do, and it’s a lot of stuff.&lt;/p&gt;

&lt;p&gt;God features are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Config files are written in Ruby&lt;/li&gt;
  &lt;li&gt;Easily write your own custom conditions in Ruby&lt;/li&gt;
  &lt;li&gt;Supports both poll and event based conditions&lt;/li&gt;
  &lt;li&gt;Different poll conditions can have different intervals&lt;/li&gt;
  &lt;li&gt;Integrated notification system (eg: &lt;a href="http://en.wikipedia.org/wiki/Extensible_Messaging_and_Presence_Protocol"&gt;XMPP&lt;/a&gt; notifier)&lt;/li&gt;
  &lt;li&gt;Easily control non-deamonizing scripts&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="god-basics"&gt;God basics&lt;/h1&gt;

&lt;h2 id="install"&gt;Install&lt;/h2&gt;

&lt;p&gt;You must first start by installing God on your system, I mean the production server:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; sudo gem install god
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;or add it to your Gemfile like so:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"god"&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;You can now create a God configuration file for the deamon you want to monitor:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; touch config/unicorn.god
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Naming config file with .god extension is a convention but this file is in fact a plain Ruby file.&lt;/p&gt;

&lt;h2 id="handle-deamons-start-and-stop"&gt;Handle deamons start and stop&lt;/h2&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="no"&gt;RAILS_ROOT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;__FILE__&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="no"&gt;God&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;watch&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;pid_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;RAILS_ROOT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"tmp/pids/unicorn.pid"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"unicorn"&lt;/span&gt;
  &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;RAILS_ROOT&lt;/span&gt;
  &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;interval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;
  &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"unicorn -c &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;RAILS_ROOT&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/config/unicorn.rb -D"&lt;/span&gt;
  &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"kill -s QUIT $(cat &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;pid_file&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;
  &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;restart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"kill -s HUP $(cat &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;pid_file&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;
  &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_grace&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;
  &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;restart_grace&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;
  &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pid_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pid_file&lt;/span&gt;
  
  &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'nico'&lt;/span&gt;
  &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'team'&lt;/span&gt;
  
  &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s1"&gt;'RAILS_ENV'&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"production"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;behavior&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:clean_pid_file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;h1 id="god-monitoring"&gt;God monitoring&lt;/h1&gt;

&lt;p&gt;We’re now going to enhance our config file to add real process monitoring. Monitoring will allow us to check CPU and memory usages by process:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="no"&gt;RAILS_ROOT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;__FILE__&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="no"&gt;God&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;watch&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;pid_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;RAILS_ROOT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"tmp/pids/unicorn.pid"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"unicorn"&lt;/span&gt;
  &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;interval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;
  &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"unicorn -c &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;RAILS_ROOT&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/config/unicorn.rb -D"&lt;/span&gt;
  &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"kill -s QUIT $(cat &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;pid_file&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;
  &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;restart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"kill -s HUP $(cat &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;pid_file&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;
  &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_grace&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;
  &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;restart_grace&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;
  &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pid_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pid_file&lt;/span&gt;
  
  &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;behavior&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:clean_pid_file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  
  &lt;span class="c1"&gt;# When to start?&lt;/span&gt;
  &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_if&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;condition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:process_running&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="c1"&gt;# We want to check if deamon is running every ten seconds&lt;/span&gt;
      &lt;span class="c1"&gt;# and start it if itsn't running&lt;/span&gt;
      &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;interval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;
      &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;running&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="c1"&gt;# When to restart a running deamon?&lt;/span&gt;
  &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;restart_if&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;restart&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;restart&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;condition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:memory_usage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="c1"&gt;# Pick five memory usage at different times&lt;/span&gt;
      &lt;span class="c1"&gt;# if three of them are above memory limit (100Mb)&lt;/span&gt;
      &lt;span class="c1"&gt;# then we restart the deamon&lt;/span&gt;
      &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;above&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;megabytes&lt;/span&gt;
      &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;times&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; 
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;restart&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;condition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:cpu_usage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="c1"&gt;# Restart deamon if cpu usage goes&lt;/span&gt;
      &lt;span class="c1"&gt;# above 90% at least five times&lt;/span&gt;
      &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;above&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;percent&lt;/span&gt;
      &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;times&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  
  &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lifecycle&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="c1"&gt;# Handle edge cases where deamon&lt;/span&gt;
    &lt;span class="c1"&gt;# can't start for some reason&lt;/span&gt;
    &lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;condition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:flapping&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:restart&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# If God tries to start or restart&lt;/span&gt;
      &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;times&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;                     &lt;span class="c1"&gt;# five times&lt;/span&gt;
      &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;within&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;minute&lt;/span&gt;             &lt;span class="c1"&gt;# within five minutes&lt;/span&gt;
      &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:unmonitored&lt;/span&gt;     &lt;span class="c1"&gt;# we want to stop monitoring&lt;/span&gt;
      &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;retry_in&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;minutes&lt;/span&gt;         &lt;span class="c1"&gt;# for 10 minutes and monitor again&lt;/span&gt;
      &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;retry_times&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;               &lt;span class="c1"&gt;# we'll loop over this five times&lt;/span&gt;
      &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;retry_within&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hours&lt;/span&gt;        &lt;span class="c1"&gt;# and give up if flapping occured five times in twoÂ hours&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;You can repeat the &lt;code&gt;God watch&lt;/code&gt; block as much as you need to handle other deamons your application makes us of.&lt;/p&gt;

&lt;h1 id="usage"&gt;Usage&lt;/h1&gt;

&lt;p&gt;Now that your config file is ready, you can check current God status&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; god status
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;which will tell you that unicorn is down. So we’re going to start it:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; god -c config/unicorn.god
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Same but not deamonized:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; god -c config/unicorn.god -D
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;God status should now tell you that unicorn is up and running.&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; god log unicorn
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;will show you what God did with the deamon and will also show you monitoring results such as last memory and CPU usages in real-time.&lt;/p&gt;

&lt;p&gt;If you like to play you can now try to kill unicorn process from another shell and look at what happen in God logs:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; &lt;span class="nb"&gt;kill&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;cat tmp/pid/unicorn.pid&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;You should see that God detected that unicorn isn’t running anymore, deleted pid file if it existed and started unicorn deamon again.&lt;/p&gt;

&lt;p&gt;Now if you need to stop all God monitorings:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; god terminate
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;or a given one:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; god stop unicorn
&lt;/pre&gt;
&lt;/div&gt;


&lt;h1 id="server-init-process"&gt;Server init process&lt;/h1&gt;

&lt;p&gt;Great we’re happy with our monitoring system, but how do I start this thing when server starts or reboots? You have to write an init script! But relax, I have one for you:&lt;/p&gt;

&lt;h2 id="init-script"&gt;Init script&lt;/h2&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# God&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# chkconfig: - 85 15&lt;/span&gt;
&lt;span class="c"&gt;# description: start, stop, restart, status for God&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;

&lt;span class="nv"&gt;RETVAL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0

&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s2"&gt;"$1"&lt;/span&gt; in
    start&lt;span class="o"&gt;)&lt;/span&gt;
      god -P /var/run/god.pid -l /var/log/god.log
      god load /etc/god.conf
      &lt;span class="nv"&gt;RETVAL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;
      ;;
    stop&lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="nb"&gt;kill&lt;/span&gt; &lt;span class="sb"&gt;`&lt;/span&gt;cat /var/run/god.pid&lt;span class="sb"&gt;`&lt;/span&gt;
      &lt;span class="nv"&gt;RETVAL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;
      ;;
    restart&lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="nb"&gt;kill&lt;/span&gt; &lt;span class="sb"&gt;`&lt;/span&gt;cat /var/run/god.pid&lt;span class="sb"&gt;`&lt;/span&gt;
      god -P /var/run/god.pid -l /var/log/god.log
      god load /etc/god.conf
      &lt;span class="nv"&gt;RETVAL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;
      ;;
    status&lt;span class="o"&gt;)&lt;/span&gt;      
      /usr/bin/god status
      &lt;span class="nv"&gt;RETVAL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;
      ;;
    *&lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Usage: god {start|stop|restart|status}"&lt;/span&gt;
      &lt;span class="nb"&gt;exit &lt;/span&gt;1
  ;;
&lt;span class="k"&gt;esac&lt;/span&gt;

&lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="nv"&gt;$RETVAL&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;h2 id="global-god-config-file"&gt;Global God config file&lt;/h2&gt;

&lt;p&gt;As you can see, the above script makes use of a file named /etc/god.conf. This file has only one simple purpose, load a bunch of God config files at once:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="no"&gt;God&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt; &lt;span class="s2"&gt;"/etc/god/*.god"&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;This trick allows you to create a symlink of your app God config files into /etc/god/ directory to ensure it will be loaded on server boot. This is very similar to the technique used for &lt;a href="http://rubyforge.org/projects/mongrel"&gt;Mongrel&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now you can do:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; /etc/init.d/god start

&lt;span class="gp"&gt;$&lt;/span&gt; /etc/init.d/god status

&lt;span class="gp"&gt;$&lt;/span&gt; /etc/init.d/god stop
&lt;/pre&gt;
&lt;/div&gt;


&lt;h1 id="notification-on-failures"&gt;Notification on failures&lt;/h1&gt;

&lt;p&gt;Let’s say you want to be notified everytime a process exits, you can add this to your God configuration file:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:up&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;condition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:process_exits&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;notify&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'devteam'&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Now god knows that everytime our process exits when starting it should send a notification to “devteam”. You can use &lt;code&gt;notify&lt;/code&gt; in any &lt;code&gt;condition&lt;/code&gt; block.&lt;/p&gt;

&lt;p&gt;But what is “devteam” and how the hell are notification sent?!&lt;/p&gt;

&lt;h2 id="sending-emails"&gt;Sending emails&lt;/h2&gt;

&lt;p&gt;First solution is to send email.&lt;/p&gt;

&lt;p&gt;We’ll first start by defining some default for email in our God config file:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="no"&gt;God&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Contacts&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Email&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;defaults&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'god@synbioz.com'&lt;/span&gt;
  &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'God'&lt;/span&gt;
  &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delivery_method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:sendmail&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Then we need to define a contact:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="no"&gt;God&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Dev Team'&lt;/span&gt;
  &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;group&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'devteam'&lt;/span&gt;
  &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'team@synbioz.com'&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;You can define as much contacts as you need but be sure “name” attribute is unique! Now our dev team will receive email notification when there’s such a problem.&lt;/p&gt;

&lt;h2 id="jabber-notifications"&gt;Jabber notifications&lt;/h2&gt;

&lt;p&gt;You don’t like emails and want &lt;a href="http://jabber.org/"&gt;XMPP&lt;/a&gt; notifications? No problem:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="no"&gt;God&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Contacts&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Jabber&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;defaults&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"jabber.synbioz.com"&lt;/span&gt;
  &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_jid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"foo@synbioz.com"&lt;/span&gt;
  &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"bar"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;God&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:jabber&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_jid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"baz@synbioz.com"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;h2 id="other-notification-systems"&gt;Other notification systems&lt;/h2&gt;

&lt;p&gt;You can also use &lt;a href="http://campfirenow.com/"&gt;Campfire&lt;/a&gt;, &lt;a href="http://prowl.weks.net/"&gt;Prowl&lt;/a&gt;, &lt;a href="http://scoutapp.com/"&gt;Scout&lt;/a&gt;, &lt;a href="http://twitter.com"&gt;Twitter&lt;/a&gt; and &lt;a href="http://www.webhooks.org/"&gt;WebHook&lt;/a&gt; to send notifications. They are part of God core.&lt;/p&gt;

&lt;p&gt;You can easily extends notifications if you need to use your own system, maybe an internal tracking system.&lt;/p&gt;

&lt;h1 id="god-is-good-for-you"&gt;God is good for you!&lt;/h1&gt;

&lt;p&gt;I hope this quick introduction to God will be helpful for those of you who want to monitor their applications. Don’t think God is only for Rails apps or even Ruby apps. You can use God for anything you want to monitor, Rails projects or not!&lt;/p&gt;

&lt;p&gt;Synbioz Team.&lt;/p&gt;</description>
      <pubDate>Wed, 04 Jan 2012 00:00:00 +0100</pubDate>
      <guid>http://www.synbioz.com/blog/2012/01/04/monitoring_server_processes_with_god</guid>
      <author>Nicolas Cavigneaux</author>
      <category>server</category>
      <category>admin</category>
      <category>reliability</category>
    </item>
    <item>
      <title>Le kit du bon développeur Rails, quelques gems à connaitre, partie 1</title>
      <link>http://www.synbioz.com/blog/2011/12/28/le_kit_du_bon_developpeur_rails_partie_1</link>
      <description>&lt;p&gt;Tout bon développeur se doit d’avoir quelques outils pour créer sites et applications. A l’instar d’un mécanicien et de sa trousse à outils, un développeur Rails a son lot de gems indispensables.&lt;/p&gt;

&lt;p&gt;Il existe différentes fonctionnalités que l’on va retrouver sur une très grande majorité des sites ou applications web.
Il n’est pas nécessaire pour celles-ci de tout refaire à la main à chaque fois, il existe des gems.&lt;/p&gt;

&lt;h2 id="authentification-et-gestion-des-utilisateurs"&gt;Authentification et gestion des utilisateurs&lt;/h2&gt;

&lt;p&gt;L’une des premières fonctionnalités demandée lors de la création d’un site est l’authentification d’utilisateur.&lt;/p&gt;

&lt;p&gt;Cette fonctionnalité est particulièrement sensible en terme de sécurité, vouloir tout refaire à la main,
c’est à coup sûr exposer son client à une faille.&lt;/p&gt;

&lt;p&gt;Généralement l’utilisateur doit pouvoir créer un compte, se connecter, se déconnecter, etc… ; nous allons donc découvrir l’une des gems qui permet de gérer tout cela.&lt;/p&gt;

&lt;h3 id="devise"&gt;Devise&lt;/h3&gt;

&lt;p&gt;Devise est une gem disponible pour Rails 2.3 et Rails 3. Différents &lt;em&gt;modules&lt;/em&gt; sont disponibles suivant les besoins que vous avez. Il est possible de valider les créations de compte avec un email par exemple.&lt;/p&gt;

&lt;p&gt;Pour utiliser cette gem dans votre application il suffit de l’ajouter à votre Gemfile :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;gem 'devise'
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Puis, un &lt;em&gt;bundle install&lt;/em&gt; suffit à installer Devise. Ensuite, il vous faut configurer cette gem avant de pouvoir l’utiliser. Pour cela, il vous faut lancer la commande suivante :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;rails generate devise:install
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Enfin, vous pouvez créer votre &lt;em&gt;MODEL&lt;/em&gt; (que nous appelons ici &lt;em&gt;USER&lt;/em&gt; mais vous pouvez choisir le nom que vous souhaitez) avec Devise pour pouvoir gérer des utilisateurs :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;rails generate devise USER
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Suite à ceci, vous allez donc avoir un &lt;em&gt;model User&lt;/em&gt;, ainsi qu’une migration pour créer la table en base et également de nouvelles &lt;em&gt;routes&lt;/em&gt; dans votre fichier &lt;em&gt;routes.rb&lt;/em&gt;. Il est maintenant possible pour une utilisateur de créer un compte, de se connecter, etc…&lt;/p&gt;

&lt;p&gt;Vous pouvez ensuite configurer le fonctionnement afin de répondre aux fonctionnalités souhaitées.&lt;/p&gt;

&lt;p&gt;Si vous souhaitez aller plus loin avec Devise, vous pouvez consulter le &lt;a href="http://railscasts.com/episodes/209-introducing-devise"&gt;Railscast de Ryan Bates&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Devise n’est pas la seule gem capable de vous aider en ce qui concerne la gestion d’utilisateurs. En effet, il existe également d’autres gems telles que &lt;a href="https://github.com/binarylogic/authlogic"&gt;Authlogic&lt;/a&gt; par exemple.&lt;/p&gt;

&lt;p&gt;Il est également possible que vous ayez besoin de permettre aux utilisateurs de se connecter via différents autres sites ou outils existants (Facebook, Twitter, LDAP…). Pour vous y aider, il y a &lt;a href="https://github.com/intridea/omniauth"&gt;OmniAuth&lt;/a&gt; ; vous permettant d’intégrer &lt;a href="http://www.synbioz.com/blog/2011/10/18/integrer_les_reseaux_sociaux_dans_son_application_rails_avec_oauth"&gt;la connexion via les réseaux sociaux sur votre site ou application web&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Maintenant que nous avons vu comment permettre à un utilisateur de se connecter sur votre site, vous pouvez avoir besoin de gérer des droits d’accès en définissant des rôles.&lt;/p&gt;

&lt;h3 id="cancan"&gt;Cancan&lt;/h3&gt;

&lt;p&gt;Cancan est une gem permettant de gérer les autorisations et les droits d’accès à certains contenus. En effet, vous pouvez définir ce qui est disponible ou non pour l’utilisateur connecté. Cette gem fonctionne parfaitement avec Devise ou Authlogic par exemple.&lt;/p&gt;

&lt;p&gt;Pour installer cette gem, si vous utilisez &lt;em&gt;Rails 3&lt;/em&gt;, il vous suffit de l’ajouter dans votre &lt;em&gt;Gemfile&lt;/em&gt; :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;gem 'cancan'
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Si vous utilisez &lt;em&gt;Rails 2&lt;/em&gt;, vous devez ajouter cette ligne dans votre fichier &lt;em&gt;environment.rb&lt;/em&gt; (après avoir installé la gem) :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;config.gem "cancan"
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Ensuite, il vous faut ajouter un champ &lt;em&gt;role&lt;/em&gt; à votre &lt;em&gt;model User&lt;/em&gt;. Puis, il faut définir une &lt;em&gt;classe Ability_où se trouveront les permissions des utilisateurs. Si l’on a par exemple, des utilisateurs avec un rôle _admin&lt;/em&gt; ou &lt;em&gt;author&lt;/em&gt;, on initialise les droits en fonction de ce rôle.&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Ability&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;CanCan&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Ability&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;
    &lt;span class="nb"&gt;send&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;role&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;admin&lt;/span&gt;
    &lt;span class="n"&gt;can&lt;/span&gt; &lt;span class="ss"&gt;:manage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:all&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;author&lt;/span&gt;
    &lt;span class="n"&gt;can&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:create&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:read&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:update&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="no"&gt;Article&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Dossier&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Ici, l’&lt;em&gt;admin&lt;/em&gt; a tous les droits alors que l’&lt;em&gt;author&lt;/em&gt; ne peut que créer, lire ou modifier des Dossiers et Articles.&lt;/p&gt;

&lt;p&gt;Vous pouvez contrôler les autorisations depuis le &lt;em&gt;controller&lt;/em&gt;, par exemple pour vérifier si l’utilisateur connecté peut voir l’article qu’il a sélectionné :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;show&lt;/span&gt;
  &lt;span class="vi"&gt;@article&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Article&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;authorize!&lt;/span&gt; &lt;span class="ss"&gt;:read&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="vi"&gt;@article&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Ou bien, vous pouvez afficher un bloc dans une vue uniquement si l’utilisateur possède les droits nécessaires.&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;can?&lt;/span&gt; &lt;span class="ss"&gt;:read&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="vi"&gt;@article&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="x"&gt;&lt;/span&gt;
&lt;span class="x"&gt;  &lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;link_to&lt;/span&gt; &lt;span class="s2"&gt;"Voir l'article"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;article_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@article&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="x"&gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="x"&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Vous pouvez également gérer les erreurs lorsque l’utilisateur n’a pas accès à une page par exemple. Plus de détails sont disponibles &lt;a href="https://github.com/ryanb/cancan"&gt;sur le Github de Cancan&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id="crer-des-formulaires"&gt;Créer des formulaires&lt;/h2&gt;

&lt;p&gt;La gestion des utilisateurs n’est pas le seul point indispensable d’un site. La création de formulaires en fait également parti. Il est nécessaire d’avoir des formulaires pour créer ou éditer différents objets, pour se connecter… Il existe donc différentes gems pour vous aider à créer vos formulaires.&lt;/p&gt;

&lt;h3 id="formtastic"&gt;Formtastic&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/justinfrench/formtastic"&gt;Formtastic&lt;/a&gt; est une gem qui vous permet, à travers un DSL, de créer des formulaires. Cette gem est compatible avec Rails 2 et 3.&lt;/p&gt;

&lt;p&gt;Pour pouvoir utiliser Formtastic dans votre projet, vous devez l’ajouter dans votre &lt;em&gt;Gemfile&lt;/em&gt; puis lancer un &lt;em&gt;bundle install&lt;/em&gt;.&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;gem 'formtastic'
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Ensuite, il vous faut installer la gem grâce à la commande suivante :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;rails generate formtastic:install
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;A partir de là, vous pouvez utiliser cette gem dans vos vues pour créer vos formulaires.&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;semantic_form_for&lt;/span&gt; &lt;span class="vi"&gt;@article&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="x"&gt;&lt;/span&gt;
&lt;span class="x"&gt;  &lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="x"&gt;&lt;/span&gt;
&lt;span class="x"&gt;    &lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="ss"&gt;:title&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="x"&gt;&lt;/span&gt;
&lt;span class="x"&gt;    &lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="ss"&gt;:content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:input_html&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;:class&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'article_content'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:rows&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:cols&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="x"&gt;&lt;/span&gt;
&lt;span class="x"&gt;    &lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="ss"&gt;:draft&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:as&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:radio&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="x"&gt;&lt;/span&gt;
&lt;span class="x"&gt;    &lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="ss"&gt;:categories&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:as&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:select&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:collection&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Categorie&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:all&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="x"&gt;&lt;/span&gt;
&lt;span class="x"&gt;  &lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="x"&gt;&lt;/span&gt;
&lt;span class="x"&gt;  &lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buttons&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="x"&gt;&lt;/span&gt;
&lt;span class="x"&gt;    &lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;commit_button&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="x"&gt;&lt;/span&gt;
&lt;span class="x"&gt;  &lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="x"&gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="x"&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Dans le cas présent, on crée un formulaire pour un article avec un champ &lt;em&gt;title&lt;/em&gt; qui est un &lt;em&gt;input&lt;/em&gt; de type &lt;em&gt;text&lt;/em&gt;, un champ &lt;em&gt;content&lt;/em&gt; qui est un &lt;em&gt;text_area&lt;/em&gt; (pour lequel on spécifie des options), un champ &lt;em&gt;draft&lt;/em&gt; qui est un bouton radio et enfin un champ &lt;em&gt;categories&lt;/em&gt; qui est un &lt;em&gt;select&lt;/em&gt;. Enfin, on retrouve le bouton de validation du formulaire. Il vous est possible de créer une multitude d’options pour mettre en forme votre formulaire selon vos souhaits.&lt;/p&gt;

&lt;p&gt;En plus de vous simplifier la tâche, Formtastic génère un code sémantiquement riche. Il ajoute également des balises HTML5 telles que &lt;em&gt;phone&lt;/em&gt;, &lt;em&gt;email&lt;/em&gt;… On y retrouve également une gestion des messages d’erreurs.&lt;/p&gt;

&lt;p&gt;Formtastic n’est pas la seule gem qui permet une création simplifiée des formulaires. En effet il existe aussi &lt;a href="https://github.com/plataformatec/simple_form"&gt;&lt;em&gt;simple_form&lt;/em&gt;&lt;/a&gt; par exemple. Encore une fois, vous pouvez choisir celle qui vous convient le mieux par rapport à vos besoins et vos habitudes.&lt;/p&gt;

&lt;h2 id="moteur-de-recherche"&gt;Moteur de recherche&lt;/h2&gt;

&lt;p&gt;Sur un site ayant un contenu suffisamment important, il peut être nécessaire d’avoir un moteur de recherche.&lt;/p&gt;

&lt;h3 id="ransack"&gt;Ransack&lt;/h3&gt;

&lt;p&gt;Ransack est un outil qui vous permet de créer un moteur de recherche sur votre site. Il vous permet de gérer vos recherches selon deux types &lt;em&gt;simple&lt;/em&gt; ou &lt;em&gt;avancé (advanced)&lt;/em&gt;. Pour l’utiliser, il vous faut tout d’abord l’ajouter à votre &lt;em&gt;Gemfile&lt;/em&gt; :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;gem 'ransack'
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Ensuite, vous pouvez créer une recherche comme dans l’exemple ci-dessous :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;
  &lt;span class="vi"&gt;@q&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Article&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:q&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="vi"&gt;@articles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@q&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;On effectue une recherche sur les articles avec les paramètres transmis par un formulaire de recherche puis on retourne les articles correspondants.&lt;/p&gt;

&lt;p&gt;Il faut également créer ce formulaire de recherche dans votre afin de spécifier les critères de recherche.&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;search_form_for&lt;/span&gt; &lt;span class="vi"&gt;@q&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="x"&gt;&lt;/span&gt;
&lt;span class="x"&gt;  &lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt; &lt;span class="ss"&gt;:title_start&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="x"&gt;&lt;/span&gt;
&lt;span class="x"&gt;  &lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text_field&lt;/span&gt; &lt;span class="ss"&gt;:title_start&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="x"&gt;&lt;/span&gt;
&lt;span class="x"&gt;  &lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt; &lt;span class="ss"&gt;:content_cont&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="x"&gt;&lt;/span&gt;
&lt;span class="x"&gt;  &lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text_field&lt;/span&gt; &lt;span class="ss"&gt;:content_cont&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="x"&gt;&lt;/span&gt;
&lt;span class="x"&gt;  &lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;submit&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="x"&gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="x"&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;On utilise le DSL pour savoir si le contenu d’un article contient bien l’expression donnée (avec &lt;em&gt;cont&lt;/em&gt; ajouter au nom du champ) ou bien si le titre commence par un mot ou une expression donnée (avec &lt;em&gt;start&lt;/em&gt; ajouté au nom du champ). Il existe de nombreux critères pour effectuer votre recherche.&lt;/p&gt;

&lt;p&gt;Encore une fois, il n’y a pas une seule et unique gem pour faire cela. Ransack est une réécriture de &lt;a href="https://github.com/ernie/meta_search"&gt;MetaSearch&lt;/a&gt; et d’autres gem existent.&lt;/p&gt;

&lt;h3 id="thinking-sphinx"&gt;Thinking Sphinx&lt;/h3&gt;

&lt;p&gt;Pour les applications nécessitant un moteur de recherche plus performant, vous pouvez utiliser le logiciel &lt;a href="http://sphinxsearch.com/"&gt;Sphinx&lt;/a&gt;. Celui-ci est un moteur de recherche indépendant de votre application Rails, il ne fait que génèrer un index à partir de la base de données. Cette indexation ne se fait d’ailleurs pas automatiquement, elle doit être invoquer régulièrement (par exemple via un cron). Afin de faire le lien entre votre application (en l’occurrence Active Record) et Sphinx, il existe une gem Thinking Sphinx.&lt;/p&gt;

&lt;p&gt;Cette dernière vous propose un certain nombre d’options afin de gérer vos recherches. Vous pouvez par exemple configurer une taille minimum pour les mots ou encore effectuer une recherche sur des morceaux de mots.&lt;/p&gt;

&lt;p&gt;Pour installer cette gem, il vous suffit de l’ajouter à votre &lt;em&gt;Gemfile&lt;/em&gt;.&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;gem 'thinking-sphinx'
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Ensuite, il vous faut définir les champs sur lesquels la recherche va s’effectuer pour le &lt;em&gt;model&lt;/em&gt; que vous souhaitez.&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Article&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="n"&gt;define_index&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;indexes&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:sortable&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
    &lt;span class="n"&gt;indexes&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;

    &lt;span class="n"&gt;has&lt;/span&gt; &lt;span class="n"&gt;created_at&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;updated_at&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Deux méthodes sont utilisées. La première, &lt;em&gt;indexes&lt;/em&gt;, permet d’indexer les champs pour lesquels on pourra effectuer une recherche. La deuxième, &lt;em&gt;has&lt;/em&gt;, permet de définir des attributs. Ils permettent de faire un tri par exemple.&lt;/p&gt;

&lt;p&gt;Ensuite, il faut lancer l’indexation des champs grâce à la tâche &lt;em&gt;rake&lt;/em&gt; suivante :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;rake thinking_sphinx:index
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Puis vous devez démarrer Thinking Sphinx :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;rake thinking_sphinx:start
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Enfin, vous pouvez effectuer une recherche sur vos articles:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="no"&gt;Article&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;search&lt;/span&gt; &lt;span class="s2"&gt;"un article"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:order&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:created_at&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:sort_mode&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:desc&lt;/span&gt;
&lt;span class="c1"&gt;# on cherche les articles contenant dans leur titre ou contenu l'expression "un article"&lt;/span&gt;
&lt;span class="c1"&gt;# et triÃ© par ordre dÃ©croissant sur le critÃ¨re "created_at".&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Il vous est donc possible d’effectuer des recherches sur un &lt;em&gt;model&lt;/em&gt; donné. Vous pouvez obtenir beaucoup de détails sur le &lt;a href="http://freelancing-god.github.com/ts/fr/"&gt;site de Thinking Sphinx&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id="pagination"&gt;Pagination&lt;/h2&gt;

&lt;p&gt;Certaines pages de votre site peuvent contenir des listes de résultats très longues et dans ce cas, il vaut mieux utiliser la pagination afin d’éviter les pages qui n’en finissent plus.&lt;/p&gt;

&lt;h3 id="will-paginate"&gt;Will Paginate&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/mislav/will_paginate"&gt;Will Paginate&lt;/a&gt; est une gem permettant de paginer vos résultats très simplement.&lt;/p&gt;

&lt;p&gt;Pour installer will_paginate_ dans une application Rails 3, il vous faut ajouter la gem dans votre &lt;em&gt;Gemfile&lt;/em&gt; :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;gem 'will_paginate', '~&amp;gt; 3.0'
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Ensuite, il vous suffit de spécifier, dans votre controller, que les résultats sont paginés tout en indiquant les paramètres correspondants.&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;
  &lt;span class="vi"&gt;@articles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Article&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;paginate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;# on indique la page sur laquelle l'utilisateur se trouve&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Il est également possible de spécifier le nombre de résultats par page.&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="vi"&gt;@articles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Article&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;paginate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:per_page&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Vous pouvez appliquer une pagination sur une relation Active Record.&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="vi"&gt;@articles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Article&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:draft&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;paginate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:per_page&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Enfin, il faut ajouter la gestion des pages dans votre vue et pour cela il vous faut uniquement ajouter le bloc suivant:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;will_paginate&lt;/span&gt; &lt;span class="vi"&gt;@articles&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="x"&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Ceci aura pour effet d’ajouter dans votre vue html un bloc contenant des liens vers les pages suivantes et précédentes ainsi que quelques liens directs vers des pages précises. Il est possible de configurer l’affichage du sélecteur de page dans votre vue.&lt;/p&gt;

&lt;p&gt;De nombreux paramètres sont à votre disposition pour obtenir ce qui convient le plus à vos besoins.&lt;/p&gt;

&lt;p&gt;Afin d’effectuer une pagination sur votre site ou application vous pouvez également utiliser la gem &lt;a href="https://github.com/amatsuda/kaminari"&gt;kaminari&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id="dploiement"&gt;Déploiement&lt;/h2&gt;

&lt;p&gt;Le déploiement d’une application ou d’un site web n’est pas la partie la plus simple. Dans ce cas encore, l’usage d’une gem pour vous faciliter la tâche peut s’avérer utile.&lt;/p&gt;

&lt;h3 id="capistrano"&gt;Capistrano&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/capistrano/capistrano"&gt;Capistrano&lt;/a&gt; est un outil permettant d’exécuter des commandes sur différentes machines distantes.&lt;/p&gt;

&lt;p&gt;On utilise pour cela un DSL afin de définir différentes tâches à exécuter. Celles-ci sont définies dans un fichier (&lt;em&gt;capfile&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;Une fois que vous avez créé votre fichier et que vous avez renseigné les différentes tâches à accomplir, il faut savoir sur quelles machines vous voulez déployer votre site ou application. Ceci se fait dans le fichier &lt;em&gt;deploy.rb&lt;/em&gt; du répertoire &lt;em&gt;config&lt;/em&gt; de votre projet. Vous pouvez obtenir plus de détails sur la façon d’utiliser capistrano dans notre &lt;a href="http://www.synbioz.com/blog/2011/11/15/deployer_et_heberger_une_application_rails_avec_capistrano_et_unicorn"&gt;article concernant le déploiement&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Il existe donc de nombreuses gems qui vont vous faciliter la tâche lors de l’ajout de fonctionnalités de base. Pour chacune d’entres elles, différentes gems peuvent être utilisées.&lt;/p&gt;

&lt;p&gt;Il n’y a pas une gem parfaite dans chaque cas, c’est à vous de choisir celle qui vous semble la plus appropriée et qui vous convient le mieux.&lt;/p&gt;

&lt;p&gt;Investissez le temps que vous ne passerez pas à développer à bien choisir vos outils et lire leur code.
La gem est elle activement maintenue, puis je facilement remonter un bug, y a t-il une communauté active autour, est-elle bien testée ?&lt;/p&gt;

&lt;p&gt;Cet investissement en veille, à l’affut des bons outils, vous sera largement récompensé à chaque fois que vous trouverez chaussure à votre pied.&lt;/p&gt;

&lt;p&gt;L’équipe Synbioz.&lt;/p&gt;

&lt;p&gt;Libres d’être ensembles.&lt;/p&gt;</description>
      <pubDate>Wed, 28 Dec 2011 00:00:00 +0100</pubDate>
      <guid>http://www.synbioz.com/blog/2011/12/28/le_kit_du_bon_developpeur_rails_partie_1</guid>
      <author>Alexandre Salaün</author>
      <category>rails</category>
    </item>
  </channel>
</rss>

