App-Info
view release on metacpan or search on metacpan
lib/App/Info.pm view on Meta::CPAN
callback => sub { -f },
error => "Not a file");
# Now return the file name, regardless of whether we found it or not.
return $found;
}
Note how in this method, we've tried to locate the file ourselves, but if we
can't find it, we trigger an unknown event. This allows clients of our
App::Info subclass to try to establish the value themselves by having an
App::Info::Handler subclass handle the event. If a value is found by an
App::Info::Handler subclass, it will be returned by C<unknown()> and we can
continue. But we can't assume that the unknown event will even be handled, and
thus must expect that an unknown value may remain unknown. This is why the
C<_find_version()> method above simply returns if C<_find_file()> doesn't
return a file name; there's no point in searching through a file that doesn't
exist.
Attentive readers may be left to wonder how to decide when to use C<error()>
and when to use C<unknown()>. To a large extent, this decision must be based
on one's own understanding of what's most appropriate. Nevertheless, I offer
the following simple guidelines: Use C<error()> when you expect something to
work and then it just doesn't (as when a file exists and should contain the
information you seek, but then doesn't). Use C<unknown()> when you're less
sure of your processes for finding the value, and also for any of the values
that should be returned by any of the L<meta data object methods|"Metadata
Object Methods">. And of course, C<error()> would be more appropriate when you
encounter an unexpected condition and don't think that it could be handled in
any other way.
Now, more than likely, a method such C<_find_version()> would be called by the
C<version()> method, which is a meta data method mandated by the App::Info
abstract base class. This is an appropriate place to handle an unknown version
value. Indeed, every one of your meta data methods should make use of the
C<unknown()> method. The C<version()> method then should look something like
this:
sub version {
my $self = shift;
unless (exists $self->{version}) {
# Try to find the version number.
$self->{version} = $self->_find_version ||
$self->unknown( key => 'version',
prompt => "Enter the version number");
}
# Now return the version number.
return $self->{version};
}
Note how this method only tries to find the version number once. Any
subsequent calls to C<version()> will return the same value that was returned
the first time it was called. Of course, thanks to the C<key> parameter in the
call to C<unknown()>, we could have have tried to enumerate the version number
every time, as C<unknown()> will return the same value every time it is called
(as, indeed, should C<_find_version()>. But by checking for the C<version> key
in C<$self> ourselves, we save some of the overhead.
But as I said before, every meta data method should make use of the
C<unknown()> method. Thus, the C<major()> method might looks something like
this:
sub major {
my $self = shift;
unless (exists $self->{major}) {
# Try to get the major version from the full version number.
($self->{major}) = $self->version =~ /^(\d+)\./;
# Handle an unknown value.
$self->{major} = $self->unknown( key => 'major',
prompt => "Enter major version",
callback => sub { /^\d+$/ },
error => "Not a number")
unless defined $self->{major};
}
return $self->{version};
}
Finally, the C<confirm()> method should be used to verify core pieces of data
that significant numbers of other methods rely on. Typically such data are
executables or configuration files from which will be drawn other meta data.
Most often, such major data points will be sought in the object constructor.
Here's an example:
sub new {
# Construct the object so that handlers will work properly.
my $self = shift->SUPER::new(@_);
# Try to find the executable.
$self->info("Searching for executable");
if (my $exe = $util->first_exe('/bin/myapp', '/usr/bin/myapp')) {
# Confirm it.
$self->{exe} =
$self->confirm( key => 'binary',
prompt => 'Path to your executable?',
value => $exe,
callback => sub { -x },
error => 'Not an executable');
} else {
# Handle an unknown value.
$self->{exe} =
$self->unknown( key => 'binary',
prompt => 'Path to your executable?',
callback => sub { -x },
error => 'Not an executable');
}
# We're done.
return $self;
}
By now, most of what's going on here should be quite familiar. The use of the
C<confirm()> method is quite similar to that of C<unknown()>. Really the only
difference is that the value is known, but we need verification or a new value
supplied if the value we found isn't correct. Such may be the case when
multiple copies of the executable have been installed on the system, we found
F</bin/myapp>, but the user may really be interested in F</usr/bin/myapp>.
Thus the C<confirm()> event gives the user the chance to change the value if
the confirm event is handled.
( run in 0.696 second using v1.01-cache-2.11-cpan-39bf76dae61 )