在perl OO包中简化默认参数处理

时间:2011-10-04 11:31:35

标签: perl oop perl-module

以下是我所拥有的重要内容:

sub logger {
    my $self = shift;
    my %def =  (
        type => $self->{options}{name}, 
        severity => 1,
        date => $self->now(),
        message => ''  
    );
    my %opt = %def;
    if ( my $ref = shift ) {
        %opt = (%def, %{$ref});
    }
    croak('message is a required option') if $opt{message} eq '';
    warn($opt{type} . ': ' . $opt{message} . "\n") if ( $self->{_verbose} );
    # Do some other interesting things.
}

那么我可以这样称呼它:

$op->logger({message => 'Some message'});

因此,如果我的任何参数丢失,它们将获得我在%def hash中指定的默认值。如果缺少必需的参数,我就死了。

它的基础是我使用用户指定的内容重载def散列。

    if ( my $ref = shift ) {
        %opt = (%def, %{$ref});
    }

问题是他们可以在我的选项列表之外指定内容,或者发送散列而不是散列引用,标量或undef,或许多其他可能爆炸的方式。

我确信有更优雅的方法可以解决这个问题 我好像回想起一些使用ref()的代码,如果没有传入任何代码,它就不会爆炸。

3 个答案:

答案 0 :(得分:2)

Method::Signatures正是您正在寻找的,而且非常优雅

method logger (
    :$type     = $self->{options}{name},
    :$severity = 1,
    :$date     = $self->now,
    :$message! # No default and required, so croaks if not provided by caller.
) {
    my %opt = (
        type     => $type, 
        severity => $severity,
        date     => $date,
        message  => $message
    );
    # Do some other interesting things.
}

签名中的冒号指定名为参数(作为哈希传递)。 <{1}}后面的感叹号使其成为必需。

答案 1 :(得分:0)

如果穆斯对你来说太沉重,那么处理这个的优雅方式就是在穆斯,或者甚至是鼠标或者Moo中都很方便的捆绑。

答案 2 :(得分:0)

我想我会做那样的事情。毫无疑问,虽然有很多CPAN模块可以使这更简单。

sub logger {
    my $self = shift;

    # Set $ref to an empty hash ref if it's not given.
    # This makes a lot of later code far simpler
    my $ref = shift || {};

    # Check you have a hash ref
    unless (ref $ref eq 'HASH') {
        die "Argument to logger must be a hash ref";
    }

    my %def =  (
        type => $self->{options}{name}, 
        severity => 1,
        date => $self->now(),
        message => '',
    );


    my %opt = (%def, %$ref);

    # Now check we only have valid options. Assume that all valid
    # keys are in %def
    foreach (keys %opt) {
        delete $opt{$_} unless exists $def{$_};
    }

    croak('message is a required option') if $opt{message} eq '';
    warn($opt{type} . ': ' . $opt{message} . "\n") if ( $self->{_verbose} );
    # Do some other interesting things.
}