<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Blog du projet ZiK &#187; Ruby</title>
	<atom:link href="https://blog.developpez.com/zik/pcategory/ruby/feed" rel="self" type="application/rss+xml" />
	<link>https://blog.developpez.com/zik</link>
	<description></description>
	<lastBuildDate>Wed, 14 Dec 2011 16:32:19 +0000</lastBuildDate>
	<language>fr-FR</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.1.42</generator>
	<item>
		<title>Adapter une bibliothèque C pour ruby (1)</title>
		<link>https://blog.developpez.com/zik/p9266/ruby/adapter_une_bibliotheque_c_pour_ruby_1</link>
		<comments>https://blog.developpez.com/zik/p9266/ruby/adapter_une_bibliotheque_c_pour_ruby_1#comments</comments>
		<pubDate>Fri, 01 Oct 2010 15:17:24 +0000</pubDate>
		<dc:creator><![CDATA[vinc-mai]]></dc:creator>
				<category><![CDATA[debian-fr]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Introduction J&#8217;utilise régulièrement ruby-taglib. Malheureusement, certains bugs empêchent son utilisation avec ruby 1.9. Après avoir tenté, avec plus ou moins de succès, de corriger ces bugs, j&#8217;ai décidé de réécrire cette bibliothèque. La version originale est basée sur ruby/DL, bibliothèque que je n&#8217;ai jamais utilisée. Je profite de cette réécriture pour proposer une série d&#8217;articles sur la manière d&#8217;adapter une bibliothèque C. Préparation Je développe pour l&#8217;instant sous ubuntu 10.04 (je terminerai sûrement ces articles [&#8230;]]]></description>
				<content:encoded><![CDATA[<h2>Introduction</h2>
<p>
J&rsquo;utilise régulièrement <a href="http://www.hakubi.us/ruby-taglib/">ruby-taglib</a>. Malheureusement, certains bugs empêchent son utilisation avec ruby 1.9. Après avoir tenté, avec plus ou moins de succès, de corriger ces bugs, j&rsquo;ai décidé de réécrire cette bibliothèque. La version originale est basée sur <a href="http://ttsky.net/ruby/ruby-dl.html">ruby/DL</a>, bibliothèque que je n&rsquo;ai jamais utilisée. Je profite de cette réécriture pour proposer une série d&rsquo;articles sur la manière d&rsquo;adapter une bibliothèque C.
</p>
<p><span id="more-14"></span></p>
<h2>Préparation</h2>
<p>
Je développe pour l&rsquo;instant sous ubuntu 10.04 (je terminerai sûrement ces articles sous la version 10.10). J&rsquo;ai installé <a href="http://developer.kde.org/~wheeler/taglib.html">taglib</a>, ruby et rdoc soit les paquets debian suivant : libtagc0, libtagc0-dev, ruby, ruby-dev, rdoc.
</p>
<h2>Hiérarchie</h2>
<p>
La commande <b>tree</b> présente l&rsquo;arborescence de mon répertoire de travail.
</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ tree <br />
. <br />
&amp;#9500;&amp;#9472;&amp;#9472; extconf.rb <br />
&amp;#9500;&amp;#9472;&amp;#9472; lib <br />
&amp;#9474;   &amp;#9492;&amp;#9472;&amp;#9472; taglib2.rb <br />
&amp;#9492;&amp;#9472;&amp;#9472; taglib2.c</div></div>
<p>
Le fichier <b>extconf.rb</b>, écrit en ruby, permettra de préparer les sources en vue de compiler la bibliothèque. Le fichier <b>lib/taglib2.rb</b>, lui aussi écrit en ruby, est le fichier lu par l&rsquo;interpréteur ruby lors de l&rsquo;appel à <b>require &laquo;&nbsp;taglib2&Prime;</b> qui chargera notre future bibliothèque.Le fichier <b>taglib2.c</b>, écrit en C, contiendra les méthodes qui permettent d&rsquo;interfacer taglib.
</p>
<h2>Ruby</h2>
<p>
Dans un premier temps, j&rsquo;utiliserai seulement le langage ruby. J&rsquo;écris donc les premières lignes de code dans le fichier <b>lib/taglib2.rb</b>.
</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ cat lib/taglib2.rb &nbsp;<br />
module TagLib <br />
&nbsp; VERSION=[0, 0, 1] <br />
end</div></div>
<p>
Une constante nommée <b>VERSION</b> est définie comme un tableau contenant 3 entiers. D’ores et déjà, je peux tester mon code grâce à irb, un interpréteur ruby en ligne de commande. La bibliothèque n&rsquo;étant pas encore installée, j&rsquo;utilise un chemin relatif pour y accéder.
</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ irb <br />
&gt; require &quot;./lib/taglib2&quot; <br />
=&gt; true <br />
&gt; TagLib::VERSION <br />
=&gt; [0, 0, 1]</div></div>
<h2>Interface ruby/C</h2>
<h3>Exceptions</h3>
<p>
Nous nous intéressons enfin au fichier <b>taglib2.c</b>. Nous définissons, tout d&rsquo;abord, les différents types d&rsquo;exceptions qui peuvent être levés par la bibliothèque.
</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ cat taglib2.c <br />
#include &lt;ruby.h&gt; <br />
#include &lt;taglib/tag_c.h&gt; <br />
&nbsp;<br />
VALUE mTagLib; <br />
VALUE eBadPath, eBadFile, eBadTag, eBadAudioProperties; <br />
&nbsp;<br />
void <br />
Init_taglib2() <br />
{ <br />
&nbsp; mTagLib=rb_define_module(&quot;TagLib&quot;); <br />
&nbsp; eBadPath=rb_define_class_under(mTagLib, &quot;BadPath&quot;, rb_eException); <br />
&nbsp; &nbsp; eBadFile=rb_define_class_under(mTagLib, &quot;BadFile&quot;, rb_eException); <br />
&nbsp; &nbsp; eBadTag=rb_define_class_under(mTagLib, &quot;BadTag&quot;, rb_eException); <br />
&nbsp; &nbsp; eBadAudioProperties=rb_define_class_under(mTagLib, &quot;BadAudioProperties&quot;, rb_eException); <br />
}</div></div>
<p>
Les fichiers nécessaires au développement de la bibliothèque sont tout d&rsquo;abord inclus puis nous déclarons des variables de type <b>VALUE</b>. Ce type est utilisé pour toute variable représentant un objet du langage ruby. Les noms de variables représentant des exceptions sont généralement préfixés par la lettre <b>e</b>. Pour les modules, la lettre <b>m</b> est utilisée, pour les classes, la lettre <b>c</b>.<br />
Il s&rsquo;agit d&rsquo;une convention et non d&rsquo;une règle. Finalement, on retrouve la fonction <b>Init_taglib2</b> qui (re)définit le module TagLib ainsi que 4 classes descendant de la classe ruby <b>Exception</b> représentée en C par la variable <b>rb_eException</b>.
</p>
<p>
Le code suivant, écrit en ruby, est équivalent à la définition donnée en C de l&rsquo;exception <b>TagLib::BadPath</b>
</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">module TagLib <br />
class BadPath &lt; Exception <br />
end <br />
end</div></div>
<h3>Compilation</h3>
<p>
Afin de compiler notre bibliothèque, nous devons créer un fichier <b>Makefile</b>. La bibliothèque <b>mkmf</b> nous facilite le travail.
</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ cat -n extconf.rb <br />
1 &nbsp;require 'mkmf' <br />
2 &nbsp;<br />
3 &nbsp;have_header('ruby.h') || exit 1 <br />
4 &nbsp;have_header('taglib/tag_c.h') || exit(1) <br />
5 &nbsp;<br />
6 &nbsp;create_makefile(&quot;taglib2&quot;) <br />
$ ruby extconf.rb &nbsp;<br />
checking for ruby.h... yes <br />
checking for taglib/tag_c.h... yes <br />
creating Makefile</div></div>
<p>
Dans le fichier <b>extconf.rb</b>, la présence des fichiers « header » de ruby et de taglib sont vérifiées ligne 3 et 4. La ligne 6 permet de créer le fichier <b>Makefile</b> du projet taglib2. Lors du chargement d&rsquo;une interface ruby/C, la fontion appelée est de la forme <b>Init_NomDuProjet</b>,c&rsquo;est pourquoi l&rsquo;unique fonction du fichier  <b>taglib2.c</b> s&rsquo;appelle <b>Init_taglib2</b>. Il s&rsquo;agit de l&rsquo;équivalent de la fonction <b>main</b> d&rsquo;un programme C traditionnel.
</p>
<p>
Après avoir créer le fichier Makefile, compilons.
</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ ruby extconf.rb <br />
$ make</div></div>
<p>
Un bibliothèque dynamique <b>taglib2.so</b> vient de faire son apparition. Ruby permet de charger directement ce type de bibliothèque. Nous ajoutons donc l&rsquo;instruction (<b>require &laquo;&nbsp;taglib2.so&nbsp;&raquo;</b>) de chargement dans le fichier <b>lib/taglib2.rb</b>.
</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ cat lib/taglib2.rb &nbsp;<br />
require &quot;taglib2.so&quot; <br />
&nbsp;<br />
module TagLib <br />
VERSION=[0, 0, 1] <br />
end</div></div>
<h3>Test</h3>
<p>
Nous testons notre code sous irb.
</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ irb <br />
&gt; $:.unshift('.') <br />
&gt; $:.unshift('lib') <br />
&gt; require &quot;taglib2&quot; <br />
=&gt; true <br />
&gt; TagLib.constants <br />
=&gt; [&quot;BadFile&quot;, &quot;BadPath&quot;, &quot;BadAudioProperties&quot;, &quot;VERSION&quot;, &quot;BadTag&quot;] <br />
&gt; TagLib::BadPath.new <br />
=&gt; #&lt;TagLib::BadPath: TagLib::BadPath&gt;</div></div>
<p>
J&rsquo;ajoute tout d&rsquo;abord le répertoire courant et le répertoire <b>lib</b> dans les chemins vérifiés lors du chargement d&rsquo;un fichier afin que les appels à <b>require &laquo;&nbsp;taglib2&Prime;</b> et à <b>require &laquo;&nbsp;taglib2.so&nbsp;&raquo;</b> n&rsquo;échouent pas. Cette astuce ne sera plus nécessaire une fois la bibliothèque installée. On vérifie que les constantes définies dans les fichiers sources <b>lib/taglib2.rb</b> et <b>taglib2.c</b> sont accessibles.
</p>
<h2>Conclusion</h2>
<p>
Lors de ce premier billet, j&rsquo;ai mis en place les différents éléments (bibliothèques, fichiers) qui seront nécessaires à l&rsquo;interface ruby de taglib. Nous avons, déjà, réussi à obtenir un code fonctionnel. Il nous reste à porter les fonctions proposées par taglib afin de pourvoir accéder, en ruby, aux tags de fichiers musicaux.<br />À la prochaine.
</p>
<p>
Je ne suis pas un spécialiste du langage C, si vous avez des suggestions à faire sur mon code<br />
commentez ce billet.
</p>
<h2>Addendum</h2>
<p>Je rajoute la liste des billets faisant suite à celui-ci :</p>
<ul>
<li><a href="http://blog.developpez.com/zik/p9343/ruby/adapter-une-bibliotheque-c-pour-ruby-2/">billet 2</a>,</li>
<li><a href="http://blog.developpez.com/zik/p9348/ruby/adapter-une-bibliotheque-c-pour-ruby-3/">billet 3</a>,</li>
<li><a href="http://blog.developpez.com/zik/p9357/ruby/adapter-une-bibliotheque-c-pour-ruby-4/">billet 4</a>,</li>
<li><a href="http://blog.developpez.com/zik/p9360/ruby/adapter-une-bibliotheque-c-pour-ruby-5/">billet 5</a>.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Adapter une bibliothèque C pour ruby (5)</title>
		<link>https://blog.developpez.com/zik/p9360/ruby/adapter_une_bibliotheque_c_pour_ruby_5</link>
		<comments>https://blog.developpez.com/zik/p9360/ruby/adapter_une_bibliotheque_c_pour_ruby_5#comments</comments>
		<pubDate>Thu, 07 Oct 2010 16:26:01 +0000</pubDate>
		<dc:creator><![CDATA[vinc-mai]]></dc:creator>
				<category><![CDATA[debian-fr]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Diverses fonctions Je vais présenter ici quelques fonctions utiles. Pour des questions de faciliter, j&#8217;ai créé deux nouvelles méthodes pour le module TagLib bien qu&#8217;elles n&#8217;aient rien avoir avec taglib. Utiliser un bloc rb_define_singleton_method(mTagLib, &#34;block&#34;, block, 0); La méthode TagLib.block ne prend aucun paramètre, mais un bloc doit lui être fourni. Elle exécute ce bloc en lui passant comme argument l&#8217;objet TagLib et retourne le bloc sous la forme d&#8217;un Proc. $ make $ irb [&#8230;]]]></description>
				<content:encoded><![CDATA[<h2>Diverses fonctions</h2>
<p>Je vais présenter ici quelques fonctions utiles. Pour des questions de faciliter, j&rsquo;ai créé deux nouvelles méthodes pour le module <b>TagLib</b> bien qu&rsquo;elles n&rsquo;aient rien avoir avec taglib.</p>
<h3>Utiliser un bloc</h3>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">rb_define_singleton_method(mTagLib, &quot;block&quot;, block, 0);</div></div>
<p>La méthode <b>TagLib.block</b> ne prend aucun paramètre, mais un bloc doit lui être fourni. Elle exécute ce bloc en lui passant comme argument l&rsquo;objet <b>TagLib</b> et retourne le bloc sous la forme d&rsquo;un <b>Proc</b>.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ make <br />
$ irb <br />
&gt; require './lib/taglib2.rb' <br />
=&gt; true <br />
TagLib.block{|a| p a} <br />
TagLib <br />
=&gt; #&lt;Proc:0xb75ba510@(irb):2&gt;</div></div>
<p>Voici la fonction implémentant ce comportement.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">VALUE <br />
block(VALUE self) <br />
{ <br />
&nbsp; &nbsp; rb_yield(self); <br />
&nbsp; &nbsp; return rb_block_proc(); <br />
}</div></div>
<p><b>rb_yield</b> permet d&rsquo;appeler le bloc passé à la méthode alors que <b>rb_block_proc</b> permet de le manipuler sous la forme d&rsquo;un <b>Proc</b>.</p>
<h3>Utiliser des paramètres optionnels</h3>
<p>Je propose d&rsquo;écrire l&rsquo;équivalent de code écrit en ruby.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">def TagLib.n(tab=[&quot;Salut&quot;, &quot;Re&quot;]) <br />
&nbsp; &nbsp; tab.to_a <br />
&nbsp; &nbsp; tab.each{|s| $stdout.puts s} <br />
&nbsp; &nbsp; tab[0] <br />
end</div></div>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">rb_define_singleton_method(mTagLib, &quot;n&quot;, n, -1);</div></div>
<p>Le dernier argument lors de la déclaration de la méthode <b>TagLib.n</b> vaut <b>-1</b> ce qui indique que la méthode ne possède pas un nombre d&rsquo;arguments fixees. La fonction <b>rb_scan_args</b> permet de récupérer de manière propre les paramètres passés à la méthode. Le troisième argument de cette fonction est une chaîne de caractère représentant deux chiffres. Le premier indique le nombre de paramètres obligatoires, le second indique le nombre de paramètres optionnels.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">VALUE <br />
n1(VALUE str) <br />
{ <br />
&nbsp; &nbsp; return rb_funcall(rb_stdout, rb_intern(&quot;puts&quot;), 1, str); <br />
} <br />
&nbsp;<br />
VALUE <br />
n(int argc, VALUE* argv, VALUE self) <br />
{ <br />
&nbsp; &nbsp; VALUE tab; <br />
&nbsp;<br />
&nbsp; &nbsp; rb_scan_args(argc, argv, &quot;01&quot;, &amp;tab); <br />
&nbsp; &nbsp; if (NIL_P(tab)) <br />
&nbsp; &nbsp; &nbsp; &nbsp; tab=rb_ary_new3(2, rb_str_new2(&quot;Salut&quot;), rb_str_new2(&quot;Re&quot;)); <br />
&nbsp; &nbsp; rb_funcall(tab, rb_intern(&quot;to_a&quot;), 0); <br />
&nbsp;<br />
&nbsp; &nbsp; rb_iterate(rb_each, tab, n1, Qnil); <br />
&nbsp; &nbsp; return RARRAY(tab)-&gt;ptr[0]; <br />
}</div></div>
<p><b>TagLib.n</b> peut donc être appelée avec un paramètre ou sans. Si aucun argument n&rsquo;a été passé (<b>tab=nil</b>), tab est initialisé en créant un tableau contenant deux objets <b>String</b>. On vérifie ensuite que <b>tab</b> appartient à la classe <b>Array</b> ou s&rsquo;en rapproche (<a href="http://fr.wikipedia.org/wiki/Duck_typing">duck typing</a>). <b>rb_funcall</b> permet d&rsquo;appeler une méthode (deuxième argument) d&rsquo;un objet (premier argument) avec un certain nombre (troisième argument) de paramètres (arguments suivant). <b>rb_intern</b> permet d&rsquo;obtenir la méthode à partir d&rsquo;une chaîne de caractères.<br />
La fonction <b>n1</b> est ensuite appelé pour chacun des éléments du tableau grâce à <b>rb_iterate</b>. LA méthode retourne, finalement, le premier élément de <b>tab</b>, la macro <b>RARRAY</b> permettant d&rsquo;accéder à la structure interne d&rsquo;un objet de la classe <b>Array</b>, le champ <b>ptr</b> permettant d&rsquo;accéder aux éléments.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&gt; TagLib.n <br />
Salut <br />
Re <br />
=&gt; &quot;Salut&quot; <br />
&gt; TagLib.n([&quot;Bonjour&quot;]) <br />
Bonjour <br />
=&gt; &quot;Bonjour&quot;</div></div>
<h2>Liens utiles</h2>
<p>Quelques liens qui m&rsquo;ont aidé à écrire des extensions pour ruby en C :<br />
le fichier README.EXt fourni avec ruby,<br />
<a href="http://ruby-doc.org/docs/ProgrammingRuby/html/ext_ruby.html">ruby-doc</a>.<br />
En ce qui concerne taglib :<br />
l&rsquo;exemple dans les sources de taglib,<br />
le fichier bindings/c/tag_c.h.</p>
<h2>Sources</h2>
<p>Le code, présenté dans ces billets, implémentant le module, <b>TagLib</b> est téléchargeable <a href="http://zik.developpez.com/blog/c_ext/source/taglib2.tar.bz2">ici</a>.</p>
<h2>Conclusion</h2>
<p>Cette série d&rsquo;articles est finie. J&rsquo;espère qu&rsquo;ils vous seront utiles.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Adapter une bibliothèque C pour ruby (4)</title>
		<link>https://blog.developpez.com/zik/p9357/ruby/adapter_une_bibliotheque_c_pour_ruby_4</link>
		<comments>https://blog.developpez.com/zik/p9357/ruby/adapter_une_bibliotheque_c_pour_ruby_4#comments</comments>
		<pubDate>Tue, 05 Oct 2010 23:43:54 +0000</pubDate>
		<dc:creator><![CDATA[vinc-mai]]></dc:creator>
				<category><![CDATA[debian-fr]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Ce quatrième billet présente comment obtenir une documentation grâce à rdoc : il suffit de commenter les fichiers sources. Documentation Commenter Pour documenter les méthodes de la classe TagLib::File, il suffit de commenter les différentes fonctions les implémentant. La méthode title permet d&#8217;obtenir le titre d&#8217;une piste. On l&#8217;indique en commentaire juste avant la fonction file_get_title. /*Get track title*/ VALUE file_get_title(VALUE self) Par défaut, les paramètres d&#8217;une méthode sont nommés p1, p2, &#8230;. Pour la [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Ce quatrième billet présente comment obtenir une documentation grâce à <a href="http://rdoc.sourceforge.net/">rdoc</a> : il suffit de commenter les fichiers sources.</p>
<h2>Documentation</h2>
<h3>Commenter</h3>
<p>Pour documenter les méthodes de la classe <b>TagLib::File</b>, il suffit de commenter les différentes fonctions les implémentant.</p>
<p>La méthode <b>title</b> permet d&rsquo;obtenir le titre d&rsquo;une piste. On l&rsquo;indique en commentaire juste avant la fonction <b>file_get_title</b>.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">/*Get track title*/ <br />
VALUE <br />
file_get_title(VALUE self)</div></div>
<p>Par défaut, les paramètres d&rsquo;une méthode sont nommés <b>p1, p2, &#8230;</b>. Pour la méthode <b>title=</b>, on utilise l&rsquo;instruction <b>call-seq:</b> pour afficher le texte <b>title=title</b> (au lieu de <b>title=(p1)</b>).</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">/* <br />
call-seq: title=title <br />
&nbsp;<br />
Set track title to title <br />
&nbsp;<br />
title: a string <br />
*/ <br />
VALUE <br />
file_set_title(VALUE self, VALUE title)</div></div>
<p>La méthode <b>initialize</b> ne devrait jamais être appelée directement depuis un code ruby. On utilise l&rsquo;instruction <b>:nodoc:</b> pour indiquer que la méthode ne doit pas apparaitre dans la documentation.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">/*:nodoc:*/ <br />
VALUE <br />
file_init(VALUE self, VALUE path)</div></div>
<p>J&rsquo;indique que je ne désire pas commenter le module <b>TagLib</b> en plaçant un commentaire vide afin d&rsquo;éviter que rdoc utilise un commentaire non-désiré.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">/* */ <br />
&nbsp; mTagLib=rb_define_module(&quot;TagLib&quot;);</div></div>
<p>Dans le fichier lib/raglib2.rb, j&rsquo;ajoute la directive <b>:main:</b> afin que la page initiale de la documentation pointe sur la classe <b>TagLib::File</b>.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">#:main: TagLib::File <br />
module TagLib</div></div>
<p>Bizarrement, cette directive ne semble pas fonctionner si elle est placée dans le fichier taglib2.c.</p>
<h3>Produire la documentation</h3>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">rdoc --exclude extconf.rb</div></div>
<p>Le fichier doc/index.html est créé.<br />
<img src="http://zik.developpez.com/blog/c_ext/pix/rdoc.png" alt="aperçu de la documentation" title="Documentation" /></p>
<h2>Conclusion</h2>
<p>Rendez-vous pour le dernier billet où j&rsquo;introduirai quelques concepts que je n&rsquo;ai pas utilisé dans le module <b>TagLib</b>.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Adapter une bibliothèque C pour ruby (3)</title>
		<link>https://blog.developpez.com/zik/p9348/ruby/adapter_une_bibliotheque_c_pour_ruby_3</link>
		<comments>https://blog.developpez.com/zik/p9348/ruby/adapter_une_bibliotheque_c_pour_ruby_3#comments</comments>
		<pubDate>Mon, 04 Oct 2010 15:47:34 +0000</pubDate>
		<dc:creator><![CDATA[vinc-mai]]></dc:creator>
				<category><![CDATA[debian-fr]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Cet article fait suite au premier et deuxième billets dans lesquels nous avons vu comment créer un objet de la classe TagLib::File. Cet objet utilise les fonctions de la bibliothèque taglib, écrite en C, afin d&#8217;accéder aux tags de fichiers audio. Dans ce billet, nous verrons comment obtenir les valeurs des tags et comment modifier un tag. Jouer avec les tags Accéder au tag La structure tgFileData contient un champ tag qui permettra d&#8217;accéder au [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Cet article fait suite au <a href="http://blog.developpez.com/zik/p9266/ruby/adapter-une-bibliotheque-c-pour-ruby-1/">premier</a> et <a href="http://blog.developpez.com/zik/p9343/ruby/adapter-une-bibliotheque-c-pour-ruby-2/">deuxième</a> billets dans lesquels nous avons vu comment créer un objet de la classe <b>TagLib::File</b>. Cet objet utilise les fonctions de la bibliothèque taglib, écrite en C, afin d&rsquo;accéder aux tags de fichiers audio. Dans ce billet, nous verrons comment obtenir les valeurs des tags et comment modifier un tag.</p>
<p><span id="more-17"></span></p>
<h2>Jouer avec les tags</h2>
<h3>Accéder au tag</h3>
<p>La structure <b>tgFileData</b> contient un champ <b>tag</b> qui permettra d&rsquo;accéder au tag du fichier. Il a été initialisé avec la valeur <b>NULL</b>. La fonction <b>file_tag</b> retourne la valeur de ce champ après l&rsquo;avoir complété au besoin.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">TagLib_Tag * <br />
file_tag(VALUE self) <br />
{ <br />
&nbsp; &nbsp; tgFileData *d; <br />
&nbsp; &nbsp; TagLib_Tag *tgTag; <br />
&nbsp;<br />
&nbsp; &nbsp; Data_Get_Struct(self, tgFileData, d); <br />
&nbsp; &nbsp; if (d-&gt;tag==NULL) <br />
&nbsp; &nbsp; { <br />
&nbsp; &nbsp; &nbsp; &nbsp; tgTag=taglib_file_tag(d-&gt;file); <br />
&nbsp; &nbsp; &nbsp; &nbsp; if (tgTag==NULL) <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;rb_raise(eBadTag, &quot;Bad tag&quot;); <br />
&nbsp; &nbsp; &nbsp; &nbsp; d-&gt;tag=tgTag; <br />
&nbsp; } <br />
&nbsp; &nbsp; return d-&gt;tag; <br />
}</div></div>
<p>La macro <b>Data_Get_Struct</b> permet d&rsquo;accéder à la structure <b>tgFileData</b> de notre objet. Si le champ <b>tag</b> n&rsquo;est pas rempli, on récupère sa valeur grâce à la fonction <b>taglib_file_tag</b> de la bibliothèque taglib. Une exception est levée dans le cas où cette dernière fonction faillirait. La valeur du champ est finalement retournée.</p>
<h3>Obtenir le titre d&rsquo;une piste audio</h3>
<p>Afin d&rsquo;obtenir le titre contenu dans un tag, une méthode <b>title</b> est ajoutée à la classe <b>TagLib::File</b>, dans la fonction <b>Init_taglib2</b>.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">rb_define_method(cFile, &quot;title&quot;, file_get_title, 0);</div></div>
<p>La fonction <b>file_get_title</b> implémente la méthode <b>TagLib::File#title</b></p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">VALUE <br />
file_get_title(VALUE self) <br />
{ <br />
&nbsp; VALUE str; <br />
&nbsp;<br />
&nbsp; str=rb_str_new2(taglib_tag_title(file_tag(self))); <br />
&nbsp; taglib_tag_free_strings; <br />
&nbsp; &nbsp; return str; <br />
}</div></div>
<p>La valeur du titre est obtenu grâce à la fonction <b>taglib_tag_title</b> qui prend la valeur du champ tag de la structure interne <b>tgFileData</b>. La fonction <b>rb_str_new2</b> transforme cette valeur obtenue sous la forme d&rsquo;un pointeur sur chaîne de caractères en un objet ruby de la classe <b>String</b>. La mémoire allouée par taglib pour cette opération est libérée avant de retourner l&rsquo;objet.</p>
<h3>Modifier le titre d&rsquo;une piste audio</h3>
<p>La méthode <b>TagLib::File#title=</b>, prenant un argument, est ajoutée.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">rb_define_method(cFile, &quot;title=&quot;, file_set_title, 1);</div></div>
<p>La fonction<b>file_set_title</b> utilise la bibliothèque taglib pour modifier le tag. Une nouvelle fois, la macro <b>StringValuePtr</b> est utilisée pour convertir une variable du type <b>VALUE</b> vers le type <b>char *</b>. Une fonction implémentant une méthode accessible depuis ruby doit obligatoirement retournée une valeur du type <b>VALUE</b>. J&rsquo;ai choisi ici de retourner la chaîne de caractère passée en argument.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">VALUE <br />
file_set_title(VALUE self, VALUE title) <br />
{ <br />
&nbsp; &nbsp; taglib_tag_set_title(file_tag(self), StringValuePtr(title)); <br />
&nbsp; &nbsp; return title; <br />
}</div></div>
<p><em>Il me semble que traditionnellement les méthodes du type <b>variable=</b> retourne l&rsquo;argument alors que les méthodes du type <b>set_variable</b> retourne l&rsquo;objet. La troisième possibilité étant de retourner <b>nil</b>.</em></p>
<h3>Sauvegarder les modifications</h3>
<p>Après avoir modifié le titre à l&rsquo;aide de la méthode vue au précédent paragraphe, il faut écrire cette modification dans le fichier audio.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">rb_define_method(cFile, &quot;save&quot;, file_save, 0);</div></div>
<p>La méthode <b>TagLib::File#save</b> permet cette écriture. La méthode retourne <b>true</b> si l&rsquo;opération est réussie ou <b>false</b>.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">VALUE <br />
file_save(VALUE self) <br />
{ <br />
&nbsp; &nbsp; tgFileData *data; <br />
&nbsp;<br />
&nbsp; &nbsp; Data_Get_Struct(self, tgFileData, data); <br />
&nbsp; &nbsp; if (taglib_file_save(data-&gt;file)) <br />
&nbsp; &nbsp; { <br />
&nbsp; &nbsp; &nbsp; &nbsp; return Qtrue; <br />
&nbsp; } <br />
&nbsp; &nbsp; else <br />
&nbsp; &nbsp; { <br />
&nbsp; &nbsp; &nbsp; &nbsp; return Qfalse; <br />
&nbsp; } <br />
}</div></div>
<p>La fonction <b>taglib_file_save</b> réalise l&rsquo;écriture après avoir accédé au champ <b>file</b> de la structure interne de notre objet ruby.</p>
<h3>Tester le code</h3>
<p>Voici le contenu du fichier taglib2.c</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ cat taglib2.c <br />
#include &lt;ruby.h&gt; <br />
#include &lt;taglib/tag_c.h&gt; <br />
&nbsp;<br />
typedef struct <br />
{ <br />
&nbsp; &nbsp; TagLib_File *file; <br />
&nbsp; &nbsp; TagLib_Tag *tag; <br />
&nbsp; &nbsp; const TagLib_AudioProperties *audio; <br />
} tgFileData; <br />
&nbsp;<br />
VALUE mTagLib; <br />
VALUE eBadPath, eBadFile, eBadTag, eBadAudioProperties; <br />
VALUE cFile; <br />
&nbsp;<br />
static void <br />
free_tgFileData(tgFileData *d) <br />
{ <br />
&nbsp; &nbsp; taglib_file_free(d-&gt;file); <br />
&nbsp; &nbsp; free(d); <br />
} <br />
&nbsp;<br />
TagLib_Tag * <br />
file_tag(VALUE self) <br />
{ <br />
&nbsp; &nbsp; tgFileData *d; <br />
&nbsp; &nbsp; TagLib_Tag *tgTag; <br />
&nbsp;<br />
&nbsp; &nbsp; Data_Get_Struct(self, tgFileData, d); <br />
&nbsp; &nbsp; if (d-&gt;tag==NULL) <br />
&nbsp; &nbsp; { <br />
&nbsp; &nbsp; &nbsp; &nbsp; tgTag=taglib_file_tag(d-&gt;file); <br />
&nbsp; &nbsp; &nbsp; &nbsp; if (tgTag==NULL) <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;rb_raise(eBadTag, &quot;Bad tag&quot;); <br />
&nbsp; &nbsp; &nbsp; &nbsp; d-&gt;tag=tgTag; <br />
&nbsp; } <br />
&nbsp; &nbsp; return d-&gt;tag; <br />
} <br />
&nbsp;<br />
VALUE <br />
file_init(VALUE self, VALUE path) <br />
{ <br />
&nbsp; &nbsp; rb_iv_set(self, &quot;@path&quot;, path); <br />
&nbsp; &nbsp; return self; <br />
} <br />
&nbsp;<br />
VALUE <br />
file_new(VALUE self, VALUE path) <br />
{ <br />
&nbsp; &nbsp; TagLib_File *tgFile; <br />
&nbsp; &nbsp; tgFileData *data; <br />
&nbsp; &nbsp; VALUE rbData; <br />
&nbsp; &nbsp; VALUE argv[1]; <br />
&nbsp;<br />
&nbsp; &nbsp; tgFile=taglib_file_new(StringValuePtr(path)); <br />
&nbsp; &nbsp; if (tgFile==NULL) <br />
&nbsp; &nbsp; &nbsp; &nbsp; rb_raise(eBadPath, &quot;Bad path&quot;); <br />
&nbsp;<br />
&nbsp; &nbsp; data=ALLOC(tgFileData); <br />
&nbsp; &nbsp; data-&gt;file=tgFile; <br />
&nbsp; &nbsp; data-&gt;tag=NULL; <br />
&nbsp; &nbsp; data-&gt;audio=NULL; <br />
&nbsp; &nbsp; rbData=Data_Wrap_Struct(cFile, 0, free_tgFileData, data); <br />
&nbsp; &nbsp; argv[0]=path; <br />
&nbsp; &nbsp; rb_obj_call_init(rbData, 1, argv); <br />
&nbsp; &nbsp; return rbData; <br />
} <br />
&nbsp;<br />
VALUE <br />
file_save(VALUE self) <br />
{ <br />
&nbsp; &nbsp; tgFileData *data; <br />
&nbsp;<br />
&nbsp; &nbsp; Data_Get_Struct(self, tgFileData, data); <br />
&nbsp; &nbsp; if (taglib_file_save(data-&gt;file)) <br />
&nbsp; &nbsp; { <br />
&nbsp; &nbsp; &nbsp; &nbsp; return Qtrue; <br />
&nbsp; } <br />
&nbsp; &nbsp; else <br />
&nbsp; &nbsp; { <br />
&nbsp; &nbsp; &nbsp; &nbsp; return Qfalse; <br />
&nbsp; } <br />
} <br />
&nbsp;<br />
VALUE <br />
file_get_title(VALUE self) <br />
{ <br />
&nbsp; VALUE str; <br />
&nbsp;<br />
&nbsp; str=rb_str_new2(taglib_tag_title(file_tag(self))); <br />
&nbsp; taglib_tag_free_strings; <br />
&nbsp; &nbsp; return str; <br />
} <br />
&nbsp;<br />
VALUE <br />
file_set_title(VALUE self, VALUE title) <br />
{ <br />
&nbsp; &nbsp; taglib_tag_set_title(file_tag(self), StringValuePtr(title)); <br />
&nbsp; &nbsp; return title; <br />
} <br />
&nbsp;<br />
void <br />
Init_taglib2() <br />
{ <br />
&nbsp; mTagLib=rb_define_module(&quot;TagLib&quot;); <br />
&nbsp;<br />
&nbsp; eBadPath=rb_define_class_under(mTagLib, &quot;BadPath&quot;, rb_eException); <br />
&nbsp; &nbsp; eBadFile=rb_define_class_under(mTagLib, &quot;BadFile&quot;, rb_eException); <br />
&nbsp; &nbsp; eBadTag=rb_define_class_under(mTagLib, &quot;BadTag&quot;, rb_eException); <br />
&nbsp; &nbsp; eBadAudioProperties=rb_define_class_under(mTagLib, &quot;BadAudioProperties&quot;, rb_eException); <br />
&nbsp;<br />
&nbsp; &nbsp; cFile=rb_define_class_under(mTagLib, &quot;File&quot;, rb_cObject); <br />
&nbsp; &nbsp; rb_define_singleton_method(cFile, &quot;new&quot;, file_new, 1); <br />
&nbsp; &nbsp; rb_define_method(cFile, &quot;initialize&quot;, file_init, 1); <br />
&nbsp; &nbsp; rb_define_method(cFile, &quot;save&quot;, file_save, 0); <br />
&nbsp; &nbsp; rb_define_method(cFile, &quot;title&quot;, file_get_title, 0); <br />
&nbsp; &nbsp; rb_define_method(cFile, &quot;title=&quot;, file_set_title, 1); <br />
}</div></div>
<p>Après avoir recompilé, nous pouvons tester les méthodes ajoutées dans cet article.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ make <br />
$ irb <br />
&gt; require './lib/taglib2.rb' <br />
=&gt; true <br />
&gt; t=TagLib::File.new('Musique/01 - Blue Bird.mp3') <br />
=&gt; #&lt;TagLib::File:0xb74ca844&gt; <br />
&gt; t.title <br />
=&gt; &quot;Blue Bird&quot; <br />
&gt; t.title='toto' <br />
=&gt; &quot;toto&quot; <br />
&gt; t.title <br />
=&gt; &quot;toto&quot; <br />
&gt; t.save <br />
=&gt; true</div></div>
<h2>Conclusion</h2>
<p>Nous avons vu comment accéder au titre d&rsquo;une piste audio. Accéder aux autres propriétés (auteur, album, etc) n&rsquo;est pas plus difficile. Je ne développerai pas cet aspect. Les sources du code complet seront cependant mis à votre disposition lors du dernier article. Le prochain article devrait parler de l&rsquo;aspect documentation.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Adapter une bibliothèque C pour ruby (2)</title>
		<link>https://blog.developpez.com/zik/p9343/ruby/adapter_une_bibliotheque_c_pour_ruby_2</link>
		<comments>https://blog.developpez.com/zik/p9343/ruby/adapter_une_bibliotheque_c_pour_ruby_2#comments</comments>
		<pubDate>Sun, 03 Oct 2010 14:37:27 +0000</pubDate>
		<dc:creator><![CDATA[vinc-mai]]></dc:creator>
				<category><![CDATA[debian-fr]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Cet article fait suite au premier. Il s&#8217;intéresse à la classe principale qui permettra de manipuler les tags de fichiers audio. Addendum Afin que notre bibliothèque soit correctement liée à taglib lors de la compilation, il faut ajouter la ligne have_library(&#8216;tag_c&#8217;) &#124;&#124; exit(1) au fichier extconf.rb, juste avant d&#8217;invoquer la création du Makefile. Créer un objet appartenant à la classe TagLib::File Ajouter une classe File Après avoir déclaré une nouvelle variable de type VALUE (cFile), [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Cet article fait suite au <a href="http://blog.developpez.com/zik/p9266/ruby/adapter-une-bibliotheque-c-pour-ruby-1/">premier</a>. Il s&rsquo;intéresse à la classe principale qui permettra de manipuler les tags de fichiers audio.</p>
<p><span id="more-16"></span></p>
<h2>Addendum</h2>
<p>Afin que notre bibliothèque soit correctement liée à taglib lors de la compilation, il faut ajouter la ligne <b>have_library(&lsquo;tag_c&rsquo;) || exit(1)</b> au fichier <b>extconf.rb</b>, juste avant d&rsquo;invoquer la création du <b>Makefile</b>.</p>
<h2>Créer un objet appartenant à la classe <b>TagLib::File</b></h2>
<h3>Ajouter une classe <b>File</b></h3>
<p>Après avoir déclaré une nouvelle variable de type VALUE (<b>cFile</b>), je définis une nouvelle classe nommée <b>File</b> appartenant au module <b>TagLib</b>. Elle hérite de la classe <b>Objet</b> (classe mère de toutes les classes en ruby).</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ cat taglib2.c <br />
#include &lt;ruby.h&gt; <br />
#include &lt;taglib/tag_c.h&gt; <br />
&nbsp;<br />
VALUE mTagLib; <br />
VALUE eBadPath, eBadFile, eBadTag, eBadAudioProperties; <br />
VALUE cFile; <br />
&nbsp;<br />
void <br />
Init_taglib2() <br />
{ <br />
&nbsp; mTagLib=rb_define_module(&quot;TagLib&quot;); <br />
&nbsp;<br />
&nbsp; eBadPath=rb_define_class_under(mTagLib, &quot;BadPath&quot;, rb_eException); <br />
&nbsp; &nbsp; eBadFile=rb_define_class_under(mTagLib, &quot;BadFile&quot;, rb_eException); <br />
&nbsp; &nbsp; eBadTag=rb_define_class_under(mTagLib, &quot;BadTag&quot;, rb_eException); <br />
&nbsp; &nbsp; eBadAudioProperties=rb_define_class_under(mTagLib, &quot;BadAudioProperties&quot;, rb_eException); <br />
&nbsp;<br />
&nbsp; &nbsp; cFile=rb_define_class_under(mTagLib, &quot;File&quot;, rb_cObject); <br />
}</div></div>
<p>Après avoir recompilé notre bibliothèque, je peux créer un objet de type <b>TagLib::File</b>, cette classe ayant héritée de la méthode <b>Objet.new</b>.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ make distclean <br />
$ ruby extconf.rb <br />
$ make <br />
$ irb <br />
&gt; require './lib/taglib2.rb' <br />
&gt; TagLib::File.superclass <br />
=&gt; Object <br />
&gt; TagLib::File.new <br />
=&gt; #&lt;TagLib::File:0xb75145e8&gt;</div></div>
<h3>Redéfinir la méthode new</h3>
<p>Dans la fonction <b>Init_taglib2</b>, je redéfinis la méthode de classe <b>new</b> (et non une méthode d&rsquo;instance). C&rsquo;est pourquoi j&rsquo;utilise <b>rb_define_singleton_method</b> et non <b>rb_define_method</b>. Cette fonction prend quatre arguments : l&rsquo;object pour lequel la méthode va &#7871;tre (re)défini, le nom de la méthode, la fonction écrite en C à appeler, le nombre d&rsquo;aguments passés à la fonction.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">rb_define_singleton_method(cFile, &quot;new&quot;, file_new, 1);</div></div>
<p>Voici la fonction <b>file_new</b> qui redéfinit <b>TagLib::File.new</b>.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">typedef struct <br />
{ <br />
&nbsp; &nbsp; TagLib_File *file; <br />
&nbsp; &nbsp; TagLib_Tag *tag; <br />
&nbsp; &nbsp; const TagLib_AudioProperties *audio; <br />
} tgFileData; <br />
&nbsp;<br />
VALUE <br />
file_new(VALUE self, VALUE path) <br />
{ <br />
&nbsp; &nbsp; TagLib_File *tgFile; <br />
&nbsp; &nbsp; tgFileData *data; <br />
&nbsp; &nbsp; VALUE rbData; <br />
&nbsp; &nbsp; VALUE argv[1]; <br />
&nbsp;<br />
&nbsp; &nbsp; tgFile=taglib_file_new(StringValuePtr(path)); <br />
&nbsp; &nbsp; if (tgFile==NULL) <br />
&nbsp; &nbsp; &nbsp; &nbsp; rb_raise(eBadPath, &quot;Bad path&quot;); <br />
&nbsp;<br />
&nbsp; &nbsp; data=ALLOC(tgFileData); <br />
&nbsp; &nbsp; data-&gt;file=tgFile; <br />
&nbsp; &nbsp; data-&gt;tag=NULL; <br />
&nbsp; &nbsp; data-&gt;audio=NULL; <br />
&nbsp; &nbsp; rbData=Data_Wrap_Struct(cFile, 0, free_tgFileData, data); <br />
&nbsp; &nbsp; argv[0]=path; <br />
&nbsp; &nbsp; rb_obj_call_init(rbData, 1, argv); <br />
&nbsp; &nbsp; return rbData; <br />
}</div></div>
<p>La méthode <b>new</b> est appelée avec un seul argument qui est une chaîne de caractère ruby représentant un chemin vers un fichier audio. Cependant, la function <b>file_new</b> possède un argument supplémentaire : le premier qui représente l&rsquo;objet auquel s&rsquo;applique la méthode.<br />
La fonction <b>taglib_file_new</b> permet de créer une structure qui représente un fichier audio pour la bibliothèque taglib. Elle requière, comme argument, un pointeur sur une chaîne de caractère C obtenu grâce à la macro <b>StringValuePtr</b>.<br />
La variable <b>data</b> est une structure qui représentera un objet de type <b>TagLib::File</b> au niveau du langage C. Elle est composée de trois champs représentant le fichier audio (<b>file</b>), le tag associé au fichier (<b>tag</b>) et les propriétés audio du fichier (<b>audio</b>). Après avoir alloué la mémoire nécéssaire (grâce à la macro <b>ALLOC</b>) et initialiser ses différents champs, cette structure est transformée en object ruby grâce à l&rsquo;aide de la macro <b>Data_Wrap_Struct</b>. Cet object <b>rbData</b> appartient à la classe <b>TagLib::File</b> (représenté par la variable <b>cFile</b>). Lorsque l&rsquo;objet est détruit, la fonction <b>free_tgFileData</b> est appelée.<br />
Enfin, l&rsquo;objet est initialisé (<b>rb_obj_call_init</b>).</p>
<h3>Écrire la méthode initialize</h3>
<p>La méthode <b>new</b> appelle la méthode <b>initialize</b> qui, comme son nom l&rsquo;indique, s&rsquo;occupe d&rsquo;initialiser l&rsquo;objet, en particulier ses variables d&rsquo;instance.<br />
Cette dernière méthode est déclarée  dans la fonction <b>Init_taglib2</b>.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">rb_define_method(cFile, &quot;initialize&quot;, file_init, 1);</div></div>
<p>Ici, la méthode <b>initialize</b> se borne à valoriser la variable d&rsquo;instance <b>@path</b>.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">VALUE <br />
file_init(VALUE self, VALUE path) <br />
{ <br />
&nbsp; &nbsp; rb_iv_set(self, &quot;@path&quot;, path); <br />
&nbsp; &nbsp; return self; <br />
}</div></div>
<h3>Libérer la mémoire</h3>
<p>Lorsque le ramasse-miettes de ruby détruit un object de type <b>TagLib::File</b>, il utilise la fonction indiquée lors de l&rsquo;appel à la macro <b>Data_Wrap_Struct</b>, pour libérer la mémoire allouée à cet objet.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">static void <br />
free_tgFileData(tgFileData *d) <br />
{ <br />
&nbsp; &nbsp; taglib_file_free(d-&gt;file); <br />
&nbsp; &nbsp; free(d); <br />
}</div></div>
<h3>Code</h3>
<p>Voici l&rsquo;ensemble du code :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ cat extconf.rb <br />
require 'mkmf' <br />
&nbsp;<br />
have_header('ruby.h') || exit(1) <br />
have_header('taglib/tag_c.h') || exit(1) <br />
have_library('tag_c') || exit(1) <br />
&nbsp;<br />
create_makefile(&quot;taglib2&quot;)</div></div>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ cat lib/taglib2.rb <br />
require &quot;taglib2.so&quot; <br />
&nbsp;<br />
module TagLib <br />
VERSION=[0, 0, 1] <br />
end</div></div>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ cat taglib2.c <br />
#include &lt;ruby.h&gt; <br />
#include &lt;taglib/tag_c.h&gt; <br />
&nbsp;<br />
typedef struct <br />
{ <br />
&nbsp; &nbsp; TagLib_File *file; <br />
&nbsp; &nbsp; TagLib_Tag *tag; <br />
&nbsp; &nbsp; const TagLib_AudioProperties *audio; <br />
} tgFileData; <br />
&nbsp;<br />
VALUE mTagLib; <br />
VALUE eBadPath, eBadFile, eBadTag, eBadAudioProperties; <br />
VALUE cFile; <br />
&nbsp;<br />
static void <br />
free_tgFileData(tgFileData *d) <br />
{ <br />
&nbsp; &nbsp; taglib_file_free(d-&gt;file); <br />
&nbsp; &nbsp; free(d); <br />
} <br />
VALUE <br />
file_init(VALUE self, VALUE path) <br />
{ <br />
&nbsp; &nbsp; rb_iv_set(self, &quot;@path&quot;, path); <br />
&nbsp; &nbsp; return self; <br />
} <br />
&nbsp;<br />
VALUE <br />
file_new(VALUE self, VALUE path) <br />
{ <br />
&nbsp; &nbsp; TagLib_File *tgFile; <br />
&nbsp; &nbsp; tgFileData *data; <br />
&nbsp; &nbsp; VALUE rbData; <br />
&nbsp; &nbsp; VALUE argv[1]; <br />
&nbsp;<br />
&nbsp; &nbsp; tgFile=taglib_file_new(StringValuePtr(path)); <br />
&nbsp; &nbsp; if (tgFile==NULL) <br />
&nbsp; &nbsp; &nbsp; &nbsp; rb_raise(eBadPath, &quot;Bad path&quot;); <br />
&nbsp;<br />
&nbsp; &nbsp; data=ALLOC(tgFileData); <br />
&nbsp; &nbsp; data-&gt;file=tgFile; <br />
&nbsp; &nbsp; data-&gt;tag=NULL; <br />
&nbsp; &nbsp; data-&gt;audio=NULL; <br />
&nbsp; &nbsp; rbData=Data_Wrap_Struct(cFile, 0, free_tgFileData, data); <br />
&nbsp; &nbsp; argv[0]=path; <br />
&nbsp; &nbsp; rb_obj_call_init(rbData, 1, argv); <br />
&nbsp; &nbsp; return rbData; <br />
} <br />
&nbsp;<br />
void <br />
Init_taglib2() <br />
{ <br />
&nbsp; mTagLib=rb_define_module(&quot;TagLib&quot;); <br />
&nbsp;<br />
&nbsp; eBadPath=rb_define_class_under(mTagLib, &quot;BadPath&quot;, rb_eException); <br />
&nbsp; &nbsp; eBadFile=rb_define_class_under(mTagLib, &quot;BadFile&quot;, rb_eException); <br />
&nbsp; &nbsp; eBadTag=rb_define_class_under(mTagLib, &quot;BadTag&quot;, rb_eException); <br />
&nbsp; &nbsp; eBadAudioProperties=rb_define_class_under(mTagLib, &quot;BadAudioProperties&quot;, rb_eException); <br />
&nbsp;<br />
&nbsp; &nbsp; cFile=rb_define_class_under(mTagLib, &quot;File&quot;, rb_cObject); <br />
&nbsp; &nbsp; rb_define_singleton_method(cFile, &quot;new&quot;, file_new, 1); <br />
&nbsp; &nbsp; rb_define_method(cFile, &quot;initialize&quot;, file_init, 1); <br />
}</div></div>
<h3>Tester le code</h3>
<p>Après une recompilation, on vérifie que la méthode <b>TagLib::File.new</b> est correctement appelée depuis l&rsquo;interpréteur irb.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ make <br />
$ irb <br />
&gt; require './lib/taglib2.rb' <br />
=&gt; true <br />
&gt; t=TagLib::File.new('Musique/01 - Blue Bird.mp3') <br />
=&gt; #&lt;TagLib::File:0xb74c29a0&gt; <br />
&gt; t.instance_variable_get(&quot;@path&quot;) <br />
=&gt; &quot;Musique/01 - Blue Bird.mp3&quot;</div></div>
<h2>Conclusion</h2>
<p>Lors de ce deuxième billet, nous avons interfacé une structure C avec un objet ruby, représentant un fichier audio. Dans le prochain billet, nous écrirons les méthodes qui permettent d&rsquo;accéder au tag de ce fichier.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Icône dans la zone de notification en ruby/Gtk</title>
		<link>https://blog.developpez.com/zik/p8460/ruby/icone_dans_la_zone_de_notification_en_ru</link>
		<comments>https://blog.developpez.com/zik/p8460/ruby/icone_dans_la_zone_de_notification_en_ru#comments</comments>
		<pubDate>Tue, 15 Dec 2009 08:16:16 +0000</pubDate>
		<dc:creator><![CDATA[vinc-mai]]></dc:creator>
				<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Le présent article explique comment afficher une icône dans la zone de notification à l&#8217;aide de la bibliothèque ruby/Gtk2. Les fonctionnalités présentées dans cet article sont implémentées par la classe StatusIcon. Cette classe est documentée, en anglais, sur le hiki du projet ruby-gnome2. Un code fonctionnel, récapitulant les notions abordées, est donné en fin d&#8217;article. Afficher une icône Nous allons tout d&#8217;abord afficher une icône dans la zone de notification. 1 #!/usr/bin/env ruby 2 3 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Le présent article explique comment afficher une icône dans la zone de notification à l&rsquo;aide de la bibliothèque ruby/Gtk2.</p>
<p><span id="more-15"></span></p>
<p>Les fonctionnalités présentées dans cet article sont implémentées par la classe <i>StatusIcon</i>. Cette classe est documentée, en anglais, sur le <a href="http://ruby-gnome2.sourceforge.jp/hiki.cgi?cmd=view&amp;p=Gtk%3A%3AStatusIcon">hiki</a> du projet ruby-gnome2. Un code fonctionnel, récapitulant les notions abordées, est donné en fin d&rsquo;article.</p>
<h2>Afficher une icône</h2>
<p>Nous allons tout d&rsquo;abord afficher une icône dans la zone de notification.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">1 #!/usr/bin/env ruby <br />
2 <br />
3 require 'gtk2' <br />
&nbsp;<br />
4 si=Gtk::StatusIcon.new <br />
5 si.stock=Gtk::Stock::DIALOG_INFO <br />
6 si.tooltip='StatusIcon' <br />
7 <br />
8 Gtk.main</div></div>
<p>Après avoir lancé le code ci-dessus dans une console, il est nécessaire d&rsquo;utiliser <i>Ctrl+C</i> pour récupérer la main.</p>
<p>Analysons le code. Nous chargeons tout d&rsquo;abord la bibliothèque ruby/Gtk2 (<i>ligne 1</i>), puis un objet icône est créé (<i>ligne 4</i>). L&rsquo;image utilisée pour afficher l&rsquo;icône est définie à la ligne suivante. Ici, une image commune est utilisée. Nous aurions pu utiliser une image personnelle grâce à la méthode <i>pixbuf=()</i> (<i><code class="codecolorer text default"><span class="text">si.pixbuf=Gdk::Pixbuf.new('/chemin/vers/image.svg')</span></code></i>). La méthode <i>tooltip=()</i> permet d&rsquo;indiquer le texte à afficher lorsque la souris survole l&rsquo;icône.</p>
<h2>Intéragir avec l&rsquo;icône</h2>
<p>Nous allons maintenant voir comment implémenter l&rsquo;intéraction entre la souris et l&rsquo;icône.</p>
<h3>Intéractions avec le bouton gauche de la souris</h3>
<p><code class="codecolorer text default"><span class="text">si.signal_connect('activate'){|icon| icon.blinking=!(icon.blinking?)}</span></code></p>
<p>La méthode <i>signal_connect</i> permet de guetter l&rsquo;émission d&rsquo;un signal. Le signal <i>activate</i> est émis lors d&rsquo;un clic gauche sur l&rsquo;icône. Le bloc appelé (<i>{|icon| icon.blinking=!(icon.blinking?)}</i>) modifie l&rsquo;état de l&rsquo;icône qui clignotera ou pas suivant le nombre de clics.</p>
<h3>Ajouter un menu</h3>
<p>Il est possible d&rsquo;ajouter un menu qui apparait lors d&rsquo;un clic droit sur l&rsquo;icône.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">info=Gtk::ImageMenuItem.new(Gtk::Stock::INFO) <br />
info.signal_connect('activate'){p &quot;Zone de notification : #{si.embedded?}&quot;; p &quot;Visible : #{si.visible?}&quot;; p &quot;Clignotant : #{si.blinking?}&quot;} <br />
quit=Gtk::ImageMenuItem.new(Gtk::Stock::QUIT) <br />
quit.signal_connect('activate'){Gtk.main_quit} <br />
menu=Gtk::Menu.new <br />
menu.append(info) <br />
menu.append(Gtk::SeparatorMenuItem.new) <br />
menu.append(quit) <br />
menu.show_all <br />
si.signal_connect('popup-menu'){|tray, button, time| menu.popup(nil, nil, button, time)}</div></div>
<p>Nous construisons un menu auquel nous ajoutons deux éléments (<i>info</i> et <i>quit</i>). Le menu est affiché par la méthode <i>popup</i> lorsque le signal <i>popup-menu</i>, indiquant un clic droit, est émis. L&rsquo;élément <i>quit</i> permet de quitter la boucle principale proprement. Un clic sur l&rsquo;élément <i>info</i> affiche en console trois informations. La méthode <i>embedded?</i> permet de vérifier la présence d&rsquo;une zone de notification. Certains bureaux n&rsquo;utilisent pas de zone de notification. Notre icône n&rsquo;est alors pas visible par l&rsquo;utilisateur.</p>
<h3>Intéractions avec la molette de la souris</h3>
<p>Si votre bibliothèque gtk est récente, vous pouvez surveiller les mouvements de la molette au niveau de l&rsquo;icône.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">si.signal_connect('scroll-event'){|icon, event| <br />
case event.direction <br />
when Gdk::EventScroll::UP <br />
&nbsp; p 'haut' <br />
when Gdk::EventScroll::DOWN <br />
&nbsp; p 'bas' <br />
end <br />
}</div></div>
<p>Surveillons le signal <i>scroll-event</i>. L&rsquo;objet <i>event</i> retourné appartient à la classe <i>Gdk::EventScroll</i>. La méthode <i>direction</i> de cet objet permet d&rsquo;obtenir le sens dans lequel la molette tourne.</p>
<p>Il est aussi possible de contrôler quels modificateurs (control, shift, alt, meta&#8230;) sont actifs lors de l&rsquo;intéraction. Remplacez le code précédent par le suivant.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">si.signal_connect('scroll-event'){|icon, event| <br />
modifier=event.state <br />
ctrl_shift=(Gdk::Window::CONTROL_MASK|Gdk::Window::SHIFT_MASK) <br />
mod=modifier&amp;ctrl_shift <br />
case mod <br />
when 0 <br />
&nbsp; p 'Aucun modificateur' <br />
when Gdk::Window::CONTROL_MASK <br />
&nbsp; p 'Control' <br />
when Gdk::Window::SHIFT_MASK <br />
&nbsp; p 'Shift' <br />
when (Gdk::Window::CONTROL_MASK|Gdk::Window::SHIFT_MASK) <br />
&nbsp; p 'Control+Shif' <br />
end <br />
}</div></div>
<p><i>event.state</i> est masque représentant l&rsquo;état de l&rsquo;ensemble des modificateurs, par exemple du clavier. Dans le cas présent, nous nous intéressons seulement aux modificateurs control et shift. À cet usage, nous filtrons les modificateurs complets avec un masque des modificateurs que nous voulons gérer. Puis nous comparons le résultat aux différents cas possibles.</p>
<h2>Récapitulatif</h2>
<p>Le code suivant est un exemple complet reprenant les notions vues dans cet article. N&rsquo;hésitez pas à réagir à cet article en laissant un commentaire.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">#!/usr/bin/env ruby <br />
&nbsp;<br />
require 'gtk2' <br />
&nbsp;<br />
###Icône <br />
si=Gtk::StatusIcon.new <br />
si.stock=Gtk::Stock::DIALOG_INFO <br />
#si.pixbuf=Gdk::Pixbuf.new('/path/to/image.svg') <br />
si.tooltip='StatusIcon' <br />
&nbsp;<br />
###Intéractions avec le bouton gauche de la souris <br />
si.signal_connect('activate'){|icon| icon.blinking=!(icon.blinking?)} <br />
&nbsp;<br />
###Intéractions avec le bouton droit de la souris <br />
#Construction d'un menu <br />
info=Gtk::ImageMenuItem.new(Gtk::Stock::INFO) <br />
info.signal_connect('activate'){p &quot;Présent : #{si.embedded?}&quot;; p &quot;Visible : #{si.visible?}&quot;; p &quot;Clignotant : #{si.blinking?}&quot;} <br />
quit=Gtk::ImageMenuItem.new(Gtk::Stock::QUIT) <br />
quit.signal_connect('activate'){Gtk.main_quit} <br />
menu=Gtk::Menu.new <br />
menu.append(info) <br />
menu.append(Gtk::SeparatorMenuItem.new) <br />
menu.append(quit) <br />
menu.show_all <br />
#Intéractions <br />
si.signal_connect('popup-menu'){|tray, button, time| menu.popup(nil, nil, button, time)} <br />
&nbsp;<br />
###Intéractions avec la molette de la souris <br />
si.signal_connect('scroll-event'){|icon, event| <br />
&nbsp; #Vérifier quels modificateurs ont été utilisés parmi control et shift. Les autres modificateurs ne sont pas pris en compte. <br />
&nbsp; mod=event.state&amp;(Gdk::Window::CONTROL_MASK|Gdk::Window::SHIFT_MASK) <br />
&nbsp; case mod <br />
&nbsp; when 0 <br />
&nbsp; &nbsp; p print_direction(event.direction) <br />
&nbsp; when Gdk::Window::CONTROL_MASK <br />
&nbsp; &nbsp; p 'Control+'+print_direction(event.direction) <br />
&nbsp; when Gdk::Window::SHIFT_MASK <br />
&nbsp; &nbsp; p 'Shift+'+print_direction(event.direction) <br />
&nbsp; when (Gdk::Window::CONTROL_MASK|Gdk::Window::SHIFT_MASK) <br />
&nbsp; &nbsp; p 'Control+Shift+'+print_direction(event.direction) <br />
&nbsp; end <br />
} <br />
&nbsp;<br />
def print_direction(direction) <br />
#Donne la direction de la molette <br />
&nbsp; case direction <br />
&nbsp; when Gdk::EventScroll::UP <br />
&nbsp; &nbsp; 'haut' <br />
&nbsp; when Gdk::EventScroll::DOWN <br />
&nbsp; &nbsp; 'bas' <br />
&nbsp; end <br />
end <br />
&nbsp;<br />
Gtk.main</div></div>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
