En fait, c'est carrément sur le bout des doigts que j'ai eu Ruby depuis quelques semaines.
Comme je le disais précédemment dans ce billet, j'ai donc commencé le ''Ruby''[1] pour développer le connecteur Monotone pour Ohloh.
Je ne suis pas un expert mais après avoir codé près de 1500 lignes de code, j'ai pu me faire une certaine idée du langage... Et c'est carrément la mort !!!

Moi qui ne suis qu'un simple développeur sans grand génie[2], j'avoue être totalement perdu quand il n'y a pas un petit compilateur pour me rappeler que je ne suis qu'un humain.
Et oui, Ruby, c'est du script !!
Alors forcément, coder 1500 lignes dans un langage de script, même objet, ça pique un peu.
Mais ce que je peux, moi, voir comme des défauts s'avère en fait être des fonctionnalités totalement hype.
Je m'en vais vous détailler[3] ce que j'ai pu croiser au cours de mes pérégrinations :

  1. Le typage est dynamique mais fort[4]. J'avoue que je reste dubitatif sur ce point. Toutefois, il semble que par fort, il soit, en fait, question de la levée d'exception quand on tente d'appeler une méthode sur une variable qui ne la supporte pas. En effet, en Ruby, tout est objet mais on ne précise jamais de quel type. Il est d'ailleurs assez drôle de voir dans la rubrique ''Philosophie'' que Ruby est inspiré par Ada et que son concepteur s'est attaché au principe de moindre étonnement mais pour éviter au développeur d'être surpris par son propre code[5]. Voilà qui est hautement rassurant...
  2. L'injection de code prévue dans le langage. Un peu comme le design pattern du visiteur mais en pas objet, une sorte d'hybride entre la fonction de rappel et les listeners anonymes
  3. L'introspection qui permet de modifier le comportement d'une classe à la volée[6] voire même d'une instance de classe seulement. A part ça, le typage est fort...

Voilà les joyeusetés que j'ai pu rencontrer. Maintenant quelques exemples de code pour tout ça.
Pour le 1er point, c'est facile !
Tout d'abord, la classe qui va servir tout au long de cet anti-tuto :D

module Test
  class MaClasse
    # Ici un attribut
    attr_accessor :nawak
 
    def initialize
      @nawak = 12
    end
 
  end
end

C'est simple et compréhensible... Ou pas.
Bon, je suis pas chien, attr_accessor permet d'indiquer à l'interpréteur que l'on veut les deux accesseurs pour ce champ de type... Pardon, c'est dynamique mais fort. La méthode initialize parle d'elle-même
Passons donc au premier test dont voici immédiatement le code

require 'ma_classe'
 
mon_instance = Test::MaClasse.new
mon_instance.nawak += 2
puts "Nawak vaut #{mon_instance.nawak}"
mon_instance.nawak = "tepor"
puts "AND NOW, Nawak vaut #{mon_instance.nawak}"
mon_instance.nawak += 24

Au delà des excellents jeux de mots dans ce code, vous aurez remarqué si vous l'avez exécuté qu'il plante sur la dernière ligne. En effet, grâce au typage fort, on fait ce qu'on veut tant qu'on sait ce qu'on fait. Et oui, rien n'oblige à utiliser le membre nawak comme un entier et on peut changer son type en cours de route mais l'interpréteur veille !!!
N'essayez donc pas de faire n'importe quoi !
Ceci dit, c'est un langage de script ce qui veut dire que vous ne vous apercevrez de cette erreur qu'après avoir testé d'où l'usage quasi obligatoire d'un moteur de tests unitaires heureusement prévu dans le langage[7].
On est quand même bien loin de ce que propose Ada[8] en termes de typage fort.

Attaquons maintenant l'utilisation avancée.
Rendons visite à nos objets. Pour cela, on rajoute la méthode suivante dans notre classe

def use_nawak
      yield @nawak
    end

et pour notre deuxième exemple,

require 'ma_classe'
 
mon_instance = Test::MaClasse.new
mon_instance.nawak += 2
mon_instance.use_nawak do |le_nawak_param|
  puts "Donnes-moi ton nawak qui vaut #{le_nawak_param}"
end

Vous avez tout compris ?
J'explique, yield passe la main au code passé dans le bloc do..end du test. Là, on voit que ça ouvre des perspectives.
D'ailleurs, pour ceux qui voudraient voir, j'en ai usé et abusé, comme les autres, sur mes contributions avec des doubles niveaux d'imbrication :D

Bon, je crois qu'il faut clore avec le plus beau car, même si je ne l'ai pas utilisé dans mon code, le lire fut pour moi une révélation.
J'ai déjà du mal avec la programmation normale que je considère comme un art compliqué alors je ne parle même pas de la méta-programmation.
Allez, un exemple tout simple sur l'introspection

require 'ma_classe'
 
mon_instance = Test::MaClasse.new
lautre = Test::MaClasse.new
lautre.nawak = 'Tiens ?, une chaine'
def mon_instance.tell_me
  "Mon nawak vaut #{@nawak}"
end
mon_instance.tell_me
lautre.tell_me

Bien sûr, comme attendu, ça se vautre sur la dernière ligne. Et oui, on a ajouté la méthode juste sur l'instance à la volée. Au passage, vous aurez remarqué l'excellence du sucre syntaxique qui fait que la valeur de retour d'une fonction n'est pas obligatoirement précisée mais que la dernière référence à une variable en fait le retour. Dans notre cas, juste écrire une chaîne en fin de fonction l'a renvoyé.
Voilà qui respecte bien le moindre étonnement[9].
Pour les psychopathes qui voudraient faire de la méta-programmation, je vous conseille cette page parce que là, je suis trop fatigué et étonné pour mettre un exemple à moi :D

En conclusion, ça reste un langage de script et franchement, écrire des applications plus grosses que quelques milliers de lignes se rapproche plus du suicide qu'autre chose. Quand on reprend le code de quelqu'un, il faut constamment se demander ce que fait telle ou telle variable, comment elle est utilisée[10] et ce que l'on peut faire avec.
L'injection de code par bloc peut rendre un code totalement illisible et se rapproche plus du bon vieux gosub cher au Basic des années 80 que d'un quelconque mécanisme objet.
C'est donc un langage hyper souple, tellement souple que pour se tirer une balle dans le pied, il suffit juste de commencer à coder et là, les ennuis commencent déjà.
On passe donc son temps dans l'interpréteur à rentrer des bouts de code pour vérifier tel ou tel comportement. Le point positif est que tout ça oblige à blinder les tests unitaires pour éviter les régressions qui sont rapidement légion.

Chui trop vieux pour ces conneries !

UPDATE : après avoir bien regardé, il vaut mieux que je vous donne le lien Wikipedia anglais qui est de bien meilleur qualité que son homologue français et permet de voir rapidement une grande partie des fonctionnalités de Ruby... Faut pas être que médisant non plus :D

Notes

[1] Alors que le rugby, j'ai arrêté il y a près de 15 ans :)

[2] Si si, je vous jure même si c'est pas évident comme ça :D

[3] Rassurez-vous, il n'y en a pas non plus des tonnes

[4] Cherchez l'erreur

[5] La classe !!!

[6] Un peu comme en Java mais en plus simple

[7] Enfin d'après ce que j'ai compris

[8] Ou tout autre langage compilé avec du typage

[9] Sur ce coup-là, j'ai été franchement étonné :)

[10] D'ailleurs, certains ne se gênent pas pour changer l'usage en cours de route