package Employee { use Moo; # loads strict and warnings and provides new() has name => (is => 'ro'); has [qw/wage hours/] => (is => 'rw'); }; package Employees { use Employee; use Moo; use namespace::clean; has _db => ( # code can be swapped later when there is a real DB is => 'rwp', default => sub { +{} }, ); sub add { my $self = shift; my $args = shift; # argument validation needed here $self->_db->{ $args->{name} } = $args; } sub find { my $self = shift; my $name = shift; # argument validation needed here my $record = $self->_db->{ $name } or die "$name not found"; return Employee->new( name => $name, wage => $record->{wage}, hours => $record->{hours}, ); } sub avg_hourly_wage { my $self = shift; my ($total_hours, $total_wages); for my $name (keys %{ $self->_db }) { $total_hours += $self->_db->{ $name }{hours}; $total_wages += $self->_db->{ $name }{wage} * $self->_db->{ $name }{hours}; } return sprintf('%d.2', $total_wages / $total_hours); } sub pay_change_for { my $self = shift; my $employee = shift; my $new_wage = shift; $employee->wage($new_wage); $self->_db->{ $employee->name }->{wage} = $new_wage; } }; #------------------------------------# use strict; use warnings; use feature 'say'; use Employee; use Employees; my $employees = Employees->new; for my $line () { chomp $line; my ($name, $wage, $hours) = split /,/, $line; $employees->add({ name => $name, wage => $wage, hours => $hours, }); } say 'Query for an employee: '; chomp( my $name = ); my $employee = $employees->find($name); say sprintf('%s earns %s for %s hours', map { $employee->$_ } qw/name wage hours/); say 'The average hourly wage overall is ' . $employees->avg_hourly_wage; say "Give $name a raise? Enter new wage or 'No'"; chomp( my $answer = ); if ($answer =~ /^\d+$/) { $employees->pay_change_for($employee, $answer); } else { say 'No change'; } say 'The average hourly wage overall is now ' . $employees->avg_hourly_wage; __DATA__ Fred Flinstone,10,40 Barney Rubble,8,40 Dino Flintstone,15,40 Bam-Bam Rubble,5,12 Mr. Slate,65,32