Les modules en Crystal remplissent deux rôles :
Le premier est de créer un espace de noms pour éviter les collisions de noms. Cependant, il regroupe aussi le code, ce qui permet de mieux comprendre à quoi il sert.
Le second est de définir des mixins pour partager du code entre les types.
Les modules sont similaires aux classes, mais la principale différence est qu'ils ne peuvent pas être instanciés et n'ont donc pas de variables d'instance.
Pour déclarer un module, on utilise le mot-clé module suivi du nom du module.
module Foo
end
Un espace de noms est une façon de regrouper du code.
Cela évite les collisions de noms et permet de mieux comprendre à quoi sert le code.
Pour accéder à une constante ou à une classe placée dans un espace de noms, on utilise l'opérateur ::.
module Foo
class Bar
end
end
Foo::Bar.new
Cela peut être utile lorsque, par exemple, plusieurs classes ont besoin de la même fonctionnalité « base », ou lorsque du code doit être partagé entre des classes sans lien entre elles. Ou encore lorsqu'on veut partager du code entre des classes qui n'ont aucun lien.
Il y a deux façons différentes d'utiliser un module comme mixin : la première consiste à utiliser le mot-clé include, et la seconde à utiliser le mot-clé extend.
Les deux méthodes rendent les constantes disponibles pour le type qui inclut ou étend le module.
Avec include, toutes les méthodes du module deviennent des méthodes d'instance du type qui inclut le module.
Le mot-clé include doit se trouver en haut du type, suivi du nom du module.
module Foo
def foo
"foo"
end
end
class Bar
include Foo
end
Bar.new.foo # => "foo"
extend fonctionne de manière similaire à include, mais au lieu de rendre les méthodes disponibles en tant que méthodes d'instance, il les rend disponibles en tant que méthodes de classe.
Le mot-clé extend doit être écrit en haut du type, suivi du nom du module.
module Foo
def foo
"foo"
end
end
class Bar
extend Foo
end
Bar.foo # => "foo"
Un motif courant en Crystal consiste à utiliser extend self dans un module.
Cela rend toutes les méthodes du module disponibles en tant que méthodes de classe sur le module lui-même.
Ainsi, tu n'as pas besoin de définir chaque méthode sur le module avec la syntaxe def self.method_name.
module Foo
extend self
def foo
"foo"
end
end
Foo.foo # => "foo"
La Bellebrook Basketball League est une ligue composée de plusieurs équipes, chacune avec un effectif de joueurs. Une nouvelle saison est sur le point de commencer et la ligue doit créer un nouveau système de billetterie pour vendre des billets pour les matchs. La saison dernière, elle vendait les billets à l'entrée du stade, mais sa popularité a explosé et elle a décidé de vendre les billets en ligne cette saison pour faire face à la demande accrue.
La ligue t'a contacté et t'a demandé de créer un système pour gérer la vente des billets.
Pour commencer, tu dois créer un système de billetterie pour gérer la vente des billets. Le système de billetterie doit indiquer combien de billets sont disponibles pour un match.
Une instance d'une classe appelée TicketSystem doit être créée pour chaque match.
L'état initialisé doit contenir les informations suivantes :
Construis un état initialisé à partir d'arguments indiquant le nombre de billets disponibles et le stade dans lequel le match est joué.
L'état initialisé doit être composé des variables d'instance @tickets_available et @stadium.
Celles-ci doivent contenir respectivement le premier et le deuxième argument fournis.
TicketSystem.new(100, "Bellebrook")
# => #<TicketSystem:0x10f0b8 @tickets_available=100, @stadium="Bellebrook">
Pour commencer, tu dois créer une méthode qui renvoie le nombre de billets disponibles pour un match donné.
Définis un module appelé TicketingReservation au-dessus de la classe déjà définie.
Ce module doit être inclus dans la classe TicketSystem.
À l'intérieur du module, définis une méthode appelée tickets_available.
Cette méthode doit renvoyer le nombre de billets disponibles.
ticket_system = TicketSystem.new(100)
ticket_system.tickets_available
#=> 100
Tu dois créer une méthode qui vérifie si des billets sont disponibles pour un match donné. Le match doit avoir 100 billets en réserve. Cela permet de garantir qu'il y a toujours des billets disponibles pour les personnes qui achètent leurs billets à l'entrée du stade.
À l'intérieur du module TicketingReservation,, définis une méthode appelée order_ticket?.
La méthode doit renvoyer true si au moins 100 billets sont disponibles et false sinon.
Si au moins 100 billets sont disponibles, la méthode doit aussi diminuer de 1 le nombre de billets disponibles.
ticket_system = TicketSystem.new(100)
ticket_system.order_ticket?
#=> true
Le système de billetterie doit avoir des messages faciles à comprendre pour les utilisateurs. Et ces messages doivent être personnels, ils doivent donc inclure le nom de l'utilisateur.
Si l'achat du billet a réussi, l'utilisateur doit recevoir un message lui indiquant que l'achat a réussi, son numéro de billet et le stade dans lequel le match est joué. Le numéro de billet doit être le nombre de billets disponibles avant la commande.
Si l'achat a réussi, le message doit ressembler à ceci : {name}, your purchase was successful, your ticket number is #{ticket_number}, and the game is played at the {stadium_name} stadium..
Si l'achat a échoué, le message doit ressembler à ceci : {name}, your purchase was unsuccessful, there are not enough tickets available..
À l'intérieur du module TicketingReservation,, définis une méthode appelée order_message qui prend un argument name contenant le nom de l'acheteur.
La méthode doit renvoyer une string avec le message.
ticket_system = TicketSystem.new(100, "Bellebrook")
ticket_system.order_message("John")
#=> "John, your purchase was successful, your ticket number is #100, and the game is played at the Bellebrook stadium."
Inscris-toi sur Exercism pour apprendre et maîtriser Crystal avec 26 concepts142 exercices, et un vrai mentorat humain, le tout gratuitement.