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

 <title>Dev blog af83 | This is the developers blog @ af83</title>
 <link href="http://dev.af83.com/atom.xml" rel="self"/>
 <link href="http://dev.af83.com/"/>
 <updated>2013-05-10T18:57:52+02:00</updated>
 <id>http://dev.af83.com/</id>

 
 <entry>
   <title type="html">Mongoid tips</title>
   <link href="http://dev.af83.com/2013/04/29/mongoid-tips.html"/>
   <updated>2013-04-29T00:00:00+02:00</updated>
   <id>http://dev.af83.com/2013/04/29/mongoid-tips</id>
   <author><name>spk</name><email>contact@af83.com</email></author>
   <content type="html">&lt;p&gt;Ce billet présente quelques astuces sur l&#39;utilisation de
&lt;a href=&quot;http://mongoid.org/&quot;&gt;mongoid&lt;/a&gt; et
&lt;a href=&quot;https://github.com/AF83/mongoid_translate&quot;&gt;mongoid_translate&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Les traductions dans mongoid_translate sont des documents «&amp;nbsp;embedded&amp;nbsp;».&lt;/p&gt;

&lt;p&gt;Pour chercher un document avec une traduction&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;Tag&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:&amp;#39;translations.name&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Content&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:&amp;#39;translations.language&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:fr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;one&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Pour trouver un tag à partir de sa traduction, ou en initialiser un
nouveau s&#39;il n&#39;existe pas encore&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Tag&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;find_or_initialize_by&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:&amp;#39;translations.name&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;On peut ensuite créer la traduction comme ceci&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;translations&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;language&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:fr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;save&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Voilà, ça permet aussi de parler du projet «&amp;nbsp;mongoid_translate&amp;nbsp;», une gem
développée par af83 pour gérer de la traduction de contenus avec mongoid.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title type="html">Dispositif interactif pour la biennale de Saint-Étienne</title>
   <link href="http://dev.af83.com/2013/04/16/dispositif-interactif-pour-la-biennale-de-saint-etienne.html"/>
   <updated>2013-04-16T00:00:00+02:00</updated>
   <id>http://dev.af83.com/2013/04/16/dispositif-interactif-pour-la-biennale-de-saint-etienne</id>
   <author><name>Alice</name><email>contact@af83.com</email></author>
   <content type="html">&lt;p&gt;Nous avons eu récemment l&#39;opportunité de travailler avec EDF sur un dispositif
interactif pour la biennale de Saint Etienne. Ce dispositif devait offrir aux
visiteurs la possibilité de construire et tester librement des systèmes
électriques à l&#39;échelle de la France, via une interface tangible conjuguant
des écrans et la manipulation d&#39;objets &quot;communicants&quot;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/upload/Edf1.jpg&quot;&gt;&lt;img src=&quot;/upload/Edf1-small.jpg&quot; alt=&quot;Edf1&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;La technologie de détection de ces objets a été créée par la start-up
&lt;a href=&quot;http://www.epawn.fr/&quot;&gt;ePawn&lt;/a&gt;. Nous sommes intervenus sur le design et le
développement de l&#39;application exploitant les déplacement des objets pour
générer des informations et des scénarios.&lt;/p&gt;

&lt;p&gt;Petit retour sur le déroulement et les principaux enjeux de ce projet.&lt;/p&gt;

&lt;h2 id=&quot;toc_296&quot;&gt;Le déroulement du projet&lt;/h2&gt;

&lt;p&gt;Nous avons travaillé en méthode agile (SCRUM). La mise en place de l&#39;API pour
récupérer les informations des objets, le design et le développement du
workflow, des mécanismes d&#39;interaction, l&#39;intégration des données et
algorithmes de production d&#39;énergie, le design graphique comme l&#39;intégration
ont été menés en parallèle, à travers les différents cycles du projet.&lt;/p&gt;

&lt;p&gt;Comme l&#39;interface est pilotée par la manipulation des objets tangibles, nous
avons mis en place un protocole nous permettant de simuler facilement les
déplacements des objets, et de tester l&#39;interface en conséquence. Nous avons
ainsi pu constamment travailler par tests et itérations.&lt;/p&gt;

&lt;p&gt;Enfin, le designer a assumé le rôle du scrum master, ce qui a permis
d&#39;impliquer le design à toutes les étapes du projet, y compris de
développement. Cela a contribué à garantir la cohérence du projet en termes
d&#39;usages. Des ateliers avec le client ont également été menés très
régulièrement.&lt;/p&gt;

&lt;h2 id=&quot;toc_297&quot;&gt;La communication en temps réel&amp;nbsp;: un enjeu crucial&lt;/h2&gt;

&lt;p&gt;La manipulation des objets par le visiteur produisent des informations. Ces
information déclenchent des actions et évènements dans l&#39;interface, et sont
associées à des représentations graphiques sur les deux écrans. Un des
principaux enjeux du projet a été de permettre que les objets, les deux écrans
et les représentations graphiques communiquent constamment en temps réel, afin
de garantir la fluidité et les performances de l&#39;interface.&lt;/p&gt;

&lt;p&gt;Pour cela&amp;nbsp;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Les deux écrans sont en fait deux fenêtres de navigateur (Chrome)&lt;/li&gt;
&lt;li&gt;Un serveur en nodejs sert à synchroniser les deux écrans en leur envoyant
des événements en EventSource&lt;/li&gt;
&lt;li&gt;La position des pions est récupérée via un daemon en C utilisant la
technologie ePawn, puis transmise au serveur nodejs pour qu&#39;il puisse
traiter les déplacements.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;toc_298&quot;&gt;Des modalités d&#39;interaction inédites&lt;/h2&gt;

&lt;p&gt;Le caractère hybride de l&#39;interface (objets physiques / interfaces numériques)
a requis de mettre en place des outils de prototypage spécifiques. Nous avons
d&#39;abord modélisé l&#39;interface et les objets en papier pour tester et préciser
le workflow. Puis nous avons réalisé une maquette échelle 1 pour mieux
percevoir les encombrements, définir les éléments graphiques et ajuster leur
taille en conséquence.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/upload/Edf2.png&quot; alt=&quot;Edf2&quot;&gt;&lt;/p&gt;

&lt;p&gt;Par ailleurs, le fait de manipuler des objets physiques pour interagir avec
des informations numériques ouvre des perspectives d&#39;usages et d&#39;interfaces
inédites. Nous avons tenté de sortir du langage informatique traditionnel,
pour proposer des représentations et interactions ayant du sens par rapport
aux objets manipulés.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/upload/Edf3.JPG&quot; alt=&quot;Edf3&quot;&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Légende&amp;nbsp;: représentation des différents usages ayant eu lieu dans la journée&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/upload/Edf4.JPG&quot; alt=&quot;Edf4&quot;&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Légende&amp;nbsp;: étape de configuration de la saison et des sources d&#39;énergie&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;toc_299&quot;&gt;Des animations full-CSS&lt;/h2&gt;

&lt;p&gt;Pour offrir une expérience d&#39;usage incitant à expérimenter le dispositif, nous
avons créé un univers graphique et des animations riches, depuis les
datavisualisations affichées autour des objets, jusqu&#39;à la simulation du
déroulement d&#39;une journée. &lt;/p&gt;

&lt;p&gt;Pour obtenir cette richesse graphique avec des technologies purement web, nous avons utilisé&amp;nbsp;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;D3 et JS pour les animations en temps réel&lt;/li&gt;
&lt;li&gt;Full CSS3 pour les autres animations&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;toc_300&quot;&gt;Pour conclure&lt;/h2&gt;

&lt;p&gt;Le fait d&#39;utiliser des technologies web pour ce type de dispositif permet
d&#39;obtenir un résultat flexible, qui pourra facilement évoluer par la suite…
Mais cela a aussi amené de nombreux challenges tant pour les développeurs back
et front que les designers. &lt;/p&gt;

&lt;p&gt;Ces challenges, ainsi que la très forte implication du client dans le projet
ont enthousiasmé toute l&#39;équipe qui s&#39;est énormément investie pendant les deux
mois et demi du projet. Nous sommes très heureux de voir à présent le
dispositif installé et utilisé avec succès à la biennale de design&amp;nbsp;!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;L&#39;équipe du projet&amp;nbsp;:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Chez af83&amp;nbsp;: Alice, Arnaud, Bruno, Gilles, Mathilde, Maxim, Victor&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Sur la partie design graphique&amp;nbsp;: Adrien Bridet&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title type="html">Release: Sponges, daemons in a pool</title>
   <link href="http://dev.af83.com/2013/04/04/release-sponges-daemons-in-a-pool.html"/>
   <updated>2013-04-04T00:00:00+02:00</updated>
   <id>http://dev.af83.com/2013/04/04/release-sponges-daemons-in-a-pool</id>
   <author><name>chatgris</name><email>contact@af83.com</email></author>
   <content type="html">&lt;p&gt;When I build workers, I want them to be like an army of little spongebobs,
always on the edge and ready to work.
&lt;a href=&quot;https://github.com/AF83/sponges&quot;&gt;&lt;code&gt;sponges&lt;/code&gt;&lt;/a&gt; helps you create this army of
sponges, control them, and well…kill them at will too. Making them eager to
work is now your job.&amp;nbsp;:)&lt;/p&gt;

&lt;p&gt;Basically, sponges is a ruby supervisor that forks processes and controls their
execution, termination and forks a new process each time a process disappears
from the processes pool.&lt;/p&gt;

&lt;p&gt;For example, the following command will start a supervision daemon and 8
processes of &quot;a_worker&quot;.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;ruby a_worker.rb start -d -s 8
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;If you kill the supervisor, it will cleanly terminate the child processes.&lt;/p&gt;

&lt;h2 id=&quot;toc_288&quot;&gt;Installation&lt;/h2&gt;

&lt;p&gt;Ruby 1.9.3 (or superior).&lt;/p&gt;

&lt;p&gt;Install it with rubygems:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;gem install sponges
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;With bundler, add it to your &lt;code&gt;Gemfile&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;sponges&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;h2 id=&quot;toc_289&quot;&gt;Usage&lt;/h2&gt;

&lt;p&gt;In a file called &lt;code&gt;example.rb&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# The worker class is the one you want to daemonize.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;sponges&amp;#39;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Worker&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Trap the HUP signal, set a boolean to true.&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;trap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:HUP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;no&quot;&gt;Sponges&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;HUP signal trapped, clean stop.&amp;quot;&lt;/span&gt;
      &lt;span class=&quot;vi&quot;&gt;@hup&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;run&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;Sponges&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Process&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pid&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@hup&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# is true, we need to shutdown this worker&lt;/span&gt;
      &lt;span class=&quot;no&quot;&gt;Sponges&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;HUP signal trapped, shutdown...&amp;quot;&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;exit&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# everything&amp;#39;s fine, we can exit&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# this worker can continue its work&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;sleep&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;rand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;run&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;Sponges&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;configure&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;logger&lt;/span&gt;            &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;MyCustomLogger&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;# optionnal&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;              &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;                    &lt;span class=&quot;c1&quot;&gt;# optionnal, default to cpu&amp;#39;s size&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;daemonize&lt;/span&gt;         &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;                 &lt;span class=&quot;c1&quot;&gt;# optionnal, default to false&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;port&lt;/span&gt;              &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5032&lt;/span&gt;                 &lt;span class=&quot;c1&quot;&gt;# optionnal, default to 5032&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;after_fork&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Execute code when a child process is created&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;on_chld&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Execute code when a child process is killed&amp;quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Register a pool named &amp;quot;worker_name&amp;quot;.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;Sponges&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;worker_name&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;Worker&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;some&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;run&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;See the help message&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;ruby example.rb
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Start workers&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;ruby example.rb start
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Start workers and daemonize them:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;ruby example.rb start -d
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Start 8 instances of the worker and daemonize them:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;ruby example.rb start -d -s 8 # By default, size equals cpu core&amp;#39;s size.
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Restart gracefully 4 instances of the worker, with a timeout of 3 seconds and
daemonize them:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;ruby example.rb restart -g -s 4 -t 3
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Stop workers with a &lt;code&gt;QUIT&lt;/code&gt; signal&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;ruby example.rb stop
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Stop workers with a &lt;code&gt;KILL&lt;/code&gt; signal&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;ruby example.rb kill
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Stop workers with a &lt;code&gt;HUP&lt;/code&gt; signal&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;ruby example.rb stop -g -t 5
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;In this case, you will have to trap the &lt;code&gt;HUP&lt;/code&gt; signal, and handle a clean stop
from each worker. The point is to wait for a task to be done before quitting. A
timeout can be specified with the &lt;code&gt;-t&lt;/code&gt; option. When this timeout is hit, the
process will be automatically killed.&lt;/p&gt;

&lt;p&gt;Increment worker&#39;s pool size&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;ruby example.rb increment # will add a worker to the pool.
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Decrement worker&#39;s pool size&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;ruby example.rb decrement # will remove a worker to the pool.
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;h2 id=&quot;toc_290&quot;&gt;Http supervision&lt;/h2&gt;

&lt;p&gt;sponges provides an http interface to supervise pool&#39;s activity, and to expose
pids. Http supervision can be enabled in configuration:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;Sponges&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;configure&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;port&lt;/span&gt;            &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3333&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;By default, sponges listens on port 5032, and responds in json. Here is an
example of response:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;javascript&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&amp;quot;supervisor&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;pid&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;11537&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;pctcpu&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;pctmem&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.22&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;created_at&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;2013-03-05 15:21:04 +0100&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&amp;quot;children&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&amp;quot;pid&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;11540&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&amp;quot;pctcpu&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&amp;quot;pctmem&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.21&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&amp;quot;created_at&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;2013-03-05 15:21:04 +0100&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&amp;quot;pid&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;11543&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&amp;quot;pctcpu&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&amp;quot;pctmem&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.21&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&amp;quot;created_at&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;2013-03-05 15:21:04 +0100&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&amp;quot;pid&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;11546&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&amp;quot;pctcpu&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&amp;quot;pctmem&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.21&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&amp;quot;created_at&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;2013-03-05 15:21:04 +0100&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&amp;quot;pid&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;11549&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&amp;quot;pctcpu&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&amp;quot;pctmem&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.21&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&amp;quot;created_at&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;2013-03-05 15:21:04 +0100&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;h2 id=&quot;toc_291&quot;&gt;Patterns&lt;/h2&gt;

&lt;p&gt;We use &lt;code&gt;sponges&lt;/code&gt; on several of our projets, and we can see two different patterns
of use for sponges.&lt;/p&gt;

&lt;h3 id=&quot;toc_292&quot;&gt;The classic way&lt;/h3&gt;

&lt;p&gt;A worker build upon Redis, Beanstalkd, or anything capable of blocking on a
queue. This worker waits for a job, receive a job, process the job, and waits
for a new job. Simple and straightforward.&lt;/p&gt;

&lt;p&gt;This task must use pull/push socket, and not pub/sub. When a pool of workers is
starting, we do not want to have several workers receiving the same task.&lt;/p&gt;

&lt;h3 id=&quot;toc_293&quot;&gt;The brutal way&lt;/h3&gt;

&lt;p&gt;The brutal way looks like the classic way, except it does not wait for a new
job, it exits.&lt;/p&gt;

&lt;p&gt;Yes, exactly, it exits. By doing so, the supervisor will catch a signal for an
exiting child, and fork a new process. This process takes the turn on the queue,
and wait for a job.&lt;/p&gt;

&lt;p&gt;Why this pattern&amp;nbsp;? Because of memory management. By exiting, the memory is
completely freed by the kernel. We used this pattern in a worker manipulating
some huge xml files (around 1 go) which happens to leak memory quite fast.&lt;/p&gt;

&lt;p&gt;However, this pattern is slower, since it has to require everything on each
job.&lt;/p&gt;

&lt;h2 id=&quot;toc_294&quot;&gt;Unix&lt;/h2&gt;

&lt;p&gt;Internally, &lt;code&gt;sponges&lt;/code&gt; strongly relies on Unix, using fork, signals and pipe.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;fork&lt;/code&gt; is used to create one or several worker process.&lt;/p&gt;

&lt;p&gt;Signals are used to delegate commands from the supervisor to each process. By
nature, signals are asynchronous and unidirectional. Not knowing when a signal
occurs is not a problem, but not knowing when Ruby will run a signal handler
could be one. The tricky case: receiving a signal while doing some work on
another signal handler.&lt;/p&gt;

&lt;p&gt;We solved these problems with a &lt;code&gt;pipe&lt;/code&gt;. When a signal occurs, only one action
is performed: writing this signal to a pipe. A thread dedicated to signals
handlers reads this pipe and performs handler one at the time. This solves two
problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;by enforcing signals to be synchronous, we erase most of weird edge cases we
have seen in the firsts versions of Sponges.&lt;/li&gt;
&lt;li&gt;Ruby 2.0 compatibility. From 2.0, Ruby does not allow to use a mutex in a
signal handler. So something like writing to a logger could break. Writing to a
pipe, on the other hand, does not break.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;toc_295&quot;&gt;One last word&lt;/h1&gt;

&lt;p&gt;Sponges would not have been the same without &lt;a href=&quot;https://github.com/jstorimer&quot;&gt;Jesse
Storimer&lt;/a&gt; and his awesome book about
&lt;a href=&quot;http://workingwithunixprocesses.com/&quot;&gt;Unix&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title type="html">Document all the things</title>
   <link href="http://dev.af83.com/2013/03/18/document-all-the-things.html"/>
   <updated>2013-03-18T00:00:00+01:00</updated>
   <id>http://dev.af83.com/2013/03/18/document-all-the-things</id>
   <author><name>chatgris</name><email>contact@af83.com</email></author>
   <content type="html">&lt;p&gt;We&#39;ve just released &lt;a href=&quot;https://github.com/AF83/documentator&quot;&gt;documentator&lt;/a&gt;.
documentator is like &lt;a href=&quot;https://github.com/AF83/capistrano-af83&quot;&gt;capistrano-af83&lt;/a&gt;,
but for documentation. The idea is the same: not to redo the same thing over and
over again on each project.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;documentator&lt;/code&gt; has one primary goal: having better docs on our projects.&lt;/p&gt;

&lt;h2 id=&quot;toc_283&quot;&gt;Installation&lt;/h2&gt;

&lt;p&gt;The rubygems way:&lt;/p&gt;

&lt;p&gt;Or with bundler, add it to your &lt;code&gt;Gemfile&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;group&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:development&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;documentator&amp;quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;h2 id=&quot;toc_284&quot;&gt;Usage&lt;/h2&gt;

&lt;p&gt;Commands should be used from the root directory of the current project.&lt;/p&gt;

&lt;h3 id=&quot;toc_285&quot;&gt;Bootstrap&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;bootstrap&lt;/code&gt; provides a minimal set of documentation files.
Those are empty, and they &lt;em&gt;must&lt;/em&gt; be written for each project. The content is specific
to each project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What&#39;s the architecture? (providing a &lt;a href=&quot;http://ditaa.sourceforge.net/&quot;&gt;ditaa&lt;/a&gt;
schema will  earn you some extra karma points)&lt;/li&gt;
&lt;li&gt;Dependencies?&lt;/li&gt;
&lt;li&gt;Environnements?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As a treat, &lt;code&gt;bootstrap&lt;/code&gt; generates a Gemfile in &lt;code&gt;project/doc&lt;/code&gt; which includes
&lt;a href=&quot;https://github.com/nono/guide-em-up&quot;&gt;Guide&#39;em up&lt;/a&gt;. Guide&#39;em up can be used to
preview markdown file in a browser.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;bundle &lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;documentator bootstrap
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;h3 id=&quot;toc_286&quot;&gt;Importing templates&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;import&lt;/code&gt; provides templates for common documentation that should be the same
from one project to another. Installing ElasticSearch is basically always the same. If
there are projet specific particularities, you can always add them here.&lt;/p&gt;

&lt;p&gt;Since version &lt;code&gt;0.1.0&lt;/code&gt;, &lt;code&gt;documentator&lt;/code&gt; supports internationalization.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;bundle &lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;documentator list
bundle &lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;documentator list fr
bundle &lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;documentator list en
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;bundle &lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;documentator import fr elasticsearch
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;h2 id=&quot;toc_287&quot;&gt;Contribution&lt;/h2&gt;

&lt;p&gt;YES. We want contributions. Pull-requests are welcome&amp;nbsp;!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Adding a bootstrap file is done by adding a file to
&lt;code&gt;lib/documentator/bootstrap&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Adding a templates file is done by adding a file to
&lt;code&gt;lib/documentator/templates&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title type="html">Why you should consider Beanstalkd</title>
   <link href="http://dev.af83.com/2013/03/13/why-you-should-consider-beanstalkd.html"/>
   <updated>2013-03-13T00:00:00+01:00</updated>
   <id>http://dev.af83.com/2013/03/13/why-you-should-consider-beanstalkd</id>
   <author><name>chatgris</name><email>contact@af83.com</email></author>
   <content type="html">&lt;p&gt;Processing in background  IO bound or cpu bound tasks is now a common
practice in most web applications. There&#39;s plenty of software to help build
background jobs, some based on Redis, some based on a specific language implementation
with threads, some based on a messaging system, and there&#39;s Beanstalkd.&lt;/p&gt;

&lt;h2 id=&quot;toc_279&quot;&gt;Background&lt;/h2&gt;

&lt;p&gt;In the past few months, I had the opportunity to work on a big scale backend
project. The essence of this project is to take as input various, in typology
and size, xml files. Complex validations and transformations are applied on this
data, caches are prepared, the extracted data is stored and indexed, and so on.
Each of these tasks is done by a well identified worker that can be written in
ruby, php or perl.&lt;/p&gt;

&lt;p&gt;This legacy system was built upon mysql, some polling and a big &lt;em&gt;start&lt;/em&gt; launched
every single day.&lt;/p&gt;

&lt;p&gt;One of our many missions was to make it resilient to stopping / restarting, to allow
input at any given moment, and eliminate any notion of beginning or end.
But… without changing everything in either the inputs or outputs of the system.
And… we get bonus points for a priority based system.&lt;/p&gt;

&lt;p&gt;Oh, one last detail, this system needs to be distributed across dozens of servers.
And, as you maybe already know, &lt;a href=&quot;http://www.somethingsimilar.com/2013/01/14/notes-on-distributed-systems-for-young-bloods/&quot;&gt;distributed systems are not easy
beasts&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;toc_280&quot;&gt;Messaging&lt;/h2&gt;

&lt;p&gt;From the beginning, we chose to inverse the approach: no more polling. Workers
do not ask for a job, they wait that another brick gives them one. We then
needed a system that organizes, prioritizes and distributes jobs, hence a
messaging system. We considered various options like
&lt;a href=&quot;http://www.rabbitmq.com/&quot;&gt;RabbitMQ&lt;/a&gt;, &lt;a href=&quot;http://www.zeromq.org/&quot;&gt;ØMQ&lt;/a&gt; and
&lt;a href=&quot;http://kr.github.com/beanstalkd/&quot;&gt;Beanstalkd&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Those options could look surprising, since one is a &quot;messaging server&quot;,
another is a &quot;socket library&quot;, and the last one is a &quot;work queue&quot;. And yet, we
had, at some extend, a proof of concept running of each of those solutions.&lt;/p&gt;

&lt;p&gt;We ruled out RabbitMQ because it does not provide any easy and reliable priority
management.&lt;/p&gt;

&lt;p&gt;We ruled out ØMQ because it was not &quot;enterprise-ready&quot; enough, and as a
framework, it demands way more effort than a &quot;server as a binary that just
works&quot;.&lt;/p&gt;

&lt;p&gt;But, ØMQ, being such a beauty, will be the topic of an upcoming blog post.&lt;/p&gt;

&lt;h2 id=&quot;toc_281&quot;&gt;So, why Beanstalkd&amp;nbsp;?&lt;/h2&gt;

&lt;p&gt;Basically, we needed to distribute jobs across a closed network, to prioritize
them, and consume them. Well, that&#39;s exactly what Beanstalkd provides.&lt;/p&gt;

&lt;p&gt;Beanstalkd gives the possibility to organize jobs in &lt;code&gt;tubes&lt;/code&gt;, each tube
corresponding to a job type. Tubes are lazily created. A client
can listen to several Beanstalkd&#39;s tubes.&lt;/p&gt;

&lt;p&gt;A producer can &lt;code&gt;put&lt;/code&gt; jobs in a tube, let&#39;s say a json representation, for
example. &lt;code&gt;put&lt;/code&gt; accepts various options like &lt;code&gt;ttr&lt;/code&gt;, &lt;code&gt;pri&lt;/code&gt; or &lt;code&gt;delay&lt;/code&gt;. and &lt;code&gt;pri&lt;/code&gt; allows
to define a priority on a job. This was a killer feature for our use case.&lt;/p&gt;

&lt;p&gt;A consumer can &lt;code&gt;reserve&lt;/code&gt; a job: if no job is available, Beanstalkd will wait
until a job becomes available. The client has a limited amount of time to
process this job. When the &lt;code&gt;ttr&lt;/code&gt; (time to run) time out, Beanstalkd will push
back the job in queue. A consumer can &lt;code&gt;touch&lt;/code&gt; to push back a TTR.&lt;/p&gt;

&lt;p&gt;When a job is successfully processed, a consumer can &lt;code&gt;delete&lt;/code&gt; the job from the tube.
In the case of failure, the consumer can &lt;code&gt;bury&lt;/code&gt; the job. This job will not be pushed
back to the tube, but will be available for further inspection.&lt;/p&gt;

&lt;p&gt;A consumer can &lt;code&gt;release&lt;/code&gt; a job, Beanstalkd will push  this job back in the tube,
and make it available for another client. &lt;code&gt;release&lt;/code&gt; is commonly used with the
&lt;code&gt;delay&lt;/code&gt; option. This option tells Beanstalkd to push back this job in
the tube, but with a delay.&lt;/p&gt;

&lt;p&gt;Beanstalkd &lt;a href=&quot;https://github.com/kr/beanstalkd/wiki/client-libraries&quot;&gt;clients&lt;/a&gt; can
be found in most common languages, a &lt;a href=&quot;https://github.com/denniskuczynski/beanstalkd_view&quot;&gt;web
interface&lt;/a&gt; can be useful
for debugging.&lt;/p&gt;

&lt;h2 id=&quot;toc_282&quot;&gt;Overall&lt;/h2&gt;

&lt;p&gt;Beanstalkd was really the right tool for the job: full-featured, lightweight,
language agnostic, and easy to administrate.&lt;/p&gt;

&lt;p&gt;It is so easy to work with, we kind of forgot Beanstalkd is at the center of
this system.&lt;/p&gt;

&lt;p&gt;If you are interested in Beanstalkd, and you should be, the best read so far is the
&lt;a href=&quot;https://github.com/kr/beanstalkd/blob/master/doc/protocol.md&quot;&gt;protocol
description&lt;/a&gt;. It
is an easy read and, by definition, an in-depth guide of Beanstalkd&#39;s features.
Proving, Beanstalkd is a really well designed piece of software.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title type="html">Ajouter un job jenkins en ligne de commande</title>
   <link href="http://dev.af83.com/2013/03/11/ajouter-un-job-jenkins-en-ligne-de-commande.html"/>
   <updated>2013-03-11T00:00:00+01:00</updated>
   <id>http://dev.af83.com/2013/03/11/ajouter-un-job-jenkins-en-ligne-de-commande</id>
   <author><name>spk</name><email>contact@af83.com</email></author>
   <content type="html">&lt;p&gt;Nous avons au fil des projets créé une sorte de template de job jenkins.&lt;/p&gt;

&lt;p&gt;Le problème est que l&#39;on utilise la fonction «&amp;nbsp;Copier un Job existant&amp;nbsp;» de
jenkins et on doit faire des rechercher/remplacer.&lt;/p&gt;

&lt;p&gt;Ce n&#39;est pas très pratique via l&#39;interface web de jenkins car certaines options
sont cachées, et donc, on finit par en oublier.&lt;/p&gt;

&lt;p&gt;On peut récupérer la config xml pour un job via un projet existant, par exemple&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;console&quot;&gt;&lt;span class=&quot;go&quot;&gt;cp ~/.hudson/jobs/NOM_DU_JOB/config.xml jenkins-project-template.xml&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Puis éditer le fichier &lt;code&gt;jenkins-project-template.xml&lt;/code&gt; pour avoir un fichier
interprétable par ERB.&lt;/p&gt;

&lt;p&gt;Un exemple avec l&#39;URL du projet&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;xml&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;projectUrl&amp;gt;&lt;/span&gt;https://github.com/AF83/&lt;span class=&quot;err&quot;&gt;&amp;lt;&lt;/span&gt;%= PROJECT %&amp;gt;/&lt;span class=&quot;nt&quot;&gt;&amp;lt;/projectUrl&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Une fois toutes les variables mises en place, on peut utiliser le template pour
générer un job avec&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;console&quot;&gt;&lt;span class=&quot;go&quot;&gt;export PROJECT=sponges&lt;/span&gt;

&lt;span class=&quot;go&quot;&gt;ruby -rerb -e &amp;quot;PROJECT = ENV[&amp;#39;PROJECT&amp;#39;]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;e = ERB.new(File.read(&amp;#39;jenkins-project-template.xml&amp;#39;))&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;puts e.result&amp;quot; &amp;gt; $PROJECT.hudson.config.xml&lt;/span&gt;

&lt;span class=&quot;go&quot;&gt;curl -H &amp;quot;Content-Type: text/xml&amp;quot; -s --data &amp;quot;@$PROJECT.hudson.config.xml&amp;quot; \&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;quot;http://localhost:8080/createItem?name=$PROJECT&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
</content>
 </entry>
 
 <entry>
   <title type="html">Scruter ses processus avec strace</title>
   <link href="http://dev.af83.com/2013/03/07/scruter-ses-processus-avec-strace.html"/>
   <updated>2013-03-07T00:00:00+01:00</updated>
   <id>http://dev.af83.com/2013/03/07/scruter-ses-processus-avec-strace</id>
   <author><name>phorque</name><email>contact@af83.com</email></author>
   <content type="html">&lt;p&gt;&lt;em&gt;strace&lt;/em&gt; est un outil, utilisable en ligne de commande, qui
affiche les appels systèmes effectués par un processus et ses
enfants. Ces appels systèmes sont le seul contact du processus avec
l&#39;extérieur&amp;nbsp;: pas de lecture de fichier, de réseau ou d&#39;affichage sans
passer par des appels au noyau. L&#39;affichage de ces appels permet de
débugger et d&#39;étudier le comportement du processus en laissant de
coté la logique du code pour s&#39;attacher uniquement à ses interactions.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;strace&lt;/em&gt; s&#39;utilise simplement en lui passant une commande à exécuter&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;$ strace ls
[...]
open(&amp;quot;.&amp;quot;, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 3
getdents(3, /* 5 entries */, 32768)     = 144
getdents(3, /* 0 entries */, 32768)     = 0
close(3)                                = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 4), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f1119e93000
write(1, &amp;quot;brownies  cookies  cupcakes\n&amp;quot;, 28) = 28
close(1)                                = 0
munmap(0x7f1119e93000, 4096)            = 0
close                                = 0
exit_group(0)                           = ?
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Cet exemple permet de décortiquer le fonctionnement de la commande
&lt;em&gt;ls&lt;/em&gt;. On peut y voir l&#39;ouverture du répertoire &lt;code&gt;.&lt;/code&gt; avec &lt;code&gt;open&lt;/code&gt;,
son parcours avec &lt;code&gt;getdents&lt;/code&gt; ainsi que l&#39;écriture du résultat sur
la sortie standard avec &lt;code&gt;write&lt;/code&gt;. Ces appels système disposent
généralement d&#39;une page de &lt;em&gt;man&lt;/em&gt; qui décrit leur différents
paramètres et la valeur renvoyée (section 2 des pages de man).&lt;/p&gt;

&lt;p&gt;Ces appels peuvent être séparés en plusieurs catégories&amp;nbsp;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;les appels dédiés à la communication avec l&#39;extérieur&amp;nbsp;: il s&#39;agit
notamment des appels &lt;code&gt;open&lt;/code&gt;, &lt;code&gt;read&lt;/code&gt;, &lt;code&gt;write&lt;/code&gt;, &lt;code&gt;close&lt;/code&gt; et par
extension tous les appels qui manipulent des descripteurs de
fichier. Dans l&#39;exemple précédent, la fonction &lt;code&gt;open&lt;/code&gt; qui ouvre le
répertoire &lt;code&gt;.&lt;/code&gt; renvoie le descripteur de fichier &lt;code&gt;3&lt;/code&gt;, ce descripteur
sera utilisé par &lt;code&gt;getdents&lt;/code&gt; pour récupérer le contenu du
répertoire avant d&#39;être fermé par &lt;code&gt;close&lt;/code&gt;. D&#39;autres appels
renvoient des descripteurs, notamment &lt;code&gt;accept&lt;/code&gt; qui ouvre un
descripteur pour la communication avec un client (généralement en
TCP) ou &lt;code&gt;connect&lt;/code&gt; pour la communication avec un serveur&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;les appels dédiés à la gestion de la mémoire&amp;nbsp;: &lt;code&gt;mmap&lt;/code&gt;,
&lt;code&gt;munmap&lt;/code&gt;, &lt;code&gt;brk&lt;/code&gt; et &lt;code&gt;sbrk&lt;/code&gt; permettent d&#39;allouer et de
libérer des portions de la mémoire. L&#39;exemple précédent montre un
appel à &lt;code&gt;mmap&lt;/code&gt; pour allouer un buffer de 4096 octets, ce buffer
sera utilisé pour copier la sortie (le nom des fichiers) avant
l&#39;écriture sur la sortie standard puis sera désalloué avec
&lt;code&gt;munmap&lt;/code&gt;. Notons que &lt;code&gt;mmap&lt;/code&gt; est aussi utilisé pour &lt;em&gt;mapper&lt;/em&gt; des
fichiers en mémoire.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;D&#39;autres appels, qui ne sont pas présents dans l&#39;exemple de &lt;em&gt;ls&lt;/em&gt;, sont
aussi très courants&amp;nbsp;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;les multiplexeurs&amp;nbsp;: généralement &lt;code&gt;poll&lt;/code&gt;, &lt;code&gt;select&lt;/code&gt;,
&lt;code&gt;epoll_wait&lt;/code&gt; ou &lt;code&gt;kqueue&lt;/code&gt;. Ces appels servent généralement de
point central à un processus, ils permettent de gérer les
différents canaux de communication d&#39;un processus en regroupant
l&#39;attente des évènements en un seul appel. Ces appels sont bloquants et ne
retournent que lorsqu&#39;un évènement arrive sur un descripteur de
fichier ou que leur &lt;em&gt;timeout&lt;/em&gt; est atteint&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;les appels dédiés au temps&amp;nbsp;: souvent &lt;code&gt;gettimeofday&lt;/code&gt; ou
&lt;code&gt;clock_gettime&lt;/code&gt; qui permettent de retourner différentes
interprétation du temps&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;les appels dédiés aux threads&amp;nbsp;: généralement tous ceux qui commencent
par &lt;code&gt;pthread_&lt;/code&gt;&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;les appels dédiés aux signaux&amp;nbsp;: &lt;code&gt;kill&lt;/code&gt; et &lt;code&gt;signal&lt;/code&gt; sont les plus
connus mais Posix en compte un certain nombre.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;toc_273&quot;&gt;Quelques explications sur les options de strace&lt;/h2&gt;

&lt;p&gt;Quelques options de &lt;em&gt;strace&lt;/em&gt; méritent un peu plus d&#39;attention&amp;nbsp;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-p&lt;/code&gt;&amp;nbsp;: permet de s&#39;attacher à un processus qui est déjà en train de
s&#39;exécuter, en utilisant son &lt;em&gt;pid&lt;/em&gt;. Notons que comme &lt;em&gt;strace&lt;/em&gt; utilise l&#39;API
&lt;code&gt;ptrace&lt;/code&gt; il n&#39;est pas possible de tracer plus d&#39;une fois le même processus
ou de tracer un processus qui se trace lui même&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-f&lt;/code&gt;&amp;nbsp;: permet de suivre les &lt;em&gt;forks&lt;/em&gt; d&#39;un processus en affichant à la
fois les appels du parents et des enfants&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-o&lt;/code&gt;&amp;nbsp;: enregistrer la sortie dans un fichier&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-c&lt;/code&gt;&amp;nbsp;: afficher des statistiques sur le temps passé et le nombre d&#39;appels.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;toc_274&quot;&gt;Identifier les problèmes&lt;/h2&gt;

&lt;h3 id=&quot;toc_275&quot;&gt;Les fuites de mémoires&lt;/h3&gt;

&lt;p&gt;Deux comportements peuvent caractériser une fuite de mémoire&amp;nbsp;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;de nombreux appels à &lt;code&gt;brk&lt;/code&gt; avec un paramètre qui augmente constamment&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;de nombreux appels à &lt;code&gt;mmap&lt;/code&gt; sans appel à &lt;code&gt;munmap&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Le programme suivant génère une fuite de mémoire&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;c&quot;&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(;;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;malloc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4096&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Le résultat avec &lt;em&gt;strace&lt;/em&gt;&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;[...]
brk(0)                                  = 0x1f7e000
brk(0x1fa0000)                          = 0x1fa0000
brk(0x1fc1000)                          = 0x1fc1000
brk(0x1fe2000)                          = 0x1fe2000
[...]
brk(0x1fd7c000)                         = 0x1fd7c000
brk(0x1fd9d000)                         = 0x1fd9d000
brk(0x1fdbe000)                         = 0x1fdbe000
[...]
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;h3 id=&quot;toc_276&quot;&gt;Les fuites de descripteurs de fichier&lt;/h3&gt;

&lt;p&gt;Les descripteurs de fichier servent d&#39;identifiants pour les fichiers,
les connexions, les pipes (dont l&#39;entrée et la sortie standard) et
pour un certain nombre d&#39;autres interfaces. Tout comme la mémoire,
ceux-ci doivent être &lt;em&gt;libérés&lt;/em&gt; pour ne pas atteindre les limites
imposés par le système.&lt;/p&gt;

&lt;p&gt;Les descripteurs de fichier sont des entiers qui se suivent, si l&#39;un
d&#39;eux est libéré il sera immédiatement &lt;em&gt;recyclé&lt;/em&gt; pour servir
d&#39;identifiant à une autre ressource. Il est donc assez facile
d&#39;identifier les fuites en observant le numéro des descripteurs&amp;nbsp;: si
ceux-ci sont de plus en plus élevés sans raison apparente c&#39;est qu&#39;ils
ne sont pas fermés correctement.&lt;/p&gt;

&lt;p&gt;Le programme suivant ouvre tous les fichiers d&#39;un répertoire sans
jamais les fermer&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;c&quot;&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;DIR&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dirent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;dir&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;opendir&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;.&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;readdir&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;open&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;d_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;O_RDONLY&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Le résultat avec strace&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;[...]
open(&amp;quot;.&amp;quot;, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 3
getdents(3, /* 128 entries */, 32768)   = 4240
open(&amp;quot;.dbus&amp;quot;, O_RDONLY)                 = 4
open(&amp;quot;.cache&amp;quot;, O_RDONLY)                = 5
open(&amp;quot;.gvfs&amp;quot;, O_RDONLY)                 = 6
[...]
open(&amp;quot;.profile&amp;quot;, O_RDONLY)              = 431
open(&amp;quot;.bash_logout&amp;quot;, O_RDONLY)          = 432
open(&amp;quot;.gegl-0.0&amp;quot;, O_RDONLY)             = 433
[...]
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;h3 id=&quot;toc_277&quot;&gt;Autres comportements anormaux&lt;/h3&gt;

&lt;p&gt;Un processus qui fait un minimum d&#39;entrée/sorties dans le temps
utilisera, presque toujours, un multiplexeur (généralement &lt;code&gt;poll&lt;/code&gt;,
&lt;code&gt;select&lt;/code&gt;, &lt;code&gt;epoll_wait&lt;/code&gt; ou &lt;code&gt;kqueue&lt;/code&gt;) qui lui permettra de suivre
simultanément tous les évènements susceptibles de le &lt;em&gt;réveiller&lt;/em&gt;, tout en
bloquant sans consommer de CPU quand aucune tâche n&#39;est en cours.&lt;/p&gt;

&lt;p&gt;Un serveur HTTP en &lt;em&gt;bonne santé&lt;/em&gt; fournira plus ou moins la trace
suivante. À la réception d&#39;une requête, la fonction &lt;code&gt;epoll_wait&lt;/code&gt;
retourne, le serveur traite la demande puis bloque à nouveau dans
&lt;code&gt;epoll_wait&lt;/code&gt; en attendant une nouvelle requête.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;$ strace -p [pid]
epoll_wait(16, }, 512, 4294967295) = 1
accept(13, {sa_family=AF_INET, sin_port=htons(39824),
           sin_addr=inet_addr(&amp;quot;127.0.0.1&amp;quot;)}, [16]) = 3
recvfrom(3, &amp;quot;GET / HTTP/1.1\r\nHost: localhost\r&amp;quot;..., 1024, 0, NULL, NULL) = 376
write(3, &amp;quot;HTTP/1.1 404 Not Found\r\nServer: &amp;quot;..., 387) = 387
close(3)
epoll_wait(16, 
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Imaginons maintenant que ce serveur HTTP ne réponde plus malgré le fait
que son processus soit toujours présent. On peut diagnostiquer le
problème en s&#39;attachant directement au processus&amp;nbsp;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;si il n&#39;y a aucun retour de &lt;em&gt;strace&lt;/em&gt;, le serveur est très certainement
bloqué dans une boucle entièrement logique (sans appels systèmes)&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;si le serveur est bloqué sur un autre appel que le multiplexeur, il
peut s&#39;agir d&#39;un I/O sur une ressource particulièrement lente, dans
le cas d&#39;appels à &lt;code&gt;read&lt;/code&gt;, &lt;code&gt;write&lt;/code&gt; ou leurs dérivés, ou d&#39;un deadlock,
notamment si le serveur bloque sur un appel à &lt;code&gt;pthread_mutex_lock&lt;/code&gt;&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;si le serveur passe toujours par son multiplexeur mais retourne
directement, il s&#39;agit généralement de la notification d&#39;un évènement
demandant une lecture ou une écriture qui ne serait pas ensuite
exécutée par le serveur&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;si le serveur reste bloqué sur le multiplexeur malgré les requêtes
qui lui sont envoyées&amp;nbsp;: il se peut que la socket du serveur soit
fermée ou qu&#39;elle ne soit pas en écoute sur le port ou l&#39;interface réseau
attendu.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;toc_278&quot;&gt;Beyond strace, d&#39;autres outils utiles&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;lsof&lt;/em&gt; permet de lister toutes les ressources ouvertes par les
processus, il est très utile pour savoir à quoi correspond un
descripteur de fichier affiché dans la sortie de &lt;em&gt;strace&lt;/em&gt;&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://valgrind.org/&quot;&gt;&lt;em&gt;valgrind&lt;/em&gt;&lt;/a&gt; et toute sa &lt;a href=&quot;http://valgrind.org/info/tools.html&quot;&gt;suite d&#39;outils&lt;/a&gt; permettent d&#39;observer la
consommation mémoire, les problèmes de multi-threading, l&#39;accès au
cache et comportement &lt;em&gt;anormaux&lt;/em&gt; d&#39;un processus&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://ltrace.org/&quot;&gt;&lt;em&gt;ltrace&lt;/em&gt;&lt;/a&gt; est le petit frère de &lt;em&gt;strace&lt;/em&gt;, permettant de
suivre non pas les appels systèmes mais les appels à des bibliothèques dynamiques.&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title type="html">Load testing with Siege</title>
   <link href="http://dev.af83.com/2013/02/28/load-testing-with-siege.html"/>
   <updated>2013-02-28T00:00:00+01:00</updated>
   <id>http://dev.af83.com/2013/02/28/load-testing-with-siege</id>
   <author><name>Kevin Lacointe</name><email>contact@af83.com</email></author>
   <content type="html">&lt;p&gt;This post will try to explain how to perform a load test of your web
application without pain.&lt;/p&gt;

&lt;p&gt;To achieve this, we&#39;ll use &lt;a href=&quot;http://www.joedog.org/siege-home/&quot;&gt;Siege&lt;/a&gt;,
which is a GPL software written by Jeff Fulmer.&lt;/p&gt;

&lt;p&gt;Its goal is to perform stress and regression tests by defining a list of urls
to be stressed.&lt;/p&gt;

&lt;h2 id=&quot;toc_268&quot;&gt;Defining scenarios&lt;/h2&gt;

&lt;p&gt;Urls are defined in a simple .txt file, each line is an url that Siege will hit
during each scenario.&lt;/p&gt;

&lt;p&gt;Siege urls are defined by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the url&lt;/li&gt;
&lt;li&gt;the HTTP verb&lt;/li&gt;
&lt;li&gt;the query string&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let&#39;s see some examples.&lt;/p&gt;

&lt;p&gt;Hitting the home page of &lt;code&gt;http://example.com&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;http://example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;To simulate a login request with login &lt;code&gt;foo&lt;/code&gt; and password &lt;code&gt;bar&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;http://example.com/users/sign_in POST login=foo&amp;amp;password=bar
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Variables can be used, to prevent domain name repetition for example:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;HOST=http://example.com
$(HOST)/
$(HOST)/page1
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;h2 id=&quot;toc_269&quot;&gt;Authenticated scenarios&lt;/h2&gt;

&lt;p&gt;Most applications can&#39;t be stressed completely without user authentication.
Siege allow to define urls that will be executed before each scenario.&lt;/p&gt;

&lt;p&gt;These urls have the same format as url in scenario, but are defines in the
login URL section of Siege config file (&lt;code&gt;siegerc&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;You can generate this file by running &lt;code&gt;siege.config&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Example&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;login-url = &lt;a href=&quot;http://example.com/users/sign_in&quot;&gt;http://example.com/users/sign_in&lt;/a&gt; POST login=user1&amp;amp;password=bar1
login-url = &lt;a href=&quot;http://example.com/users/sign_in&quot;&gt;http://example.com/users/sign_in&lt;/a&gt; POST login=user2&amp;amp;password=bar2
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Given this configuration, Siege will execute one of these requests before
launching a new scenario.&lt;/p&gt;

&lt;p&gt;Of course, if your application is protected against CSRF attacks, you must
disable these protections during the test.&lt;/p&gt;

&lt;p&gt;In a Rails application, you just need to remove the &lt;code&gt;protect_from_forgery&lt;/code&gt;
in your controllers.&lt;/p&gt;

&lt;h2 id=&quot;toc_270&quot;&gt;Start&amp;nbsp;!&lt;/h2&gt;

&lt;p&gt;Now you can start mistreating your application&amp;nbsp;;)&lt;/p&gt;

&lt;p&gt;There are many options you can use, &lt;code&gt;man siege&lt;/code&gt; is your friend, the most important:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-C&lt;/code&gt;: path of your &lt;code&gt;siegerc&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-f&lt;/code&gt;: path of your urls file&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-c&lt;/code&gt;: concurrency&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-t&lt;/code&gt;: test duration&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v&lt;/code&gt;: verbose, this will output hits during test.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The following command will start the test using:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;siege -C .siege/siegerc -f .siege/urls.txt -c 100 -t 1H
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.siege/siegerc&lt;/code&gt; as config file&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.siege/url.txt&lt;/code&gt; as urls file&lt;/li&gt;
&lt;li&gt;a concurrency of 100 users&lt;/li&gt;
&lt;li&gt;a duration of 1 hour for the test&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;toc_271&quot;&gt;Report&lt;/h2&gt;

&lt;p&gt;At the end of the test, Siege will output some informations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;number of transactions performed&lt;/li&gt;
&lt;li&gt;elapsed time&lt;/li&gt;
&lt;li&gt;amount of data transferred&lt;/li&gt;
&lt;li&gt;average response time of transactions&lt;/li&gt;
&lt;li&gt;average number of transaction per second&lt;/li&gt;
&lt;li&gt;average amount of data transferred per second&lt;/li&gt;
&lt;li&gt;average number of simultaneous connections&lt;/li&gt;
&lt;li&gt;number of transaction where status code is 200&lt;/li&gt;
&lt;li&gt;number of successful transactions&lt;/li&gt;
&lt;li&gt;number of failed transactions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It also writes a log file with a summary of the test results in &lt;code&gt;.siege/siege.log&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;toc_272&quot;&gt;Troubleshooting&lt;/h2&gt;

&lt;p&gt;There is a known issue with Siege and cookies without expiration, see &lt;a href=&quot;https://github.com/tail/siege/pull/1&quot;&gt;this ticket&lt;/a&gt; for more informations.&lt;/p&gt;

&lt;p&gt;In a rails application, you can simply add an expiration to bypass this issue,
like this in &lt;code&gt;config/initializers/session_store.rb&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;MyApp::Application.config.session_store :cookie_store, key: &amp;#39;_my_app_session&amp;#39;, expire_after: 1.year
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
</content>
 </entry>
 
 <entry>
   <title type="html">Persisting changes - chrome dev tools</title>
   <link href="http://dev.af83.com/2013/02/25/persisting-changes-chrome-dev-tools.html"/>
   <updated>2013-02-25T00:00:00+01:00</updated>
   <id>http://dev.af83.com/2013/02/25/persisting-changes-chrome-dev-tools</id>
   <author><name>pix</name><email>contact@af83.com</email></author>
   <content type="html">&lt;p&gt;Pourquoi ne pas utiliser chrome dev tools pour faire de la css&amp;nbsp;?&lt;/p&gt;

&lt;p&gt;Ne connaît-on pas trop bien le workflow qui suit&amp;nbsp;?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Je rajoute des styles dans mon inspecteur chrome&lt;/li&gt;
&lt;li&gt;J&#39;arrive à mon objectif&lt;/li&gt;
&lt;li&gt;J&#39;ouvre mon éditeur de texte préféré&lt;/li&gt;
&lt;li&gt;J&#39;essaye de me souvenir des changements que je viens de rentrer dans
mon inspecteur afin de les rapporter dans ma feuille de style définitive&lt;/li&gt;
&lt;li&gt;Je pense avoir terminé et refresh mon navigateur pour voir le
résultat&lt;/li&gt;
&lt;li&gt;Horreur&amp;nbsp;! Le résultat n&#39;est pas celui que j&#39;avais précédemment et en
plus je viens de perdre toutes mes modifications css&lt;/li&gt;
&lt;li&gt;Énervé, je tente de retrouver mon objectif&lt;/li&gt;
&lt;li&gt;Je retourne à l&#39;étape 3 et en fonction de la santé de ma mémoire, je peux
parcourir les étapes 3/ à 8/ une fois, ou bien un nombre de fois qui tend
vers l&#39;infini…&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Trêve de plaisanteries, je pense que nous nous sommes tous plus ou moins
reconnus dans ce workflow peu glorieux.&lt;/p&gt;

&lt;p&gt;Heureusement, il est possible grâce aux chrome dev tools de pallier ce
problème&amp;nbsp;: Les &quot;Persisting Changes&quot;.&lt;/p&gt;

&lt;p&gt;Pour faire joujou, vous aurez besoin d&#39;une &lt;a href=&quot;http://dev.chromium.org/getting-involved/dev-channel&quot;&gt;version dev de
chrome&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Revenons à la fin de l&#39;étape 2 de notre workflow et continuons&amp;nbsp;:&lt;/p&gt;

&lt;p&gt;En exemple j&#39;ai rajouté un &lt;code&gt;text-align: left&lt;/code&gt; et un &lt;code&gt;position:
absolute&lt;/code&gt; sur &lt;code&gt;.page&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Il est possible de cliquer sur la feuille de style afin qu&#39;elle s&#39;ouvre
dans l&#39;onglet &quot;Sources&quot; (voir ci-dessous)&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;Screenshot 1&quot; src=&quot;/img/screen1.png&quot; width=&quot;770&quot; /&gt;&lt;/p&gt;

&lt;p&gt;style.css à été modifié, les modifications sont visibles.&lt;/p&gt;

&lt;p&gt;Avec un clic droit sur le fichier style.css, il est également possible
de sélectionner &quot;local modifications&quot; (voir ci-dessous)&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;Screenshot 2&quot; src=&quot;/img/screen2.png&quot; width=&quot;770&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Une timeline apparaît en bas de l&#39;inspecteur dans laquelle les
modifications ont été versionnées ce qui permet de choisir ou revenir à
l&#39;état attendu.
Vous pouvez visualiser l&#39;historique complet de vos étapes de
développement.   (voir ci-dessous)&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;Screenshot 3&quot; src=&quot;/img/screen3.png&quot; width=&quot;770&quot; /&gt;&lt;/p&gt;

&lt;p&gt;En enregistrant style.css dans un repo git (voir ci-dessous) il est
possible de faire un &lt;code&gt;git diff&lt;/code&gt; pour vous faire une idée des changements
apportés.
Tant que l&#39;inspecteur est ouvert, le fichier est actualisé dès lors
qu&#39;une révision est appliquée.&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;Screenshot 4&quot; src=&quot;/img/screen4.png&quot; width=&quot;770&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Dans un prochain post, nous pourrons nous pencher sur l&#39;utilisation de
cette technique dans le cadre d&#39;un projet SASS ou LESS.&lt;/p&gt;

&lt;p&gt;Pour plus d&#39;informations&amp;nbsp;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developers.google.com/chrome-developer-tools/docs/elements-styles#persist&quot;&gt;https://developers.google.com/chrome-developer-tools/docs/elements-styles#persist&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://paulirish.com/2011/a-re-introduction-to-the-chrome-developer-tools/&quot;&gt;http://paulirish.com/2011/a-re-introduction-to-the-chrome-developer-tools/&lt;/a&gt; ce post date de 2011 mais reste très intéressant&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title type="html">Ruby 2.0 : Keyword arguments</title>
   <link href="http://dev.af83.com/2013/02/18/ruby-2-0-keyword-arguments.html"/>
   <updated>2013-02-18T00:00:00+01:00</updated>
   <id>http://dev.af83.com/2013/02/18/ruby-2-0-keyword-arguments</id>
   <author><name>chatgris</name><email>contact@af83.com</email></author>
   <content type="html">&lt;p&gt;Here&#39;s the long awaited last post in the &quot;Ruby 2.0 feature&#39;s tour&quot; series. With
a release date still fixed to the 24th of February, it was about time.&lt;/p&gt;

&lt;p&gt;This post&#39;s topic will be about &quot;Keyword arguments&quot;. As you can
&lt;a href=&quot;http://en.wikipedia.org/wiki/Named_parameter&quot;&gt;see&lt;/a&gt;, Keyword arguments is not
really a new feature invented by the Ruby designers, but rather an addition that
has been available for years in others languages..&lt;/p&gt;

&lt;h1 id=&quot;toc_265&quot;&gt;Principle&lt;/h1&gt;

&lt;p&gt;Keyword arguments gives the possibility to define arguments in a flexible way.
The common practice is to use &lt;code&gt;Hash&lt;/code&gt; to pass several arguments in any order.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;devblog&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{})&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:tags&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:layout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;post&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;devblog&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Ruby 2.0 : Keyword arguments&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;ruby&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; &amp;quot;Ruby 2.0 : Keyword arguments&amp;quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; [&amp;#39;ruby&amp;#39;]&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; &amp;quot;post&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;The same feature could be achieved by using Keyword arguments:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;devblog&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;layout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;post&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;layout&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;devblog&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Ruby 2.0 : Keyword arguments&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;ruby&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; &amp;quot;Ruby 2.0 : Keyword arguments&amp;quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; [&amp;#39;ruby&amp;#39;]&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; &amp;quot;post&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;No extra &lt;code&gt;fetch&lt;/code&gt; for default values, and arguments available as local variable.&lt;/p&gt;

&lt;p&gt;In the above example, &lt;code&gt;title&lt;/code&gt; is not specified as a Keyword argument to mark
this argument as mandatory.&lt;/p&gt;

&lt;p&gt;Well, it could be done using Keyword arguments but it&#39;s kind of weird.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;devblog&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ArgumentError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;layout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;post&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;layout&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;devblog&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Ruby 2.0 : Keyword arguments&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;ruby&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; &amp;quot;Ruby 2.0 : Keyword arguments&amp;quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; [&amp;#39;ruby&amp;#39;]&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; &amp;quot;post&amp;quot;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;devblog&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;ruby&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; ArgumentError (ArgumentError)`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;h1 id=&quot;toc_266&quot;&gt;Real world use case&lt;/h1&gt;

&lt;p&gt;Let&#39;s now have a look at the &lt;code&gt;select&lt;/code&gt; method from Rails&#39;s
&lt;a href=&quot;http://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html#method-i-select&quot;&gt;ActionView::Helpers::FormOptionsHelper&lt;/a&gt;.
This method takes 5 arguments, including 2 hashes. The first hash relates to
generic options about the select (like, does it include a blank option), and
another one about html&#39;s options (like class, id and so on).&lt;/p&gt;

&lt;p&gt;So, it can lead to something like this where we want to add a css class to the
select element:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;post&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;person_id&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;collection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;selectable&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;How many Rails&#39; developers have wondered about the order of those 2 hashes?&lt;/p&gt;

&lt;p&gt;It could be a common hash, with a key for &lt;code&gt;options&lt;/code&gt;, and another one for
&lt;code&gt;html_options&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;post&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;person_id&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;collection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;html_options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;selectable&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;include_blank&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;That would be nicer, but this will lead to more complexity in setting default values
on &lt;code&gt;options&lt;/code&gt; and &lt;code&gt;html_options&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;By using Keyword arguments, this would look like:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;post&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;person_id&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;collection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;html_options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;selectable&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;include_blank&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Yes, that would look exactly like the previous example.&lt;/p&gt;

&lt;p&gt;The main difference would be on the implementation side.&lt;/p&gt;

&lt;h1 id=&quot;toc_267&quot;&gt;Usage&lt;/h1&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Helpers&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# Just here to allow to call Helpers.select directly. For the sake of the&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# example.&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;module_function&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;choices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;html_options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{})&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;include_blank&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;merge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;html_options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;select_one_hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;choices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{})&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;include_blank&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;merge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}))&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:html_options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;select_keyword&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;choices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;html_options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{})&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;include_blank&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;merge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;html_options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;This module provides 3 versions of the select method, which returns just the
options with the defaults.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Helpers#select&lt;/code&gt; takes two options hashes&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Helpers#select_one_hash&lt;/code&gt; takes one nested hash&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Helpers#select_keyword&lt;/code&gt; uses Keyword arguments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The only difference between &lt;code&gt;Helpers#select&lt;/code&gt; and &lt;code&gt;Helpers#select_keyword&lt;/code&gt; can be
found in the method declaration where the arguments are declared with a &lt;code&gt;:&lt;/code&gt;
instead of &lt;code&gt;=&lt;/code&gt; for the named argument.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Helpers#select_one_hash&lt;/code&gt; has a more complex implementation due to the nested
hash.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;collection&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;23&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# Choises provided to the select method&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Helpers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;post&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;person_id&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;collection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;selectable&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; {:include_blank=&amp;gt;true}&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; {:class=&amp;gt;&amp;quot;selectable&amp;quot;}&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Helpers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;post&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;person_id&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;collection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;include_blank&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
                    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;selectable&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; {:include_blank=&amp;gt;false}&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; {:class=&amp;gt;&amp;quot;selectable&amp;quot;}&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Helpers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;select_one_hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;post&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;person_id&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;collection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                             &lt;span class=&quot;n&quot;&gt;html_options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;selectable&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; {:include_blank=&amp;gt;true}&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; {:class=&amp;gt;&amp;quot;selectable&amp;quot;}&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Helpers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;select_one_hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;post&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;person_id&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;collection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                             &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;html_options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;selectable&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
                             &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;include_blank&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}})&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; {:include_blank=&amp;gt;false}&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; {:class=&amp;gt;&amp;quot;selectable&amp;quot;}&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Helpers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;select_keyword&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;post&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;person_id&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;collection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                            &lt;span class=&quot;n&quot;&gt;html_options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;selectable&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; {:include_blank=&amp;gt;true}&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; {:class=&amp;gt;&amp;quot;selectable&amp;quot;}&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Helpers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;select_keyword&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;post&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;person_id&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;collection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                            &lt;span class=&quot;n&quot;&gt;html_options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;selectable&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
                            &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;include_blank&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; {:include_blank=&amp;gt;false}&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; {:class=&amp;gt;&amp;quot;selectable&amp;quot;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;This feature will be available in Ruby 2.0 in less than one month, and worth to
be looked at!&lt;/p&gt;

&lt;p&gt;And this post closes the Ruby 2.0 preview series.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title type="html">Git commit message</title>
   <link href="http://dev.af83.com/2013/02/11/git-commit-message.html"/>
   <updated>2013-02-11T00:00:00+01:00</updated>
   <id>http://dev.af83.com/2013/02/11/git-commit-message</id>
   <author><name>spk</name><email>contact@af83.com</email></author>
   <content type="html">&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;git commit -m &lt;span class=&quot;s1&quot;&gt;&amp;#39;Devblog: Importance des messages de commit&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Les messages de commit sont importants pour la compréhension du patch et pour
cibler/intéresser un code-reviewer.&lt;/p&gt;

&lt;p&gt;Si vous voulez aussi que votre patch soit accepté par un projet, il est
souvent apprécié que votre message soit cohérent et explique votre
modification. Ceci aide le travail de l&#39;&lt;em&gt;upstream&lt;/em&gt; et augmente les chances
qu&#39;il soit intégré.&lt;/p&gt;

&lt;p&gt;Un bon moyen de montrer le sérieux de l&#39;auteur est de signer le message par
l&#39;option &lt;code&gt;-S&lt;/code&gt;. Vous pouvez lire cet
&lt;a href=&quot;https://phreaknerd.wordpress.com/2012/02/09/signing-git-commits-with-your-gpg-key/&quot;&gt;article&lt;/a&gt;
pour plus d&#39;informations dessus.&lt;/p&gt;

&lt;p&gt;Les conventions de formatage viennent de l&#39;utilisation des emails pour envoyer
un patch pour le kernel, avec la commande &lt;code&gt;git format-patch&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;La première ligne doit avoir moins de 50 caractères (c&#39;est le sujet du mail).&lt;/p&gt;

&lt;p&gt;Avec pour format d&#39;exemple&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;Sujet: Courte description des changements de ce patch &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;que fait ce patch ?&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;

Une description si nécessaire plus détaillée du pourquoi, problème rencontré...
Comme pour les emails, la description ne devrait pas dépasser 80 caractères.

On peut mettre le ticket ou numéro de ticket sur une autre ligne.

Si le commit a été relu ou fait par plusieurs développeurs, il y a le mot clef
&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;Signed-off-by:&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;--signoff&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;. Ou encore &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;Reported-by:&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt; pour les bugs reportés.
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Linus parle justement de ces mots clef sur
&lt;a href=&quot;https://github.com/torvalds/linux/pull/17#issuecomment-5663733&quot;&gt;github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;N&#39;hésitez pas, non plus, à consulter des projets avec des messages de commit bien faits&amp;nbsp;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://git.kernel.org/?p=linux/kernel/git/stable/linux-stable.git;a=commit;h=c284979affcc6870a9a6545fc4b1adb3816dfcbf&quot;&gt;Message de commit du kernel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/joyent/node/commit/6b99fd23237d30a269f35690920ed6a4ab75de1a&quot;&gt;Message de commit de nodejs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title type="html">Release de Koalab, outil de collaboration en ligne</title>
   <link href="http://dev.af83.com/2013/02/04/release-koalab-outil-collaboration-en-ligne.html"/>
   <updated>2013-02-04T00:00:00+01:00</updated>
   <id>http://dev.af83.com/2013/02/04/release-koalab-outil-collaboration-en-ligne</id>
   <author><name>Marie Ailloud</name><email>contact@af83.com</email></author>
   <content type="html">&lt;p&gt;&lt;a href=&quot;https://github.com/AF83/koalab&quot;&gt;Koalab&lt;/a&gt; est une plateforme de board en ligne,
et un projet initié pendant la codeweek d&#39;af83 par une équipe rassemblant des
aviateurs de (presque) tous les pôles&amp;nbsp;: développeurs, gestion de projets, user
experience, commercial/communication.&lt;/p&gt;

&lt;p&gt;Petit retour sur la genèse et les premiers pas du projet…&lt;/p&gt;

&lt;h3 id=&quot;toc_260&quot;&gt;Pourquoi un board en ligne&amp;nbsp;?&lt;/h3&gt;

&lt;p&gt;Chez af83, nous menons la majeure partie des projets en mode agile. Nous
faisons également régulièrement des brainstormings, ateliers, etc. en interne
comme avec des clients et partenaires. Nous sommes donc familiers avec les
boards, Scrum ou autres.&lt;/p&gt;

&lt;p&gt;Cependant les supports physiques ont montré leurs limites&amp;nbsp;:
le partage à distance (télétravail, clients en confcall,…) est compliqué&amp;nbsp;;
certains projets sont confidentiels et avoir à retourner le board quand des
personnes externes sont de passage - ce qui est plus que fréquent - est
contraignant&amp;nbsp;;
la quantité de murs libres (et de planches support) est limitée&amp;nbsp;;
il peut y avoir trop d&#39;informations pour que cela tienne sur un board&amp;nbsp;;
etc.&lt;/p&gt;

&lt;h3 id=&quot;toc_261&quot;&gt;Les partis pris&lt;/h3&gt;

&lt;p&gt;Il existe déjà pas mal de solutions en ligne&amp;nbsp;: &lt;a href=&quot;https://trello.com/&quot;&gt;Trello&lt;/a&gt;
(que nous utilisons beaucoup en interne), des boards collaboratifs comme
&lt;a href=&quot;http://beta.mural.ly/&quot;&gt;mural.ly&lt;/a&gt;, &lt;a href=&quot;http://www.stixy.com/&quot;&gt;stixy&lt;/a&gt;… Cependant
ces outils ne répondaient pas toujours à nos besoins, soit parce qu&#39;ils
faisaient trop de choses, soit parce qu&#39;ils avaient des contraintes de &quot;forme&quot;
trop grandes. Et puis, avouons-le, nous aimons bien faire nos outils&amp;nbsp;;)&lt;/p&gt;

&lt;p&gt;Donc nous avons décidé de profiter de la &quot;codeweek&quot; annuelle pour développer
Koalab, avec les principes directeurs suivants&amp;nbsp;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;simplicité d&#39;usage&lt;/li&gt;
&lt;li&gt;liberté la plus grande possible&lt;/li&gt;
&lt;li&gt;synchronisation temps réel&lt;/li&gt;
&lt;li&gt;multi devices et plateformes&lt;/li&gt;
&lt;li&gt;et bien sûr open-source parce que c&#39;est ce que nous aimons…&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;toc_262&quot;&gt;La première version&lt;/h3&gt;

&lt;p&gt;Elle a été développée en mode lean&amp;nbsp;: première étape le concept, décliné en
&lt;em&gt;wishlist&lt;/em&gt;, qui a été triée rapidement par fonctionnalités clés, futures et
&quot;rêvées&quot;. Deuxième étape, Mathilde et Marie ont travaillé sur l&#39;UX d&#39;un board
et une créa &quot;minimale&quot; pendant que Jérôme, Bruno et Pierre ont implémenté les
toutes premières features.&lt;/p&gt;

&lt;p&gt;Après les premiers tests techniques et utilisateurs, le premier jet est
modifié et nous attaquons en parallèle la recherche d&#39;un nom et d&#39;un premier
logo… Enfin, une home page listant les boards existants et permettant de
créer de nouveaux boards est ajoutée.&lt;/p&gt;

&lt;p&gt;À la fin de ces quelques jours, Koalab permet de créer des boards, lignes et
post-its et d&#39;éditer et déplacer des post-its sous (presque…) tous les bons
navigateurs.&lt;/p&gt;

&lt;h3 id=&quot;toc_263&quot;&gt;Itérations&lt;/h3&gt;

&lt;p&gt;Nous avons profité du temps réservé aux ateliers hebdomadaires, et Bruno de
ses nuits, pour faire&amp;nbsp;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;du bugfix et l&#39;implémentation de features non réalisées pendant la code week&lt;/li&gt;
&lt;li&gt;des tests, des tests et encore des tests&lt;/li&gt;
&lt;li&gt;de la compatibilité tablettes&lt;/li&gt;
&lt;li&gt;du travail UX (nouvelles fonctionnalités, modifications de comportement)&lt;/li&gt;
&lt;li&gt;une &quot;vraie&quot; créa (merci Élodie pour le graphisme et Maxim pour l&#39;intégration).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;toc_264&quot;&gt;Le résultat&lt;/h3&gt;

&lt;p&gt;Comme pour tout projet agile, certaines choses prévues au départ ont été
abandonnées ou repoussées, d&#39;autres ont été ajoutées en cours de développement
(ou supprimées après mise en ligne…), mais nous sommes fiers de cette
première version publique.&lt;/p&gt;

&lt;p&gt;Bien entendu, nous mettrons en production des améliorations et nouvelles
fonctionnalités régulièrement, nous n&#39;avons pas épuisé la &lt;em&gt;to-do list&lt;/em&gt;…&lt;/p&gt;

&lt;p&gt;Et vous, votre avis sur Koalab&amp;nbsp;?&lt;/p&gt;

&lt;p&gt;PS&amp;nbsp;: Pour les curieux, Bruno prépare un billet plongeant sous le capot de Koalab&amp;nbsp;!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title type="html">Petite liste d&#39;événements</title>
   <link href="http://dev.af83.com/2013/01/28/petite-liste-d-evenements.html"/>
   <updated>2013-01-28T00:00:00+01:00</updated>
   <id>http://dev.af83.com/2013/01/28/petite-liste-d-evenements</id>
   <author><name>Bruno Michel</name><email>contact@af83.com</email></author>
   <content type="html">&lt;p&gt;Nous sommes dans une période où nous regardons les événements à venir pour
savoir pour lesquels nous avons particulièrement envie de participer. Il y a
beaucoup d&#39;événements intéressants et le choix est donc difficile. Voici ceux
que nous avons retenu pour le moment&amp;nbsp;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://fosdem.org/2013/&quot;&gt;FOSDEM&lt;/a&gt;, les 2 et 3 février à Bruxelles, est un
événement de référence au niveau européen sur l&#39;Open Source.&lt;/li&gt;
&lt;li&gt;Je vais faire une introduction à Go le 19 février au
&lt;a href=&quot;http://www.gdgnantes.com/evenements/saison-2013/2013---02---19---go-appengine&quot;&gt;GDG Nantes&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.devoxx.com/display/FR13/Accueil&quot;&gt;Devoxx France&lt;/a&gt;, la conférence
pour les développeurs passionnés de Java, se tiendra du 27 au 29 mars à
Paris.&lt;/li&gt;
&lt;li&gt;Nous attendons avec beaucoup d&#39;impatience &lt;a href=&quot;http://realtimeconf.eu/&quot;&gt;The Realtime Conference
Europe&lt;/a&gt;, où nous espérons être à la fois sponsor et
speakers. Ce sera les 22 et 23 avril à Lyon&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://2013.la-conf.org/&quot;&gt;La Conf&lt;/a&gt; va proposer un événement Rails de
qualité avec des speakers reconnus les 9 et 10 mai à Paris.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://sudweb.fr/2013/&quot;&gt;Sud Web&lt;/a&gt; se tiendra les 17 et 18 mai dans le
superbe Palais des Papes, en Avignon, et le programme est très alléchant.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://rubykaigi.org/2013&quot;&gt;The RubyKaigi 2013&lt;/a&gt; sera l&#39;événement de
référence sur Ruby cette année, du 30 mai au 1&lt;sup&gt;er&lt;/sup&gt; juin à Tokyo et nous y
assisterons.&lt;/li&gt;
&lt;li&gt;Nous serons également présent à &lt;a href=&quot;http://www.magmaconf.com/&quot;&gt;MagmaConf&lt;/a&gt; du 5
au 7 juin au Mexique.&lt;/li&gt;
&lt;li&gt;Même si rien n&#39;est encore annoncé, nous sommes confiants que cette année
encore &lt;a href=&quot;http://rulu.eu/&quot;&gt;Ruby Lugdunum&lt;/a&gt; sera une conférence de très grande
qualité organisée par les rubyistes lyonnais.&lt;/li&gt;
&lt;li&gt;L&#39;édition 2013 d&#39;&lt;a href=&quot;http://euruko2013.org/&quot;&gt;Euruko&lt;/a&gt;, la conférence européenne
sur Ruby se déroulera les 28 et 29 juin à Athènes.&lt;/li&gt;
&lt;li&gt;Sur le thème de la conception web et de ses bonnes pratiques, la &lt;a href=&quot;http://kiwiparty.fr/&quot;&gt;Kiwi
Party&lt;/a&gt; se passera le 28 juin à Strasbourg.&lt;/li&gt;
&lt;li&gt;Les &lt;a href=&quot;http://2013.rmll.info/&quot;&gt;Rencontres Mondiales du Logiciel Libre&lt;/a&gt; sont un
rendez-vous incontournable pour nous. Nous serons présents pour cette
édition à Bruxelles début juillet.&lt;/li&gt;
&lt;li&gt;Toujours dans le milieu de l&#39;Open Source, nous étudions la possibilité
d&#39;aller faire un tour à &lt;a href=&quot;http://www.oscon.com/oscon2013&quot;&gt;l&#39;OSCON&lt;/a&gt; du 22 au
26 juillet à Portland, Oregon.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.paris-web.fr/&quot;&gt;Paris Web&lt;/a&gt; sera de nouveau présent en 2013, du 10
au 12 octobre pour être précis, et nous comptons bien y participer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Et maintenant, j&#39;ai une question pour vous&amp;nbsp;: est-ce que vous voyez d&#39;autres
événements à ajouter absolument à cette liste&amp;nbsp;?&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title type="html">URxvt autotransform</title>
   <link href="http://dev.af83.com/2013/01/18/urxvt-autotransform.html"/>
   <updated>2013-01-18T00:00:00+01:00</updated>
   <id>http://dev.af83.com/2013/01/18/urxvt-autotransform</id>
   <author><name>Laurent Arnoud</name><email>contact@af83.com</email></author>
   <content type="html">&lt;p&gt;Beaucoup de langages interprétés nous donnent la ligne où le programme a planté.&lt;/p&gt;

&lt;p&gt;Cela donne, par exemple, en Ruby&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;console&quot;&gt;&lt;span class=&quot;go&quot;&gt;app/controllers/admin/users_controller.rb:13:in `edit&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Il arrive souvent de vouloir aller directement à ligne en question.
Grace à l&#39;option autotransform d&#39;URxvt c&#39;est possible juste en sélectionnant le
&lt;code&gt;fichier:ligne:in&lt;/code&gt; qui sera automatiquement copié dans le «&amp;nbsp;clipboard&amp;nbsp;».&lt;/p&gt;

&lt;p&gt;Pour cela, il suffit de mettre dans votre fichier &lt;code&gt;~/.Xdefaults&lt;/code&gt; ou &lt;code&gt;~/.Xresources&lt;/code&gt;&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;URxvt.selection-autotransform.0: if(/\\n\\[?\\d\\d(\\d\\d-|:)\\d\\d/) { s{^\\[?[\\d:_-]+\\]? +}{};
    s/\\s*\\n\\[?[\\d:_-]{5,}\\]? +/ || /g; s/^\\s+/ /mg; s/( ?) \*\\n( ?)/($1||$2)/eg; s{ $}{}; };
URxvt.selection-autotransform.1: if(/^irb.*?&amp;gt; /) { s{^irb.*?[&amp;gt;*]\\s*}{}mg; s/\\n=&amp;gt;/ #=&amp;gt;/mg; s{\\n$}{};}
URxvt.selection-autotransform.2: if(m{^[ab]/}) { s{^[ab]/}{}g; }
URxvt.selection-autotransform.3: s/^([^:\\s]*):(\\d+)(:|:in)?$/+$2 $1/g;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Cela transforme le &lt;code&gt;fichier:ligne:in&lt;/code&gt; en &lt;code&gt;fichier +ligne&lt;/code&gt;. Il ne reste plus
qu&#39;à faire un&amp;nbsp;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;EDITOR &amp;lt;Shift&amp;gt;+&amp;lt;Insert&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Ces expressions régulières ont été écrites par tpope, vous pouvez consulter son
&lt;a href=&quot;https://github.com/tpope/tpope/blob/master/.Xresources&quot;&gt;.Xresources&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title type="html">Managing Rails assets with Bower</title>
   <link href="http://dev.af83.com/2013/01/02/managing-rails-assets-with-bower.html"/>
   <updated>2013-01-02T00:00:00+01:00</updated>
   <id>http://dev.af83.com/2013/01/02/managing-rails-assets-with-bower</id>
   <author><name>Arnaud Berthomier</name><email>contact@af83.com</email></author>
   <content type="html">&lt;p&gt;Web applications have been shifting from server to client, and with them a lot
more Javascript code and stylesheets are written and, hopefully, re-used.  While
this is quite an obvious statement, it means that we need an efficient way to
manage those assets.&lt;/p&gt;

&lt;p&gt;I&#39;d like to write then that this is a simple matter, and that there is one way
to do it.  But let&#39;s face it, every Javascript coder out there has their own
ideal solution.  So yes we have plenty, which is probably a good thing in a
not-immediately-obvious way.&lt;/p&gt;

&lt;p&gt;This article is to be pragmatic and short however.  As a consequence, I will
write about accommodating &lt;a href=&quot;https://github.com/rails/rails&quot;&gt;Rails&lt;/a&gt; and &lt;a href=&quot;https://github.com/twitter/bower&quot;&gt;Bower&lt;/a&gt;, without mentioning
&lt;a href=&quot;https://github.com/amdjs/amdjs-api/wiki&quot;&gt;AMD&lt;/a&gt;, or projects like &lt;a href=&quot;https://github.com/component/component&quot;&gt;component&lt;/a&gt; that try to solution the
“assets problem” in Rails lingo.  I hope, we can write about these later on
though.&lt;/p&gt;

&lt;h2 id=&quot;toc_251&quot;&gt;How do you manage vendor assets in Rails?&lt;/h2&gt;

&lt;p&gt;Well as rubyists go, &lt;code&gt;gem search&lt;/code&gt; is a common approach to solving problems.
And surely enough there are rubygems that bundle Rails-engines with a bunch of
static assets.&lt;/p&gt;

&lt;p&gt;For example, you can add the following line to your &lt;code&gt;Gemfile&lt;/code&gt; to have the
&lt;a href=&quot;http://backbonejs.org&quot;&gt;BackboneJS&lt;/a&gt; library served through a Rails engine:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;gem &amp;#39;backbone-rails&amp;#39;, &amp;#39;~&amp;gt; 0.9.2&amp;#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;When the asset pipeline requires the Backbone library, it is served by
&lt;code&gt;backbone-rails&lt;/code&gt;.  It looks a little like a case of hammer-nail syndrome: using
Ruby packages for Javascript?  However some gems also provide Rails generators
to save developers the hurdle of bootstrapping their SPA (and a handful of
&lt;code&gt;mkdir&lt;/code&gt;s).  I have mixed feelings about this whole deal: it feels like a hack,
but it is a very practical one.&lt;/p&gt;

&lt;p&gt;There is another way of managing assets around there.  I call it the &lt;em&gt;ostrich
approach&lt;/em&gt; and it&#39;s quite possibly the dirtiest.  It merely consists of using
&lt;code&gt;wget&lt;/code&gt;, or &lt;code&gt;curl&lt;/code&gt;, to throw those annoying Javascript files into your &lt;code&gt;vendor&lt;/code&gt;
directory, and forget about them.  Great idea! (j/k it&#39;s stupid, don&#39;t do
that.)&lt;/p&gt;

&lt;p&gt;All in all, rubyists do not have much tools to manage static assets.&lt;/p&gt;

&lt;p&gt;At af83 we&#39;ve been playing with Twitter&#39;s &lt;a href=&quot;https://github.com/twitter/bower&quot;&gt;Bower&lt;/a&gt; to manage our Rails
app assets for a little while.  If you never heard of Bower, imagine
&lt;a href=&quot;http://gembundler.org&quot;&gt;Bundler&lt;/a&gt; for Javascript code, stylesheets, images: &lt;em&gt;components&lt;/em&gt;.  And
just maybe, have a &lt;a href=&quot;http://net.tutsplus.com/tutorials/tools-and-tips/meet-bower-a-package-manager-for-the-web/&quot;&gt;crash course&lt;/a&gt; on how it&#39;s used.&lt;/p&gt;

&lt;h2 id=&quot;toc_252&quot;&gt;Wait… What about Sprockets?&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/sstephenson/sprockets&quot;&gt;Sprockets&lt;/a&gt; is the core of the Rails asset pipeline.  It is a very
nice tool to help compile/compress your assets in a bandwidth-friendly way.
For all the trouble it saves you from, you should love Sprockets.  Say it loud
now: “I love Sprockets”.&lt;/p&gt;

&lt;p&gt;Then again, to be honest, it would be nice if Sprockets &lt;em&gt;also&lt;/em&gt; did Bower&#39;s job:
for example, it could &lt;em&gt;just work&lt;/em&gt; should I throw a &lt;code&gt;component.json&lt;/code&gt; at it — or,
since we&#39;re in Ruby land have it load some YAML with a list of components.
Maybe that&#39;s akin to feature creep though, and a separate gem would keep things
simpler.&lt;/p&gt;

&lt;p&gt;But that&#39;s for another post I hope.  Meanwhile, let&#39;s see how we can use Bower
with Rails.&lt;/p&gt;

&lt;h2 id=&quot;toc_253&quot;&gt;Setup Bower with Rails&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/twitter/bower&quot;&gt;Bower&lt;/a&gt; is a step in the right direction: it lets you declare a browser
application&#39;s dependencies, and their versions, explicitly.  It is a (young)
&lt;a href=&quot;http://nodejs.org&quot;&gt;nodejs&lt;/a&gt; program though, so it doesn&#39;t integrate seamlessly with your vanilla
Ruby/Rails stack.&lt;/p&gt;

&lt;h3 id=&quot;toc_254&quot;&gt;The hacker way&lt;/h3&gt;

&lt;p&gt;Let&#39;s start by doing things the hacker-way, and have Bower speak Railsish.&lt;/p&gt;

&lt;h4 id=&quot;toc_255&quot;&gt;Setup Bower&lt;/h4&gt;

&lt;p&gt;Using &lt;code&gt;bower&lt;/code&gt; to fetch static assets for rails is simple.  The first step is to
setup a &lt;code&gt;.bowerrc&lt;/code&gt; in your Rails root that looks like this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;{
  &amp;quot;directory&amp;quot;: &amp;quot;vendor/assets/components&amp;quot;,
  &amp;quot;json&amp;quot;: &amp;quot;component.json&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;directory&lt;/code&gt; key sets the destination path,&lt;/li&gt;
&lt;li&gt;the &lt;code&gt;json&lt;/code&gt; key sets the name of the configuration file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the &lt;code&gt;.bowerrc&lt;/code&gt; file is missing, Bower will merely reset to its defaults, and
install components in the &lt;code&gt;./components&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;Second step: specifying Bower dependencies.  Use your favorite editor and open
the &lt;code&gt;component.json&lt;/code&gt; file.  Here&#39;s a sample that will load the jQuery, Backbone
and Lodash libraries:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;{
  &amp;quot;dependencies&amp;quot;: {
    &amp;quot;jquery&amp;quot;: &amp;quot;~1.8.3&amp;quot;,
    &amp;quot;backbone&amp;quot;: &amp;quot;0.9.9&amp;quot;,
    &amp;quot;lodash&amp;quot;: &amp;quot;https://raw.github.com/bestiejs/lodash/v1.0.0-rc.3/lodash.underscore.js&amp;quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Dependencies can be set by version, git repository, local directory, or even
links to remote files: check Bower&#39;s documentation for a complete list of what
you can do here.&lt;/p&gt;

&lt;p&gt;Finally, run &lt;code&gt;bower install&lt;/code&gt; to fetch and install the dependences:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;$ bower install
bower downloading &lt;a href=&quot;https://raw.github.com/bestiejs/lodash/v1.0.0-rc.3/lodash.underscore.js&quot;&gt;https://raw.github.com/bestiejs/lodash/v1.0.0-rc.3/lodash.underscore.js&lt;/a&gt;
bower cloning &lt;a href=&quot;git://github.com/documentcloud/backbone.git&quot;&gt;git://github.com/documentcloud/backbone.git&lt;/a&gt;
bower cached &lt;a href=&quot;git://github.com/documentcloud/backbone.git&quot;&gt;git://github.com/documentcloud/backbone.git&lt;/a&gt;
bower fetching backbone
bower cloning &lt;a href=&quot;git://github.com/components/jquery.git&quot;&gt;git://github.com/components/jquery.git&lt;/a&gt;
bower cached &lt;a href=&quot;git://github.com/components/jquery.git&quot;&gt;git://github.com/components/jquery.git&lt;/a&gt;
bower fetching jquery
bower checking out jquery#1.8.3
bower copying /home/oz/.bower/cache/jquery/cf68c4c4e7507c8d20fee7b5f26709d9
bower checking out backbone#0.9.9
bower copying /home/oz/.bower/cache/backbone/f184345e8f03dbe160c843ce1b7248eb
bower installing jquery#1.8.3
bower installing backbone#0.9.9
bower installing lodash
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;If you check the &lt;code&gt;vendor/assets/components&lt;/code&gt; directory, each dependency is now
sitting under its own subdirectory.&lt;/p&gt;

&lt;h4 id=&quot;toc_256&quot;&gt;Setup Rails&lt;/h4&gt;

&lt;p&gt;Now that we fetched some static files, they must be loaded through Rails&#39;
asset-pipeline.  Since we installed those files under
&lt;code&gt;vendor/assets/components&lt;/code&gt;, we need to add a line to &lt;code&gt;config/application.rb&lt;/code&gt; to
add the directory to our assets path:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;assets&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;paths&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Rails&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;vendor&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;assets&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;components&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;(Don&#39;t forget to restart your Rails server after this one.)&lt;/p&gt;

&lt;p&gt;Your assets are now ready for consumption.  Sprockets will happily load them…&lt;/p&gt;

&lt;p&gt;But there&#39;s a catch: unless you&#39;re running the latest release of Sprockets
(starting at &lt;code&gt;~&amp;gt; 2.6&lt;/code&gt;) you can &lt;em&gt;not&lt;/em&gt; require jQuery by applying the usual &lt;code&gt;//=
require jquery&lt;/code&gt;. Instead, you have to &lt;code&gt;//= require jquery/jquery&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Why is that? Well, Bower stores the libraries where you tell him, under neatly
ordered directories.  Bower also expects the library to come with his own
&lt;code&gt;component.json&lt;/code&gt; to describe itself: name, authors, version, etc.  More
importantly in our case, this file &lt;em&gt;should&lt;/em&gt; point to an entry point.  In
jQuery&#39;s case, you will have to require the library with &lt;code&gt;//= require
jquery/jquery&lt;/code&gt;.  Meh.&lt;/p&gt;

&lt;p&gt;In fact, you &lt;em&gt;may&lt;/em&gt; be left on your own to have a look a each component&#39;s
directory in order to &lt;code&gt;require&lt;/code&gt; the appropriate file; that is, unless you&#39;re
running a &quot;recent&quot; release of Sprockets that will do just that for you (hang in
there, Rails 4 is coming).  Did I mention how much I love Sprockets?&lt;/p&gt;

&lt;h4 id=&quot;toc_257&quot;&gt;Setup your VCS&lt;/h4&gt;

&lt;p&gt;Ignoring the &lt;code&gt;vendor/assets/components&lt;/code&gt; directory is a good idea since you
don&#39;t want to commit more than your &lt;code&gt;components.json&lt;/code&gt; file.  If you&#39;re using
Git, the following should do the trick:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;$ mkdir vendor/assets/components
$ touch vendor/assets/components/.gitkeep
$ git add vendor/assets/components/.gitkeep
$ echo /vendor/assets/components &amp;gt;&amp;gt; .gitignore
$ git add .gitignore
$ git commit -m &amp;#39;Setup bower components directory&amp;#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;And that&#39;s all there is to it.&lt;/p&gt;

&lt;h3 id=&quot;toc_258&quot;&gt;Using the bower-rails gem&lt;/h3&gt;

&lt;p&gt;Why, of course there &lt;em&gt;is&lt;/em&gt; a gem that does all the tedious work for you.  And
it&#39;s quite simple too.&lt;/p&gt;

&lt;p&gt;Ross Harrison&#39;s &lt;a href=&quot;https://github.com/rharriso/bower-rails/&quot;&gt;bower-rails&lt;/a&gt; adds two rake tasks to read a
list of components from a &lt;code&gt;bower.json&lt;/code&gt; file.  Those are then installed under
&lt;code&gt;vendor/assets/javascripts/&lt;/code&gt;, or &lt;code&gt;lib/assets/javascripts&lt;/code&gt; directories.  The
naming is a bit off when/if you&#39;re installing things like Twitter Bootstrap,
that contain stylesheets, but in the sake of simplicity let&#39;s ignore this for
now.&lt;/p&gt;

&lt;p&gt;Here is a sample &lt;code&gt;bower.json&lt;/code&gt; file straight from the project&#39;s README:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;{
    &amp;quot;lib&amp;quot;: {
        &amp;quot;dependencies&amp;quot;: {
            &amp;quot;threex&amp;quot;      : &amp;quot;git@github.com:rharriso/threex.git&amp;quot;,
            &amp;quot;gsvpano.js&amp;quot;  : &amp;quot;https://github.com/rharriso/GSVPano.js/blob/master/src/GSVPano.js&amp;quot;
        }
    },
    &amp;quot;vendor&amp;quot;: {
        &amp;quot;dependencies&amp;quot;: {
            &amp;quot;three.js&amp;quot;  : &amp;quot;https://raw.github.com/mrdoob/three.js/master/build/three.js&amp;quot;
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;What the gem really does is &lt;code&gt;chdir&lt;/code&gt; here and there, rewrite this JSON to a
valid Bower format, and exec &lt;code&gt;bower install&lt;/code&gt;.  It&#39;s easy as pie, and painless
for Ruby developers.&lt;/p&gt;

&lt;h2 id=&quot;toc_259&quot;&gt;Wrapping up&lt;/h2&gt;

&lt;p&gt;Although I really like Javascript (and its bizarre quirks), I don&#39;t like to add
heterogeneous tools to a developer&#39;s environment when it can be avoided:
increased complexity, and maintenance, are not helping your productivity.  I
won&#39;t argue in favor or against &lt;a href=&quot;http://nodejs.org&quot;&gt;nodejs&lt;/a&gt; here.  However I doubt you prefer
downloading files into &lt;code&gt;vendor/&lt;/code&gt;, over having a program do the job better that
you would.  Bower is simply too good to ignore.&amp;nbsp;:)&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title type="html">Les défis du développement des single page webapps</title>
   <link href="http://dev.af83.com/2012/12/18/defis-single-page-webapp.html"/>
   <updated>2012-12-18T00:00:00+01:00</updated>
   <id>http://dev.af83.com/2012/12/18/defis-single-page-webapp</id>
   <author><name>Bruno Michel</name><email>contact@af83.com</email></author>
   <content type="html">&lt;p&gt;Les &lt;em&gt;single page webapps&lt;/em&gt;, vous savez ces petites applications écrites
totalement en HTML5, JavaScript et CSS3, sont à la mode. Elles permettent
d&#39;offrir une expérience utilisateur optimale, sans la lenteur des changements
de page. Mais pour ça, encore faut-il qu&#39;elles soient développées dans les
règles de l&#39;art.&lt;/p&gt;

&lt;p&gt;Cet article vise à montrer quels sont les défis que l&#39;on rencontre lors du
développement de telles applications et présente comment, chez af83, nous y
répondons.&lt;/p&gt;

&lt;h2 id=&quot;toc_246&quot;&gt;La façon naïve de développer une &lt;em&gt;single-page webapp&lt;/em&gt;&lt;/h2&gt;

&lt;p&gt;Un développeur expérimenté dans les sites web mais qui se lance pour la
première fois dans une &lt;em&gt;single page webapp&lt;/em&gt; sera tenté de faire comme à son
habitude&amp;nbsp;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;utiliser jQuery&lt;/li&gt;
&lt;li&gt;sélectionner des plugins jQuery pour chaque fonctionnalité&lt;/li&gt;
&lt;li&gt;vérifier rapidement que ces plugins sont d&#39;une qualité suffisante&lt;/li&gt;
&lt;li&gt;écrire un peu de code pour faire la glue entre tout ça.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Et, au début, ça ne va pas trop mal marcher. Oh, bien sûr, il y aura quelques
bugs par-ci par-là, mais rien de bien méchant. Comme pour les sites web,
certains plugins vont se marcher sur les pieds et il faudra corriger ça. Mais, 
pour notre développeur, cela reste du domaine connu.&lt;/p&gt;

&lt;p&gt;Pourtant, au fur et à mesure qu&#39;il va continuer à avancer, cette situation va
vite se dégrader. Notre développeur va rencontrer de plus en plus de bugs. Et
il passera plus de temps sur la correction de bugs, il avancera moins vite sur
les fonctionnalités.&lt;/p&gt;

&lt;p&gt;Puis, il va arriver à un point où il va devoir commencer à réécrire certains
plugins jQuery pour réussir à corriger les bugs qu&#39;il rencontre et continuer à
avancer. Comme si ce n&#39;était pas assez compliqué, notre développeur se rend
également compte que les performances de son application se dégradent
rapidement&amp;nbsp;: ça devient moins fluide, le temps de chargement initial
s&#39;allonge. Mais comme il n&#39;a pas le temps d&#39;optimiser ça, il cache la misère
en rajoutant des loaders.&lt;/p&gt;

&lt;p&gt;Et le pire finit par arriver. Notre développeur n&#39;arrive plus à s&#39;en sortir
dans son code&amp;nbsp;: il ne comprend plus comment ça marche. Chaque modification ou
nouvelle fonctionnalité entraîne des tas de nouveaux bugs. Même la correction
d&#39;un bug fait apparaître de nouveaux bugs.&lt;/p&gt;

&lt;p&gt;Malgré tous ces efforts, l&#39;application est lente et buggée et les utilisateurs
ne sont donc pas au rendez-vous. Si vous en arrivez à ce point, il ne vous
reste plus qu&#39;une solution&amp;nbsp;: vous accrocher à l&#39;espoir d&#39;une V2.&lt;/p&gt;

&lt;p&gt;Mais quelles sont les clés pour comprendre cet échec&amp;nbsp;? Nous pouvons isoler 3
grandes limitations de cette approche&amp;nbsp;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Le développement d&#39;une telle application doit être maîtrisé et structuré,
or les plugins jQuery rendent très difficiles la mise en place d&#39;une telle
structure.&lt;/li&gt;
&lt;li&gt;Il est crucial de prendre en compte les performances, et tout
particulièrement dans le contexte de pages qui restent longtemps ouvertes.&lt;/li&gt;
&lt;li&gt;L&#39;absence d&#39;outils fait perdre beaucoup de temps au final.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Voyons plus en détails ces 3 défis.&lt;/p&gt;

&lt;h2 id=&quot;toc_247&quot;&gt;Structure et maîtrise&lt;/h2&gt;

&lt;p&gt;Comme pour toute application, le développement sur le long-terme se passe
d&#39;autant mieux quand il est maîtrisé, c&#39;est-à-dire quand les développeurs
arrivent facilement à comprendre quels seront les effets des modifications
qu&#39;ils apportent mais également quand il est facile pour un développeur
externe de rentrer sur le projet.&lt;/p&gt;

&lt;p&gt;L&#39;agglomération de plugins jQuery est problématique de ce point de vue, car,
ils se comportent comme des boîtes noires mais surtout leurs interfaces sont
très limitées. Le code qui fait la glue entre ces éléments se retrouve alors
très fragile car il oblige à avoir un couplage fort entre les plugins.&lt;/p&gt;

&lt;p&gt;Pourtant, il n&#39;est pas si difficile de structurer le code d&#39;une application
JavaScript. Les principes sont d&#39;ailleurs très similaires à ceux des
applications web classique ou desktop&amp;nbsp;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Utilisation d&#39;un framework MVC (chez af83, nous avons une préférence pour
&lt;a href=&quot;http://backbonejs.org&quot;&gt;Backbone&lt;/a&gt; mais &lt;a href=&quot;http://angularjs.org/&quot;&gt;AngularJS&lt;/a&gt;
ou &lt;a href=&quot;http://emberjs.com/&quot;&gt;Ember&lt;/a&gt; sont de très bonnes factures également)&lt;/li&gt;
&lt;li&gt;Respect de conventions de codage (&lt;a href=&quot;http://www.jshint.com/&quot;&gt;jshint&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Séparation du code en plusieurs fichiers avec une classe par fichier (nous
utilisons les classes fournies par &lt;a href=&quot;http://coffeescript.org/&quot;&gt;CoffeeScript&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Emploi de templates pour le code HTML généré (avec
&lt;a href=&quot;http://handlebarsjs.com/&quot;&gt;handlebars&lt;/a&gt; ou &lt;a href=&quot;http://jade-lang.com/&quot;&gt;jade&lt;/a&gt; par
exemple)&lt;/li&gt;
&lt;li&gt;Utilisation d&#39;événements/signaux au couplage fort entre composants (avec
Backbone, cela vient naturellement via le module
&lt;a href=&quot;http://backbonejs.org/#Events&quot;&gt;Events&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;toc_248&quot;&gt;Performances et optimisations&lt;/h2&gt;

&lt;p&gt;Le deuxième défi des &lt;em&gt;single page webapps&lt;/em&gt; est le coté performances. Cela
couvre beaucoup d&#39;aspects&amp;nbsp;: temps de chargement, fluidité des animations,
réactivité, endurance, etc.&lt;/p&gt;

&lt;p&gt;J&#39;aurais beaucoup à dire sur chacun de ces points mais globalement l&#39;approche
est toujours la même. On commence par se fixer des objectifs, idéalement de
manière formelle mais, dans la pratique, c&#39;est souvent un ressenti assez
subjectif qui sera le déclencheur. Si un de ces objectifs n&#39;est pas atteint,
on va s&#39;appliquer à améliorer ça. Mais avant tout changement, il convient de
mesurer pour détecter où le bât blesse. Les optimisations en aveugle sont
souvent inefficaces et on fait perdre beaucoup de temps. Donc, surtout, avant
de commencer à optimiser un point, il faut être confiant que ce point entre
bien en compte dans notre objectif. Enfin, il ne reste plus qu&#39;à optimiser et
vérifier que l&#39;on s&#39;est bien rapproché de notre objectif.&lt;/p&gt;

&lt;p&gt;Je pourrais entrer plus dans les détails mais cette méthode est très
classique et je ne pense pas que cela apporterait grand chose.&lt;/p&gt;

&lt;p&gt;Par contre, je souhaite parler d&#39;un point un peu particulier qui est souvent
négligé&amp;nbsp;: ces webapps sont souvent utilisées pendant une longue période de
temps sans rechargement et cela a un fort impact sur les performances.&lt;/p&gt;

&lt;p&gt;En effet, le nombre d&#39;objets JavaScript, de nœuds dans le DOM, de &lt;em&gt;listeners&lt;/em&gt;
d&#39;événements, etc. a tendance à grossir et à consommer beaucoup de mémoire, au
point de rendre la webapp très lente.&lt;/p&gt;

&lt;p&gt;Par exemple, Google a montré que &lt;a href=&quot;https://docs.google.com/a/google.com/presentation/d/1wUVmf78gG-ra5aOxvTfYdiLkdGaR9OhXRnOlIcEmu2s/pub?start=false&amp;amp;loop=false&amp;amp;delayms=3000#slide=id.g1d65bdf6_0_0&quot;&gt;Gmail pouvait facilement prendre plusieurs Go
de mémoire
vive&lt;/a&gt;
et a expliqué les optimisations qu&#39;ils ont mises en place pour réduire ce
gouffre en termes de performances.&lt;/p&gt;

&lt;p&gt;Pour les objets JavaScript, les &lt;em&gt;Garbage collectors&lt;/em&gt; des navigateurs ont fait
de grand progrès ces derniers temps. En respectant quelques principes, comme
éviter de créer des objets inutiles dans des boucles, il y a peu de surprises.&lt;/p&gt;

&lt;p&gt;Plus difficile, la gestion des nœuds du DOM et des &lt;em&gt;listeners&lt;/em&gt; associés a un
impact plus conséquent et est plus difficile à maîtriser. Il convient de
faire particulièrement attention à ne pas &lt;em&gt;leaker&lt;/em&gt; des fragments de DOM. Pour
des pages web que l&#39;on recharge régulièrement, le problème passe inaperçu mais
sur une webapp qui reste ouverte pendant quelques dizaines minutes, cela peut
ralentir très fortement les navigateurs.&lt;/p&gt;

&lt;p&gt;Jusqu&#39;à récemment, le «&amp;nbsp;ménage&amp;nbsp;» de ces éléments avec Backbone devait se faire
manuellement. Heureusement, un grand travail a été effectué ces derniers mois
et la version 0.9.9 permet d&#39;en récolter les fruits. La gestion de la mémoire
s&#39;en trouve grandement simplifiée si l&#39;on respecte les &lt;em&gt;best practices&lt;/em&gt; de
Backbone. Il reste des cas où l&#39;expertise d&#39;un dév front confirmé reste
nécessaire, mais ces cas restent très rares.&lt;/p&gt;

&lt;h2 id=&quot;toc_249&quot;&gt;Sans outils, point de salut&lt;/h2&gt;

&lt;p&gt;J&#39;ai déjà cité pas mal d&#39;outils ci-dessus&amp;nbsp;: Backbone, CoffeeScript,
Handlebars, etc. Mais, je vais insister sur ce point.&lt;/p&gt;

&lt;p&gt;Pour construire un site web avec quelques effets JavaScript, on pouvait
facilement s&#39;en sortir en faisant tout manuellement ou avec quelques scripts
maison. Mais, comme pour les applications web coté serveur, c&#39;est
l&#39;utilisation de frameworks, outils et bibliothèques qui a permis de passer à
la vitesse supérieure. Grâce à eux, nous avons pu gagner fortement en vélocité
et nous attaquer à des projets bien plus complexes.&lt;/p&gt;

&lt;p&gt;Le même cheminement est valable pour les applications coté client. Cela peut
faire peur aux nouveaux venus dans ce domaine car la barrière à l&#39;entrée est
plus importante. Mais c&#39;est un fonctionnement indispensable pour réussir des
projets plus conséquents.&lt;/p&gt;

&lt;p&gt;Un de ces outils est &lt;a href=&quot;http://gruntjs.com/&quot;&gt;grunt&lt;/a&gt;. C&#39;est une sorte de
&lt;code&gt;Makefile&lt;/code&gt; pour le front dev. Il vient avec de nombreuses extensions pour
compiler des fichiers CoffeeScript ou Sass, concaténer des fichiers, réduire
le poids des fichiers générés, lancer des tests, etc. Sans lui, il faudrait
faire toutes ces tâches manuellement (ou avec des scripts maison), ce qui
serait une grosse perte de temps et peut conduire à introduire des bugs dans
ce processus.&lt;/p&gt;

&lt;p&gt;Autre exemple, &lt;a href=&quot;http://twitter.github.com/bower/&quot;&gt;Bower&lt;/a&gt;. C&#39;est un outil qui
permet d&#39;installer facilement des bibliothèques CSS et JS et d&#39;en gérer les
mises à jour. Pour un site web, on peut facilement s&#39;en passer&amp;nbsp;: on va sur le
site web de chaque bibliothèque, on regarde ce qu&#39;elle fait et si ça nous
convient, on télécharge le code et on le met quelque part.&lt;/p&gt;

&lt;p&gt;Pour une application, c&#39;est plus problématique. D&#39;une part, le nombre de
bibliothèques utilisées est plus important. D&#39;autre part, ces bibliothèques
sont plus complexes et ont souvent des dépendances. On se retrouve alors à
devoir jongler entre les versions pour trouver un ensemble cohérent.&lt;/p&gt;

&lt;p&gt;Puis, vient le problème des mises à jour. Quand on veut mettre à jour une
bibliothèque, il faut retrouver où on l&#39;avait téléchargée, quelles sont ses
dépendances, etc. Ce n&#39;est pas forcément très compliqué mais on peut vite y
perdre pas mal de temps.&lt;/p&gt;

&lt;p&gt;Avec bower, la liste des bibliothèques est déclarée dans un fichier
&lt;code&gt;component.json&lt;/code&gt;, avec la version utilisée. En une ligne de commande, on peut
mettre à jour une bibliothèque ou en installer une nouvelle.&lt;/p&gt;

&lt;p&gt;Bien entendu, je pourrais continuer à lister d&#39;autres outils (intégration
continue, scripts de déploiement, couverture de code…) mais je pense que
vous avez compris l&#39;idée&amp;nbsp;!&lt;/p&gt;

&lt;h2 id=&quot;toc_250&quot;&gt;En deux mots&lt;/h2&gt;

&lt;p&gt;Le développement front a souvent été considéré comme étant plus facile que le
développement back. Je pense que cette époque est révolue et que les &lt;em&gt;single
page webapps&lt;/em&gt; sont au moins aussi complexes que les applications plus
classiques. Pour les réussir, il convient donc de changer d&#39;état d&#39;esprit et
réussir à transposer les clés de la réussite des applications web classiques&amp;nbsp;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Utiliser un framework pour structurer son code&lt;/li&gt;
&lt;li&gt;Écrire des tests&lt;/li&gt;
&lt;li&gt;Sélectionner un ensemble efficace d&#39;outils&lt;/li&gt;
&lt;li&gt;Se fixer des objectifs de performances, les mesurer et optimiser lorsque
c&#39;est nécessaire&lt;/li&gt;
&lt;li&gt;S&#39;appuyer sur des développeurs expérimentés pour poser le cœur de
l&#39;application.&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title type="html">API Days</title>
   <link href="http://dev.af83.com/2012/12/17/apidays.html"/>
   <updated>2012-12-17T00:00:00+01:00</updated>
   <id>http://dev.af83.com/2012/12/17/apidays</id>
   <author><name>Alice</name><email>contact@af83.com</email></author>
   <content type="html">&lt;p&gt;Il y a quelques jours se sont déroulées les API Days, organisés par Fabernovel et Webshell. Les conférences ont
couvert un large spectre des API, d&#39;un point de vue à la fois technique et
commercial. Cet évènement a aussi permis de démontrer le potentiel des API en
termes d&#39;usages&amp;nbsp;: en ramenant de la transversalité entre les sources de
données, les API permettent de créer des services plus proches des parcours
d&#39;usages réels des personnes.&lt;/p&gt;

&lt;p&gt;Certains exemples au succès avéré revenaient régulièrement&amp;nbsp;: Netflix, Shopify,
Amazon, Facebook, etc. Mais les API ouvrent des opportunités dans de nombreux
autres secteurs, comme par exemple le journalisme. Plusieurs médias étaient
d&#39;ailleurs présents (France Télévision, L&#39;Express, Le Monde, Rue89, Les Échos)
pour expliquer leurs positionnements sur le sujet.&lt;/p&gt;

&lt;p&gt;Voici 3 aspects des API, abordés à travers 3 conférences, qui m&#39;ont
particulièrement intéressée.&lt;/p&gt;

&lt;h2 id=&quot;toc_242&quot;&gt;Les API dans l&#39;histoire du web&lt;/h2&gt;

&lt;p&gt;Dans sa conférence &quot;&lt;em&gt;Future Interface: What the last 50+ years of modern
computing history may tell us about the future&lt;/em&gt;&quot;, Mike Amundsen (Layer7) balaie
les 50 dernières années de l&#39;histoire du web et ses différents acteurs pour
remettre en perspective les enjeux des API.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;En 1945, Vannevar Bush tente déjà de relier les informations des humains à
distance au moyen de la machine qu&#39;il avait conçue, le Memex.&lt;/li&gt;
&lt;li&gt;En 1963, Ted Nelson poursuit la réflexion de V.Bush et décrit plus précisément le
fonctionnement de ces liens. Il invente la notion d&#39;hypertexte.&lt;/li&gt;
&lt;li&gt;A la même époque, Douglas Engelbart met au point le hardware qui permet de
faire réellement fonctionner et d&#39;incarner ce réseau de liens.&lt;/li&gt;
&lt;li&gt;Puis en 1965, Christopher Alexander identifie les patterns pour penser et
agir dans ce réseau (notions de maillage et de noeuds plutôt que
d&#39;arborescence).&lt;/li&gt;
&lt;li&gt;Dans les années 90, Tim Berners Lee part des hypertext de T.Nelson et développe le HyperText Transfert Protocol (HTTP)&lt;/li&gt;
&lt;li&gt;Roy T. Fielding construit ensuite les nouveaux systèmes basés sur ces
patterns (architecture REST).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Plus récemment, M. Amundsen cite&amp;nbsp;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Github qui donne une nouvelle envergure au Memex de Vannevar Bush en rendant
effectivement possible des interactions collaboratives à distance (de temps
et d&#39;espace).&lt;/li&gt;
&lt;li&gt;Ryan Dahl a également contribué à traiter la latence en créant NodeJS.&lt;/li&gt;
&lt;li&gt;Enfin Eric Schweikardt a poursuivi la réflexion en concevant des systèmes
qui accompagnent et stimulent les comportements émergents, à travers son
projet Cubelets.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;En s&#39;appuyant sur ce bref historique, M. Amundsen démontre que le web tend
vers les mêmes objectifs depuis le début&amp;nbsp;: des briques faciles à combiner, un
système capable d&#39;opérer de façon largement distributive. Tout cela dans le
but d&#39;augmenter les capacités intellectuelles de l&#39;homme. Les API se
positionnent dans la suite logique de cette évolution.&lt;/p&gt;

&lt;h2 id=&quot;toc_243&quot;&gt;API et internet des objets&amp;nbsp;: vers une API unique&amp;nbsp;?&lt;/h2&gt;

&lt;p&gt;Dans &quot;&lt;em&gt;API and ubiquity&lt;/em&gt;&quot;, François Daoust (Joshfire) explore les enjeux des API
liés à l&#39;Internet des objets.&lt;/p&gt;

&lt;p&gt;Le fait que les objets deviennent &quot;connectés&quot; requière que l&#39;utilisateur
puisse accéder au contenu sur n&#39;importe quel device, quel qu&#39;il soit. Cela
implique notamment de pouvoir dissocier le contenu du contenant (le js des
données par exemple), d&#39;être &quot;&lt;em&gt;provider agnostic&lt;/em&gt;&quot; autant que possible, et de
privilégier l&#39;exécution côté client.&lt;/p&gt;

&lt;p&gt;Il y a néanmoins deux problèmes majeurs&amp;nbsp;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;chaque fournisseur de contenu définit sa propre API, souvent propriétaire&lt;/li&gt;
&lt;li&gt;chaque fournisseur de contenu définit aussi sa propre structure de réponse
(xml ou json par exemple, avec un vocabulaire propre)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;L&#39;enjeu est donc d&#39;aller vers une seule API REST &lt;em&gt;read/write&lt;/em&gt; pour tout, avec
un vocabulaire et une syntaxe commune pour décrire les objets web.&lt;/p&gt;

&lt;p&gt;F. Daoust propose pour cela d&#39;utiliser &lt;a href=&quot;http://json-ld.org/&quot;&gt;json-ld&lt;/a&gt; (&quot;ld&quot;
signifie linking data). Ce format vise à utiliser un seul nom pour chaque
chose, en définissant des types comme &lt;code&gt;schema&lt;/code&gt;, &lt;code&gt;person&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt;, etc. Cela
permet ensuite d&#39;effectuer une conversion automatique entre les contextes,
sans bouleverser les méthodes de développement.&lt;/p&gt;

&lt;p&gt;Actuellement, la syntaxe de json-ld est stable, l&#39;API est en cours de
finalisation. Elle est notamment utilisée sur Joshfire Factory, l&#39;outil de
développement d&#39;application créé par Joshfire.&lt;/p&gt;

&lt;h2 id=&quot;toc_244&quot;&gt;API et open source&lt;/h2&gt;

&lt;p&gt;Dans sa conférence &quot;&lt;em&gt;Why open&lt;/em&gt;&quot;, S. Klabnik s&#39;appuie sur les concepts de Gilles
Deleuze pour penser les enjeux open source liés aux API.&lt;/p&gt;

&lt;p&gt;Il propose ainsi qu&#39;Internet, de même que les entreprises, ne sont pas des
entités définies et fermées, mais au contraire des agencements d&#39;éléments
divers. Ces agencements sont en constant rééquilibrage&amp;nbsp;: telle entreprise en
rachète une autre, intègre ses composants et redéfinit ainsi son propre
périmètre d&#39;actions et d&#39;acteurs. C&#39;est ce que Deleuze nomme la
dé-territorialisation et la re-territorialisation.&lt;/p&gt;

&lt;p&gt;Les API exacerbent ces processus d&#39;agencement et de &quot;déterritorialisation&quot;&amp;nbsp;:
des sociétés de tout secteur vont utiliser l&#39;API de Facebook, ainsi vont-elle
bouleverser leur périmètre actuel (dé-territorialisation) pour intégrer les
possibilité de cette API et définir un nouveau périmètre de fonctions,
d&#39;usages (re-territorialisation).&lt;/p&gt;

&lt;p&gt;Cela crée un important enjeu industriel et économique&amp;nbsp;: la plupart des
entreprises souhaitent mettre en place des API qui valorisent leurs données et
diffusent leurs services, mais craignent de perdre leur travail en ouvrant
trop ces API. C&#39;est le cas par exemple de Twitter qui entend partager son API
tout en contrôlant son utilisation/accès.&lt;/p&gt;

&lt;p&gt;Le problème, explique S. Klabnik, c&#39;est qu&#39;on ne peut pas partager quelque
chose et en même temps vouloir le contrôler. En ouvrant son API et en
permettant aux gens de participer au développement de nouvelles
fonctionnalités/contenus, l&#39;entreprise évolue mieux et plus rapidement, et les
utilisateurs sont d&#39;avantage impliqués dans le service.&lt;/p&gt;

&lt;h2 id=&quot;toc_245&quot;&gt;Pour conclure&lt;/h2&gt;

&lt;p&gt;Ces conférences ne représentent donc que 3 aspects des API. De nombreux autres aspects ont été abordés, tels que le temps réel (au sujet desquels Bruno Michel, notre CTO, a d&#39;ailleurs fait une présentation intitulée &quot;Welcome to the evented age&quot;), l&#39;hypermédia, la valeur commerciale des API, &quot;l&#39;évangélisation&quot; que cela implique dans les entreprises, etc. Le sujet est donc vaste… Vivement la prochaine édition&amp;nbsp;! &lt;/p&gt;

&lt;p&gt;Pour en savoir plus&amp;nbsp;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://fr.slideshare.net/faberNovel/6-reasons-why-apis-are-reshaping-your-business&quot;&gt;L&#39;étude de Fabernovel &quot;6 reasons why APIs are reshaping your business&quot;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://apidays.io&quot;&gt;Le site web de l&#39;évènement&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.youtube.com/watch?v=nf7-pFyKhiw&amp;amp;feature=youtu.be&quot;&gt;Les retours en vidéo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;@apidays2012&quot;&gt;Et sur Twitter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title type="html">Ruby 2.0 : Enumerator::Lazy</title>
   <link href="http://dev.af83.com/2012/11/22/ruby-2-0-enumerator-lazy.html"/>
   <updated>2012-11-22T00:00:00+01:00</updated>
   <id>http://dev.af83.com/2012/11/22/ruby-2-0-enumerator-lazy</id>
   <author><name>chatgris</name><email>contact@af83.com</email></author>
   <content type="html">&lt;p&gt;With the release of a first preview during &lt;a href=&quot;http://rubyconf.org/&quot;&gt;RubyConf
2012&lt;/a&gt;, the release of Ruby 2.0 is getting closer.&lt;/p&gt;

&lt;p&gt;After
&lt;a href=&quot;http://dev.af83.com/2012/10/19/ruby-2-0-module-prepend.html&quot;&gt;Module#prepend&lt;/a&gt;,
&lt;a href=&quot;http://dev.af83.com/2012/11/05/ruby-2-0-module-refine.html&quot;&gt;Module#refine&lt;/a&gt;, let&#39;s talk about
&lt;a href=&quot;http://www.ruby-doc.org/core-2.0/Enumerator/Lazy.html&quot;&gt;Enumerator::Lazy&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;toc_239&quot;&gt;Chainable iteration&lt;/h2&gt;

&lt;p&gt;Given this nonsensical example:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;hashes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:even?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:to_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;This code does the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;keeps only even numbers&lt;/li&gt;
&lt;li&gt;fetches their internal hash&lt;/li&gt;
&lt;li&gt;transforms those hash in String&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But it also creates a intermediate array for each block, and iterates several
times.&lt;/p&gt;

&lt;p&gt;That can be done in one iteration:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;hashes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;accumulator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;even?&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;accumulator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_s&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;accumulator&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Let&#39;s face the truth: the code is less readable.&lt;/p&gt;

&lt;h2 id=&quot;toc_240&quot;&gt;Enumerator::Lazy&lt;/h2&gt;

&lt;p&gt;Here comes the laziness.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;hashes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lazy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:even?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:to_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;When &lt;code&gt;to_a&lt;/code&gt; is called, the code is evaluated. Internally, Ruby builds a specific
block: no intermediate arrays are created and only one iteration occurs.&lt;/p&gt;

&lt;p&gt;Without calling &lt;code&gt;to_a&lt;/code&gt; (which is an alias to the &lt;code&gt;force&lt;/code&gt; method), it returns a
Enumerator#Lazy object.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;#&amp;lt;Enumerator::Lazy: #&amp;lt;Enumerator::Lazy: #&amp;lt;Enumerator::Lazy: #&amp;lt;Enumerator::Lazy:&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10000&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:select&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;h2 id=&quot;toc_241&quot;&gt;Benchmarking&lt;/h2&gt;

&lt;p&gt;Since there is only one iteration, it should be faster. Well, let&#39;s run some
benchmarks first.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;benchmark&amp;#39;&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1000000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10000000&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;Benchmark&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bm&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;report&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;chainable &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;hashes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;.size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:even?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:to_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;no&quot;&gt;Benchmark&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bm&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;report&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;one iteration &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;hashes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;.size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;accumulator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;even?&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;accumulator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_s&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;accumulator&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;no&quot;&gt;Benchmark&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bm&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;report&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;chainable lazy &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;hashes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;.size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lazy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:even?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:to_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_a&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;So, Enumerator#Lazy seems to be the slowest in every case. According to a &lt;a href=&quot;http://bugs.ruby-lang.org/issues/6183&quot;&gt;bug
report&lt;/a&gt;, the cost of block creation for
laziness is bigger than its gain. That being said, those benchmarks need to be
rerun when Ruby 2.0 will be released.&lt;/p&gt;

&lt;p&gt;As pointed out in this bug report, there are some cases where Enumerator#Lazy
is definitely the best choice you can make. For example, you can use it when
extracting elements from a huge, or even infinite enumerator.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;Prime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;take&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;This code iterates on all prime numbers before doing a select, then a take.
However, it will iterates indefinitely and will never do the select nor the
take.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;Prime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;next&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;This code would do the job, but is not easily readable.&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;lazy&lt;/code&gt;, we can do:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;Prime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lazy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;take&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;This would return immediately, and provide a good readability.&lt;/p&gt;

&lt;p&gt;Coming next in this series: Named arguments.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title type="html">Release: gaston, a configuration store for Ruby</title>
   <link href="http://dev.af83.com/2012/11/16/release-gaston-a-configuration-store-for-ruby.html"/>
   <updated>2012-11-16T00:00:00+01:00</updated>
   <id>http://dev.af83.com/2012/11/16/release-gaston-a-configuration-store-for-ruby</id>
   <author><name>chatgris</name><email>contact@af83.com</email></author>
   <content type="html">&lt;p&gt;Gaston is a store configuration that can be used in any Ruby project, it was
released a bit more than year ago. We use it on most of our Ruby projects but
Gaston didn&#39;t have the honours of a blog post yet.&lt;/p&gt;

&lt;h3 id=&quot;toc_236&quot;&gt;Installation&lt;/h3&gt;

&lt;p&gt;Ruby 1.9.2 is required.&lt;/p&gt;

&lt;p&gt;Install it with rubygems:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;gem install gaston
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;With bundler, add it to your &lt;code&gt;Gemfile&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;gaston&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;h3 id=&quot;toc_237&quot;&gt;Environment&lt;/h3&gt;

&lt;p&gt;Let&#39;s take a look at this yaml file containing some configuration values.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;yaml&quot;&gt;&lt;span class=&quot;l-Scalar-Plain&quot;&gt;:gaston&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;l-Scalar-Plain&quot;&gt;:api&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;:state&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;awesome&amp;quot;&lt;/span&gt;
&lt;span class=&quot;l-Scalar-Plain&quot;&gt;:development&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;l-Scalar-Plain&quot;&gt;:api&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;:token&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;api_token&amp;quot;&lt;/span&gt;
&lt;span class=&quot;l-Scalar-Plain&quot;&gt;:test&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;l-Scalar-Plain&quot;&gt;:api&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;l-Scalar-Plain&quot;&gt;:token&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;&amp;lt;%= ENV[&amp;quot;API_TOKEN&amp;quot;] %&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Gaston allows to specify different values depending on the environment. The
&lt;code&gt;gaston&lt;/code&gt; environment represents the default values that all environments
inherit, unless a given value is overwritten in a specific environment.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;development&lt;/code&gt; environment, calling &lt;code&gt;Gaston.api&lt;/code&gt; will yield the following
hash:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&amp;quot;state&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;awesome&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&amp;quot;token&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;api_token&amp;quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;In &lt;code&gt;test&lt;/code&gt; environment (with the Environment variable set to
&quot;269596961710045034&quot;), calling &lt;code&gt;Gaston.api&lt;/code&gt; will yield the following hash:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&amp;quot;state&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;awesome&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&amp;quot;token&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;269596961710045034&amp;quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;This example also shows that gaston accepts Ruby code as a value through ERB
templating.&lt;/p&gt;

&lt;p&gt;Gaston also accepts json files:&lt;/p&gt;

&lt;p&gt;The same rules apply here.&lt;/p&gt;

&lt;p&gt;A small setup is required to use Gaston. You can define an environment with the
&lt;code&gt;env&lt;/code&gt; method and specify config files with the &lt;code&gt;files&lt;/code&gt; method. Default &lt;code&gt;env&lt;/code&gt; is
&lt;code&gt;:development&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;gaston&amp;#39;&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;Gaston&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;configure&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gaston&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;gaston&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;env&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ENV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;ENV&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;gaston&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;files&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Dir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;*.yml&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;*.json&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;Gaston&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;api&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; {:state=&amp;gt;&amp;quot;awesome&amp;quot;, :token=&amp;gt;&amp;quot;api_token&amp;quot;}&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;Gaston&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hostname&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &amp;quot;dev.af83.com&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;h3 id=&quot;toc_238&quot;&gt;One last thing&lt;/h3&gt;

&lt;p&gt;At its core, Gaston inherits from the Ruby core class &lt;code&gt;Hash&lt;/code&gt;. A Gaston store
give access to all the &lt;a href=&quot;http://www.ruby-doc.org/core-1.9.3/Hash.html&quot;&gt;methods&lt;/a&gt;
defined on the Hash class. So you can use the classic &lt;code&gt;keys&lt;/code&gt;, &lt;code&gt;fetch&lt;/code&gt; methods.
In order to do that, Gaston does not allow key names that are also a method
defined on Hash. In this case, Gaston does not add this part of the
configuration and logs a warning.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title type="html">Ruby 2.0 : Module#refine</title>
   <link href="http://dev.af83.com/2012/11/05/ruby-2-0-module-refine.html"/>
   <updated>2012-11-05T00:00:00+01:00</updated>
   <id>http://dev.af83.com/2012/11/05/ruby-2-0-module-refine</id>
   <author><name>chatgris</name><email>contact@af83.com</email></author>
   <content type="html">&lt;p&gt;We already talked about
&lt;a href=&quot;http://dev.af83.com/2012/10/19/ruby-2-0-module-prepend.html&quot;&gt;Module#prepend&lt;/a&gt; as
one of the new features of the upcoming Ruby 2.0… Today, let&#39;s talk about
refinements. Refinements had landed into trunk, but is actually reviewed. It
could eventually be reverted for performance issues.&lt;/p&gt;

&lt;h2 id=&quot;toc_232&quot;&gt;Why refinements&lt;/h2&gt;

&lt;p&gt;Because &lt;a href=&quot;http://en.wikipedia.org/wiki/Monkey_patch&quot;&gt;Monkey patching&lt;/a&gt;: Monkey
patching is a powerful feature, but as everybody knows, with great power comes
great responsibility. Refinements intend to give you the power of Monkey
patching, but without messing with the whole universe of the Ruby runtime.&lt;/p&gt;

&lt;h2 id=&quot;toc_233&quot;&gt;Module#refine&lt;/h2&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;FooBar&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;refine&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;hello&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; says : Hello, world&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Bar&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;FooBar&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;attr_reader&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:user&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;say&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hello&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;Bar&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;af83&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;say&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;say&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;In the module &lt;code&gt;FooBar&lt;/code&gt;, we use the class method &lt;code&gt;refine&lt;/code&gt; to enhance the class
&lt;code&gt;String&lt;/code&gt;. And in the class &lt;code&gt;Bar&lt;/code&gt;, we declare that we want to use &lt;code&gt;FooBar&lt;/code&gt; with the
&lt;code&gt;using&lt;/code&gt; methods.&lt;/p&gt;

&lt;p&gt;Running this code with Ruby 2.0 outputs the following:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;af83 says : Hello, world
refinements.rb:23:in &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&amp;lt;main&amp;gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;: undefined method `say&amp;#39;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;:String &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;NoMethodError&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;h2 id=&quot;toc_234&quot;&gt;What&#39;s happening here&lt;/h2&gt;

&lt;p&gt;When we call &lt;code&gt;Bar.new(&amp;#39;af83&amp;#39;).say&lt;/code&gt;, the addition of the method &lt;code&gt;hello&lt;/code&gt; on the
class &lt;code&gt;String&lt;/code&gt; is only effective in the context of the &lt;code&gt;Bar&lt;/code&gt; class, thanks to
the use of &lt;code&gt;using FooBar&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;On the contrary, &lt;code&gt;String.new&lt;/code&gt; has no knowledge of the method &lt;code&gt;say&lt;/code&gt;. Hence, the
&lt;code&gt;NoMethodError&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Like I said, safer monkey patching.&amp;nbsp;:)&lt;/p&gt;

&lt;h2 id=&quot;toc_235&quot;&gt;Resource&lt;/h2&gt;

&lt;p&gt;You can read the &lt;a href=&quot;https://bugs.ruby-lang.org/issues/4085&quot;&gt;whole story&lt;/a&gt; of
refinements in Ruby.&lt;/p&gt;

&lt;p&gt;Coming next in this series: Enumerator::Lazy.&lt;/p&gt;
</content>
 </entry>
 

</feed>
