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

时间:2014-05-22 19:19:37

标签: perl moose moosex-types

我正在尝试在应用程序中使用MooseX::Method::SignaturesMooseX::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 =>   '功能',invocant =>' $ this',' inject' =>' my($ me)= $ this-> me ;&#39);

现在在所有方法中,我都会注入代码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 个答案:

答案 0 :(得分:3)

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

  

警告: MooseX :: Declare基于Devel :: Declare,这是一个最初由mst实施的一大堆破解,目的是让perl核心开发人员因为它们的存在而烦恼在核心中实施了适当的关键字处理。

     

[...]

     

如果你想在新代码中使用声明性语法,那么为了对小猫的喜爱,请让自己成为最近的perl,而不是看看Moops。

MooseX ::声明自己不是很容易扩展。我知道。 I've tried

因此,考虑到所有这些,并且因为我写了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"