Programmation Ruby/Contrôle
Méthodes logiques
modifierUne expression booléenne est toute expression qui renvoie après évaluation vrai (true
) ou faux (false
).
Une valeur booléenne peut être de type booléen (true
ou false
)
Attention:
- 0 est
true
=> Objet Fixnum de valeur 0 - "" est
true
=> Objet String de valeur "" - 'False' est
true
=> Objet String de valeur 'False'
Il s'agit ici d'une autre des caractéristiques des langages 'tout objet' ou même les nombres sont des objets. Tout objet est true.
Une autre caractéristique de Ruby et de tous les langages "tout objet", est que les "opérateurs", décrit ci-dessous, comme on les appelle dans les langages orientés objet ou procéduraux, sont en réalités des méthodes d'instance. En règles générale, le développeur doit implémenter lui même ses méthodes. Néanmoins certaines d'entre, dont les equivalents d'"opérateurs", sont pré-définies dans la classe Object
, mère de toutes les autres classes, ou encore dans un module. Nous reviendrons sur ces concepts dans le chapitre traitant de la programmation objet.
Les exemples, ici, utilisent des objets "standards" pour un souci de clarté, ils peuvent être remplacés par des expressions placées entre parenthèses. Ainsi :
42 == 42 => true
équivaut à
(40 + 2) == (21 * 2) => true
defined?
modifierdefined?
permet de vérifier l'existence d'une variable, l'opérateur renvoie nil
si la variable n'existe pas, sinon renvoi une description :
defined? 42 => "expression" defined? toto => nil defined? 42.times => "method" defined? $_ => "global-variable" ...
eql?
modifiereql?
teste si 2 variables ou valeurs sont égales et du même type, renvoi true
si c'est le cas, sinon false
.
42.eql?(42) => true 42.eql?(18) => false # Valeurs différentes 42.eql?(42.0) => false # Types différents, en effet 42 est un entier, 42.0 un flottant
equal?
modifierequal?
renvoie true
si les deux objets comparés sont en réalité un même objet (même id), sinon renvoie false
.
a = "mon objet" b = a a.equal?(a) => true a.equal?(b) => true
c = "mon objet"
a.equal?(c) => false
42.equal?(42) => true "uv".equal?("uv") => false
==
modifier==
permet de tester l'égalité entre les valeurs de deux éléments :
42 == 42 => true 42 == 23 => false 42 == "42" => false
!=
modifier!=
permet de tester l'inégalité entre les valeurs de deux éléments :
42 != 42 => false 42 != 23 => true 42 != "42" => true
<=>
modifier<=>
sert à comparer deux variables, cette méthode n'est pas à proprement parler un opérateur booléen. En effet celle-ci renvoie -1
, 0
ou 1
si, le premier élément est respectivement inférieur, égal ou supérieur au second, et renvoie nil
si les types sont différents.
2 <=> 2 => 0 2 <=> 3 => -1 42 <=> 18 => 1 42 <=> "42" => nil 42 <=> 42.0 => 0 # contrairement à eql?, c'est la valeur qui est comparée
Pour deux valeurs numériques cet opérateur retourne donc le signe de la différence entre celles-ci.
< et <=
modifier<
et <=
correspondent respectivement à "inférieur" et "inférieur ou égal à" :
42 < 43 => true 42 < 42 => false 42 <= 42 => true "abcdef" < "abzd" => true #la comparaison entre chaînes de caractères se fait lettre à lettre "abzd" < "abcdef" => false
> et >=
modifier>
et >=
correspondent respectivement à "supérieur à" et "supérieur ou égal à" :
42 > 43 => false 42 > 42 => false 42 >= 42 => true "abcdef" > "abzd" => false #la comparaison entre chaînes de caractères se fait lettre à lettre "abzd" > "abcdef" => true
not et !
modifiernot
et !
exprime la négation, l'opérateur "inverse" l'élément placé juste après, ainsi :
not true => false (!false) => true
De même, on peut exprimer la négation sur une expression si celle-ci se trouve entre parenthèses :
(!(2 < 10)) => false not (2 < 10) => false
and et &&
modifierand
et &&
correspondent au "et logique" :
true and false => false true and true => true
Dans un souci d'optimisation, Ruby teste la première expression, et si celle-ci est fausse, il ne teste pas la seconde.
or et ||
modifieror
et ||
correspondent au "ou logique"
true or false => true true or true => true false or false => false
Dans un souci d'optimisation, Ruby teste la première expression, et si celle-ci est vraie, il ne teste pas la seconde.
Les expressions conditionnelles
modifierUne expression conditionnelle sert à réagir en fonction d'un élément donné.
Expression IF...THEN...ELSE
modifierEn algorithmique :
SI <EXPRESSION CONDITIONNELLE> ALORS
EXPRESSION1
[SINON
EXPRESSION2
]
FIN SI
se traduit en Ruby par :
if <EXPRESSION CONDITIONNELLE> [then]
EXPRESSION1
[else
EXPRESSION2
]
end
La condition peut être une expression, à condition que celle-ci soit une expression booléenne (vrai ou faux), ou une valeur numérique (0 ayant valeur de faux).
donc :
if (1)
équivaut à
if (true)
qui équivaut à
if (2 + 2 == 4)
de même :
if (0)
équivaut à
if (false)
qui équivaut à
if (2 + 2 == 5)
Une expression conditionnelle peut être l'élément ouvrant d'un bloc, ou succéder à une expression si celle-ci tient sur une ligne, dans ce denier cas on ne peut utiliser else :
if true puts "true" end => "true"
équivaut à
puts "true" if true => "true"
Le pendant de if est unless (sauf si) et suit les mêmes règles, toutefois l'instruction n'est exécuté que si la condition est fausse :
puts "false" unless false => "false"
À noter que pour faciliter la lecture, ruby permet de faire suivre l'expression testée du mot clef then :
if (true) then
Expression CASE...WHEN
modifier
SI <EXPRESSION CONDITIONNELLE>
VAUT EXPRESSION 1 ALORS EXPRESSION RESULTANTE 1
VAUT EXPRESSION 2 ALORS EXPRESSION RESULTANTE 2
...
VAUT EXPRESSION N ALORS EXPRESSION RESULTANTE N
SINON EXPRESSION RESULTANTE
FIN SI
ce qui se traduit en ruby par :
case <EXPRESSION CONDITIONNELLE>
when EXPRESSION 1 then EXPRESSION RESULTANTE 1
[ when EXPRESSION 2 then EXPRESSION RESULTANTE 2
...
when EXPRESSION N then EXPRESSION RESULTANTE N
else EXPRESSION RESULTANTE]
end
case va comparer l'expression le suivant avec les expressions passées après les mots-clefs when. Si l'une d'elle correspond, case appelera l'expression suivant le then. Sinon il évaluera l'expression suivant le else :
chaine = "ça va ?" case chaine when "bonjour" then "bonjour" when "ça va ?" then "oui merci" else "au revoir" end => "oui merci"
À noter que l'expression suivant le case est facultative :
age = 40 case when ((age > 60) and (age < 100)) then "Vous êtes agé" when ((age <= 60) and (age > 15)) then "Vous êtes dans la fleur de l'age" when age <= 15 then "Vous êtes jeune" else "Mathusalem" end => "Vous êtes dans la fleur de l'age"
Si age avait été supérieur à 100, c'est la condition else qui aurait été prise en compte.
À noter que then peut être remplacé par le caractère deux points ( :
), on peut également mettre la clause when sur deux lignes :
case when ((age > 60) and (age < 100)) "Vous êtes agé" ... end
Les boucles
modifierLes boucles permettent de parcourir une liste d'éléments, ou d'effectuer une action tant qu'une condition est respectée.
While/Until
modifier
TANT QUE <EXPRESSION CONDITIONNELLE> FAIRE
EXPRESSION1
FIN TANT QUE
ce qui se traduit en ruby par
while <EXPRESSION CONDITIONNELLE>
EXPRESSION1
end
Par exemple :
i = 0 while (i < 5) puts i i = i + 1 end => 0 1 2 3 4
Dans cet exemple l'expression conditionnelle est évaluée avant l'évaluation du corps de la boucle, donc si i avait été égal à 6, le contenu de la boucle n'aurait jamais été évalué. Néanmoins nous pouvons utiliser une autre construction commençant par un bloc et suivit de while, dans ce cas là le corps de la boucle est évalué au moins une fois :
i = 12 begin puts i i = i + 1 end while (i < 5) => 12
La négation de while est until, que l'on pourrait traduire par "jusqu'à" :
i = 0 until (i > 5) puts i i = i + 1 end => 0 1 2 3 4 5
loop
modifierloop ressemble à la structure while, mais ne prend pas d'expression conditionnelle. En fait loop correspond à
while(true)
Le seul moyen de quitter la boucle est d'utiliser l'instruction break :
i = 0 loop do puts i i = i + 1 break if i >= 5 end => 0 1 2 3 4
For in
modifierLa boucle for permet d'itérer à travers un ensemble :
for i in 5..8 puts i end => 5 6 7 8
Nous verrons les intervalles (de forme x..y) dans le chapitre suivant, pour l'heure il suffit de savoir qu'ils représentent tous les éléments compris entre x et y.
Ceci est une manière d'itérer, néanmoins nous verrons dans les chapitres suivant qu'en ruby il vaut mieux itérer en utilisant les méthodes adaptées. Ainsi le même exemple aurait pu s'écrire :
(5..8).each do |i| puts i end
Pour les chaînes de caractères, le retour chariot servira de séparateur :
for ligne in "première\ndeuxième\ntroisième" puts ligne end => première deuxième troisième
Itérateurs
modifierun grand nombre d'objet en Ruby implémente des itérateurs, cad; des méthodes de parcours des éléments de l'objet lui-même.
each
modifierLa boucle each (chaque en anglais) parcours tous les éléments d'un tableau en assignant à une variable temporaire l'élément actuel.
Soit dans une classe la va
noms = ['toto', 'tata', 'titi'] noms.each do |nom| puts "Salut #{nom} !" end => Salut toto ! => Salut tata ! => Salut titi !
each_byte et each_line
modifierLes chaînes de caractères ont une méthode spécifique appelée each_byte (chaque caractère) qui parcours la chaîne caractère par caractère :
"abcdef".each_byte{ |caractere| printf "%c\n", caractere } a b c d e f
Et each_line (chaque ligne) qui parcoure les lignes séparés par le retour chariot :
["première", "suite", "autre"].join("\n").each_line{|ligne| puts ligne} => première suite autre
times
modifierFonction typique à Ruby, la méthode d'itération des classes d'entiers nommée times (fois) et qui peut être utilisé avec les constantes numériques (ce langage étant pur objet) :
3.times{puts "texte"} => texte texte texte
ou bien :
3.times do puts "texte" done => texte texte texte
Les mots clés de contrôle d'execution
modifierParmi les rares mots clés du langage, on trouve un certain nombre de controles d'execution
Break
modifierNous avons déjà vu break qui permet d'interrompre l'exécution d'une boucle :
i = 0 while (true) break if i > 3 puts i i = i+1 end => 0 1 2 3
Redo
modifierredo va réévaluer le corps de la boucle, mais sans retester la condition, et sans utiliser l'élément suivant (dans un itérateur)
for i in 1..4 print "#{i} " if i==2 i=0 redo end puts i end => 1 1 2 0 0 3 3 4 4
La variable i étant définie localement (dans la boucle), cela ne change pas le déroulement par rapport à la liste globale, mais la variable est bien vue comme ayant une valeur différente de 2 la seconde fois et le redo est évité. Le puts suivant le redo dans le bloc de code de la boucle n'est pas exécuté lorsque celui est exécuté.
Next
modifiernext va aller à la fin de la boucle, puis recommencer l'itération avec l'élément suivant dans le cas d'un itérateur :
i=0 loop do i += 1 next if i < 3 puts i break if i > 4 end => 3 4 5
Retry
modifierretry recommence l'itération à son début, dans son état premier :
for i in 1..5 puts i retry if i == 2 end => 1 2 1 2 ...
On entre ici dans une boucle infinie.
Remarques
modifierBoucles implicites
modifierLe parcours des éléments d'un tableau dans Ruby est implicite lorsque on l'utilise comme variable d'assignation, comme c'est le cas pour les chaînes de caractère dans la majorité des langages :
puts [ "élément 1", "élément 2", "élément 3" ] => élément 1 élément 2 élément 3
On peut de la même façon extraire une partie d'un tableau simplement sans avoir à créer de boucle qui parcoure tous les éléments.
Exemple tiré du site officiel de Ruby
villes = %w[ Londres Oslo Paris Amsterdam Berlin ] visitees = %w[Berlin Oslo] puts "J'ai toujours besoin " + "de visiter les " + "villes suivantes :", villes - visitees => Londres Paris Amsterdam
Cet exemple sort les éléments du tableau qui sont dans les villes mais pas dans visitées