Les exceptions forment un arbre — et une frontière y compte.Exceptions form a tree — and one boundary matters in it.
Le № 1 rattrapait par type ; mais ce tri ne vaut que par la qualité de l'arbre qu'on lui donne. Toutes les exceptions descendent d'Exception. Juste en dessous, une frontière décisive sépare deux mondes : StandardError, où vivent les erreurs ordinaires d'un programme (et où doivent aller les tiennes), et tout ce qui est sous Exception mais hors de StandardError — les signaux système : Interrupt (le Ctrl-C de l'utilisateur), SystemExit, NoMemoryError. Ce ne sont pas des bugs à gérer, ce sont des ordres de l'extérieur. C'est pour ça que rescue, sans précision, s'arrête à StandardError : il laisse passer les signaux.№ 1 caught by type; but that sorting is only as good as the tree you give it. Every exception descends from Exception. Just below, a decisive boundary splits two worlds: StandardError, home to a program's ordinary errors (and where yours belong), and everything under Exception but outside StandardError — the system signals: Interrupt (the user's Ctrl-C), SystemExit, NoMemoryError. These aren't bugs to handle, they're orders from outside. That's why rescue, unqualified, stops at StandardError: it lets the signals through.
# l'arbre des exceptions — et la frontière qui compte Exception # la racine de TOUT ├─ NoMemoryError # ┐ ├─ SignalException → Interrupt # │ hors de StandardError : ├─ SystemExit # │ les signaux système, à NE PAS rattraper ├─ ScriptError # ┘ └─ StandardError # ← le défaut de rescue, et la maison de TES erreurs ├─ RuntimeError # raise "msg" en crée une ├─ ArgumentError, KeyError # les erreurs « normales » d'un programme └─ NoMethodError, TypeError raise "boom" # => RuntimeError, donc < StandardError RuntimeError.ancestors # => [RuntimeError, StandardError, Exception, Object, ...]
NoMemoryError
tes erreurs maison
La règle tient en une ligne : hérite de StandardError, rattrape StandardError — jamais Exception. La frontière n'est pas cosmétique : d'un côté ce que ton programme peut gérer, de l'autre ce qu'il doit laisser le tuer.The rule fits one line: inherit from StandardError, rescue StandardError — never Exception. The boundary isn't cosmetic: on one side what your program can handle, on the other what it must let kill it.
« J'hérite de StandardError, je rattrape StandardError, jamais Exception. » Tes classes d'erreur descendent de StandardError pour qu'un rescue ordinaire les voie ; et tu ne rattrapes jamais Exception, pour ne pas avaler les signaux que l'utilisateur ou le système t'envoient."I inherit from StandardError, I rescue StandardError, never Exception." Your error classes descend from StandardError so an ordinary rescue sees them; and you never rescue Exception, so you don't swallow the signals the user or system sends you.
Rien de neuf depuis le Vol 5 : rescue KeyError attrape KeyError et ses descendants parce que rescue teste l'appartenance avec === (donc is_a?) le long de la chaîne. Rattraper une classe, c'est rattraper tout son sous-arbre. C'est précisément ce qui rend une hiérarchie maison si utile : une classe de base bien placée attrape toute une famille d'erreurs d'un seul rescue.Nothing new since Vol 5: rescue KeyError catches KeyError and its descendants because rescue tests membership with === (hence is_a?) along the chain. Catching a class catches its whole subtree. That's exactly what makes a custom hierarchy so useful: one well-placed base class catches a whole family of errors with a single rescue.