Pour fêter ses 20 ans, Ruby arrive en version 2.0 !
Malgré ce changement de version majeur, il y a moins de différences entre Ruby 2.0 et 1.9 qu'entre Ruby 1.9 et 1.8.
La compatibilité avec les logiciels 1.9 est quasiment assurée. Cerise sur le gâteau : cette nouvelle version est considérée comme stable et on y trouve un certain nombre de nouveautés et d'optimisations.
Pour rappel : Ruby est un langage de programmation orienté objets, à typage dynamique et qui s'est inspiré de Lisp, Perl, Smalltalk, Eiffel, etc. Sa principale caractéristique est de mettre en avant les besoins humains avant ceux informatiques, et notamment le fun et la productivité.
NdM : merci à reno pour son journal et _jordan_ pour ses compléments pour approfondir, ainsi qu'à YLD, Marc Quinton, Nicolas Blanco, Barret Michel, Nÿco, Katyucha pour leur participation.
Sommaire
Changements du langage
Paramètres par mot-clé
Le langage gère maintenant directement le passage de paramètres par mots clefs : c'était déjà possible avant, mais en utilisant un moyen détourné (via un Hash en paramètre).
Ci dessous un exemple de définition de méthode avec une valeur par défaut pour un argument "nommé".
# Ruby 1.9 et précédents
def render(source, opts = {})
opts = {fmt: 'html'}.merge(opts)
r = Renderer.for(opts[:fmt])
r.render(source)
end
# Ruby 2
def render(source, fmt: 'html')
r = Renderer.for(fmt)
r.render(source)
end
A noter que le passage de paramètres par mots clefs utilise la syntaxe de Ruby 1.9 pour définir les Hash.
# Ruby 1.8
my_hash = { :key1 => 1, :key2 => 3 }
# Ruby 1.9
my_hash = { key1: 1, key2: 3 }
UTF8
Ruby 1.9 ayant introduit la prise en charge complète de l'UTF-8 au niveau des chaînes, Ruby 2.0 traite désormais les fichiers de code source dans cet encodage (ce qui peut poser des problèmes de compatibilité).
Débogage
DTrace et SystemTap sont maintenant pris en charge pour instrumenter l'exécution des scripts.
Variables non utilisées
Les variables commençant par _
peuvent désormais être inutilisées dans vos sources sans causer de warning. C'est l'option -w
qui permet d'activer cette fonction.
# Ruby 1.9
def foo
_, world = 'hello, world'.split(', ')
world
end
# => pas d'avertissement
# Ruby 2.0
def hi
_hello, world = 'hello, world'.split(', ')
world
end
# => pas d'avertissement non plus.
Création de hash
to_Hash
permet de convertir une classe en hash. Cette méthode a été implémentée pour nil
, Struct
et OpenStruct
# Ruby 2.0:
Car = Struct.new(:make, :model, :year) do
def build
#...
end
end
car = Car.new('Toyota', 'Prius', 2014)
car.to_h # => {:make=>"Toyota", :model=>"Prius", :year=>2014}
nil.to_h # => {}
Attention, cela n'a pas été implémenté pour les classes Enumerable
/Array
{hello: 'world'}.map{|k, v| [k.to_s, v.upcase]}
.to_h # => NoMethodError:
# undefined method `to_h' for [["hello", "WORLD"]]:Array
Chemin du dossier courant
__dir__
retourne le chemin absolu du dossier du fichier en cours d'exécution.
Création de tableaux de symboles
%i et %I ont été ajoutés pour la création de tableaux de symboles avec une syntaxe minimale.
# Ruby 1.9:
KEYS = [:foo, :bar, :baz]
# Ruby 2.0:
KEYS = %i[foo bar baz]
de la même manière que %w et %W servaient à la création simplifiée de listes de chaîne de caractères :
KEYS = %w[foo bar baz]
KEYS = ["foo", "bar", "baz"]
Inclusion par précédence
Lorsqu'un module est inclus dans un autre, il se retrouve automatiquement ajouté après la définition de celui qui l'inclut. Cela oblige à pas mal de gymnastique lorsque l'on veut "wrapper" des méthodes du conteneur.
class Template
def initialize(erb)
@erb = erb
end
def render values
ERB.new(@erb).result(binding)
end
end
module RenderProfiler
def self.included base
base.send :alias_method, :render_without_profiling, :render
base.send :alias_method, :render, :render_with_profiling
end
def render_with_profiling values
start = Time.now
render_without_profiling(values).tap {
$stderr.puts "Rendered in #{Time.now - start}s."
}
end
end
class Template
include RenderProfiler
end
Template.ancestors
#=> [Template, RenderProfiler, Object, Kernel, BasicObject]
Désormais il est possible d'inclure un module avant la défintion de son conteneur:
module RenderProfiler
def render values
start = Time.now
super(values).tap {
$stderr.puts "Rendered in #{Time.now - start}s."
}
end
end
class Template
prepend RenderProfiler
end
Template.ancestors
#=> [RenderProfiler, Template, Object, Kernel, BasicObject]
Exemples ci-dessus issus du blog de Ben Hoskings
Onigmo : nouveau moteur d'expression régulière
Onigmo remplace Oniguruma comme moteur d'expressions régulières (c'est un fork). Il permet d'utiliser certaines fonctionnalités présentes dans perl depuis la version 5.10.
Notamment l'expression conditionnelle (?(condition)yes-pattern|no-pattern)
qui vaut yes-pattern
si la condition est vérifiée, no-pattern
sinon.
Refinements
Les versions précédentes de Ruby permettent déjà de redéfinir des méthodes ou d'étendre des classes existantes. Le défaut principal de cette fonction très puissante est que les modifications de classes existantes se retrouvent dans tout un projet ainsi que les librairies utilisées. Les refinements, introduits dans Ruby 2.0 en fonctionnalité expérimentale, permettent d'effectuer ces modifications de manière "cloisonnée".
Magnus Holm en a donné un bon exemple dans un article à ce sujet (en anglais)
module TimeExtensions
refine Fixnum do
def minutes; self * 60; end
end
end
class MyApp
using TimeExtensions
def initialize
p 2.minutes
end
end
MyApp.new # => 120
p 2.minutes # => NoMethodError
Dans cet exemple, plutôt que d'ajouter la méthode minutes
dans la classe Fixnum
, il l'a ajouté en tant que «raffinement» dans le module TimeExtensions
. L'intérêt est que la méthode minutes n'existe que dans le bloc contenant using TimeExtensions
Lazy Enumerator et Enumerable
Enumerators et Enumerables sont maintenant disponibles en version lazy (optimisation visant à retarder une opération jusqu'au moment où son résultat est nécessaire, ou bien au moment où des ressources sont inoccupées ) :
Enumerable#lazy et Enumerator::Lazy permettent de gérer des suites potentiellement infinies (lazy streams)
A cela s'ajoutent Enumerator#size et Range#size pour déterminer la taille par évaluation retardée (lazy evaluation)
API de gestion asynchrone des exceptions
Une nouvelle API de gestion asynchrone des exceptions fait son apparition dans cette version 2.0.
Optimisations des performances
Ramasse-miette
Le ramasse-miettes a été optimisé par la technique du "bitmap marking". Il devrait radicalement réduire la mémoire occupée par les programmes ruby tournant sur serveur web. Narihiro Nakamura (en anglais) y travaillait depuis 2008.
L'idée principale est de profiter de la non-duplication de structures égales lors des forks (voir Copy-On-Write). En ruby, les valeurs sont divisées en deux parties : les données (RArray, RHash, RFile …) et un ensemble de flags. On appelle ces valeurs des RValue (Ruby Value).
Les ensembles de flags sont souvent identiques d'une RValue à une autre. Le système ne devrait donc pas avoir à les dupliquer. Seulement, l'un des flags FL_MARK
, est régulièrement modifié par le garbage collector pour indiquer les RValue recyclables. Comme celui-ci change très souvent de valeur, l'ensemble de flags varie, obligeant le système à dupliquer tout l'ensemble.
Narihiro Nakamura a donc sorti FL_MARK de la structure en regroupant tous les FL_MARK dans une collection de bit mappés à la RValue (d'où le "bitmap marking"). Ainsi Ruby peut régulièrement modifier FL_MARK sans toucher à l'ensemble de flags de la RValue.
Dès lors, le système n'a pas besoin de dupliquer les ensembles de flags lorsqu'ils sont parfaitement égaux pour deux RValue différentes. Vous l'aurez peut-être compris, ceci est valable lors des appels de fork qui, dans les systèmes UNIX, ne dupliquent pas la mémoire tant qu'elle est identique aux deux processus.
Pour plus d'informations à ce sujet, je vous invite à lire cet article très intéressant (en anglais).
Autres
D'autres optimisations ont été faites pour améliorer la vitesse de démarrage notamment sur Kernel#require
, les calculs sur des nombres à virgule flottante et sur la machine virtuelle. Cela profite déjà grandement au framework web Ruby on Rails.
Documentation
D'après le site ruby-lang.org : « Un effort important à également été produit pour améliorer la documentation, ce qui a été une demande régulière de la part de la communauté. Le volume de documentation rdoc pour les modules et les méthodes a ainsi notablement augmenté : 75% de la 2.0.0 est couvert, tandis que la 1.9.3 plafonnait vers les 60%. Par ailleurs, vous pouvez retrouver une description de la syntaxe ruby en appelant : »
$ ri ruby:syntax
L'ouvrage de référence sur Ruby (le "pickaxe") sort, lui, dans une nouvelle édition qui couvre désormais Ruby 2.0.
Autres mises à jour notables
La version 2.0.0 de RubyGems et la version 1.3 de Bundler accompagnent la sortie de Ruby 2.0, elles ajoutent la gestion de cette dernière, tout en restant compatible avec les 1.9.x.
De même, l'équipe de Ruby on Rails sort une version 3.2.13-rc1 compatible Ruby 2.0 ainsi qu'une version 4 en bêta pour qui Ruby 2 sera l'environnement de prédilection.
Aller plus loin
- Journal à l'origine de la dépêche (83 clics)
- journal de sortie ruby 1.9.2 (41 clics)
- nouveautés de ruby 2 par l'exemple (154 clics)
- Annonce officielle (87 clics)
- What's new in ruby 2.0 (83 clics)
# Quelques coquilles
Posté par windu.2b . Évalué à 4.
[^] # Re: Quelques coquilles
Posté par BAud (site web personnel) . Évalué à 1.
Corrigé.
Tu es le bienvenu en Rédaction pour traquer ce genre de coquilles (ou attendre le 5e fil de commentaire, plutôt que de le passer en first post).
[^] # Re: Quelques coquilles
Posté par _jordan_ . Évalué à 2.
ça c'est un peu ma signature, la faute sur le dernier mot que j'écris.
En programmation c'est pareil, je compile jamais du premier coup à cause du ; que j'ai oublié sur la dernière ligne écrite.
# Bof
Posté par gasche . Évalué à 2.
Les deux aspects les plus intéressants de Ruby sont le traitement de
yield
et l'histoire de_why
. Cette nouvelle version ne touchant aucun des deux, il me semble que l'annonce de Topaz intéressera plus les gens qui ne sont pas concernés par les petites améliorations incrémentales du langages.# VM
Posté par fredix . Évalué à 1. Dernière modification le 05 mars 2013 à 15:25.
Je ne suis plus l'actu de Ruby notamment de la VM. Elle utilise toujours les green threads ? La 2 ou la 1.9 utilise t-elle une nouvelle implémentation plus efficace ?
[^] # Re: VM
Posté par peikk0 . Évalué à 2.
Sur la page que tu cites, il y a bien « Ruby before version 1.9 » ;) Ruby 1.9 et 2.0 utilisent les pthreads.
[^] # Re: VM
Posté par fredix . Évalué à 1.
En effet désolé pour le bruit. Par contre cette page indique qu'il y a un toujours un global lock ce qui n'aide pas en perf je présume.
[^] # Re: VM
Posté par Jean B . Évalué à 6.
Oui et non. Le global lock est tout de même libéré lors des IO. Donc s'il n'est toujours pas envisageable de faire du calcul intensif sur plusieurs coeurs (sauf à utiliser une autre implémentation), les thread permettent tout de même de paralléliser les IO ce qui est loin d'être négligeable.
[^] # Re: VM
Posté par fredix . Évalué à 2.
ok merci pour l'info !
[^] # Re: VM
Posté par lasher . Évalué à 2.
J'ai aussi une question bête du coup. Est-ce qu'il est possible d'utiliser les « green threads » ET les pthreads ? Je m'explique : très souvent les pthreads sont utiles pour garantir qu'ils vont tourner sur des cœurs différents, et donc profiter de caches, etc. séparés. Mais les threads collaboratifs sont très utiles pour séparer logiquement les traitements quand l'ordre n'a pas d'importance (si on veut juste des séparations logiques, des fonctions/méthodes suffisent). Donc voilà, on utilise les pthreads pour séparer des traitements en parallèle (au moins pour les entrées/sorties), et on sépare les traitements indépendants en threads coopératifs pour les traitements qui vont arriver séquentiellement mais dont l'ordre d'exécution n'a pas d'importance.
Je ne sais pas ce que le verrou au niveau de l'interpréteur limite cependant. Si seules les E/S sont « débloquées » alors je ne vois pas l'intérêt d'utiliser les pthreads : autant utiliser GnuPth. Au moins c'est optimisé pour exactement ce cas (threads en espace utilisateur avec un mécanisme pour ne pas bloquer en cas d'E/S).
[^] # Re: VM
Posté par Jean B . Évalué à 2.
Pas vraiment. En fait la bibliothèque standard de ruby expose simplement une class Thread sans préciser d'implémentation. Le fait que ce soit implémenté avec des green thread, ou des pthreads et un GIL dépend de quelle implementation tu utilise. YARV (implémentation "de référence" de Ruby >= 1.9) à fait ce choix. JRuby par exemple implémente ça avec des trhead Java sans GIL ce qui n'est pas sans poser des problèmes avec les librairies non "thread-safe"
Pour ce qui est du reste de ta question je dois avouer que je ne suis pas suffisamment calé en threads pour te répondre avec certitude. Mais ce dont tu parles me rappelle les Fiber: http://www.ruby-doc.org/core-2.0/Fiber.html
[^] # Re: VM
Posté par lasher . Évalué à 2.
Oui, les fibers sont en gros ce que je veux, mais je veux aussi un vrai environnement multithread (ce qui n'est pas gagné, je sais, car les interpréteurs ont tendance a rendre les choses très compliquées pour les accès concurrents).
Du coup on a bien des threads coopératifs, on a bien des (p|green)threads, mais on se retrouve a faire uniquement du multiplexage en temps (pour les I/O), et pas de "vrai" parallélisme (il faut quand même un processus par cœur, puis plusieurs threads par processus, ce qui gâche de la mémoire).
Bon, c'est aussi le cas pour Perl et Python je crois, du coup je suppose qu'il faut se contenter de ça. :)
# String... symbol
Posté par lolop (site web personnel) . Évalué à 4.
Utilisateur de Python, je me demandais pourquoi il y avait en Ruby des string et des symboles (préfixe :), c'est lié au fait que les chaînes Ruby sont mutables. Un article là dessus The Difference Between Ruby Symbols and Strings.
Votez les 30 juin et 7 juillet, en connaissance de cause. http://www.pointal.net/VotesDeputesRN
[^] # Re: String... symbol
Posté par Jean B . Évalué à 4.
Oulà attention ! Les
Symbol
ne sont pas que desString
immuables.Les
Symbol
sont également des "singletons". Il t'es garanti qu'une seule instance d'un même symbol existe. Si tu crée deux symboles identiques la seconde instantiation te renverra en fait la première instance.Jusque là rien de grave. Par contre ça implique que les
Symbol
ne sont jamais déalloués par le GC. Autrement dit il ne faut jamais créer un symbol à partir d'une entrée utilisateur sans quoi tu t'exposes à un déni de service.[^] # Re: String... symbol
Posté par lolop (site web personnel) . Évalué à 4.
Ok, il y a un truc un peu similaire en Python, c'est l'utilisation de la fonction builtin intern().
Sauf qu'à partir de la version 2.3 ces chaînes "internes" ont perdu leur côté "immortel" jusqu'à la fin du process, donc désallouées si plus utilisées.
L'utilisation de intern() dans Python produit les mêmes avantages que les symboles de Ruby, ça permet des comparaisons directement sur l'identité de l'objet, donc plus rapide. Par contre l'utilisation en Ruby est plus directe en en faisant un élément syntaxique du langage là où Python n'en fait qu'un simple outil à partir d'une fonction.
Votez les 30 juin et 7 juillet, en connaissance de cause. http://www.pointal.net/VotesDeputesRN
[^] # Re: String... symbol
Posté par Jean B . Évalué à 2.
Oui c'est exactement ça. D'ailleurs en Ruby
Est un alias de
# En bon pythoniste, je m'interroge...
Posté par flan (site web personnel) . Évalué à 4.
Surtout sur cette phrase : « Sa principale caractéristique est de mettre en avant les besoins humains avant ceux informatiques, et notamment le fun et la productivité. »
C'est des arguments qui reviennent souvent quand on parle du Ruby, et franchement je ne vois pas en quoi c'est « fun » et en quoi il est plus « humain » qu'un autre langage. Les exemples que je vois me font quand même beaucoup penser à du Python, et ce dernier n'a jamais mis en avant ces aspects-là. D'ailleurs, j'ai un peu du mal à voir les avantages de l'un par rapport à l'autre (mis à part leurs catalogues de projets respectifs).
[^] # Re: En bon pythoniste, je m'interroge...
Posté par xcomcmdr . Évalué à 3.
Pour les différences :
http://stackoverflow.com/questions/1113611/what-does-ruby-have-that-python-doesnt-and-vice-versa
Aussi python a plus de trucs tiers que ruby je trouve (équivalent à PyGTK, pypy, voire Pygame en Ruby ? Pas vraiment…)
"Quand certains râlent contre systemd, d'autres s'attaquent aux vrais problèmes." (merci Sinma !)
[^] # Re: En bon pythoniste, je m'interroge...
Posté par Marc Quinton . Évalué à 6.
sur le site Rubytoolbox, tu pourras trouver les paquets logiciels (généralement sous forme de GEM) disponibles pour le langage Ruby : https://www.ruby-toolbox.com/ ; on peut y trouver une catégorie GUI-Framework qui contient plusieurs API de programmation d'interfaces graphiques.
Ce que j'apprécie dans Ruby :
Ayant pratiqué le langage PHP pendant des années, je viens tout juste de migrer sur Ruby. Et je me suis surpris à ne plus avoir envie de coder en PHP.
[^] # Re: En bon pythoniste, je m'interroge...
Posté par Alex . Évalué à 10.
Vu que personne ne regarde un petit troll discret:
AMHA c'est plus lié à php qu'à ruby
[^] # Re: En bon pythoniste, je m'interroge...
Posté par barmic . Évalué à 2.
Ça me fait beaucoup penser à perl :
(c'est écris à l'envers, la notation n'est pas objet et split n'a pas le fonctionnement par défaut de ruby)
Après ce n'est rien de bien spécifique à ruby, avec de bonnes méthodes n'importe quel langage objet le permet (je parle pas des times et autres).
Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)
[^] # Re: En bon pythoniste, je m'interroge...
Posté par sifu . Évalué à 3.
Pour avoir fait un peu de Ruby, j'ai beaucoup apprécié les codes blocks qui permettait de faire des trucs assez élégants.
Par exemple, j'ai bien apprécié cela pour générer des XML (via http://builder.rubyforge.org/).
[^] # Re: En bon pythoniste, je m'interroge...
Posté par reno . Évalué à 2.
Comme gasche le note, Topaz réutilise pypy pour Ruby, mais bon Topaz c'est très, très jeune.
Après pypy ne supporte toujours pas Python3..
[^] # Re: En bon pythoniste, je m'interroge...
Posté par spider-mario . Évalué à 7.
Ruby-GNOME2 (qui supporte désormais GTK+ 3 contrairement à ce que suggère le nom), QtRuby
Rubinius
Gosu
[^] # Re: En bon pythoniste, je m'interroge...
Posté par xcomcmdr . Évalué à 2.
Merci beaucoup !
J'en étais resté à rubygame (abandonné) pour mes projets de jeux en Ruby, gosu a l'air énorme. :)
Le reste est aussi très intéressant.
"Quand certains râlent contre systemd, d'autres s'attaquent aux vrais problèmes." (merci Sinma !)
[^] # Re: En bon pythoniste, je m'interroge...
Posté par flan (site web personnel) . Évalué à 2.
Oui, mais ça ne répond pas à ma question :D
Comment peut-on dire que c'est plus « fun » et « humain » d'avoir des blocs délimités par end ou de pouvoir appeler une méthode sans les parenthèses ?
Après, sur le côté plus technique, je trouve qu'il y a vraiment peu de différences entre les deux, à part un peu de sucre syntaxique. Sauf le coup des parenthèses facultatives, qui enlève bêtement un côté super sympa de Python, le fait de pouvoir faire référence dans une variable à une fonction.
Sinon, je suis bien d'accord avec le message https://groups.google.com/forum/?fromgroups=#!msg/comp.lang.python/xBWUWWWV5RE/gyJRB9cihAIJ
[^] # Re: En bon pythoniste, je m'interroge...
Posté par Alex . Évalué à 4.
Les 2 sont tres proches, mais bon lorsque je me suis mis a ruby certaine choses me saoulaient en python, comme le self a se trimbaler, l'utilisation de fonctions au lieu de méthode (cas de len) qui oblige à avoir 2 sens de lecture, une lib standard un peu légère.
Ruby avait ce coté full objet, permettait plus d'introspection, permettait de faire très simplement des mixins (et proposait pas mal de design patterns en mixin), utilisait des blocs, permettait de faire très facilement de petits dsl, enfin bref permettait de développer rapidement et simplement avec encore moins de prise de tête que python
Bon par contre c'était il y a 10 ans… et python a évolué depuis (dailleurs j'aimerai bien retrouver les décorateurs en ruby, plus propre que les mixins je trouve)
[^] # Re: En bon pythoniste, je m'interroge...
Posté par xcomcmdr . Évalué à 3.
Euh c'est très facile à faire en Ruby avec Object#method :
http://stackoverflow.com/questions/485151/how-can-i-get-a-reference-to-a-method
Quant à ton lien qui parle du fait qu'en Ruby on peut modifier les classes de bases très facilement (monkey patching) :
1.Ça a toujours été déconseillé
2.Ruby 2.0 apporte les refinements pour résoudre le problème.
"Quand certains râlent contre systemd, d'autres s'attaquent aux vrais problèmes." (merci Sinma !)
[^] # Re: En bon pythoniste, je m'interroge...
Posté par barmic . Évalué à 2.
C'est encore expérimental.
Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)
[^] # Re: En bon pythoniste, je m'interroge...
Posté par Nicolas Blanco (site web personnel) . Évalué à 2.
Une des fonctionnalités sympa de Ruby est de permettre la création de sous-langages (DSL).
C'est une fonctionnalité utilisée par certaines librairies spécifiques, par exemple Rake, pour écrire des tâches spécifiques à un projet.
Les outils de déploiement Puppet et Chef utilisent aussi Ruby pour cette fonctionnalité en partie.
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.