Perl MooseX::Method::Signatures внедряет пользовательский код во все методы
Я пытаюсь использовать MooseX::Method::Signatures и MooseX::Declare в приложении, мне нужно внедрить пользовательский код в начале каждого метода во время компиляции, а не во время выполнения:
вместо этого:
use MooseX::Declare;
method check ($value) {
$return $value;
}
Я хочу внедрить код в начале каждого метода во время компиляции, чтобы быть таким:
method check ($value) {
my ($value) = $self->validate($value);
$return $value;
}
теперь я хочу код
my ($value) = $self->validate($value);
быть введенным автоматически в начале всех методов в пакете, использующих модуль MooseX:: Decalre во время компиляции, а не во время выполнения, я имею в виду не использовать модификаторы метода Moose до, после, вокруг и т. д.
Это требует модификации этих модулей, но мне нужен кто-то, кто скажет мне, с чего начать.
Я смог изменить модуль Method::Signatures::Simple, чтобы сделать это точно, и отправил письмо автору для модификации, но не получил ответа. Причина, по которой я не могу использовать это даже с модификацией, потому что она не поддерживает проверку типов и значения по умолчанию, такие как MooseX::Declare.
Модифицированная версия модуля Method::Signatures::Simple приведена ниже для справки, и я использую ее следующим образом:
используйте Method::Signatures::Simple (method => 'method,action', function => 'function', invocant=>'$this', 'inject'=>'my ($me) = $this->me;');
теперь во всех методах я получаю код my ($me) = $this->me;
впрыскивается, и я просто могу использовать это так:
method check ($value) {
say $me
}
Вот модифицированный метод Method::Signatures::Simple.
package Method::Signatures::Simple;
{
$Method::Signatures::Simple::VERSION = '1.07';
}
use warnings;
use strict;
=head1 NAME
Method::Signatures::Simple - Basic method declarations with signatures, without source filters
=head1 VERSION
version 1.07
=cut
use base 'Devel::Declare::MethodInstaller::Simple';
our $inject_code;
sub import {
my $class = shift;
my %opts = @_;
$opts{into} ||= caller;
my $meth = delete $opts{name} || delete $opts{method};
my $func = delete $opts{function};
my $invocant = delete $opts{invocant} || '$self';
$inject_code = delete $opts{inject};
$inject_code .= ";" if ($inject_code && $inject_code !~ /\;$/);
# if no options are provided at all, then we supply defaults
unless (defined $meth || defined $func) {
$meth = 'method';
$func = 'func';
}
my @meth = split /\s*\,+\s*/, $meth;
# we only install keywords that are requested
foreach $meth (@meth) {
if (defined $meth) {
$class->install_methodhandler(
name => $meth,
invocant => $invocant,
%opts,
);
}
}
if (defined $func) {
$class->install_methodhandler(
name => $func,
%opts,
invocant => undef,
);
}
}
sub strip_proto {
my $self = shift;
my ($proto) = $self->SUPER::strip_proto()
or return '';
# we strip comments and newlines here, and stash the number of newlines.
# we will re-inject the newlines in strip_attrs(), because DD does not
# like it when you inject them into the following code block. it does not
# object to tacking on newlines to the code attribute spec though.
# (see the call to inject_if_block() in DD::MethodInstaller::Simple->parser)
$proto =~ s/\s*#.*$//mg;
$self->{__nls} = $proto =~ s/[\r\n]//g;
$proto;
}
sub strip_attrs {
my $self = shift;
my ($attrs) = $self->SUPER::strip_attrs();
$attrs ||= '';
$attrs .= $/ x $self->{__nls} if $self->{__nls};
$attrs;
}
sub parse_proto {
my $self = shift;
my ($proto) = @_;
$proto ||= '';
$proto =~ s/\s*#.*$//mg;
$proto =~ s/^\s+//mg;
$proto =~ s/\s+$//mg;
$proto =~ s/[\r\n]//g;
my $invocant = $self->{invocant};
$invocant = $1 if $proto =~ s{(\$\w+)\s*:\s*}{};
my $inject = '';
$inject .= "my ${invocant} = shift;" if $invocant;
$inject .= "my ($proto) = \@_;" if defined $proto and length $proto;
$inject .= "$inject_code" if $inject_code;
$inject .= '();'; # fix for empty method body
return $inject;
}
1 ответ
Moops и Kavorka предоставляют синтаксис, практически совместимый с MooseX:: Declare и MooseX:: Method:: Signatures, и предназначены для очень расширяемого (даже изнутри!) Характера. Обращу ваше внимание на следующий раздел документации для MooseX:: Declare:
Предупреждение: MooseX:: Declare основан на Devel::Declare, гигантской сумке взлома, изначально реализованной mst с целью огорчить разработчиков Perl-ядра тем, что они сами реализовали правильную обработку ключевых слов в ядре.
[...]
Если вы хотите использовать декларативный синтаксис в новом коде, пожалуйста, ради любви к котятам, приобретите свежую версию Perl и вместо этого посмотрите на Moops.
MooseX:: Объявить себя не очень легко расширить. Я знаю. Я пробовал
Поэтому, учитывая все это, а также потому, что я написал Moops, я буду использовать это в качестве примера. Здесь мы определяем роль Kavorka::TraitFor::Sub::ProvidesMe
который вставит немного кода в метод. Затем мы применяем эту роль к методу, используя does ProvideMe
,
package main;
use Moops;
role Kavorka::TraitFor::Sub::ProvideMe
{
around inject_prelude (@_)
{
my $prelude = $self->$next(@_);
$prelude .= 'my ($me) = $self->me;();';
return $prelude;
}
}
class MyClass
{
method me () { "tobyink" }
method example () does ProvideMe
{
# This gets injected: my ($me) = $self->me;
return $me;
}
}
my $obj = MyClass->new;
say $obj->example; ## says "tobyink"