http://ksnk.github.com/preprocessor/preprocessor.tar.gz - здесь можно скачать последнюю актуальную версию.
Сам проект находится здесь - https://github.com/Ksnk/preprocessor
Казалось бы, зачем благородному дону условная компиляция в php?
Однако, при создании web-проектов зачастую не хватает этапа "компиляции" скриптов проекта. К примеру, в шапки всех текстов, выкладываемых на целевой сервер неплохо бы вставить информацию о проекте, ревизии SVN и какую-нибудь сопроводительную муть. При создании ajax приложения возникает настойчивое желание спрятать в javascript-строку формочки и стили, созданные в обычном html редакторе.
При рисовании какой-нибудь заковыристой формочки, основанной на картинке, размеры этой картинки "гармонично" вливаются в javascript, css и разметку. Отсутствие констант в CSS служит источником вдохновения для создателей SASS...
Для демонстрации работы заказчику, часто требуется размещать проект на разных серверах с разным окружением. В итоге код проекта приходится слегка модифицировать для того или иного сервера, той или иной среды.
Изредка посещают крамольные мысли – сделать код одновременно для php4 и для php5.
Как правило, для таких целей используются файлы конфигурации, в которые, с соблюдением определенной ловкости рук, упакованы все кардинальные отличия проекта, в зависимости от погодных условий.
Однако решение некоторых этих проблем уже есть. Нужно ввести дополнительный язык препроцессора и научится с ним работать...
Web-программист - специалист по PHP и достаточно логично, что язык препроцессора будет тем же PHP. Тем более, что сам PHP и есть, с какой-то точки зрения, достаточно универсальный язык препроцессора. При этом совершенно бесплатно препроцессор приобретает всю могутность PHP, которой так не хватает другим языкам препроцессинга. Вот только теги препроцессора должны отличатся от тегов PHP, чтобы не возникало недоразумений. Пусть они будут asp-like <% %>
. Чтобы "выполнить" такой текст - достаточно заменить все PHP теги на что-то другое, поменять asp-like на php теги и исполнить их обычным eval'ом. После этого - вернуть php теги взад. It's easy... Хотя, чтобы сделать эту простую идею еще и полезной - нужно ее усложнить и понять, что же обычно требуется для сборки проекта.
Чтобы не путать с функциями обычного PHP, будем называть функции и константы, описанные в тегах препроцессора макрами или макрокомандами и макропеременными. В принципе, они именно этим и являются...
Часто приходится собирать несколько "целей" - комплектов файлов для разных условий содержания. Для отладки на локальном сервере, для отладки на целевом сервере, для выкладывания конечному клиенту. Так что наш проект - это комплект файлов, которые берутся из разных мест с девелоперской машины и помещаются в определенные каталоги "билда". Различать варианты сборок будем по имени "цели", которую будем хранить в макропеременной $target.
Чтобы можно было спокойно пользоваться макрами определенными в других файлах проекта, нужно исполнять их все в одном цикле. Тогда не нужно будет особенно заботится о видимости макрокоманд. Зато сам этап исполнения разбивается на 3 этапа - подготовка текста файла проекта к исполнению, путем замены тегов, собственно исполнение и возврат тегов обратно. Так что сначала нам придется каким-то образом описать весь комплект файлов проекта, а потом уже пробежаться по этому списку.
Сам препроцессор будет набором скриптов на php и будет запускаться в CLI режиме. Достаточно несложно включить такой вариант использования в ant/phing-сборщик или просто в батник, для хардкорщиков. При запуске скрипта мы передадим ему параметры
/usr/local/php5/php.exe -f /preprocessor/preprocessor.php /Dtarget=release /Ddst=build/$target config.xml
Имя config.xml
не является обязательно именно таким, однако для определенности, всегда в этом описании это имя будет обозначать файл, конфигурации, переданный на обработку препроцессору.
параметр /D - описание переменных c именами target и dst соответственно. Потом эти переменные можно будет использовать.
Все переменные окружения доступны в скрипте с префиксом env_.
set common=/project
макропеременная будет доступна с именем $env_common
В результате выполнения, появится комплект файлов, модифицированный для того или иного варианта сборки. Время модификации файлов будет скопировано (touch) из времени модификации исходных файлов. Для файлов, описанных в секции copy или file, которые не содержат тегов препроцессора, время будет браться из исходного файла. Для файлов, собранных препроцессором - время будет максимальным из времен всех "исходных" файлов, включая config.xml.
если "время" исходных файлов осталось не больше, чем время готового файла - собственно копирования и обработки файла не производится, что существенно ускоряет работу с большими объемами файлов проекта.
диагностика ошибок выполнения eval'уируемого кода проверена на php 5.2.8.8 Мне она представляется странной, однако, вроде работает ;)
Для того, чтобы сообщить препроцессору какие файлы входят в проект - создадим xml файл (config.xml). Вот такого, примерно, вида
<?xml version="1.0" encoding="UTF-8"?>
<config>
<var name="license"><![CDATA[
----------------------------------------------------------------------------
License GNU/LGPL - Serge Koriakin - June 2010
http://forum.vingrad.ru/users/ksnk
----------------------------------------------------------------------------
]]></var>
<files>
<file>rev.tmp</file>
</files>
<files dir="../cms/plugins">
<file>altname.php</file>
</files>
<files dstdir="$dst">
<file>index.php</file>
<file name=".htaccess">htaccess.txt</file>
<file>project.php</file>
<file>*.css</file>
<file>.htaccess</file>
<copy>style/*.*</copy>
<file>engine/hosts.*</file>
<file>engine/main.*</file>
<file>engine/project_core.*</file>
<copy>img/*.*</copy>
<file>js/*.*</file>
<file>templates/*.*</file>
</files>
<files dstdir="$dst" dir="../debug/debug">
<copy>Debug/HackerConsole/*.*</copy>
</files>
<files dstdir="$dst">
<copy>uploaded/*.*</copy>
</files>
</config>
Все используемые здесь пути вычисляются относительно расположения самого config.xml
config
- объемлющие скобки этого xml
var
- завести макропеременную с именем name. В текстах проекта этой переменной можно пользоваться внутри тегов препроцессора. Можно пользоваться параметром default, чтобы определить переменную, которой не было присвоено значение ранее. Областью видимости переменной будет тот блок групповых тегов, в котором она описана
import
- параметр NAME тега указывает на xml файл, файлы из которого будут вставлены в этот список. При этом имя XLM файла задается относительно текущего XML, а имена файлов в новом XML - относительно его самого Таким образом можно импортировать файлы из других проектов.
files
- объединяет группу файлов с одинаковыми параметрами dir и dstdir, а также служит ограничителем области видимости тегов var и remove.
dir - каталог, откуда будут браться файлы, dstdir - куда они будут помещаться.
name - имя группы файлов. Эту группу можно исключить по имени тегом remove.
depend - маски файлов через ";", по которым определяется максимальное время модификации, или
depend='{время}' - явно указанное время. Все фалы билда, время модификации которых менее заданного, будут пересобраны
file
- маска файлов, с которыми будет проводится "выполнение" препроцессором. Каталог перед именем файла означает, что в каталоги билда будет создана такая же структура. Кстати, здесь могут быть заданы свои параметры dir и dstdir, которые перекрывают параметры "верхнего" уровня. В дополнение может быть задан параметр name - имя файла, в который будет копироваться исходный
<files dstdir="$dst" dir="../debug/debug">
<copy>Debug/HackerConsole/*.*</copy>
</files>
этот кусок, к примеру, означает, что все файлы ../debug/debug/Debug/HackerConsole/*.*
будут размещены в каталоге
$dst/Debug/HackerConsole
<file name=".htaccess">htaccess.txt</file>
означает, что файл htaccess.txt будет помещен в нужный каталог под именем .htaccess. (одна из причин такого переименования та, что Eclipse не любил показывать файлы с точкой в начале имени в списке файлов проекта, к тому же для локальной отладки файлов проекта встроенным сервером, такой файл может мешать нормальной работе.).
$dst
- переменная, которая задается в командной строке.
copy
- все файлы, подходящие под маску будут просто скопированы в каталог назначения без eval'а с теми же правилами по поводу каталогов.
echo
- весь текст внутри тега воспринимается как содержимое файла. Если необходимо записать содержимое в файл, нужно ставить параметр NAME.
<files dstdir="$dst">
<echo name="readme.txt"><![CDATA[<%=point('readme','wiki_txt');%>]]></echo>
</files>
remove
- выкидывает из сформированного списка файлы по маске. при этом выкидываются файлы по "исходному" имени. Следует понимать, что "сокращенное" имя при формировании пары "файл - место назначения", заменяется на полное имя до исходного файла. Файл, который попадает под маску "выкидывания" не выполняется. В качестве символов для маски используются
<remove>**/chat/*</remove>
- будут выкинуты все имена, находящиеся в каталоге chat. Например /project/version/chat/chat.php. но не /project/version/chat.php
<files name="tdd.debug.email_test">... </files>
<files name="debug.chat_debug">... </files>
...
<remove name="tdd.*"/>
выкинуть из списка файлы, описанные в группе. вместо имени может использоваться маска, которая будет применяться к именам групп файлов.
Если конструкция внутри тега remove начинается и заканчивается символом тильда ~, то она (конструкция) считается регулярным выражением и непосредственно применяется ко всем именам в парах.
область действия remove ограничена тегом files, в котором он описан. Если тег встречается вне тега files, функция применяется ко всему уже сформированному списку файлов. Список файлов заполняется последовательно, по мере чтения файла конфигурации, так что после remove можно опять вставить файлы, которые предыдущим правилом уже удалялись-вставлялись.
Отвлечемся теперь от всей этой мути и представим себе работающий web-проект. Вообразим себе, что начальнику проекта приспичило вставить в проект фенечку, использующую диалоговое окошко, описанное в некоем плагине. Этот плагин предполагает, что будут добавлены некие стили в файл стилей, добавлена некая разметка в html файл, добавлены некие файлы в каталог проекта и изменен один или несколько javaScript файлов проекта. Если наша фенечка использует ajax, при этом возникнет желание поменять и php-файлы. Изменения каждый раз невелики, однако они размазаны по большому количеству файлов, уследить за ними даже с использованием системы контроля версий может быть непросто. Особенно страшно становится, когда начальник в творческих муках перебирает многие варианты таких фенечек от разных производителей.
Как наш новоявленный компилятор может облегчить нашу судьбу в этом случае? Легко!
Мысленно представим себе куда и как мы будем вставлять компоненты фенечки. В функцию, вызывающуюся в методе onload документа будет вставлен код инициализации фенечки. Вставим туда код
<%=POINT::get ('js_onload'); %>
В том же файле нам нужно описать поведение фенечки. Все это мы запихаем в область файла, в которой описываются все такие функции общего назначения
//<%=POINT::get ('js_body'); %>
В css файл мы будем добавлять некие стили. Туда запихаем:
<%=POINT::get ('css_styles'); %>
В html шаблон окна приложения нужно вставить заготовку диалогового окна. Туда поместим
<%=POINT::get ('html_body'); %>
Вот, вроде и все, если про ajax пока забыть…
А теперь, со всем этим хозяйством начнем взлетать. Соединим все конструктивные части фенечки в одном файле, однако разделим эти конструктивные части конструкциями POINT::start и POINT::finish.
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>fenechka module</title>
<script type=”text/javascript”>
<% POINT::start('js_body'); %>
function Fenechka(){
}
<% POINT::start('js_onload'); %>
Fenechka();
<% POINT::finish(); %>
</script>
<style type=”text/css”>
<% POINT::start('css_style'); %>
#fenechka { visible:none;}
<% POINT::finish(); %>
</style>
</head>
<body>
<% POINT::start('html_body'); %>
<div id="fenechka">Hello world!</div>
<% POINT::finish(); %>
</div>
</body>
</html>
При некоторой ловкости рук, файл с модулем может одновременно оказаться простой тестовой площадкой для проверки фенечки в отдельном окне. Впрочем, не в этом счастье.
Добавим строчку <file>fenechka.html</file>
в первый блок (без указания параметра dir, чтобы не произошло копирование самого файла) нашего файла конфигурации, откомпилируем проект и незамедлительно, после исправления совсем уж явных опечаток, случится чудо! Все необходимые части нашего нового функционала вставятся в правильные места нашего проекта. Если по какой-то причине использование фенечки не понравится заказчикам, чтобы убрать ее из проекта, достаточно выкинуть одну строку конфигурации.
Реализация механизма находится в файле point.ext.php исходника.
Запуск и использование препроцессора можно посмотреть в исходниках самого препроцессора. Готовые для исполнения файлы утилиты собраны с использованием самого препроцессора.
config.xml представляет собой пример файла конфигурации с достаточно навороченной структурой, который может служить отправной точкой для вашего собственного конфигурационного файла.
Запуск препроцессора может быть выполнен с помощью phing. Для этого в нужное место в каталоге дополнений phing нужно разместить содержимое каталога build/phing.
Можно пользоваться build.bat, который включен в проект. Нужно убедиться, что в нем корректно указан путь до php-интерпретатора.
Исходные тексты препроцессора находятся в каталоге src. Каталог build является результатом "препроцессинга" исходных файлов. В файлах выполняется внедрение версии в help - функцию, дополнение шапок в файлах и кое-что еще... Файл readme.txt и readme.html изготовлен из этого файла с использованием markdown-html и markdown-txt фильтров.
Для создания препроцессора использовался PHPstorm с Phing’ом и система с установленным TortoiseGIT что накладывает отпечаток на используемые инструменты.
Build.xlm
– make-файл для Phing’а. Он описывает пару макрокоманд – init – собственно вызов препроцессора и property – определение параметров + вызов утилиты SubWCRev для внедрения номера ревизии SVN в текст.
Config.xml
– файл конфигурации препроцессора, список файлов проекта
preprocessor.php
- главный файл, анализ командной строки и вызов препроцессора
preprocessor.class.php
- класс с методами препроцессора - сборка и хранение пар Source-Destination, исполнение файла препроцессором, собственно чтение и анализ файла конфигурации.
point.ext.php
- набор функций, для реализации MACRO-OOP.
wiki.ext.php
- класс для работы с wiki-разметкой. разметка сильно упрощенная, поддерживаться, вероятно, не будет. Пользуйтесь Markdown разметкой.
markdown.filter\*.*
- набор фильтров для обслуживания markdown разметки. Сейчас используется оригинальный markdown от John Gruber http://daringfireball.net/projects/markdown/ , но в планах заменить его на свой.
Все файлы обрабатываются в порядке их перечисления в файле config.xml. Все встретившиеся в тексте описания переменных-макрокоманд будут видны во всех файлах, обрабатываемых после первого их описания.
Например список файлов включает описание css файла с текстом
/*<%
if(!function_exists('rgb')){
// r,g,b => #rrggbb
function rgb($r,$g,$b){
$res='#';
foreach(array($r,$g,$b) as $v) $res.=str_pad(dechex($v),'0',STR_PAD_LEFT);
return $res;
}
}
$gray =rgb(99,100,102);
$lgray =rgb(217,220,227);
$red = rgb(152,27,30) ;
$textlink = rgb(97,134,186);
%> */
body {
color: <%=gray%>;
}
Во всех файлах, включенных после этого файла, можно пользоваться описанными макрами $gray, $lgray, $red, $textlink.
Для вывода какой-либо информации в окно, нужно пользоваться функцией preprocessor::log
или $this->log
. Первый параметр - уровень вывода, если не было никаких дополнительных настроек, то можно указать 2. Остальные параметры можно указывать через запятую не смотря на тип. Для массивов и объектов будет применяться print_r автоматически.
0-ошибка, 1-warning, 2-info, 3-замечание, 4-отладка. По умолчанию включен уровень 2.
При включении некоторых утилит может внезапно понадобится включить в набор файлов какие-то дополнительные. Это можно делать, используя функцию xml_read. $this в контексте макрокоманд всегда указывает на $preprocessor
/*<%
$this->xml_read('
<config>
<files dstdir="$dst/plugins" dir="../..">
<files dir="templater">
<file>template_parser.class.php</file>
<file>compiler.class.php</file>
<file>compiler.php.php</file>
</files>
<files dir="nat2php">
<file>nat2php.class.php</file>
</files>
<files dir="templater/templates">
<file>tpl_base.php</file>
<file>tpl_compiler.php</file>
</files>
</files>
</config>
');
%>*/
Включаемые файлы будут располагаться после всех файлов, добавленных в config.xml. Обрамляющий тег files содержит информацию о размещении готовых файлов и смещении "текущего каталога" для поиска файлов. Относительные пути считаются от файла, где содержится этот текст.
Таким образом, системные плагины могут вставляться одной строчкой в config.xml
фильтры при использовании POINT::get могут быть
comment
- фильтр обеспечивает вставку содержимого в окружении комментариев. При этом происходит автоопределение используемых комментариев и стиля. Фильтр является автоопределителем для целого пучка фильтров
line_comment
- в текущую позицию выводится имя точки вставки. Вставка содержимого происходит с новой строкиeveryline_comment
- каждая строка содержимого сопровождается комментарием //
tplcomment
- то же для комментария ##
jscomment
- каждая строка сопровождается символом *
php_comment
- закрываем комментарий */
, выводим содержимое на новой строке и открываем комментарий /*
html2js
- вывод HTML содержимого в строку JavaScript. Можно использовать в том числе и для PHP, но, в этом случае, строку необходимо поместить в двойные кавычки и осторожно обращаться с символом $( если подразумевается jQuery, можно оставлять пробел после $, или заменить его на jQuery
)
css2js
- вывод текста на CSS в строку JavaScript.markdown-html
- вывод markdown - разметки в виде HTMLmarkdown-txt
- вывод markdown - разметки в текстовом виде. С выравниванием по 70 символов в строке.при работе с файлами, содержащими русские буквы (актуально для Windows) используется перекодирование в UTF из системной кодировки. Указанные маски для файлов в XML файле вводятся в UTF-8 кодировке, они автоматически конвертируются в системную. При выводе в консоль используется кодировка UTF-8, для совместимости с PHPStorm. Однако, для комфортного использования препроцессора в батниках, возможно использование системной консольной кодировки. Для этого необходимо определить переменную SYS_CONSOLE
set SYS_CONSOLE=true
call z:\usr\local\php5\pear\phing.bat
В некоторых случаях, файлы, указанные в config.xml, упорно не попадют в сборку. Метод внимательного просмотра кода тоже не выявляет ошибки.
В этом случае оможет "отладка файла конфигурации". Запустить скрипт в режиме отладки просто. Нужно указать уровень выдачи диагностических сообщений. Для запуска из build.xml - PHING'овского файла, указать level=debug
как параметр задачи preprocess.
Вот рецепт, которым я сам пользовался для SVN.
для начала необходимо вставить в каждый файл "заготовку" шапки
/**
* Some words about file in project
*
* <%=POINT::get('hat','comment');
%>
*/
Обратите внимание, что после POINT::get(...); пропущены строки! Дело в том, что шапка занимает в получившемся файле несколько строк, так что сообщения об ошибках и варнингах окажутся смещенными на эти несколько строк в бOльшую сторону. Чтобы это не раздражало - не помешает добавить несколько пустых строк.
добавить конструирование шапки в config.xml проекта вот так
<var name="version">PHP Preprocessor, written by Ksnk (sergekoriakin@gmail.com)</var>
<var name="license">License MIT - Serge Koriakin - Jule 2010-2012</var>
<import name="git.hat.xml"/>
в файле git.hat.xml
конструируется шапка в зависимости от установленной системы контроля версий. Для SVN требуется установить command-line утилиту SVN
, так как стандартная установка TortuesSVN не устанавливает ее по умолчанию. То же самое с GIT
. Желательно, чтобы эти утилиты были в переменной окружения PATH, иначе придется править команду запуска в файле git.hat.xml
.
Внешний вид вставляемой шапки также определяется внутри файла git.hat.xml
.
Если вы пользовались предыдущим рецептом со вставкой шапки, у вас должны быть проинициализированные переменные $version и $tag или $svn_revision, так что после
define('VERSION',"<%=$trim($version).', ',$tag;%>");
у вас получится достаточно удобная, в некоторых отношениях, строчка с номером версии.
Существующая схема доводки таких случаев предполагает, что отдаваемый HTML кусок будет вставлен прямо в строковую константу. К сожалению при этом сильно затруднена отладка и просмотр получившейся конструкции.
Можно хранить все такие кусочки в отдельном файле template.html
<html><head><title> Debug pane</title></head>
<body>
<% POINT::start('html1') %>
<div id="xxx"></div>
<% POINT::finish('html1') %>
</body>
</html>
при этом файл можно редактировать html-редактором и смотреть в броузере, Если добавить туда нужные стили и скрипты, несложно отладить поведение и внешний вид.
в файл config.xml добавить секцию
<files>
<file>template.html</file>
</files>
в том месте, где находится обработчик AJAX, непосредственно отвечающий за отдачу клиенту строковой конструкции, пишем
echo json_decode("<%=POINT::get('html1','html2js')%>");
При этом, в строковом изображении HTML будут удалены комментарии, удалены лишние пробелы. В Javascript и style секциях, если они есть, также будут удалены комментарии.
Если некоторый файл не пришло еще время оформлять как плагин, а пользоваться им уже хочется, можно сделать так:
файл site.css
/*
<% POINT::file('css_site','../common/regedit.css');
%>
*/
...
/* <% POINT::get("css_site"); %> */
...
в файле config.xml нужно в секции, которая отвечает за генерацию нужного файла поставить параметр depend
. Тогда при изменении зависимого файла будет автоматически перегенерироваться основной.
...
<file depend="common/*.css">css/*.*</file>
...
При генерации текстов препроцессором автоматически удаляются пустые теги-комментарии ? если внутри только пробельные символы. Так что теги препроцессора можно вставлять прямо в
/* ... */
комментариях. В некоторых случаях нужно, чтобы тег выводил значение в текст
/* <%=POINT::get('mypoint');%>*/
При этом будет обнаружено, что точка вставки располагается в комментариях и к этому комментарию будет автоматически сгенерирован закрывающий тег. После окончания вывода будет сгенерирован открывающий тег.
Можно использовать вставки кода препроцессора в комментариях другого вида
// <%=POINT::get('mypoint');%>
## <%=POINT::get('mypoint');%>
Во всех этих случаях препроцессор обнаружит строковые комментарии и выведет текст на следующей строке. Хотя такие комментарии не удаляются автоматически.
Можно готовить внутреннюю документацию в виде markdown разметки. Синтаксис markdown достаточно прост, но, тем не менее, хорошо подходит для документирования небольших проектов.
Дополнительным бонусом оказывается то, что markdown является одним из языков разметки, автоматически обрабатываемых github'ом.
Принцип построения документации может быть таким:
основной документ выполняется в виде файла с именем readme.markdown в корне проекта. При этом, в случае размещении проекта на github, сразу получается достаточно приличная страничка с описанием проекта.
для конструирования txt и html документов нужно добавить в config.xml секцию
<files dstdir="$dst">
<echo name="readme.txt" depend="readme.markdown">
<![CDATA[<% POINT::inline('readme','readme.markdown');
echo POINT::get('readme','markdown-txt')
%>]]>
</echo>
<echo name="readme.html" depend="readme.markdown">
<![CDATA[<% echo '<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head><body>'
.POINT::get('readme','markdown-html').'</body></html>';%>]]>
</echo>
</files>
пользуйтесь фильтром 'comment' при вставке. Предположим, что в текст нужно вставить двухстрочный текст.
Часть проекта ABCDEFG,
Copyright (c) XXXX
Фильтр позволяет распознать место, в которое делается попытка вставить текст и определить как его нужно оформлять.
комментарии // - большинство языков
// <%=POINT::get('mypoint','comment');%>
получится
// Часть проекта ABCDEFG,
// Copyright (c) XXXX
комментарии ## - язык шаблонов, основанный на Django-шаблонах
## <%=POINT::get('mypoint','comment');%>
## Часть проекта ABCDEFG,
## Copyright (c) XXXX
многострочный комментарий /* ... */ каждая новая строчка вставляемого текста будет снабжена соответствующим комментарием
/**
* <%=POINT::get('mypoint','comment');%>
*/
каждая новая строчка текста будет снабжена * в нужной позиции.
/**
* Часть проекта ABCDEFG,
* Copyright (c) XXXX
*/
Для PHING можно указать текст конфигурации прямо в задаче. Примерно так
<target name="test captcha" description="build project">
<preprocess force="force">
<config><![CDATA[
<files dir="plugins/captcha" dstdir="$dst">
<file name=".htaccess">.htaccess.sample</file>
<file>captcha.new.php</file>
<file>captcha.test.php</file>
<copy>*.ttf</copy>
</files>
]]></config>
<param name="dst_dir" value="/calc/test.captcha"/>
<param name="dst" value="z:/home/localhost/www/calc/test.captcha"/>
</preprocess>
</target>
В конец файла вставляем что-то вроде вот такого
/************************************************************************************
*
* <% if($target!='allinone')
POINT::file('license','mit.licence.ru.txt');
else
POINT::inline('license','# License agreement
follow <http://www.gnu.org/copyleft/lesser.html> to see a complete text of license');
echo POINT::get('license','markdown-txt|comment') ;
%> ***********************************************************************************
*/
Как можно заметить, заполнение точки хранения лицензии можно произвести из файла или непосредственно в тексте. Вывод точки проходит через фильтры markdown-txt
- преобразует markdown - разметку в текстовый формат с выравниванием по 70 литер в строке. Затем - фильтр comment
добавляет комментарии перед каждой новой строкой. Выглядит достаточно стильно.
/************************************************************************************
*
* Лицензионное соглашение.
* ========================
*
* Copyright (c) 2012 Serge Koriakin <sergekoriakin@gmail.com>
*
* Данная лицензия разрешает лицам, получившим копию данного программного
* обеспечения и сопутствующей документации (в дальнейшем именуемыми «Программное
...
* ТPЕБОВАНИЙ ПО ДЕЙСТВУЮЩИМ КОНТPАКТАМ, ДЕЛИКТАМ ИЛИ ИНОМУ, ВОЗНИКШИМ ИЗ, ИМЕЮЩИМ
* ПPИЧИНОЙ ИЛИ СВЯЗАННЫМ С ПPОГPАММНЫМ ОБЕСПЕЧЕНИЕМ ИЛИ ИСПОЛЬЗОВАНИЕМ
* ПPОГPАММНОГО ОБЕСПЕЧЕНИЯ ИЛИ ИНЫМИ ДЕЙСТВИЯМИ С ПPОГPАММНЫМ ОБЕСПЕЧЕНИЕМ.
*
*
***********************************************************************************
*/