Движок текстовых шаблонов
От: VladD2 Российская Империя www.nemerle.org
Дата: 11.04.07 00:29
Оценка:
В первую очередь нам нужен движек текстовых шаблонов.
По сути он будет похож на сегодняшнюю $-строку, но все же будет отличаться некоторыми расширенными возможностями:
1. Главное отличие заключается в том, что шаблон должен жить не сам по себе, а в составе и при непосредственном взаимодействии с другими шаблонами. Такие шаблоны объединяются в группу шаблонов.
2. Все шаблоны группы должны использовать для генерации текста единый для группы StringBuilder. Это обеспечит высокую скорость генерации текста.
3. Шаблоны должны позволять рекурсивное применение.
5. У шаблона должно быть описание входных параметров. Они могут исползовать в $ и ..$ конструкциях.

Группы шаблонов я вижу себе в виде класса (возможно помеченного неким атрибутом). Например:
[StringTemplateGroup]
class MyStringTemplateGroupe
{
    ...
}

Каждый шаблон можно описывать как некую псевдо-функцию тело которой не код, а строка с $-включениями. Вот пример группы шаблонов генерирующих код создания и удаления индексов.

[StringTemplateGroup]
class MethodGenerator
{
    // Описывает генерацию индекса.
    public virtual CreateIndex(index : Index, table : Table, isClustered : bool,
                                         isUnique : bool) : string StringTemplate 
    <[
    CREATE $(Unique(index.IsUnique)) $(Clustered(index.IsClustered)) INDEX $(Quot(index.Name)) ON $(Quot(table))
    (
      ..$(index.EntryColumns; "\n"; entry => $(entry.Column) $(Direction(entry.IsAscending)))
    )
    ]>
    
    // Генерирует выражение удаления индекса.
    // name - имя индекса подлежащего удалению.
    // table - имя таблицы индекс которой требуется удалить.
    public virtual DropIndex(name : string, table : string) : string StringTemplate <[
    DROP INDEX $Quot(name)$ ON $Quot(table)$
    ]>
    
    // Добавляет к имени символы цитирования. Это позволяет именам содержать
    // пробельные символы и пересекаться с ключевыми словами
    protected virtual Quot(name : string) StringTemplate <[
    [$name]
    ]>

    // Выводит сточку "UNIQUE" если isUnique равен true.
    // Это просто фукнция! Ее тело не является шаблоном.
    protected virtual Unique(isUnique : bool) : string
    {
      if (isUnique) " UNIQUE" else ""
    }

    ...
    
    // Выводит сточку ASC" если isAscending равен true или "DESC" в обратом случае.
    protected virtual Direction(isAscending : bool) : string
    {
      if (isAscending) "ASC" else "DESC"
    }
    
    ...
}

Общая идея такова. Данный код обрабатывается макросами и преобразуется в эффективный код генерации строк (с использованием StringBuilder-а).

Для каждого шаблона в группе создается две функции одна срытая имеющий прототим:
protected ИмяШаблона(список_параметров_шаблона) : void;

А другая имеющая прототип аналогичный описанному в группе. В случае рекурсивного вызова шаблонов вызывается скрытая функция. Это исключает лишние преобразования в строку, так как скрытая версия функции выводит генерируемый текст в StringBuilder.
Публичную функцию может вызвать пользователь. При этом внутренний StringBuilder сбрасывается, производится вызов скрытой версии фукнции, а затем содержимое внутреннего StringBuilder-а преобразуется в строку и возвращается наружу как возвращаемое значение функции.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.