[Catalyst] Attribute::Handlers wont work in own classes under
catalyst
Felix Antonius Wilhelm Ostmann
ostmann at websuche.de
Wed Aug 29 18:54:46 GMT 2007
OK, first the problem:
we have build some classes with Attribute::Handlers (was inspired from
Attribute::Property)
This works realy fine!
after a few tests we gone use this classes under catalyst ... and ...
dont work :-/ under catalyst our classes dont use Attribute::Handlers
:-/ we declare UNIVERSAL::Property and then use "sub nondigit : Property
{ defined && !m{[0-9]} }" (see the code)
then you can call: $obj->nondigit(4) and it will croak or
$obj->nondigit("car") and it will set the object-property nondigit to "car".
under catalyst he ignore the redefined sub in UNIVERSAL::Property ...
no, he dont call UNIVERSAL::Property to redefine sub :-/
MfG
Felix Ostmann
OK, here the code, you can test it with (works):
perl -d -MData::Dumper -MmyExample -e 'my $e = myExample->create();
$e->nondigit("car"); print Dumper($e);'
or
perl -d -MData::Dumper -MmyExample -e 'my $e = myExample->create();
$e->nondigit(4); print Dumper($e);'
under catalyst (wont work):
sub default : Private {
my ($self, $c) = @_;
use myExample;
use Data::Dumper;
my $e = myExample->create();
$e->nondigit("car");
$c->response->body( Dumper($e) );
}
CODE:
package myExample;
use strict;
use warnings;
use 5.006;
use Attribute::Handlers;
use Carp qw/carp croak/;
$Carp::Internal{q/Attribute::Handlers/}++; # may we be forgiven for our
sins
$Carp::Internal{+__PACKAGE__}++;
sub UNIVERSAL::Property : ATTR(CODE) {
my (undef, $self_glob, $check_code) = @_;
ref($self_glob)
or croak "Cannot use property attribute with anonymous sub";
my $property = *$self_glob{NAME};
defined(&$self_glob)
or undef $check_code;
no warnings 'redefine';
*$self_glob = sub {
(my $self, local $_) = @_;
if( @_ == 1 ) {
exists($self->{_property}->{_current}->{$property})
or croak "Property $property not loaded";
return $self->{_property}->{_current}->{$property};
}
if( @_ == 2 ) {
ref($_)
and croak "Invalid value for $property property, no refs";
# Property wurde geladen, sonst Abbruch
$self->{_in_storage} &&
!exists($self->{_property}->{_storage}->{$property})
and croak "Property $property not loaded";
my $value = $_;
# überprüfe neuen Wert auf Gültigkeit, sonst Abbruch
defined($check_code) && !$check_code->($self, $_)
and croak "Invalid value for $property property";
if( !defined($self->{_in_storage}) ) {
# status "schammig"es Objekt, dann alles laden als "from
storage"
# ist neuer Wert != alter Wert, warnung ausgeben
if( defined($_) ^ defined($value) or defined($_) && $_
ne $value ) {
carp "Property $property from database are
inconsistent";
$self->{_property}->{_storage}->{$property} = $value;
}
else {
$self->{_property}->{_storage}->{$property} = $_;
}
}
# wenn Objekt in der Datenbank
elsif( $self->{_in_storage} ) {
# lösche dirty-Status, wird neu berechnet
delete($self->{_property}->{_dirty}->{$property});
# ist neuer Wert != alter Wert, dirty-Status neu setzten
defined($_) ^
defined($self->{_property}->{_storage}->{$property})
and $self->{_property}->{_dirty}->{$property} = undef;
# ist neuer Wert != alter Wert, dirty-Status neu setzten
defined($_) && $_ ne
$self->{_property}->{_storage}->{$property}
and $self->{_property}->{_dirty}->{$property} = undef;
}
# wenn nicht in der Datenbank
else {
# auf jeden Fall auf dirty setzten
$self->{_property}->{_dirty}->{$property} = undef
}
return $self->{_property}->{_current}->{$property} = $_;
}
croak "Too many arguments for $property method";
};
}
sub new {
my ($class, @args) = @_;
@args
and croak q{Can't call method "new" with arguments};
my $self = {
_property => {
_current => {},
_storage => {},
_dirty => {},
},
_in_storage => undef,
};
bless($self, $class);
return $self;
}
sub create {
my ($class, @args) = @_;
@args % 2
and croak "wrong count of arguments";
my %customer_row = @args;
# erstelle Objekt und setzte übergebene Parameter
my $self = $class->new();
$self->in_storage(0);
$self->$_($customer_row{$_}) for( keys(%customer_row) );
return $self;
}
sub in_storage {
my ($self, $in_storage) = @_;
if( @_ == 1 ) {
return $self->{_in_storage};
}
if( @_ == 2 ) {
if( !defined($in_storage) ) {
$self->{_property}->{_storage}->{$_} =
$self->{_property}->{_current}->{$_} for( $self->is_changed );
$self->{_property}->{_dirty} = {};
}
return $self->{_in_storage} = $in_storage;
}
}
sub is_changed {
my ($self, $property) = @_;
return keys(%{$self->{_property}->{_dirty}}) if( !defined($property) );
return 1 if(
exists($self->{_property}->{_dirty}->{$property}) );
return 0;
}
## PROPERTIES
sub undef_or_digit : Property { !defined || m{^\d+$} };
sub nondigit : Property { defined && !m{\d} };
1;
More information about the Catalyst
mailing list