mercredi 11 juillet 2012

{{ Mustache }}

Bonjour,


Qui n’a jamais entendu de la bouche d’un développeur backend (pour ne pas dire Java) “Javascript, moins j’en fais, mieux je me porte”. Je parle en connaissance de cause car j’étais assez imperméable au Javascript par le passé. Mais je ne faisais que “bidouiller” du Javascript car en vérité, je ne connaissais pas le langage et après quelques lectures d’ouvrages de référence (Javascript: The Good Parts de Douglas Crockford par exemple), je me suis surpris à apprécier Javascript de plus en plus. Et du Javascript il y en a partout, déguisé derrière du jQuery, et même côté serveur avec Node.js.
Dans cet article, je vais vous parler d’une librairie Javascript très spécifique, qui ne fait qu’une seule chose mais qui le fait bien. Il s’agit de la librairie de templating Mustache.js.




1. jQuery sans les moustaches

Imaginons qu’on veuille afficher une liste de livres (titre, auteur) que l’on récupère sous forme d’objets Javascript. Voici le code Javascript/jQuery correspondant :
var book = { title: "Javascript: the Good Parts", author: "Douglas Crockford" };
$('#example').append('Title: <b>' + book.title + '</b><br/>Author: ' + book.author);

Et le résultat :
Title: Javascript: the Good Parts
Author: Douglas Crockford
Je ne sais pas vous mais cette ligne là, elle m’irrite un peu quand je la lis et encore plus quand je l’écris :
$('#example').append('Title: <b>' + book.title + '</b><br/>Author: ' + book.author);

Pleins de ' et de +, c’est facile de s’y perdre et surtout on mélange affichage et données. Il existe de nombreux systèmes de templates pour mettre en oeuvre cette séparation. Et bien en Javascript, il existe également des systèmes de template dont Mustache, que je trouve simple et pourtant très puissant. Alors faisons appel à Mustache.js et voyons comment on peut rendre l’exemple précédent plus sexy.
var data = {title: "Javascript: the Good Parts", author: "Douglas Crockford"};
var template = 'Title: <b>{{title}}</b> <br/> Author: {{author}}';
var output = Mustache.render(template, data);
$('#example').append(output);

Title: Javascript: the Good Parts
Author: Douglas Crockford
Aaah fini les ' et + parasites ! On a maintenant une belle séparation entre le template et les données. On utilise Mustache.render qui prend en paramètre le template et notre objet de données data. Dans le template, il y a deux tags {{title}} et {{author}} qui vont être remplacés par les valeurs correspondantes de l’objet data lors de l’appel à Mustache.render.
On peut faire donc une première observation, un template Mustache est composé de tags et un tag est délimité par des doubles accolades : les fameuses moustaches !


2. Les tags Mustache

Pour l’instant, nous n’avons vu qu’un type de tag {{name}} qui permet d’afficher la valeur de l’attribut name de votre objet de données. Dans le jargon Mustache, name est la clé du tag. Voici un petit listing des tags Mustache qui existent :

{{#name}}, la moustache de section

Ce tag va ouvrir ce que Mustache appelle une section. Cette section peut contenir du text/html ou des tags Mustache. Une section est fermée par un tag {{/name}}. Si l’attribut name existe dans votre objet de données et est non null, non vide, non undefined alors Mustache va interpréter cette section. Dans le cas contraire, la section n’est pas interprétée.
var data = {title: "Javascript: the Good Parts", author: ""};
var template = '{{#title}} Title: <b>{{title}}</b> {{/title}} {{#author}} ne sera pas affiché {{/author}}';
var output = Mustache.render(template, data);
$('#example').append(output);

Title: Javascript: the Good Parts
Si name est un array, alors Mustache va itérer sur cet array et interpréter la section autant de fois que nécessaire.
var data = { books: [ "Javascript: the Good Parts", "Clean Code" ] };
var template = '{{#books}}<li>{{.}}</li>{{/books}}';
var output = Mustache.render(template, data);
$('#example').append(output);

  • Javascript: the Good Parts
  • Clean Code
Notez l’utilisation de {{.}} afin d’afficher l’élément de l’array.

{{^name}}, la moustache inverse

C’est l’inverse du tag {{#name}}, c’est-à-dire que le body du tag ne sera interprété que si l’attribut name n’existe pas, est vide, null ou undefined dans votre objet de données. Exemple :
var data = { books: [ ] };
var template = '{{#books}}<li>{{.}}</li>{{/books}} {{^books}}Aucun livre{{/books}}';
var output = Mustache.render(template, data);
$('#example').append(output);

Aucun livre

{{! comment}}, la moustache invisible

C’est le tag de commentaire. Tout ce qu’il y a entre les moustaches est ignorée.
var data = {title: "Javascript: the Good Parts", author: "Douglas Crockford"};
var template = 'Le commentaire suivant ne sera pas affiché : {{! ne doit pas être affiché}}';
var output = Mustache.render(template, data);
$('#example').append(output);

Le commentaire suivant ne sera pas affiché :

{{> tag}}, la moustache partielle

Avec Mustache, il est possible de définir des templates partiels afin de décomposer des templates qui seraient trop verbeux ou des templates que vous récupérez de plusieurs sources.
var data = {title: "Javascript: the Good Parts", author: "Douglas Crockford"};
var template = 'Title: <b>{{title}}</b> <br/>{{> tplAuthor}}';
var partials = { tplAuthor: 'Author: {{author}}' };
var output = Mustache.render(template, data, partials);
$('#example').append(output);

Title: Javascript: the Good Parts
Author: Douglas Crockford


3. Fonctions

Dans votre objet de données, vous n’êtes pas cantonnés à avoir uniquement des valeurs ou des arrays. Vous pouvez également définir des fonctions qui vont déterminer le texte à afficher. Exemple :
var i = 0;
var data = { currentdate: function() { return i++;} };
var template = '<li>{{currentdate}}</li>';
$('#example').append(Mustache.render(template, data));
$('#example').append(Mustache.render(template, data));
$('#example').append(Mustache.render(template, data));

  • 0
  • 1
  • 2
Ok j’avoue, ça c’était l’exemple facile avec les fonctions. On peut faire un poil plus évolué. Dans les exemples précédents avec les livres, on affiche le titre en gras. Imaginons qu’on veuille rendre paramétrable l’affichage de “Title”, donc au choix en gras, en italique ou ce que vous voulez. Il suffit de fournir une fonction qui va faire ça.
var data = {
 title: "Javascript: the Good Parts",
 titleDisplay: function() {
   return function(text, render) {
     return '<b>' + render(text) + '</b>';
   }
 }
};
var template = 'Title: {{#titleDisplay}} {{title}} {{/titleDisplay}}';
var output = Mustache.render(template, data);
$('#example').append(output);

Title: Javascript: the Good Parts
Mais maintenant si je veux afficher le titre en italique et l’entourer par des guillemets, on remplace le corps de la fonction par :
return '"<i>' + render(text) + '</i>"';

Title: “Javascript: the Good Parts
Donc celui qui fournit l’objet data peut maintenant personnaliser l’affichage du titre.


4. Template multi lignes

“T’es bien gentil Ludo, mais tes exemples sont simplistes, tes templates ne tiennent que sur une seule ligne. Tiens prend ce template là. C’est beaucoup moins beau du coup et on peut vite oublier un antislash…”
var template = 'Title: {{title}} <br/>\
Author: {{author}} <br/>\
Edition: {{edition}}';

Effectivement, ce n’est pas très sexy. Alors il y a une petite astuce. Il suffit de mettre le template dans une balise <script> de typetext/html, de récupérer son contenu et de le passer à Mustache ! En exemple ça donne :
<script id="book" type="text/html">
Title: {{title}} <br/>
Author: {{author}} <br/>
Edition: {{edition}}
</script>

var data = {title: "Javascript: the Good Parts", author: "Douglas Crockford", edition: "O'Reilly"};
var template = $('#book').html();
var output = Mustache.render(template, data);
$('#example').append(output);

Title: Javascript: the Good Parts
Author: Douglas Crockford
Edition: O’Reilly
Mais on peut faire encore mieux !


5. ICanHaz.js

ICanHaz.js est une petite librairie Javascript qui wrappe Mustache.js et qui reprend l’idée de définir ses templates dans des balises script de type text/html. Au chargement de la page, ICanHaz.js va rechercher tous les templates de la page, créer un cache contenant ces templates et une fonction pour chaque template. A l’utilisation, c’est encore plus simple que Mustache.js. Si on reprend l’exemple précédent, le javascript devient :
<script id="book" type="text/html">
Title: {{title}} <br/>
Author: {{author}} <br/>
Edition: {{edition}}
</script>

var data = {title: "Javascript: the Good Parts", author: "Douglas Crockford", edition: "O'Reilly"};
var output = ich.book(data);
$('#example').append(output);

ICanHaz.js fournit un objet ich et a créé une méthode book correspondant à l’id de la balise script. ICanHaz.js permet également de gérer les partials Mustache de manière élégante en indiquant un attribut à la balise script. Si on remplace la partie “edition” par un partial :
<script id="book" type="text/html">
Title: {{title}} <br/>
Author: {{author}} <br/>
{{> edition}}
</script>
<script id="edition" type="text/javascript">
Edition: {{edition}}
</script>

et l’appel à ich.book(data) reste le même !
Comme je vous le disais précédemment, ICanHaz.js gère un cache de templates et fournit donc des méthodes pour rajouter des templates dans le cache, nettoyer le cache ou recharger le cache.


Conclusion

Si, sur votre projet, vous utilisez jQuery et n’utilisez pas de système de template côté client, alors foncez ! Essayez Mustache.js et ICanHaz.js ! Le tout ne fait que 5,4ko minifié.
Ensuite, je voudrais donner quelques précisions sur Mustache.js. Mustache.js est en fait l’implémentation Javascript du système de template Mustache (sans le .js). En effet, il existe de nombreuses implémentations de Mustache, en Java, Ruby, Python, PHP, etc…
De plus, on dit souvent que Mustache est un système de template “logic-less”, car il n’y a pas de if, else ou autre, il n’y a que des tags, que des moustaches :}}

dimanche 22 avril 2012

mRuby has been released !




Bonjour,

mRuby is out !

mRuby ( minimalistic Ruby ) est l'implémentation de Ruby qui vise a remplacer Lua, Objective-C et Java sur les devices et mobiles. Cette implémentation est conforme à la norme ISO. MRuby a été présenté par Matz ce 20 Avril 2012. Voir la vidéo.

mRuby
 peut exécuter du code Ruby en mode «interprèté» ou «compilé» et l'exécuter sur une machine virtuelle, selon les préférences du développeur.
La sortie de mRuby a inspiré "Yuichiro MASUI" et lui a permis d'écrire son "MobiRuby" qui permet de créer des applications IOS en Ruby.Un exemple :Et ça donne :





mardi 15 novembre 2011

Active Admin !!!



Hello c'est moi...


Aujourd'hui j'aimerais vous parler d'un souci majeur dans un processus de développement : la mise en place d'un module d'administration souple efficace, et intuitif. Sur les différents projets dans lesquels j'ai eu a travailler, c'était souvent la partie la plus laborieuse et bien souvent bâclée. On se comprend....

Mais comme le monde n'est pas toujours si cruel, on a notre petite communauté qui nous a mijoté un petit bijou, une gem, pour la mise en place d'un module d'administration. Hé oui oui...si si je blague pas...en 10 min et encore c'est déjà beaucoup vous aurez une interface d'administration clean et flexible.


Comment fonctionne cette gem ?

Bah très simplement une fois l'installation effectuée, il suffit de spécifier les ressources qui font l'objet de cette administration, par ressource j'entends les modèles. 


En effet Active admin se base sur les modèles pour récupérer les différents champs et construire les différents formulaires, champs de recherche, filtres et autres outils. 
La commande a taper est tres simple :


> rails g active_admin:resource nom_du_model

Prenez le temps de googler tout ça, vous ne le regretterez sûrement pas.


Quelques liens utiles :

C'était moi...

Dakar Ruby Brigade : Meetup



Reprise des activités ce Samedi 19 novembre 2011 
a l'Ecole Supérieure Polytechnique de Dakar
a partir de 15 h

 Présentation sur REST suvie d'un atelier 

lundi 3 octobre 2011

Sinatra 1.3.0 is out ! and it streams


Bonjour tout le monde,


Pour ce mois d'Octobre la communauté Ruby nous fera beaucoup de beaux cadeaux ! Et ça a déjà commencé avec l'équipe Sinatra qui fait une "double" release : en sortant deux versions de sinatra : 1.2.7 et la 1.3.0.

Les nouveautés !

I - Sinatra-contrib

Sinatra a un très grand nombre d'extensions ( plugins ) et certaines ( tels que sinatra-content-for et sinatra-reloader) sont très utilisées. Ce qui a poussé l'équipe Sinatra à décider de les incorporer dans le "core" de sinatra et en faire un "third party component". Et de ce fait nous avons une grande partie des helpers de Rails disponibles et qui fonctionnent de la même maniére. YOUPI !!!

II - "Sinatra recipes"

Zachary Scott a (enfin) lancé son projet "Recipes". C'est en effet un ensemble de techniques, d'astuces et d'applications réalisées par les amoureux de Sinatra.

III - Streaming 

La version "vanilla" ressemble à ça : 


get '/' do
  stream do |out|
    out << "Ce sera vraiment ... -\n"
    sleep 0.5
    out << " (vous attendez toujours ? :)) \n"
    sleep 1
    out << "- SUPER !\n"
  end
end


La chose la plus cool dans cette abstraction est que cette fonctionnalité (streaming) n'est pas spécifique à un serveur Rack particulier ! Et oui ça marche partout ! Que votre serveur soit du type "evented" ( Ebb, Rainbows, thin) ou "sequential" (Unicorn, Mogrel ou passenger).
Pour le moment le seul serveur à ne pas utiliser est WEBrick! Et ne me demandez pas pourquoi :)


Un truc super intéressant : si vous utilisez un serveur "evented" ( thin par exemple ) vous pourrez garder la connexion active et avoir facilement un "messaging service" et de facto votre applicatoin devient plus rapide.


set :server, :thin
connections = []

get '/' do
  # garder la connexion active
  stream(:keep_open) { |out| connections << out }
end

post '/' do
  # Envoyer un message à tous les canaux (connexions) ouverts 
  connections.each { |out| out << params[:message] << "\n" }
  "message envoyé "
end


NB : Tout cela est fait sans l'utilisation des "Fibers". Ce qui permet d'éviter de saturer la stack.


Il est à noter aussi que l'ajout du PATCH HTTP permettra d'accéler certains requêtes ( mise à jour surtout). Merci à l'équipe GitHub.


patch '/' do
  # ... modifier une ressource devient facile, rapide et toujours secure
end


Les tests sont toujours les mêmes :)


Bonne semaine !



jeudi 1 septembre 2011

Sortie de Rails 3.1



Ruby on Rails 3.1 : Les nouveautés


  • Streaming
  • Reversible Migrations
  • Assets Pipeline
  • jQuery as the default JavaScript library
Introduction à Rails 3 :


Quelques applications Rails 3.1 : 


Quelques screencasts pour démarrer comprendre comment ça marche :
   

jeudi 28 juillet 2011

Tester son code Ruby : Minitest



la programmation est une activité super intéressante. Chacun a sa métaphore préférée qui explique ce que signifie pour lui la programmation. Eh bien, pour moi "la programmation est tout au  sujet d'automatisation". 

Vous êtes devant votre ordinateur pour lui apprendre à faire automatiquement un travail que vous savez faire, mais que vous ne voulez pas faire encore et encore.

Quand on s'en rend compte, on cherche tout de suite des choses qui  peuvent être automatisées. Je n'aime pas me répéter encore et encore et encore. C'est ennuyeux et parfois énervant!
 Eh bien, il y a une tâche particulière qui est liée à la programmation et qui se répète tout le temps : "vérifier que votre logiciel fonctionne!" Donc une tâche à automatiser.

 > MINITEST 

Heureusement pour nous, Ruby a des outils fantastiques qui vous permettent de mettre en place des tests pour votre code que vous pouvez exécuter automatiquement. Vous pouvez vous éviter de perdre du temps et de l'effort en laissant l'ordinateur exécuter des milliers de tests à chaque fois que vous modifiez votre code. Je ne vais pas disserter sur les vertus du«Test Driven Development" dans cet article, mais écrire les premiers tests. Pour commener, nous allons prendre un petit peu de code pour travailler, et je vais vous montrer comment le tester en utilisant minitest.

Pour cet exercice, nous allons faire quelque chose de simple et nous concentrer sur les tests. Nous allons écrire une classe Ruby appelée Membre. Il va falloir un tas de fonctionnalités, mais voici les deux premières méthodes, nous aurons besoin:
-> un membre peut ajouter d'autres membres en tant qu'amis-> un membre peut savoir combien d'amis il a-> quand il est nouveau, le nombre de ses amis est 0-> quand il supprimer sa liste d'amis, il revient à 0 ami.
Très simple non ? Pour écrire ces tests nous allons utiliser une librairie Ruby appelée minitest. Elle est native dans Ruby1.9 mais si vous utiliser 1.8 installez la en faisant :
> gem install minitest
Ecrivons notre premier test !

require 'minitest/autorun'

class TestMembre < MiniTest::Unit::TestCase
  def setup
    @membre = Membre.new
  end
  def test_pas_d_amis
    assert_equal 0, @membre.nombre_amis
  end
end

Ok! Il ya beaucoup de choses ici. Prenons ligne par ligne. Sur la première ligne, nous avons un «require». La partie 'minitest/autorun' comprend tout ce dont vous avez besoin pour exécuter vos tests, automatiquement. 
Tout ce dont nous avons besoin pour faire tourner nos tests est de taper "ruby membre.rb". Mais regardons le reste du fichier avant de faire cela. La prochaine chose que nous faisons est écrire une classe qui hérite de l'une des classes de base de minitest. Voilà comment fonctionne minitest, en exécutant une série de TestCases. Minitest permet également les tests de groupe et en plusieurs fichiers.
Dans notre TestCase nous avons 2 méthodes : setup et test_pas_d_amis. La méthode setup est exécutée automatiquement et avant chaque test. Elle permet de préparer le terrain pour réaliser les tests. La deuxiéme méthode permet de vérifier qu'un nouveau membre n'a pas encore d'amis.
Lançons notre test et voyons ce que ça donne :
> ruby membre.rb

Loaded suite membre
Started
E
Finished in 0.000853 seconds.

1) Error:
test_pas_d_amis(TestMembre):
NameError: uninitialized constant TestMembre::CashRegister
membre.rb:5:in `setup'

1 tests, 0 assertions, 0 failures, 1 errors, 0 skips

Test run options: --seed 36463
Waaaaw cool ! Comme vous pouvez le voir nous avons un test et un échec. Nous savons que les classes Ruby sont des constantes et il en manque une ici. Ecrivons cette classe alors.
class Membre
end

Relançons le test :

1) Error:
test_pas_d_amis(TestMembre):
NoMethodError: undefined method `nombre_amis' for #<Membre:0x00000101032a80>
membre.rb:9:in `test_pas_d_amis'

ça avance ! et cette fois ça nous dit qu'il manque une méthode.

class Membre
  def nombre_amis
  end
end
Relançons le test encore une fois.

1) Failure:
test_pas_d_amis(TestMembre) [membre.rb:9]:
Expected 0, not nil.
Erreur claire : On s'attend à 0 pas à nil

def nombre_amis
  0
end

Ok cool. Le test passe mais notre total est toujours fixe (0). Vérifions que quand on ajoute des amis, le nombre d'amis change.

def test_calculer_nombre_amis
  @membre.ajouter 1
  @membre.ajouter 2
  assert_equal 3, @register.nombre_amis
end
A ce stade, la visoin doit être un peu plus claire pour vous. Lançons nos tests encore une fois


Loaded suite membre
Started
.E
Finished in 0.000921 seconds.

1) Error:
test_calculer_nombre_amis(TestMembre):
NoMethodError: undefined method `ajouter' for #<Membre:0x00000101031838>
membre.rb:13:in `test_calculer_nombre_amis'

2 tests, 1 assertions, 0 failures, 1 errors, 0 skips

Test run options: --seed 54501
Ok! vous voyez le ".E" sur la 3iéme ligne du résultat ? Ben ça veut dire qu'on a eu 2 tests, un réussi '.' et un échoué "E".
Ajouter la méthode qui manque et continuons .


def ajouter(ami)
  @amis << ami
end


Oups ! le @amis n'a pas encore été défini :) Lancez le test et il vous le dira.



def initialize
  @amis = []
end
Avec ce constructeur, nous n'aurons plus ce genre de problèmes.


Relancez le test et vous aurez une erreur : le nombre d'amis est toujours 0 alors qu'il devait passer à 3 .
Corrigeons ce petit souci:



def nombre_amis
  @amis.inject(0, &:+)
end

C'est fait. Alors pour vérifier que vous avez bien compris le truc, écrivez le dernier test : supprimer_liste_amis.


.....


Alors c'est quoi l'intérêt d'écrire les tests en premier ? Ben ça vous permet d'écrire le code qu'il faut pour répondre aux spécifications que contient votre cahier de charges d'une part et de vous assurer que votre logiciel fait exactement ce pour quoi il a été écrit. 


Les mises à jour du code deviennent chose simple. Et quand il a un problème on sait que c'est le nouveau code qui a cassé quelque chose surtout que le "code base" était digne de confiance.


Dans la suite de cette série d'articles sur les tests, nous allons intégrer les tests à des applications Rails et Sinatra.