Интерполяция

Материал из Eludia
Перейти к: навигация, поиск

Опишем механизм подстановки данных в большие тексты, используемый в Eludia (функция fill_in_template) для печати офисных документов и рассылке e-mail.

Cтроки с интерполяцией в perl – это готовый язык шаблонов, абсолютно полнофункциональный. Лучшего вы не напишете, да это и не требуется. К глубокому сожалению, даже среди профессиональных perl-разработчиков многие не представляют себе, какие возможности предоставляет нехитрый на вид вызов eval ("qq{ ... }").

Начнём с простого. Все знают, как пользоваться интерполяцией скаляров: "Hello, $name!". Многие знают о возможности интерполяции списков: "Hello, @letters!" – но не пользуются ей, поскольку обычно в качестве склеивающего разделителя требуется не пустая строка, а как минимум запятая. Интерполяция элементов иерархических структур : "Hello, $users->[-1]->{name}!" – тоже фокус довольно стандартный.

Имя переменной, идущее после сигила, можно заключать в фигурные скобки. Это само по себе ценно в тех случаях, когда позволяет избежать разночтений: "Hello, ${user}_looser!". Сигил $ подставляет скаляр, на который указывает последующая ссылка (в данном случае слово user – символическая ссылка на анонимную переменную). Аналогично для списка "Hello, @{letters}!". А вот здесь – важный момент. Для создания ссылки на список, как известно, у нас есть специальный конструктор: [], который может содержать произвольные выражения, в том числе использующие вызовы функций: "Hello, @{[ 2 * 2, cos (0) ]}!". Значит, можно рассматривать скобки @{[ ... ]} как включение в строку значения выражения, точь-в-точь <%= ... %> в ASP.

Итак, в qq-строку можно интерполировать любые выражения Perl, в том числе использующие вызовы функций, в том числе qq (или её вариант – here-документ). Получаем вложенный шаблон. Простейший случай его применения – включение/выключение некоторого куска текста:

@{[ !$_REQUEST {full} ? ' ' : qq {

	А ещё тебе желаю, дорогой товарищ мой...

}]}

И совершенно необходимой становится эта вещь в отчётах, содержащих таблицы:

@{[ map {qq {

	<tr>
		... $_->{label} ...
	</tr>

}} @{$data -> {rows}} ]}

Для внутренней qq справедливо всё сказанное выше. В том числе, она может содержать вложенный подшаблон (вложенность может быть любой — это вам не PHP!) – что весьма удобно использовать, скажем, для таблиц с переменным числом столбцов:

@{[ map {qq {

	<tr>

	@{[ map {qq {

		<td>
			... $_->{price} ...
		</td>

       }} @{$_ -> {cols}} ]}

	</tr>

}} @{$data -> {rows}} ]}

Единственный неприятный сюрприз — то, что во внутреннем map теряется значение переменной $_ от внешнего. А оно вполне может понадобиться. Но это ерунда: ведь 1-й аргумент map — полноценный блок кода, внутри которого можно заявлять лексические переменные и вообще производить любые дополнительные операции:

@{[ map {

   my $LINE = $_;

   qq {

	<tr>

	@{[ map {qq {

		<td>
			... $LINE->{$_->{id}}->{price} ...
		</td>

       }} @{$data -> {cols}} ]}

	</tr>

   }

} @{$data -> {rows}} ]}

Итак, интерполяция qq-строк позволяет реализовать шаблоны любой степени вложенности. А значит, всё, что нужно для генерации документа – это выбрать данные в глобальную переменную (для определённости желательно использовать имя $data), достать из файла (желательно в директории docroot/templates) текст шаблона и вычислить его как qq-строку, после чего выдать клиенту под видом .doc или .xls. Именно так следует печатать в офисных форматах. И никак иначе.

На заметку

Чтобы знак доллара $ попал на печать, а не был посчитан спецсимволом, замените его на &#36;.

Персональные инструменты
Пространства имён

Варианты
Действия
Навигация
Разработчику
Администратору
Инструменты