cvsuser     03/11/18 12:38:51

  Modified:    App-BEGIN Makefile.PL
               App-BEGIN/lib/App BEGIN.pm
               App-BEGIN/t app.conf main.t
  Added:       App-BEGIN/t deprecated.conf deprecated.t
  Log:
  enhanced option handling substantially
  
  Revision  Changes    Path
  1.3       +3 -3      p5ee/App-BEGIN/Makefile.PL
  
  Index: Makefile.PL
  ===================================================================
  RCS file: /cvs/public/p5ee/App-BEGIN/Makefile.PL,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -w -r1.2 -r1.3
  --- Makefile.PL       20 Jun 2003 17:17:46 -0000      1.2
  +++ Makefile.PL       18 Nov 2003 20:38:51 -0000      1.3
  @@ -1,6 +1,6 @@
   
   ######################################################################
  -## File: $Id: Makefile.PL,v 1.2 2003/06/20 17:17:46 spadkins Exp $
  +## File: $Id: Makefile.PL,v 1.3 2003/11/18 20:38:51 spadkins Exp $
   ######################################################################
   
   use ExtUtils::MakeMaker;
  @@ -10,7 +10,7 @@
   %opts = (
       'NAME'        => 'App-BEGIN',
       'DISTNAME'    => 'App-BEGIN',
  -    'VERSION'     => '0.50',
  +    'VERSION'     => '0.60',
       'dist'        => {'COMPRESS'=>'gzip -9f', 'SUFFIX' => 'gz',
                         'ZIP'=>'/usr/bin/zip','ZIPFLAGS'=>'-rl'},
   );
  @@ -25,7 +25,7 @@
       return <<EOF;
   
   install ::
  -     @\$(MOD_INSTALL) bin/prefix "\$(PREFIX)/bin/prefix
  +     @\$(MOD_INSTALL) bin/prefix "\$(PREFIX)/bin/prefix"
   
   EOF
   }
  
  
  
  1.4       +393 -117  p5ee/App-BEGIN/lib/App/BEGIN.pm
  
  Index: BEGIN.pm
  ===================================================================
  RCS file: /cvs/public/p5ee/App-BEGIN/lib/App/BEGIN.pm,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -w -r1.3 -r1.4
  --- BEGIN.pm  10 Jul 2003 13:58:28 -0000      1.3
  +++ BEGIN.pm  18 Nov 2003 20:38:51 -0000      1.4
  @@ -1,15 +1,17 @@
   
   #############################################################################
  -## $Id: BEGIN.pm,v 1.3 2003/07/10 13:58:28 spadkins Exp $
  +## $Id: BEGIN.pm,v 1.4 2003/11/18 20:38:51 spadkins Exp $
   #############################################################################
   
   package App::BEGIN;
   
   use strict;
   
  +use Carp;
  +
   =head1 NAME
   
  -App::BEGIN - search for and read a deployment config file within a BEGIN block
  +App::BEGIN - search for and read a config file within a BEGIN block
   
   =head1 SYNOPSIS
   
  @@ -17,17 +19,40 @@
   
       BEGIN {
           use App::BEGIN;
  -        App::BEGIN->load_conf();
  +        App::BEGIN->init();
       }
   
  -    print "Deployment Configuration:\n";
  +    print "Configuration:\n";
       foreach $var (sort keys %App::conf) {
           printf "    %-20s => [%s]\n", $var, $App::conf{$var};
       }
   
  +  or a more full-featured example...
  +
  +    #!/usr/local/bin/perl
  +
  +    BEGIN {
  +        use App::BEGIN;
  +        App::BEGIN->init(
  +            conf => \%MyPkg::my_hash,
  +        );
  +    }
  +
  +    print "Configuration:\n";
  +    foreach $var (sort keys %MyPkg::my_hash) {
  +        printf "    %-20s => [%s]\n", $var, $MyPkg::my_hash{$var};
  +    }
  +
   =head1 DESCRIPTION
   
  -Search for and read a deployment config file within a BEGIN block.
  +App::BEGIN combines command-line arguments, environment variables,
  +configuration files, and program defaults to produce a hash of
  +configuration values.
  +
  +All of this is done within the BEGIN block so that the @INC variable
  +may be modified in time to affect "use" statements within the 
  +regular code.  This is particularly important to support the installation
  +of multiple versions of a Perl application on the same physical computer.
   
   App::BEGIN supports the P5EE/App-Context variant of the Perl 5 Enterprise
   Environment.  See the P5EE web sites for more information.
  @@ -49,13 +74,17 @@
   =cut
   
   #############################################################################
  -# load_conf()
  +# init()
   #############################################################################
   
  -=head2 load_conf()
  +=head2 init()
   
  -    * Signature: App::BEGIN->load_conf();
  -    * Param:  void
  +    * Signature: App::BEGIN->init();
  +    * Signature: App::BEGIN->init(%named);
  +    * Signature: App::BEGIN->init($myconf);          # deprecated
  +    * Signature: App::BEGIN->init($myconf, %named);  # deprecated
  +    * Param:  $myconf       HASH                     # deprecated
  +    * Param:  conf          HASH
       * Return: void
       * Throws: <none>
       * Since:  0.01
  @@ -64,39 +93,74 @@
   
       BEGIN {
           use App::BEGIN;
  -        App::BEGIN->load_conf();
  +        App::BEGIN->init();
       }
   
  -The load_conf() method reads the command line args (@ARGV),
  +    ... or, to use every option available ...
  +
  +    BEGIN {
  +        use App::BEGIN;
  +        App::BEGIN->init(
  +            conf => \%MyPackage::conf
  +            params => [ "config_file", "prefix", "app", "app_path_info",
  +                        "perlinc", "debugconf", "import", ],
  +            param => {
  +                config_file   => "~/.app/app.conf",         # set default
  +                app           => "default=app;type=string", # default & type
  +                app_path_info => {default=>"",type=>"string"}, # as a hashref
  +                prefix        => "type=string;required",
  +                perlinc       => undef,         # no default
  +                debugconf     => "type=int",
  +                import        => "type=string",
  +                flush_imports => 1,
  +            },
  +            no_cmd_args => 1,
  +            no_env_vars => 1,
  +            no_config_file => 1,
  +            print_usage => sub { my ($conf, $options) = @_; print "Use it 
right!\n"; },
  +        );
  +    }
  +
  +The init() method reads the command line args (@ARGV),
   finds a configuration file, and loads it, all in a way which
   can be done in a BEGIN block.  This is important to be able
   to modify the @INC array so that normal "use" and "require"
   statements will work with the configured @INC path.
   
  -The load_conf() method stores command line options and configuration
  +The init() method stores command line options and configuration
   file values all in the global %App::conf hash.
   The special keys to this hash are as follows.
   
  -    conf - specifies the exact file name of the config file
  -       useful for command line usage (i.e. "app --conf=/path/to/app.conf")
  -       "conf" is automatically set with the config file that it found
  +    config_file - specifies the exact file name of the config file useful
  +       for command line usage (i.e. "app --config_file=/path/to/app.conf")
  +       "config_file" is automatically set with the config file that it found
          if it is not supplied at the outset as an argument.
   
  -    conf_tag - specifies the tag that will be used when searching for
  -       a config file. (i.e. "app --conf_tag=myapp" will search for "myapp.conf"
  +    app - specifies the tag that will be used when searching for
  +       a config file. (i.e. "app --app=myapp" will search for "myapp.conf"
          before it searches for "app.conf")
  -       "conf_tag" is automatically set with the stem of the program file that 
  +       "app" is automatically set with the stem of the program file that 
          was run (or the first part of PATH_INFO) if it is not supplied at
          the outset as an argument.
   
       app_path_info - this is the remainder of PATH_INFO after the first
  -       part is taken off to make the conf_tag.
  +       part is taken off to make the app.
   
       prefix - This represents the base directory of the software
          installation (i.e. "/usr/myproduct/1.3.12").  If it is not
  -       set explicitly ...
  -
  -    perlinc
  +       set explicitly, it is detected from the following places:
  +          1. PREFIX environment variable
  +          2. the real path of the program with /bin or /cgi-bin stripped
  +          3. the current directory
  +       If it is autodetected from one of those three places, that is
  +       only provisional, in order to find the "config_file".  The "prefix"
  +       variable should be set authoritatively in the "config_file" if it
  +       is desired to be in the $conf structure.
  +
  +    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.)
   
       debugconf
   
  @@ -107,9 +171,16 @@
   
   =cut
   
  -sub load_conf {
  +sub init {
       shift if ($#_ > -1 && $_[0] eq "App::BEGIN");
  -    my $conf = ($#_ > -1 && ref($_[0]) eq "HASH") ? $_[0] : \%App::conf;
  +    my $conf = ($#_ > -1 && ref($_[0]) eq "HASH") ? shift : \%App::conf;
  +    my (%option);
  +    ($#_ % 2 == 1) || croak "must have an even number of args/values for named 
arguments";
  +    %option = @_;
  +    if (defined $option{conf}) {
  +        (ref($option{conf}) eq "HASH") || croak "'conf' argument must be a hash 
reference";
  +        $conf = $option{conf};
  +    }
   
       #################################################################
       # we do all this within a BEGIN block because we want to get a
  @@ -117,7 +188,7 @@
       # by "require" and "use".
       # The global configuration hash (%App::conf) is set from two sources:
       # 1. Read the command line options
  -    # 2. Read a Deployment Configuration File
  +    # 2. Read a Configuration File
       #    This is a sort of "deployment descriptor", describing only
       #    the things which are different about this installation of
       #    the application from other installations.
  @@ -132,38 +203,40 @@
       # Put the var/value pairs in %$conf
       #################################################################
       my ($var, $value);
  +    if (! $option{no_cmd_args}) {
       while ($#ARGV >= 0 && $ARGV[0] =~ /^--?([^=-][^=]*)(=?)(.*)/) {
           $var = $1;
           $value = ($2 eq "") ? 1 : $3;
           shift @ARGV;
           $conf->{$var} = $value;
       }
  +    }
   
       #################################################################
  -    # 2. find the conf_tag.
  +    # 2. find the app.
       #    by default this is the basename of the program
       #    in a web application, this is overridden by any existing
       #    first part of the PATH_INFO
       #################################################################
  -    my $conf_tag = $conf->{conf_tag};
  +    my $app = $conf->{app};
       my $app_path_info = $ENV{PATH_INFO} || "";
  -    if (!$conf_tag) {
  -        if ($app_path_info && $app_path_info =~ s!^/([^/]+)!!) {
  -            $conf_tag = $1;                  # PATH_INFO without the leading slash 
("/")
  +    if (!$app) {
  +        if ($app_path_info && $app_path_info =~ s!/([^/]+)/*$!!) {
  +            $app = $1;            # last part of PATH_INFO (without slashes)
           }
           else {
  -            $conf_tag = $0;                  # start with the full script path
  -            $conf_tag =~ s!.*/!!;            # strip off leading path
  -            $conf_tag =~ s/\.[^\.]+$//;      # strip off trailing file type (i.e. 
".pl")
  +            $app = $0;            # start with the full script path
  +            $app =~ s!.*/!!;      # strip off leading path
  +            $app =~ s/\.[^.]+$//; # strip off trailing file type (i.e. ".pl")
           }
  -        $conf->{conf_tag} = $conf_tag;
  +        $conf->{app} = $app;
       }
       $conf->{app_path_info} = $app_path_info;
   
       #################################################################
       # 3. find the directory the program was run from.
       #    we will use this directory to search for the
  -    #    deployment configuration file.
  +    #    configuration file.
       #################################################################
       my $prog_dir = $0;                   # start with the full script path
       if ($prog_dir =~ m!^/!) {            # absolute path
  @@ -182,70 +255,97 @@
       #    $prefix/bin or $prefix/cgi-bin.
       #################################################################
       my $prefix = $conf->{prefix};  # possibly set on command line
  +
  +    # it can be set in environment.
  +    # This is the preferred way for Registry and PerlRun webapps.
       $prefix = $ENV{PREFIX} if (!$prefix && $ENV{PREFIX});
  -    $prefix = $ENV{DOCUMENT_ROOT} if (!$prefix && $ENV{DOCUMENT_ROOT});
  +
  +    # Using "abs_path" gets rid of all symbolic links and gives the real path
  +    # to the directory in which the script runs.
       if (!$prefix) {
  -        $prefix = $prog_dir;
  -        $prefix =~ s!/?bin$!!;
  -        $prefix =~ s!/?cgi-bin.*$!!;
  +        use Cwd 'abs_path';
  +        $prefix = abs_path($prog_dir);
  +        $prefix =~ s!/bin$!!;
  +        $prefix =~ s!/cgi-bin.*$!!;
       }
  -    $prefix = "." if (!$prefix);
   
  +    $prefix = "." if (!$prefix);   # last resort: current directory
  +
  +    my ($env_var);
  +    if (! $option{no_config_file}) {
       #################################################################
       # 5. Define the standard places to look for a conf file
       #################################################################
  -    my @conf = ();
  -    if ($conf->{conf}) {
  -        @conf = ( $conf->{conf} );
  -    }
  +        my @conf_file = ();
  +        if ($conf->{config_file}) {
  +            @conf_file = ( $conf->{config_file} );
  +        }
  +        elsif ($conf->{conf}) {             # deprecated
  +            @conf_file = ( $conf->{conf} ); # deprecated
  +        }                                   # deprecated
       else {
  -        push(@conf, "$ENV{HOME}/.app/$conf_tag.conf") if ($ENV{HOME} && $conf_tag 
ne "app");
  -        push(@conf, "$ENV{HOME}/.app/app.conf") if ($ENV{HOME});
  -        push(@conf, "$prog_dir/$conf_tag.conf") if ($conf_tag ne "app");
  -        push(@conf, "$prog_dir/app.conf");
  -        push(@conf, "$prefix/etc/app/$conf_tag.conf") if ($conf_tag ne "app");
  -        push(@conf, "$prefix/etc/app/app.conf");
  +            push(@conf_file, "$ENV{HOME}/.app/$app.conf") if ($ENV{HOME} && $app ne 
"app");
  +            push(@conf_file, "$ENV{HOME}/.app/app.conf") if ($ENV{HOME});
  +            push(@conf_file, "$prog_dir/$app.conf") if ($app ne "app");
  +            push(@conf_file, "$prog_dir/app.conf");
  +            push(@conf_file, "$prefix/etc/app/$app.conf") if ($app ne "app");
  +            push(@conf_file, "$prefix/etc/app/app.conf");
       }
   
       #################################################################
       # 6. now actually read in the file(s)
  -    #    we only read the first file that is found, but
  +        #    we read a set of standard files, and
       #    we may continue to read in additional files if they
       #    are indicated by an "import" line
       #################################################################
   
       local(*App::FILE);
  -    my ($prog, $conf_file, $firstonly, $regexp, $excluding);
  -    $firstonly = 1;
  -    $prog = $0;
  -    $prog =~ s!.*/!!;
  -    while ($#conf > -1) {
  -        $conf_file = shift(@conf);
  -        $excluding = 0;
  +        my ($conf_file, $exclude_section);
  +        my ($regexp, $expr, @expr, $exclude);
  +        while ($#conf_file > -1) {
  +            $conf_file = shift(@conf_file);
  +            $exclude_section = 0;
           print STDERR "Looking for conf [$conf_file]\n" if ($conf->{debugconf});
           if (open(App::FILE, "< $conf_file")) {
               print STDERR "Found conf [$conf_file]\n" if ($conf->{debugconf});
  -            @conf = () if ($firstonly);  # throw out other files to look for
  -            $firstonly = 0;       # but keep others which get added (via "import")
               while (<App::FILE>) {
                   chomp;
  -                # for lines that are like "#!/regexp/ var = value" ...
  -                # (also accept the "#![regexp] var = value" syntax)
  -                if (s|^#![/\[]([^/]+)[/\]] *||) {
  -                    $regexp = $1;
  -                    next if ($prog !~ m!$regexp!);  # keep only if "regexp" matches 
the program name
  +                    # for lines that are like "[regexp]" or even "[regexp] var = 
value"
  +                    # or "[regexp;var=value]" or "[regexp;var1=value1;var2=value2]"
  +                    if (s|^ *\[([^\[\]]*)\] *||) {
  +                        @expr = split(/;/,$1);
  +                        $regexp = undef;
  +                        $exclude = 0;
  +                        foreach $expr (@expr) {
  +                            if ($expr =~ /^([^=]+)=(.*)$/) {  # a variable-based 
condition
  +                                $exclude = ((defined $conf->{$1} ? $conf->{$1} : 
"") ne $2);
  +                            }
  +                            else {  # a program name regexp
  +                                $regexp = $expr;
  +                                $exclude = ($regexp ne "" && $regexp ne "ALL" && 
$app !~ m!^$regexp$!);
  +                                $exclude = (!defined $regexp && $#expr > -1 && 
$exclude_section) if (!$exclude);
  +                            }
  +                            last if ($exclude);
                   }
  -                elsif (s|^\[(.*)\] *||) {
  -                    $regexp = $1;
                       if ($_) {
  -                        next if ($regexp && $prog !~ m!^$regexp$!);  # keep only if 
"regexp" matches the program name
  +                            # this is a single-line condition, don't change the 
$exclude_section flag
  +                            next if ($exclude);
                       }
                       else {
  -                        $excluding = ($regexp && ($prog !~ m!^$regexp$!));
  +                            # this condition pertains to all lines after it
  +                            $exclude_section = $exclude;
                           next;
                       }
                   }
  -                next if ($excluding);
  +                    # for lines that are like "#!/regexp/ var = value" ...  # 
[deprecated]
  +                    # (also accept the "#![regexp] var = value" syntax)     # 
[deprecated]
  +                    elsif (s|^#![/\[]([^/]+)[/\]] *||) {                    # 
[deprecated]
  +                        $regexp = $1;
  +                        next if ($app !~ m!$regexp!);  # keep only if "regexp" 
matches the program name
  +                    }
  +                    else {
  +                        next if ($exclude_section);
  +                    }
                   s/#.*$//;        # delete comments
                   s/^ +//;         # delete leading spaces
                   s/ +$//;         # delete trailing spaces
  @@ -259,19 +359,100 @@
                       # TODO: here documents, var = <<EOF
                       # only add values which have never been defined before
                       if (!defined $conf->{$var}) {
  -                        # do variable substitutions, var = {:prefix=/usr:}/bin
  -                        $value =~ 
s/\{:([a-zA-Z0-9_\.-]+)(=?)([^:\{\}]*):\}/(defined $conf->{$1} ? $conf->{$1} : ($2 ? 
$3 : $1))/eg;
  +                            if (! $option{no_env_vars}) {
  +                                $env_var = "APP_" . uc($var);
  +                                if (defined $ENV{$env_var}) {
  +                                    $value = $ENV{$env_var};
  +                                }
  +                            }
  +                            # do variable substitutions, var = ${prefix}/bin
  +                            # do variable substitutions, var = {:prefix=/usr:}/bin  
 # deprecated
  +                            $value =~ s/\$\{([a-zA-Z0-9_\.-]+)\}/(defined 
$conf->{$1} ? $conf->{$1} : "")/eg;
  +                            $value =~ 
s/\{:([a-zA-Z0-9_\.-]+)(=?)([^:\{\}]*):\}/(defined $conf->{$1} ?
  +                                $conf->{$1} : ($2 ? $3 : $1))/eg;   # deprecated
                           $conf->{$var} = $value;    # save all in %App::conf
                       }
                   }
               }
               close(App::FILE);
  +
  +                if ($conf->{flush_imports}) {
  +                    @conf_file = ();  # throw out other files to look for
  +                    delete $conf->{flush_imports};
  +                }
               if ($conf->{import}) {
  -                push(@conf, split(/[,:; ]+/, $conf->{import}));
  +                    unshift(@conf_file, split(/[,:; ]+/, $conf->{import}));
                   delete $conf->{import};
               }
           }
       }
  +    }
  +
  +    #################################################################
  +    # 6b. convert $option{param} to deep hash
  +    #################################################################
  +
  +    my (@vars, $paramdef);
  +    $paramdef = $option{param};
  +
  +    if ($paramdef) {
  +        die "App::BEGIN->init(): param must be a hash reference"
  +            if (ref($paramdef) ne "HASH");
  +
  +        my (@args, $hash, $arg);
  +        foreach $var (keys %$paramdef) {
  +            $value = $paramdef->{$var};
  +            if (ref($value) eq "") {
  +                $hash = {};
  +                $paramdef->{$var} = $hash;
  +                @args = split(/ *; */,$value);
  +                foreach $arg (@args) {
  +                    if ($arg =~ /^([^=]+)=(.*)$/) {
  +                        $hash->{$1} = $2;
  +                    }
  +                    elsif (! defined $hash->{default}) {
  +                        $hash->{default} = $arg;
  +                    }
  +                    else {
  +                        $hash->{$arg} = 1;
  +                    }
  +                }
  +            }
  +        }
  +    }
  +
  +    #################################################################
  +    # 6c. fill in ENV vars and defaults
  +    #################################################################
  +
  +    @vars = ();
  +    if ($option{params}) {
  +        die "App::BEGIN->init(): params must be an array reference"
  +            if (ref($option{params}) ne "ARRAY");
  +        push(@vars, @{$option{params}});
  +    }
  +
  +    if ($paramdef) {
  +        push(@vars, (sort keys %$paramdef));
  +    }
  +
  +    foreach $var (@vars) {
  +        if (!defined $conf->{$var}) {
  +            $value = $paramdef ? $paramdef->{$var}{default} : undef;
  +            if (! $option{no_env_vars}) {
  +                $env_var = "APP_" . uc($var);
  +                if (defined $ENV{$env_var}) {
  +                    $value = $ENV{$env_var};
  +                }
  +            }
  +            # do variable substitutions, var = ${prefix}/bin
  +            # do variable substitutions, var = {:prefix=/usr:}/bin   # deprecated
  +            $value =~ s/\$\{([a-zA-Z0-9_\.-]+)\}/(defined $conf->{$1} ? $conf->{$1} 
: "")/eg;
  +            $value =~ s/\{:([a-zA-Z0-9_\.-]+)(=?)([^:\{\}]*):\}/(defined 
$conf->{$1} ?
  +                $conf->{$1} : ($2 ? $3 : $1))/eg;   # deprecated
  +            $conf->{$var} = $value;    # save all in %App::conf
  +        }
  +    }
   
       #################################################################
       # 7. establish the definitive (not inferred) $prefix
  @@ -305,8 +486,8 @@
               unshift(@INC, "$libdir");
               if ($^V) {
                   my $perlversion = sprintf("%vd", $^V);
  -                unshift(@INC, "$libdir/site_perl/$perlversion");  # site_perl goes 
first!
  -                unshift(@INC, "$libdir/$perlversion");
  +                unshift(@INC, "$libdir/perl5/site_perl/$perlversion");  # site_perl 
goes first!
  +                unshift(@INC, "$libdir/perl5/$perlversion");
               }
           }
       }
  @@ -324,6 +505,101 @@
           foreach $var (@INC) {
               print STDERR "   $var\n";
           }
  +    }
  +
  +    #################################################################
  +    # 10. perform validations, print help, and exit
  +    #################################################################
  +
  +    my $exit_status = -1;
  +    if ($conf->{"?"} || $conf->{help}) {
  +        $exit_status = 0;
  +    }
  +
  +    my ($type);
  +    if ($paramdef) {
  +        @vars = (sort keys %$paramdef);
  +        foreach $var (@vars) {
  +            $type = $paramdef->{$var}{type};
  +            next if (!$type);  # nothing to validate against
  +            $value = $conf->{$var};
  +            next if (! defined $value);
  +            if ($type eq "int" || $type eq "integer") {
  +                if ($value !~ /^-?[0-9]+$/) {
  +                    $exit_status = 1;
  +                    print "Error: \"$var\" must be of type \"$type\" (not 
\"$value\")\n";
  +                }
  +            }
  +            elsif ($type eq "number" || $type eq "float") {
  +                if ($value !~ /^-?[0-9]+\.?[0-9]*([eE][+-]?[0-9]+)?$/ &&
  +                    $value !~ /^-?[0-9]*\.[0-9]+([eE][+-]?[0-9]+)?$/) {
  +                    $exit_status = 1;
  +                    print "Error: \"$var\" must be of type \"$type\" (not 
\"$value\")\n";
  +                }
  +            }
  +            elsif ($type eq "date") {
  +                if ($value !~ /^[0-9]{4}-[0-9]{2}-[0-9]{2}$/) {
  +                    $exit_status = 1;
  +                    print "Error: \"$var\" must be of type \"$type\" (format 
\"YYYY-MM-DD\") (not \"$value\")\n";
  +                }
  +            }
  +            elsif ($type eq "datetime") {
  +                if ($value !~ /^[0-9]{4}-[0-9]{2}-[0-9]{2} 
[0-9]{2}:[0-9]{2}:[0-9]{2}$/) {
  +                    $exit_status = 1;
  +                    print "Error: \"$var\" must be of type \"$type\" (format 
\"YYYY-MM-DD HH:MM::SS\") (not \"$value\")\n";
  +                }
  +            }
  +        }
  +        foreach $var (@vars) {
  +            next if (!$paramdef->{$var}{required});
  +            next if (defined $conf->{$var});
  +            $exit_status = 1;
  +            print "Error: \"$var\" is a required parameter but is not defined\n";
  +        }
  +    }
  +
  +    if ($exit_status >= 0) {
  +        if ($option{print_usage}) {
  +            &{$option{print_usage}}($conf, \%option);
  +        }
  +        else {
  +            App::BEGIN->print_usage($conf, \%option);
  +        }
  +        exit($exit_status);
  +    }
  +}
  +
  +# provided only for backward compatibility
  +sub load_conf {                                     # deprecated
  +    shift if ($#_ > -1 && $_[0] eq "App::BEGIN");   # deprecated
  +    App::BEGIN->init(@_);                           # deprecated
  +}                                                   # deprecated
  +
  +sub print_usage {
  +    shift if ($#_ > -1 && $_[0] eq "App::BEGIN");
  +    my ($conf, $option) = @_;
  +    print STDERR "Usage: $0 [options]\n";
  +    printf STDERR "       --%-32s print this message (also -?)\n", "help";
  +    my (@vars);
  +    if ($option->{params}) {
  +        @vars = @{$option->{params}};
  +    }
  +    elsif ($option->{param}) {
  +        @vars = (sort keys %{$option->{param}});
  +    }
  +    else {
  +        @vars = (sort keys %$conf);
  +    }
  +    my ($var, $value, $type, $desc, $params);
  +    $params = $option->{param} || {};
  +    foreach $var (@vars) {
  +        next if ($var eq "?" || $var eq "help");
  +        $value = $conf->{$var};
  +        $type  = $params->{$var}{type} || "";
  +        $desc  = $params->{$var}{desc} || "";
  +        $type  = " ($type)" if ($type);
  +        $desc  = " $desc" if ($desc);
  +        printf STDERR "       --%-32s [%s]$type$desc\n", "$var=<$var>", (defined 
$value) ? $value : "undef";
       }
   }
   
  
  
  
  1.4       +16 -7     p5ee/App-BEGIN/t/app.conf
  
  Index: app.conf
  ===================================================================
  RCS file: /cvs/public/p5ee/App-BEGIN/t/app.conf,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -w -r1.3 -r1.4
  --- app.conf  10 Jul 2003 13:58:28 -0000      1.3
  +++ app.conf  18 Nov 2003 20:38:51 -0000      1.4
  @@ -1,17 +1,26 @@
   var = value
  -#!/main/ var1 = pattern match
  -#![main] var2 = old pattern match
  -[main.t] var3 = value3
  +prefix = /usr/local
  +[junk]
  +var1 = some other junk
  +var5 = it better not be this
  +[ALL]
  +[main] var1 = pattern match
  +[main] var2 = old pattern match
  +[main] var3 = value3
   dir = /usr/local
  -htdocs_dir   = {:dir:}/htdocs
  -template_dir = {:dir=/usr/bad:}/template
  -cgibin_dir   = {:dir2=/usr/local:}/cgi-bin
  -greeting     = {:Hello:}
  +htdocs_dir   = ${dir}/htdocs
  +[:dir=] dir = /usr/bad
  +template_dir = ${dir}/template
  +[:dir2=] dir2 = /usr/local
  +cgibin_dir   = ${dir2}/cgi-bin
  +[:greeting=] greeting = Hello
   [bozo]
   var4 = value4
   []
   var5 = value5
   [bozo]
   var6 = value6
  +[ALL]
  +var8 = value8
   [ma.*]
   var7 = value7
  
  
  
  1.4       +22 -11    p5ee/App-BEGIN/t/main.t
  
  Index: main.t
  ===================================================================
  RCS file: /cvs/public/p5ee/App-BEGIN/t/main.t,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -w -r1.3 -r1.4
  --- main.t    10 Jul 2003 13:58:28 -0000      1.3
  +++ main.t    18 Nov 2003 20:38:51 -0000      1.4
  @@ -14,11 +14,11 @@
   delete $ENV{PREFIX};
   delete $ENV{DOCUMENT_ROOT};
   
  -App::BEGIN->load_conf();
  +App::BEGIN->init();
   #print "CONF:\n   ", join("\n   ",%App::conf), "\n";
   ok(%App::conf, "put something in %App::conf");
  -is($App::conf{prefix}, $dir, "prefix = $dir");
  -is($App::conf{conf_tag}, "main", "conf_tag = main");
  +is($App::conf{prefix}, "/usr/local", "prefix = /usr/local");
  +is($App::conf{app}, "main", "app = main");
   is($App::conf{var}, "value", "var = value");
   is($App::conf{var1}, "pattern match", "pattern match");
   is($App::conf{var2}, "old pattern match", "old pattern match");
  @@ -31,30 +31,41 @@
   is($App::conf{var5}, "value5", "section exclusion ended");
   is($App::conf{var6}, undef,    "section excluded again");
   is($App::conf{var7}, "value7", "section included");
  +is($App::conf{var8}, "value8", "ALL works");
   
   %App::conf = (
  -    conf => "$dir/app.conf",
  +    config_file => "$dir/app.conf",
       prefix => "/usr/local",
  -    perlinc => "/usr/mycompany/2.1.7"
  +    perlinc => "/usr/mycompany/2.1.7/lib/perl5"
   );
  -App::BEGIN->load_conf();
  +
  +App::BEGIN->init();
   #print "CONF:\n   ", join("\n   ",%App::conf), "\n";
   ok(%App::conf, "put something in %App::conf");
   is($App::conf{prefix}, "/usr/local", "prefix = /usr/local");
  -is($App::conf{conf_tag}, "main", "conf_tag = main");
  +is($App::conf{app}, "main", "app = main");
   is($App::conf{var}, "value", "var = value");
   is($App::conf{var1}, "pattern match", "pattern match");
   is($App::conf{var2}, "old pattern match", "old pattern match");
  -is($INC[0], "/usr/mycompany/2.1.7", "[EMAIL PROTECTED] affected by perlinc");
  +is($INC[0], "/usr/mycompany/2.1.7/lib/perl5", "[EMAIL PROTECTED] affected by 
perlinc");
   
  -App::BEGIN->load_conf(\%App::otherconf);
  +App::BEGIN->init(\%App::otherconf);
   #print "CONF:\n   ", join("\n   ",%App::otherconf), "\n";
   ok(%App::otherconf, "put something in %App::otherconf");
  -is($App::otherconf{prefix}, $dir, "prefix = $dir");
  -is($App::otherconf{conf_tag}, "main", "conf_tag = main");
  +is($App::otherconf{prefix}, "/usr/local", "prefix = /usr/local");
  +is($App::otherconf{app}, "main", "app = main");
   is($App::otherconf{var}, "value", "var = value");
   is($App::otherconf{var1}, "pattern match", "pattern match");
   is($App::otherconf{var2}, "old pattern match", "old pattern match");
  +
  +App::BEGIN->init(conf => \%App::conf3);
  +#print "CONF:\n   ", join("\n   ",%App::conf3), "\n";
  +ok(%App::conf3, "put something in %App::conf3");
  +is($App::conf3{prefix}, "/usr/local", "prefix = /usr/local");
  +is($App::conf3{app}, "main", "app = main");
  +is($App::conf3{var}, "value", "var = value");
  +is($App::conf3{var1}, "pattern match", "pattern match");
  +is($App::conf3{var2}, "old pattern match", "old pattern match");
   
   exit 0;
   
  
  
  
  1.1                  p5ee/App-BEGIN/t/deprecated.conf
  
  Index: deprecated.conf
  ===================================================================
  var = value
  #!/deprecated/ var1 = pattern match
  #![deprecated] var2 = old pattern match
  [deprecated] var3 = value3
  dir = /usr/local
  htdocs_dir   = {:dir:}/htdocs
  template_dir = {:dir=/usr/bad:}/template
  cgibin_dir   = {:dir2=/usr/local:}/cgi-bin
  greeting     = {:Hello:}
  [bozo]
  var4 = value4
  []
  var5 = value5
  [bozo]
  var6 = value6
  [dep.*]
  var7 = value7
  
  
  
  1.1                  p5ee/App-BEGIN/t/deprecated.t
  
  Index: deprecated.t
  ===================================================================
  #!/usr/local/bin/perl -w
  
  use Test::More qw(no_plan);
  use lib "lib";
  use lib "../lib";
  
  use_ok("App::BEGIN");
  
  my ($dir);
  
  $dir = ".";
  $dir = "t" if (! -f "app.conf");
  
  delete $ENV{PREFIX};
  delete $ENV{DOCUMENT_ROOT};
  
  App::BEGIN->load_conf();
  #print "CONF:\n   ", join("\n   ",%App::conf), "\n";
  ok(%App::conf, "put something in %App::conf");
  is($App::conf{prefix}, "/usr/local", "prefix = /usr/local");
  is($App::conf{app}, "deprecated", "app = deprecated");
  is($App::conf{var}, "value", "var = value");
  is($App::conf{var1}, "pattern match", "pattern match");
  is($App::conf{var2}, "old pattern match", "old pattern match");
  is($App::conf{htdocs_dir}, "/usr/local/htdocs", "variable substitution");
  is($App::conf{cgibin_dir}, "/usr/local/cgi-bin", "variable substitution (default 
used)");
  is($App::conf{template_dir}, "/usr/local/template", "variable substitution (default 
supplied but not used)");
  is($App::conf{greeting}, "Hello", "variable substitution (var name used since var 
not defined)");
  is($App::conf{var3}, "value3", "inline pattern match");
  is($App::conf{var4}, undef,    "section excluded");
  is($App::conf{var5}, "value5", "section exclusion ended");
  is($App::conf{var6}, undef,    "section excluded again");
  is($App::conf{var7}, "value7", "section included");
  
  %App::conf = (
      config_file => "$dir/deprecated.conf",
      prefix => "/usr/local",
      perlinc => "/usr/mycompany/2.1.7"
  );
  App::BEGIN->load_conf();
  #print "CONF:\n   ", join("\n   ",%App::conf), "\n";
  ok(%App::conf, "put something in %App::conf");
  is($App::conf{prefix}, "/usr/local", "prefix = /usr/local");
  is($App::conf{app}, "deprecated", "app = deprecated");
  is($App::conf{var}, "value", "var = value");
  is($App::conf{var1}, "pattern match", "pattern match");
  is($App::conf{var2}, "old pattern match", "old pattern match");
  is($INC[0], "/usr/mycompany/2.1.7", "[EMAIL PROTECTED] affected by perlinc");
  
  App::BEGIN->load_conf(\%App::otherconf);
  #print "CONF:\n   ", join("\n   ",%App::otherconf), "\n";
  ok(%App::otherconf, "put something in %App::otherconf");
  is($App::conf{prefix}, "/usr/local", "prefix = /usr/local");
  is($App::otherconf{app}, "deprecated", "app = deprecated");
  is($App::otherconf{var}, "value", "var = value");
  is($App::otherconf{var1}, "pattern match", "pattern match");
  is($App::otherconf{var2}, "old pattern match", "old pattern match");
  
  exit 0;
  
  
  
  

Reply via email to