Aide-mémoire Ruby


Une fiche synthétique sur le langage de programmation Ruby pour rafraîchir sa mémoire ou découvrir ce langage si vous connaissez déjà un langage similaire comme Python, Perl ou PHP.

Elle aborde toutes les connaissances de base du langage, ainsi que l'essentiel de sa bibliothèque intégrée (Core API) mais pas sa bibliothèque standard, ni des bibliothèques populaires comme Ruby On Rails.

Cette fiche n'est pas recommandée pour quelqu'un souhaitant découvrir la programmation et ses principaux concepts. Pour cela, mieux vaut se tourner vers une véritable introduction à la programmation.

Damien Gouteux,
mis à jour le 18 septembre 2018,
créé le 10 mars 2015 (3 ans).

Sommaire

1. Bases

Date d'apparition du langage : 1995

Créateur : Yukihiro "Matz" Matsumoto (Japon)

Type : langage de script orienté objet

Philosophie :

Principaux traits :

Principaux concurrents : JavaScript, Python, Perl, PHP.

Version actuelle à la date d'écriture : 2.5.1 (2018)

Standardisation : ISO 30170:2012 (payant)

Extension d'un fichier Ruby : rb

Exécuter mon_fichier.rb : ruby mon_fichier.rb

Accéder aux options de l'interpréteur : ruby -h

Première ligne d'un fichier sous Linux : #!/usr/bin/ruby

Accéder à la console interactive : irb

IRb signifie Interactive Ruby.

Affichage

Affichage sur la sortie standard (console) : puts

Le programme le plus simple en Ruby : puts "Hello World!"

Interprétation de code dans une chaîne : puts "#{a+1}"

Mots réservés

Mots réservés (39) : BEGIN, END, alias, and, begin, break, case, class, def, defined?, do, else, elsif, end, ensure, false, for, if, in, module, next, nil, not, or, redo, rescue, retry, return, self, super, then, true, undef, unless, until, when, while, yield, __FILE__, __LINE__

Commentaires

Commentaires en Ruby : # mon commentaire jusqu'à la fin de la ligne

Commentaires sur plusieurs lignes :

=begin
  vos lignes
=end

BEGIN et END

Déclarer un bloc de code exécuté avant l'exécution du programme : BEGIN { code }

Déclarer un bloc de code exécuté après l'exécution du programme : END { code }

Organisation du code

Ruby considère une fin de ligne comme la fin d'une expression à interpréter sauf si un opérateur binaire termine la ligne ou si la ligne se termine par un backslash \.

Ruby fait la distinction entre majuscules et minuscules.

Retour sommaire

2. Autres ressources en ligne

La validité des liens a été vérifiée le 18 septembre 2018.

Retour sommaire

3. Variables, constantes et globales

Variables

Déclaration d'une variable locale : mon_identifiant = expression

Les caractères autorisés pour constituer mon_identifiant sont les chiffres, les lettres et le caractère souligné _.

Un identifiant NE PEUT PAS commencer par un chiffre néanmoins.

Un identifiant NE PEUT PAS être un des mots réservés.

Une variable ne durera que jusqu'à la fin de son bloc où elle définit (classe, fonction, module, begin/end {}.

Constantes

Déclaration d'une constante : Mon_identifiant = expression

En Ruby, une constante commence par une majuscule et EST modifiable mais un message d'avertissement sera généré :

warning: already initialized constant Mon_identifiant

warning: previous definition of Mon_identifiant was here

Les noms de classe en Ruby doivent être des constantes (et donc commencer par une majuscule).

La constance en Ruby est une constance de référence. Mon_identifiant réfèrera toujours le même objet. Mais cet objet peut-être changé lui. Pour geler l'état d'un objet, il faut utiliser sa méthode freeze.

Globales

Déclaration d'une variable globale (elle sera accessible partout) : $mon_identifiant = expression

Variables d'environnement

Les variables d'environnement sont stockées dans le dictionnaire ENV

Variables d'instance

Une variable d'instance commence par le signe @ : @a

Elles se déclarent dans le corps des méthodes.

Variables de classe

Une variable d'instance commence par le signe @@ : @@a

Elle se déclarent dans le corps de la classe.

Pseudo-variables

Ce sont des variables fondamentales utilisées par Ruby que l'on ne peut assigner à nouveau :

Les booléens true et false.

La "valeur vide" : nil.

Une référence vers l'objet courant : self.

Le nom du fichier courant : __FILE__.

Le numéro de la ligne courante : __LINE__.

Retour sommaire

4. Entiers et réels (Fixnum | Bignum, Float)

Pour chaque type, on présentera son nom et les formes possibles pour ses littéraux. On complétera par une liste de leurs principales méthodes.

Entiers

Nom Littéral
Fixnum, Bignum (fusionnées en Integer) 0b1 (binaire)
07 (octal)
0o10 (octal)
0xf (hexadécimal)
10 (décimal)
1_000 (1000 en format plus lisible)

Ruby transforme automatiquement un Fixnum en Bignum quand c'est nécessaire.

Réels

Nom Littéral
Float 1000.0
1E3
1.0e8
5e+10

Listes des fonctions principales :

Fonction Type retourné Description
f.floor
f.truncate
Fixnum | Bignum entier inférieur immédiat (troncation)
f.ceil Fixnum | Bignum entier supérieur immédiat
f.round Fixnum | Bignum arrondi
f.to_s String représentation en chaîne de caractère

5. Chaînes de caractères (String)

Nom Littéral
String "abcde"
'abcde'

Les chaînes avec des guillemets doubles interprètent les caractères spéciaux précédés d'un antislash ainsi que le code dans #{code}. Le code sera exécuté une fois à la création de l'objet et la valeur retournée sera substituée au code dans la chaîne.

Les chaînes avec les guillemets simples n'interprètent que les caractères spéciaux \' et \\, produisant ' et \ respectivement.

Le caractère spécial le plus utilisé est \n pour faire une nouvelle ligne.

Deux chaînes adjacentes sont automatiquement concaténées.

On peut définir des chaînes à l'aide de l'expression : %qX...X où X est un caractère délimiteur. Si X est ( [ { ou <, le caratère délimiteur de fin sera le caractère fermant respectif soit ) ] } ou >.

Listes des fonctions principales :

Fonction Description
to_s produit une chaîne
equal? égalité entre deux chaînes
size longueur de la chaîne
+ concaténation de 2 chaînes
* duplique n fois
upcase mise en majuscule
downcase mise en minuscule
s[i] accès au caractère à l'index i
s[n..m] extrait une sous-chaîne
s[n, longueur] extrait une sous-chaîne
index(s) cherche l'index d'une sous-chaîne
rindex(s) cherche l'index d'une sous-chaîne en partant de la fin

6. Booléens, intervalles et type vide (TrueClass | FalseClass, Range, NilClass)

Booléens

Classe Littéral
FalseClass false
TrueClass true

Intervalles

Nom Littéral
Range a..b
a...b

Cela produit un intervalle comprenant les valeurs entières de a à b.

En utilisant trois points, la valeur b est exclue.

Type "vide"

Il représente l'absence de référence. Une variable qui est égale à nil ne référence rien.

Classe Littéral
NilClass nil

Retour sommaire

7. Listes (Array)

Création

Le premier élément d'une liste en Ruby a 0 pour indice.

Le dernier élément d'une liste en Ruby à n-1 pour indice, où n est le nombre d'élément de la liste.

Un indice négatif signifie que l'on part de la fin : -1 désigne le dernier élément dans ce cas et -n, le premier élément de la liste, où n est le nombre d'élément de la liste.

Nom Littéral
Array [ 1, 2, 3]
1, 2, 3
%w(abc def)

La méthode de classe new permet de créer une nouvelle liste :

liste1 = Array.new # liste1 aura 0 élément
liste2 = Array.new(5) # liste2 aura 5 éléments nil
liste3 = Array.new(3, "a") # liste3 aura 3 éléments "a"
liste4 = Array.[]("a", "b", "c") # liste4 aura 3 éléments
liste5 = Array["a", "b", "c"] # liste5 aura 3 éléments
liste6 = Array(0..2) # liste6 aura 3 éléments : 0, 1, 2
# liste7 aura 4 éléments égaux à 0, 3, 6, 9. i est l'indice qui sera donné en paramètre au bloc :
liste7 = Array.new(4) { |i| i = i * 3 }

La classe Array inclut le module Enumerable

Fonctions d'accès

Fonction Type retourné Description
a[i], a.slice(i), a.at(i) selon valeur accès à la valeur à l'indice i. Si l'indice ne correspond à aucun élément, nil est retourné.
a.fetch(i) selon valeur accès à l'objet référencé par l'indice i. Si l'indice n'est pas valide, une exception de type IndexError est levée
a.fetch(i, v) selon valeur accès à l'objet référencé par l'indice i. Si l'indice n'est pas valide, v est retournée
a.fetch(i) { |i| actions } selon valeur accès à l'objet référencé par l'indice i. Si l'indice n'est pas valide, le résultat du bloc, auquel est passé l'indice en paramètre, est retourné
a[-1] selon valeur accès au dernier élément. Si l'indice ne correspond à aucun élément, nil est retourné.
a.first selon valeur retourne le premier élément de la liste a ou nil si la liste est vide
a.first(n) selon valeur retourne les n premiers éléments de la liste a
a.last selon valeur retourne le dernier élément de la liste a ou nil si la liste est vide
a.first(n) selon valeur retourne les n derniers éléments de la liste a
a.slice(s, n), a[s, n] Array renvoie une nouvelle liste constituée des éléments de la liste a à partir de l'indice s jusqu'à (s+n)-1.
a.slice(x..y), a[x..y] Array renvoie nouvelle liste constituée des éléments d'indice x à y dans a
a.slice(x...y), a[x...y] Array renvoie nouvelle liste constituée des éléments d'indice x à y-1 dans a
a.find(o), a.detect(o), a.indexOf(o), a.index(o), a.search(o) Fixnum | Bignum retourne le premier indice référençant l'objet o dans la liste a
a.rindex(o) Fixnum | Bignum retourne le dernier indice référençant l'objet o dans la liste a
a.find_all { |o| actions }, a.select { |o| actions } Array retourne une nouvelle liste avec tous les éléments pour lesquels le bloc, auquel on passe l'élément, retourne vrai
a.reject {|o| block } Array retourne une nouvelle liste contenant chaque élément de a pour lequel le bloc qui le prend en paramètre est faux
a.values_at(filter, ...) Array retourne les éléments de a correspondant au filtre filter qui peut être une suite d'indices ou d'intervalles (Range).

Fonctions d'affectation et d'insertion

Fonction Type retourné Description
a[i] = e e.class l'indice i de la liste référencera à présent l'objet e. Si i >= a.length, autant d'object nil sont insérés jusqu'à l'indice i qui référencera e
a[i, n] = e e.class les indices entre i+1 et (i+n) sont supprimés. L'indice i référence à présent l'objet e.
Si n est égal à zéro, un indice référençant l'élément e sera ajouté à la liste (comme insert) à i
a[i, n] = b # b est une liste Array (a) tous les indices entre i et (i+n)-1 référenceront à présent l'objet de même indice dans la liste b.
Si la liste b est trop petite, la liste a sera raccourcie
a.insert(i, o) Array (a) insère dans la liste juste avant l'indice i un nouvel indice qui référencera l'objet o et deviendra le nouvel indice i
a.fill(o) Array (a) tous les indices de la liste a référenceront l'objet o
a.fill(o, s), a.fill(o, s, n) Array (a) les indices de la liste a de s à la fin, ou de s à (s+n)-1 si n est spécifié, référenceront l'objet o
a.fill(o, x..y) Array (a) les indices de x à y de la liste a référenceront l'objet o
a.fill { |i| actions }, a.fill(s) { |i| actions }, a.fill(s, n) { |i| actions }, a.fill(x..y) { |i| actions } Array (a) les indices spécifiés référenceront le résultat du bloc auquel l'indice sera passé en paramètre
a.replace(b) Array (a == b) remplace les éléments de a par ceux de b (cela réaffecte a à une nouvelle liste)
a.unshift(o, ...) Array (a) ajoute un ou plusieurs éléments au début de la liste et retourne la liste
a.push(o, ...) Array (a) ajoute un ou plusieurs éléments à la fin de la liste et retourne la liste

Fonctions de suppression

Fonction Type retourné Description
a.clear Array (a) efface toute la liste, sa longueur sera égale à 0 après. Cette fonction modifie a, même si elle n'a pas de !
a.delete_at(i) Array (a) supprime l'indice i en retournant l'objet à qui il faisait référence. Si l'indice est invalide, nil est retourné. Cette fonction modifie a, même si elle n'a pas de !
a.delete(o) type de o (o) supprime tous les indices référençant o. Si aucun n'est trouvé, retourne nil. Cette fonction modifie a, même si elle n'a pas de !
a.delete(o) { actions } type de o (o) | résultat du bloc supprime tous les indices référençant o. Si aucun n'est trouvé, retourne le résultat du bloc qui n'est pas exécuté sinon. Cette fonction modifie a, même si elle n'a pas de !
a.delete_if { |o| actions } Array (a) supprime tous les indices pour lequel le bloc, auquel on passe l'objet référencé par l'indice, retourne vrai. Cette fonction modifie a, même si elle n'a pas de !
a.reject! {|o| block } Array (a) supprime dans a chaque élément pour lequel le bloc qui le prend en paramètre est vrai, équivalent à delete_if
array.slice!(index), array.slice!(s, n), array.slice!(x..y), array.slice!(x...y) type de l'élément supprimé |
Array des éléments supprimés
supprime les éléments spécifiés

Fonctions de tests et d'information

Fonction Type retourné Description
a == b TrueClass | FalseClass vrai si a et b ont la même longueur et a[i] == b[i] pour i compris entre 0 et la longueur-1.
a.member?(o), o in a, a.include?(o) TrueClass | FalseClass vrai si a contient un indice référençant l'objet o
a.any? TrueClass | FalseClass vrai si a contient au moins 1 indice référençant un objet autre que nil
a.all?(o) TrueClass | FalseClass vrai si tous les indices de a référencent l'objet o
a.empty? TrueClass | FalseClass vrai si la longueur de la liste a est égale à 0
a.eql?(b) TrueClass | FalseClass vrai si a et b sont le même objet ou sont deux listes contenant les mêmes références
a.size, a.length Fixnum | Bignum retourne la taille de la liste a
a.nitems Fixnum | Bignum retourne le nombre d'éléments non égal à nil dans la liste a
a.min selon élément retourne l'élément minimal de la liste a (tous les éléments doivent pouvoir être comparés)
a.max selon élément retourne l'élément maximal de la liste a (tous les éléments doivent pouvoir être comparés)

Autres fonctions principales

Fonction Type retourné Description
a + b, a | b, a.concat(b) Array retourne une nouvelle liste qui est la concaténation de a et b
a - b Array retourne une nouvelle liste qui contient les éléments de a ne figurant pas dans b
a * i Array si i est un entier, retourne une nouvelle liste qui est la concaténation de i fois a
a * abc String si abc est une chaîne, retourne une nouvelle chaîne qui est la concaténation des éléments de a séparés par abc. Équivalent de join.
a & b Array renvoie une nouvelle liste contenant les éléments communs à a et b
a << e Array (a) ajout d'un élément e dans a
a <=> b Fixnum (-1, 0 ou 1) passe les éléments a et b à l'opérateur <=> un à un. S'arrête dès que le résultat est différent de 0 (donc à la première différence) et retourne le résultat
a.shift selon élément retourne le premier élément et l'enlève. Retourne nil si la liste a est vide
a.pop selon élément retourne le dernier élément et l'enlève. Retourne nil si la liste a est vide
a.reverse Array donne la liste inversée
a.reverse! Array inverse l'ordre des éléments de a
a.flatten Array si la liste contient des listes, elles seront toutes fusionnées en la seule liste qui sera retournée
a.flatten! Array si la liste contient des listes, elles seront toutes fusionnées au sein de la liste a. Retourne nil si aucune modification n'est faite
a.frozen? TrueClass | FalseClass retourne vrai si la liste ne peut être modifiée (soit par l'appel de la fonction freeze, soit durant un tri de façon temporaire)
a.hash Fixnum retourne une valeur unique selon le contenu de la liste. Deux listes avec le même contenu auront la même valeur
a.each { |o| actions } Array (a) parcours chaque élément de la liste a en le passant en paramètre du bloc
a.reverse_each { |o| actions } Array (a) parcours chaque élément de la liste a en ordre inverse en le passant en paramètre du bloc
a.each_index { |i| actions } Array (a) parcours chaque élément de la liste a en passant son indice en paramètre du bloc
a.compact Array retourne une nouvelle liste à partir de a en ne reprenant pas les indices qui référencent nil
a.compact! Array supprime dans la liste a les indices qui référencent nil. Retourne nil si aucun n'a été trouvé, a sinon
a.map {|o| actions} a.collect {|o| actions} Array invoque le bloc pour chaque élément de la liste a et collecte les résultats dans une nouvelle liste retournée
a.map! {|o| actions} a.collect! {|o| actions} Array (a) remplace chaque élément de la liste a par l'élément retourné par le bloc appelé avec l'objet que référence l'indice en paramètre
a.partition { |o| block } Array retourne une liste contenant deux listes. Dans la première sont les éléments pour lequel le bloc est vrai. Dans la seconde sont les éléments pour lequel le bloc est faux
a.join(sep) String fusionne tous les éléments de la liste a en y intercalant la chaîne sep (pareil que l'opérateur * avec une chaîne)
a.each_with_index { |o, i| block } Array (a) parcours la liste avec un bloc recevant l'élément et un index
a.uniq Array retourne une nouvelle liste en supprimant les éléments en double
a.uniq! Array (a) enlève les éléments en double dans a
a.sort, a.sort { |a, b| actions } Array retourne une nouvelle liste en triant les éléments de la liste a
a.sort!, a.sort! { |a, b| actions } Array (a) trie la liste a
a.zip(p, ...), a.zip(p, ...) { |arr| actions } Array | NilClass p doit répondre à la méthode each. Associe chaque élément de p à un élément de a et retourne la nouvelle liste ainsi constituée. Si un bloc est fourni, chaque élément ainsi créé sera passé en paramètre au bloc mais la méthode retournera nil
a.assoc(o) Array la liste a doit être une liste de liste. Retourne la première liste (par ordre d'indice) qui se trouve dans a dont le premier élément est une référence vers o.
a.rassoc(o) Array la liste a doit être une liste de liste. Retourne la première liste (par ordre d'indice) qui se trouve dans a dont le second élément est une référence vers o.
a.to_a Array (a) renvoie la liste elle-même. si cette méthode est appelée sur une instance d'une sous-classe de Array, le résultat sera une instance d'Array (la classe-mère)
a.to_ary Array (a) retourne a
a.to_s String retourne a.join (c'est-à-dire une chaîne des éléments de la liste concaténés sans séparateur)
a.inspect String renvoie une version affichable de la liste
a.inject(initial) { |r, o| block } selon r exécute un bloc sur chaque élément en passant le résultat à l'exécution suivante dans r. r est initialisé à a[0] et l'exécution du bloc commence à a[1] si initial n'est pas défini. Sinon r est égal à initial et l'exécution du bloc commence à a [0]
a.pack(template) String transforme le tableau en une séquence binaire (sous la forme d'une chaîne) selon le format template
a.transpose Array ne marche que si a est une liste de liste. inverse les lignes et les colonnes

Retour sommaire

8. Dictionnaires (Hash)

Création

Un dictionnaire, ou table de hachage, associe une clé à une valeur. La clé peut être de n'importe quel type, comme la valeur.

Lorsque l'on tente d'accéder à une valeur par une clé qui n'existe, nil est retourné ou la valeur par défaut, si elle a été définie lors de la création du dictionnaire.

Nom Littéral
Hash { 1 => 'a' , 2 => 'b' , 3 => 'c' }

La méthode de classe new permet de créer un nouveau dictionnaire :

dico1 = Hash.new # dico1 aura 0 élément
dico2 = Hash.new(23) # 0 élément et 23 comme valeur par défaut
dico3 = Hash.new[1 => 'a', 2 => 'b'] # dico3 aura 2 éléments

On peut changer plus tard le hash en utilisant :

dico2.default = nouvelle_valeur

Fonctions d'accès

Fonction Type retourné Description
d[key] d[key].class retourne la valeur de la paire avec la clé correspondante. Si elle n'existe pas, retourne la valeur par défaut dictionnaire
d.fetch(key)
d.fetch(key, default)
d[key].class | default.class retourne la valeur de la paire avec la clé correspondante. Si elle n'existe pas et qu'un paramètre default a été spécifié il est retourné. Sinon une exception KeyError est levée. la valeur par défaut du dictionnaire n'est pas utilisée
d.fetch(key) { | key | block } d[key].class | selon bloc retourne la valeur de la paire avec la clé correspondante. Si elle n'existe pas, le bloc auquel on passe la clé demandée en paramètre est exécuté et son résultat retourné. Il ne sert à rien de passer un second paramètre defaut si on utilise un bloc car le paramètre sera ignoré
d.key(value)
d.index(value) # ne plus utiliser
selon la clé trouvée retourne une des clés correspondant à la valeur value, ou nil si la valeur n'a pas été trouvée (indépendamment de la valeur de d.default)
d.each { |key, value| block }
d.each_pair { |key, value| block }
Hash (d) parcours l'ensemble du dictionnaire, exécutant à chaque fois le block qui reçoit en paramètre la paire clé-valeur
d.each_key { |key| block } Hash (d) parcours l'ensemble du dictionnaire, exécutant à chaque fois le block qui reçoit en paramètre la clé de la paire
d.each_value { |key| block } Hash (d) parcours l'ensemble du dictionnaire, exécutant à chaque fois le block qui reçoit en paramètre la valeur de la paire
d.select { |key, value| block } Hash retourne un dictionnaire constitué des paires de d pour lesquelles le block, auquel on passe la clé et sa valeur correspondante, retourne vrai
d.reject { |key, value| block } Hash retourne un dictionnaire constitué des paires de d pour lesquelles le block, auquel on passe la clé et sa valeur correspondante, retourne faux
d.values_at(key1, key2, ...) Array retourne une liste contenant les valeurs correspondant aux clés données en paramètres

Fonctions d'affectation et d'insertion

Fonction Type retourné Description
d[key] = value value.class stocke une nouvelle paire (key, value) dans d ou met à jour la valeur pour la paire ayant la clé key
d1.merge(d2) Hash (d1) retourne un nouveau dictionnaire, résultant de la fusion de d1 et d2. Si une clé existe à la fois dans d1 et d2, la valeur correspondante dans d2 est prise
d1.merge(d2) {|key, d1val, d2val| block} Hash (d1) retourne un nouveau dictionnaire, résultant de la fusion de d1 et d2. Si une clé existe à la fois dans d1 et d2, la valeur finale sera déterminée par le block auquel la clé, la valeur correspondante dans d1 et la valeur correspondante dans d2 sont passées
d1.merge!(d2)
d1.update(d2)
Hash (d1) met à jour d1 selon d2 : ajoute les paires clé-valeur existant dans d2 et non d1, met à jour les clés de d1 contenues aussi dans d2 en prenant la valeur de d2
d1.merge!(d2) {|key, d1val, d2val| block}
d1.update(d2) {|key, d1val, d2val| block}
Hash (d1) met à jour d1 selon d2 : ajoute les paires clé-valeur existant dans d2 et non d1. Si un clé existe de d2 existe déjà dans d1, la valeur finale sera déterminée par le block auquel la clé, la valeur correspondante dans d1 et la valeur correspondante dans d2 sont passées
d1.replace(d2) Hash (d2) remplace le contenu de d1 par celui de d2
d.store(key, value) value.class stocke la valeur value à la clé key dans d ou si key existe déjà dans d, met à jour la valeur. Retourne value
d.shift Array retourne une paire sous la forme d'un tableau [clé, valeur] en l'enlevant de d

Fonctions de suppression

Fonction Type retourné Description
d.clear Hash (d) enlève toutes les paires du dictionnaire
d.delete(key) d[key].class enlève la paire correspondant à la clé key
d.delete(key) { |k| block } d[key].class ou selon bloc enlève la paire correspondant à la clé key. Si la clé n'est pas trouvée, retourne le résultat du bloc auquel la clé key est passé en paramètre
d.delete_if { |key,value| block } Hash (d) enlève toutes les paires du dictionnaire pour lequel le bloc, auquel la paire est passée en paramètre, retourne vrai
d.reject! { |key, value| block } Hash (d) ne garde que les paires pour laquelle le bloc, auquel on passe la clé et sa valeur, retourne faux
d.select! { |key, value| block } Hash (d) ne garde que les paires pour laquelle le bloc, auquel on passe la clé et sa valeur, retourne vrai

Fonctions de tests et d'information

Fonction Type retourné Description
d1 == d2 TrueClass | FalseClass retourne vrai si les deux dictionnaires ont le même nombre de paires et qu'elles sont égales
d.empty? TrueClass | FalseClass retourne vrai si le dictionnaire ne contient pas de paires
d.default(p = nil) selon valeur retourne la valeur par défaut qui est retournée lorsque l'on tente d'accéder à la valeur d'une clé qui n'existe pas, on peut passer une valeur qui sera envoyée à la procédure par défaut, si un bloc a été passé à la création du dictionnaire
d.default_proc Proc retourne la procédure par défaut lorsqu'une clé n'existe pas, si un bloc a été passé à la création du dictionnaire, sinon retourne nil
d.has_key?(key)
d.include?(key)
d.key?(key)
d.member?(key)
TrueClass | FalseClass retourne vrai si le dictionnaire contient une paire avec la clé key
d.has_value?(value)
d.value?(value)
TrueClass | FalseClass retourne vrai si le dictionnaire contient une paire avec la valeur value
d.keys Array fournit une liste de toutes les clés des paires du dictionnaire
d.size
d.length
Fixnum | Bignum retourne le nombre de paires dans le dictionnaire
d.sort Array retourne une liste triée dont chaque élément est une sous-liste de 2 éléments : la clé et sa valeur
d.values Array fournit une liste de toutes les valeurs des paires du dictionnaire

Autres fonctions principales

Fonction Type retourné Description
d.invert Hash renvoi un nouveau dictionnaire où, pour chaque paire (clé, valeur) de d, on aura une paire (valeur, clé)
d.rehash Hash (d) Reconstruit le dictionnaire suivant ses différentes valeurs. Si un itérateur le parcours et que la fonction est appelée, une exception RuntimeError sera levée dans l'itérateur
d.to_a Array retourne un tableau contenant autant de tableaux qu'il y a de paires dans d. Chaque tableau contient deux éléments : en premier la clé et ensuite sa valeur correspondante
d.to_hash Hash retourne le dictionnaire lui-même
d.to_s
d.inspect
String traduit le dictionnaire en une chaîne lisible et la retourne

Retour sommaire

9. Opérateurs

Opérateurs binaires

Type Syntaxe
Arithmétiques + - * / % (modulo) ** (puissance)
Comparaison < <= > >=
<=> (retourne 0 si égaux, 1 si le premier est le plus grand, -1 sinon)
Égalité == !=
=== (utilisé dans les clauses case)
Affectation = += -= *= /= %= **=
Bit à bit & | ^ (ou exclusif) ~ (complément)
<< >> (décalages gauche et droit)
Logique and or && ||
Création d'intervalle borne_inf..borne_sup (inclusif)
borne_inf...borne_sup (exclusif de borne_sup)
Appel de méthode objet.message
Accès à une constante définie dans un module ou une classe identifiant::constante

La méthode eql? teste à la fois la valeur et le type des 2 objets comparés. Ainsi 2.0 == 2 est vrai mais 2.0.eql?(2) retournera faux.

La méthode equal? retourne vrai si et seulement les deux objets ont le même id.

Ruby permet des affectations parallèles : x, y = 10, 20. Cela est utilise pour échanger la valeur de deux variables sans passer par une troisième : x, y = y, x.

Opérateurs unaires

Type Syntaxe
Mathématique + -
Logique ! not
Définition defined? identifiant
Résolution de portée ::identifiant

defined? retourne nil si l'identifiant ne correspond à aucune variable, la chaîne "local-variable" s'il correspond à une variable locale, "constant" s'il correspond à une constante, et "global-variable" s'il correspond à une variable globale.

L'opérateur de résolution de portée sert lorsqu'une constante à l'intérieur d'un module porte le même nom qu'une constante d'une plus grande portée. Pour pouvoir accéder à la constante qui a la portée la plus grande, on la précède de :: :

Bonjour = 0
module Cache
  Bonjour = 22
  puts Bonjour # affichera 22
  puts ::Bonjour # affichera 0
end

Opérateur ternaire

Type Syntaxe
Opérateur ternaire expression ? action si vrai : action si faux

Précédence des opérateurs

Voici les opérateurs du plus prioritaire au moins prioritaire (les opérateurs sur la même ligne ont la même précédence) :

::
[] []=
**
! ~ + (unaire) - (unaire)
* / %
+ -
>> <<
&
^ |
<= < > >=
<=> == === != =~ !~
&&
||
.. ...
? : (ternaire)
= %= { /= -= += |= &= >>= <<= *= &&= ||= **=
defined?
not
or and

Redéfinition d'opérateur

Les opérateurs ::, [], []=, **, !, ~, +, -, * / %, >>, <<, &, |, ^, <=, <, >, >=, <=>, ==, ===, !=, =~, !~ sont des fonctions et peuvent donc être redéfinies, changeant ainsi le comportement des opérateurs :

def +(a)
  # votre code ici
end

Attention, rappelez vous que a + b et b + a ne sont pas équivalent. Le premier correspond à a.+(b) et le second à b.+(a). Si a et b ne sont pas du même type, vérifiez bien où vous redéfinissez l'opérateur.

Pour faire la différence entre les opérateurs unaires + et -, lorsque l'on redéfinit ceux-ci il faut employer +@ et -@

Retour sommaire

10. Contrôle du flux

Séquence

action # En Ruby, chaque instruction est une expression évaluable action # Il suffit de passer à la ligne pour les faire suivre
action ; action # Sur un même ligne, on sépare les actions par un ;

Conditions

Pour qu'une partie du code ne soit exécutée que si une condition est vrai, on utilisera if :

if condition [ then ]
   actions
[ elsif condition [ then ]
   actions ] *
[ else
   actions ] ?
end

Sont considérées fausses les valeurs false et nil. Toutes les autres valeurs sont vraies.

if peut également s'utiliser en modificateur de ligne ou de bloc :

action if condition

begin
  actions
end if condition

Ruby possède aussi l'instruction unless qui exécute le bloc qu'elle garde si et seulement la condition est fause. On pourrait la traduire par "à moins que" ou "sauf si".

unless condition [ then ]
   actions
[ else
   actions ] ?
end

unless peut également s'utiliser en modificateur de ligne ou de bloc :

action unless condition ]

begin
  actions
end unless condition

Ruby possède aussi l'instruction case qui permet d'exécuter du code en fonction de la valeur d'une expression. Lorsque l'expression qui suit directement le case est égale à une des expressions spécifiées par le when, les actions suivantes du when sont exécutées et seulement celles-ci (pas de falling-through à travers les when suivants comme en C avec "switch").

case expression
[ when expression [, expression]* [ then ]
  actions ]*
[ else
  actions ]
end

L'opérateur === est utilisé pour effectuer la comparaison, qui correspond à la méthode équivalente de l'expression utilisé dans le when.

Si aucun when ne correspond, les actions sous le else sont exécutées.

Répétitions

Boucle qui s'exécute tant que la condition est vraie :

while condition [ do ]
   actions
end

while peut également s'utiliser en modificateur de ligne ou de bloc :

action while condition

begin
  actions
end while condition

Dans ces deux derniers cas, le code est exécuté au moins une fois avant l'évaluation de la condition à la manière d'un "do ... while" dans d'autres langages.

De la même manière que unless et l'inverse de if, until est l'inverse de while : le code s'exécute tant que la condition est fausse.

until condition [ do ]
   actions
end

until peut également s'utiliser en modificateur de ligne ou de bloc, et le code sera exécuté également une fois avant la vérification de la condition :

action [ until condition ]

begin
  actions
end until condition

Autre grand classique des boucles, for :

for identifiant in expression [ do ]
   actions
end

Pour sauter à la prochaine itération de la boucle la plus interne, il faut utiliser next.

Pour quitter la boucle la plus interne, il faut utiliser break.

On peut recommencer la dernière itération de la boucle la plus interne, sans vérifier la condition à nouveau néanmoins, avec redo. Attention aux boucles infinies.

On peut recommencer totalement l'itération de la boucle la plus interne avec retry. Cette fonctionnalité a été désactivée depuis Ruby 1.9 et génère à présent une exception de type SyntaxError.

for i in 1..3 # lance 3 fois un dé
  de = Random.new.rand(1..6)
  puts i, de
  retry if de == 1 # recommence tout si on tombe sur 1 (Ruby < 1.9)
  redo if de < 4 # recommence l'itération si on tombe sur 2 ou 3
end

Ruby propose également des méthodes pour itérer sur un objet :

(1..10).each { |i| actions }
1.upto(10) { |i| actions }
10.downto(1) { |i| actions }
(1..10).step(2) { |i| actions }
['a', 'b'].each_with_index { |v, i| actions }

Retour sommaire

11. Fonctions

Définition d'une fonction

En Ruby, les fonctions sont toutes des méthodes, c'est-à-dire appartenant à un objet. Pour définir une méthode, il faut utiliser le mot-clé def.

def identifiant [ ( par [ = defval] [, pari [ = defval] ]* [, *parl ] [, &parh ] ) ]
   actions
end

# Exemple 1
def affiche_bonjour (nom)
   puts "Bonjour #{nom}"
end

# Exemple 2
def affiche_bonjour_x (nom, nb)
   i = 0
   while i < nb
      affiche_bonjour nom
      i += 1
   end
end

Si la fonction ne prend pas de paramètres, on peut se passer de parenthèse dans sa signature.

On peut préciser pour chaque paramètre une valeur par défaut. Si une valeur par défaut est définie, passer une valeur pour le paramètre devient optionnel.

Au contraire de Python, n'importe quel paramètre peut avoir une valeur par défaut, et on peut intercaler des paramètres avec et sans : def f (a=5, b).

Il faut toujours appeler une méthode avec le nombre de paramètre requis, au contraire d'un langage comme Lua. Sinon Ruby lèvera une exception ArgumentError

Il peut y avoir potentiellement jusqu'à deux paramètres spéciaux pour avoir un nombre variable de paramètres :

*nom doit toujours précédé &nom s'il existe. *nom doit toujours être en avant-dernière position si &nom existe ou en dernière position sinon. &nom doit toujours être en dernière position de la liste de paramètres.

Appel de fonction

Pour appeler une fonction, en Ruby on considère que l'on envoie un message (le nom de la fonction) à un objet, il faut utiliser la syntaxe suivante :

[ objet . ] identifiant [ ( paramètres ) ] # Appel de fonction
# Exemple
affiche_bonjour("Bob")
affiche_bonjour(nom="Bob")
affiche_bonjour "Slim"
affiche_bonjour nom="Slim"
affiche_bonjour_x "Bob", 2

Si aucun objet n'est précisé, le receveur est l'objet courant.

Les parenthèses sont optionnelles.

On peut préciser le nom du paramètre auquel on passe une valeur. Sinon l'attribution des valeurs se fait par la position.

On peut éclater un énumérable avec l'opérateur * :

*enum # Fracturation d'un énumérable pour passer différents arguments

# Exemple
a = ["Bob", 2]
affiche_bonjour_x *a

Attention : un hash se fracture en autant de liste qu'il a d'éléments. Chaque liste comportant 2 éléments : en indice 0 la clé, en indice 1 la valeur.

Retour de fonction

Normalement, une fois appelé, la fonction s'exécute jusqu'à sa fin.

En Ruby, une fonction retourne toujours une valeur, la dernière évaluée.

On peut sortir du code d'une fonction avec le mot-clé return, éventuellement suivi d'une expression :

return [ expression [, expressioni]* ] # Quitte la fonction

Si aucune expression n'est donnée, nil sera retourné. Si plus d'une expression sont données, le type du résultat sera Array.

Alias d'une fonction (et d'une variable globale)

En Ruby, on peut définir un alias, un nouveau nom pour une méthode ou une variable globale. Le premier nom reste inchangé, il s'agit juste d'un nouveau moyen d'y accéder. Pratique pour avoir par exemple deux noms, count et length, pour une fonction qui compte un nombre d'éléments, sans avoir à écrire deux fois le même code.

Un alias ne peut pas être défini dans le corps d'une fonction.

alias nouveau_nom ancien_nom # Définition d'un alias

Suppression de la définition d'une fonction

Supprime la définition d'une méthode.

Cela ne peut pas être fait dans le corps d'une méthode.

undef nom_methode # Suppression de la définition d'une fonction

Retour sommaire

12. Classes et objets

L'orientée objet

En Ruby, tout est objet. Une classe est la définition générale d'un concept, qui possède des attributs et des méthodes. Par exemple, une voiture (classe) a une couleur et un propriétaire (deux attributs) et elle peut rouler et s'arrêter (deux méthodes). Les instances d'une classe, ou objets, sont des cas particuliers du concept, la voiture rouge de Marc, la voiture verte de Katia, qui ont à leur disposition toutes les méthodes définies dans la classe, ici rouler et s'arrêter.

Ruby est donc un langage orienté objet. De façon universitaire, on définit l'orientation objet d'un langage par le fait de pouvoir :

En Ruby, une classe ne peut avoir qu'une seule classe mère, c'est le mono-héritage.

Enfin, et c'est là où la phrase "en Ruby, tout est objet" prend tout son sens, les classes sont des objets de la classe Class ! Si cette dernière phrase provoque des migraines chez vous, ignorez la pour l'instant.

Notons que d'autres langages sont orientés objets mais n'utilise pas la division classe/instance. Un tel exemple est le langage JavaScript, qui utilise une notion appelée prototype.

Création d'une classe

class identifiant [ < parent ]
   actions
end

A l'intérieur d'une classe, on définit des méthodes d'instances et à l'intérieur de celles-ci, des attributs des instances (appelés aussi variables d'instance).

class UneClasse < UneAutreClasse
   def une_methode (paramètre1, paramètre2)
     b = 2 # cette variable b est une variable locale, définie seulement pour la méthode
     @a = 1 # une variable d'instance commence par le symbole @
   end
end

Par convention, pour les noms des méthodes, on utilise des lettres minuscules et s'il y a plusieurs mots, on les sépare par un "_".

Pour les noms des classes, on utilise des mots accolés en les faisant commencer par une majuscule.

Redéfinition d'une méthode d'instance

Si dans une classe fille on nomme une méthode d'instance du même nom qu'une méthode d'instance qui se trouve dans une ou plusieurs de ses classes mères, on dit que l'on redéfinit cette méthode d'instance, on parle de redéfinition (ou overriding en anglais, à ne pas confondre avec overloading ou surcharge qui est un autre concept non utilisé en Ruby).

class UneClasse
   def une_methode
     puts "je suis une instance d'UneClasse"
   end
end

class UneClasseFille < UneClasse
   def une_methode # on va redéfinir cette méthode
     puts "je suis une instance d'UneClasseFille"
   end
end

Méthodes et variables de classe

On peut définir également des variables de classe. La valeur d'une variable de classe est la même pour toute les instances de la classe.

class UneClasse < UneAutreClasse
   def une_methode (paramètre1, paramètre2)
     @@c = 3 # cette variable de classe commence par deux symboles @
   end
   @@c = 5 # on peut définir une variable de classe en dehors de toute méthode d'instance
end

Les variables de classe ne sont néanmoins pas accessibles en dehors de leur classe. On utilisera une variable globale (commençant avec $) pour partager une valeur entre différentes classes.

Il existe également des méthodes de classe. Il faut faire précéder leur nom par le nom de la classe suivi d'un point.

class UneClasse < UneAutreClasse
   def UneClasse.une_methode (paramètre1) # ceci est une méthode de classe
     b = 2 # il ne peut y avoir que des variables locales ou
     @@c = 3 # des variables de classe dans son corps
   end
end

On n'a pas besoin d'avoir une instance pour appeler une méthode de classe.

Une méthode de classe ne peut pas accéder aux variables d'instance @.

Pour l'appeler, on spécifiera comme receveur la classe : UneClasse.une_methode.

Modifier la définition d'une classe

Pour ajouter une méthode d'instance ou de classe à une classe, ou remplacer le corps d'une méthode déjà définie, il suffit de réouvrir sa définition, sans répéter son éventuelle classe-mère.

class UneClasse
   def une_nouvelle_methode
   end
end

Création d'une instance

Pour créer une instance, il faut appeler la méthode de classe new qui est disponible dans toutes les classes.

# Code générique d'une création d'instance
nom_classe . new [ ( paramètres ) ]
# Exemple qui stocke une référence à l'objet créé dans mon_instance
mon_instance = UneClasse.new

La méthode de classe new va créer l'objet puis appeler sa méthode initialize en lui passant ses paramètres. On peut redéfinir cette méthode d'instance pour contrôler l'initialisation de notre objet. Par analogie avec d'autres langages, on appelle cette fonction un constructeur, bien que dans le cas de Ruby il s'agisse plutôt d'une initilisation.

class Voiture
   def initialize(col, proprietaire)
     @couleur = col
     @proprietaire = prop
   end
end
v1 = Voiture.new("rouge", "Marc")
v2 = Voiture.new("verte", "Katia")

Pour appeler une méthode d'instance, on utilise la syntaxe suivante : instance.methode(paramètres)

Encapsulation en Ruby

En Ruby, les attributs d'instances sont protégés, ils ne sont accessibles que dans les instances de la classe où ils sont définis et dans ses sous-classes.

En Ruby, les méthodes d'instances sont publiques par défaut, accessibles par tous. On peut utiliser les méthodes protected et private avant le def pour changer cela.

Une méthode protégée ne peut être appelée que dans la classe et dans ses sous-classes.

Contrairement aux autres langages orientés objetsoù une méthode privée ne peut être appelée que dans la classe même, en Ruby, une méthode privée peut-être appelée également dans ses sous-classes. La différence entre une méthode protégée et privée, et que cette dernière ne peut être appelée avec un receveur explicite (notation receveur . méthode ). De ce fait, une fonction privée ne peut être appelée que par son objet.

class A
   def une_methode_publique
   end
   protected
   def une_methode_protegee
   end
   private
   def une_methode_privee
   end
end

# Visibilité générale
a = A.new
a.une_methode_publique # marche
a.une_methode_protegee # lève une exception NoMethodError
a.une_methode_privee # lève une exception NoMethodError

# Visibilité dans une classe fille
class B < A
   def une_methode
     une_methode_publique # marche
     une_methode_protegee # marche
     une_methode_privee # marche
   end
end

Notons que quand une fonction est définie dans une classe, elle est par défaut publique. Au contraire, en dehors d'une classe, une méthode définie sera par défaut privée.

Le mot-clé self

Le mot-clé self contient une référence vers l'objet "en cours". Dans le corps d'une méthode d'instance, self désigne l'objet lui-même.

Dans le corps d'une classe, en-dehors des corps des méthodes d'instance, self désigne l'objet classe lui-même et non une instance !.

class A
   def une_methode
     self # L'instance elle-même
   end
   def self.une_methode_de_classe
   # équivalent à A.une_methode_de_classe
   end
end

Pour accéder à une variable d'instance, on ne peut pas utiliser self.

Pour accéder à une méthode d'instance dans le corps d'une méthode d'instance, faire précéder l'appel par self. n'est pas obligatoire (et résulte en une exception NoMethodError pour les méthodes d'instance privées). À quoi sert self alors ?

On peut retourner une référence à l'objet lui-même. Cela permet de chaîner les appels : mon_objet.methode1(a).methode2(b).methode3

On peut faire la distinction dans une méthode entre un appel de méthode sans paramètre et une variable locale portant le même nom :

class A
   def une_methode
    return 2
   end
  
   def une_autre_methode
    une_methode = 5
    puts une_methode # affiche 5
    puts self.une_methode # affiche 2
   end
end

Le mot-clé super

super # Pour accéder aux fonctions du parent

Les méthodes d'actualisation (mutators)

Type objet

Fonction Type retourné Description
object.method(id) renvoie s'il existe un objet Method correspondant à l'id
identifiant.new crée une nouvelle instance
identifiant.clone clone l'objet
identifiant.is_a? ou kind_of? renvoie vrai s'il est de cette classe
identifiant.class donne la classe de l'objet
identifiant.methods liste de chaînes de symboles de toutes les méthodes de l'objet
identifiant.respond_to? l'objet répond-t-il au message ? (= s'il a une méthode correspondante)

Retour sommaire

13. Modules et fichiers

Définition d'un module

Un module en Ruby est un espace de nom dans lequel vous pouvez déclarer des constantes, des fonctions et des classes. De base, des éléments portant le même nom mais déclarés dans des modules différents sont des objets différents.

module identifiant
   actions
end

Les fonctions de module se déclarent comme les fonctions de classe, en précédant l'identifiant de la fonction par celui du module suivi d'un point : def mon_module.ma_fonction.

Inclusion des éléments d'un module

On peut en Ruby importer tous les éléments définis dans un module dans l'espace de nom courant à l'aide de include :

include identifiant_module

On aura plus alors à précéder les éléments déclarés dans le module par son nom et :: (pour les constantes) ou . (pour les fonctions).

module Bob
    ConsBob = 6
end
puts Bob::ConsBob # Bob:: est requis
include Bob
puts ConsBob # Plus besoin de Bob::

Ruby ne supporte pas l'héritage multiple (le fait pour une classe d'avoir plusieurs classes mères). En incluant un module dans une classe, les instances de cette classe auront accès aux fonctions définies dans le module comme des méthodes d'instance. On appelle cette technique d'émulation de l'héritage multiple des mixins.

Les fonctions définies dans le module peuvent utiliser des variables d'instance (@) comme si elles avaient été définies dans la classe.

module Mix
    def display
        puts @val
    end
end

class Test
    include Mix
    def initialize(val)
        @val = val
    end
end

t = Test.new(55)
t.display

Code réparti sur plusieurs fichiers

Quand on a du code dans plusieurs fichiers, si on veut qu'un fichier A utilise du code du fichier B, il faut utiliser l'instruction require :

# Exige la présence d'un fichier
require "nom_du_fichier"
require "nom_du_fichier.rb"
require a #a est convertible en chaîne

Si le fichier ne peut pas être chargé, une exception LoadError sera levée.

Le fichier sera cherché dans tous les dossiers listés dans la variable globale $LOAD_PATH.

De base, le dossier du script courant n'est pas dans $LOAD_PATH, il faut le rajouter manuellement avant de faire le require ainsi : $LOAD_PATH << '.'

Retour sommaire

14. Gestion des exceptions

Exceptions

Pour gérer une exception il suffit d'ajouter un ou plusieurs blocs rescue à un bloc begin / end.

begin
   actions
rescue [ identifiant_type [=> identifiant_variable] ]
   actions
[ else    actions ]
[ ensure
   actions ]
end

L'identifiant passé en paramètre du rescue indique le type d'exception capturée (ainsi que ses sous-classes) par la clause rescue.

Si l'exception ne correspond pas à un des identifiants attendus par les clauses rescue, le code dans la clause else sera exécuté.

La clause ensureindique du code qui sera toujours exécuté à la fin, qu'il y ait eu une exception ou pas, et même s'il y a un return dans le bloc initial.

Pour lever une exception :

raise
raise chaîne
raise Type, chaîne

Le type de base des exceptions dans les cas 1 et 2 est RuntimeError.

La variable globale $! contient le message de la dernière exception levée ou nil s'il n'y en avait pas.

Ruby permet aussi dans une clause rescue de reprendre l'exécution à partir du begin avec le mot clé retry :

retry

Attention aux boucles infinies avec retry! La puissance vient avec son prix !

Type d'exceptions

Les classes d'exception descendent toutes de Exception. Elle a 7 classes filles : Interrupt, NoMemoryError, SignalException, ScriptError, StandardError, SystemExit. RuntimeError est une classe fille de StandardError.

On peut bien sûr définir nos propres classes d'exception :

class MonException < StandardError
  def initialize(reason)
    @reason = reason
  end
end

On l'a lèvera en déclarant une nouvelle instance :

raise MonException.new("motif de l'erreur")

Catch et throw

En plus ce que nous venons de voir, Ruby propose un modèle pour dépiler la pile jusqu'à un point précis. On définit déjà une étiquette pour un bloc avec catch. Si on utilise throw dans ce bloc ou dans une fonction appelée dans ce bloc, Ruby interrompra l'exécution du bloc, dépilera jusqu'à son début et le sautera.

a = "abc"
catch :reviens do
  a.upcase!
  throw :reviens, 0
  # code jamais exécuté
end

Le second paramètre optionnel après le throw est la valeur qui sera retournée (comme toute instruction en Ruby est évaluable, le bloc catch l'est aussi). S'il n'est pas fourni, nil sera retourné.

throw :symbole
throw "chaîne"
throw :symbole, expression
throw "chaîne", expression

De même, catch peut s'utiliser avec un symbole ou une chaîne :

catch :symbole
catch "chaîne"

Retour sommaire

15. Utiles

Randow.new.rand(min..max) # Nombres aléatoires (min et max inclus)

Sérialisation (doc) :

data = Marshal.dump(o) # sérialise dans une chaîne
obj = Marshal.load(data) # charge la chaîne

Retour sommaire