# Build and require the subclass for this type:
my $class = __PACKAGE__ . "::" . $opts{type};
eval "require $class";
if ($@) {
Carp::carp("Part type '$opts{type}' unknown");
return undef;
}
# Build the Part object template:
my $self = {
# name provided directly, or implicitly by type.
name => $opts{name} // $opts{type},
};
# Bless into the determined subclass for this type:
bless $self, $class;
####
use strict;
use warnings;
require Carp;
use lib 'lib';
require Widget;
# Create a new widget.
my $w = Widget->new
or Carp::confess("new widget failed");
# Add a part of type 'Cog' to this widget, named 'cog-62'
my $part = $w->addPart(type=>'Cog', name=>'cog-62')
or Carp::confess("addPart failed");
# Show some info about the part just added:
printf( "part name is: %s, of class: %s\n",
$part->name(),
ref($part)
);
####
package Widget;
use strict;
use warnings;
require Carp;
require Widget::Part;
sub new {
my $class = shift;
$class = ref($class) || $class;
my $self = {
parts => { },
};
bless $self, $class;
return $self;
}
sub addPart {
my $self = shift;
my %opts = (@_);
# Create the new part:
my $part;
unless ( $part = Widget::Part->new(%opts) ) {
Carp::carp("unable to add Widget part");
return undef;
}
$self->{parts}{$opts{type}} = $part;
return $part; # use as bool or ref to part object.
}
1;
####
package Widget::Part;
use strict;
use warnings;
require Carp;
sub new {
shift; # throw away this class. We won't use it.
my %opts = (@_);
# Must have a part 'type' for success.
unless (defined $opts{type}) {
Carp::carp("no part type provided");
return undef;
}
# Build and require the subclass for this type:
my $class = __PACKAGE__ . "::" . $opts{type};
eval "require $class";
if ($@) {
Carp::carp("Part type '$opts{type}' unknown");
return undef;
}
# Build the Part object template:
my $self = {
# name provided directly, or implicitly by type.
name => $opts{name} // $opts{type},
};
# Bless into the determined subclass for this type:
bless $self, $class;
# Call subclass initilization code:
$self->init();
return $self;
}
# Basic example accessor: return this part's name.
sub name {
my $self = shift;
return $self->{name};
}
1;
####
package Widget::Part::Cog;
use strict;
use warnings;
use parent 'Widget::Part';
sub init {
my $self = shift;
# Additional 'Cog' attributes would be set up here.
# Omitted for example brevity.
}
1;