Perl MooseX::Method::Signatures 将自定义代码注入(inject)所有方法

标签 perl moose moosex-types

我正在尝试使用MooseX::Method::SignaturesMooseX::Declare在应用程序中,我的需要是在编译时而不是运行时在每个方法的开头注入(inject)自定义代码:

而不是这个:

use MooseX::Declare;

method check ($value) {
     $return $value;
}

我想在编译时在每个方法的开头注入(inject)一段代码,如下所示:

method check ($value) {
     my ($value) = $self->validate($value);
     $return $value;
}

现在我想要代码

my ($value) = $self->validate($value);

在编译时而不是运行时使用 MooseX::Decalre 模块在包中所有方法的开头自动注入(inject),我的意思是不使用 Moose 方法修饰符之前、之后、周围等。

这需要对这些模块进行修改,但我需要有人告诉我从哪里开始。

我能够修改模块 Method::Signatures::Simple为此,我给作者发了邮件要求修改,但没有得到回复。即使经过修改我也无法使用它,因为它不支持类型检查和像 MooseX::Declare 这样的默认值。

模块的修改版本Method::Signatures::Simple以下供引用,我的使用方式如下:

use Method::Signatures::Simple (method => 'method,action', function => 'function', invocant=>'$this', 'inject'=>'my ($me) = $this->me;');

现在在所有方法中,我都注入(inject)了代码 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;
}

最佳答案

MoopsKavorka提供与 MooseX::Declare 和 MooseX::Method::Signatures 几乎兼容的语法,并且被设计为通过特征非常可扩展(甚至从内部!)。我会提请您注意以下section of documentation for MooseX::Declare :

Warning: MooseX::Declare is based on Devel::Declare, a giant bag of crack originally implemented by mst with the goal of upsetting the perl core developers so much by its very existence that they implemented proper keyword handling in the core.

[...]

If you want to use declarative syntax in new code, please for the love of kittens get yourself a recent perl and look at Moops instead.

MooseX::Declare 本身并不是很容易扩展。我知道。 I've tried .

因此请牢记所有这些,并且因为我写了 Moops,所以我将使用它作为示例。这里我们定义了一个角色 Kavorka::TraitFor::Sub::ProvidesMe ,它将向方法中注入(inject)一点代码。然后,我们将该角色应用到使用 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"

关于Perl MooseX::Method::Signatures 将自定义代码注入(inject)所有方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23815446/

相关文章:

perl - MooseX::Types 声明问题,严格的测试用例:)

perl - MooseX::Types 强制转换和 $self

perl - 为什么 "use namespace::autoclean"比 "no Moose"更受欢迎?

perl - 将 Moose 别名与 MooseX::Constructor::AllErrors 一起使用

linux - (清理中)在全局销毁期间无法在未定义的值 Object/InsideOut.pm 行 1953 上调用方法 "FETCH"

perl - 如何从 localtime() 中提取时区

regex - 正则表达式从命令历史记录中获取已执行的脚本名称

perl - 提取每第n个数字

Perl Moose - 从配置文件加载值时的参数是什么?