package My::UNIVERSAL;
use base qw(Class::Data::Inheritable);
1;
####
package My::UNIVERSAL;
use strict;
use warnings;
use base qw(
Class::Data::Inheritable
Class::Accessor
);
1;
##
##
package Creature;
use base 'My::UNIVERSAL';
__PACKAGE__->mk_classdata( mortal => 1 );
__PACKAGE__->mk_accessors( qw/name gender/ );
1;
# in the code
my $creature = Creature->new({
name => 'Alice',
gender => 'female',
} );
##
##
$VAR1 = bless( {
gender => 'female',
name => 'Alice'
}, 'Creature' );
##
##
sub mk_accessors {
my ( $class, @accessors ) = @_;
foreach my $accessor (@accessors) {
no strict 'refs';
my $key = "$class\::$accessor";
*$key = sub {
my $self = shift;
return $self->{$key} unless @_;
$self->{$key} = shift;
return $self;
};
}
}
##
##
sub area {
my $self = shift;
return $self->height * $self->width;
}
##
##
use Scalar::Util 'reftype';
sub new {
my ( $class, $args ) = @_;
$args = {} unless defined $args;
unless ( 'HASH' eq reftype $args ) {
croak "Argument to new() must be a hash reference";
}
my $self = bless {} => $class;
while ( my ( $key, $value ) = each %$args ) {
$self->$key($value);
}
return $self;
}
##
##
$VAR1 = bless( {
'Creature::gender' => 'female',
'Creature::name' => 'Alice'
}, 'Creature' );
##
##
$creature->name('Bob')
->gender('unknown');
##
##
my $creature = Creature->new( {
name => 'Alice',
gender => 'female',
foo => 1,
} );
##
##
__PACKAGE__->mk_class_data('__data_key');
sub new {
my ( $class, $args ) = @_;
# XXX I don't like doing this for every instance, but
# use 'base' doesn't call import()
my $key = " $class data ";
$class->__data_key($key);
$args ||= {};
unless ( 'HASH' eq reftype $args ) {
croak('Argument to new() must be a hashref');
}
my $self = bless { $key => $args } => $class;
$self->_initialize;
delete $self->{$key};
return $self;
}
sub _initialize {
my $class = ref($_[0]);
croak "_initialize() must be overridden in a ($class)";
}
# a truly private method!
my $check_attribute = sub {
my ( $self, $attribute ) = @_;
my $value = delete $self->{ $self->__data_key }->{$attribute};
if ( ! defined wantarray ) {
$self->$attribute($value);
}
else {
return $value;
}
};
sub _must_have {
my ( $self, $attribute ) = @_;
croak("Mandatory attribute ($attribute) not found")
unless exists $self->{ $self->__data_key }->{$attribute};
goto $check_attribute;
}
sub _may_have {
my ( $self, $attribute ) = @_;
return unless exists $self->{ $self->__data_key }->{$attribute};
goto $check_attribute;
}
##
##
package Creature;
use base 'My::UNIVERSAL';
__PACKAGE__->mk_classdata( mortal => 1 );
__PACKAGE__->mk_accessors(qw/name gender/);
sub _initialize {
my ( $self, $args ) = @_;
$self->_must_have('name');
$self->_may_have('gender');
}
##
##
package IP::Address;
use base 'My::Universal';
__PACKAGE__->mk_accessors('address');
sub _initialize {
my $self = shift;
$self->address( $self->_must_have('ip') );
}
1;
#
use IP::Address;
my $ip = IP::Address->new({ ip => $some_ip });
print $ip->address; # prints $some_ip
##
##
my $check_keys = sub {
my $self = shift;
my $data = delete $self->{ $self->__data_key };
if ( my @keys = keys %$data ) {
local $" = ', ';
croak("Unknown keys to constructor: (@keys)");
}
};
sub new {
my ( $class, $args ) = @_;
my $key = " $class data ";
$class->__data_key($key);
$args ||= {};
unless ( 'HASH' eq reftype $args ) {
croak('Argument to new() must be a hashref');
}
my $self = bless { $key => $args } => $class;
$self->_initialize;
$self->$check_keys;
return $self;
}
##
##
my $creature = Creature->new( {
name => 'Alice',
gender => 'female',
foo => 1,
bar => 1,
} );
# Unknown keys to constructor: (bar, foo)
##
##
package Tall::Square;
use Scalar::Util 'looks_like_number';
use base 'My::UNIVERSAL';
__PACKAGE__->mk_accessors(
width => sub { looks_like_number($_[1]) && $_[1] > 0 ),
height => sub {
my ( $self, $height ) = @_;
return looks_like_number($height) && $height > $self->width;
},
);
sub _initialize {
my $self = shift;
$self->_must_have('height');
$self->_must_have('width');
}
sub area {
my $self = shift;
return $self->height * $self->width;
}
1;
##
##
package My::UNIVERSAL;
use strict;
use warnings;
use Scalar::Util 'reftype';
use Carp 'croak';
use base qw(Class::Data::Inheritable);
__PACKAGE__->mk_classdata('__data_key');
sub mk_accessors {
my ( $class, @accessors ) = @_;
foreach my $accessor (@accessors) {
no strict 'refs';
my $key = "$class\::$accessor";
*$key = sub {
my $self = shift;
return $self->{$key} unless @_;
$self->{$key} = shift;
return $self;
};
}
}
my $check_keys = sub {
my $self = shift;
my $data = delete $self->{ $self->__data_key };
if ( my @keys = keys %$data ) {
local $" = ', ';
croak("Unknown keys to constructor: (@keys)");
}
};
sub new {
my ( $class, $args ) = @_;
my $key = " $class data ";
$class->__data_key($key);
$args ||= {};
unless ( 'HASH' eq reftype $args ) {
croak('Argument to new() must be a hashref');
}
my $self = bless { $key => $args } => $class;
$self->_initialize;
$self->$check_keys;
return $self;
}
sub _initialize {
my $class = ref($_[0]);
croak "_initialize() must be overridden in a ($class)";
}
my $check_attribute = sub {
my ( $self, $attribute ) = @_;
my $value = delete $self->{ $self->__data_key }->{$attribute};
if ( !defined wantarray ) {
$self->$attribute($value);
}
else {
return $value;
}
};
sub _must_have {
my ( $self, $attribute ) = @_;
croak("Mandatory attribute ($attribute) not found")
unless exists $self->{ $self->__data_key }->{$attribute};
goto $check_attribute;
}
sub _may_have {
my ( $self, $attribute ) = @_;
return unless exists $self->{ $self->__data_key }->{$attribute};
goto $check_attribute;
}
1;