05. Plus Sur les Méthodes

Jusqu'à présent, nous avons vu un certain nombre de méthodes différentes, puts et gets entre autres (Interrogation Surprise : Listez toutes les méthodes que nous avons vues jusqu'à présent ! Il y en avait dix ; la réponse est plus bas.), mais nous n'avons pas vraiment parlé de ce que sont les méthodes. Nous savons ce qu'elles font, mais nous ne savons pas ce qu'elles sont.

Mais en fait, c'est ce qu'elles sont : des choses qui font des choses. Si les objets (comme les chaînes, les entiers et les flottants) sont les noms dans le langage Ruby, alors les méthodes sont comme les verbes. Et, contrairement au français (où il y a des sujets indéfinis et d'autres constructions ésotériques), vous ne pouvez pas avoir un verbe sans un nom pour faire le verbe. Mais même le français traite l'absence d'un nom comme une exception : par exemple, le tic-tac n'est pas quelque chose qui arrive juste comme ça ; une horloge (ou un chronomètre, ou quelque chose de similaire) doit le faire. En français, nous dirions : "L'horloge fait tic-tac." En Ruby, nous disons horloge.tic_tac (en supposant que horloge est un objet Ruby, bien sûr). Les programmeurs pourraient dire que nous "appelons la méthode tic_tac sur horloge", ou que nous "avons appelé tic_tac sur horloge."

Alors, avez-vous fait le quiz ? Bien. Eh bien, je suis sûr que vous vous êtes souvenu des méthodes puts, gets et chomp que nous venons de voir. Vous vous êtes aussi probablement souvenu des méthodes de conversion, to_i, to_f et to_s. Cependant, avez-vous trouvé les quatre autres ? Eh bien, ce n'étaient autres que nos vieux amis arithmétiques, +, -, * et / !

Comme je le disais, chaque méthode a besoin d'un objet. Habituellement, il est facile de dire quel objet exécute la méthode : c'est ce qui vient juste avant le point, comme dans notre exemple horloge.tic_tac, ou dans 101.to_s. Parfois, cependant, ce n'est pas si évident ; comme avec les méthodes arithmétiques. En fait, 5 + 5 est vraiment juste un raccourci pour écrire 5.+ 5. Par exemple :

puts 'bonjour '.+ 'monde'
puts (10.* 9).+ 9
bonjour monde
99

Ce n'est pas très joli, donc nous ne l'écrirons jamais comme ça ; cependant, il est important de comprendre ce qui se passe vraiment. (Sur ma machine, cela me donne aussi un avertissement : warning: parenthesize argument(s) for future version. Le code a quand même bien fonctionné, mais il me dit qu'il a du mal à comprendre ce que je voulais dire, et me demande d'utiliser plus de parenthèses à l'avenir). Cela nous donne aussi une compréhension plus profonde de pourquoi nous pouvons faire 'cochon'*5 mais pas 5*'cochon' : 'cochon'*5 dit à 'cochon' de faire la multiplication, mais 5*'cochon' demande à 5 de faire la multiplication. 'cochon' sait comment faire 5 copies de lui-même et les additionner ; cependant, 5 aura beaucoup plus de mal à faire 'cochon' copies de lui-même et à les additionner.

Et, bien sûr, nous avons encore puts et gets à expliquer. Où sont leurs objets ? En français, vous pouvez parfois omettre le nom ; par exemple, si un méchant crie "Meurs !", le nom implicite est la personne sur laquelle il crie. En Ruby, si je dis puts 'être ou ne pas être', ce que je dis vraiment est self.puts 'être ou ne pas être'. Alors qu'est-ce que self ? C'est une variable spéciale qui pointe vers l'objet dans lequel vous vous trouvez actuellement. Nous ne savons même pas encore comment être dans un objet, mais jusqu'à ce que nous le découvrions, nous sommes toujours dans un grand objet qui est... le programme entier ! Et par chance, le programme a quelques méthodes propres, comme puts et gets. Regardez ça :

jeNePeuxPasCroireQueJaiFaitUnNomDeVariableAussiLongJustePourStockerUn3 = 3
puts jeNePeuxPasCroireQueJaiFaitUnNomDeVariableAussiLongJustePourStockerUn3
self.puts jeNePeuxPasCroireQueJaiFaitUnNomDeVariableAussiLongJustePourStockerUn3
3
3

Si vous n'avez pas tout suivi, ce n'est pas grave. La chose importante à retenir de tout cela est que chaque méthode est exécutée par un objet, même s'il n'est pas juste devant vous. Si vous comprenez cela, alors vous êtes prêt.

Méthodes de Chaîne Élégantes

Apprenons quelques méthodes de chaîne amusantes. Vous n'avez pas à toutes les mémoriser ; vous pouvez simplement regarder cette page à nouveau si vous les oubliez. Je veux juste vous montrer une petite partie de ce que les chaînes peuvent faire. En fait, je ne me souviens même pas de la moitié des méthodes de chaîne moi-même — mais ce n'est pas grave, car il existe d'excellentes références sur Internet avec toutes les méthodes de chaîne listées et expliquées. (Je vous montrerai où les trouver à la fin de ce tutoriel.) Pour être honnête, je ne veux même pas connaître toutes les méthodes de chaîne ; c'est comme connaître chaque mot du dictionnaire. Je peux parler français parfaitement bien sans connaître chaque mot du dictionnaire... et n'est-ce pas là tout l'intérêt ? Que vous n'avez pas besoin de savoir tout ce qu'il contient ?

Donc, notre première méthode de chaîne est reverse, qui nous donne une version inversée de la chaîne :

var1 = 'stop'
var2 = 'radar'
var3 = 'Pouvez-vous prononcer cette phrase a l\'envers ?'

puts var1.reverse
puts var2.reverse
puts var3.reverse
puts var1
puts var2
puts var3
pots
radar
? srevne'l a esarhp ettec recnonorp suov-zevuoP
stop
radar
Pouvez-vous prononcer cette phrase a l'envers ?

Comme vous pouvez le voir, reverse n'inverse pas la chaîne originale ; elle crée simplement une nouvelle version inversée de celle-ci. C'est pourquoi var1 est toujours 'stop' même après avoir appelé reverse sur var1.

Une autre méthode de chaîne est length, qui nous indique le nombre de caractères (y compris les espaces) dans la chaîne :

puts 'Quel est votre nom complet ?'
nom = gets.chomp
puts 'Saviez-vous qu\'il y a ' + nom.length + ' caractères dans votre nom, ' + nom + ' ?'
Quel est votre nom complet ?
Christopher David Pine
#<TypeError: can't convert Fixnum into String>

Ouh là ! Quelque chose a mal tourné, et il semble que ce soit arrivé après la ligne nom = gets.chomp... Voyez-vous le problème ? Voyez si vous pouvez le deviner.

Le problème est avec length : il vous donne un nombre, mais nous voulons une chaîne. Assez facile, ajoutons un to_s (et croisons les doigts) :

puts 'Quel est votre nom complet ?'
nom = gets.chomp
puts 'Saviez-vous qu\'il y a ' + nom.length.to_s + ' caractères dans votre nom, ' + nom + ' ?'
Quel est votre nom complet ?
Christopher David Pine
Saviez-vous qu'il y a 22 caractères dans votre nom, Christopher David Pine ?

Non, je ne le savais pas. Note : c'est le nombre de caractères dans mon nom, pas le nombre de lettres (comptez-les). Je suppose que nous pourrions écrire un programme qui demande vos prénoms et nom de famille individuellement, puis additionne ces longueurs... Hé, pourquoi ne faites-vous pas ça ? Allez-y, j'attends.

Prêt ? Bien ! C'est un joli programme, n'est-ce pas ? Après quelques chapitres de plus, cependant, vous serez étonné de ce que vous pouvez faire.

Il existe également un certain nombre de méthodes de chaîne qui changent la casse (majuscules et minuscules) de votre chaîne. upcase change chaque lettre minuscule en majuscule, et downcase change chaque lettre majuscule en minuscule. swapcase inverse la casse de chaque lettre dans la chaîne, et enfin, capitalize est comme downcase, sauf qu'il met le premier caractère en majuscule (si c'est une lettre).

lettres = 'aAbBcCdDeE'
puts lettres.upcase
puts lettres.downcase
puts lettres.swapcase
puts lettres.capitalize
puts ' a'.capitalize
puts lettres
AABBCCDDEE
aabbccddee
AaBbCcDdEe
Aabbccddee
 a
aAbBcCdDeE

Des trucs assez standards. Comme vous pouvez le voir à la ligne puts ' a'.capitalize, la méthode capitalize met seulement le premier caractère en majuscule, pas la première lettre. Aussi, comme nous l'avons vu auparavant, tout au long de ces appels de méthode, lettres reste inchangée. Je ne veux pas insister sur ce point, mais il est important de comprendre. Il y a certaines méthodes qui changent l'objet associé, mais nous n'en avons pas encore vu, et nous n'en verrons pas avant un certain temps.

Les dernières méthodes de chaîne élégantes que nous allons regarder concernent le formatage visuel. La première, center, ajoute des espaces au début et à la fin de la chaîne pour la centrer. Cependant, tout comme vous devez dire à puts ce que vous voulez qu'il imprime, et à + ce que vous voulez qu'il ajoute, vous devez dire à center quelle largeur vous voulez que votre chaîne centrée ait. Donc, si je voulais centrer les lignes d'un poème, je ferais comme ceci :

largeurLigne = 50
puts(                'Old Mother Hubbard'.center(largeurLigne))
puts(               'Sat in her cupboard'.center(largeurLigne))
puts(         'Eating her curds an whey,'.center(largeurLigne))
puts(          'When along came a spider'.center(largeurLigne))
puts(         'Which sat down beside her'.center(largeurLigne))
puts('And scared her poor shoe dog away.'.center(largeurLigne))
                Old Mother Hubbard                
               Sat in her cupboard                
            Eating her curds an whey,             
             When along came a spider             
            Which sat down beside her             
        And scared her poor shoe dog away.        

Hmm... Je ne pense pas que ce soit comme ça que va la comptine, mais je suis trop paresseux pour vérifier. (Aussi, je voulais aligner la partie .center largeurLigne, donc j'ai mis ces espaces supplémentaires avant les chaînes. C'est juste parce que je pense que c'est plus joli. Les programmeurs ont souvent des opinions tranchées sur ce qui est joli dans un programme, et ils sont souvent en désaccord à ce sujet. Plus vous programmerez, plus vous trouverez votre propre style). En parlant d'être paresseux, la paresse n'est pas toujours une mauvaise chose en programmation. Par exemple, avez-vous vu comment j'ai stocké la largeur du poème dans la variable largeurLigne ? J'ai fait cela pour que si je veux rendre le poème plus large plus tard, je n'ai qu'à changer la toute première ligne du programme, au lieu de chaque ligne qui fait le centrage. Avec un poème très long, cela pourrait me faire gagner beaucoup de temps. Ce genre de paresse est vraiment une vertu en programmation.

Alors, à propos de ce centrage... vous avez peut-être remarqué que ce n'est pas aussi beau que ce qu'un traitement de texte aurait fait. Si vous voulez vraiment un centrage parfait (et peut-être une plus jolie police), alors vous devriez simplement utiliser un traitement de texte ! Ruby est un outil merveilleux, mais aucun outil n'est le bon outil pour chaque travail.

Les deux autres méthodes de formatage de chaîne sont ljust et rjust, qui signifient justifier à gauche et justifier à droite. Elles sont similaires à center, sauf qu'elles remplissent la chaîne avec des espaces à droite et à gauche, respectivement. Voyons les trois en action :

largeurLigne = 40
str = '--> texte <--'
puts str.ljust  largeurLigne
puts str.center largeurLigne
puts str.rjust  largeurLigne
puts str.ljust (largeurLigne/2) + str.rjust (largeurLigne/2)
--> texte <--                           
             --> texte <--              
                           --> texte <--
--> texte <--              --> texte <--

Quelques Petites Choses à Essayer

  • Écrivez un programme de Patron En Colère. Il doit demander grossièrement ce que vous voulez. Quoi que vous répondiez, le Patron En Colère doit vous le crier dessus, puis vous virer. Par exemple, si vous tapez Je veux une augmentation., il doit crier QU'EST-CE QUE TU VEUX DIRE PAR "JE VEUX UNE AUGMENTATION." ?!? TU ES VIRÉ !!
  • Voici quelque chose à faire pour jouer un peu plus avec center, ljust et rjust : Écrivez un programme qui affichera une Table des Matières pour qu'elle ressemble à ceci :
                Table des Matières                
                                                  
Chapitre 1 :  Nombres                     page 1
Chapitre 2 :  Lettres                    page 72
Chapitre 3 :  Variables                 page 118

Mathématiques Supérieures

(Cette section est complètement optionnelle. Elle suppose un certain niveau de connaissances mathématiques. Si vous n'êtes pas intéressé, vous pouvez aller directement au Contrôle de Flux sans aucun problème. Cependant, un coup d'œil rapide à la section Nombres Aléatoires pourrait être utile.)

Il n'y a pas autant de méthodes pour les nombres que pour les chaînes (bien que je ne les aie pas encore toutes mémorisées). Ici, nous allons regarder le reste des méthodes arithmétiques, un générateur de nombres aléatoires et l'objet Math, avec ses méthodes trigonométriques et transcendantales.

Plus d'Arithmétique

Les deux autres méthodes arithmétiques sont ** (exponentiation) et % (modulo). Donc, si vous vouliez dire "cinq au carré" en Ruby, vous écririez 5**2. Vous pouvez aussi utiliser des flottants pour votre exposant, donc si vous voulez la racine carrée de 5, vous pouvez écrire 5**0.5. La méthode modulo vous donne le reste après la division par un nombre. Donc, par exemple, si je divise 7 par 3, j'obtiens 2 avec un reste de 1. Voyons-les en action dans un programme :

puts 5**2
puts 5**0.5
puts 7/3
puts 7%3
puts 365%7
25
2.23606797749979
2
1
1

De cette dernière ligne, nous apprenons qu'une année (non bissextile) a un certain nombre de semaines, plus un jour. Donc si votre anniversaire était un mardi cette année, ce sera un mercredi l'année prochaine. Vous pouvez aussi utiliser des flottants avec la méthode modulo. Cela fonctionne essentiellement de la seule manière raisonnable possible... mais je vous laisse jouer avec ça.

Il y a une dernière méthode à mentionner avant de vérifier le générateur de nombres aléatoires : abs. Elle prend simplement la valeur absolue du nombre :

puts((5-2).abs)
puts((2-5).abs)
3
3

Nombres Aléatoires

Ruby est livré avec un générateur de nombres aléatoires assez sympa. La méthode pour obtenir un nombre choisi au hasard est rand. Si vous appelez rand juste comme ça, vous obtenez un flottant supérieur ou égal à 0.0 et inférieur à 1.0. Si vous donnez à rand un entier (5 par exemple), il vous donnera un entier supérieur ou égal à 0 et inférieur à 5 (donc cinq nombres possibles, de 0 à 4).

Voyons rand en action. (Si vous rechargez cette page, ces nombres changeront à chaque fois. Vous saviez que j'exécutais vraiment ces programmes, n'est-ce pas ?)

puts rand
puts rand
puts rand
puts(rand(100))
puts(rand(100))
puts(rand(100))
puts(rand(1))
puts(rand(1))
puts(rand(1))
puts(rand(99999999999999999999999999999999999999999999999999999999999))
puts('Le monsieur meteo a dit qu\'il y a '+rand(101).to_s+'% de chance de pluie,')
puts('mais vous ne pouvez jamais faire confiance a un monsieur meteo.')
0.533099438199271
0.692927743758217
0.940976910494312
35
25
43
0
0
0
43268570703742641064840128301077341089498686011220522458380
Le monsieur meteo a dit qu'il y a 42% de chance de pluie,
mais vous ne pouvez jamais faire confiance a un monsieur meteo.

Remarquez que j'ai utilisé rand(101) pour obtenir des nombres de 0 à 100, et que rand(1) renvoie toujours 0. Ne pas comprendre la plage des valeurs de retour possibles est la plus grande erreur que je vois les gens faire avec rand ; même des programmeurs professionnels ; même dans des produits finis que vous pouvez acheter au magasin. J'ai eu une fois un lecteur CD qui, s'il était réglé sur "Lecture Aléatoire", jouait toutes les chansons sauf la dernière... (Je me demande ce qui se passerait si vous mettiez un CD avec une seule chanson dessus ?)

Parfois, vous pourriez vouloir que rand renvoie les mêmes nombres aléatoires dans la même séquence lors de deux exécutions différentes de votre programme. (Par exemple, j'utilisais une fois des nombres aléatoires pour générer un monde généré aléatoirement dans un jeu vidéo. Si je trouvais un monde que j'aimais vraiment, je voudrais peut-être y rejouer, ou l'envoyer à un ami). Pour faire cela, vous devez définir la graine (seed), ce que vous pouvez faire avec srand. Comme ceci :

srand 1776
puts(rand(100))
puts(rand(100))
puts(rand(100))
puts(rand(100))
puts(rand(100))
puts ''
srand 1776
puts(rand(100))
puts(rand(100))
puts(rand(100))
puts(rand(100))
puts(rand(100))
24
35
36
58
70

24
35
36
58
70

Il fera la même chose chaque fois que vous l'amorcez avec le même nombre. Si vous voulez obtenir à nouveau des nombres différents (comme ce qui se passe si vous ne touchez jamais à srand), alors appelez simplement srand 0. Cela l'amorce avec un nombre vraiment bizarre, utilisant (entre autres choses) l'heure actuelle de votre ordinateur, à la milliseconde près.

L'Objet Math

Enfin, regardons l'objet Math. Plongeons directement dedans :

puts(Math::PI)
puts(Math::E)
puts(Math.cos(Math::PI/3))
puts(Math.tan(Math::PI/4))
puts(Math.log(Math::E**2))
puts((1 + Math.sqrt(5))/2)
3.14159265358979
2.71828182845905
0.5
1.0
2.0
1.61803398874989

La première chose que vous avez remarquée était probablement la notation ::. Expliquer l'opérateur de portée (c'est ce que c'est) dépasse un peu la, euh... portée de ce tutoriel. Sans jeu de mots. Je le jure. Il suffit de dire que vous pouvez utiliser Math::PI exactement comme vous vous y attendez.

Comme vous pouvez le voir, Math a toutes les choses que vous attendriez d'une calculatrice scientifique décente. Et comme toujours, les flottants sont vraiment proches d'être les bonnes réponses.

Alors entrons dans le flux !