#!/usr/local/bin/perl use strict; use warnings; use Player; my $player = Player->new('vx' => -1); for (keys %$player) { print "$_: ", $player->{$_}, $/; } #### package Player; use Mover; @Player::ISA = qw(Mover); use strict; sub defaults { my $defaults = { 'symbol' => '_', 'score' => 0, } } 1; #### package Mover; use Object; @Mover::ISA = qw(Object); use strict; sub defaults { my $defaults = { 'symbol' => '?', # override this in subclasses 'x' => 0, # x-coordinate 'y' => 0, # y-coordinate 'vx' => 0, # velocity in x-direction 'vy' => 0, # velocity in y-direction 'shown' => 1, # still alive? } } 1; #### package Object; use strict; sub new { my ($caller, %args) = @_; my ($self, $class); $class = ref $caller; $class ||= $caller; $self = bless {}, $class; $self->init(\%args); return $self; } sub init { my ($self, $args) = @_; my ($defaults); # See if superclass has defaults if ($self->can('SUPER::defaults')) { $defaults = $self->SUPER::defaults(); } # Let current class override superclass if ($self->can('defaults')) { my $current_defaults = $self->defaults(); for my $attr (keys %$current_defaults) { $defaults->{$attr} = $current_defaults->{$attr}; } } # Set default values if (ref($defaults) eq 'HASH') { for my $attr (keys %$defaults) { $self->{$attr} = $defaults->{$attr}; } } # If %args are given to new(), use those instead for my $attr (keys %$args) { $self->{$attr} = $args->{$attr}; } } 1; #### $ ./test.pl score: 0 vx: -1 symbol: _