Есть вложенные классовые уловки.Почему?
Вместо того, чтобы быть элегантным кодом с самоописанием, как можно было бы разумно ожидать, этот метод выглядит так, как будто он основан на боевом, исправленном и исправленном рабочем коде (поэтому, возможно, мы можем проститьих немного).
Так почему же два зла?Прежде чем второй вложенный «реальный» код метода шаблона может быть eval'd, код, который должен быть eval'd, должен иметь префикс с правильной исходной кодировкой, которая могла быть определена как «магический комментарий» в файле шаблона.
Как только строковое кодирование установлено правильно, может быть предпринят реальный class_eval.Другой способ сказать, что это может быть «Это исходный код, который пишет исходный код, который пишет исходный код»! *
Предположительно, это исправляет проблемы совместимости, которые могут возникнуть в Ruby 1.9, где компилируемый шаблон может содержатькодировка символов (UTF-8), которая отличается от кодировки самого исходного кода библиотеки Tilt (кодировка US-ASCII), что приведет к неправильной оценке строк шаблона (поскольку кодировка строки уже будет установлена в коде хоста, которыйвызывает файл шаблона).
Почему метод определяется и затем не связан?
Чтобы уточнить: в Ruby unbound не являетсятак же, как undefined .
Существуют несвязанные методы как свободные объекты методов типа UnboundMethod , которые можно вызывать, хотя они больше не связаны с конкретным объектом.У несвязанного метода больше нет получателя.
Чтобы создать несвязанный метод, он сначала должен быть привязан (определен к) к объекту.Вот почему метод скомпилированного шаблона быстро удаляется из объекта верхнего уровня, потому что это было только временное расположение, необходимое для генерации несвязанного метода.
Этот метод используется, чтобы сделать возможным использование скомпилированных шаблонов, которыеограничены различными экземплярами данного класса, без изменения корневого объекта или клиентского класса стороннего разработчика любым видимым или постоянным способом.
Отключая метод скомпилированного шаблона от конкретного объекта кода клиента, скомпилированныйМетод шаблона может быть позднее восстановлен для новых экземпляров класса этого объекта во время будущих вызовов шаблонов, использующих объекты этого типа.
Например, с учетом следующего шаблона ERB:
<p>Hello <%= @name %></p>
... и следующий код вызова:
scott = Person.new
scott.name = "Scott"
output = template.render(scott)
=> "<p>Hello Scott</p>"
Во время этого первого рендеринга шаблон eval'd и скомпилирован с экземпляром объекта TOPOBJECT.Метод скомпилированного шаблона будет называться как «__tilt_2151955260
».Затем этот метод не привязывается для повторного использования со всеми экземплярами типа TOPOBJECT (который в зависимости от версии Ruby является просто Object или BasicObject) и, следовательно, может использоваться против любого типа объекта клиента.
В следующий разшаблон отображается, метод скомпилированного шаблона связан с экземпляром baq для TOPOBJECT:
baq = Person.new
baq.name = "Baq"
output = template.render(baq)
Под капотом, когда вызывается template.render(baq)
, несвязанный метод скомпилированного шаблона привязывается к 'baq 'instance of Person:
__tilt_2151955260.bind(baq).call
Отсутствие необходимости каждый раз вызывать class_eval приводит к значительному увеличению производительности.
Почему код компилирует кучу шаблонов идержит их для повторного использования настолько сложный внешний вид?
Моя оценка состоит в том, что хотя реализация кода действительно выглядит излишне сложной на первый взгляд, эти уровни косвенности часто необходимы в коде платформыцелью которого является сделать публичный API невероятно простым и приятным для использованиямногие тысячи других разработчиков, даже если это за счет тех немногих разработчиков, которые должны поддерживать его.
Сложность кода (двойное вложение) также возросла в результате реальных проблем, возникающих из-за API, который используется во многих различных локалях и, следовательно, во многих кодировках со всего мира.
Сноска :
Класс Template, упомянутый в вопросе, с тех пор был преобразован в отдельный файл github.com / rtomayko / tilt / blob / master / lib / tilt / template.rb