use strict; use warnings; package OptionsBase; sub new { my ($class, %options) = @_; my $self = bless \%options, $class; $self->{headingsLU} = {map {$_ => 1} @{$options{headings}}}; return $self; } sub load { my ($self) = @_; open my $fIn, '<', $self->{file} or die ("Can't open $self->{file}: $!"); while (defined (my $line = <$fIn>)) { chomp $line; my ($rowName, @values) = split (/\|/, $line); $self->{options}{$rowName}{sort_number} = $. if $self->{sort}; for my $heading (@{$self->{headings}}) { $self->{rows}{$rowName}{$heading} = shift @values || ''; } } } sub save { my ($self) = @_; open my $fOut, '>', $self->{file} or die ("Can't create $self->{file}: $!"); for my $key (keys %{$self->{rows}}) { my @values = map {defined $_ ? $_ : ''} @{$self->{rows}{$key}}{@{$self->{headings}}}; print $fOut join ('|', $key, @values), "\n"; } } sub setOptions { my ($self, $key, %options) = @_; my @badOptions = grep {!exists $self->{headingsLU}{$_}} keys %options; die "Bad options: @badOptions\n" if @badOptions; @{$self->{rows}{$key}}{keys %options} = values %options; } sub getOptions { my ($self, $key, @options) = @_; my @badOptions = grep {!exists $self->{headingsLU}{$_}} @options; die "Bad options: @badOptions\n" if @badOptions; die "No such row: $key\n" if !exists $self->{rows}{$key}; return map {$_ => $self->{rows}{$key}{$_}} @options; } package TwitterOptions; push @TwitterOptions::ISA, 'OptionsBase'; sub new { my ($class, %options) = @_; return $class->SUPER::new( name => 'Twitter', file => 'account_totals.txt', headings => [qw(screen_name followers friends updates)], %options ); } package main; my $obj = TwitterOptions->new(); $obj->setOptions('joe', screen_name => 'Joe', followers => 'Freida'); $obj->save(); my $another = TwitterOptions->new(); $another->load(); my %options = $another->getOptions('joe', 'screen_name', 'followers'); print "$options{screen_name}'s followers are: $options{followers}\n"; #### Joe's followers are: Freida