package Data_holder; =head CONSTRUCTOR Nothing terribly exciting here. All we do is bless a hashref, embed a data hash, and store two hashes that map attribute names to the names of the methods that will handle them. =cut sub new { my $O = bless {}, shift; $O->{'data'} = {}; $O->{'get-funcs'} = { 'key-1' => 'get_normal', 'key-2' => 'get_synthetic', }; $O->{'set-funcs'} = { 'key-1' => 'set_normal', 'key-2' => 'set_synthetic', }; return ($O); } =head1 DISPATCH FUNCTIONS =over 4 =item get (list) : hash This is the inspection routine. It takes a list of attribute names as input, and returns a hash of named values as output. It does its job by calling functions identified in {'get-funcs'}. =cut sub get { my ($O, @keys) = @_; my $result = {}; for my $k (@keys) { my $func = $O->{'get-funcs'}->{ $k } || 'get_error'; $result->{ $k } = $O->$func ( $k ); } return ($result); } =item set (hash) : hash This is the storage function. It takes a hash of named values as input, and returns a hash of result codes as output. It does its job by calling functions identified in {'set-funcs'}. =cut sub set { my ($O, $args) = @_; my $result = {}; for my $k (keys %$args) { my $func = $O->{'set-funcs'}->{ $k } || 'set_error'; $result->{ $k } = $O->$func ( $k, $args->{ $k } ); } return $result; } =back =head1 INSPECTION METHODS These are the functions that do the actual work of getting values. They're called by get() when it finds their names in {'get-funcs'}. =over 4 =item get_normal (key) : value This routine simply pulls the named value from the emedded hash. =cut sub get_normal { my ($O, $key) = @_; return ($O->{'data'}->{ $key }); } =item get_synthetic (key) : value This routine is a little more interesting. It calculates the return value from some other value or combination of values in the embedded data hash. In this case, we'll calculate the farenheit value of a stored centigrade temperature. This is also just an example. In a real version of this class, you'd have a different function for every value you wanted to calculate. =cut sub get_synthetic { my ($O, $key) = @_; my $result = 32 + (1.8 * $O->{'data'}->{'temperature'}); return ($result); } =back =head1 STORAGE METHODS These are the functions that do the actual work of setting values. They're called by set() when it finds their names in {'set-funcs'}. =over 4 =item set_normal (key, value) : result This is the basic storage routine. It drops the value into the embedded data hash under the assigned key. It also returns a success code since there's no way that operation can fail. =cut sub set_normal { my ($O, $key, $val) = @_; $O->{'data'}->{ $key } = $val; return ('SUCCESS'); } =item set_synthetic (key, value) : result Like get_synthetic(), this is a sample routine. Here we store the centigrade value of a temperature entered in farenheit. =cut sub set_synthetic { my ($O, $key, $value) = @_; $O->{'data'}->{'temperature'} = ($value / 1.8) - 32; return ('SUCCESS'); } =back =head1 ERROR ROUTINES These are the catch-all routines. They handle keys that don't have set() or get() functions defined in the lookup tables. In theory, you could use these routines to replace the get_normal() and set_normal() operations, but I really don't like that idea. It makes typos *way* too powerful for my taste. I prefer to define my interfaces explicitly. =over 4 =cut sub get_error { my ($O, $key) = @_; return ( "FAILURE - " . "I don't know how to locate the value for '$key'." ); } sub set_error { my ($O, $key, $val) = @_; return ( "FAILURE - " . "I don't know how to set '$key' to '$value'." ); } #### sub set_normal { my ($O, $key, $val) = @_; my $func = $O->{'validate-funcs'}->{ $key }; my $result = $O->$func ($val); if ($result eq 'SUCCESS') { $O->{'data'}->{ $key } = $val; } return ($result); } #### sub new { {...} $O->{'synonyms'} = { 'rm' => 'REQUEST_METHOD', 'q' => 'QUERY_STRING', {...} }; {...} } sub get { my ($O, @keys) = @_; my $result = {}; for my $k (@keys) { my $real_key = $O->{'synonyms'}->{ $k } || $k; my $func = $O->{'get-funcs'}->{ $real_key } || 'get_error' ; $result->{ $k } = $O->$func ($real_key); } return ($result); } #### $O->$func ($key); #### package Command; sub new { return (bless {}, shift); } sub execute { } package Get_normal; @ISA = qw( Command ); sub execute { my ($O, $target, $key) = @_; $target->get_normal ($key); return; } package Data_holder; sub new { {...} my $g = new Get_normal; $O->{'get-funcs'} = { 'key-1' => $g, {...} } {...} } sub get { {...} my $cmd = $O->{'get-funcs'}->{ $k } || $O->{'get-funcs'}->{'get_error'} ; $result->{ $k } = $cmd->execute ( $k ); {...} }