Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages

  
 
  

home | help
App::Info(3)	      User Contributed Perl Documentation	  App::Info(3)

NAME
       App::Info - Information about software packages on a system

SYNOPSIS
	 use App::Info::Category::FooApp;

	 my $app = App::Info::Category::FooApp->new;

	 if ($app->installed) {
	     print "App	name: ", $app->name, "\n";
	     print "Version:  ", $app->version,	"\n";
	     print "Bin	dir:  ", $app->bin_dir,	"\n";
	 } else	{
	     print "App	not installed on your system. :-(\n";
	 }

DESCRIPTION
       App::Info is an abstract	base class designed to provide a generalized
       interface for subclasses	that provide meta data about software packages
       installed on a system. The idea is that these classes can be used in
       Perl application	installers in order to determine whether software
       dependencies have been fulfilled, and to	get necessary meta data	about
       those software packages.

       App::Info provides an event model for handling events triggered by
       App::Info subclasses. The events	are classified as "info", "error",
       "unknown", and "confirm"	events,	and multiple handlers may be specified
       to handle any or	all of these event types. This allows App::Info
       clients to flexibly handle events in any	way they deem necessary.
       Implementing new	event handlers is straight-forward, and	use the
       triggering of events by App::Info subclasses is likewise	kept easy-to-
       use.

       A few sample subclasses are provided with the distribution, but others
       are invited to write their own subclasses and contribute	them to	the
       CPAN. Contributors are welcome to extend	their subclasses to provide
       more information	relevant to the	application for	which data is to be
       provided	(see App::Info::HTTPD::Apache for an example), but are
       encouraged to, at a minimum, implement the abstract methods defined
       here and	in the category	abstract base classes (e.g., App::Info::HTTPD
       and App::Info::Lib).  See Subclassing for more information on
       implementing new	subclasses.

INTERFACE
       This section documents the public interface of App::Info.

   Constructor
       new

	 my $app = App::Info::Category::FooApp->new(@params);

       Constructs an App::Info object and returns it. The @params arguments
       define attributes that can be used to help the App::Info	object search
       for application information on the file system, as well as how the
       App::Info object	will respond to	certain	events.	The event parameters
       correspond to their like-named methods. See the "Event Handler Object
       Methods"	section	for more information on	App::Info events and how to
       handle them. The	search parameters that can be passed to	"new()"	are:

       search_exe_names
	   An array reference of possible names	for binary executables.	These
	   may be used by subclasses to	search for application programs	that
	   can be used to retrieve application information, such as version
	   numbers. The	subclasses generally provide reasonable	defaults for
	   most	cases.

       search_bin_dirs
	   An array reference of local directories in which to search for
	   executables.	 These may be used to search for the value of the
	   "bin_dir" attribute in addition to and in preference	to the
	   defaults used by each subclass.

       search_lib_names
	   An array reference of possible names	for library files. These may
	   be used by subclasses to search for library files for the
	   application.	The subclasses generally provide reasonable defaults
	   for most cases.

       search_so_lib_names
	   An array reference of possible names	for shared object library
	   files. These	may be used by subclasses to search for	shared object
	   library files for the application. The subclasses generally provide
	   reasonable defaults for most	cases.

       search_lib_dirs
	   An array reference of local directories in which to search for
	   libraries.  These may be used to search for the value of the
	   "lib_dir" and "so_lib_dir" attributes in addition to	and in
	   preference to the defaults used by each subclass.

       search_inc_names
	   An array reference of possible names	for include files. These may
	   be used by subclasses to search for include files for the
	   application.	The subclasses generally provide reasonable defaults
	   for most cases.

       search_inc_dirs
	   An array reference of local directories in which to search for
	   include files. These	may be used to search for the value of the
	   "inc_dir" attribute in addition to and in preference	to the
	   defaults used by each subclass.

       The parameters to "new()" for the different types of App::Info events
       are:

       on_info
       on_error
       on_unknown
       on_confirm

       When passing event handlers to "new()", the list	of handlers for	each
       type should be an anonymous array, for example:

	 my $app = App::Info::Category::FooApp->new( on_info =>	\@handlers );

   Meta	Data Object Methods
       These are abstract methods in App::Info and must	be provided by its
       subclasses. They	provide	the essential meta data	of the software
       package supported by the	App::Info subclass.

       key_name

	 my $key_name =	$app->key_name;

       Returns a string	that uniquely identifies the software for which	the
       App::Info subclass provides data. This value should be unique across
       all App::Info classes. Typically, it's simply the name of the software.

       installed

	 if ($app->installed) {
	     print "App	is installed.\n"
	 } else	{
	     print "App	is not installed.\n"
	 }

       Returns a true value if the application is installed, and a false value
       if it is	not.

       name

	 my $name = $app->name;

       Returns the name	of the application.

       version

	 my $version = $app->version;

       Returns the full	version	number of the application.

       major_version

	 my $major_version = $app->major_version;

       Returns the major version number	of the application. For	example, if
       "version()" returns "7.1.2", then this method returns "7".

       minor_version

	 my $minor_version = $app->minor_version;

       Returns the minor version number	of the application. For	example, if
       "version()" returns "7.1.2", then this method returns "1".

       patch_version

	 my $patch_version = $app->patch_version;

       Returns the patch version number	of the application. For	example, if
       "version()" returns "7.1.2", then this method returns "2".

       bin_dir

	 my $bin_dir = $app->bin_dir;

       Returns the full	path the application's bin directory, if it exists.

       executable

	 my $executable	= $app->executable;

       Returns the full	path the application's bin directory, if it exists.

       inc_dir

	 my $inc_dir = $app->inc_dir;

       Returns the full	path the application's include directory, if it
       exists.

       lib_dir

	 my $lib_dir = $app->lib_dir;

       Returns the full	path the application's lib directory, if it exists.

       so_lib_dir

	 my $so_lib_dir	= $app->so_lib_dir;

       Returns the full	path the application's shared library directory, if it
       exists.

       home_url

	 my $home_url =	$app->home_url;

       The URL for the software's home page.

       download_url

	 my $download_url = $app->download_url;

       The URL for the software's download page.

   Search Attributes
       These methods return lists of things to look for	on the local file
       system when searching for application programs, library files, and
       include files. They are empty by	default, since each subclass generally
       relies on its own settings, but you can add your	own as preferred
       search parameters by specifying them as parameters to the "new()"
       constructor.

       exe_names

	 my @search_exe_names =	$app->search_exe_names;

       Returns a list of possible names	for an executable. Typically used by
       the "new()" constructor to search for an	executable to execute and
       collect application info.

       search_bin_dirs

	 my @search_bin_dirs = $app->search_bin_dirs;

       Returns a list of possible directories in which to search an
       executable.  Typically used by the "new()" constructor to find an
       executable to execute and collect application info. The found directory
       will also generally then	be returned by the "bin_dir" method.

       lib_names

	 my @search_lib_names =	$app->search_lib_names;

       Returns a list of possible names	for library files. Typically used by
       the "lib_dir()" method to find library files.

       so_lib_names

	 my @search_so_lib_names = $app->search_so_lib_names;

       Returns a list of possible names	for library files. Typically used by
       the "so_lib_dir()" method to find shared	object library files.

       search_lib_dirs

	 my @search_lib_dirs = $app->search_lib_dirs;

       Returns a list of possible directories in which to search for
       libraries.  Typically used by the "lib_dir()" and "so_lib_dir()"
       methods to find library files.

       inc_names

	 my @search_inc_names =	$app->search_inc_names;

       Returns a list of possible names	for include files. Typically used by
       the "inc_dir()" method to find include files.

       search_inc_dirs

	 my @search_inc_dirs = $app->search_inc_dirs;

       Returns a list of possible directories in which to search for includes.
       Typically used by the "inc_dir()" method	to find	include	files.

   Event Handler Object	Methods
       These methods provide control over App::Info event handling. Events can
       be handled by one or more objects of subclasses of App::Info::Handler.
       The first to return a true value	will be	the last to execute. This
       approach	allows handlers	to be stacked, and makes it relatively easy to
       create new handlers.  App::Info::Handler	for information	on writing
       event handlers.

       Each of the event handler methods takes a list of event handlers	as its
       arguments. If none are passed, the existing list	of handlers for	the
       relevant	event type will	be returned. If	new handlers are passed	in,
       they will be returned.

       The event handlers may be specified as one or more objects of the
       App::Info::Handler class	or subclasses, as one or more strings that
       tell App::Info construct	such handlers itself, or a combination of the
       two. The	strings	can only be used if the	relevant App::Info::Handler
       subclasses have registered strings with App::Info. For example, the
       App::Info::Handler::Print class included	in the App::Info distribution
       registers the strings "stderr" and "stdout" when	it starts up. These
       strings may then	be used	to tell	App::Info to construct
       App::Info::Handler::Print objects that print to STDERR or to STDOUT,
       respectively. See the App::Info::Handler	subclasses for what strings
       they register with App::Info.

       on_info

	 my @handlers =	$app->on_info;
	 $app->on_info(@handlers);

       Info events are triggered when the App::Info subclass wants to send an
       informational status message. By	default, these events are ignored, but
       a common	need is	for such messages to simply print to STDOUT. Use the
       App::Info::Handler::Print class included	with the App::Info
       distribution to have info messages print	to STDOUT:

	 use App::Info::Handler::Print;
	 $app->on_info('stdout');
	 # Or:
	 my $stdout_handler = App::Info::Handler::Print->new('stdout');
	 $app->on_info($stdout_handler);

       on_error

	 my @handlers =	$app->on_error;
	 $app->on_error(@handlers);

       Error events are	triggered when the App::Info subclass runs into	an
       unexpected but not fatal	problem. (Note that fatal problems will	likely
       throw an	exception.) By default,	these events are ignored. A common way
       of handling these events	is to print them to STDERR, once again using
       the App::Info::Handler::Print class included with the App::Info
       distribution:

	 use App::Info::Handler::Print;
	 my $app->on_error('stderr');
	 # Or:
	 my $stderr_handler = App::Info::Handler::Print->new('stderr');
	 $app->on_error($stderr_handler);

       Another approach	might be to turn such events into fatal	exceptions.
       Use the included	App::Info::Handler::Carp class for this	purpose:

	 use App::Info::Handler::Carp;
	 my $app->on_error('croak');
	 # Or:
	 my $croaker = App::Info::Handler::Carp->new('croak');
	 $app->on_error($croaker);

       on_unknown

	 my @handlers =	$app->on_unknown;
	 $app->on_uknown(@handlers);

       Unknown events are triggered when the App::Info subclass	cannot find
       the value to be returned	by a method call. By default, these events are
       ignored.	A common way of	handling them is to have the application
       prompt the user for the relevant	data. The App::Info::Handler::Prompt
       class included with the App::Info distribution can do just that:

	 use App::Info::Handler::Prompt;
	 my $app->on_unknown('prompt');
	 # Or:
	 my $prompter =	App::Info::Handler::Prompt;
	 $app->on_unknown($prompter);

       See App::Info::Handler::Prompt for information on how it	works.

       on_confirm

	 my @handlers =	$app->on_confirm;
	 $app->on_confirm(@handlers);

       Confirm events are triggered when the App::Info subclass	has found an
       important piece of information (such as the location of the executable
       it'll use to collect information	for the	rest of	its methods) and wants
       to confirm that the information is correct. These events	will most
       often be	triggered during the App::Info subclass	object construction.
       Here, too, the App::Info::Handler::Prompt class included	with the
       App::Info distribution can help out:

	 use App::Info::Handler::Prompt;
	 my $app->on_confirm('prompt');
	 # Or:
	 my $prompter =	App::Info::Handler::Prompt;
	 $app->on_confirm($prompter);

SUBCLASSING
       As an abstract base class, App::Info is not intended to be used
       directly.  Instead, you'll use concrete subclasses that implement the
       interface it defines. These subclasses each provide the meta data
       necessary for a given software package, via the interface outlined
       above (plus any additional methods the class author deems sensible for
       a given application).

       This section describes the facilities App::Info provides	for
       subclassing. The	goal of	the App::Info design has been to make
       subclassing straight-forward, so	that developers	can focus on gathering
       the data	they need for their application	and minimize the work
       necessary to handle unknown values or to	confirm	values.	As a result,
       there are essentially three concepts that developers need to understand
       when subclassing	App::Info: organization, utility methods, and events.

   Organization
       The organizational idea behind App::Info	is to name subclasses by broad
       software	categories. This approach allows the categories	themselves to
       function	as abstract base classes that extend App::Info,	so that	they
       can specify more	methods	for all	of their base classes to implement.
       For example, App::Info::HTTPD has specified the "httpd_root()" abstract
       method that its subclasses must implement. So as	you get	ready to
       implement your own subclass, think about	what category of software
       you're gathering	information about.  New	categories can be added	as
       necessary.

   Utility Methods
       Once you've decided on the proper category, you can start implementing
       your App::Info concrete subclass. As you	do so, take advantage of
       App::Info::Util,	wherein	I've tried to encapsulate common functionality
       to make subclassing easier. I found that	most of	what I was doing
       repetitively was	looking	for files and directories, and searching
       through files. Thus, App::Info::Util subclasses File::Spec in order to
       offer easy access to commonly-used methods from that class, e.g.,
       "path()". Plus, it has several of its own methods to assist you in
       finding files and directories in	lists of files and directories,	as
       well as methods for searching through files and returning the values
       found in	those files. See App::Info::Util for more information, and the
       App::Info subclasses in this distribution for usage examples.

       I recommend the use of a	package-scoped lexical App::Info::Util object.
       That way	it's nice and handy when you need to carry out common tasks.
       If you find you're doing	something over and over	that's not already
       addressed by an App::Info::Util method, consider	submitting a patch to
       App::Info::Util to add the functionality	you need.

   Events
       Use the methods described below to trigger events. Events are designed
       to provide a simple way for App::Info subclass developers to send
       status messages and errors, to confirm data values, and to request a
       value when the class cannot determine a value itself. Events may
       optionally be handled by	module users who assign	App::Info::Handler
       subclass	objects	to your	App::Info subclass object using	the event
       handling	methods	described in the "Event	Handler	Object Methods"
       section.

       info

	 $self->info(@message);

       Use this	method to display status messages for the user.	You may	wish
       to use it to inform users that you're searching for a particular	file,
       or attempting to	parse a	file or	some other resource for	the data you
       need. For example, a common use might be	in the object constructor:
       generally, when an App::Info object is created, some important initial
       piece of	information is being sought, such as an	executable file. That
       file may	be in one of many locations, so	it makes sense to let the user
       know that you're	looking	for it:

	 $self->info("Searching	for executable");

       Note that, due to the nature of App::Info event handlers, your
       informational message may be used or displayed any number of ways, or
       indeed not at all (as is	the default behavior).

       The @message will be joined into	a single string	and stored in the
       "message" attribute of the App::Info::Request object passed to info
       event handlers.

       error

	 $self->error(@error);

       Use this	method to inform the user that something unexpected has
       happened. An example might be when you invoke another program to	parse
       its output, but it's output isn't what you expected:

	 $self->error("Unable to parse version from `/bin/myapp	-c`");

       As with all events, keep	in mind	that error events may be handled in
       any number of ways, or not at all.

       The @erorr will be joined into a	single string and stored in the
       "message" attribute of the App::Info::Request object passed to error
       event handlers. If that seems confusing,	think of it as an "error
       message"	rather than an "error error." :-)

       unknown

	 my $val = $self->unknown(@params);

       Use this	method when a value is unknown.	This will give the user	the
       option -- assuming the appropriate handler handles the event -- to
       provide the needed data.	The value entered will be returned by
       "unknown()". The	parameters are as follows:

       key The "key" parameter uniquely	identifies the data point in your
	   class, and is used by App::Info to ensure that an unknown event is
	   handled only	once, no matter	how many times the method is called.
	   The same value will be returned by subsequent calls to "unknown()"
	   as was returned by the first	call, and no handlers will be
	   activated. Typical values are "version" and "lib_dir".

       prompt
	   The "prompt"	parameter is the prompt	to be displayed	should an
	   event handler decide	to prompt for the appropriate value. Such a
	   prompt might	be something like "Path	to your	httpd executable?". If
	   this	parameter is not provided, App::Info will construct one	for
	   you using your class' "key_name()" method and the "key" parameter.
	   The result would be something like "Enter a valid FooApp version".
	   The "prompt"	parameter value	will be	stored in the "message"
	   attribute of	the App::Info::Request object passed to	event
	   handlers.

       callback
	   Assuming a handler has collected a value for	your unknown data
	   point, it might make	sense to validate the value. For example, if
	   you prompt the user for a directory location, and the user enters
	   one,	it makes sense to ensure that the directory actually exists.
	   The "callback" parameter allows you to do this. It is a code
	   reference that takes	the new	value or values	as its arguments, and
	   returns true	if the value is	valid, and false if it is not. For the
	   sake	of convenience,	the first argument to the callback code
	   reference is	also stored in $_ .This	makes it easy to validate
	   using functions or operators	that, er, operate on $_	by default,
	   but still allows you	to get more information	from @_	if necessary.
	   For the directory example, a	good callback might be "sub { -d }".
	   The "callback" parameter code reference will	be stored in the
	   "callback" attribute	of the App::Info::Request object passed	to
	   event handlers.

       error
	   The error parameter is the error message to display in the event
	   that	the "callback" code reference returns false. This message may
	   then	be used	by the event handler to	let the	user know what went
	   wrong with the data she entered.  For example, if the unknown value
	   was a directory, and	the user entered a value that the "callback"
	   identified as invalid, a message to display might be	something like
	   "Invalid directory path". Note that if the "error" parameter	is not
	   provided, App::Info will supply the generic error message "Invalid
	   value". This	value will be stored in	the "error" attribute of the
	   App::Info::Request object passed to event handlers.

       This may	be the event method you	use most, as it	should be called in
       every meta data method if you cannot provide the	data needed by that
       method. It will typically be the	last part of the method. Here's	an
       example demonstrating each of the above arguments:

	 my $dir = $self->unknown( key	    => 'lib_dir',
				   prompt   => "Enter lib directory path",
				   callback => sub { -d	},
				   error    => "Not a directory");

       confirm

	 my $val = $self->confirm(@params);

       This method is very similar to "unknown()", but serves a	different
       purpose.	 Use this method for significant data points where you've
       found an	appropriate value, but want to ensure it's really the correct
       value. A	"significant data point" is usually a value essential for your
       class to	collect	meta data values.  For example,	you might need to
       locate an executable that you can then call to collect other data. In
       general,	this will only happen once for an object -- during object
       construction -- but there may be	cases in which it is needed more than
       that. But hopefully, once you've	confirmed in the constructor that
       you've found what you need, you can use that information	to collect the
       data needed by all of the meta data methods and can assume that they'll
       be right	because	that first, significant	data point has been confirmed.

       Other than where	and how	often to call "confirm()", its use is quite
       similar to that of "unknown()". Its parameters are as follows:

       key Same	as for "unknown()", a string that uniquely identifies the data
	   point in your class,	and ensures that the event is handled only
	   once	for a given key.  The same value will be returned by
	   subsequent calls to "confirm()" as was returned by the first	call
	   for a given key.

       prompt
	   Same	as for "unknown()". Although "confirm()" is called to confirm
	   a value, typically the prompt should	request	the relevant value,
	   just	as for "unknown()". The	difference is that the handler should
	   use the "value" parameter as	the default should the user not
	   provide a value. The	"prompt" parameter will	be stored in the
	   "message" attribute of the App::Info::Request object	passed to
	   event handlers.

       value
	   The value to	be confirmed. This is the value	you've found, and it
	   will	be provided to the user	as the default option when they're
	   prompted for	a new value. This value	will be	stored in the "value"
	   attribute of	the App::Info::Request object passed to	event
	   handlers.

       callback
	   Same	as for "unknown()". Because the	user can enter data to replace
	   the default value provided via the "value" parameter, you might
	   want	to validate it.	Use this code reference	to do so. The callback
	   will	be stored in the "callback" attribute of the
	   App::Info::Request object passed to event handlers.

       error
	   Same	as for "unknown()": an error message to	display	in the event
	   that	a value	entered	by the user isn't validated by the "callback"
	   code	reference.  This value will be stored in the "error" attribute
	   of the App::Info::Request object passed to event handlers.

       Here's an example usage demonstrating all of the	above arguments:

	 my $exe = $self->confirm( key	    => 'shell',
				   prompt   => 'Path to	your shell?',
				   value    => '/bin/sh',
				   callback => sub { -x	},
				   error    => 'Not an executable');

   Event Examples
       Below I provide some examples demonstrating the use of the event
       methods.	 These are meant to emphasize the contexts in which it's
       appropriate to use them.

       Let's start with	the simplest, first. Let's say that to find the
       version number for an application, you need to search a file for	the
       relevant	data.  Your App::Info concrete subclass	might have a private
       method that handles this	work, and this method is the appropriate place
       to use the "info()" and,	if necessary, "error()"	methods.

	 sub _find_version {
	     my	$self =	shift;

	     # Try to find the revelant	file. We cover this method below.
	     # Just return if we cant' find it.
	     my	$file =	$self->_find_file('version.conf') or return;

	     # Send a status message.
	     $self->info("Searching '$file' file for version");

	     # Search the file.	$util is an App::Info::Util object.
	     my	$ver = $util->search_file($file, qr/^Version\s+(.*)$/);

	     # Trigger an error	message, if necessary. We really think we'll have the
	     # value, but we have to cover our butts in	the unlikely event that	we're
	     # wrong.
	     $self->error("Unable to find version in file '$file'") unless $ver;

	     # Return the version number.
	     return $ver;
	 }

       Here we've used the "info()" method to display a	status message to let
       the user	know what we're	doing. Then we used the	"error()" method when
       something unexpected happened, which in this case was that we weren't
       able to find the	version	number in the file.

       Note the	"_find_file()" method we've thrown in. This might be a method
       that we call whenever we	need to	find a file that might be in one of a
       list of directories. This method, too, will be an appropriate place for
       an "info()" method call.	But rather than	call the "error()" method when
       the file	can't be found,	you might want to give an event	handler	a
       chance to supply	that value for you. Use	the "unknown()"	method for a
       case such as this:

	 sub _find_file	{
	     my	($self,	$file) = @_;

	     # Send a status message.
	     $self->info("Searching for	'$file'	file");

	     # Look for	the file. See App::Info:Utility	for its	interface.
	     my	@paths = qw(/usr/conf /etc/conf	/foo/conf);
	     my	$found = $util->first_cat_path($file, @paths);

	     # If we didn't find it, trigger an	unknown	event to
	     # give a handler a	chance to get the value.
	     $found ||=	$self->unknown(	key	 => "file_$file",
					prompt	 => "Location of '$file' file?",
					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
       "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 "_find_version()" method above
       simply returns if "_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
       "error()" and when to use "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 "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 "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 meta data	object methods.	And of course,
       "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 "_find_version()" would be called
       by the "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 "unknown()" method. The "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 "version()" will return the same value that was
       returned	the first time it was called. Of course, thanks	to the "key"
       parameter in the	call to	"unknown()", we	could have have	tried to
       enumerate the version number every time,	as "unknown()" will return the
       same value every	time it	is called (as, indeed, should
       "_find_version()". But by checking for the "version" key	in $self
       ourselves, we save some of the overhead.

       But as I	said before, every meta	data method should make	use of the
       "unknown()" method. Thus, the "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 "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 "confirm()" method is quite similar to that of "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 /bin/myapp, but the user
       may really be interested	in /usr/bin/myapp.  Thus the "confirm()" event
       gives the user the chance to change the value if	the confirm event is
       handled.

       The final thing to note about this constructor is the first line:

	 my $self = shift->SUPER::new(@_);

       The first thing an App::Info subclass should do is execute this line to
       allow the super class to	construct the object first. Doing so allows
       any event handling arguments to set up the event	handlers, so that when
       we call "confirm()" or "unknown()" the event will be handled as the
       client expects.

       If we needed our	subclass constructor to	take its own parameter
       argument, the approach is to specify the	same "key =" $arg> syntax as
       is used by App::Info's "new()" method. Say we wanted to allow clients
       of our App::Info	subclass to pass in a list of alternate	executable
       locations for us	to search.  Such an argument would most	make sense as
       an array	reference. So we specify that the key be "alt_paths" and allow
       the user	to construct an	object like this:

	 my $app = App::Info::Category::FooApp->new( alt_paths => \@paths );

       This approach allows the	super class constructor	arguments to pass
       unmolested (as long as we use unique keys!):

	 my $app = App::Info::Category::FooApp->new( on_error  => \@handlers,
						     alt_paths => \@paths );

       Then, to	retrieve these paths inside our	"new()"	constructor, all we
       need do is access them directly from the	object:

	 my $self = shift->SUPER::new(@_);
	 my $alt_paths = $self->{alt_paths};

   Subclassing Guidelines
       To summarize, here are some guidelines for subclassing App::Info.

       o   Always subclass an App::Info	category subclass. This	will help to
	   keep	the App::Info name space well-organized. New categories	can be
	   added as needed.

       o   When	you create the "new()" constructor, always call
	   "SUPER::new(@_)". This ensures that the event handling methods
	   methods defined by the App::Info base classes (e.g.,	"error()")
	   will	work properly.

       o   Use a package-scoped	lexical	App::Info::Util	object to carry	out
	   common tasks.  If you find you're doing something over and over
	   that's not already addressed	by an App::Info::Util method, and you
	   think that others might find	your solution useful, consider
	   submitting a	patch to App::Info::Util to add	the functionality you
	   need. See App::Info::Util for complete documentation	of its
	   interface.

       o   Use the "info()" event triggering method to send messages to	users
	   of your subclass.

       o   Use the "error()" event triggering method to	alert users of
	   unexpected conditions. Fatal	errors should still be fatal; use
	   "Carp::croak()" to throw exceptions for fatal errors.

       o   Use the "unknown()" event triggering	method when a meta data	or
	   other important value is unknown and	you want to give any event
	   handlers the	chance to provide the data.

       o   Use the "confirm()" event triggering	method when a core piece of
	   data	is known (such as the location of an executable	in the "new()"
	   constructor)	and you	need to	make sure that you have	the correct
	   information.

       o   Be sure to implement	all of the abstract methods defined by
	   App::Info and by your category abstract base	class -- even if they
	   don't do anything. Doing so ensures that all	App::Info subclasses
	   share a common interface, and can, if necessary, be used without
	   regard to subclass. Any method not implemented but called on	an
	   object will generate	a fatal	exception.

       Otherwise, have fun! There are a	lot of software	packages for which
       relevant	information might be collected and aggregated into an
       App::Info concrete subclass (witness all	of the Automake	macros in the
       world!),	and folks who are knowledgeable	about particular software
       packages	or categories of software are warmly invited to	contribute. As
       more subclasses are implemented,	it will	make sense, I think, to	create
       separate	distributions based on category	-- or even, when necessary, on
       a single	software package. Broader categories can then be aggregated in
       Bundle distributions.

       But I get ahead of myself...

SUPPORT
       This module is stored in	an open	GitHub repository
       <http://github.com/theory/app-info/>. Feel free to fork and contribute!

       Please file bug reports via GitHub Issues
       <http://github.com/theory/app-info/issues/> or by sending mail to
       bug-App-Info@rt.cpan.org	<mailto:bug-App-Info@rt.cpan.org>.

AUTHOR
       David E.	Wheeler	<david@justatheory.com>

SEE ALSO
       The following classes define a few software package categories in which
       App::Info subclasses can	be placed. Check them out for ideas on how to
       create new category subclasses.

       App::Info::HTTP
       App::Info::RDBMS
       App::Info::Lib

       The following classes implement the App::Info interface for various
       software	packages. Check	them out for examples of how to	implement new
       App::Info concrete subclasses.

       App::Info::HTTPD::Apache
       App::Info::RDBMS::PostgreSQL
       App::Info::Lib::Expat
       App::Info::Lib::Iconv

       App::Info::Util provides	utility	methods	for App::Info subclasses.

       App::Info::Handler defines an interface for event handlers to subclass.
       Consult its documentation for information on creating custom event
       handlers.

       The following classes implement the App::Info::Handler interface	to
       offer some simple event handling. Check them out	for examples of	how to
       implement new App::Info::Handler	subclasses.

       App::Info::Handler::Print
       App::Info::Handler::Carp
       App::Info::Handler::Prompt

COPYRIGHT AND LICENSE
       Copyright (c) 2002-2011,	David E. Wheeler. Some Rights Reserved.

       This module is free software; you can redistribute it and/or modify it
       under the same terms as Perl itself.

perl v5.32.0			  2020-08-11			  App::Info(3)

NAME | SYNOPSIS | DESCRIPTION | INTERFACE | SUBCLASSING | SUPPORT | AUTHOR | SEE ALSO | COPYRIGHT AND LICENSE

Want to link to this manual page? Use this URL:
<https://www.freebsd.org/cgi/man.cgi?query=App::Info&sektion=3&manpath=FreeBSD+12.1-RELEASE+and+Ports>

home | help