package Particle; use strict; use warnings; use Data::Dumper; $Data::Dumper::Deepcopy = 1; $Data::Dumper::Sortkeys = 1; our %param; our %REGISTRY; sub new { my $class = shift; $param{is_movable} = 0; @{ $param{history} } = (); $param{position} = { x => 0, y => 0, z => 0, }; $param{movement} = { dx => 0, dy => 0, dz => 0, }; $param{is_active} = 0; my $self = bless \%param, $class; if ( scalar @_ ) { $self->init(@_); } $REGISTRY{$self} = $self; # my $format_str = qq{Class: %s\n\tKey: %s\n\tref(): %s\n}; # my $t = ref( $REGISTRY{$self} ); # print sprintf $format_str, $class, $self, $t; return $self; } sub init { my $self = shift; my ($data) = @_; foreach my $k ( keys %{$data} ) { $self->set( $k, \$data->{$k} ); } } sub get { my $self = shift; my $k = shift; if ( $k =~ m/^p_?(.)/i ) { return $self->{position}{$1}; } elsif ( $k =~ m/^m_?d?(.)/i or $k =~ m/^d(.)/i ) { return $self->{movement}{ q{d} . $1 }; } elsif ( $k =~ m/^is_a/i ) { return $self->{is_active}; } elsif ( $k =~ m/^is_m/i ) { return $self->{is_movable}; } elsif ( $k =~ m/^h_?(\d+)/i ) { return $self->{history}[$1]; } elsif ( $k =~ m/^hc/i ) { return scalar @{ $self->{history} }; } } sub set { my $self = shift; my $k = shift; if ( $k =~ m/^h_?self/i ) { push @{ $self->{history} }, { time => time, position => \$self->{position}, movement => \$self->{movement}, }; return; } my $v = shift; if ( ref $v eq q{REF} ) { if ( $k =~ m/^position/i ) { $self->{position} = $$v; } elsif ( ref $v eq q{REF} and $k =~ m/^movement/i ) { $self->{movement} = $$v; } } else { if ( $k =~ m/^p_?(.)/i ) { $self->{position}{$1} = $v; } elsif ( $k =~ m/^m_?d?(.)/i or $k =~ m/^d(.)/i ) { $self->{movement}{ q{d} . $1 } = $v; } elsif ( $k =~ m/^is_a/i ) { $self->{is_active} = $v; } elsif ( $k =~ m/^is_m/i ) { $self->{is_movable} = $v; } elsif ( $k =~ m/^h_?(\d+)/i ) { $self->{history}[$1] = $v; } elsif ( $k =~ m/^h/i ) { push @{ $self->{history} }, $v; } } } sub total_count { my $class = shift; print __FILE__, q{:}, __LINE__, q{ }, $class, qq{\n}; # print Data::Dumper->Dump( # [ \%REGISTRY, ], # [ qw( *REGISTRY ) ] # ), qq{\n}; my $format_str = qq{Class: %s\n\tKey: %s\n\tref(): %s\n}; foreach my $k ( keys %REGISTRY ) { my $t = ref( $REGISTRY{$k} ); print sprintf $format_str, $class, $k, $t; } return scalar grep { ref( $REGISTRY{$_} ) eq $class } keys %REGISTRY; } 1; #### package MoveableParticle; use parent 'Particle'; use Data::Dumper; $Data::Dumper::Deepcopy = 1; $Data::Dumper::Sortkeys = 1; our @ISA = ( 'Particle', ); our %REGISTRY; sub new { my $class = shift; my $self = $class->SUPER::new( @_ ); $self->set( 'is_moveable', 1 ); return $self; } 1; #### package StationaryParticle; use parent 'Particle'; use Data::Dumper; $Data::Dumper::Deepcopy = 1; $Data::Dumper::Sortkeys = 1; our @ISA = ( 'Particle', ); our %REGISTRY; sub new { my $class = shift; my $self = $class->SUPER::new( @_ ); $self->set( 'is_moveable', 0 ); return $self; } 1; #### #!/usr/bin/perl use strict; use warnings; use Carp::Always; use Data::Dumper; use Test::More; use StationaryParticle; use MoveableParticle; $| = 1; srand(); $Data::Dumper::Deepcopy = 1; $Data::Dumper::Sortkeys = 1; my @particles; push @particles, MoveableParticle->new( { position => { x => 10, y => 10, z => 10, }, movement => { dx => 5, dy => -5, dz => 0, }, } ); # print Data::Dumper->Dump( [ \@particles, ], [ qw( *particles ) ] ), # qq{\n}; $particles[0]->set( 'is_active', 0, ); isa_ok( $particles[0], 'MoveableParticle' ); isa_ok( $particles[0], 'Particle' ); isa_ok( $particles[0], 'StationaryParticle' ); print qq{Object 0: }, ref( $particles[0] ), qq{\n}; print qq{\n}; push @particles, StationaryParticle->new( { position => { x => 20, y => 20, z => 0, }, }, ); isa_ok( $particles[1], 'MoveableParticle' ); isa_ok( $particles[1], 'Particle' ); isa_ok( $particles[1], 'StationaryParticle' ); print qq{Object 1: }, ref( $particles[1] ), qq{\n}; print qq{\n}; # print Data::Dumper->Dump( [ \@particles, ], [ qw( *particles ) ] ), # qq{\n}; print qq{Particle count: }, Particle->total_count, qq{\n}; print qq{\n}; print qq{Stationary particle count: }, StationaryParticle->total_count, qq{\n}; print qq{\n}; print qq{Moveable particle count: }, MoveableParticle->total_count, qq{\n}; print qq{\n}; Test::More::done_testing(); #### Class: MoveableParticle Key: MoveableParticle=HASH(0x264e050) ref(): MoveableParticle ok 1 - The object isa MoveableParticle ok 2 - The object isa Particle not ok 3 - The object isa StationaryParticle # Failed test 'The object isa StationaryParticle' # at module_test.20140103.pl line 28. # The object isn't a 'StationaryParticle' it's a 'MoveableParticle' Object 0: MoveableParticle Class: StationaryParticle Key: StationaryParticle=HASH(0x264e050) ref(): StationaryParticle not ok 4 - The object isa MoveableParticle # Failed test 'The object isa MoveableParticle' # at module_test.20140103.pl line 35. # The object isn't a 'MoveableParticle' it's a 'StationaryParticle' ok 5 - The object isa Particle ok 6 - The object isa StationaryParticle Object 1: StationaryParticle Particle.pm:307 Particle Class: Particle Key: StationaryParticle=HASH(0x264e050) ref(): StationaryParticle Class: Particle Key: MoveableParticle=HASH(0x264e050) ref(): StationaryParticle Particle count: 0 Particle.pm:307 StationaryParticle Class: StationaryParticle Key: StationaryParticle=HASH(0x264e050) ref(): StationaryParticle Class: StationaryParticle Key: MoveableParticle=HASH(0x264e050) ref(): StationaryParticle Stationary particle count: 2 Particle.pm:307 MoveableParticle Class: MoveableParticle Key: StationaryParticle=HASH(0x264e050) ref(): StationaryParticle Class: MoveableParticle Key: MoveableParticle=HASH(0x264e050) ref(): StationaryParticle Moveable particle count: 0 1..6 # Looks like you failed 2 tests of 6.