В байткод-компиляторе реализован простой механизм AST-трансформации,
распознающий и подменяющий определенные AST-конструкции. Измененные
конструкции порождают байткод иной, чем изначальные. Исходники преобразований
находятся в lib/compiler/ast/transforms.rb.
TODO: описать plugin-архитектуру компилятора.
Поскольку базовые (core) библиотеки построены из тех же блоков, что и любой
другой Ruby-код, а Ruby — язык динамический, с открытыми классами и
отложенным связыванием, появляется возможность изменять фундаментальные классы
вроде Fixnum таким образом, что нарушается семантика, от которой зависят
другие классы. К примеру, представьте себе такое нововведение:
class Fixnum
def +(other)
(self + other) % 5
end
end
Хотя переопределение арифметического_с_фиксированной_точкой_плюса в
остаток_от_деления_на_пять вполне возможно, это действие обязательно
заставит некоторый класс вроде Array не смочь в нужный момент вычислить,
например, корректную длину. Динамическая натура Ruby — одна из его любимых
черт, но она же в некотором смысле и палка о двух концах.
Одна из стандартных библиотек, mathn, переопределяет Fixnum#/ в опасной и
несовместимой манере. Библиотека алиасит Fixnum#/ в Fixnum#quo, который по
умолчанию возвращает Float.
Из-за этого сделан специальный плагин компилятора, который, встречая #/,
порождает иное имя метода. Компилятор вместо #/ выдает #divide. Численные
классы Fixnum, Bignum, Float и Numeric все определяют этот метод.
Для запуска плагина безопасная трансформация математики включается в момент
компиляции Core libraries. Когда компилируется обычный «юзер-код», плагин
выключен. Это делает возможной поддержку mathn без повреждения базовых
библиотек и принуждения к использованию прочих нехороших приемов.