[Moscow.pm] tie на стандартные переменные

Vladimir Timofeev vovkasm на gmail.com
Вс Янв 23 10:44:33 PST 2011


2011/1/23 Ivan Petrov <i.petro.77.00 на gmail.com>:
> У Ларри Уолла есть пример когда используя tie перехватывают все обращения к
> $_.
>
> В перле есть старый баг, который видимо никогда уже не поправят: переменная
> $! всегда кривая, если используется use utf8
>
> =пример
>
> #!/usr/bin/perl
>
> use warnings;
> use strict;
>
> use utf8;
> use open qw(:std :utf8);
>
> open my $file, '<', 'abrakadabra/not-found'
>     or die "Ошибка открытия файла: $!";
>
> =конец примера
>
> соответственно выведет этот пример такую строку:
>
> =
> Ошибка открытия файла: ÐÐµÑ Ñакого Ñайла или каÑалога at
> test_e.pl line 9.
>
> Хочется иметь в логах правильные коды ошибок. Поэтому я попробовал
> поиграться со связыванием чтобы пофиксить этот баг целиком на проекте но не
> ходя по коду и не делая decode utf8 => $! на каждое место где встречается
> $!.
>
> соответственно вышеприведенный тест переписал к виду:
>
> =второй пример
>
> #!/usr/bin/perl
>
> use warnings;
> use strict;
>
> use utf8;
> use open qw(:std :utf8);
>
> package FixErrno;
>
> use base qw(Tie::Scalar);
> use Encode qw(decode);
>
> sub TIESCALAR
> {
>     return bless \my $dummy;
> }
>
> sub FETCH
> {
>     print "FETCH\n";
>     return decode utf8 => ${ $_[0] };
> }
>
> sub STORE
> {
>     print "STORE\n";
>     ${ $_[0] } = $_[1];
> }
>
>
> tie $! => 'FixErrno';
>
> package main;
> use Encode qw(decode);
>
>
> open my $file, '<', 'abrakadabra/not-found'
>     or die "Ошибка открытия файла: $!";
>
> =конец второго примера
>
> соответственно  результат работы такой:
>
> =начало
>
> perl test_e.pl
> FETCH
> Ошибка открытия файла: ÐÐµÑ Ñакого Ñ
>                                          айла или каÑалога at
> test_e.pl line 38.
> =конец
>
> то есть FETCH вызывается, а STORE не вызывается. А поскольку STORE не
> вызывается, то и все это не работает.
> Есть идеи что можно простого сделать с проектом у которого много $! но не
> хочется расставлять decode повсюду?

И собственно в тему топика:
$! - магическая переменная... у нее просто нет значения, а значит
нечего устанавливать, значит не вызывается STORE.
Можно проверить так: perl -E '$! = "test"; say $!'
Когда из нее читают значение, вызывается magic get, который
устанавливает два слота в возвращаемом значении, код из errno в IV
(для числового контекста) и результат strerror(errno) в PV (для
строкового).
Она уже магическая и юзерская магия tie (или напрямую через
Variable::Magic) применяется до и изменить ничего не может уже.

Поэтому по ходу менять придется каждую строку с $! в коде (благо
обнаружить их достаточно просто... ;-)
Либо глобально менять семантику конкатенации через use locale 'utf8';,
как показал Дмитрий. Только вот боюсь других багов с этим можно
огрести.
Врядли что-то еще здесь можно придумать, имхо.

>
> --
> Moscow.pm mailing list
> moscow-pm на pm.org | http://moscow.pm.org
>
>



-- 
Vladimir Timofeev <vovkasm на gmail.com>


Подробная информация о списке рассылки Moscow-pm