Introduction
La métaprogrammation Ruby permet de générer du code à l'exécution, créant des DSL puissants et des frameworks flexibles. En 2026, elle reste essentielle pour les gems modernes et les applications haute performance. Ce tutoriel couvre les techniques avancées utilisées dans Rails et les bibliothèques professionnelles. Vous apprendrez à manipuler les méthodes dynamiquement tout en évitant les pièges de maintenabilité.
Prérequis
- Ruby 3.3+
- Connaissance solide de la POO Ruby
- Expérience avec les gems et Bundler
- Terminal et éditeur configuré
Définition dynamique de méthodes
class DynamicAPI
def self.define_endpoint(name, &block)
define_method(name) do |*args|
instance_exec(*args, &block)
end
end
end
api = Class.new(DynamicAPI)
api.define_endpoint(:users) { |id| "User #{id}" }
instance = api.new
puts instance.users(42)Cette technique crée des méthodes à la volée via define_method. Elle est utilisée dans les routeurs Rails. Attention à la lisibilité et au débogage.
Implémentation de method_missing
class MethodProxy
def method_missing(name, *args, &block)
if name.to_s.start_with?('get_')
key = name.to_s.sub('get_', '')
return "Value for #{key}"
end
super
end
def respond_to_missing?(name, include_private = false)
name.to_s.start_with?('get_') || super
end
end
proxy = MethodProxy.new
puts proxy.get_usernamemethod_missing permet d'intercepter les appels inconnus. Toujours implémenter respond_to_missing pour une compatibilité complète avec respond_to?.
Singletons et eigenclasses
obj = Object.new
class << obj
def unique_behavior
"Comportement spécifique à cet objet"
end
end
puts obj.unique_behavior
def obj.another_method
"Autre méthode singleton"
endLes singletons permettent d'ajouter des comportements à des instances spécifiques sans modifier la classe. Utile pour les mocks et les configurations.
Refinements pour scoping
module StringExtensions
refine String do
def reverse_words
split.reverse.join(' ')
end
end
end
using StringExtensions
puts "hello world".reverse_wordsLes refinements limitent la portée des monkey-patches. Ils sont essentiels en 2026 pour éviter les conflits dans les grosses applications.
Création d'un mini DSL
class Workflow
def self.define(&block)
instance = new
instance.instance_eval(&block)
instance
end
def step(name, &block)
(@steps ||= []) << { name: name, action: block }
end
def run
@steps.each { |s| s[:action].call }
end
end
wf = Workflow.define do
step(:init) { puts 'Initialisation' }
step(:process) { puts 'Traitement' }
end
wf.runinstance_eval permet de créer des DSL lisibles. Cette approche est utilisée dans RSpec et les builders. Gardez le scope contrôlé.
Bonnes pratiques
- Préférez define_method aux eval pour la sécurité
- Documentez toujours les méthodes dynamiques générées
- Utilisez les refinements plutôt que les monkey-patches globaux
- Testez exhaustivement les chemins method_missing
- Limitez la profondeur des eigenclasses pour la lisibilité
Erreurs courantes à éviter
- Oublier respond_to_missing crée des bugs avec les bibliothèques tierces
- Utiliser eval sans sanitisation expose à des failles de sécurité
- Les refinements non activés avec 'using' n'ont aucun effet
- Surcharger method_missing sans super casse la chaîne d'héritage
Pour aller plus loin
Approfondissez ces concepts avec nos formations avancées Ruby.