Je suis, depuis ce soir et pour deux semaines, en vacances.
Du coup je pars (ouais. J’aurais pas pris de vacances si c’était pas pour partir).

Mon avion pars donc mardi, pour Israel (oui carrément). Je vais être le photographe officiel pour le groupe de Lyon lors du pélerinage étudiant en terre sainte.
Suite à cela, il me faudra au moins le mois d’aout pour traiter toutes les photos prises pendant les 10 jours ou je serai là-bas.

Le seul article que j’ai antidaté étant celui de mes critiques de cinéma qui sera publié le lendemain de mon retour, il n’y aura aucun billet sur ce blog pendant toute cette période.
Je n’aurai pas non plus accès à mes mails.

A dans deux semaines donc.

Psst avant de partir j’ai refondu la home de refstats.
J’en ai beaucoup de critiques et la chose a déjà pas mal évolué. Mais personnelement, je suis content de moi (et niveau design/ergonomie, c’est pas souvent que je le suis).

Je me suis un peu amusé cette semaine en développant rapidement un widget Netvibes pourRefStats (annonce).
Vous pouvez voir celui-ci et l’installer sur votre page.

Et comme c’est un composant de l’application web refstats, il est sur Github.
Analysons rapidement la chose.

Nous avons tout d’abord des balises xml. Nous définissons l’auteur du plugin, la version de l’API utilisée et le fait qu’on est pas en debug.

<meta name="author" content="Damien MATHIEU" />
<meta name="description" content="Shows the evolution of your positions on Google and any other search engine via refstats.net." />
<meta name="apiVersion" content="1.0" />
<meta name="debugMode" content="false" />

Jusqu’à maintenant, pas grand chose d’intéressant. Mais si on descends un peu en dessous de l’inclusion des CSS de netvibes, on a :

<widget:preferences>
    <preference name="apikey" type="text" label="API Key" defaultValue="69dc57d333617ffcaa136109a0ff5e3d" />
    <preference name="engine" type="list" label="Engine" defaultValue="1" >
        <option value="0" label="all" />
        <option value="1" label="google.com" />
        <option value="2" label="google.fr" />
        <option value="4" label="google.ch" />
        <option value="5" label="google.be" />
        <option value="6" label="google.ca" />
        <option value="3" label="Yahoo!" />
    </preference>
</widget:preferences>

Pour comprendre ce que nous faisons, regardez ce que donne le widget (voir le lien « voir celui-ci » plus haut).
Et cliquez sur le bouton « Editer ». Vous constatez que nous avons les champs tels que définis dans les préférences ici.

Nous définissons ici un champ texte pour la clé d’API et une liste pour le moteur à utiliser.
Mais il existe d’autres types : text, boolean, hidden, password, range, list.
Ces options sont sauvegardées automatiquement lorsque vous validez et accessibles par la suite en javascript avec la méthode

widget.getValue('option_name');

Puisque nous parlons de javascript, attaquons-nous y.
Vous pouvez voir un

widget.onLoad = function() {
[...]
}

Cette méthode est exécutée lors du chargement du widget. Et à chaque modification des paramètres de celui-ci.
Les autres méthodes utilisées ici sont des méthodes internes au script. Je vous laisse les analyser vous même si cela vous amuse.

Vous constaterez cependant deux choses :
Les appels ajax. L’API RefStats retourne du json. Je fais donc appel à la méthode UWA.Data.getJson, qui prends deux arguments : l’url de la page à appeller.
Et la méthode à appeller avec les données une fois celles-ci reçues.
A vous après de traiter vos données, que cela soit du json avec getJson, du xml avec getXml ou du texte avec getText.

Vous constaterez également l’utilisation de la méthode widget.setBody();.
Cette méthode permet de définir le contenu du widget de manière dynamique. Ici, je redéfinis entièrement le contenu à chaque fois en me basant sur les données que j’ai en variables.
Rien ne vous empêche cependant de manipuler le dom de manière plus fine. L’objet widget possède une méthode createElement.

Bon, cet article est particulièrement concis. Mais il deviendrait trop long si je commencais à détailler entièrement ce qui est déjà indiqué dans la documentation Netvibes. Je vous laisse donc vous y référer.
Mais je pense que cela fait déjà un bon début. Rien qu’avec ça, il est déjà possible de faire deux ou trois trucs sympa :)

Lorsque vous développez une application en utilisant un framework quelconque, vous vous retrouvez inévitablement à avoir un layout qui contient tout ce qui est censé être le design global de votre application.
Et parce qu’il faut des exceptions qui confirment la règle de ce design global, vous avez des pages qui doivent se comporter différemment :
Ne pas afficher le menu de gauche ou avoir un body avec une class différente.

Pour cela, Django et Symfony proposent deux concepts fortement intéressants qui sont similaires, bien qu’ayant des noms différents et que le concept soit beaucoup développé avec Django.
Je vais faire l’explication avec Django. Et je vous montrerai ensuite l’équivalent en PHP avec Symfony.

Avec Django

Dans votre layout, nous avons le code suivant :
<div>
  {% block 'menu' %}
    Contenu par défaut
  {% endblock %}
</div>

Et dans la vue de l’une de vos actions :
{% extend 'layout' %}
{% block 'menu' %}
  Contenu spécifique à la vue
{% endblock %}

Notre vue va charger le layout (celui à charger est précisé par le extend).
Le layout, en détectant le block va alors aller voir si la vue n’en définit pas un elle-même. Vu qu’elle en définit un, à l’endroit du block du layout sera affiché le contenu du block de la vue.

En gros ici, nous aurons le message « Contenu spécifique à la vue » d’affiché.
Si la vue ne définissait pas de block menu, nous aurions le message « Contenu par défaut d’affiché ».
Vous pouvez ainsi définir divers éléments de votre design spécifiques à votre vue tout en ayant également une valeur « par défaut ».

C’est d’ailleurs ainsi qu’il est conseillé de placer, en plus des éléments du design, le contenu de la vue en lui même, en créant un block « content ».
Plus plus d’informations, je vous invite à voir la documentation de Django.

Avec Symfony

Les slots de Symfony sont beaucoup moins utilisés que les blocks de Django. Il s’agit d’une fonctionnalité disponible dans les templates. Pas de la fonctionnalité autour de laquelle vous construisez vos templates.

Dans notre nous allons donc définir un slot dans notre layout :
<div>
  <?php if (has_slot('menu')): ?>
    <?php include_slot('menu') ?>
  
    Contenu par défaut
  
</div>

Et en redéfinir son contenu dans notre vue :
<?php slot('menu') ?>
  Contenu spécifique à la vue
<?php end_slot() ?>

Ou encore, si vous avez peu de contenu à définir dans votre slot :
<?php slot('menu', 'Contenu spécifique à la vue') ?>

Le première forme en fera tiquer certains puisqu’il s’agit d’un yield-like (pour les autres, c’est le genre de choses qui rendrait php encore mieux si c’était implémenté).
Le code donné ici fonctionne exactement de la même manière que celui donné plus haut pour Django.
Pour plus d’informations, je vous invite à voir la documentation Symfony.

Ainsi avec les slots et blocks à utiliser en fonction de la technologie que vous utilisez, vous pouvez rendre votre design entièrement DRY sans pour autant vous fixer de limites :)

S’il vous plait ! Et je m’explique.

J’utilise, comme outil d’intégration continue, Integrity.
Avec un « post-receive » sur le repository github, à chacun de mes commits, Integrity est mis au courant et il exécute les tests.

Ca fonctionne à merveille avec mes projets Rails (l’API RefStats et mon portfolio); mes projets Django (la documentation de RefStats).
Mais pour les projets Zend Framework (l’appli web RefStats) et un autre sur lequel je vais bosser en aout et qui sera fait avec Symfony, c’est pas cool.
Les tests, bien qu’ils ne passent pas tous, sont considérés par Integrity, comme valides.

La raison de cela est très simple : lorsqu’un processus console est exécuté, il peut retourner un code de status. Un peu comme le code HTTP sur les pages web.
Ce code doit être à 0 pour que les tests soient valides et à une autre valeur, quelconque, si les tests ne passent pas.
Voir notamment la documentation Integrity.
En PHP, un simple exit(0) ou exit(1) à la fin des tests suffirait à exécuter la chose correctement.

Et vraissemblablement, Symfony tout comme le Zend Framework ne renvoient pas le bon code de status.
Alors s’il vous plait, PHP a déjà pas mal de retard au niveau des tests automatisés d’applications, qu’il serait cool de rattraper. Faire ceci serait déjà un premier pas :)

Lorsque vous cherchez à créer des graphiques, quelque soit le langage, c’est toujours un peu prise de tête. En Ruby par exemple, il existe gruff.
Par ailleurs trouver une librairie qui fera des graphiques joli est tout aussi difficile.

Du coup j’ai préféré bosser avec Google Charts. Et j’ai eu besoin d’une librairie Ruby qui me permette de générer les graphiques de manière assez simple.
Les deux ou trois que j’ai testé ne m’ont pas convenu. J’ai donc décidé de créer la mienne. Et voici donc Ruby on GChart :)
C’est un plugin rails. Mais il n’a aucune dépendance autre que net/http (pour l’enregistrement du fichier). Vous pouvez donc l’utiliser dans n’importe quel script ruby.

Son fonctionnement est assez simple. Vous instanciez la classe :
chart = GoogleChart::Chart.new({
  :type => :text,
  :height => 250,
  :width => 100,
  :encoding => :simple,
  :datas => [25, 15, 50],
  :labels => ['First', 'Second', 'Third'],
})

Puis, pour obtenir le graphique, deux possibilités :
graph.to_url
Qui retournera simplement l’url du graphique.

Ou bien :
graph.to_file /chemin/vers/le/fichier.png
Qui récupèrera l’image générée et l’enregistrera sur votre disque à l’endroit demandé.

Ainsi le code ci-dessus vous génèrera le graphique suivant :

Plusieurs paramètres sont disponibles en plus de ceux donnés ci-desus :

  • encoding : permet de préciser le type d’encodage des données (supportés : :text et :simple)
  • colors : permet de spécifier les couleurs des graphiques. Exemple : :colors => ['000000', 'FFFFFF']

Il est par ailleurs possible d’obtenir plusieurs graphiques en y passant un tableau de données.
Exemple :
chart = GoogleChart::Chart.new({
  :type => :text,
  :height => 250,
  :width => 100,
  :encoding => :simple,
  :datas => [[25, 15, 50], [15, 50, 25]],
  :labels => ['First', 'Second', 'Third'],
  :colors => ['00FF00', 'FF0000']
})

Affichera le graphique suivant :

Sympa non ? N’hésitez pas à l’utiliser et à me faire vos retour en commentaire à ce billet :)

Après Floriane qui a gagné une place pour Blur (grâce à son réseau et le notre, ce qui nous a permis d’avoir des pains au chocolat lundi :mrgreen: ), j’ai, pour ma part, gagné deux places pour aller voir « le hérisson« .

Si vous regardez bien mon commentaire sur le premier billet de Camille, vous verrez que j’ai promis d’offrir la seconde place à la fille qui en fera la demande.
C’est donc ici qu’il faut en faire la demande mesdemoiselles !

Quelques petites notes tout de même :

  • J’invite une fille. Pas un mec (désolé Jean-Seb).
  • Ca sera sur Lyon.
  • Vous aurez le droit à un super remerciement et un lien dans mon billet « mes films du mois de juillet » (ça, c’est de l’argument qui va en convaincre plus d’une :mrgreen: ).

Du coup, balancez des commentaires si vous êtes intéressées. Vous avez jusqu’au lundi 13 juillet.
Après ça, j’irais trouver une âme charitable pour m’accompagner autre part.

Comme déjà dit dans mon précédent billet, j’ai migré sous Ubuntu en début de semaine.
Tout en continuant à tester Townce, j’ai voulu y passer un coup de rcov.

Et la, Ô infamie.

/usr/lib/ruby/1.8/rexml/formatters/pretty.rb:131:in `[]‘: no implicit conversion from nil to integer (TypeError)
from /usr/lib/ruby/1.8/rexml/formatters/pretty.rb:131:in `wrap’
from /usr/lib/ruby/1.8/rexml/formatters/pretty.rb:131:in `wrap’
from /usr/lib/ruby/1.8/rexml/formatters/pretty.rb:90:in `write_text’
from /usr/lib/ruby/1.8/rexml/formatters/default.rb:50:in `write’
from /usr/lib/ruby/1.8/rexml/formatters/pretty.rb:75:in `write_element’
from /usr/lib/ruby/1.8/rexml/formatters/pretty.rb:73:in `each’
from /usr/lib/ruby/1.8/rexml/formatters/pretty.rb:73:in `write_element’
from /usr/lib/ruby/1.8/rexml/formatters/default.rb:31:in `write’
from /usr/lib/ruby/1.8/rexml/formatters/pretty.rb:75:in `write_element’
from /usr/lib/ruby/1.8/rexml/formatters/pretty.rb:73:in `each’
from /usr/lib/ruby/1.8/rexml/formatters/pretty.rb:73:in `write_element’
from /usr/lib/ruby/1.8/rexml/formatters/default.rb:31:in `write’
from /usr/lib/ruby/1.8/rexml/formatters/pretty.rb:117:in `write_document’
from /usr/lib/ruby/1.8/rexml/formatters/pretty.rb:111:in `each’
from /usr/lib/ruby/1.8/rexml/formatters/pretty.rb:111:in `write_document’
from /usr/lib/ruby/1.8/rexml/formatters/default.rb:28:in `write’
from /usr/lib/ruby/1.8/rexml/document.rb:197:in `write’
from (eval):93:in `pretty’
from /usr/lib/ruby/1.8/rcov/report.rb:1003:in `create_file’
from /usr/lib/ruby/1.8/rcov/report.rb:708:in `execute’
from /usr/lib/ruby/1.8/rcov/report.rb:125:in `each’
from /usr/lib/ruby/1.8/rcov/report.rb:125:in `each_file_pair_sorted’
from /usr/lib/ruby/1.8/rcov/report.rb:707:in `execute’
from /usr/lib/ruby/1.8/rcov.rb:640:in `dump_coverage_info’
from /usr/lib/ruby/1.8/rcov.rb:640:in `each’
from /usr/lib/ruby/1.8/rcov.rb:640:in `dump_coverage_info’
from /usr/bin/rcov:421
from /var/lib/gems/1.8/gems/rspec-1.2.7/lib/spec/runner.rb:45

Rcov il a tout cassé ;)

En cherchant un peu, il s’avère qu’il s’agit d’un bug dans la librairie ReXML. Il a été corrigé en septembre dernier.
Mais la version apt de Ruby est plus ancienne que cela. Du coup le bug n’a pas été répercuté.

Qu’à cela ne tienne, allons le corriger nous même !
Ouvrez le fichier qui bugue.

sudo nano /usr/lib/ruby/1.8/rexml/formatters/pretty.rb

Nous sommes obligés de le faire en sudo. Vous n’avez, en toute logique, pas le droit de modifier ce fichier.

Descendez tout en bas du fichier. Vous verrez la méthode suivante :
def wrap(string, width)
  # Recursively wrap string at width.
  return string if string.length <= width
  place = string.rindex(' ', width) # Position in string with last ' ' before cutoff
  return string[0,place] + "\n" + wrap(string[place+1..-1], width)
end

L'erreur que nous avons plus haut vient du fait que la variable "place" est égale à nil. Il est donc impossible de l'utiliser comme clé dans le tableau "string".
Il suffit d'ajouter un return avant celui qu'il y a déjà, indiquant de retourner "string" si "place" est égal à nil.
Je n'invente rien. Il s'agit du commit fait dans Ruby en septembre dernier.

Modifiez donc votre méthode en y ajoutant la ligne suivante :
return string if place.nil?

Votre méthode doit maintenant ressembler à cela :
def wrap(string, width)
  # Recursively wrap string at width.
  return string if string.length <= width
  place = string.rindex(' ', width) # Position in string with last ' ' before cutoff
  return string if place.nil?
  return string[0,place] + "\n" + wrap(string[place+1..-1], width)
end

De mon côté, suite à cela ça fonctionne. Si vous avez toujours une erreur, je vous invite à la signaler ici. Mais c'est probablement un autre problème ;)

Je ne m’en cache pas, je suis un pro git à fond.
Cependant et malheureusement, git n’est pas (encore) très répandu et beaucoup de projets sont encore hébergés sur des repositories SVN.
C’est le cas chez O2Sources (mais on parle d’y remédier, notamment lorsque Townce gèrera cela).

Vu que je viens de migrer ma machine de Windows vers Ubuntu, j’ai décidé d’en profiter pour faire un test.
Utiliser git-svn pour commiter en local en git et pousser par la suite sur le repository svn :)

Déjà, l’installation. Sous Debian-Like,
sudo aptitude install git-svn
Normalement, cela vous crée une commande « git-svn ». Moi, ça l’a pas fait. Du coup un petit coup de sudo find / -name git-svn; vous trouvez l’emplacement de l’exécutable (théoriquement dans /usr/bin) et y créer une commande globale.
ln -s /chemin/vers/git-svn /usr/bin/git-svn

Ensuite, commençons par récupérer notre repository
git-svn clone -s http://domaine.net/chemin/vers/le/repository
Si vous avez une arborescence avec des tags (dossiers tags/, trunk/ et branchs/), placez l’option -s.
Ainsi, git-svn les convertira en tags et branches GIT.
Sinon, c’est inutile :)

Deuxième étape : si vous avez des options git:ignore, elles ne sont pas prises en compte. Faites les donc :
git-svn show-ignore > .gitignore

Maintenant, faites vous une session de développement. Committez comme d’habitude sur votre repository git et oubliez svn (youpi !!).
Une fois que celle-ci est terminée, il vous faut committer (bah ouais hein).

Pour cela, commencons par faire un update. On sait jamais que vous seriez pas le seul à travailler et que l’un de vos collègues n’ait committé entre temps ;)
git-svn rebase
Et committons
git-svn dcommit

Vous verrez que votre repository svn a été mis à jour.
Cool non ? :)
Et vous, vous préférez GIT ou SVN ? (ouais, postez des commentaires !!)

Comme en mai, voici ma liste de films pour juin.

  • Looking for Eric
    Note : 7 / 10
    N’étant absolument pas intéressé par le foot, je ne voulais au début pas aller voir ce film. Et puis ayant entendu des bonnes critiques, j’ai changé d’avis.
    Et j’ai grandement bien fait ! Une superbe comédie qui ne vole pas très haut du point de vue de jeu des acteurs. Mais dont la morale est magnifique et qui offre de nombreux éclats de rire.
  • Ne te retourne pas
    Note : 3 / 10
    Peut-être que en regardant ce film tout en ayant fumé avant, on comprends un peu mieux.
    Pour ma part, soit je n’ai pas compris grand chose; soit des énormes inepsies se sont glissées un peu partout. A cela il faut ajouter le jeu horrible de Thierry Neuvic. Un film plus que moyen au final.
  • Terminator : Renaissance
    Note : 4.5 / 10
    Ce film peut-il vraiment être classé dans la catégorie action ? On dirait vraiment du comique.
    Entre John qui se fait enlever sa chaussure au début par un Terminator et qui la retouve par magie et le Terminamoto qui a un port firewire, c’est vraiment rigolo.
    Heureusement pour ceux qui aiment l’action, on nous en met plein le nez. Et c’est ce qui rattrape la note (même si je ne pouvais pas sérieusement mettre la moyenne).
  • Les beaux gosses
    Note : 7 / 10
    Je ne m’attendais pas à rigoler autant. Les autres films du même genre (Lol; Nos 18 ans; …) sont généralement assez intellectuels. Ici, on ne se prends pas au sérieux et on rigole à vive voix pendant 1h30.
  • Je vais te manquer
    Note : 6 / 10
    En grand fan de Love Actually, j’espérais beaucoup de ce film. Malheureusement, bien que très touchant, très bien joué et réalisé, la recette est toujours la même et il n’y a pas de réelle surprise.
    Alors on passe un bon moment. Mais au final, aucune nouveauté. C’est une comédie romantique de destins croisés comme les autres.
  • Blood : the Last Vampire
    Note : 4 / 10
    Un scénario plutôt creux et ayant pour seul but (comme c’était, de toute façon, prévisible) de montrer du sang.
    Sang qui est, par contre, très mal représenté. Je ne savais pas que ça faisait des bulles quand on coupe des bras. A conseiller aux fans d’action et de Kill Bill like. Mais pas aux autres.
  • Tellement proches
    Note : 8 / 10
    Je tiens à saluer quelque chose d’exceptionnel de par ce film : la bande annonce ne spoil rien du tout de l’histoire !! Et ça, c’est particulièrement rare et fortement appréciable :)
    Par ailleurs le film est plein de pics, toujours criants de vérité et à hurler de rire. On y reconnait plus ou moins sa famille et on apprécie tout autant.
  • Lascars
    Note : 3 / 10
    Le comique de répétition c’est sympa. Mais faut que la blague soit drôle la première fois. Sinon c’est carrément lourd.
  • Jeux de pouvoir
    Note : 5 / 10
    On vois pas souvent des films ou le suspens du dénouement reste jusqu’à bout. Et même si on s’y perds quelques fois dans des déductions plutôt compliquées, l’histoire est particulièrement bien ficelée et mérite nos 2h d’attention.
  • Very Bad Trip
    Note : 5 / 10
    On regrette un petit peu le « happy end ». Mais on rigole de temps en temps et dans l’ensemble, on s’amuse.
  • Transformers II
    Note : 5 / 10
    On passera le manque de scenario. De toute façon, ce n’est pas le but de ce genre de film. En revanche, sur ce qu’il essaye de faire, nous en mettre plein la vue, il le réussit très bien et c’est tout ce qu’on lui demande.
  • Notorious Big
    Note : 6 / 10
    D’abord perplexe sur ce film, j’ai été fort agréablement surpris. Et bien que l’on ne s’identifie pas forcément aux personnages, on s’attache et on pleure.
 
Fork me on GitHub