<?xml version="1.0" encoding="IBM866"?>
<!--
Source: http://forum.template-toolkit.ru/rss/forum_8.rss
Expect: IBM866
-->
<rss version="2.0">
	<channel>
		<title>Форумы Template Toolkit : Библиотеки для работы с шаблонами в Perl</title>
		<link>http://forum.template-toolkit.ru/view_forum/forum_id-8.html?rss</link>
		<description>Template Toolkit - быстрая, мощная и расширяемая система обработки шаблонов. На сайте работает форум, в котором обсуждаются вопросы использования библиотеки по работе с шаблонами. Text::Template, HTML::Template, Mason и другие библиотеки</description>
		<language>ru</language>
		<copyright>Lobanov Igor</copyright>
		<webMaster>Lobanov Igor &lt;webmaster@template-toolkit.ru&gt;</webMaster>
		<pubDate>Thu, 17 Mar 2005 12:03:32 GMT</pubDate>
		<lastBuildDate>Wed,  4 Jan 2006 02:29:01 GMT</lastBuildDate>
		<managingEditor>Perl script, Template Toolkit</managingEditor>
		<image>
			<url>http://forum.template-toolkit.ru/images/tt2powered.gif</url>
			<title>Template Toolkit - шаблоны в perl</title>
			<link>http://forum.template-toolkit.ru/</link>
			<width>88</width>
			<height>31</height>
		</image>
		<docs>http://blogs.law.harvard.edu/tech/rss</docs>
		<item>
			<guid isPermaLink="true">http://forum.template-toolkit.ru/view_topic/topic_id-53.html?rss</guid>
			<pubDate>Tue, 28 Dec 2004 19:07:19 GMT</pubDate>
			<title>Разделение кода, представления, и конфигурации</title>
			<link>http://forum.template-toolkit.ru/view_topic/topic_id-53.html?rss</link>
			<description>На &lt;a target="_blank" href="http://www.theperlreview.com/"&gt;Perl Review&lt;/a&gt; опубликована статья Брайана де Фоя (brian d foy) &amp;quot;Separating Code, Presentation, and Configuration&amp;quot;. Ниже приводится перевод статьи.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold"&gt;Краткий обзор.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Я взял программу из предыдущей статьи и разделил код, представление и конфигурацию, чтобы сделать программу более гибкой и легкой для поддержки.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold"&gt;1. Введение.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;В последнем выпуске я представил программу, которую я использую для того, чтобы забирать и отображать Rich Site Summaries (RSS) с других веб-сайтов&lt;span style="font-weight:bold"&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/span&gt;. В коде я использовал литеральные величины, чтобы указать какие файлы загружать и как представлять данные, и обещал что в этом выпуске я это исправлю.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic"&gt;Листинг 1&lt;/span&gt; содержит программу, которую я представлял в предыдущем выпуске. В массиве &lt;span style="font-weight:bold"&gt;@files&lt;/span&gt; хранятся файлы, которые необходимо загрузить, &lt;span style="font-weight:bold"&gt;$base&lt;/span&gt; - каталог, где сохраняется вывод, и несколько выражений &lt;span style="font-weight:bold"&gt;print&lt;/span&gt; создают HTML с подстановкой простых переменных (что предпочтительнее скажем чем использовать HTML-функции модуля CGI). Это негибкий и трудный для сопровождения код. Когда я захочу поменять список сайтов или вывод, я рискую сломать программу, если наберу что-то неправильно или сделаю другую ошибку.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic"&gt;Листинг 1: Загрузчик RSS с жесткопрописанными значениями.&lt;/span&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;pre&gt;1	#!/usr/bin/perl -w
2	use strict;
3
4	use LWP::Simple;
5	use XML::RSS;
6
7	my @files = qw(
8	  http://use.perl.org/useperl.rss
9	  http://search.cpan.org/rss/search.rss
10	  http://jobs.perl.org/rss/standard.rss
11	  http://www.perl.com/pace/perlnews.rdf
12	  http://www.perlfoundation.org/perl-foundation.rdf
13	  http://www.stonehenge.com/merlyn/UnixReview/ur.rss
14	  http://www.stonehenge.com/merlyn/WebTechniques/wt.rss
15	  http://www.stonehenge.com/merlyn/LinuxMag/lm.rss
16	);
17
18	my $base = '/usr/home/comdog/TPR/rss-html';
19
20	foreach my $url ( @files )
21	  {
22	  my $file = $url;
23
24	  $file =~ s|.*/||;
25
26	  my $result = open my $fh, &amp;quot;&amp;gt; $base/$file.html&amp;quot;;
27
28	  unless( $result )
29	    {
30	    warn &amp;quot;Could not open [$file] for writing! $!&amp;quot;;
31	    next;
32	    }
33
34	  select $fh;
35
36	  my $rss = XML::RSS-&amp;gt;new();
37	  my $data = get( $url );
38	  $rss-&amp;gt;parse( $data );
39
40	  my $channel = $rss-&amp;gt;{channel};
41	  my $image = $rss-&amp;gt;{image};
42
43	  print &amp;lt;&amp;lt;&amp;quot;HTML&amp;quot;;
44	  &amp;lt;table cellpadding=1&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td bgcolor=&amp;quot;#000000&amp;quot;&amp;gt;
45	  &amp;lt;table cellpadding=5&amp;gt;
46	    &amp;lt;tr&amp;gt;&amp;lt;td bgcolor=&amp;quot;#aaaaaa&amp;quot; align=&amp;quot;center&amp;quot;&amp;gt;
47	HTML
48
49	  if( $image-&amp;gt;{url} )
50	    {
51	    my $img = qq|&amp;lt;img src=&amp;quot;$$image{url}&amp;quot; alt=&amp;quot;$$channel{title}&amp;quot;&amp;gt;|;
52	    print qq|&amp;lt;a href=&amp;quot;$$channel{link}&amp;quot;&amp;gt;$img&amp;lt;/a&amp;gt;&amp;lt;br&amp;gt;\n|;
53	    }
54	  else
55	    {
56	    print qq|&amp;lt;a href=&amp;quot;$$channel{link}&amp;quot;&amp;gt;$$channel{title}&amp;lt;/a&amp;gt;&amp;lt;br&amp;gt;\n|;
57	    }
58
59	  print &amp;lt;&amp;lt;&amp;quot;HTML&amp;quot;;
60	  &amp;lt;font size=&amp;quot;-1&amp;quot;&amp;gt;$$channel{description}&amp;lt;/font&amp;gt;
61	  &amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;
62	  &amp;lt;tr&amp;gt;&amp;lt;td bgcolor=&amp;quot;#bbbbff&amp;quot; width=200&amp;gt;&amp;lt;font size=&amp;quot;-1&amp;quot;&amp;gt;
63	HTML
64
65	  foreach my $item ( @{ $rss-&amp;gt;{items} } )
66	    {
67	    print qq|&amp;lt;b&amp;gt;&amp;gt;&amp;lt;/b&amp;gt;&amp;lt;a href=&amp;quot;$$item{link}&amp;quot;&amp;gt;$$item{title}&amp;lt;/a&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;\n|;
68	    }
69
70	  print &amp;lt;&amp;lt;&amp;quot;HTML&amp;quot;;
71	    &amp;lt;/font&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;
72	  &amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;
73	  &amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;
74	HTML
75
76	  close $fh;
77	  }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold"&gt;2. Отделение представления.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Хороший дизайн не связывает себя с частным представлением данных. Моя программа должна забрать данные и сделать их доступными чему-то, что их представляет - то, что я работаю с RSS не должно иметь значения. Я могу захотеть производить HTML, TeX, простой текст, или даже какой-то формат, который не могу себе представить.&lt;br /&gt;&lt;br /&gt;Возможно кто-то захочет написать собственную систему для работы с шаблонами, но мне нравится модуль Text::Template Марка-Джейсона Доминуса (Mark-Jason Dominus). Он делает все что мне необходимо, не требует для своей работы дополнительных программ и написан полностью на Perl. У него простой интерфейс и мне не требуется изучать язык шаблонов, поскольку шаблоны используют Perl.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic"&gt;Листинг 2&lt;/span&gt; - это та же программа, только вместо внедренного HTML используется Text::Template. В строке 5 я импортирую метод fill_in_file(). В строке 13 указываю шаблон, который буду использовать. Весь HTML, используемый программой, теперь вынесен в файл шаблона, приведенный в &lt;span style="font-style:italic"&gt;листинге 3&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Модуль Text::Template может принимать данные как хеш. Ключи хеша становятся именами переменных в шаблоне, а значения - значениями переменных шаблона, а также определяют тип переменных. Если значение хеша простой скаляр, переменная шаблона скаляр. Если значение хеша - анонимный массив, переменная шаблона - массив, и так далее.&lt;br /&gt;&lt;br /&gt;Объект, создаваемый XML::RSS - анонимный хеш. Модуль предоставляет абстрактный интерфейс для создания, но не для доступа. Это отчасти именно то, что я должен передать моему шаблону. В шаблоне &lt;span style="font-weight:bold"&gt;$rss-&amp;gt;channel&lt;/span&gt;, которая в качестве значения содержит анонимный хеш, становится &lt;span style="font-weight:bold"&gt;%channel&lt;/span&gt;, а &lt;span style="font-weight:bold"&gt;$rss-&amp;gt;items&lt;/span&gt;, содержащая анонимный массив становится &lt;span style="font-weight:bold"&gt;@items&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic"&gt;Листинг 2: Использование шаблона.&lt;/span&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;pre&gt;1	#!/usr/bin/perl -w
2	use strict;
3
4	use LWP::Simple;
5	use Text::Template qw(fill_in_file);
6	use XML::RSS;
7
8	my @files = qw(
9	  http://use.perl.org/useperl.rss
10	);
11
12	my $base = '.';
13	my $template = 'rss-html.tmpl';
14
15	foreach my $url ( @files )
16	  {
17	  my $file = $url;
18
19	  $file =~ s|.*/||;
20
21	  my $result = open my $fh, &amp;quot;&amp;gt; $base/$file.html&amp;quot;;
22
23	  unless( $result )
24	    {
25	    warn &amp;quot;Could not open [$file] for writing! $!&amp;quot;;
26	    next;
27	    }
28
29	  my $rss = XML::RSS-&amp;gt;new();
30	  my $data = get( $url );
31	  $rss-&amp;gt;parse( $data );
32
33	  print fill_in_file( $template, HASH =&amp;gt; $rss );
34	  close $fh;
35	  }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Внутри шаблона Text::Template исполняет блоки кода, которые он находит между фигурными скобками. Он заменяет блок последним вычисленным выражением. Имена переменных - ключи хеша, ссылку на который я передал в качестве аргумента функции fill_in_file() в коде, приведенном в &lt;span style="font-style:italic"&gt;листинге 2&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic"&gt;Листинг 3: HTML шаблон.&lt;/span&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;pre&gt;1	&amp;lt;table cellpadding=1&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td bgcolor=&amp;quot;#000000&amp;quot;&amp;gt;
2	&amp;lt;table cellpadding=5&amp;gt;
3	  &amp;lt;tr&amp;gt;
4	    &amp;lt;td bgcolor=&amp;quot;#aaaaaa&amp;quot; align=&amp;quot;center&amp;quot;&amp;gt;
5	    &amp;lt;a href=&amp;quot;{ $channel{link} }&amp;quot;&amp;gt;{
6
7	    $image ? qq|&amp;lt;img src=&amp;quot;$image&amp;quot; alt=&amp;quot;$channel{title}&amp;quot;&amp;gt;| : $channel{title}
8
9	    }&amp;lt;/a&amp;gt;&amp;lt;br&amp;gt;
10
11	    { $channel{description} }
12	    &amp;lt;/td&amp;gt;
13	  &amp;lt;/tr&amp;gt;
14
15	  &amp;lt;tr&amp;gt;
16	    &amp;lt;td bgcolor=&amp;quot;#bbbbff&amp;quot; width=200&amp;gt;&amp;lt;font size=&amp;quot;-1&amp;quot;&amp;gt;
17	{
18	    my $str;
19
20	    foreach my $item ( @items )
21	      {
22	      $str .= qq|&amp;lt;b&amp;gt;&amp;gt;&amp;lt;/b&amp;gt;&amp;lt;a href=&amp;quot;$$item{link}&amp;quot;&amp;gt;$$item{title}&amp;lt;/a&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;\n|;
23	      }
24
25	    $str;
26	}&amp;lt;/font&amp;gt;&amp;lt;/td&amp;gt;
27	  &amp;lt;/tr&amp;gt;
28	&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;
29	&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Как только система шаблонов задейстована, я могу менять представление не меняя логику кода. Если я приму решение изменить вид представления данных, я поменяю только шаблон. Если мне вместо HTML требуется простой текст, я только изменю под новый формат шаблон, как это сделано в &lt;span style="font-style:italic"&gt;листинге 4&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic"&gt;Листинг 4: Шаблон для обычного текста.&lt;/span&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;pre&gt;1	{ $channel{title} }
2
3	{ $channel{description} }
4
5	{
6	my $str;
7
8	foreach my $item ( @items )
9	  {
10	  $str .= qq|* $$item{title}\n|;
11	  }
12
13	$str;
14	}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold"&gt;3. Отделение конфигурации.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Хороший дизайн также позволяет адаптировать скрипт к различному окружению. В &lt;span style="font-style:italic"&gt;листинге 1&lt;/span&gt; я жестко прописал значение директории для вывода, что делает мой скрипт хрупким - если моя домашняя директория поменяется, скрипт сломается. Кроме того &lt;span style="font-style:italic"&gt;в листинге 2&lt;/span&gt; жестко прописано имя шаблона, несмотря на то что я могу менять представление, изменяя шаблон. Мне нужно иметь возможность давать каждому шаблону содержательное имя вместо использования одного и того же имени для разного содержимого.&lt;br /&gt;&lt;br /&gt;Многие свободно-доступные скрипты, которые я нашел в Интернет требуют, чтобы пользователь отредактировал верхнюю часть скрипта или включаемую библиотеку, которая содержит только конфигурационные данные. Такой подход требует, чтобы конечный пользователь знал основы языка программирования и правил скрипт - ошибка сломает скрипт. Плохие конфигурационные данные могут привести к неожиданным результатам, но они не поломают программу.&lt;br /&gt;&lt;br /&gt;Я могу указать текущие конфигурационные данные несколькими способами и покажу только один из них. Архив Comprehensive Perl Archive Network (CPAN)&lt;span style="font-weight:bold"&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/span&gt; содержит несколько модулей для разбора конфигурационных файлов в различных форматах или аргументов командной строки. Дизайнеры должны выбирать подход, который удовлетворяет их нуждам.&lt;br /&gt;&lt;br /&gt;Когда я впервые начал отделять данные конфигурации от моих скриптов, я перебрал несколько модулей на CPAN и остановился на ConfigReader::Simple, который использует построчный формат ключ-значение. Я использовал его настолько часто, что начал отправлять мои изменения Беку Оберину (Bek Oberin), автору оригинальной версии, затем полностью взял на себя поддержку модуля.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic"&gt;Листинг 5&lt;/span&gt; адаптирует &lt;span style="font-style:italic"&gt;листинг 2&lt;/span&gt; к использованию ConfigReader::Simple. Я создаю новый объект конфигурации, затем читаю значения из объекта. Модуль преобразует имена ключей конфигурации в имена методов для простого доступа (хотя для доступа к значениям ключей с экзотическими именами, которые не могут быть преобразованы в идентификаторы Perl приходится использовать метод get()). &lt;span style="font-style:italic"&gt;Листинг 6&lt;/span&gt; содержит конфигурационный файл.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic"&gt;Листинг 5: Использование ConfigReader::Simple.&lt;/span&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;pre&gt;1	#!/usr/bin/perl -w
2	use strict;
3
4	use ConfigReader::Simple;
5	use LWP::Simple;
6	use Text::Template qw(fill_in_file);
7	use XML::RSS;
8
9	my $config = ConfigReader::Simple-&amp;gt;new( './rss.config' );
10
11	my $base = $config-&amp;gt;base;
12	my $template = $config-&amp;gt;template;
13	my $extension = $config-&amp;gt;extension;
14
15	my @files = split /\s+/, $config-&amp;gt;files;
16
17	foreach my $url ( @files )
18	  {
19	  my $file = $url;
20
21	  $file =~ s|.*/||;
22
23	  my $result = open my $fh, &amp;quot;&amp;gt; $base/$file.$extension&amp;quot;;
24
25	  unless( $result )
26	    {
27	    warn &amp;quot;Could not open [$file] for writing! $!&amp;quot;;
28	    next;
29	    }
30
31	  my $rss = XML::RSS-&amp;gt;new();
32	  my $data = get( $url );
33	  $rss-&amp;gt;parse( $data );
34
35	  print $fh fill_in_file( $template, HASH =&amp;gt; $rss );
36	  close $fh;
37	  }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-style:italic"&gt;Листинг 6: Файл конфигурации.&lt;/span&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;pre&gt;1	base .
2	template rss-html.tmpl
3	files http://use.perl.org/useperl.rss
4	extension html&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold"&gt;4. Заключение.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Я могу уменьшить размер моих программ, отделяя код от логики представления и конфигурационной информации. Это разделение делает программу более гибкой и простой в адаптации к новым окружениям. Шаблоны позволяют изменять вывод, а конфигурационные файлы управлять работой программы  без изменения кода. Text::Template и ConfigReader::Simple делают это настолько простым, насколько возможно.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold"&gt;5. Ссылки&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Все модули, упоминаемые в этой статье, можно найти на Comprehensive Perl Archive Network (CPAN) - &lt;a target="_blank" href="http://search.cpan.org"&gt;http://search.cpan.org&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold"&gt;6. Об авторе.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Брайан де Фой (brian d foy) - издатель &lt;span style="font-style:italic"&gt;The Perl Review&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold"&gt;Примечания.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold"&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/span&gt; &amp;quot;Simple RSS with Perl&amp;quot; by brian d foy, The Perl Review v0 i5, November 2002, &lt;a target="_blank" href="http://www.theperlreview.com"&gt;http://www.ThePerlReview.com&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold"&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/span&gt; &lt;a target="_blank" href="http://search.cpan.org"&gt;http://search.cpan.org&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a target="_blank" href="http://www.theperlreview.com/Articles/v0i7/config.pdf"&gt;оригинал статьи на Perl Review (PDF)&lt;/a&gt;
			</description>
			<author>Лобанов Игорь &lt;authors@template-toolkit.ru&gt;</author>
			<comments>http://forum.template-toolkit.ru/view_topic/topic_id-53.html</comments>
			<category>Другие темы, связанные с шаблонами и Perl</category>
			<source url="http://forum.template-toolkit.ru/rss/forum_id-8.rss">http://forum.template-toolkit.ru/view_topic/topic_id-53.html?rss</source>
		</item>
	</channel>
</rss>
