<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"
      xmlns:wfw="http://wellformedweb.org/CommentAPI/"
      xml:lang="fr">
 <title type="html">blog.name.nil? - blog</title>
 <subtitle type="html">blog.name.nil?, le blog de Fabien Jakimowicz</subtitle>
 <link rel="self" type="application/atom+xml" href="http://fabien.jakimowicz.com/blog/index.php/blog/feed" />
 <link rel="alternate" type="text/html" href="http://fabien.jakimowicz.com/blog/index.php/blog" />
 <id>http://fabien.jakimowicz.com/blog/index.php/blog</id>
 <updated>2010-02-12T22:42:23+01:00</updated>
 <rights>Copyright 2010, Fabien Jakimowicz</rights>
 <generator uri="http://zwe.bulix.org" version="v2.6-angela">Zwe v2.6-angela(http://zwe.bulix.org)</generator>
 <author>
  <name>Fabien Jakimowicz</name>
  <email>fabien@jakimowicz.com</email>
 </author>
 
 <entry>
  <id>http://fabien.jakimowicz.com/blog/index.php/blog/45</id>
  <link rel="alternate" type="text/html" href="http://fabien.jakimowicz.com/blog/index.php/blog/45" />
  <title type="html"><![CDATA[db/seeds.rb]]></title>
  <updated>2010-02-12T22:42:23+01:00</updated>
  <author>
   <name>Fabien Jakimowicz</name>
   <email>fabien@jakimowicz.com</email>
  </author>
  <content type="html">
   <![CDATA[<p>
Initialiser une application avec des donn&eacute;es n&eacute;cessaires &agrave; son bon fonctionnement n'&eacute;tait pas vraiment aid&eacute;e par rails et ses normes : faut il cr&eacute;er un script distinct ? utiliser un jeu de fixtures ? un controlleur de configuration de l'application ? une migration ?<br /><br />Depuis <a href="http://ryandaigle.com/articles/2009/5/13/what-s-new-in-edge-rails-database-seeding">l'arriv&eacute;e</a> des <a href="http://github.com/rails/rails/commit/4932f7b38f72104819022abca0c952ba6f9888cb">'seed data'</a>, nous avons une m&eacute;thode normalis&eacute;e rails pour effecter cette t&acirc;che : le fichier <tt>db/seeds.rb</tt> peut &ecirc;tre &eacute;x&eacute;cut&eacute;e via la task <tt>rake db:seed</tt>. En l'instance, il s'agit d'un simple script ruby ex&eacute;cut&eacute; par la rake task. Mais on peut tout de m&ecirc;me en tirer beaucoup, notemment pour g&eacute;rer cela en production.</p>

<div class="cmd">
<pre class="prettyprint">
City.create :name =&gt; &quot;Paris&quot;
City.create :name =&gt; &quot;New-York&quot;
</pre>
</div>
<p></p>
<p>
Apr&egrave;s avoir jou&eacute; quelque peu avec cette commande, on constate qu'elle souffre d'un grand d&eacute;faut : &eacute;tant un script ruby, des ex&eacute;cutions multiples risquent de cr&eacute;er les donn&eacute;es de base &agrave; chaque ex&eacute;cution. Il est toujours plus agr&eacute;able et moins risqu&eacute; de ne pas avoir &agrave; r&eacute;fl&eacute;chir &agrave; l'&eacute;tat ou le contenu de sa base de donn&eacute;es avant d'ex&eacute;cuter une tache. L'id&eacute;e ici est de remplacer les <tt>create</tt> par des <tt>find_or_create</tt> &eacute;vitant de doubler les donn&eacute;es.</p>

<div class="cmd">
<pre class="prettyprint">
%w{Paris New-York}.each {|city_name| City.find_or_create_by_name city_name}
</pre>
</div>
<p></p>
<p>
On peut aussi perfectionner la chose en autorisant la mise &agrave; jour de ces donn&eacute;es primaires avec le script de seeds :</p>

<div class="cmd">
<pre class="prettyprint">
cities = {
&nbsp;&nbsp;&quot;Paris&quot; =&gt; {
&nbsp;&nbsp;&nbsp;&nbsp;:country =&gt; &quot;France&quot;,
&nbsp;&nbsp;&nbsp;&nbsp;:zipcode =&gt; &quot;75000&quot;
&nbsp;&nbsp;},
&nbsp;&nbsp;&quot;New-York&quot; =&gt; {
&nbsp;&nbsp;&nbsp;&nbsp;:country =&gt; &quot;USA&quot;,
&nbsp;&nbsp;&nbsp;&nbsp;:zipcode =&gt; &quot;10001&quot;
&nbsp;&nbsp;}&nbsp;&nbsp;
}

cities.each do |city_name, city_infos|
&nbsp;&nbsp;city = City.find_or_initialize_by_name city_name
&nbsp;&nbsp;city.update_attributes city_infos
end
</pre>
</div>
<p></p>
<p>
Ainsi, &agrave; chaque appel de la rake task, les donn&eacute;es seront soit cr&eacute;es si non pr&eacute;sentes soit mises &agrave; jour, sans avoir &agrave; se pr&eacute;ocuper de l'&eacute;tat de la base.</p>
<p>
Toujours dans l'id&eacute;e de simplifier les choses et minimiser les interventions humaines (et les erreurs potentielles), on peut lancer cette rake task &agrave; chaque d&eacute;ploiement en production : un simple ajout dans le script de d&eacute;ploiement capistrano fait l'affaire.</p>

<div class="cmd">
<pre class="prettyprint">
namespace :deploy do
  namespace :database do
    desc &quot;Load seed data&quot;
    task :seed, :roles =&gt; :db, :only =&gt; { :primary =&gt; true } do
      run &quot;cd #{current_path} &amp;&amp; rake db:seed&quot;
    end
  end
end

after &quot;deploy&quot;, &quot;deploy:database:seed&quot;
</pre>
</div>
<p></p>
<p>
On transforme donc le simple script d'initialisation d'application en outil l&eacute;ger de maintenance de donn&eacute;es syst&egrave;mes, simplifiant le d&eacute;ploiement et le d&eacute;veloppement quotidien.</p>
]]>
  </content>
  <category term="rails" label="rails" />
  <wfw:commentRss>http://fabien.jakimowicz.com/blog/index.php/blog/feed/45/comments</wfw:commentRss>
 </entry>

 <entry>
  <id>http://fabien.jakimowicz.com/blog/index.php/blog/44</id>
  <link rel="alternate" type="text/html" href="http://fabien.jakimowicz.com/blog/index.php/blog/44" />
  <title type="html"><![CDATA[Steve jobs : dancing hero]]></title>
  <updated>2010-02-01T18:37:21+01:00</updated>
  <author>
   <name>Fabien Jakimowicz</name>
   <email>fabien@jakimowicz.com</email>
  </author>
  <content type="html">
   <![CDATA[<p>
La <a href="http://events.apple.com.edgesuite.net/1001q3f8hhr/event/index.html">page de pr&eacute;sentation de la keynote</a> de ce mois de janvier (iPad) contient quelques surprises concernant la photo de Steve Jobs.</p>

<p style="text-align: center"><img src="http://images.apple.com/quicktime/qtv/specialevent0110/images/hero20100127.jpg" alt="http://images.apple.com/quicktime/qtv/specialevent0110/images/hero20100127.jpg" /></p>
<p><br />Si vous regardez le nom du fichier, on trouve la racine 'hero' : <a href="http://images.apple.com/quicktime/qtv/specialevent0110/images/hero20100127.jpg">http://images.apple.com/quicktime/qtv/specialevent0110/images/hero20100127.jpg</a></p>
<p>
En poussant un peu plus loin, l'&eacute;l&eacute;ment <tt>alt</tt> de la balise html image contient la chose suivante : </p>
<blockquote><p>
Silhouette of person dancing with an iPod.</p></blockquote>
<p></p>
<p>
On notera la petite erreur sur le nom de l'engin. Vu les pubs pass&eacute;es concernant l'iPod pr&eacute;sentant des danseurs en ombre sur fonds color&eacute;s, on sent le copier/coller un peu rapide.</p>
]]>
  </content>
  <wfw:commentRss>http://fabien.jakimowicz.com/blog/index.php/blog/feed/44/comments</wfw:commentRss>
 </entry>

 <entry>
  <id>http://fabien.jakimowicz.com/blog/index.php/blog/43</id>
  <link rel="alternate" type="text/html" href="http://fabien.jakimowicz.com/blog/index.php/blog/43" />
  <title type="html"><![CDATA[RubyZip vs Zip]]></title>
  <updated>2009-12-26T03:12:03+01:00</updated>
  <author>
   <name>Fabien Jakimowicz</name>
   <email>fabien@jakimowicz.com</email>
  </author>
  <content type="html">
   <![CDATA[<p>
Ayant besoin dans un projet de cr&eacute;er des archives zip depuis un code ruby, j'ai cherch&eacute; dans un premier temps du c&ocirc;t&eacute; de gems ou librairies purement ruby pour faire cela. Je n'ai pu trouver que quelques librairies dont certains semblent obsol&egrave;tes ou non maintenues.</p>
<p>
D&eacute;cidant tout de m&ecirc;me de tester une de ces librairies (<a href="http://rubyzip.sourceforge.net">rubyzip</a>), je me suis pos&eacute; la question des performances de ces librairies en comparaison d'une impl&eacute;mentation en C. Etant donn&eacute; que je n'ai que l'archivage d'un r&eacute;pertoire &agrave; effectuer, sans contr&ocirc;le d'erreur fin, pourquoi ne pas cr&eacute;er l'archive en passant par un bon vieux binaire zip disponible de facto sur pratiquement tous les syst&egrave;mes.<br /><br />J'ai donc pris des conditions simples : 4 fichiers, 2 textes (un readme et un code source c++) et 2 binaires (image jpeg et pdf). La librairie ruby benchmark pouvant comptabiliser le temps &eacute;coul&eacute; pour ex&eacute;cuter un block, il ne reste plus qu'&agrave; &eacute;crire le test.</p>
<div class="cmd">
<pre class="prettyprint">
require 'benchmark'
require 'rubygems'
require 'zip/zip'

Benchmark.bm(10) do |x|

  1.upto(10) do  
    x.report(&quot;rubyzip&quot;) do  
      FileUtils.rm_f &quot;/tmp/rubyzip_test.zip&quot;
      Zip::ZipFile.open(&quot;/tmp/rubyzip_test.zip&quot;, Zip::ZipFile::CREATE) do |zipfile|
        zipfile.add(&quot;tmp/files_to_zip/README&quot;,             &quot;/tmp/files_to_zip/README&quot;)
        zipfile.add(&quot;tmp/files_to_zip/trombinoscope.pdf&quot;,  &quot;/tmp/files_to_zip/trombinoscope.pdf&quot;)
        zipfile.add(&quot;tmp/files_to_zip/test3_1.jpg&quot;,        &quot;/tmp/files_to_zip/test3_1.jpg&quot;)
        zipfile.add(&quot;tmp/files_to_zip/cpp_challenge.cpp&quot;,  &quot;/tmp/files_to_zip/cpp_challenge.cpp&quot;)
      end
    end
  end
  
  1.upto(10) do  
    x.report(&quot;zip&quot;) do  
      FileUtils.rm_f &quot;/tmp/zip_test.zip&quot;
      `zip /tmp/zip_test.zip \
            /tmp/files_to_zip/README \
            /tmp/files_to_zip/trombinoscope.pdf \
            /tmp/files_to_zip/test3_1.jpg \
            /tmp/files_to_zip/cpp_challenge.cpp`
    end
  end
  
end
</pre>
</div>
<p><br />Tr&egrave;s simplement, ce script va cr&eacute;er la m&ecirc;me archive zip dix fois de suite en utilisant l'impl&eacute;mentation purement ruby : <tt>rubyzip</tt>. Une autre archive zip sera par la suite cr&eacute;&eacute;e aussi dix fois de suite, cette fois-ci en ex&eacute;cutant la commande <tt>zip</tt>. Sur mon syst&egrave;me, il s'agit de l'impl&eacute;mentation libre provenant de <a href="http://www.info-zip.org">info-zip</a>, derni&egrave;re version en date : Zip 3.0 (July 5th 2008). Du c&ocirc;t&eacute; ruby, nous avons un ruby branche 1.8.7 (2009-06-12 patchlevel 174) avec la librairie rubyzip 0.9.1.</p>
<p>
Les r&eacute;sultats sont clairs :</p>
<div class="cmd">
<pre class="prettyprint">
                user     system      total        real
rubyzip     1.030000   0.080000   1.110000 (  1.354941)
rubyzip     1.020000   0.080000   1.100000 (  1.333094)
rubyzip     1.030000   0.080000   1.110000 (  1.410450)
rubyzip     1.020000   0.070000   1.090000 (  1.400208)
rubyzip     1.020000   0.080000   1.100000 (  1.421957)
rubyzip     1.010000   0.080000   1.090000 (  1.367412)
rubyzip     1.010000   0.080000   1.090000 (  1.488286)
rubyzip     1.010000   0.070000   1.080000 (  1.388657)
rubyzip     1.010000   0.080000   1.090000 (  1.388629)
rubyzip     1.000000   0.070000   1.070000 (  1.377627)
zip         0.000000   0.010000   0.870000 (  1.041277)
zip         0.000000   0.000000   0.870000 (  1.122224)
zip         0.000000   0.000000   0.870000 (  1.121751)
zip         0.000000   0.000000   0.870000 (  1.116203)
zip         0.000000   0.000000   0.880000 (  1.176530)
zip         0.000000   0.010000   0.880000 (  1.219610)
zip         0.000000   0.000000   0.870000 (  1.122010)
zip         0.000000   0.010000   0.880000 (  1.121724)
zip         0.000000   0.000000   0.870000 (  1.120681)
zip         0.000000   0.000000   0.880000 (  1.122107)
</pre>
</div>
<p><br />M&ecirc;me si l'appel au binaire zip n&eacute;cessite l'ouverture d'un pipe, son ex&eacute;cution reste n&eacute;anmoins moyennement 20% plus rapide que l'utilisation de la librairie purement ruby. Il est aussi interessant de noter que cette librairie ne semble pas avoir &eacute;t&eacute; &eacute;crite avec des consid&eacute;rations de performance fortes en t&ecirc;te et qu'elle n'est plus maintenue depuis bient&ocirc;t 2 ans alors que ruby a beaucoup &eacute;volu&eacute; sur la m&ecirc;me p&eacute;riode. </p>
<p>
Mais l'interface fournie par rubyzip est tr&egrave;s facile &agrave; utiliser et offre bien plus que ce qu'on peut obtenir avec l'ex&eacute;cution d'une commande externe. Comme par exemple la possibilit&eacute; d'ajouter un fichier &agrave; l'archive &agrave; partir d'un flux. De plus, certaines contraintes d'h&eacute;bergement emp&ecirc;chent parfois d'ouvrir un pipe pour ex&eacute;cuter une commande externe. Reste &agrave; savoir si ces apports et ornements sont vraiment utiles &agrave; votre besoin et valent les 20% de performance perdue.</p>
]]>
  </content>
  <category term="ruby" label="Ruby" />
  <wfw:commentRss>http://fabien.jakimowicz.com/blog/index.php/blog/feed/43/comments</wfw:commentRss>
 </entry>

 <entry>
  <id>http://fabien.jakimowicz.com/blog/index.php/blog/42</id>
  <link rel="alternate" type="text/html" href="http://fabien.jakimowicz.com/blog/index.php/blog/42" />
  <title type="html"><![CDATA[Flickraw et rails]]></title>
  <updated>2009-12-25T02:00:45+01:00</updated>
  <author>
   <name>Fabien Jakimowicz</name>
   <email>fabien@jakimowicz.com</email>
  </author>
  <content type="html">
   <![CDATA[<p>
Ayant parl&eacute; avant d'une librairie ruby pour flickr, je me suis lanc&eacute; dans un petit test de cette librairie en l'incorporant &agrave; une application ruby on rails. L'id&eacute;e est simple : nous avons des utilisateurs qui peuvent avoir un compte flickr. Les acc&egrave;s &agrave; ce compte seront stock&eacute;s dans la base de donn&eacute;es pour donner &agrave; l'utilisateur un acc&egrave;s &agrave; ses donn&eacute;es flickr &agrave; tout moment sans qu'il ne doive se r&eacute;-authentifier sur flickr.<br /><br />La toute premi&egrave;re chose dont il faut se rappeler avec flickraw, c'est que cette librairie est totalement dynamique : tous les appels au webservice sont construits &agrave; l'aide d'un appel initial sur flickr listant les appels possibles. Ce premier appel est crutial pour permettre &agrave; flickraw d'effectuer son travail, mais inutile tant que l'on ne se sert pas de flickraw. On va donc ajouter une d&eacute;pendance &agrave; flickraw dans l'environnement de notre application rails, en pr&eacute;cisant que nous chargeons nous m&ecirc;me la librairie quand nous en avons besoin :</p>
<div class="cmd">
<pre class="prettyprint">
Rails::Initializer.run do |config|
  # Some other stuff
  config.gem &quot;flickraw&quot;, :lib =&gt; false
end
</pre>
</div>
<p></p>
<p>
La phase d'authentification se fait en plusieurs &eacute;tapes : obtenir un identifiant (<tt>frob</tt>) de flickr, rediriger l'utilisateur sur le site de flickr avec ce frob pour lui demander d'autoriser notre site &agrave; acc&eacute;der &agrave; ses donn&eacute;s, et enfin le retour de l'utilisateur de flickr sur notre site avec une valeur de frob modifi&eacute;e nous permettant d'obtenir un token plus d&eacute;finitif.</p>
<div class="cmd">
<pre class="prettyprint">
require 'flickraw'

class FlickrController &lt; ApplicationController
  before_filter :login_required

  # Redirect user to flickr
  def authenticate
    redirect_to FlickRaw.auth_url(:frob =&gt; current_user.flickr.auth.getFrob,
                                  :perms =&gt; 'read')
  end

  # User returns from flickr with a frob used to generate an authentication token
  def callback
    response = current_user.flickr.auth.getToken(:frob =&gt; params[:frob])
    current_user.update_attributes :flickr_token =&gt; response.token
  rescue FlickRaw::FailedResponse =&gt; e
    render :text =&gt; &quot;Auth failed with #{e}&quot;
  end
end
</pre>
</div>
<p></p>
<p>
Si vous avez lu attentivement le code pr&eacute;c&eacute;dent, vous avez du remarquer la m&eacute;thode <tt>flickr</tt> sur l'user authentifi&eacute; fourni par restful_authentication (<tt>current_user</tt>). Il s'agit d'un petit d&eacute;tournement de la librairie flickraw qui est &agrave; la base 'mono-utilisateur' : la librairie ajoute une m&eacute;thode <tt>flickr</tt> a la classe <tt>Kernel</tt> lui permettant ainsi d'&ecirc;tre facilement accessible. Le probl&egrave;me vient d&egrave;s lors que l'on est authentifi&eacute; : n'ayant qu'une seule instance de flickraw avec son token d'authentification, il est impossible de g&eacute;rer plusieurs utilisateurs. Il nous faut de plus une colonne <tt>token</tt> de type <tt>String</tt> pour stocker le token retourn&eacute; par flickr.</p>
<p>
C'est pourquoi on instancie un client flickraw par utilisateur, au niveau du mod&egrave;le :</p>
<div class="cmd">
<pre class="prettyprint">
require 'flickraw'

class User &lt; ActiveRecord::Base

  def flickr
    @flickr ||= FlickRaw::Flickr.new(self.token)
  end
end
</pre>
</div>
<p></p>
<p>
Si le token est d&eacute;j&agrave; pr&eacute;sent (utilisateur ayant d&eacute;j&agrave; authoris&eacute; le site), on a alors un client flickraw pouvant acc&eacute;der directement aux photos. Sinon, on a une simple instance flickraw nous permettant de nous authentifier. L'autre avantage est aussi de nous donner l'acc&egrave;s au compte flickr de l'utilisateur d&egrave;s lors qu'on instancie la classe : il n'est donc pas n&eacute;cessaire d'&ecirc;tre dans une r&eacute;ponse web classique pour acc&eacute;der &agrave; ces photos, on peut aussi le faire dans un m&eacute;canisme s&eacute;par&eacute; comme une tache de fond.</p>
<p>
R&eacute;cup&eacute;ration des sets de photo :</p>
<div class="cmd">
<pre class="prettyprint">
@user.flickr.photosets.getList.each do |flickr_set|
  puts &quot;#{flickr_set.title} =&gt; #{flickr_set.description}&quot;
end
</pre>
</div>
<p></p>
<p>
Une derni&egrave;re &eacute;tape est n&eacute;cessaire pour sp&eacute;cifier la cl&eacute; ainsi que le secret pour acc&eacute;der &agrave; l'API flickr : la librairie flickraw va chercher une constante <tt>FlickRawOptions</tt> avec des options globales. J'ai donc ajout&eacute; le fichier <tt>flickraw_options.rb</tt> dans les initializers (<tt>config/initializers/flickraw_options.rb</tt>), les 2 constantes <tt>FlickrKey</tt> et <tt>FlickrSecret</tt> &eacute;tant d&eacute;finies sp&eacute;cifiquement dans chaque environnement pour avoir des cl&eacute;s d'API s&eacute;par&eacute;s pour le d&eacute;veloppement et la production :</p>
<div class="cmd">
<pre class="prettyprint">
FlickRawOptions = {

  'api_key'       =&gt; FlickrKey,
  'shared_secret' =&gt; FlickrSecret,

  'lazyload'      =&gt; true
  
}
</pre>
</div>
<p></p>
]]>
  </content>
  <category term="rails" label="rails" />
  <category term="ruby" label="Ruby" />
  <wfw:commentRss>http://fabien.jakimowicz.com/blog/index.php/blog/feed/42/comments</wfw:commentRss>
 </entry>

 <entry>
  <id>http://fabien.jakimowicz.com/blog/index.php/blog/41</id>
  <link rel="alternate" type="text/html" href="http://fabien.jakimowicz.com/blog/index.php/blog/41" />
  <title type="html"><![CDATA[Objective-C : ajout dynamique de fonctions]]></title>
  <updated>2009-12-25T01:19:30+01:00</updated>
  <author>
   <name>Fabien Jakimowicz</name>
   <email>fabien@jakimowicz.com</email>
  </author>
  <content type="html">
   <![CDATA[<p>
L'Objective-C pouvant &ecirc;tre percu comme une imposante librairie tournant au dessus du C/C++, il ne semble pas impossible pour ce langage compil&eacute; de fournir des m&eacute;canismes de <a href="http://fr.wikipedia.org/wiki/R&eacute;flexion_(informatique)">r&eacute;flexion</a>. Une des possibilit&eacute;s appr&eacute;ci&eacute;e dans l'intercession est l'ajout de fonctions au runtime, en fonction du contexte rencontr&eacute; par le programme lors de son ex&eacute;cution. En ruby, ceci est relativement ais&eacute; avec <tt><a href="http://fabien.jakimowicz.com/blog/index.php/blog/35">method_missing</a></tt>, il existe un m&eacute;canisme similaire en Objective-C.</p>
<p>
Le c&ocirc;t&eacute; r&eacute;flection de l'Objective-C est fourni &agrave; travers la class <tt>NSObject</tt>, classe racine de toutes les autres classes. La lecture de la documentation de cette classe peut fournir des &eacute;l&eacute;ments int&eacute;ressants, comme les m&eacute;thodes permettant de d&eacute;terminer la classe ainsi que la classe parente : <tt>class</tt> et <tt>superclass</tt>.<br /><br />L'&eacute;quivalent de <tt>method_missing</tt> est ici repr&eacute;sent&eacute; par 2 fonctions : <tt>resolveClassMethod</tt> et <tt>resolveInstanceMethod</tt> qui sont appel&eacute;es quand une fonction n'a pas &eacute;t&eacute; trouv&eacute;e lors d'un appel, respectivement &agrave; la classe et &agrave; l'instance. Elles prennent toutes les deux comme param&egrave;tre le s&eacute;lecteur (<tt>SEL</tt>) appel&eacute; et retournent un bool&eacute;en (<tt>BOOL</tt>) indiquant si la m&eacute;thode demand&eacute;e &agrave; &eacute;t&eacute; ajout&eacute;e ou non.</p>
<p>
La seconde partie importante dans l'ajout de m&eacute;thode est l'appel permettant effectivement d'ajout cette m&eacute;thode : <tt>class_addMethod</tt>. Elle prend comme param&egrave;tres la classe recevant la nouvelle m&eacute;thode, le nom de la m&eacute;thode, son impl&eacute;mentation ainsi qu'un array d&eacute;finissant les types d'arguments accept&eacute;s par la m&eacute;thode.</p>

<h3>ajout de m&eacute;thode d'instance</h3>
<p>
</p>
<p>
Ayant besoin d'effectuer un traitement interm&eacute;diaire toujours identique avant de set/get des &eacute;l&eacute;ments d'une de mes classes, j'ai pr&eacute;f&eacute;r&eacute; utiliser cette m&eacute;thode de r&eacute;solution et d'ajout dynamique. Une impl&eacute;mentation simple est par exemple :</p>
<div class="cmd">
<pre class="prettyprint">
+ (BOOL) resolveInstanceMethod:(SEL)sel
{
  // Check if implementation is available in parent class
  if ([super resolveInstanceMethod:sel])
    return YES;
  
  // If not, add our method, returning add result
	if ([NSStringFromSelector(sel) hasPrefix:@&quot;set&quot;])
    return class_addMethod([self class], sel, (IMP)dynamicTransitorySetter, &quot;v@:@&quot;);
  else
    return class_addMethod([self class], sel, (IMP)dynamicTransitoryGetter,&quot;@@:&quot;);
}

static id dynamicTransitoryGetter(id self, SEL sel)
{
  return @&quot;something else&quot;;
}

static void dynamicTransitorySetter(id self, SEL sel, id value)
{
  // Make with value
}
</pre>
</div>
<p></p>
<p>
L'id&eacute;e est ici assez simple : en fonction du selecteur pass&eacute;, on va ajouter une m&eacute;thode dynamiquement prenant certains param&egrave;tres. On peut ainsi sp&eacute;cifier toute une vari&eacute;t&eacute; de <a href="http://developer.apple.com/mac/library/documentation/cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html">param&egrave;tres accept&eacute;s</a> par la m&eacute;thode ajout&eacute;e. Dans le cas pr&eacute;sent : <tt>v@:v</tt> est d&eacute;compos&eacute; en <tt>v</tt> pour void, <tt>@:</tt> pour le selecteur et le charact&egrave;re final <tt>@</tt> correspond au param&egrave;tre accept&eacute; par la m&eacute;thode. Quand &agrave; <tt>@@:</tt>, le premier <tt>@</tt> correspond au type retourn&eacute;, ici <tt>id</tt>, le <tt>@:</tt> restant correspond au selecteur.</p>

<h3>ajout de m&eacute;thode de classe</h3>
<p>
</p>
<p>
L'ajout de m&eacute;thode d'instance est presque trivial, mais l'ajout de m&eacute;thode de classe utilisant le m&ecirc;me appel <tt>class_addMethod</tt>, il faut jouer un peu plus avec ce que nous offre l'Objective-C.</p>
<p>
Nous avons ajout&eacute; simplement notre m&eacute;thode d'instance &agrave; notre classe en pr&eacute;cisant que la destination &eacute;tait l'objet <tt>\[self class\]</tt>, repr&eacute;sentant l'objet de la classe. Comme tout est objet ou presque en Objective-C, une classe est elle-m&ecirc;me une instance de <tt>Class</tt>, avec comme m&eacute;thode les m&eacute;thodes d'instance d&eacute;finie dans la classe. Les m&eacute;thodes de classe sont quand &agrave; elles stock&eacute;es dans un autre objet : la metaclasse.</p>
<p>
Un appel &agrave; <tt>objc_getMetaClass</tt> nous permettant de r&eacute;cup&eacute;rer la metaclasse, le reste est identique &agrave; l'ajout de m&eacute;thode d'instance :</p>
<div class="cmd">
<pre class="prettyprint">
Class metaClass = objc_getMetaClass([[self className] UTF8String]);
class_addMethod(metaClass, aSEL, (IMP)dynamicSomething, &quot;v@:&quot;);
</pre>
</div>
<p></p>
]]>
  </content>
  <category term="objc" label="Objective-C" />
  <wfw:commentRss>http://fabien.jakimowicz.com/blog/index.php/blog/feed/41/comments</wfw:commentRss>
 </entry>

 <entry>
  <id>http://fabien.jakimowicz.com/blog/index.php/blog/40</id>
  <link rel="alternate" type="text/html" href="http://fabien.jakimowicz.com/blog/index.php/blog/40" />
  <title type="html"><![CDATA[Flickraw: client flickr en moins de 300 lignes]]></title>
  <updated>2009-12-24T02:03:29+01:00</updated>
  <author>
   <name>Fabien Jakimowicz</name>
   <email>fabien@jakimowicz.com</email>
  </author>
  <content type="html">
   <![CDATA[<p>
Encore une librairie cliente pour flickr, mais enfin une impl&eacute;mentation vraiment diff&eacute;rente cette fois-ci : aucun des appels ou presque n'est impl&eacute;ment&eacute; dans la librairie, tout est cr&eacute;&eacute; dynamiquement.</p>
<p>
Dans un premier temps, il ne faut pas oublier 2 choses : flickr offre une <a href="http://www.flickr.com/services/api">API</a> tr&egrave;s bien construite permettant ce genre de chose et ruby de part son dynamisme permet de l'utiliser pleinement.<br /><br />Concr&ecirc;tement, on va distinguer 3 cas de r&eacute;ponse : une erreur, un objet ou une liste d'objet. Chaque r&eacute;ponse &agrave; sa classe propre : FailedResponse, Response et ResponseList. Arm&eacute; de ces 3 type de r&eacute;ponse, la quasi-totalit&eacute; des r&eacute;ponses faites par flickr peuvent &ecirc;tre g&eacute;r&eacute;es.</p>
<p>
La seconde partie concerne les requ&ecirc;tes : une simple classe <tt>Request</tt> fera l'affaire. Un appel sur l'API flickr &agrave; <tt>flickr.reflection.getMethods</tt> nous retournera une liste de tous les appels possible. Il ne reste plus qu'a lier ces appels &agrave; des m&eacute;thodes cr&eacute;es dynamiquement. Pour chaque appel de la liste, une m&eacute;thode d'instance est ajout&eacute;e &agrave; la classe <tt>Request</tt>, prenant des arguments qu'elle passe directement &agrave; une m&eacute;thode g&eacute;n&eacute;rique charg&eacute;e de l'appel a flickr, parsing et cr&eacute;ation de la r&eacute;ponse ad&eacute;quat.</p>
<p>
Cependant, afin de g&eacute;rer les appels du type <tt>flickr.photosets.getList</tt>, il est n&eacute;cessaire d'avoir un m&eacute;canisme de proxy (<tt>photosets</tt>) qui sera uniquement charg&eacute; de transmettre l'appel (<tt>getList</tt>). Ce syst&egrave;me est assur&eacute; en cr&eacute;ant, lors du parcours des appels flickr, un getter prenant dans le cas pr&eacute;sant comme nom <tt>photosets</tt> et qui sera, lors de l'instanciation de la classe, initialis&eacute; avec une instance de <tt>Request</tt>. Cette instance, ayant re&ccedil;u dynamiquement la m&eacute;thode <tt>getList</tt>, est capable d'ex&eacute;cuter la m&eacute;thode.</p>
<p>
Les seules parties sp&eacute;cifiques et les plus longues de la librairies concernent l'upload, l'authentification et la signature des requ&ecirc;tes. Le reste est g&eacute;r&eacute; totalement dynamiquement par la cr&eacute;ation dynamique de m&eacute;thodes et accesseurs.</p>
<p>
<a href="http://hanklords.github.com/flickraw">Flickraw</a> : une belle r&eacute;alisation technique d&eacute;montrant le potentiel de ruby et une impl&eacute;mentation flickr presque toujours &agrave; jour sans modification, ne demandant comme documentation que l'officielle de l'API flickr.</p>
]]>
  </content>
  <category term="ruby" label="Ruby" />
  <wfw:commentRss>http://fabien.jakimowicz.com/blog/index.php/blog/feed/40/comments</wfw:commentRss>
 </entry>

 <entry>
  <id>http://fabien.jakimowicz.com/blog/index.php/blog/39</id>
  <link rel="alternate" type="text/html" href="http://fabien.jakimowicz.com/blog/index.php/blog/39" />
  <title type="html"><![CDATA[Console en ruby + readline]]></title>
  <updated>2009-12-24T01:21:13+01:00</updated>
  <author>
   <name>Fabien Jakimowicz</name>
   <email>fabien@jakimowicz.com</email>
  </author>
  <content type="html">
   <![CDATA[<p>
Ayant besoin d'une petite console effectuant des appels sur un webservice, je me suis lanc&eacute; &agrave; la d&eacute;couverte de readline. Cependant, la documentation officielle est totalement <a href="http://ruby-doc.org/stdlib/libdoc/readline/rdoc/index.html">innexistante</a>.</p>
<p>
Apr&egrave;s quelques recherches, j'ai pu trouver un tutoriel donnant les <a href="http://bogojoker.com/readline/">principales fonctions de readline</a>.</p>
<p>
L'id&eacute;e derri&egrave;re readline est simple : fournir une librairie permettant simplement d'&eacute;diter des lignes de commandes au moment de leur frappe. La gestion des racourcis ctrl+a et ctrl+e, ainsi que l'historique sont des exemples des fonctions support&eacute;es par readline.<br /><br />Revenons &agrave; son impl&eacute;mentation ruby, dans sa version la plus simple :</p>
<div class="cmd">
<pre class="prettyprint">
while line = Readline.readline('&gt; ')
  puts &quot;you entered #{line}&quot;
end
</pre>
</div>
<p></p>
<p>
Le param&egrave;tre pris par la m&eacute;thode readline d&eacute;fini l'apparence du shell. Quand a la gestion de l'historique, elle est juste triviale : il est accessible via la constante <tt>Readline::HISTORY</tt>. Son activation demande juste l'ajout d'un boolean &agrave; l'appel readline :</p>
<div class="cmd">
<pre class="prettyprint">
while line = Readline.readline('&gt; ', true)
  puts &quot;you entered #{line}&quot;
end
</pre>
</div>
<p></p>
<p>
De mon c&ocirc;t&eacute;, j'avais besoin d'ex&eacute;cuter des commandes simples ne prennant pas d'argument, par exemple: <tt>profile create</tt>. Il me faut aussi pouvoir d&eacute;finir et modifier certaines variables globale &agrave; la session en cours. J'ai d&eacute;fini une classe <tt>Setup</tt> charg&eacute;e de contenir et modifier toutes les variables. Quand aux commandes simples, elles ressemblent &agrave; des appels de m&eacute;thodes sur des objets.</p>
<p>
La magie du ruby faisant le reste :</p>
<div class="cmd">
<pre class="prettyprint">
require 'readline'
require 'pp'

class Setup
  def initialize
    # set default values
  end
end

class CommandLine
  def initialize
    @setup = Setup.new
    @profile = Profile.new
    @room = Room.new
  end

  def parse(line)
    values = line.split

    case values.first
    when 'setup'
      if values.count == 1
        pp @setup
      elsif values.count == 2
        pp @setup.instance_variable_get(&quot;@#{values[1]}&quot;)
      elsif values.count == 3
        pp @setup.instance_variable_set(&quot;@#{values[1]}&quot;, values[2])
      else
        puts &quot;too many arguments&quot;
      end

    else
      var = instance_variable_get(&quot;@#{values.shift}&quot;)
      if var.nil?
        puts &quot;command not recognized&quot;
      else
        pp var.send(values.shift, *values)
      end

    end
  end

  def loop
    while line = Readline.readline('&gt; ', true)
      next if line.empty?
      parse line
    end
  end
end

CommandLine.new.loop
</pre>
</div>
<p></p>
<p>
Tr&egrave;s simplement, la classe CommandLine initialise des variables d'instances qui pourront recevoir des commandes sous la forme de simples appels de m&eacute;thode. La partie setup est quand &agrave; elle plus particuli&egrave;re car elle g&egrave;re 3 cas : l'affichage des variables contenues dans <tt>@setup</tt>, la consultation d'une des variable ainsi que son &eacute;dition.</p>
<p>
La r&eacute;cup&eacute;ration de la variable d'instance sur laquelle la m&eacute;thode sera appliqu&eacute;e se fait &agrave; l'aide de <tt>instance_variable_get</tt> nous permettant de r&eacute;cup&eacute;rer un variable d'instance &agrave; partir d'une string. L'ex&eacute;cution de la commande se fait en utilisant <tt>send</tt> qui permet d'ex&eacute;cuter une m&eacute;thode &agrave; partir d'une string ou d'un symbole.</p>
<p>
Apr&egrave;s impl&eacute;mentation d'une partie plus sp&eacute;cifique dans les classes <tt>Room</tt> et <tt>Profile</tt>, on peut obtenir le r&eacute;sultat suivant :</p>
<div class="cmd">
<pre class="prettyprint">
&gt; setup
#&lt;Setup:0x1003d44c8&gt;
&gt; setup foo
nil
&gt; setup foo 50
&quot;50&quot;
&gt; setup foo
&quot;50&quot;
&gt; setup bar some_value
&quot;some_value&quot;
&gt; setup
#&lt;Setup:0x1003d44c8 @bar=&quot;some_value&quot;, @foo=&quot;50&quot;&gt;
&gt; room pouet
&quot;in pouet from room&quot;
&gt; bleh
command not recognized
&gt; setup 1 2 3
too many arguments
</pre>
</div>
<p></p>
]]>
  </content>
  <category term="ruby" label="Ruby" />
  <wfw:commentRss>http://fabien.jakimowicz.com/blog/index.php/blog/feed/39/comments</wfw:commentRss>
 </entry>

 <entry>
  <id>http://fabien.jakimowicz.com/blog/index.php/blog/38</id>
  <link rel="alternate" type="text/html" href="http://fabien.jakimowicz.com/blog/index.php/blog/38" />
  <title type="html"><![CDATA[Mac os X : terminal tips]]></title>
  <updated>2009-12-01T01:31:00+01:00</updated>
  <author>
   <name>Fabien Jakimowicz</name>
   <email>fabien@jakimowicz.com</email>
  </author>
  <content type="html">
   <![CDATA[<p>
Voici une petite liste de quelques petites commandes commandes unix pour sp&eacute;cifiques Mac os X.<br /><br />
</p>
<h3>Gestion du pasteboard/clipboard</h3>
<p>
</p>
<div class="cmd">
<pre class="prettyprint">
$&gt; echo &quot;something&quot; | pbcopy
$&gt; pbpaste
something
</pre>
</div>
<p></p>
<p>
<tt>pbcopy</tt> permet d'ajouter l'entr&eacute;e standard au clipboard, ensuite accessible sur toutes les applications.<br /><tt>pbpaste</tt> va &agrave; l'inverse afficher sur la sortie standard le contenu du clipboard.</p>

<h3>Ouverture de documents</h3>
<p>
</p>
<div class="cmd">
<pre class="prettyprint">
$&gt; open test.pdf
$&gt; open http://www.google.com
</pre>
</div>
<p></p>
<p>
<tt>open</tt> offre de nombreuses options permettant d'ouvrir par exemple le document directement dans TextEdit (-e), d'afficher le fichier dans le Finder au lieu de l'ouvrir dans l'application correspondante (-R) ou encore d'ouvrir le fichier dans une application en background pour ne pas perdre le focus dans le terminal.</p>

<h3>Synth&eacute;tiseur vocal</h3>
<p>
</p>
<div class="cmd">
<pre class="prettyprint">
$&gt; say &quot;my computer is beautiful&quot;
</pre>
</div>
<p></p>
<p>
<tt>say</tt> permet de synth&eacute;tiser le texte pass&eacute; en param&egrave;tre en voix audible sur la sortie audio. Des options permettent de pr&eacute;ciser la voix &agrave; utiliser, d'&eacute;ventuellement exporter la sortie dans un fichier au lieu de la sortie son ou encore d'envoyer le son via r&eacute;seau en utilisant le protocole AUNetSend.</p>

<h3>Capture d'&eacute;cran</h3>
<p>
</p>
<div class="cmd">
<pre class="prettyprint">
$&gt; screencapture file.png
</pre>
</div>
<p></p>
<p>
<tt>screencapture</tt> comme son nom l'indique effectue une saisie d'&eacute;cran et la sauvegarde dans un fichier. Des options particuli&egrave;rement utiles permettent d'ouvrir un nouveau mail avec la capture en pi&egrave;ce jointe (-M), de pr&eacute;ciser le format (-t), d'ouvrir le fichier dans Preview (-P) ou encore de ne pas jouer de son lors de la capture (-x).</p>

<h3>Gestion du syst&egrave;me</h3>
<p>
</p>
<div class="cmd">
<pre class="prettyprint">
$&gt; softwareupdate -l
Software Update Tool
Copyright 2002-2009 Apple

No new software available.
$&gt; system_profiler
Hardware:

    Hardware Overview:

      Model Name: MacBook Pro
      Model Identifier: MacBookPro5,3
    .
    .
    .
</pre>
</div>
<p></p>
<p>
<tt>softwareupdate</tt> offre une interface en ligne de commande pour les mises &agrave; jour syst&egrave;me. Les options permettent de lister les mises &agrave; jour disponibles (-l), de lancer leur t&eacute;l&eacute;chargement (-d) ou encore leur installation (-i).<br /><tt>system_profiler</tt> affiche les informations du syst&egrave;me telles que celles affich&eacute;es dans l'application graphique System Profiler.</p>
]]>
  </content>
  <category term="leopard" label="leopard" />
  <wfw:commentRss>http://fabien.jakimowicz.com/blog/index.php/blog/feed/38/comments</wfw:commentRss>
 </entry>

 <entry>
  <id>http://fabien.jakimowicz.com/blog/index.php/blog/37</id>
  <link rel="alternate" type="text/html" href="http://fabien.jakimowicz.com/blog/index.php/blog/37" />
  <title type="html"><![CDATA[Ruby: blocks, to_proc, &amp;]]></title>
  <updated>2009-11-30T21:41:41+01:00</updated>
  <author>
   <name>Fabien Jakimowicz</name>
   <email>fabien@jakimowicz.com</email>
  </author>
  <content type="html">
   <![CDATA[<p>
Les blocks repr&eacute;sentent une fonctionnalit&eacute; puissante de Ruby. Mais comment sont ils trait&eacute;s d'un point de vue langage ?</p>
<p>
Ruby &eacute;tant totalement objet, derri&egrave;re les blocks se cache en fait une classe Ruby : <a href="http://ruby-doc.org/core/classes/Proc.html">Proc</a>. De la d&eacute;claration en utilisant les accolades '{}' ou l'ensemble do..end resulte une instance de la classe Proc :</p>

<div class="cmd">
<pre class="prettyprint">
class MyClass
  def envelope(myblock)
    myblock.call
  end
end

m = MyClass.new
p = Proc.new { puts 'test' }
m.envelope p
</pre>
</div>
<p><br />L'appel <tt>yield</tt> ainsi que la cr&eacute;ation de Proc sans pour autant les instancier explicitement sont des &eacute;l&eacute;ments de plus &agrave; ajouter au sucre syntaxique que nous fourni Ruby. Le code pr&eacute;c&eacute;dent aurait pu &ecirc;tre &eacute;cris :</p>

<div class="cmd">
<pre class="prettyprint">
class MyClass
  def envelope(&amp;myblock)
    myblock.call
  end
end

m = MyClass.new
m.envelope { puts 'test' }
</pre>
</div>
<p></p>
<p>
Que vient faire le caract&egrave;re '&amp;' avant l'argument <tt>myblock</tt> ? Il convertit simplement l'argument <tt>myblock</tt> en un objet Proc, en appelant la m&eacute;thode <tt>to_proc</tt>. Un exemple que vous avez du voir de nombreuses fois est la conversion d'un symbol en un Proc :</p>

<div class="cmd">
<pre class="prettyprint">
[1,2,3].collect &amp;:to_s
# =&gt; [&quot;1&quot;, &quot;2&quot;, &quot;3&quot;]
</pre>
</div>
<p></p>
<p>
Cette fonctionalit&eacute; pr&eacute;sente dans Ruby On Rails depuis de nombreuses releases &agrave; &eacute;t&eacute; ajout&eacute;e &agrave; Ruby 1.8.7 et 1.9. Son code simplifi&eacute; est le suivant :</p>
<div class="cmd">
<pre class="prettyprint">
def to_proc
  Proc.new { |obj| obj.send self }
end
</pre>
</div>
<p></p>
<p>
On cr&eacute;e une instance de Proc re&ccedil;evant l'objet sur lequel on souhaites appeler la m&eacute;thode (ici, chaque &eacute;l&eacute;ment de l'array). On appelle la m&eacute;thode ayant pour nom le symbol (ici, to_s). La m&eacute;thode <tt>collect</tt> recoit donc un block prenant un argument et ex&eacute;cutant la m&eacute;thode correspondant au symbol.</p>
<p>
Cependant, cette m&eacute;thode reste un peu moins efficace que la d&eacute;claration explicite d'un block car Ruby devra, au moment de l'ex&eacute;cution, convertir le symbol en Proc. Elle n'en reste pas moins tr&egrave;s &eacute;l&eacute;gante.</p>
<p>
Un autre usage courant des blocks pour clarifier le code est leur utilisation dans des vues ERB Ruby on Rails : <a href="http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#M001604">les formulaires</a>, <a href="http://api.rubyonrails.org/classes/ActionView/Helpers/TagHelper.html#M001726">conteneurs</a> et m&ecirc;me <a href="http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#M001597">les liens</a>.<br />Si vous utilisez des balises div avec un traitement sp&eacute;cial (coins arrondis par exemple), une m&eacute;thode &eacute;l&eacute;gante consiste &agrave; d&eacute;clarer un Helper utilisant le block comme contenu de cette div :</p>

<div class="cmd">
<pre class="prettyprint">
&lt;% rounded_block do %&gt;
  Contenu de la div.
&lt;% end %&gt;
</pre>
</div>
<p></p>
<p>
L'astuce permettant ici de r&eacute;cup&eacute;rer le contenu du block pour l'ins&eacute;rer au bon endroit est d'utiliser la m&eacute;thode <a href="http://api.rubyonrails.org/classes/ActionView/Helpers/CaptureHelper.html#M001762">capture</a> fournie par Ruby on Rails :</p>
<div class="cmd">
<pre class="prettyprint">
def rounded_block(&amp;block)
  content_tag(:div, :class =&gt; &quot;rounded_box&quot;) do
    capture &amp;block
  end
end
</pre>
</div>
<p></p>
<p>
Les blocks permettant d'&eacute;crire plus naturellement des codes complexes, leur utilisation permet d'augmenter &agrave; la fois la lisibilit&eacute; du code et aussi le plaisir d'&eacute;criture.</p>
]]>
  </content>
  <category term="ruby" label="Ruby" />
  <wfw:commentRss>http://fabien.jakimowicz.com/blog/index.php/blog/feed/37/comments</wfw:commentRss>
 </entry>

 <entry>
  <id>http://fabien.jakimowicz.com/blog/index.php/blog/36</id>
  <link rel="alternate" type="text/html" href="http://fabien.jakimowicz.com/blog/index.php/blog/36" />
  <title type="html"><![CDATA[Ruby: blocks]]></title>
  <updated>2009-11-30T21:38:32+01:00</updated>
  <author>
   <name>Fabien Jakimowicz</name>
   <email>fabien@jakimowicz.com</email>
  </author>
  <content type="html">
   <![CDATA[<p>
Les blocks en Ruby est une des fonctions incontournables qui rendent ce langage si attrayant. En simplifi&eacute;, il s'agit d'un bo&ucirc;t de code que l'on peut passer &agrave; des fonctions. Ce code peut prendre des param&egrave;tres si n&eacute;cessaire. On les appelle plus commun&eacute;ment fonction annonyme.</p>
<p>
Une des utilisations principales de ces blocks est fait lors de l'it&eacute;ration d'&eacute;l&eacute;ments Enumerable :</p>
<div class="cmd">
<pre class="prettyprint">
[1,2,3].each do |item|
  puts item + 5
end
</pre>
</div>
<p><br />Que se passe -t- il lors de l'ex&eacute;cution du code pr&eacute;c&eacute;dent : le block d&eacute;fini va &ecirc;tre pass&eacute; &agrave; la m&eacute;thode <tt>each</tt> de l'array. Cette fonction annonyme sera alors ex&eacute;cut&eacute; pour chaque &eacute;l&eacute;ment de l'array, en passant comme param&egrave;tre l'&eacute;l&eacute;ment courant.</p>
<p>
Chaque fonction peut recevoir un block et l'ex&eacute;cuter :</p>

<div class="cmd">
<pre class="prettyprint">
class MyClass
  def envelope
    puts &quot;before&quot;
    yield
    puts &quot;after&quot;
  end
end

m = MyClass.new
m.envelope { puts 'test' }
</pre>
</div>
<p></p>
<p>
Ce code devrait afficher la chaine de caract&egrave;res 'test' entre les chaines 'before' et 'after'. La m&eacute;thode <tt>block_given?</tt> permet de savoir si un block &agrave; &eacute;t&eacute; pass&eacute; &agrave; la fonction :</p>

<div class="cmd">
<pre class="prettyprint">
def envelope
  yield if block_given?
end
</pre>
</div>
<p></p>
<p>
Une des grandes utilit&eacute;s des blocks est par exemple de pouvoir effectuer un ensemble d'op&eacute;rations dans le contexte d'une m&eacute;thode. Cet usage des blocks est particuli&egrave;rement employ&eacute; dans les traitements IO (r&eacute;seau, fichier, ...). En effet, le code contenu dans le block peut ex&eacute;cuter des m&eacute;thodes de l'instance de classe, si elle est pass&eacute;e en argument du block :</p>

<div class="cmd">
<pre class="prettyprint">
class MyClass
  def envelope(var)
    @given_value = var
    yield self
  end

  def func2
    puts &quot;calling func2, given_value: #{@given_value}&quot;
  end
end

m = MyClass.new
m.envelope(&quot;value1&quot;) do |my_instance|
  my_instance.func2
end

# =&gt; &quot;calling func2, given_value: value1&quot;
</pre>
</div>
<p></p>
<p>
On peut aussi passer un block lors de l'instanciation d'une classe, si la m&eacute;thode initialize ad&eacute;quate est renseign&eacute;e, ce qui permet par exemple d'effectuer un certain nombre de traitement sur l'objet d&egrave;s sa cr&eacute;ation. Le code obtenu est ainsi plus clair.</p>
]]>
  </content>
  <category term="ruby" label="Ruby" />
  <wfw:commentRss>http://fabien.jakimowicz.com/blog/index.php/blog/feed/36/comments</wfw:commentRss>
 </entry>

</feed>
