Subject: | evaluating Perl code |
It is a great idea, but implementation is not very good now.
Run v0.038, file Runner.pm:
sub _eval_cmd {
my ( $self, $code, $params, $dry_run ) = @_;
<...>
$code = $self->build_formatter($params)->format($code);
<...>
my $sub = sub { eval $code };
$sub->($self);
if ($@) {
<...>
}
}
1. Variable $@ is not localized. It should be "local $@;" before eval.
2. User code sees all the local variables: $self, $code, $params, $dry_run. It has some drawbacks: if user code (accidentally) changes $self, it will break plugin and entire dzil:
[Run::BeforeBuild]
eval = undef $self; die;
But if $self properly documented, it can be an advantage: instead of long explanations that shift operates on @ARGV, and user should use $_[0] to get reference to plugin object, you could simply document that within the user code $self variable contains reference to plugin object. Alternatively, you may want to set $plugin and $dist variables, like GenerateFile and GatherDir::Template plugins (TemplateFile plugin sets $dist too).
Also, this feature can be used instead of %a, %d, %p and other placeholders. This is a Perl code, no need in introducing %x: in Perl code $^X works. Similarly, %t is not much shorter than $dist->is_trial, %v — $dist->version, etc. For convenience, you may provide variables $p, $v, etc — just create these variables before eval. It also will look more naturally in Perl code, than hashes %a, %d, %p. It will be also more portable. Imagine that someone used in his code variable %y:
my %y = ...;
In current version of Run it will work. If later you decide to introduce %y placeholder, it will break user code, while predefined $y variable will continue to work — user code will just ignore predefined value and declare own variable.