Документация
HTML CSS PHP PERL другое

Section A.13.  Answers for Chapter 14

 
Previous
Table of Contents
Next

A.13. Answers for Chapter 14

A.13.1. Exercise 1

There a couple of ways to tackle this problem. In our solution, we created a MyDate package in the same file as the script. The naked block defines the scope of the package MyDate statement. Later, in our script, we can't use the module because Perl won't find a file for it. We'll have to remember to call the import method to get the symbols into our main namespace.

To make the AUTOLOAD subroutine work only for the right subroutines, we defined %Allowed_methods to hold the names of the methods that will work. Their values are their offsets in the list we get back from localtime. That almost solves it, but localtime uses 0-based numbers for the month and year. In the @Offsets array, we store the number to add to the corresponding entry in the localtime list. It seems like a lot of work now since only two values have offsets, but doing it this way eliminates two special cases.

We need a new method (or some constructor) to give us an object. In this example, it doesn't really matter what the object actually looks like. We just use an empty, anonymous hash blessed into the current package (that's the first thing in the argument list, so it's $_[0]). We also know that we'll need a DESTROY method, since Perl will automatically look for it when it tries to clean up the object. If we don't have it, our AUTOLOAD will complain about an unknown method when it tries to handle DESTROY on its own (comment out the DESTROY to see what happens).

Inside the AUTOLOAD, we store the method name in $method so we can change it. We want to strip off the package information and get just the method name. That's everything after the last ::, so we use the substitution operator to get rid of everything up to that point. Once we have the method name, we look for its key in %Allowed_methods. If it's not there, we print an error with carp. TRy calling an unknown method. For which line does Perl report the error?

If we find the method name in %Allowed_methods, we get the value, which is the position of the value in the localtime list. We store that in $slice_index and use it to get the value from localtime as well as the offset for that value. We add those two values together and return the result.

That sounds like a lot of work, but how much work would we have to do to add new methods for the hour and minute? We simply add those names to %Allowed_methods. Everything else already works.

#!/usr/bin/perl -w
use strict;

{
package MyDate;
use vars qw($AUTOLOAD);

use Carp;

my %Allowed_methods = qw( date 3 month 4 year 5 );
my @Offsets         = qw(0 0 0 0 1 1900 0 0 0);

sub new      { bless {  }, $_[0] }
sub DESTROY  {  }

sub AUTOLOAD {
        my $method = $AUTOLOAD;
        $method =~ s/.*:://;

        unless( exists $Allowed_methods{ $method } ) {
                carp "Unknown method: $AUTOLOAD";
                return;
                }

        my $slice_index = $Allowed_methods{ $method };

        return (localtime)[$slice_index] + $Offsets[$slice_index];
        }
}

MyDate->import;         # we don't use it
my $date = MyDate->new(  );

print "The date is "  . $date->date  . "\n";
print "The month is " . $date->month . "\n";
print "The year is "  . $date->year  . "\n";

A.13.2. Exercise 2

Our script looks the same as the previous answer with the addition of the UNIVERSAL::debug routine. At the end of our script, we call the debug method on our $date object. It works without changing the MyDate module.

MyDate->import;         # we don't use it
my $date = MyDate->new(  );

sub UNIVERSAL::debug {
        my $self = shift;
        print '[' . localtime . '] ' . join '|', @_
        }

print "The date is "  . $date->date  . "\n";
print "The month is " . $date->month . "\n";
print "The year is "  . $date->year  . "\n";

$date->debug( "I'm all done" );

How did that get past the AUTOLOAD? Remember that Perl searches through all of @ISA and UNIVERSAL before it starts looking in any AUTOLOAD method. So, Perl finds UNIVERSAL::debug before it has to use our AUTOLOAD magic.


Previous
Table of Contents
Next
© 2000- NIV