Découvrez quelques facettes cachées du ruby avec cette série d'articles, et devenez un vrai développeur ninja.

Introduction

Le Ruby est un langage de programmation clair et simple à comprendre. Je pense que n'importe quel anglophone peut, rien qu'en regardant une portion de code (pas trop complexe tout de même), en comprendre l'utilité sans réelles connaissances en programmation.

Mais le Ruby possède aussi ses petits trucs, pas forcément évidents au premier abord, mais qui permettent d'économiser de quelques caractères à quelques lignes, et que nous allons essayer de voir dans cette série d'articles.

Premier exemple: les opérateurs booléens &&, ||, and et or.

La base

Leur utilisation principale est bien sur dans l'évaluation d'opérations. &&/and nécessiteront que les deux membres de l'opération soient équivalents à true, et ||/or qu'au moins l'un des deux le soit. Exemple:

true && false
=> false

true and false
=> false

true || false
=> true

true or false
=> true

Il faut tout de même bien différencier and/or de &&/||. Ils ont l'air identiques, mais ont une petite différence: &&/|| sont prioritaires sur and/or. Cela a plus de répercutions que ce que l'on peut croire.

D'autres façons de les utiliser.

(Pour comprendre la suite, et Ruby en général, il est important de rappeler qu'en Ruby, false et nil valent false, alors que tout le reste vaut true)

Ces opérateurs ont deux propriétés qui leur permettent d'avoir bien plus d'utilité que de simples évaluations. Tout d'abord, ils traitent les membres de l'évaluation de gauche à droite, et surtout, ne traitent pas le membre de droite si celui de gauche leur suffit pour trancher.

Exemple simple: var1 && var2

Si var1 vaut false, rien ne sert de regarder var2, de toute manière, la condition n'est pas remplie. Et avec un ||, c'est l'inverse. Si var1 vaut true, rien ne sert de regarder var2, la condition est ok.

Leur autre propriété est qu'ils ne renvoient pas ‘true' ou ‘false', mais le dernier membre évalué.

false || "default"
=> "default"

nil && true
=> nil

 

Tout ça fait qu'ils peuvent servir à :

Définir une valeur par défaut

Nous sommes sur Rails, avec une gem de pagination (disons kaminari). Nous récupérons le numéro de page depuis l'url, mais voulons que sur la page1, le numéro ne soit pas écrit explicitement (et pour les besoins de l'exemple, on ne parlera pas du fait de pouvoir mettre la valeur dans le fichier route, ni de la valeur par défaut de kaminari, merci).

Si params[:page] n'est pas définit, plutôt que d'envoyer nil à kaminari et se prendre une erreur, nous devons envoyer 1.

Model.page params[:page] || 1

if params[:page]
   Model.page params[:page]
else
   Model.page 1
end

params[:page] ||= 1
Model.page params[:page]

Notez que l'on peut aussi l'utiliser avec un =, pour n'assigner une valeur que si le contenu actuel est false ou nil.

Évaluer la valeur d'un tableau sans risque

Il arrivera peut être que vous soyez obligé de travailler avec une valeur d'un tableau si elle existe, et sinon renvoyer nil. && peut nous aider dans ce cas

if (address = table[:user] && table[:user][:address])
  puts address[:city]
  puts address[:street]
end 

De cette manière, si table[:user] n'existe pas, nous stockons nil dans adresse, et nous renvoyons nil. Le if ne s’exécute donc pas, et voilà. Si table[:user] existe, par contre, nous stockons son adresse dans une variable qui nous évitera les noms à rallonge pour la suite.

Il est important de noter quelque chose, ici: L'exemple précédent vas provoquer un bug si nous l'utilisons avec and. Pourquoi? Car and à une moins grande priorité que le =. Donc adresse sera égal à table[:user], et non table[:user][:address].

Pour éviter ça, deux solutions: toujours utiliser des parenthèses explicitement, ou bien toujours utiliser les opérateurs en symboles.

Exécuter des opérations successivement, et s’arrêter en cas de soucis. 

@user.save and return
raise "Un problème est survenu durant l'enregistrement de l'utilisateur"

Partons du fait que la fonction save renvois true en cas de succès et false en cas d'échec (une fonction sage, donc). Si la sauvegarde a été sucessfull, nous pouvons quitter notre fonction actuelle. Sinon, nous montons une erreur.

Charger une gem

gem 'nokogiri' and require 'nokogiri'

Je ne vous ferais pas l'affront d'expliquer.

 Le mot de la fin

my_var = (my_table && my_table[:my_key]) || "default" # ça fonctionne, mais bon...
my_var = my_table ? my_table[:my_key] : "default" # c'est mieux

 

Ce n'est évidemment pas là une liste exhaustive, car elle n'existe pas. À vous, selon la situation, de voir si les opérateurs peuvent vous arranger sur le moment. Une dernière recommandation cependant : Ce n'est pas parce qu’ils sont pratiques qu'ils s'adaptent partout, comme le montre le dernier exemple.

Bonne journée à tous.