• Contenu
  • Bas de page
logo ouidoulogo ouidoulogo ouidoulogo ouidou
  • Qui sommes-nous ?
  • Offres
    • 💻 Applications métier
    • 🤝 Collaboration des équipes
    • 🛡️ Sécurisation et optimisation du système d’information
    • 🔗 Transformation numérique
  • Expertises
    • 🖥️ Développement logiciel
    • ♾️ DevSecOps
    • ⚙️ Intégration de logiciels et négoce de licences
      • Atlassian : Jira, Confluence, Bitbucket…
      • Plateforme monday.com
      • GitLab
      • SonarQube
    • 📚​ Logiciel de CRM et de gestion
    • 🎨 UX/UI design
    • 🌐 Accessibilité Numérique
    • 🗂️​ Démarches simplifiées
    • 📝 Formations Atlassian
  • Références
  • Carrières
    • 🧐 Pourquoi rejoindre Ouidou ?
    • ✍🏻 Nous rejoindre
    • 👨‍💻 Rencontrer nos collaborateurs
    • 🚀 Grandir chez Ouidou
  • RSE
  • Ressources
    • 🗞️ Actualités
    • 🔍 Articles techniques
    • 📖 Livres blancs
    • 🎙️ Interviews Clients
Nous contacter
✕
Mise en place d’un cluster PostgreSQL avec Pgpool II
Mise en place d’un cluster PostgreSQL avec Pgpool II
3 septembre 2014
Création d’un menu en accordéon avec CSS
Création d’un menu en accordéon avec CSS
4 juin 2015
Ressources > Articles techniques > Blocks, Proc et Lambda en Ruby

Blocks, Proc et Lambda en Ruby

Écrit par Jonathan F.

Les closures (Block, Proc & Lambda) Ruby sont l’un des aspects les plus puissants du langage. Ce sont des fonctions liées à l’environnement dans lequel elles ont été définies. Elles ont la particularité de garder l’accès à des variables présentes dans la portée de celle-ci au moment où elles sont créées mais qui peut également ne plus être dans cette portée au moment où nous appelons cette closure.

Voici un exemple qui montre que notre closure à accès à une variable locale dans l’état qu’elle avait au moment de la création de la fonction :

counter = 1 defexample variable Proc.new {variable} end a = example counter # A cet instant counter = 1 counter = 10 a.call # => 1

Contrairement à d’autres langages, ruby dispose de différentes manières de gérer ces closures. Chacune d’entre elles se comporte de façon légèrement différente, ce qui ne simplifie pas son utilisation.

Pour résumer, ces fonctions vous permettent de passer du code à une méthode et de l’exécuter à une date antérieure au sein de cette méthode.

Blocs

Pour être simple, un block est un morceau de code qui sera appelé dans la méthode à laquelle vous le fournissez. Selon les conventions il se définit entre accolade {} s’il peut être défini sur une ligne ou entre do et end s’il est multi-lignes.

defon_dit_merci_a_qui(name) yield(name) if block_given? end on_dit_merci_a_qui("bibi") { |name| puts "Merci #{name}" } on_dit_merci_a_qui("bibi") do|name| puts "Merci #{name}" end# => "Merci bibi"

En Ruby, toute fonction peut prendre un block et un seul comme argument, celui-ci sera interprété si la fonction fait appel au mot-clé yield qui évalue le block.

L’utilisation de la condition if block_given? est importante car utiliser yield dans une fonction ne recevant pas de block lève une exception LocalJumpError: no block given (yield).

Le résultat du block pourra ensuite être évalué par le restant du code de la fonction. yield peut accepter des arguments (ici name) qu’il va transmettre au block. Contrairement à yield le block ne vérifie pas le nombre d’arguments, il les ignore comme le montre l’exemple suivant :

on_dit_merci_a_qui("bibi") { |name, test| puts "Merci #{name.class} et #{test.class}" } => "Merci à String et NilClass"

Quelle classe à un block ?

defblock_class(&code) code.class end block_class {} # => Proc

Pouvons-nous réutiliser un block ultérieurement sans devoir le retaper ? Autrement dit, pouvons-nous stocker un block dans une variable ? Non ! Ce qui le rend assez limité car “jetable”. Proc et lambda vont nous permettre de faire cela.

Proc

Un proc est une instance de la classe Proc. C’est un objet qui peut être lié à une variable et réutilisé. Il se définit en appelant Proc.new ou proc suivi d’un block. Il peut également être créé en appelant la méthode to_proc d’une méthode, proc ou symbole. Il est appelé via sa méthode call.

p = Proc.new {|name| puts "Merci #{name}" } @staff =["bibi", "chuck", "norris"]defmerci_tout_le_monde(proc) @staff.each do|name| proc.call(name) endend merci_tout_le_monde(p) # => Merci bibi# => Merci chuck# => Merci norrisdefmerci_qui(proc) proc.call(@staff.first) end merci_qui(p) # => Merci bibi

Notre proc est donc bien réutilisable au sein de différentes méthodes. Lorsqu’un proc est appelé via sa fonction call, et qu’il rencontre une instruction de retour (return) dans son exécution, il arrête la méthode et renvoie la valeur. De ce fait :

defmerci_qui(name) p = Proc.new {|name|return "Merci #{name}" } p.call(name) return "Merci à tous" end merci_qui("bibi") # => Merci bibi

L’utilisation de l’instruction de retour return au sein d’un bloc dépend du contexte dans lequel il est initialisé, c’est la raison pour laquelle notre proc est créé dans le scope de la méthode qui sera appelée. Retrouvez plus d’explications sur ce comportement via cet échange de stackoverflow.

Comme le block, un proc ne vérifie pas le nombre d’arguments, il les ignore :

p.call("bibi", "chuck") # => Merci bibi

La classe d’un proc est naturellement Proc.

Lambda

La fonction lambda se définie par l’appel de son nom de fonction suivie d’un block :

l = lambda { |name| puts "Merci #{name}" } l.call("bibi") # => Merci bibi

Depuis la version 1.9 de Ruby, la syntaxe s’est simplifiée :

l =-> (name) { puts "Merci #{name}" } l.call("bibi") # => Merci bibi

La fonction lambda est similaire à proc à l’exception de deux règles : – il vérifie le nombre d’arguments qui lui est fourni et renvoie un ArgumentError si celui ne correspond pas :

l.call("bibi", "chuck") # => ArgumentError: wrong number of arguments (2 for 1)
  • il n’interrompt pas l’exécution de la méthode dans lequel il est appelé même s’il rencontre une instruction de retour (return) :

l =-> (name) { return “Merci #{name}” } defmerci_qui(lambda) lambda.call(“bibi”) return “Merci à tous” end merci_qui(l) => Merci à tous

La classe d’un lambda est Proc.

L’opérateur unaire &

L’opérateur & est souvent utilisé en Ruby avec les fonctions définies précédemment. Il n’est pas toujours évident de le comprendre à la lecture et pourtant assez simple. Son comportement dépend de ce qu’il lui est appliqué. – il permet de convertir un block en proc :

defmethod&block block.call # Notre block est devenu un proc et nous pouvons l'appeler via la méthode callend
  • il permet de convertir un proc en block
  • si l’object qui lui est passé n’est ni un proc, ni un block il fera appel à to_proc sur l’objet, puis il convertira ce proc en block.

Conclusion

Voici un tableau récapitulatif des différences de ces fonctions :

FonctionBlockProcLambda
ClasseProcProcProc
Stockable en variableNonOuiOui
Interrompt l’exécution–OuiNon
Sensible aux nombres d’argumentsNonNonOui

À lire aussi

Fresque numérique miniature image
16 avril 2025

Fresque du Numérique

Lire la suite

intelligence artificielle Ouicommit miniature image
17 mars 2025

Ouicommit – L’intelligence artificielle en entreprise, on y est ! 

Lire la suite

Image miniature Hackathon Women in Tech
13 mars 2025

Hackathon Women in Tech :  un engagement pour une tech plus inclusive 

Lire la suite

image miniature les nouveautés Atlassian
26 février 2025

Les nouveautés Atlassian en 2025

Lire la suite

Articles associés

Fresque numérique miniature image
16 avril 2025

Fresque du Numérique


Lire la suite
intelligence artificielle Ouicommit miniature image
17 mars 2025

Ouicommit – L’intelligence artificielle en entreprise, on y est ! 


Lire la suite
Image miniature Hackathon Women in Tech
13 mars 2025

Hackathon Women in Tech :  un engagement pour une tech plus inclusive 


Lire la suite

À propos

  • Qui sommes-nous ?
  • Références
  • RSE
  • Ressources

Offres

  • Applications métier
  • Collaboration des équipes
  • Sécurisation et optimisation du système d’information
  • Transformation numérique

Expertises

  • Développement logiciel
  • DevSecOps
  • Intégration de logiciels et négoce de licences
  • Logiciel de CRM et de gestion
  • UX/UI design
  • Accessibilité Numérique
  • Démarches simplifiées
  • Formations Atlassian

Carrières

  • Pourquoi rejoindre Ouidou ?
  • Nous rejoindre
  • Rencontrer nos collaborateurs
  • Grandir chez Ouidou

SIEGE SOCIAL
70-74 boulevard Garibaldi, 75015 Paris

Ouidou Nord
165 Avenue de Bretagne, 59000 Lille

Ouidou Rhône-Alpes
4 place Amédée Bonnet, 69002 Lyon

Ouidou Grand-Ouest
2 rue Crucy, 44000 Nantes

Ouidou Grand-Est
7 cour des Cigarières, 67000 Strasbourg

  • Linkedin Ouidou
  • GitHub Ouidou
  • Youtube Ouidou
© 2024 Ouidou | Tous droits réservés | Plan du site | Mentions légales | Déclaration d'accessibilité
    Nous contacter