在Perl还在编译时,你能挂钩模块的DATA句柄的开口吗?我的意思是,有一种方法可以插入代码,在 Perl打开DATA
glob进行读取之后运行但是之前编译阶段已经停止。
如果失败了,你能在编译器打开它之前至少看到__DATA__
之后的 raw 文本吗?
为了回应Ikegami,在我最近编写的最新脚本上,我一直使用__DATA__
section + YAML语法来配置脚本。我也在构建YAML配置处理程序的词汇表,其中use
- 模块请求行为。在一些快速脏,但不足以放弃strict
的脚本中,我想看看是否可以公开YAML规范中的变量。
虽然只是在import
潜艇中保存数据然后等待INIT
块来处理YAML,但这有点令人讨厌。但这是可行的。
答案 0 :(得分:3)
DATA
中的文件句柄就是解析器用来读取__DATA__
之前找到的代码的句柄。如果该代码仍在编译中,那么__DATA__
尚未到达,则句柄尚未存储在DATA
中。
您可以执行以下操作:
open(my $data_fh, '<', \<<'__EOI__');
.
. Hunk of text readable via $data_fh
.
__EOI__
答案 1 :(得分:2)
我不知道你想要的钩子。可能在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.
答案 2 :(得分:2)
您可以使用任何运行时之前但在编译块之后更改*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联机帮助页。
答案 3 :(得分:1)
请注意,您无法从BEGIN块中的DATA文件句柄中读取: BEGIN块一看到就会被执行(期间) 汇编),此时相应的 DATA (或 END ) 令牌尚未见过。
还有另一种方法:用 DATA 部分作为普通文本文件读取文件,解析此部分,然后require
脚本文件本身(将在运行时完成 - 时间)。不知道它是否与你的情况有关。 )
答案 4 :(得分:1)
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>
答案 5 :(得分:0)
我发现::STDIN
实际上允许我访问流'-'
。我完成后,我可以通过tell
( $inh )
然后seek
()
保存当前位置。
通过使用该方法,我可以阅读__DATA__
sub中的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脚本文件做一些编程。我喜欢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