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 :
- Développer rapidement et en y prenant du plaisir,
- Principe de moindre surprise.
Principaux traits :
- Syntaxe simple dérivée d'Algol et Pascal, proche de Lua,
- Blocs de code passables comme paramètres,
- Gestion automatique de la mémoire,
- Gestion de niveaux de confiance,
- Gestion des exceptions.
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 :
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.
2. Autres ressources en ligne
La validité des liens a été vérifiée le 18 septembre 2018.
- Sites principaux
- Site officiel du langage : https://www.ruby-lang.org
- Site de la documentation : http://ruby-doc.org/
- Installer Ruby sur Windows : http://rubyinstaller.org/
- Télécharger le code source de Ruby : https://www.ruby-lang.org/fr/downloads/
- Fiches Wikipédia en français et en anglais sur Ruby
- Tester Ruby en ligne
- Console Ruby en ligne : https://ruby.github.io/TryRuby/
- Une autre console Ruby en ligne : https://repl.it/languages/ruby
- Site d'actualités
- Ruby Inside, actualités et tutoriels (jusqu'à 2014): http://www.rubyinside.com/
- Apprendre et progresser en Ruby
- Site de tutoriels Tutorials Point : http://www.tutorialspoint.com/ruby/
- Ruby Quicktips, des bouts de code utile : http://rubyquicktips.com/
- Livre sur Wikibooks : https://en.wikibooks.org/wiki/Ruby_Programming
- Le Pickaxe, livre de référence sur Ruby 1.6 (dépassée) : Programming Ruby
- Liste de bibliothèques pour Ruby
- Dépôt RubyGems : https://rubygems.org/
- Dépôt The Ruby Toolbox : https://www.ruby-toolbox.com/
- Ruby On Rails (RoR), le framework qui a fait connaître Ruby : http://rubyonrails.org/
- Gosu, une bibliothèque pour faire des jeux 2D : https://www.libgosu.org/
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__.
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 |
- Dans les tests, toutes les valeurs autres que false et nil sont vraies (dont 0).
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 |
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 :
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 |
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 :
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 :
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 |
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 :: :
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 :
# 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 -@
10. Contrôle du flux
Séquence
Conditions
Pour qu'une partie du code ne soit exécutée que si une condition est vrai, on utilisera if :
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 :
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".
actions
[ else
actions ] ?
end
unless peut également s'utiliser en modificateur de ligne ou de bloc :
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").
[ 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 :
actions
end
while peut également s'utiliser en modificateur de ligne ou de bloc :
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.
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 :
begin
actions
end until condition
Autre grand classique des boucles, for :
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.
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.upto(10) { |i| actions }
10.downto(1) { |i| actions }
(1..10).step(2) { |i| actions }
['a', 'b'].each_with_index { |v, i| actions }
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.
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 indique qu'il peut y avoir une infinité de paramètres, séparés par une virgule. Ils seront tous stockés dans nom sous la forme d'une liste.
- &nom indique qu'il peut y avoir une infinité de paramètres nommés, constitués d'un identifiant = une valeur. Ils seront tous stockés sous la forme d'un dictionnaire.
*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 :
# 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 * :
# 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 :
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.
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.
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 :
- cacher certains attributs d'une classe aux autres, c'est l'encapsulation,
- reprendre la définition générale d'une classe (la classe mère) dans une nouvelle (la classe fille) en ajoutant à cette dernière de nouveaux attributs et méthodes, c'est l'héritage,
- pour une instance d'une classe fille, se faire passer à tout moment pour une instance d'une de ses classes mères, c'est le polymorphisme.
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
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).
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).
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.
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.
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.
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.
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.
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.
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 !.
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 :
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
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) |
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.
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 :
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).
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.
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 :
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 << '.'
14. Gestion des exceptions
Exceptions
Pour gérer une exception il suffit d'ajouter un ou plusieurs blocs rescue à un bloc begin / end.
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 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 :
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 :
def initialize(reason)
@reason = reason
end
end
On l'a lèvera en déclarant une nouvelle instance :
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.
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 "chaîne"
throw :symbole, expression
throw "chaîne", expression
De même, catch peut s'utiliser avec un symbole ou une chaîne :
catch "chaîne"
15. Utiles
Sérialisation (doc) :
obj = Marshal.load(data) # charge la chaîne