Можете ли вы зацепить открытие ручки данных? - PullRequest
3 голосов
/ 06 марта 2012

Можете ли вы подключить открытие дескриптора DATA для модуля, пока Perl все еще компилируется? Под этим я подразумеваю, есть ли способ вставить код, который будет запускаться после Perl открыл глобус DATA для чтения, но за до фаза компиляции прекратилась.

В противном случае, вы можете хотя бы увидеть текст raw после __DATA__ до того, как его откроет компилятор?


В ответ на Ikegami, в недавних сценариях, над которыми я работал, я использовал __DATA__ section + синтаксис YAML для настройки сценария. Я также создавал словарь обработчиков конфигурации YAML, где поведение запрашивается use -ing модулями. И в некоторых скриптах, которые бывают быстрыми и грязными, но их недостаточно, чтобы отказаться от strict, я хотел посмотреть, смогу ли я представить переменные из спецификации YAML.

Это немного раздражает, хотя я просто сохраняю данные в подпрограммах import и затем жду блока INIT для обработки YAML. Но это было выполнимо.

Ответы [ 6 ]

3 голосов
/ 06 марта 2012

Дескриптор файла в DATA - это не что иное, как дескриптор, который синтаксический анализатор использует для чтения кода, найденного до __DATA__.Если этот код все еще компилируется, то __DATA__ не был достигнут, тогда дескриптор не был сохранен в DATA.

Вместо этого вы могли бы сделать что-то вроде следующего:

open(my $data_fh, '<', \<<'__EOI__');
.
. Hunk of text readable via $data_fh
.
__EOI__
2 голосов
/ 06 марта 2012

Вы можете использовать любой из до выполнения, но после блоков компиляции, чтобы изменить дескриптор *DATA. Вот краткий пример использования INIT для изменения *DATA на uc.

while (<DATA>) {
    print;
}

INIT {  # after compile time, so DATA is opened, but before runtime.
    local $/;
    my $file = uc <DATA>;
    open *DATA, '<', \$file;
}

__DATA__
hello,
world!

печать:

HELLO,
WORLD!

Какой из блоков использовать, зависит от других факторов в вашей программе. Подробнее о различных временных блоках можно узнать на справочной странице perlmod .

2 голосов
/ 06 марта 2012

Я не знаю, где вы хотите крюк.Вероятно, в UNITCHECK.

use warnings;

sub i'm {
    print "in @_\n";
    print scalar <DATA>;
}

BEGIN       { i'm "BEGIN" }
UNITCHECK   { i'm "UNITCHECK" }
CHECK       { i'm "CHECK" }
INIT        { i'm "INIT" }
END         { i'm "END" }

i'm "main";
exit;

__END__
Data line one.
Data line two.
Data line three.
Data line four.
Data line five.
Data line six.

Создает это при запуске:

in BEGIN
readline() on unopened filehandle DATA at /tmp/d line 5.
in UNITCHECK
Data line one.
in CHECK
Data line two.
in INIT
Data line three.
in main
Data line four.
in END
Data line five.
1 голос
/ 06 марта 2012

perlmod говорит:

Блоки кода CHECK запускаются сразу после окончания начальной фазы компиляции Perl и до начала времени выполнения в порядке LIFO.

Может быть, вы ищете что-то подобное?

CHECK {
    say "Reading from <DATA> ...";
    while (<DATA>) {
        print;
        $main::count++;
    };
}

say "Read $main::count lines from <DATA>";

__DATA__
1
2
3
4
5

Создает следующий вывод:

Reading from <DATA> ...
1
2
3
4
5
Read 5 lines from <DATA>
1 голос
/ 06 марта 2012

Боюсь, что нет, если я правильно понял ваш вопрос. Это написано в Документ :

Обратите внимание, что вы не можете прочитать из файлового дескриптора DATA в блоке BEGIN: блок BEGIN выполняется, как только он виден (во время компиляция), в этот момент соответствующий ДАННЫЕ (или END ) токен еще не был замечен.

Есть и другой способ: прочитать файл с разделом DATA как обычный текстовый файл, проанализировать этот раздел, а затем require сам файл сценария (что будет сделано во время выполнения). Не знаю, будет ли это актуально в вашем случае. )

0 голосов
/ 15 ноября 2012

Я обнаружил, что ::STDIN фактически дает мне доступ к потоку '-'.И что я могу сохранить текущее местоположение через tell( $inh ), а затем seek(), когда я закончу.

Byиспользуя этот метод, я мог прочитать раздел __DATA__ в подпункте import!

sub import { 
    my ( $caller, $file ) = ( caller 0 )[0,1];
    my $yaml;
    if ( $file eq '-' ) {
        my $place = tell( ::STDIN );
        local $RS;
        $yaml  = <::STDIN>;
        seek( ::STDIN, $place, 0 );
    }
    else { 
        open( my $inh, '<', $file );
        local $_ = '';
        while ( defined() and !m/^__DATA__$/ ) { $_ = <$inh>; }
        local $RS;
        $yaml = <$inh>;
        close $inh;
    }        
    if ( $yaml ) { 
        my ( $config ) = YAML::XS::Load( $yaml );;
        no strict 'refs';
        while ( my ( $n, $v ) = each %$config ) { 
            *{"$caller\::$n"} = ref $v ? $v : \$v;
        }
    }    
    return;
}

Это работало на Strawberry Perl 5.16.2, поэтому я не знаю, насколько это переносимо.Но сейчас для меня это работает.

Просто фон.Раньше я немного программировал с помощью Windows Script Files.Одна вещь, которая мне понравилась в формате wsf, это то, что вы можете указывать глобально полезные объекты вне кода.<object id="xl" progid="Application.Excel" />.Мне всегда нравился вид программирования по спецификации и позволяющий некоторому модульному обработчику сортировать данные.Теперь я могу получить аналогичное поведение через обработчик YAML: excel: !ActiveX: Excel.Application.

Это работает для меня.

Тест здесь, если вам интересно:

use strict;
use warnings;
use English qw<$RS>;
use Test::More;

use data_mayhem; # <-- that's my module.

is( $k, 'Excel.Application' );
is( $l[1], 'two' );

{   local $RS;
    my $data = <DATA>;
    isnt( $data, '' );
    say $data
}

done_testing;

__DATA__
---
k : !ActiveX Excel.Application
l : 
  - one
  - two
  - three
...