Пересмотр WWW::Page

Я использую подход, заложенный в модуле WWW::Page, уже несколько лет, постоянно изменяя его код. Не будет преувеличением утверждение, что на каждом сайте работают разные варианты модуля.

Однако, мне хочется несколько поменять идеологию, сократив на треть число файлов, которые необходимы для развертывания сайта.

Сейчас URI запрошенной страницы отображается на один из нескольких XML-файлов с описаниями страниц. Иными словами, некий диспатчер определяет тип страницы и смотрит его описание в соответствующем файле. В таких XML, в частности, подключается один из кастомных модулей, отвечающих за логику приложения, дана ссылка на файл с XSLT-преобразованиями и записаны вызовы функций (из кастомного модуля). Типичный пример подобного файла описания входит в поставку.

Со временем стало ясно, что такая структура, хотя и позволяет полную свободу, отнимает много времени при добавлении на сайт новых страниц (точнее, типов страниц). Дело даже не в том, что это отнимает время; дело в том, что каждая такая операция — типовая: обновить диспатчер, научив его разпознавать новые адреса, создать описание страницы в XML, создать файл с XSLT.После выхода Perl 5.10 в диспатчерах применяется конструкция given/when, и на каждый тип страниц обычно приходится одна строка:

given($uri) {
    when(m{^/?$})
       {$path = 'index.xml'}
    when(m{^/api/(rate)/[^/]+/?$})
       {$path = "api/$1.xml"}
    when(m{^/api/[^/]+/?$})
       {$path = 'api/rates-all.xml'}
    when(m{^/(currency|list|cloud)/?$})
       {$path = "$1.xml"}
 ...

Не слишком утомительно и вполне расширяемо. Однако задача такого распределителя — подготовить переменную $path, записав в нее имя соответствующего XML-файла с описанием страницы.

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

Сейчас (на самом деле лет уже 10 как, еще до появления WWW::Page) я вижу такое развитие подхода. Вместо имен файлов диспатчер сразу будет возвращать объекты страниц соответствющих классов. Есть, например, страница «Новости», для нее возвращается MySite::Page::News.

given($uri) {
    when(/^news$/)
       {return new MySite::Page::News::List}
    when(/^news/(.*)$)
       {return new MySite::Page::News::Detail($1)}

Этот подход я опробую на сайте books.perl.org.

Хитрый момент во множественном наследовании

Если создать класс, унаследованный от двух других, то будет не слишком очевидно, от какого класса окажется унаследованным метод import.

Простой пример. Имеется два модуля BaseA и BaseB, содержащие только метод import.

package BaseA;

sub import {
    print "Base A\n";
}

1;


package BaseB;

sub import {
    print "Base B\n";
}

1;

Модуль Derived содержит лишь инструкции, указывающие эти два класса как базовые:

package Derived;

use base BaseA;
use base BaseB;

1;

Что произойдет, если в программе используется модуль Derived, и вызван метод import?

use Derived;

Derived->import();

На печать дважды выводится строка Base A (первый раз при подключении, второй — при явном вызове import).

А вот если поменять порядок наследования внутри Derived:

package Derived;

use base BaseB;
use base BaseA;

1;

то на печать дважды выводится Base B.

Perl, Пърл, पर्ल

Мне стало интересно, как выглядит название языка Perl на языках, не использущих латинский алфавит.

На википедии нашлось более десятка вариантов названия:

Арабский — يرلبيرل
Болгарский — Пърл
Грузинский — პერლი
Гуджарати — પર્લ
Иврит — פרל
Корейский — 펄
Персидский — پەرل
Сербский — Перл
Тайский — เพิร์ล
Тамильский — பெர்ள்
Фарси — پرل
Хинди — पर्ल
Японский — パール

Некотрые из представленных здесь языков используют противоположное европейскому направление письма — слева направо. В большинстве случаев наверняка записано просто звучание слова, а не исходная аббревиатура. Гугл, кстати, переводит часть из этих названий как Pearl.

Планы на 2010 материализуются

В списке сайтов конференций, построенных на платформе Act, появилось первое мероприятие на 2010 год.

Это второй болгарский Perl-воркшоп «BG Perl — 2», который состоится в Софии в конце января или начале февраля.

Предыдущий воркшоп 31 января 2009 года собрал около 40 человек, и помещение оказалось немного тесным. Как организатор могу сказать, что это мероприятие я считаю одним из лучших, которые мы сделали. Кстати, в очередной раз замечу, что участники весьма хорошо общались по-английски. Все выступления, за исключением вступительного слова, были на английском языке.

Недавно к соревнованию Iron Man присоединился один из участников воркшопа, Петар Шангов, который открыл блог mechanicalrevolution.com. (На фотографии видны сложенные руки Петара — он крайний справа за передним рядом столов.)

Верблюды

В рассылке Лондон.pm активно обсуждаются плюшевые верблюды, их стоимость и где приобрести.

Где бы вы ни встретили Лиона Брокарда (на фото справа), всегда увидете с ним маленького плюшевого верблюда, которого Лион постоянно привозит на все мероприятия.

Верблюда зовут Амелия и он является официальным верблюдом London.pm.

Обсуждение, впрочем, перешло от ссылок на Амазон к проблеме отстрела верблюдов в Австралии, а затем и к блюдам из верблюжатины.

Inline::CPP

Inline::CPP — замечательный инструмент для того, чтобы с легкостью собирать вместе компоненты, написанные на C++ и Perl.

Не то, чтобы мне потребовалось радикально оптимизировать программу, переписав критические куски на C++. Мне просто захотелось сделать на этом языке часть проекта, написанного на Perl. Мне потребовался грамматический парсер, который легко удалось написать, используя библиотеку Spirit из комплекта Boost.

Что у нас есть для вызова функции из программы на Perl? У нас есть XS, но он в оригинале пригоден для связки с C, а не C++. Даунгрейдить программу ради промежуточного инструмента — не выход. В любом случае писать приходится на синтетическом языке (я пробовал).

Существуют несколько рецептов того, как используя XS подключить фрагменты программы на C++. Но даже те методы, которые аккуратно и доступно изложены, неадекватно сложны для вызова calc(«2+2»). Например, по одному из старых рецептов требуется выполнить с десяток шагов, найти специальный файл perlobject.map, а в каталоге с проектом возникает месиво из файлов:

blib        lib          MANIFEST      MyPackage.o    perlobject.map    ppport.h  typemap
Changes     Makefile     MyPackage.bs  MyPackage.xs   perl-xs-c++.html  README
_howto.txt  Makefile.PL  MyPackage.c   MyPackage.xsc  pm_to_blib        t

Мой выбор — Inline::CPP. Вся программа сводится к подключению этого модуля и вызову нужной функции:

use Modern::Perl;
use Inline 'CPP' => "./calc.cpp";

say calc($ARGV[0]);

Магия компиляции и сборки остается за горизонтом; единственное видимое проявление — каталог _Inline в рабочей директории (но и его можно перенести в /tmp или куда угодно). И, разумеется, замедление первой загрузки программы. При повторных запусках задержек нет, потому что используются готовые .so-библиотеки.

Замечательно, что C++-файл остается C++-программой: никаких дополнительных инструкций не требуется. Еще более важно, что такая программа, не будучи специально предназначенной для работы с перлом, может быть частью обычной программы на C++. Например, функцию можно вызвать для тестирования:

#include<iostream>

using namespace std;
double calc(char*);

int main() {
    cout << calc("1+2*3") << "\n";
}

У Inline::CPP пара мелких недостатков (которые, в прочем, никак не омрачают впечатление, удобство и пользу модуля). Во-первых, вывод сообщений об ошибках, который в моем случае по умолчанию попадал в логи Апача, оказывается месивом из строк и литерализированных переводов строк. Вместе с сообщением о самой ошибке (а в C++, когда используешь шаблонные классы, легко получить многостраничное сообщение даже при небольшой ошибке) сюда же попадает командная строка, с которой вызывался компилятор C++:

/usr/bin/perl /usr/share/perl/5.10/ExtUtils/xsubpp  -typemap /usr/share/perl/5.10/ExtUtils/typemap   Calculator_f4e3.xs > Calculator_f4e3.xsc && mv Calculator_f4e3.xsc Calculator_f4e3.c\ng++ -c   -D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fno-strict-aliasing -pipe -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -O2 -g   -DVERSION=\\"0.00\\" -DXS_VERSION=\\"0.00\\" -fPIC "-I/usr/lib/perl/5.10/CORE"   Calculator_f4e3.c\nIn file included from Calculator_f4e3.xs:15:\n/usr/include/boost/spirit/core.hpp:18:4: warning: #warning "This header is deprecated. Please use: boost/spirit/include/classic_core.hpp"\nCalculator_f4e3.xs: In function 'double eval_expr()':\nCalculator_f4e3.xs:154: error: 'info' was not declared in this scope\nCalculator_f4e3.xs: In function 'double calc(const char*)':\nCalculator_f4e3.xs:190: error: 'exal_expr' was not declared in this scope\nCalculator_f4e3.c: In function 'void boot_WHL__Parser__Calculator_f4e3(PerlInterpreter*, CV*)':\nCalculator_f4e3.c:354: warning: deprecated conversion from string constant to 'char*'\nmake: *** [Calculator_f4e3.o] Error 1\n\nA problem was encountered while attempting to compile and install your Inline\nCPP code. The command that failed was:\n  make > out.make 2>&1\n\nThe build directory was:\n/_Inline/build/WHL/Parser/Calculator_f4e3\n\nTo debug the problem, cd to the build directory, and inspect the output files.\n\n at /home/ash/infolavka/trunk/whoyougle/lib/WHL/Parser/Calculator.pm line 6\nBEGIN failed--compilation aborted at /home/ash/infolavka/trunk/whoyougle/lib/WHL/Parser/Calculator.pm line 6.\nCompilation failed in require at /home/ash/infolavka/trunk/whoyougle/lib/WHL/Parser.pm line 21.\nBEGIN failed--compilation aborted at /home/ash/infolavka/trunk/whoyougle/lib/WHL/Parser.pm line 21.\nCompilation failed in require at /home/ash/infolavka/trunk/whoyougle/lib/Infolavka/Default/Worker.pm line 10.\nBEGIN failed--compilation aborted at /home/ash/infolavka/trunk/whoyougle/lib/Infolavka/Default/Worker.pm line 10.\nCompilation failed in require at (eval 39) line 3.\n\t...propagated at /usr/share/perl/5.10/base.pm line 92.\nBEGIN failed--compilation aborted at /home/ash/infolavka/trunk/whoyougle/lib/Tinyurl/Worker.pm line 12.\nCompilation failed in require at /usr/local/apache2-dev/conf/vhosts/ash.dev line 480.\nBEGIN failed--compilation aborted\t(in cleanup) /usr/bin/perl /usr/share/perl/5.10/ExtUtils/xsubpp  -typemap /usr/share/perl/5.10/ExtUtils/typemap   Calculator_f4e3.xs > Calculator_f4e3.xsc && mv Calculator_f4e3.xsc Calculator_f4e3.c\ng++ -c   -D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fno-strict-aliasing -pipe -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -O2 -g   -DVERSION=\\"0.00\\" -DXS_VERSION=\\"0.00\\" -fPIC "-I/usr/lib/perl/5.10/CORE"   Calculator_f4e3.c\nIn file included from Calculator_f4e3.xs:15:\n/usr/include/boost/spirit/core.hpp:18:4: warning: #warning "This header is deprecated. Please use: boost/spirit/include/classic_core.hpp"\nCalculator_f4e3.xs: In function 'double eval_expr()':\nCalculator_f4e3.xs:154: error: 'info' was not declared in this scope\nCalculator_f4e3.xs: In function 'double calc(const char*)':\nCalculator_f4e3.xs:190: error: 'exal_expr' was not declared in this scope\nCalculator_f4e3.c: In function 'void boot_WHL__Parser__Calculator_f4e3(PerlInterpreter*, CV*)':\nCalculator_f4e3.c:354: warning: deprecated conversion from string constant to 'char*'\nmake: *** [Calculator_f4e3.o] Error 1\n\nA problem was encountered while attempting to compile and install your Inline\nCPP code. The command that failed was:\n  make > out.make 2>&1\n\nThe build directory was:\n/_Inline/build/WHL/Parser/Calculator_f4e3\n\nTo debug the problem, cd to the build directory, and inspect the output files.\n\n at /home/ash/infolavka/trunk/whoyougle/lib/WHL/Parser/Calculator.pm line 6\nBEGIN failed--compilation aborted at /home/ash/infolavka/trunk/whoyougle/lib/WHL/Parser/Calculator.pm line 6.\nCompilation failed in require at /home/ash/infolavka/trunk/whoyougle/lib/WHL/Parser.pm line 21.\nBEGIN failed--compilation aborted at /home/ash/infolavka/trunk/whoyougle/lib/WHL/Parser.pm line 21.\nCompilation failed in require at /home/ash/infolavka/trunk/whoyougle/lib/Infolavka/Default/Worker.pm line 10.\nBEGIN failed--compilation aborted at /home/ash/infolavka/trunk/whoyougle/lib/Infolavka/Default/Worker.pm line 10.\nCompilation failed in require at (eval 39) line 3.\n\t...propagated at /usr/share/perl/5.10/base.pm line 92.\nBEGIN failed--compilation aborted at /home/ash/infolavka/trunk/whoyougle/lib/Tinyurl/Worker.pm line 12.\nCompilation failed in require at /usr/local/apache2-dev/conf/vhosts/ash.dev line 480.\nBEGIN failed--compilation aborted at /usr/local/apache2-dev/conf/vhosts/ash.dev line 480.\n

Во-вторых, из документации не сразу понимаешь, как обеспечить прозрачную компиляцию, когда хочется компилировать внешний файл (а не писать код прямо в Perl-файле после __DATA__). А поскольку мне нужен вывод через поток iostream из стандартной библиотеки STL, приходится конфигурировать Inline::CPP для его поддержки. Несколько впадаешь в ступор, когда понимаешь, что одновременно эти пожелания выполнить не получится. Вместо этого, оказывается, нужно записать use Inline::CPP дважды:

use Modern::Perl; use utf8; use Inline 'CPP' => Config => ENABLE => 'STD_IOSTREAM', DIRECTORY => '/tmp'; use Inline 'CPP' => "$ENV{PROJECT_ROOT}/lib/WHL/Parser/calculator.cpp";

Резюме: пользуйтесь Inline::CPP, это облегчит жизнь.

Белорусский Perl-воркшоп

17 октября 2009 года в Минске пройдет второй белорусский Perl-воркшоп «BY Perl».

Мероприятие бесплатное, для участия необходимо зарегистрироваться на сайте 2009.perlbelarus.org. Место проведения будет объявлено позже.

Организаторы (Minsk.pm и Moscow.pm) приглашают докладчиков выступить на воркшопе.

Исходные коды perldoc.perl.org

Опубликованы исходники сайта perldoc.perl.org.

Джон Аллен (Jon Allen, JJ) — создатель сайта perldoc.perl.org — открыл исходные коды сайта. Они доступны на Гитхабе.

Perldoc.perl.org представляет собой онлайновую версию документации по Perl. Сайт содержит все материалы, входящие в дистрибутив языка. Сейчас доступна документация версий 5.10, 5.8.9 и 5.8.8, однако автор сайта планирует расширить набор как минимум до версии 5.8.

Чуть меньше месяца назад perldoc.perl.org поменял дизайн. Предыдущая версия выглядела примерно так, как сейчас выглядит еще один сайт — с переводами документации на другие языки — perldoc.org.

Почему важны слайды и видеозаписи

Организаторы каждого мероприятия — воркшопа или конференции — должны заботиться о том, чтобы доклады были сохранены для истории.

Perl-сообщство проводит множество мероприятий. Но в то же время сообщество расслоено таким образом, что на мероприятия приходят далеко не все программисты, использующие Perl.

Например, недавнюю YAPC::Europe в Лиссабоне посетило около 330 человек. При этом по статистике 2007 года известно по крайней мере о 4580 Perl-программистах в мире (знакомых с английским языком). Большинство из них не были на конференции и никогда не увидят ни слайдов, ни видезаписей.

Реально программистов в несколько раз больше: нужно учесть тех, кто не смог принять участия в опросе perlsurvey.org из-за незнания английского, либо просто не захотел, либо вообще не знал.

А еще есть категория людей, которые занимаются перлом только в рабочее время. Хотя они и не поехали бы ни на какие конференции, многие из них готовы посмотреть выступления докладчиков через интернет на дому.

Мероприятия в восточной части Европы до конца года

До конца текущего года состоятся несколько Perl-мероприятий в восточной части Европы.

Во-первых, на 17 октября планируется второй белорусский Perl-воркшоп в Минске.

Во-вторых, на начало декабря готовится второй воркшоп TwinCity — совместное мероприятие Vienna.pm и Bratislava.pm.

В-третьих, 21 ноября в Риге состоится первый в истории балтийский Perl-воркшоп.