2016-09-15 75 views
1

對於Perl Moo對象的某些字段,我想在將空字符串分配給undef字段時將其替換爲空字符串。在Perl Moo對象中自動將空字符串轉換爲undef

這就是我想要的:$obj->x("")使字段x未定義。

請幫助開發一個這樣做的Moo擴展。


一個可能的方式做到這一點:

sub make_field_undef { 
    my ($class, $field_name) = @_; 
    eval "package $class"; 
    around $field_name => sub { 
    my $orig = shift; 
    my $self = shift; 
    my @args = @_; 
    if(@args >= 1) { 
     $args[0] = undef if defined $args[0] && $args[0] eq ''; 
    } 
    $orig->($self, @args); 
    }; 
} 

但是否有「更多的結構化」或「更具聲明」的方式來做到這一點?任何其他方式來做到這一點?


下面是我的一個完整的例子。但運行它產生的錯誤,我不明白:

package UndefOnEmpty; 
use Moo; 

sub auto_undef_fields {() } 

sub make_fields_undef { 
    my ($class) = @_; 
    eval "package $class"; 
    around [$class->auto_undef_fields] => sub { 
    my $orig = shift; 
    my $self = shift; 
    my @args = @_; 
    if(@args >= 1) { 
     $args[0] = undef if defined $args[0] && $args[0] eq ''; 
    } 
    $orig->($self, @args); 
    }; 
    around 'BUILD' => { 
    my ($self, $args) = @_; 
    foreach my $field_name ($class->auto_undef_fields) { 
     $args->{$field_name} = undef if defined $args->{$field_name} && $args->{$field_name} eq ""; 
    } 
    }; 
} 

1; 

用例:

#!/usr/bin/perl 

package X; 
use Moo; 
use lib '.'; 
extends 'UndefOnEmpty'; 
use Types::Standard qw(Str Int Maybe); 
use Data::Dumper; 

has 'x' => (is=>'rw', isa=>Maybe[Str]); 
has 'y' => (is=>'rw', isa=>Maybe[Str]); 

sub auto_undef_fields { qw(x y) } 
__PACKAGE__->make_fields_undef; 

my $obj = X->new(x=>""); 
$obj->y(""); 
print Dumper $obj->x, $obj->y; 

下面是錯誤:

$ ./test.pl 
"my" variable $class masks earlier declaration in same scope at UndefOnEmpty.pm line 20. 
"my" variable $args masks earlier declaration in same statement at UndefOnEmpty.pm line 21. 
"my" variable $field_name masks earlier declaration in same statement at UndefOnEmpty.pm line 21. 
"my" variable $args masks earlier declaration in same statement at UndefOnEmpty.pm line 21. 
"my" variable $field_name masks earlier declaration in same statement at UndefOnEmpty.pm line 21. 
syntax error at UndefOnEmpty.pm line 20, near "foreach " 
Compilation failed in require at /usr/share/perl5/Module/Runtime.pm line 317. 

請幫忙瞭解什麼是的原因錯誤。

+2

這不是一個代碼寫入服務。這是爲了解決特定的代碼問題。請告訴我們你已經擁有了什麼,並解釋你遇到的具體問題。 – stevieb

+1

我會很樂意幫助你,但你還沒有做任何事情,所以我沒有看到我能做些什麼來幫助。 – Borodin

+0

我已經添加了我的解決方案嘗試 – porton

回答

2

爲什麼不使用強制coerce屬性in has?這似乎是最簡單直接的方法。

package Foo; 
use Moo; 

has bar => (
    is  => 'rw', 
    coerce => sub { $_[0] eq q{} ? undef : $_[0] }, 
); 

下面是對象的外觀。

package main; 
use Data::Printer; 
p my $foo1 = Foo->new(bar => q{}); 
p my $foo2 = Foo->new(bar => 123); 
p my $foo3 = Foo->new; 

__END__ 

Foo { 
    Parents  Moo::Object 
    public methods (2) : bar, new 
    private methods (0) 
    internals: { 
     bar undef 
    } 
} 
Foo { 
    Parents  Moo::Object 
    public methods (2) : bar, new 
    private methods (0) 
    internals: { 
     bar 123 
    } 
} 
Foo { 
    Parents  Moo::Object 
    public methods (2) : bar, new 
    private methods (0) 
    internals: {} 
} 

在穆斯你也可以定義自己的類型,從你Str派生並有一個內置的脅迫。然後,您可以創建該類型的所有屬性並開啓強制。

爲了使Moo的行爲如此,請查看has的文檔和屬性isa,這正好在coerce(以上鍊接)之上。