четверг, 26 ноября 2009 г.

Perl :: Структуры данных :: Переменная :: Объявление переменной

В арсенале Perl имеется достаточно широкий набор приёмов, которые могут использоваться разработчиком при создании переменных там, где это необходимо в данный момент; однако за это, как, впрочем, и за всё остальное в этой жизни, программисту приходится платить, а здесь начинается та часть, где надо быть особенно внимательным. Данный язык программирования, в самом деле, может облегчить существование разработчика за счёт правильного использования специальных помощников ‘my’, ‘local’, ‘our’. Каждый из них по-своему может быть полезен, и сберечь массу времени при отладке готовых программ, не говоря о том, что можно (и должно) использовать их "врождённые" свойства, которые не надо "программировать" самому, поскольку создатели языка об этом уже позаботились, а разработчику надо всего лишь уметь правильно ими пользоваться.

Главным в работе с переменными, равно как и со всеми другими имеющимися типами данных языка, является так называемая "область видимости" переменной. Существует несколько простых правил на сей счёт:
  • когда программа может использовать несколько одноимённых (но не равных по значению в каждый конкретный момент времени) переменных, в языке существует встроенный механизм "отслеживания" и использования переменных с одинаковыми именами и в разных областях видимости (или блоках), который реализован путём объявления переменной с помощью ‘our’; можно сказать, что в данном случае происходит автоматическое "переопределение" значений переменной по ходу всей программы;

  • когда же разработчику необходимо каждый раз в пределах какого-либо блока использовать переменную с одним и тем же именем, но с абсолютно "чистым" начальным значением, то, как правило, (и до возникновения ‘our’) используется ‘my’;

  • в случае же когда программист хочет очень жёстко "привязать" само существование конкретной переменной в пределах одного блока кода и напрочь "забыть" о том, что она когда-то существовала после выхода из него, у него всегда имеется ‘local’ для этого.
Подобно многим другим языкам программирования объявление переменной может происходить как с присваиванием ей начального значения, так и без оного, например: 'my $var=1;', где между переменной и её значением находится оператор присваивания (пожалуйста, не путайте его со знаком «тождественно равно» ‘==’). Существуют также иные способы присваивания значений переменным, но об этом не здесь и не сейчас.

Если читатель считает необходимым освежить свои знания по переменным, то раздел стандартной документации 'perldoc perlvar' всегда к Вашим услугам; или же зайдите на любое из зеркал CPAN.org, чтобы найти нужный Вам раздел документации.

вторник, 24 ноября 2009 г.

Perl :: Data Structures :: Scalar :: Perl scalar value

First, Perl uses the special mark to designate a scalar variable and it is '$' (dollar sign). As the Perl father says, he has picked this one just because it looks like 's' that can stand for 'scalar' and it comes handy indeed. But, on the other hand, recalling Larry Wall's linguistic background it is in place to say that 's' may stand for 'singular', too. This is especially important to keep in mind, when one is using it in Perl scripting as any scalar variable in Perl can keep only 'single' value. The real thing about everything in Perl lies near the context, which may make one 'miserable' unless one knows what the context in Perl is.

One more general thing about variable names in Perl, starting not so long before, unlike in many other languages the programmer can give names to his babies and beasts in his native language belonging to, say, Slavonic, Sino-Tibetian, Judaeo-German or any other family. Here are our special thanks to the Unicode team. It does not make much from efficacy point of view, but adds a lot to the readability of the source code.

The Perl scalars may look like '$var', and all; or, if one prefers Chinese flavour, he might write something like this: $輕 (qìng - easy, light).

FYI: (%perldoc) perldata - Perl data types

пятница, 13 ноября 2009 г.

Perl :: Структуры данных :: Переменная :: Значение переменной

Во-первых, как всем наверное известно, для обозначения переменной в Perl используется знак доллара ‘$’. Согласно создателю этого языка он выбрал такое обозначение, так как оно очень похоже на латинскую букву ‘S’ и очень подходит для мнемонического обозначения слова ‘scalar’ (скаляр). С другой стороны, памятуя лингвистическое прошлое г-на Волла уместно предположить, что ‘S’ может относиться и к слову ‘single’ (один, единственный).

Это становится актуальным, когда надо запомнить, что в Perl скалярный контекст соотносят с переменной, то есть, скаляром. По большому счёту всё, что надо знать в данном языке (или почти всё) вращается вокруг контекста, что может стать камнем преткновения для любого программиста.

Ещё одно замечание в отношении имён переменных в Perl: не так давно и совсем не так как во многих других языках программирования стало возможным называть переменные практически на любом языке (речь не идёт о транслитерации): язык, который имеет письменность и представлен в наборе символов Юникода может принадлежать к Индо-Европейской, Сино-Тибетской, Романо-Германской или любой другой семье языков.

Переменная может выглядеть как ‘$var’ в традиционном представлении или же если есть необходимость представления имени переменной, скажем, на китайском, то это может быть нечто наподобие $輕 (qìng - лёгкий, легко).

FYI: (%perldoc) perldata - Perl data types

понедельник, 2 ноября 2009 г.

Perl :: Myths and reality of HTML::Mason

What everyone knows


For those, who himself even had never dealt with Perl the very words HTML::Mason are hardly unfamiliar; and CPAN might be a source for either admiration or envy. Among the tremendous number of library modules, HTML::Mason could survive a row of releases of his own and got qualified as entirely professional web-development environment. Though one can narrate a lot on what exactly it is, but if in the course of conversation they utter ‘HTML::Mason’ occasionally, the sharp rejoinders like “well, it’s a mod_perl’s only” aren’t rare. It’s well-known that the module was designed and developed with this Apache web-server extension in mind, however, far not all modules presented at CPAN can (at least in their pods) make a brilliant display of flexible features. In here we’re going to talk how to ‘cut the coat according to the cloth’, that is how to use available things at hand and produce good enough and practical applications.

Perhaps, there are not so many brave heads can claim they used HTML::Mason in full and without mod_perl+Apache out there; much as well as this, and what the reader might know, is possible with the module. But in our case we’re going to solve a bit different problem and that is how to put in use all HTML::Mason power when one has got an ordinary web-hosting, offering the old good CGI.pm.

 

What Mr. Rolsky is silent about


Despite HTML::Mason possesses an excellent set of docs and examples for virtually any option possible, the real life shows that by intent or not (and there are numerous graphic evidences of that on the Internet) it lacks for CGI use a lot. No secret that anybody, who ever tried to dive into the problem made their first stop at HTML::Mason, HTML::Mason::Admin, HTML::Mason::CGIHandler and the rest. Well, more often than not they skipped to something else or ... whatever, as those guys once faced this wall obviously never ever got back again. And pitiful are they! The lines authors do not reproach HTML::Mason’s developers with this notice, but still it could be better to shed more light in this respect for the uninitiated.
Thus, what does the standard documents of HTML::Mason offer, when there is no way to use mod_perl? First, all the options are cut to two as a matter of fact.

The option using HTML::Mason within a stand-alone (and baked) cgi-script from the very beginning, if even to omit the scape and scope and scalability and usability, will bring to naught all the mighty of Mason in its components interoperability and interchangeability, and, say, for system administrators templates are excessive as the standard Perl’s features are more than enough. To be short, this variant makes a developer to say good-bye to any template system and the most unfortunate is to the Mason’s ability ‘to bind’ components dynamically.

The next option is pointing to incomplete emulation mode, where HTML::Mason is working in CGI environment via HTML::Mason::CGIHandler. As the Mason developers say it’s a poor man’s option that can re-produce just a few features of what Mason can in mod_perl mode. And that is true. The question ‘does anyone need this?’ is out of place here; on the other hand, is it good to start anything what is of no interest to finish is open yet.

 

How much and what for


The invention history is redundant in examples born right in between two or more technologies or techniques or just notions. Fortunately, HTML::Mason is not an exception. Those, who knows something on the Internet history, the history of CGI might be a good example. The protocol could meet almost all existing earlier needs for client-server communication. But the time passes by and the people are acquiring more sophisticated toys.

The old story on how hard for a web-designer to understand problems of a web-developer seems getting shabby since the world saw various CMS and the like. Nevertheless, as usual in the first place (but may be not so usual) the choice of platform arises. If one tries to compile the list of hosting providers offering mod_perl feature, he might be disappointed to learn how much that costs and how few are those who can offer the feature indeed. They state many reasons to excuse the price and the main of their own is support; which we cannot accept though. That is why we are turning back to what is offered here and there, to CGI.pm plus a set of standard features and for free, almost. In case they don’t have HTML::Mason installed they can do that easily, that’s not a problem, all the problems are just one step ahead, namely, when a happy developer with his home-grown project will try to deploy it at the hosting.

For the languished readers it is worthy to say that the starting point is the creation of cgi-handler, that is the script which is channeling all ins and outs, coming form CGI environment and going back, to HTML::Mason for processing. Till now everything is more or less clear; this is the turn of auto- and dhandler. Technically, these are common in shape and contents, but due to the difference between %ENV of CGI and %ARGS of Mason (and these two are really different, not only in names, but also in what they can be containers for) it is strongly recommended to inform HTML::Mason where to obtain the environment variables.

 

The theory smelling


In theory, or to be more precise in the documentation, they say that autohandler is triggered and executed right before everything else and this is true always; on the other hand, dhandler does … well, everyone knows how it works. But this makes a big difference when transferred into CGI environment. Dlhandler under such conditions, if one follows the Mason docs, is not working as needed; well, autohandler is still there! What’s wrong?

The question is how to turn on dhandler forcibly, that is how to make it CGI-aware. The example we placed below might be far from perfect, however, if the service has no heavy load of simultaneous and/or concurrent requests it performs well. Here is the recipe:

#!/usr/bin/perl
# File: mason_handler.cgi ( cgi handler to process, auto-, dhandler )
use HTML::Mason::CGIHandler;
use lib '/path/to/lib ';  # absolute path to your lib
use YourModule1;    
use YourModule2;    
use utf8;

# we DO call dhandler explicitly
$ENV{PATH_INFO} = '/path/to/DocumentRoot/dhandler';

my $h = HTML::Mason::CGIHandler->new(
  data_dir   => '/path/to/mason data dir',
  comp_root => '/path/to/component/root',
  allow_globals => [qw($globalscalar)],
);

$h->handle_request;

 

What else should be said about HTML::Mason


This section is a sort of obligation, or, may be, just a compulsory piece of a development inventory, especially needed for those dealing with non-English web-resources and aware about consequences of ‘use utf8’ usage within HTML::Mason.

All-known UTF-8 is getting more and more common on the Web. The standard Perl documentation says about built-in classes like “\p{InBasinLatin}”, “\p{InCyrillic}” and so on; those when used together, for example, with ‘qr()’ may, and really are, the powerful tools. Also let’s bring forward the old ‘quotemeta()’ that also may be of a good help yet; nonetheless, when it comes to use the like from inside HTML::Mason, not everything goes smoothly. Suppose, you’ve got a mysql table, which is queried exclusively with ‘SET NAMES utf8’ (so that mixed data make no noise) and which itself has ‘CHARSET=utf8 COLLATE=utf8_unicode_ci’ collation tags placed properly; next, somewhere in the UI form you must sift the user’s input with fascinating ‘s///go’ (needless to say all your pages are containing the valid XHTML with meta-tag ‘charset=utf-8’ or generated with HTML::Masonheaders_out()’), but the problem is still there as your regexp isn’t working properly! Again, as it is said in perldoc – ‘use utf8’ to rescue and place it right into the component… now, regular expression is alright, but the generated page content is odd a bit. Finally, you found Encode.pm with its “decode(), encode()” and feverishly started to “normalize” the utf8 input… it’s the same and not entirely what’s expected.

Sure, your own story may be a bit different, but the conventional morality is following:
all the data, corresponding UTF8, in the internal Perl representation almost always looks differently (and for Perl as well); the use of data presented in the way, well, they are looking correct in the browser, as well, to be fed to regular expressions; the latter, if they are well-formed, will process the data happily and supply the correct (read – expected) result. As to the rest of your precious resource, none of the beasts should be let out, otherwise, you’re in troubles: the explicit turning on UTF8 by any means and in any of the Mason processed components will result to the correct data display from this one and incorrect within the others.
The problem got the shape, but what’s the solution? It’s time to get back to the sources: they strongly advise to follow ‘divide-and-conquer strategy’; for the case it sounds like: all the routines requiring to process Unicode (utf8) data with Perl should reside in modules only, and none of those must be put inside a component; the same is true about the tools like Encode::encoded/decoded(“utf8”, $datum). This is one of the few limitations one should keep in mind while designing his/her HTML::Mason applications.

All the said above was ‘inside’, now we’re going to make a set of notes what’s ‘outside’. HTML::Mason, as the dear reader probably knows already, has some *escape* hooks; it is out of place to repeat the pods and instead we just recall few things like ‘|h’.

In fact if one has, say, an English site, then no worries; in case of otherwise, and if the developer has to use UTF8, the following bit of code may help to escape the user’s data properly. It happens, for instance, when there’s a UI html form; suppose a user has input the data mixed with markup, to avoid his own data to be treated as markup afterwards we do recommend to append to your code something like:

File name: autohandler
……
% $m->interp->set_escape( h => \&HTML::Mason::Escapes::basic_html_escape );
% $m->call_next();
……

file: 
……
<% $htmlstring | h %>
……

 

The whole thing sample


Finally, we’d like to illustrate what’s said with a plain example.
The example we’re creating a small site, containing the following:
  • perl module with DB interface;
  • autohandler and dhandler;
  • a set of components to construct the simple UI;
The reader will find the comments inside.

You can download the example here (~ 10 Kb).

вторник, 27 октября 2009 г.

Perl :: Мифы и реальность с HTML::Mason

То, что знают все


Для людей, которые даже никогда сами не имели в своей программерской практике никакого опыта с Perl само слово HTML::Mason может быть не ново, а сам CPAN может вызывать равно как и зависть, так и восторг. Среди огромного количестве библиотечных модулей данного репозитория, HTML::Mason уже смог выдержать ряд релизов и квалифицироваться не иначе как профессиональная среда разработки веб-ресурсов. Впрочем, можно долго рассуждать на тему того, что именно представляет из себя это явление, но вот с чем приходилось сталкиваться чаще всего, когда произносилось слово “HTML::Mason”, так это что-то типа: «ну, так без mod_perl это никак!».

Никто и не скрывает, что данная библиотека и разрабатывалась с этим расширением веб-сервера Apache в голове; но далеко не все из библиотек, которые присутствуют на CPAN могут (хотя бы в части pod) «похвастаться» таким разнообразием возможных применений; здесь речь пойдёт о том, как «по одёжке – протягивать ножки», а точнее, как можно используя то, что доступно и под рукой, делать достаточно хорошие и надёжные вещи.

Наверное, найдётся далеко немного людей, которые могут с гордостью сказать, что вот там-то и там-то они использовали HTML::Mason в полном объёме не только без mod_perl, но и без Apache; многое как и это, о чём Вы, наверняка знаете, тоже возможно с данной библиотекой. Однако в данном случае будет немного иная задача, а именно, как используя практически весь арсенал HTML::Mason заставить его работать на обычном сервере, где есть лишь старый, добрый CGI.pm.

 

О чём, «молчит» г-н Рольский

 

Несмотря на то, что в комплекте HTML::Mason имеется хороший набор документации и масса примеров практически «на все случаи жизни», практика показывает, что то ли умышленно, то ли нет (и этому существует масса свидетельств в интернете, к сожалению) в отношении CGI имеется там явный пробел. Разумеется, что все, кто когда-либо пытался решить подобную проблему сразу же обращались к HTML::Mason, HTML::Mason::Admin, HTML::Mason::CGIHandler и прочим вещам. И, наверное, большинство из этих смельчаков либо останавливало выбор на чём-то другом, либо... вообщем, это не важно уже сейчас, поскольку это «большинство» приобрёв некоторый печальный опыт «работы» с HTML::Mason, возможно, уже никогда более не обращало свой взор сюда снова. А жаль! Авторы этих строк никоим образом не ставят всё это в упрёк команде разработчиков HTML::Mason, но, наверное, всё же стоило пролить свет на возможности HTML::Mason в этом направлении для массы несведущих.

Итак, что же согласно стандартной документации предлагает данная библиотека всем тем, у кого нет возможности пользоваться всеми прелестями mod_perl? Сразу надо сказать, что вариантов не очень много и все они, как правило, сводятся к двум.
Вариант использования HTML::Mason в отдельно взятом (и сделанном) cgi-скрипте с самого начала, даже если не вдаваться в подробности возможной сферы применения, сводит на нет всю мощь HTML::Mason в части многократного использования в разных местах приложения одних и тех же компонент; а для системных администраторов шаблоны не нужны и вовсе – возможностей Perl хватает с головой. Если кратко, то этот вариант заставляет почти попрощаться с системой шаблонов и, что самое обидное, с тем механизмом, посредством которого они могут взаимодействовать!

Вариант второй указывает на незавершённую эмуляцию взаимодействия HTML::Mason с Apache API в виде HTML::Mason::CGIHandler. По словам самих разработчиков это лишь «жалкое подобие» того, что возможно в связке с mod_perl. И это действительно так. Вопрос «а надо ли это вообще?» авторами данных строк даже никогда не ставился, а вот стоит ли начинать то, что не очень хочется заканчивать, пока остаётся открытым.

 

Что по чём и зачем это надо

 

История открытий и изобретений пестрит примерами, которые родились на стыке двух или более технологий, или просто понятий. HTML::Mason, в этом смысле, не является исключением, к счастью. Для тех, кто или знаком с историей Интернета, или просто интересовался ею, должна быть известна история возникновения протокола CGI; который до известного времени удовлетворял всем известным ранее требованиям динамического взаимодействия клиента и сервера. Времена меняются – люди тоже, а вместе с ними и их «игрушки».

Старая сказка про то, что веб-дизайнер никогда не сможет понять веб-разработчика начала, кажется, уже устаревать, когда мир увидел всякого рода системы управления контентом, системы шаблонов и иже с ними. Но всегда и везде первым (хотя, впрочем, и не обязательно первым) встаёт вопрос о платформе. Итак, если побродить по бескрайним просторам Интернета, то краеугольным вопросом, в нашем случае, по-прежнему остаётся наличие mod_perl у провайдера. Для тех, кто когда-либо занимался подобным «изысканием» должно быть известно, что хостинг подобного рода далеко не копеечный и встречается далеко не везде.

Причин тому достаточно, но главная – в якобы дорогостоящем сопровождении данного вида хостинга, с чем мы не можем согласится (и у нас также есть достаточно причин для этого). Поэтому, возвращаемся к тому что может найтись практически везде – к CGI.pm со стандартными примочками и что стоит действительно копейки. HTML::Mason, если не установлен, то получить его на обычном хостинге не есть проблема; все проблемы возникают после того, как окрылённый обладатель готового сайта, который собран согласно документации и вроде бы работает «в домашних» условиях, попытается привинтить его на своем хосте у провайдера.

Чтобы не томить души страждущих, сразу надо сказать, что отправной точкой является наличие cgi-handler, т.е. скрипта, который «пропускает» через себя все запросы проходящие через CGI окружение и перенаправляет их к HTML::Mason для дальнейшей работы. До сих пор вроде бы всё ясно; теперь несколько замечаний о святая-святых HTML::Mason, а именно об auto- и dhandler.

В общем и целом, их работа (равно как и содержимое) неизменны, но поскольку то, что в CGI называется %ENV, а в HTML::Mason - %ARGS (а оно не только называется, но и в самом деле суть две большие разницы) является универсальными контейнерами для обмена данными через переменные окружения (а, как известно mod_perl очень плотно трётся с Apache, а не с CGI, что и выросло у HTML::Mason), то неплохо было бы сказать HTML::Mason откуда их брать, не так ли?

 

Теория, которая витает в воздухе

 

В теории, или точнее в документации, говорится, что autohandler срабатывает прежде всего другого и всегда, а dhandler только в случае... ну, вообщем, это известно всем. Как оказывается на практике, в CGI окружении поведение этих рабочих лошадок HTML::Mason несколько иное. Оказывается, что в таких условиях dhandler, если всё оставить согласно документации, просто не срабатывает тогда, когда надо; хотя autohandler работает без проблем.

В чём же дело? Собака зарыта в том, как принудительно завести dhandler; это значит, каким образом «вкинуть» его в CGI. Несмотря на то, что данный пример такого проброса не претендует на звание идеального, но там, где не требуется обработка 1000 одновременных запросов, он справляется вполне достойно. Вот рецепт:

#!/usr/bin/perl
#Файл: mason_handler.cgi ( cgi handler для обработки компонент, auto-, dhandler’a )
use HTML::Mason::CGIHandler;
use lib '/path/to/lib ';  # Абсолютный путь к библиотекам Ваших модулей
use YourModule1;    # Ваш модуль1
use YourModule2;    # Ваш модуль2
use utf8;

# Установка для принудительного вызова dhandler
$ENV{PATH_INFO} = '/path/to/DocumentRoot/dhandler';

my $h = HTML::Mason::CGIHandler->new(
  data_dir   => '/path/to/mason data dir',
  comp_root => '/path/to/component/root',
  allow_globals => [qw($globalscalar)],
);

$h->handle_request;


Что ещё надо было бы сказать про HTML::Mason

 

Данный раздел помещён здесь далеко не случайно, а скорее как «крик души». Наверное, многие разработчики, которые имеют работы с неанглоязычными данными сталкивались с различного рода казусами ввода-вывода и последующего отображения языков, отличных от английского.
Начнём с классики, которая в данном случае представляется UTF-8. В теории (perlunicode, etc) говорится о встроенных классах символов типа “\p{InBasinLatin}”, “\p{InCyrillic}” и так далее, которые в связке с оператором ‘qr()’ могут, и действительно делают, чудеса. Также нелишним будет вспомнить и старушку ‘quotemeta()’, которая и сейчас бывает полезной; однако, когда дело доходит до использования всего этого добра в HTML::Mason, то всё оказывается не так гладко.

Приведём пример: у вас есть таблица mysql, которую вы используюте исключительно с ‘SET NAMES utf8’ (ну, чтобы попроще было со смешанными текстами и сборными страницами) и которая также сама имеет там, где надо ‘CHARSET=utf8 COLLATE=utf8_unicode_ci’; затем, вам где-то в форме у пользователя надо бы «почистить» ввод с помощью всеми любимой ‘s///go’ (само собой разумеется, что у вас все страницы содержат валидный XHTML с мета-тэгом ‘charset=utf-8’, указанным явно или через ‘headers_out()’ от HTML::Mason), но почему-то «очистка» не работает как надо! Вы лихорадочно пытаетесь задействовать, опять же согласно стандартной документации Perl, до боли знакомую прагму ‘utf8’ прямо в компоненте... теперь с регулярными выражениями всё, кажется, в порядке, но при этом как-то странно выглядит контент на сборной странице. Вот вроде бы появился свет в конце туннеля, вы «находите» спасительный модуль Encode с его “decode(), encode()” и пытаетесь «нормализовать» входные данные, поступающие прямо из формы... Результат тот же, и не тот, что надо.

Возможно, ваша собственная история несколько иная, но мораль сей байки такова: все данные, которые соответствуют UTF8, во внутреннем представлении Perl практически всегда отличаются от приходящих из интерфейса; единственное назначение такой формы данных, хотя справедливости ради надо сказать, что они вполне пригодны для отображения в браузере, это скармливание их регулярным выражениям, которые, в свою очередь, если составлены верно, с радостью их обработают в таком виде и выдадут вам правильный (читай – ожидаемый) результат. Во всех же остальных местах вашего драгоценного ресурса их никогда нельзя выпускать «на волю», в противном случае, будет беда: явное включение UTF8 каким-либо образом хотя бы в одной из компонент HTML::Mason приводит к тому, что данные из этой компоненты отображаются правильно, а все остальные, как в нашем случае со сборной страницей, будет «не так».

Проблема обрела форму, но где же решение? Здесь также нелишне вернуться к первоисточникам: там настоятельно советуют следовать старому принципу – «разделяй и властвуй», что в применении к настоящей проблеме можно перефразировать следующим образом. Все процедуры, которые требуют сугубо юникодовской трактовки данных при обработке исключительно средствами языка Perl, должны находиться только в модулях, а не в компонентах; там же можно использовать инструменты, подобные Encode::encoded/decoded(“uf8”, $datum). Это одно из, слава нашему Богу, немногих ограничений при планировании приложений, разрабатываемых с помощью HTML::Mason.

Это всё было «внутри», теперь же несколько слов про то, что возможно сделать «снаружи». В HTML::Mason имеются встроенные *escape* функции; не стоит, наверное, цитировать авторов, надо лишь сделать несколько замечаний относительно вещей, подобных ‘|h’.
На самом деле, если у Вас англоязычный ресурс, то повода для беспокойств нет. Однако в противном случае, если Вы используете кодировку unicode (utf8), следующий код поможет решить проблему с организацией литерального представления данных пользователя. Это нужно, например, тогда, когда на Вашем ресурсе пользователи осуществляют ввод посредством html form. Если пользователи введут данные вместе с HTML – тэгами, тогда при отображении этих данных, чтобы не нарушился интерфейс ресурса нелишним будет следующее:

Файл: autohandler
……
% $m->interp->set_escape( h => \&HTML::Mason::Escapes::basic_html_escape );
% $m->call_next();
……

Файл: <Ваша компонента>
……
<% $htmlstring | h %>
……

Пример сборки ресурса

 

Здесь мы хотели бы проиллюстрировать на простом примере всё, о чём было сказано выше.
В данном примере мы создаём небольшой ресурс, составными частями которого будут:
  • модуль, основным назначением которого будет сопряжение с БД;
  • autohandler и dhandler
  • набор компонент для сборки нехитрого интерфейса.
Замечания и комментарии будут даваться по ходу представления исходного кода ресурса.
Пример приложения можно скачать здесь (~ 10 Kb).

понедельник, 26 октября 2009 г.

Perl :: Unicode and regular expressions

To paraphrase a famous French thinker and in connection to Perl it is trustworthy to say: "If there would not exist regular expressions, there would not be Perl". Perhaps, Larry Wall would disagree, but none could neglect the importance of regular expressions for Perl mongers (or, may be, vice versa); anyway, it is not almost possible to find a perl programmer who does not use regexp ever (otherwise, the one does not use Perl at all, we suppose).

There is a huge lot of data on Perl's regular expressions out there, but of course the real leader is 'Mastering Regular Expressions' by J. Friedl, worthy to read, worthy to disagree and, after all, worthy to learn. The issues we're going in for here are covering to some extent Unicode and how Perl's regexp can help in handling something with it.

FYI: perldoc perlunicode - Perl Unicode support

To do one's homework the right way, he has to get some confident understanding (based mostly on his own experience, of course) of how regular expressions work and especially the parts related to building regexp objects and the embedded code, that is during matching or substitution to dynamically execute some piece of Perl code inside m// or s///. It would be nice if the reader has gotten already some experience in Unicode and there won't be necessary to remind him that under 'use utf8' or 'use encoding "utf8"' pragmas it's almost always advisable to add one more - 'use re "eval"' so that to make any snippet within a regexp executable by perl interpreter. Nor to recall such Perl Unicode ABC notion like behaviour of '\w' in some home-grown alphanumeric class of symbols.

The last note right before the start: 'use locale', sure, puts the death shadow on the cross-platform design of your applications, especially when there's something like '\p{InCyrillic}' or '\p{InCJKCompatibilityIdeographs}' because beasts like these are getting extremely sensitive in regular expressions to locale settings and 'use bytes' and 'no bytes' contexts.
FYI: perldoc utf8 - Perl pragma to enable/disable UTF-8 (or UTF-EBCDIC) in source code
In order to do away with the introduction let's refresh a row of basic functions that can be of a good help in baking and stuffing some Unicodish frameworks:

#!/usr/bin/perl
use strict;
use encoding 'utf8';
our ( @packed, );
@packed = map{chr($_)} (0x4E00 .. 0x9FFF);
print $_, "\n" for @packed[0 .. 9];
exit(0);
this short and speedy 'CJK character generator' is able to give birth to more than 20 000 characters in no time, that one can find in Chinese, Japanese, Korean and, probably, in the old Vietnamese. The line:
@packed = map{chr($_)} (0x4E00 .. 0x9FFF);
may be seamlessly replaced with something like following:
@packed = map{pack 'U', $_} (0x4E00 .. 0x9FFF);

for this 'pack' and 'chr' are interchangable, no doubt.
Now let's do some matching job. The job should be effective enough without any temporary variables that take a significant piece of memory; in other words, we have to make use of Perl's built-ins. Again, let's take some Chinese string as a sample due to a good amount of Unicode codepoints devoted to this language:

#!/usr/bin/perl
use strict;
use utf8;
use encoding 'utf8';
our ( $re, $sample );
$re = qr{(
        [\p{InCJKUnifiedIdeographs}] |
        [\p{InCJKCompatibility}] |
        [\p{InCJKCompatibilityForms}] |
        [\p{InCJKRadicalsSupplement}] |
        [\p{InCJKCompatibilityIdeographsSupplement}] |
        [\p{InCJKUnifiedIdeographsExtensionA}] |
        [\p{InCJKCompatibilityIdeographs}] |
        [\p{InCJKUnifiedIdeographsExtensionB}])}ox;

$sample = '五行: 一曰水, 二曰火, 三曰木, 四曰金, 五曰土 
  пять стихий: первая называется вода, 
  вторая — огонь, третья — дерево, 
  четвёртая — металл, 
  пятая — земля Five Elements: first is Water, 
  second is Fire, third is Wood, fourth is Metal, fifth is Earth';
while($sample =~ m/$re/g)
{
    print $1,"\n";
}
exit(0);

As one can see the sample consists of three languages, from which Perl carefully has chosen, one by one, (as it was said to him) those of CJK family. For those who has forgotten what kind of Latin bull is placed right after '$re' regexp object, we advise to go to 'perldoc perlre' listed in Perl pod; and for those Perl critters, who likes to know everything about anything we've got few questions: (1) where did Perl get the value for '$1' variable? (2) what's the difference between 'use utf8' and 'use encoding "utf8"'? (actually, why both of them are here?!) (3) why 'ox' and 'g' regexp modifiers are separated here? In case you've got all answers ready at once, you're the best!

It is the right time to bring in more dynamical pictures, that is, to breathe some spirit into regular expressions. Check this:

#!/usr/bin/perl
use strict;
use utf8;
use encoding 'utf8';
use re 'eval';
our ( $re, $index, $num, $line, $key1, 
                                $key2, @estimate, @over, @under, %got, );
$re = qr{(
        [\p{InCJKUnifiedIdeographs}] |
        [\p{InCJKCompatibility}] |
        [\p{InCJKCompatibilityForms}] |
        [\p{InCJKRadicalsSupplement}] |
        [\p{InCJKCompatibilityIdeographsSupplement}] |
        [\p{InCJKUnifiedIdeographsExtensionA}] |
        [\p{InCJKCompatibilityIdeographs}] |
        [\p{InCJKUnifiedIdeographsExtensionB}])}ox;
@over       = qw(估計過高 переоценивать overestimate);
@under      = qw(估計過低 недооценивать underestimate);
@estimate   = (@over, @under);
$index = $num = 0;
grep{
        $num++;
        ($line) = $_;
        $got{$num}{s/$re/$index++/e} = $line if(/$re/);
    } @estimate;
foreach $key1 ( sort {$a <=> $b} keys %got )
{
    print "\n\nelement number:\t", $key1, "\n";
    foreach $key2 ( sort {$a <=> $b} keys %{ $got{ $key1 } } )
    {
                  print "match number: \t", $key2, "\t",  
                     $got{ $key1 }{ $key2 }, "\n";
    }
}
exit(0);

The script possesses some redundancy, but this is for teaching purposes only and produces no performance hits: just benchmark anything similar with seen-so-often if/else branching and measure the time. What's special on these 40 and something lines? There are two things deserving your, dear reader, attention:
(1) using 'our'; as you probably noticed, neither passing, nor returning any "parameters" are present. There exists from the very beginning a hash '%got', which is what every line of the script is using in turn;
(2) there's a conditional increment for '$index', which is what gives the matched subscript numbers to get back to the source array if needed.
 
Another way of thinking regexp like way is to use the embedded code; it looks very much alike the thing described above, however, it is not only a different flavour of using regular expressions, but also another way of building conditions while matching:
 
#!/usr/bin/perl
use strict;
use utf8;
use encoding 'utf8';
use re 'eval';
our ( $re, $index, $num, $sample1, 
         $sample2, $sample3, %src, %got, );
$re = qr{(
        [\p{InCJKUnifiedIdeographs}] |
        [\p{InCJKCompatibility}] |
        [\p{InCJKCompatibilityForms}] |
        [\p{InCJKRadicalsSupplement}] |
        [\p{InCJKCompatibilityIdeographsSupplement}] |
        [\p{InCJKUnifiedIdeographsExtensionA}] |
        [\p{InCJKCompatibilityIdeographs}] |
        [\p{InCJKUnifiedIdeographsExtensionB}])}ox;
$sample1    = q[一萬一千一百一十一 11111];
$sample2    = q[天一地二天三地四 
  небу соответствует число один, 
  земле — два, небу— три, земле — четыре... (и т. д.; «Ицзин») 
  one belongs to the Heaven, 
  two belongs to the Earth, 
  three belongs to the Heaven, 
  four belongs to the Earth... (etc, "YiJing")];
$sample3    =q[道生一, 一生二, 二生三, 三生萬物 
  Дао рождает одно (нерасчленённое единство), 
  одно рождает два (раздвоенность), 
  два рождает три (триаду), 
  от трёх рождаются все существа (вещи) 
  Dao bears one (indivisible unity), 
  one gives birth to the two (duality), 
  two produces three (triad), 
  those three flood everything (all things in the world)];
grep{ $src{$index++} = $_} ($sample1, $sample2, $sample3);
grep{
    grep{
            m#($re) ? (??{$got{$_}++ if($1 ne '')})#cgx;
        } split //, $src{$_};
    } sort keys %src;
foreach $num ( keys %got )
{
         print 'the match: ', "\t", $num, ' was seen:', "\t",  
           $got{ $num }, " time(s)\n";
}
exit(0);

Building '%src' is artificial here, but in real life hashes can do a lot of useful job and the extreme of such usefulness is a transparency of hash use through the whole script. Another interesting point is the way 'split' treats strings, because it really splits strings with Unicode in mind. One can find more things like this, for example: cho(m)p; but be aware: not everything is smooth in this respect - just try to play with 'use/no bytes' and 'length'.

пятница, 23 октября 2009 г.

Perl :: Юникод и регулярные выражения

   Перефразируя известного французского мыслителя применительно к Perl вполне справедливо заметить: «Если бы не существовало регулярных выражений, то не было бы и языка Perl». Возможно, Лари Уолл и не согласился бы с данным утверждением, но никто, наверное, не осмелился бы оспаривать важность регулярных выражений для приверженцев этого языка (обратное, вероятней всего, также верно). Как бы там ни было, но, согласитесь, тяжело найти Perl программиста, который бы не использовал регулярных выражений (а иначе, он попросту не использует его).

   Существует множество ресурсов по регулярным выражениям, но неоспоримым лидером, конечно же, является 'Mastering Regular Expressions' Дж. Фридла, которую стоит прочитать, с которой стоит не соглашаться и, в конце концов, по которой стоит учиться. Ряд вопросов, которые здесь будут затронуты, касаются в определённой степени самого Юникода, как явления необычайно важного, и то, как регулярные выражения в Perl могут помочь в их решении.

   FYI: perldoc perlunicode - Perl Unicode support

   Чтобы быть достаточно подготовленным для прочтения данного материала читатель должен уверенно себя чувствовать в вопросах работы регулярных выражений и особенно в части, которая касается построения объектов регулярных выражений; а также, как внедрять исполняемый код в регулярные выражения в ходе замены или при поиске совпадений, чтобы динамически выполнять куски кода внутри m// или s///. Было бы неплохо, если бы читатель уже имел некоторый опыт работы с Юникодом и знал его организацию, и что при использовании всех вышеупомянутых предметов необходимо использовать 'use utf8' либо 'use encoding "utf8"' вместе с ещё одной прагмой - 'use re "eval"', которая разрешает внедрять исполняемый код в регулярные выражения. Всё это, естественно, само собой подразумевает, что читатель знаком с поведением '\w' в среде Юникода.

   И последнее перед тем, как приступить к повествованию: 'use locale' накладывает гранитную глыбу на кросс-платформенность ваших приложений, в особенности, когда у вас присутствует что-то типа '\p{InCyrillic}' или 'p{InCJKCompatibilityIdeographs}', поскольку эти «звери» становятся чрезвычайно чувствительны к настройкам системы в регулярных выражениях и в контекстах 'use bytes' и 'no bytes'.

   FYI: perldoc utf8 - Perl pragma to enable/disable UTF-8 (or UTF-EBCDIC) in source code

   Чтобы покончить с введением, давайте освежим в памяти несколько базовых функций, которые могут помочь в наполнении вакуума о Юникоде:

#!/usr/bin/perl
use strict;
use encoding 'utf8';
our ( @packed, );
@packed = map{chr($_)} (0x4E00 .. 0x9FFF);
print $_, "\n" for @packed[0 .. 9];
exit(0);


этот малыш может сгенерировать практически мгновенно более 20.000 иероглифов, которые используются в китайском, японском, корейском и, возможно, в старо-вьетнамском языках. Строка:

@packed = map{chr($_)} (0x4E00 .. 0x9FFF);


может быть совсем безболезненно переписана как:

@packed = map{pack 'U', $_} (0x4E00 .. 0x9FFF);


   Здесь функции 'pack' и 'chr' несомненно взаимозаменяемы.

   Теперь попробуем сделать что-либо более полезное. Поскольку Perl сам имеет встроенную поддержку Юникода нам не понадобится даже создание временных переменных и мы сможем сразу перейти к созданию нужных нам объектов регулярных выражений. Если у кого-либо из читателей возникнет вопрос по поводу присутствия китайских предложений, то можно ответить, что это потому, что постольку данный язык (а точнее CJK) имеет наибольшее присутствие в Юникоде в виде символов:

#!/usr/bin/perl
use strict;
use utf8;
use encoding 'utf8';
our ( $re, $sample );
$re = qr{(
        [\p{InCJKUnifiedIdeographs}] |
        [\p{InCJKCompatibility}] |
        [\p{InCJKCompatibilityForms}] |
        [\p{InCJKRadicalsSupplement}] |
        [\p{InCJKCompatibilityIdeographsSupplement}] |
        [\p{InCJKUnifiedIdeographsExtensionA}] |
        [\p{InCJKCompatibilityIdeographs}] |
        [\p{InCJKUnifiedIdeographsExtensionB}])}ox;

$sample = '五行: 一曰水, 二曰火, 三曰木, 四曰金, 五曰土 
  пять стихий: первая называется вода, 
  вторая — огонь, третья — дерево, 
  четвёртая — металл, пятая — земля 
  Five Elements: first is Water, second is Fire, 
  third is Wood, fourth is Metal, fifth is Earth';

while($sample =~ m/$re/g)
{
    print $1,"\n";
}
exit(0);


очевидно, что в примере используются строки-образцы, содержащие текст на трёх языках и Perl совершенно точно (как и было ему велено) выбрал лишь те, которые принадлежат группе CJK.

   Для тех, кому не понятно присутствие латинского «быка» в конце объекта регулярного выражения, мы рекомендуем обратиться к 'perldoc perlre'; ну, а для тех «книжных червей», которые желают знать всё обо всём, имеется несколько вопросов:
(1) откуда берётся значение для '$1'?
(2) в чём разница между 'use utf8' и 'use encoding "utf8"'? (то есть, точнее, почему они обе здесь?)
(3) почему модификаторы 'ox' и 'g' здесь разделены? Если у Вас готовы ответы на все эти вопросы, мы все как один снимаем перед Вами шляпы!

   Настало время прибавить газу, или внести больше динамики в наши иллюстрации к регулярным выражениям. Взгляните на это:

#!/usr/bin/perl
use strict;
use utf8;
use encoding 'utf8';
use re 'eval';
our ( $re, $index, $num, $line, $key1, $key2, 
  @estimate, @over, @under, %got, );

$re = qr{(
        [\p{InCJKUnifiedIdeographs}] |
        [\p{InCJKCompatibility}] |
        [\p{InCJKCompatibilityForms}] |
        [\p{InCJKRadicalsSupplement}] |
        [\p{InCJKCompatibilityIdeographsSupplement}] |
        [\p{InCJKUnifiedIdeographsExtensionA}] |
        [\p{InCJKCompatibilityIdeographs}] |
        [\p{InCJKUnifiedIdeographsExtensionB}])}ox;

@over       = qw(估計過高 переоценивать overestimate);
@under      = qw(估計過低 недооценивать underestimate);
@estimate   = (@over, @under);
$index = $num = 0;
grep{
        $num++;
        ($line) = $_;
        $got{$num}{s/$re/$index++/e} = $line if(/$re/);
    } @estimate;
foreach $key1 ( sort {$a <=> $b} keys %got )
{
    print "\n\nelement number:\t", $key1, "\n";
    foreach $key2 ( sort {$a <=> $b} keys %{ $got{ $key1 } } )
    {
                print "match number: \t", $key2, "\t",  
                $got{ $key1 }{ $key2 }, "\n";
    }
}
exit(0);


в скрипте присутствует определённая избыточность, но это исключительно в образовательных целях и, к тому же, в данном случае это никоим образом не влияет на КПД: попробуйте изобразить что-то типа этого, используя if/else управляющие структуры и сравните время выполнения. Что особенного в этих сорока строках? Есть пару вещей, которые заслуживают внимания:

(1)использование 'our'; как вы уже заметили, даёт возможность не передавать и не принимать никаких данных: всё решается за счёт создания хэша '%got', который программа вызывает и использует там, где надо;

(2)имеется инкремент счётчика '$index' по условию, который и возвращает номера элементов, отвечающих условию совпадения.

   Другим способом подобного мышления является использование внедрённого кода; несмотря на то, что это выглядит примерно так, как и выше, но это не только иной вариант применения регулярных выражений, а иной способ построения условий, которые внедряются в них:

#!/usr/bin/perl
use strict;
use utf8;
use encoding 'utf8';
use re 'eval';
our ( $re, $index, $num, $sample1, $sample2, 
   $sample3, %src, %got, );

$re = qr{(
        [\p{InCJKUnifiedIdeographs}] |
        [\p{InCJKCompatibility}] |
        [\p{InCJKCompatibilityForms}] |
        [\p{InCJKRadicalsSupplement}] |
        [\p{InCJKCompatibilityIdeographsSupplement}] |
        [\p{InCJKUnifiedIdeographsExtensionA}] |
        [\p{InCJKCompatibilityIdeographs}] |
        [\p{InCJKUnifiedIdeographsExtensionB}])}ox;

$sample1    = q[一萬一千一百一十一 11111];
$sample2    = q[天一地二天三地四 
  небу соответствует число один, 
  земле — два, небу— три, 
  земле — четыре... (и т. д.; «Ицзин») 
  one belongs to the Heaven, 
  two belongs to the Earth, 
  three belongs to the Heaven, 
  four belongs to the Earth... (etc, "YiJing")];
$sample3    =q[道生一, 一生二, 二生三, 三生萬物 
  Дао рождает одно (нерасчленённое единство), 
  одно рождает два (раздвоенность), 
  два рождает три (триаду), 
  от трёх рождаются все существа (вещи) 
  Dao bears one (indivisible unity), 
  one gives birth to the two (duality), 
  two produces three (triad), 
  those three flood everything (all things in the world)];

grep{ $src{$index++} = $_} ($sample1, $sample2, $sample3);

grep{
    grep{
            m#($re) ? (??{$got{$_}++ if($1 ne '')})#cgx;
        } split //, $src{$_};
    } sort keys %src;

foreach $num ( keys %got )
{
         print 'the match: ', "\t", $num, ' was seen:', "\t",  
              $got{ $num }, " time(s)\n";
}
exit(0);


   Построение хэша '%src' является несколько искусственным здесь, если сравнивать с мощью хэшей вообще, и в этом примере как нельзя лучше показан способ применения хэшей, точнее, «прозрачность» их использования через всю программу. Другой интересной точкой является функция 'split', которая действительно полностью «понимает» Юникод. Есть и другие функции с подобным поведением в Юникодовской среде, например: cho(m)p; но надо помнить, что не всё гладко в этом отношении. Чтобы понять это попробуйте поиграть с 'use/no bytes' и 'length'.