cvsuser 04/01/07 07:24:07
Modified: App-Options MANIFEST Makefile.PL README TODO
App-Options/lib/App Options.pm
Log:
first version to upload to CPAN. a bit better documented, added string and boolean
types, added description to --help
Revision Changes Path
1.2 +7 -1 p5ee/App-Options/MANIFEST
Index: MANIFEST
===================================================================
RCS file: /cvs/public/p5ee/App-Options/MANIFEST,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -w -r1.1 -r1.2
--- MANIFEST 16 Nov 2003 21:21:22 -0000 1.1
+++ MANIFEST 7 Jan 2004 15:24:07 -0000 1.2
@@ -5,5 +5,11 @@
TODO
bin/prefix
lib/App/Options.pm
-t/main.t
t/app.conf
+t/main.t
+t/test1
+t/test1.conf
+t/test2
+t/test3
+t/test4
+t/test5
1.2 +2 -2 p5ee/App-Options/Makefile.PL
Index: Makefile.PL
===================================================================
RCS file: /cvs/public/p5ee/App-Options/Makefile.PL,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -w -r1.1 -r1.2
--- Makefile.PL 16 Nov 2003 21:21:22 -0000 1.1
+++ Makefile.PL 7 Jan 2004 15:24:07 -0000 1.2
@@ -1,6 +1,6 @@
######################################################################
-## File: $Id: Makefile.PL,v 1.1 2003/11/16 21:21:22 spadkins Exp $
+## File: $Id: Makefile.PL,v 1.2 2004/01/07 15:24:07 spadkins Exp $
######################################################################
use ExtUtils::MakeMaker;
@@ -14,7 +14,7 @@
%opts = (
'NAME' => 'App-Options',
'DISTNAME' => 'App-Options',
- 'VERSION' => '0.60',
+ 'VERSION' => '0.61',
'EXE_FILES' => [ @programs ],
'dist' => {'COMPRESS'=>'gzip -9f', 'SUFFIX' => 'gz',
'ZIP'=>'/usr/bin/zip','ZIPFLAGS'=>'-rl'},
1.2 +156 -36 p5ee/App-Options/README
Index: README
===================================================================
RCS file: /cvs/public/p5ee/App-Options/README,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -w -r1.1 -r1.2
--- README 16 Nov 2003 21:21:22 -0000 1.1
+++ README 7 Jan 2004 15:24:07 -0000 1.2
@@ -1,54 +1,174 @@
######################################################################
-## File: $Id: README,v 1.1 2003/11/16 21:21:22 spadkins Exp $
+## File: $Id: README,v 1.2 2004/01/07 15:24:07 spadkins Exp $
######################################################################
-This is the App-Options distribution.
+1. What is the App-Options distribution?
-It parses command line options, incorporates values from environment
-variables and configuration files, validates option values, and
-returns them in a simple hash structure. It would be used instead
-of modules like Getopt::Long, but of course it does a lot more.
-
-In particular, it may be run within a BEGIN block in order to
-modify the @INC variable with additional directories so that
-subsequent "use" and "require" statements are affected.
-
-FEATURES
-
- o Easy to use.
- o Parse long (--whatever) and short (-w) command line options
- o Combine options with Environment Variables
- o Combine options with global and local config files
- o Multiple config files can be used via "import" option
- o Modify @INC variable with the "perlinc" option
- o Validate "required" options provided
- o Validate option values against types (integer, int, float,
- number, date, datetime, string)
+The App-Options distribution is "yet another command line processor."
+However, it was created for maximum ease of use with the needs of
+the Perl 5 Enterprise Environment in mind (more on that later).
+
+The distribution consists of one Perl module and one shell script.
+
+ App::Options - a perl module which combines command line parameters,
+ environment variables, and configuration files to produce
+ a hash of option values.
+
+ prefix - a shell script which works for ksh (Korn shell) or
+ bash (Bourne Again Shell) which allows you to change
+ a family of environment variables (PATH, LD_LIBRARY_PATH,
+ MANPATH, etc.) necessary for running programs out of a
+ directory in which software has been installed.
+
+2. What are the features?
+
+FEATURES OF App::Options
+
+ o Flexible command line syntax
+ Parse long (--whatever) and short (-w) command line options
+ (with [--verbose=3] or without [--verbose] arguments)
+ and just put the values in %App::options (or some other hash
+ that you may specify).
+ o Automatic boolean command line switches
+ An option like "--help" is equivalent to "--help=1".
+ o Combines options with Environment Variables
+ The --whatever=value option can be supplied with the
+ APP_WHATEVER environment variable.
+ o Combines options with variables in global and local config files
+ The --whatever=value option can be supplied in config files with
+ the "whatever = value" statement. Initialization searches
+ "$HOME/.app/$prog.conf", "$HOME/.app/app.conf",
+ "$progdir/$prog.conf", "$progdir/app.conf",
+ "$prefix/$prog.conf", and "$prefix/app.conf" in order
+ to find the option values.
+ o Import other files with "import = filename" statement
+ Config files can, in essence, include other config files.
+ o Stop importing other files with "flush_imports = 1" statement
+ A config file can use this statement to tell the program
+ to stop searching for other config files it was planning
+ on searching.
+ o Option values undergo variable expansion
+ This means that some values may rely on other values.
+ i.e. "prefix = /usr/mycompany/3.2.1" and "logdir = ${prefix}/log"
+ o Config files can have conditional sections
+ A section specifier "[cleanup]" begins a section only valid
+ for the program "cleanup" (or "cleanup.exe" or cleanup.pl, etc.).
+ A section specifier "[ALL]" (or just "[]") begins another
+ unconditional section. In fact, "[cleanup]" is just a synonym
+ for "[app=cleanup]". Sections can be made conditional on the
+ current values of any variables. i.e. "[country=US;city=LAX]"
+ would begin a section of variables only valid if the two
+ specified variables have the required values.
+ o Config files can have conditional lines
+ Any section specifier can apply only to a single line by
+ putting a statement after it. "[city=LAX] state = CA"
+ o Modify @INC variable with the "perlinc = path1,path2" statement
+ If invoked in the BEGIN block, this allows the person deploying
+ the software to set up the Perl include path so that a
+ particular version of the software installed on the system is
+ used. Subsequent uses of "use" and "require" will load modules
+ from the configured locations.
+ o Validate that "required" options are provided
+ Certain options can be identified as required. Otherwise the
+ program will not run.
+ o Validate option values against types
+ Certain options can be identified as to their type or pattern
+ (integer, int, float, number, date, datetime, string, regexp).
+ If the option value is provided and it does not match the
+ type or pattern, the program will not run.
o Provide automatic "-?" and "--help" messages
+ Adds user-friendliness to programs with no extra effort.
-It is useful on its own for any perl programs which require flexible
-and easy option processing, and it has no dependencies other than
-on "Cwd", a module included with Perl itself. However, it was
-specifically designed in order to support the P5EE/App-Context
-variant of the Perl 5 Enterprise Environment.
+3. What were the design goals that make this distribution unique?
-For more information on the P5EE project, see the web pages at
+ #1 Support multiple installations of a complex suite of software.
+ This is useful for development and deployment of large systems,
+ where multiple versions may be in varying states of development,
+ testing, or production.
- http://www.officevision.com/pub/p5ee
+ #2 Support a suite of programs all using a common set of configuration
+ files. Large systems have many programs. We don't want to
+ repeat the database name, username, and password in a separate
+ config file for each program.
-and/or join the mailing list at
+ #3 Make it so easy to use that a developer would be silly not to
+ use it in even his smallest and simplest of scripts. However,
+ it should be powerful enough to support advanced features as
+ the developer needs them.
- [EMAIL PROTECTED]
+ #4 Support conditions where the environment variables are not
+ easy to control. i.e. CGI programs or cron jobs.
-The mailing list is described at
+These were important design goals to support the App-Context variant
+of the Perl 5 Enterprise Environment (P5EE). See the P5EE website
+(http://www.officevision.com/pub/p5ee) for more details.
- http://p5ee.perl.org/mailinglist/
- http://lists.perl.org/showlist.cgi?name=p5ee
+4. Why another module? Why not use Getopt::Long or others?
-HOW DO I INSTALL IT?
+There are many configuration modules on CPAN. See
+
+ http://search.cpan.org/modlist/Option_Parameter_Config_Processing
+
+The most important feature was to be able to run it within a
+BEGIN block to modify the Perl include path (@INC). This is
+most of design goal #1. This means very few dependencies and
+only on core modules.
+
+I started by writing a few lines of code in a BEGIN block.
+Then it got to be a lot of lines of code in a BEGIN block.
+Then I moved it out to a module so I could reuse it easily.
+Then it grew into a full-fledged command line, environment
+variable, and config file value option processor.
+
+In retrospect, I don't really know whether or not the other
+modules can run just as well in a BEGIN block and have a special
+feature to modify @INC. However, this met a primary design
+goal of App::Options.
+
+I did try Getopt::Long, but it wasn't that easy to use, you had
+to code your own "--help" feature, and it didn't incorporate
+environment variables or config files. I wanted something
+more high-level and full-featured, so I wrote App::Options.
+
+I looked at the description of the AppConfig distribution,
+and it sounds similar to what I describe here. However,
+the meaning of "sections" (i.e. "[cleanup]") is a conditional
+construct in App::Options. Thus, it supports a single
+family of configuration files to configure a whole suite
+of programs and scripts. (Each program can have its own
+section, and optionally its own file in both "user" and
+"system" places.) This met design goal #2.
+
+See the section below on ease of use for design goal #3.
+
+Design goal #4 required the autodetection of the ${prefix}
+variable. Thus, the App::Options module is integrated with
+the discipline of choosing a root directory for your
+software installation (i.e. PREFIX=/usr/mycompany/2.0.12).
+
+5. You say it's so easy. Show me.
+
+ #!/usr/bin/perl
+
+ BEGIN {
+ use App::Options;
+ App::Options->init();
+ }
+
+ # now use the %App::options hash
+ print "yada yada\n" if ($App::options{verbose});
+
+It's that easy.
+
+And it automatically has "-?" and "--help" support without
+you having to code a thing.
+
+Read the man page (or the code) if you want more power.
+
+6. How do I install it?
To install this module, cd to the directory that contains this README
-file and type the following:
+file and type the following (as usual).
perl Makefile.PL
make
1.2 +4 -3 p5ee/App-Options/TODO
Index: TODO
===================================================================
RCS file: /cvs/public/p5ee/App-Options/TODO,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -w -r1.1 -r1.2
--- TODO 16 Nov 2003 21:21:22 -0000 1.1
+++ TODO 7 Jan 2004 15:24:07 -0000 1.2
@@ -1,10 +1,11 @@
######################################################################
-## File: $Id: TODO,v 1.1 2003/11/16 21:21:22 spadkins Exp $
+## File: $Id: TODO,v 1.2 2004/01/07 15:24:07 spadkins Exp $
######################################################################
o quoting, var = " hello world "
- o here documents, var = <<EOF
o check list of configurable environment vars instead of "APP_${uc_var}"
+ o write "prefix.pod"
+ o figure out a way to do it outside the BEGIN block (i.e. use App::Options
qw(:init))
+ o here documents, var = <<EOF
o try use lib "dir"; instead of unshift(@INC,"dir")
- o reconsider "perlinc", perhaps use "perl5lib" instead
o consider checking the PERL5LIB variable under -T
1.2 +54 -14 p5ee/App-Options/lib/App/Options.pm
Index: Options.pm
===================================================================
RCS file: /cvs/public/p5ee/App-Options/lib/App/Options.pm,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -w -r1.1 -r1.2
--- Options.pm 11 Dec 2003 12:55:04 -0000 1.1
+++ Options.pm 7 Jan 2004 15:24:07 -0000 1.2
@@ -1,6 +1,6 @@
#############################################################################
-## $Id: Options.pm,v 1.1 2003/12/11 12:55:04 spadkins Exp $
+## $Id: Options.pm,v 1.2 2004/01/07 15:24:07 spadkins Exp $
#############################################################################
package App::Options;
@@ -43,7 +43,7 @@
app_path_info => {default=>"",type=>"string"}, # as a hashref
prefix => "type=string;required",
perlinc => undef, # no default
- debug_options => "type=int",
+ debug_options => "type=integer",
import => "type=string",
flush_imports => 1,
},
@@ -143,9 +143,35 @@
to modify the @INC array so that normal "use" and "require"
statements will work with the configured @INC path.
+The various named parameters of the init() method are as follows.
+
+ values - specify a hash reference other than %App::options to
+ put configuration values in.
+ options - specify a limited, ordered list of options to be
+ displayed when the "--help" or "-?" options are invoked
+ option - specify optional additional information about any of
+ the various options to the program (see below)
+ no_cmd_args - do not process command line arguments
+ no_env_vars - do not read environment variables
+ no_option_file - do not read in the option file
+ print_usage - provide an alternate print_usage() function
+
+The additional information that can be specified about any individual
+option variable is as follows.
+
+ default - the default variable if none supplied on the command
+ line, in an environment variable, or in an option file
+ required - the program will not run unless a value is provided
+ for this option
+ type - if a value is provided, the program will not run unless
+ the value matches the type ("string", "integer", "float",
+ "boolean", "date", "time", "datetime", regexp).
+ description - printed next to the option in the "usage" page
+
The init() method stores command line options and option
-file values all in the global %App::options hash.
-The special keys to this hash are as follows.
+file values all in the global %App::options hash (unless the
+"values" argument specifies another reference to a hash to use).
+The special keys to this resulting hash are as follows.
option_file - specifies the exact file name of the option file useful
for command line usage (i.e. "app --option_file=/path/to/app.conf")
@@ -175,12 +201,14 @@
perlinc - a path of directories to prepend to the @INC search path.
This list of directories is separated by any combination of
- [,;: ] characters. (Hmmm. Windows drive specifiers could be hurt
- by this approach.)
+ [,; ] characters.
- debug_options
+ debug_options - if this is set, a variety of debug information is
+ printed out during the option processing. This helps in debugging
+ which option files are being used and what the resulting variable
+ values are.
- import
+ import - a list of additional option files to be processed
=cut
@@ -469,7 +497,7 @@
#################################################################
if (defined $values->{perlinc}) { # add perlinc entries
- unshift(@INC, split(/[,:; ]+/,$values->{perlinc}));
+ unshift(@INC, split(/[,; ]+/,$values->{perlinc}));
}
else {
my $libdir = "$prefix/lib";
@@ -534,6 +562,15 @@
print "Error: \"$var\" must be of type \"$type\" (not
\"$value\")\n";
}
}
+ elsif ($type eq "string") {
+ # anything is OK
+ }
+ elsif ($type eq "boolean") {
+ if ($value !~ /^[01]$/) {
+ $exit_status = 1;
+ print "Error: \"$var\" must be of type \"$type\" (\"0\" or
\"1\") (not \"$value\")\n";
+ }
+ }
elsif ($type eq "date") {
if ($value !~ /^[0-9]{4}-[01][0-9]-[0-3][0-9]$/) {
$exit_status = 1;
@@ -593,15 +630,18 @@
@vars = (sort keys %$values);
}
my ($var, $value, $type, $desc, $option);
+ my ($var_str, $value_str, $type_str, $desc_str);
$option = $init_options->{option} || {};
foreach $var (@vars) {
next if ($var eq "?" || $var eq "help");
$value = $values->{$var};
$type = $option->{$var}{type} || "";
- $desc = $option->{$var}{desc} || "";
- $type = " ($type)" if ($type);
- $desc = " $desc" if ($desc);
- printf STDERR " --%-32s [%s]$type$desc\n", "$var=<$var>", (defined
$value) ? $value : "undef";
+ $desc = $option->{$var}{description} || "";
+ $var_str = ($type eq "boolean") ? $var : ($type ? "$var=<$type>" :
"$var=<$var>");
+ $value_str = (defined $value) ? $value : "undef";
+ $type_str = ($type) ? " ($type)" : "";
+ $desc_str = ($desc) ? " $desc" : "";
+ printf STDERR " --%-32s [%s]$type_str$desc_str\n", $var_str,
$value_str;
}
}