Quoi de neuf dans Ruby 2.2 ?

En cette fin d’année 2014, les rubyists ont eu la joie de trouver sous le sapin la toute dernière version de Ruby. En effet, c’est le 25 décembre qu’a été publié Ruby 2.2.0.

Cette nouvelle mouture apporte en particulier un important changement en termes de performances mais contient aussi quelques nouveautés et corrections de bugs.

Nous vous proposons un petit tour d’horizon de ce qui a changé.

Performances

Jusqu’à maintenant, les symboles créés dans une application Ruby étaient gardés en mémoire sans aucun espoir de récupérer cet espace quand bien même les symboles ne seraient plus utilisés.

À partir de Ruby 2.2 les symboles créés avec String#to_sym et String#intern sont maintenant traités par le Garbage Collector (GC).

Cela peut apporter un important gain de performance, en particulier dans des applications créant de nombreux symboles de façon dynamique. On peut rapidement faire le lien avec les applications Ruby on Rails donc la core team a d’ailleurs annoncé que la version 5.0 tirerait parti de cette fonctionnalité et dépendrait donc de Ruby 2.2.

Les modifications autour du GC ne s’arrêtent d’ailleurs pas là puisque celui-ci continue son évolution vers de meilleures performances en passant à un modèle incrémental qui réduit le temps de pause dû aux différentes phases du garbage collecting.

La VM Ruby a également subi quelques améliorations comme l’utilisation de chaines gelées (frozen) en clés de hash ou un gain de performance sur le passage des keyword arguments.

On notera enfin l’utilisation de l’appel système vfork par les méthodes de création de processus comme spawn. L’appel vfork est en effet plus performant que fork.

Symboles en clés de hash

Ruby 1.9 a vu l’introduction d’une nouvelle syntaxe pour l’écriture des hash permettant de passer d’une syntaxe verbeuse

h = {
  :name => 'Marvin',
  :age => 42,
  :type => :robot
}

à une syntaxe plus légère et plus lisible, ressemblant un peu à JSON

h = {
  name: 'Marvin',
  age: 42,
  type: :robot
}

Cette nouvelle syntaxe a été majoritairement adoptée par les rubyists au fil des années mais certains cas restaient impossibles à gérer avec la nouvelle syntaxe comme les symboles contenant des espaces :

h = { "hello world": "Hello" }
SyntaxError: syntax error, unexpected ':'

Avec la version 2.2, Ruby permet enfin d’écrire ces symbole-clés comme n’importe quel autre :

h = { "hello world": "Hello" }
#=> { :"hello world" => "Hello" }

Nouvelles méthodes

Un certain nombre de méthodes a été ajouté à l’API Ruby.

Enumerable

On trouve maintenant Enumerable#slice_after et Enumerable#slice_when.

Enumerable#slice_after crée une slice après chaque élément qui correspond à la valeur passée en paramètre ou pour lequel le block retourne true :

[1, 2, 3, 4, 3, 5, 6].slice_after(3).to_a
#=> [[1, 2, 3], [4, 3], [5, 6]]

[1, 2, 3, 4, 5, 6, 7].slice_after { |n| n % 0 == 0 }.to_a
#=> [[1, 2], [3, 4], [5, 6], [7]]

Enumerable#slice_when passe deux éléments consécutifs au bloc et crée une slice quand celui-ci retourne true :

[1, 2, 3, 1, 4, 2, 3].slice_when { |n1, n2| n1 > n2 }.to_a
#=> [[1, 2, 3], [1, 4], [2, 3]]

File et File::Stat

Les classes File et File::Stat se voient dotées d’une nouvelle méthode birthtime qui retourne la date de création d’un fichier sous forme d’objet Time.

File.birthtime('somefile.txt')      #=> 2014-12-26 03:27:45 +0100
File.new('somefile.txt').birthtime  #=> 2014-12-26 03:27:45 +0100
File.stat('somefile.txt').birthtime #=> 2014-12-26 03:27:45 +0100

Kernel#itself

Cas étrange que celui de la méthode itself. Cette méthode, présente sur n’importe quel objet, retourne l’objet lui-même.

Intéressant mais quels peuvent en être les cas d’usage ?

On peut par exemple s’en servir dans le cas de transformations, dont la variante la plus simple serait aucune et retournerait simplement l’objet. On peut également s’en servir pour interagir de façon générique avec les méthodes de collection :

[1, 2, 3, 4, 1, 2, 2, 3].group_by(&:itself)
#=> { 1 => [1, 1], 2 => [2, 2, 2], 3 => [3, 3], 4 => [4] }

Method

La classe Method reçoit deux nouvelles méthodes : super_method et curry.

Autant la première est assez simple à comprendre, elle retourne la méthode qui serait appelée si la méthode courante appelait super.

class Person
  def hello
    'Hello I am a Person'
  end
end

class Bob < Person
  def hello
    'Hello I am Bob'
  end
end

meth = Bob.new.method(:hello).super_method
#=> #<Method: Person#hello>
meth.call
#=> Hello I am a Person

Autant curry est un peu plus complexe : elle retourne un Proc représentant la méthode à laquelle on peut passer une partie des arguments, ce qui retournera également un Proc tant que tous les arguments ne sont pas présents :

def intro(name, gender, age)
  "Hello, I am #{name}, I'm a #{gender} and I'm #{age}."
end

intro = method(:intro).curry
intro2 = intro.call('Robert Paulson', 'male') #=> #<Proc>

intro2.call(42) #=> "Hello, I am Robert Paulson, I'm a male and I'm 42."
intro2.call(84) #=> "Hello, I am Robert Paulson, I'm a male and I'm 84."

À noter qu’il est également possible de gérer les méthodes acceptant un nombre variable d’arguments en donnant l’arité à partir de laquelle appeler la méthode :

def list(*items)
  items
end

items = method(:list).curry(3)
items1 = items.call(:first)   #=> #<Proc>
items2 = items1.call(:second) #=> #<Proc>
items2.call(:third)           # => [:first, :second, :third]

Autres classes

Pour le reste les méthodes prev_float et next_float ont été ajoutées à la classe Float, la classe Dir reçoit une nouvelle méthode fileno, String se voit ajoutées trois méthodes qui concernent unicode : unicode_normalize, unicode_normalize! et unicode_normalized?, et enfin Binding qui gagne local_variables et receiver.

Méthodes revues

En plus de nouvelles méthodes, certaines méthodes déjà présentes dans le langage ont été étendues.

Enumerable

Les méthodes min, min_by, max et max_by acceptent maintenant un argument permettant de demander plusieurs valeurs :

[1, 3, 2, 4, 2].max(2) #=> [4, 3]
[1, 3, 2, 4, 2].min(3) #=> [1, 2, 2]

Process

Les méthodes comme spawn peuvent maintenant ouvrir les fichiers en écriture pour permettre la redirection depuis :out et :err.

spawn(command, in: '/dev/null')  # mode lecture
spawn(command, out: '/dev/null') # mode écriture
spawn(command, err: 'log')       # mode écriture

En savoir plus

Pour la liste complète des changements, modifications de la lib standard ou encore les méthodes rendues obsolètes, vous pouvez consulter l’annonce de sortie de Ruby 2.2.

Publié le 28 décembre 2014

Notre vision des choses vous correspond ? Vous avez envie de travailler avec nous ?