
Exemple : une classe `User` dans son propre fichier
Mettez en pratique la séparation de code en Ruby. Cet exemple concret vous montre comment créer une classe User dans son propre fichier et la charger dans un script principal avec `require_relative`.
Quelle est la structure de fichiers idéale pour cet exemple ?
Pour illustrer la séparation du code, nous allons adopter une structure de projet simple mais très courante en Ruby. Nous aurons un fichier principal, que nous nommerons app.rb, qui agira comme le point d'entrée de notre programme. La logique métier, ici notre classe User, sera placée dans un sous-dossier dédié appelé lib (abréviation de "library").
Voici l'arborescence de notre projet. Cette organisation est un excellent point de départ pour la plupart des petites applications.
mon_application/
├── app.rb # Le point d'entrée qui exécute notre code
└── lib/
└── user.rb # Le fichier contenant la définition de la classe UserLe rôle de chaque fichier est clair : lib/user.rb ne fait que définir ce qu'EST un utilisateur, tandis que app.rb est responsable de l'UTILISATION de cette définition pour créer des instances et les faire interagir.
Etape 1 : Définir la classe `User` dans `lib/user.rb`
Commençons par créer le fichier lib/user.rb. L'objectif de ce fichier est unique : il doit contenir tout le code relatif à la classe User, et rien d'autre. C'est le principe de responsabilité unique.
Notre classe User sera simple : elle prendra un nom et un email lors de sa création et aura une méthode pour afficher ses informations.
# lib/user.rb
class User
# attr_reader crée automatiquement les méthodes `name` et `email`
# pour lire les valeurs des variables d'instance.
attr_reader :name, :email
def initialize(name, email)
@name = name
@email = email
end
def info
"Utilisateur : #{@name}, Email : #{@email}"
end
endA ce stade, si vous exécutez ce fichier seul (ruby lib/user.rb), rien ne se passera. C'est normal : nous n'avons fait que définir un "plan" (la classe), mais nous ne l'avons pas encore utilisé pour construire quoi que ce soit.
Etape 2 : Charger et utiliser la classe dans `app.rb`
Maintenant, passons à notre fichier principal, app.rb. Pour pouvoir créer des objets de type User, ce fichier doit d'abord charger la définition de la classe qui se trouve dans lib/user.rb. C'est le rôle de require_relative.
Nous allons indiquer le chemin vers notre fichier user.rb par rapport à l'emplacement de app.rb. Une fois cette instruction exécutée, c'est comme si le code de user.rb avait été copié-collé au début de notre fichier app.rb.
# app.rb
# 1. On charge le fichier `user.rb` qui se trouve dans le sous-dossier `lib`.
# Le chemin est relatif à `app.rb`.
require_relative 'lib/user'
puts "Bienvenue dans notre application !"
# 2. La classe User est maintenant connue. Nous pouvons créer des instances.
user1 = User.new('Alice', 'alice@example.com')
user2 = User.new('Bob', 'bob@example.com')
# 3. Nous pouvons appeler les méthodes sur nos nouvelles instances.
puts user1.info
puts user2.infoEtape 3 : Exécuter le programme et voir le résultat
Tout est en place. Pour lancer notre application, il suffit d'exécuter le point d'entrée depuis notre terminal. Assurez-vous d'être à la racine du dossier mon_application/.
$ ruby app.rbLa sortie devrait être la suivante :
Bienvenue dans notre application !
Utilisateur : Alice, Email : alice@example.com
Utilisateur : Bob, Email : bob@example.comQue s'est-il passé exactement ? Lorsque vous lancez ruby app.rb, l'interpréteur lit le fichier ligne par ligne. En arrivant sur require_relative 'lib/user', il met en pause l'exécution de app.rb, va lire et exécuter entièrement lib/user.rb (définissant ainsi la classe User en mémoire), puis revient à app.rb pour exécuter les lignes suivantes. L'appel à User.new réussit car la classe a été chargée juste avant.
Pourquoi cet exemple est-il fondamental ?
Cet exemple, bien que simple, représente la manière dont la quasi-totalité des applications Ruby sont structurées. En séparant les définitions (les classes dans lib/) de l'exécution (le script principal), vous gagnez énormément en clarté et en maintenance.
Imaginez un projet avec 20 classes différentes. Si tout était dans un seul fichier, ce serait le chaos. Avec cette structure, vous savez immédiatement où chercher si vous devez modifier la classe Order : dans le fichier lib/order.rb. Cette convention est la première étape vers la construction d'applications robustes et scalables, et c'est le socle sur lequel reposent des outils plus avancés comme Bundler, que nous allons découvrir très prochainement.