Perl 5.10 в 2010-м — первая часть части III

| 1 комментарий

Часть III
Как пишут другие

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

Как включить режим Perl 5.10

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

Cпособы, которыми пользуются авторы, как нельзя лучше демоснтрируют принцип TIMTOWTDI:

use 5.010000;
use 5.01001;
use 5.010;
use 5.010_000;
use 5.10.0;
use v5.10.0;
use v5.10;
use feature ':5.10';

Строки, начинающиеся с буквы v, либо содержащие две точки, называются v-string (version string или, иногда, vector string). При объявлении версии интерпретатора следущие варианты эквивалентны.

5.10.0
v5.10.0
v5.10

Обратите внимание, если при указании версии используется обычное число (с одной десятичной точкой), то следует писать не 5.10, а 5.010.

say для отладки

Функцию say удобно использовать во время отладки программы для вывода промежуточных значений переменных. На CPAN можно найти следы такой отладки — закомментированный вызов say.

given ($action) {
    when (/^include_cmd:/) {
        my $cmd = $child->content;
        $cmd =~ /^include_cmd:(\s*)/;
        my $ws = $1 || '';
        $cmd =~ s/^include_cmd:\s*//;
        #say("cmd:$ws$cmd");
        $cmd = cwd() . '/' . $cmd;
        @output = qx($cmd);
        $child->content($ws . join($ws, @output));
    }

Pod::Elemental::Transformer::Include — 08 Jan 2010
include output via files and commands

(Здесь и далее рядом с примером кода указано название модуля, откуда взят пример, дата выхода его первой версии и авторское описание; пунктуация, отступы и пробелы в коде в большинстве случаев сохранены.)

// и //= для значений по умолчанию

Пожалуй, самое распространенное применение оператора defined-or — установка значений по умолчанию.

В частности, удобно пользоваться вариантом с присвоением.

$port //=  5432;
$host //= 'localhost';

$col  //= '';

Pg::Loader — 07 Jul 2008
Perl extension for loading Postgres tables

$attrz{ maxjob  } //= 1;
$value //= 1;

$attrz{ $_ } //= 0;
$attrz{ verbose } //= '';
$attrz{ debug   } //= '';
$val //= 1;
$exit //= 0;
$skipz->{ $job_id } //= 'Skip on SIGHUP'

Parallel::Depend — 12 Aug 2009
Parallel-dependent dispatch of perl or shell code

Чуть более сложный пример — с обращением к встроенной функции:

sub import   {
    shift;
    my %args = @_;
    # we do not care about autoviv
    $^H{fixedtime} = $args{epoch_offset} // 
                     CORE::time;
}

fixedtime — 14 Aug 2008
lexical pragma to fix the epoch offset for time related functions

Defined-or используют и непосредственно при передаче аргументов функциям.

say $answer // 
    "I don't know enough to answer you yet.";

Hailo — 29 Jan 2010
A pluggable Markov engine analogous to MegaHAL

Следует обратить внимание, что оператор возможно использовать не только с истинными скалярами.

my $marpa_version  = 
$Parse::Marpa::VERSION // 'undef';
my $source_version = 
$Parse::Marpa::Source::VERSION // 'undef';

$options //= {};

Parse::Marpa — 14 Dec 2008
Generate Parsers from any BNF grammar

В следующем примере помимо многократного использования // интересно отметить, что say передается файловый дескриптор.

my $nulling_symbol =
  $rhs_symbol->[Parse::Marpa::Internal::Symbol::NULL_ALIAS] // $rhs_symbol;

$action //= $default_action;

say {$trace_fh}
    'Problems compiling action for original rule: ',
    Parse::Marpa::brief_original_rule($rule);

my $clone = $clone_arg // 1;
my $current_parse_set = $parse_set_arg // $default_parse_set;

$choice //= 0;

$lines //= [0];
$source_options //= {};

Parse::Marpa::Internal::Evaluator — 14 Dec 2008
Generate Parsers from any BNF grammar

Наконец, и сам файловый дескриптор удобно вписывается в работу с defined-or:

my $trace_fh = $arg_trace_fh // (*STDERR);

my $trace_fh = shift;
$trace_fh //= *STDERR;

Parse::Marpa::Recognizer — 14 Dec 2008
Generate Parsers from any BNF grammar

// внутри return

Оператор defined-or часто встречается внутри вызова return, опять же чтобы вернуть определенное значение, если оно не получено на предыдущих шагах.

return $self->_get_infection( $disease->id ) // 0;

my $val = $self->_get($key) // $default->{$key};


return @{ $self->_players // [] };

Games::Pandemic::City, Games::Pandemic::Config — 07 Sep 2009
Games::Risk — 18 Oct 2008

Иногда в одном из операндов // вызывают фукнции, которые могут привести к досрочному завершению программы или выходу из блока.

sub homedir {
  my ($self) = @_;
  require File::HomeDir;
  return File::HomeDir->my_home
    // croak 'File::HomeDir says you have no home
              directory';
}

App::RSS2Leafnode — 02 Feb 2010
post RSS feeds to newsgroups

А вот пример, когда операндом является целый блок кода do:

sub config_filename {
  my ($self) = @_;
  return $self->{'config_filename'} // do {
    require File::Spec;
    File::Spec->catfile ($self->homedir, '.rss2leafnode.conf');
  };
}

App::RSS2Leafnode — 02 Feb 2010
post RSS feeds to newsgroups

В частных случаях // действует лишь внутри части выражения, передаваемое return.

return 
isodate_to_rfc822($date // $self->{'now822'});

return URI::Title::title
    ({ url  => ($resp->request->uri // ''),
       data => $resp->decoded_content 
 (charset => 'none')});

App::RSS2Leafnode — 02 Feb 2010
post RSS feeds to newsgroups

return внутри //

Весьма распространена и противоположная конструкция, когда в одном из плеч // делают попытку возврата из подпрограммы.

my $b_time = $self->item_to_timet($b_item)
   // return $a_item;

my $a_time = $self->item_to_timet($a_item) 
   // return $b_item;;

my $str = $self->item_to_date($item) 
   // return;

App::RSS2Leafnode — 02 Feb 2010
post RSS feeds to newsgroups

// легко объединяется в цепочку, поэтому возможно написать конструкцию, которая делает несколько попыток присвоить defined-значение:

return (elt_to_email ($item->first_child('author'))
        // elt_to_email ($item   ->first_child('dc:creator'))
        // elt_to_email ($item   ->first_child('dc:contributor'))
        // non_empty ($item->first_child_text('wiki:username'))

        // elt_to_email ($channel->first_child('dc:creator'))
        // elt_to_email ($channel->first_child('author'))
        // elt_to_email ($channel->first_child('managingEditor'))
        // elt_to_email ($channel->first_child('webMaster'))

        // elt_to_email ($item   ->first_child('dc:publisher'))
        // elt_to_email ($channel->first_child('dc:publisher'))

        // non_empty ($channel->first_child_text('title'))

        # RFC822
        // 'nobody@'.$self->uri_to_host
       );

App::RSS2Leafnode — 02 Feb 2010
post RSS feeds to newsgroups

Возможен и подход, при котором возвращается одна-единственная переменная, которая перед этим проходит через несколько проверок с оператором defined-or:

sub item_to_language {
  my ($self, $item) = @_;
  my $content;
  my $ret = (elt_to_language($item)
             // elt_to_language($item->first_child('content')));
  for (;;) {
    $item = $item->parent // last;
    $ret //= elt_to_language($item);
  }
  $ret //= $self->{'resp'}->content_language;
  return $ret;
}

App::RSS2Leafnode — 02 Feb 2010
post RSS feeds to newsgroups

Несколько //

Объединение в цепочку нам уже встречалось, однако на нем следует задержать внимание еще раз.

my $captures    = $arg {captures}       // [];
my $comment     = escape $arg {comment} // $name // "";
my $upgrade     = $arg {utf8_upgrade}   // 1;
my $downgrade   = $arg {utf8_downgrade} // 1;
my $match       = $arg {match}          // 1;

Games::Wumpus — 24 Nov 2009
Play Hunt the Wumpus


Продолжение будет.

1 комментарий

Хороший пост примеров исользования новых возможностей perl, добавил в закладки.
Модули CPAN написанные с применением новых фич perl не всегда позитивно оцениваются, к примеру когда последняя версия модуля требует perl >= 5.10, в то время как раньше совместимость была до версии 5.6x. Хороший пример - отзывы о Date::Manip 6.xx (http://cpanratings.perl.org/dist/Date-Manip)

Комментировать

Страницы

  • img

Об этой записи

Сообщение опубликовано 12.03.2010 10:35. Автор — ash.

Предыдущая запись — Команда rmfunc в job-сервере Gearman

Следующая запись — Strawberry Perl Professional

Смотрите новые записи на главной странице или загляните в архив, где есть ссылки на все сообщения.