Path: news.ruhr-uni-bochum.de!news.rwth-aachen.de!newsserver.rrzn.uni-hannover.de!aix11.hrz.uni-oldenburg.de!uniol!namib.north.de!grizu.fh.uni-regensburg.de!uni-regensburg.de!lrz-muenchen.de!informatik.tu-muenchen.de!Germany.EU.net!howland.reston.ans.net!newsfeed.internetmci.com!in1.uu.net!nntp.teleport.com!usenet
From: [email protected] (Francesco Callari)
Newsgroups: comp.lang.perl.announce,comp.lang.perl.misc
Subject: ANNOUNCE - Resources-1.00b available
Followup-To: comp.lang.perl.misc
Date: 20 May 1996 22:25:31 GMT
Organization: Centre for Intelligent Machines, McGill University
Lines: 788
Approved: [email protected] (comp.lang.perl.announce)
Message-ID: <[email protected]>
NNTP-Posting-Host: julie.teleport.com
X-Disclaimer: The "Approved" header verifies header information for article transmission and does not imply approval of content.
Xref: news.ruhr-uni-bochum.de comp.lang.perl.announce:327 comp.lang.perl.misc:30510


Hello,

following my second RFC of may 9, and the favourable feedback received
(thanks, among the others,  to Tim Bunce, John C. Randolph, B. K. Oxley)
I am distributing the 1.00beta version of my Resources.pm package.

I uploaded it to ftp.cis.ufla.edu, and wrote to A. Koenig to register it.
It is immediately available at

       ftp://ftp.cim.mcgill.ca/pub/people/franco/Resources-1.00b.tar.gz

The package, for those who missed my RFCs, helps managing the definition of
configuration paramenters (a.k.a. resources) for applications through objects
trees. It offers an uniform way for defining class defaults, inheriting them
through subclassing, overriding them in subclasses, searching, loading from
files, wildcarding, etc etc, including dynamical viewing and editing.  A copy
of the package documentation (revised since the last RFC is attached).

>From an external point of view, it look prety much like the XWindows
default database idea. However, the idea of embedding parameter documentaion
with the parameters themselves is a new and, I think, valuable addition.

Please report your comments/bug reports to [email protected].

Enjoy
Franco

===8<=======8<=======8<=======8<=======8<=======8<=======8<=======8<====

NAME
   Resources - handling application defaults in Perl.

SYNOPSIS
       use Resources;

       $res = new Resources;
       $res = new Resources "resfile";


DESCRIPTION
   Resources are a way to specify information of interest to
   program or packages.

   Applications use resource files to specify and document the
   values of quantities or attributes of interest.

   Resources can be loaded from or saved to resource files. Methods
   are provided to search, modify and create resources.

   Packages use resources to hardwire in their code the default
   values for their attributes, along with documentation for the
   attibutes themselves.

   Packages inherit resources when subclassed, and the resource
   names are updated dynamically to reflect a class hierarchy.

   Methods are provided for interactive resource inspection and
   editing.

 1. Resource Files.

   A resource specification in a (text) resource file is a line of
   the form:

           name: value


   There may be any number of whitespaces between the name and the
   colon character, and between the colon and the value.

   name    A word not containing whitespaces, colons (':'), dots ('.')
           or asterisks ('*'), nor starting with '_'.

           A sequence in one the following forms:

                   word.name
                   word*name
                   *name


           No distinction is made between uppercase and lowercase
           letters.

           The asterisks in a resource name act as wildcards,
           matching any sequence of characters.

   value   An unadorned word or a quoted sequence of whitespace-
           separated words. Both single (' ') and double quotes
           quotes (" ") are allowed, and they must be paired.

           Any *constant* scalar constructor in Perl, including
           anon references to constant arrays or hashes.

           The special words yes, true, no, false (case
           insensitive) are treated as boolean resources and
           converted 1 and 0, unless they are quoted.


   Examples of valid resource specifications:

        hotdog*pickles : plenty      # A word.
        hotdog.price   : 22          # Another word
        hotdog.recipe : 'Help me!'   # A quoted sentence
        hotdog*taste*sucks : yes     # A boolean, converted to 1.
        hotdog*smell*sucks : 'yes'   # yes, aken verbatim
        hotdog.size  : [1, [2, 3]]           # An anon array.
        hotdog.lett : {"P"=>1, "Q"=>[2, 3]}  # An anon hash.


   Examples of illegal resource names:

        hot dog    # Whitespace in the name.
        .hotdog    # Leading dot in name.
        hot._dog   # Leading underscore in _dog.
        hotdog*    # Trailing asterisk.
        hotdog.    # Trailing dot.


   A resource file may contain comments: anything from a hash ('#')
   character to the end of a line is ignored, unless the hash
   character appears inside a quoted value string.

 2. Resource hashes

   Resource hashes provide a way to specify the default values for
   the attributes of a package in its source code, along with
   documentation for the attributes themselves. The documentation
   itself is "dynamical" (as opposed to the static, pod-like
   variety) in that it follows a class hyerarchy and is suitable
   for interactive display and editing.

   A resource hash is just a hash of ($Name => $Value) or ($Name =>
   [$Value, $Doc]) things. Each hash key $Name is a resource name
   as above. Each hash value is either just the resource $Value, or
   a reference to an anon array [$Value, $Doc], with $Doc being the
   resource documentation.

   The resource $Name *cannot* contain wildcard ('*') or colon
   (':') characters, nor start or end with a dot ('.'). Also, it
   must *not* be prefixed with the package name (since this is
   automatically prepended by the merge method, see below). Names
   starting with an underscore ('_') character are special in that
   they define "hidden" resources. These may not be specified in
   resource files, nor dynamically viewed/edited: they come handy
   to specify global parameters when you dont want to use global
   application-wide variables, and/or want to take advantage of the
   inheritance mechanism.

   The resource $Value can be any *constant* scalar Perl
   constructor, including references to arrays and/or hashes of
   constants (or references thereof). Boolean values must be
   specified as 1 or 0.

   The resource documentation is a just string of any length: it
   will be appropriately broken into lines for visualization
   purposes. It can also be missing for resources defined in base
   classes, in which case the base class documentation is used (see
   the merge method below).

   The content of a resource hash is registered in a global
   Resource object using the merge method.

   Here is an example of deafults specification for a package.

           package HotDog;
           @ISA = qw( Food );

           %HotDogDefaults =  (
               taste       => ["Yuck!", "Tongue feeling"],
               meatcolor   => ["Corpse", "Freshness indicator"],
               stinks      => [1, "Does it smell?"],
               onions      => [ { on => 2, ions => [3, 5] }, "Rings" ],
               'food.good' => 0, # just a scalar, doc is in base class
               '_ghost'    => [0, "Hidden. Mr. Invisible"]
           );


 3. Objects and resources

   The recommended way to use resources with Perl objects is to
   pass a Resource object to the "new" method of a package. The
   method itself will merge the passed resources with the package
   defaults, and the passed resource will override the defaults
   where needed.

   Resource inheritance via subclassing is then easily achieved,
   amounting to something like:

           package HotDog;
           @ISA = qw( Food );

           # Called as: $hotdog = new HotDog ($resources);
           sub new {
              my $package = shift;
              my $res = shift;

              $res = new Resources if (ref($res) !~ /Resources/o);
              $res->merge(\%HotDogDefaults);

              my $hd = bless new Food ($res);

              # Whatever initialization code
              return $hd;
           }


 4. Methods in class Resources

 4.1. Creation and initialization

   new Resources ($resfile);
           Creates a new resource database, initialized with the
           defaults for class Resources (see below for a list of
           them).

           If a nonempty file name is specified in $resfile, it
           initializes the object with the content of the so named
           resource file. For safe (non overwriting) loading, see
           the load method below.

           If the special file name "_RES_NODEFAULTS" is specified,
           the object is created completely empty, with not even
           the Resources class defaults in it.

           Returns the new object, or undef in case of error.

   load($resfile, $mode, $nonew);
           Loads resources from a file named $resfile into a
           resource database.

           The loading is controlled by the $mode argument as
           follows.

           If $mode is omitted, or equal to "replace", the content
           of the file is loaded as it is, save for syntax checks.

           If $mode is equal to "merge", resource merging via merge
           is performed if the database is not empty. This
           effectively prevents loaded resources from overwriting
           those already defined in the database.

           The $nonew argument controls whether loading of non
           already defined resurces is allowed. If it is true, safe
           loading is performed: attempting to load non-wildcarded
           resource names that do not match those already present
           in the database causes an error. This can be useful if
           you want to make sure that only pre-defined resources
           (for which you presumably have hardwired defaults) are
           loaded. It can be a safety net against typos in a
           resource file.

           Use is made of Safe::reval to parse values specified
           through Perl constructors (only constants, anon hashes
           and anon arrays are allowed).

           Returns 1 if ok, 0 if error.

   merge(\%defaults);
           Merges the resources of $res with the content of the
           resource hash %defaults. Only non-wildcarded names are
           admissible in %defaults. Merging does *not* change the
           value of resources already defined in $res.

           Note that merging reflects subclassing in that the names
           of default resources of a base classe are prepended with
           the name of the caller package (lowercased and stripped
           of all foo::bar:: prefixes), followed by a dot. In the
           above example, the defaults of HotDog will be renamed,
           after merging as:

              hotdog.taste, hotdog.meatcolor, ...


           and, if Bell::Taco is a new blessed HotDog, then they
           will be translated again upon merging, to read:

              taco.hotdog.taste, taco.hotdog.meatcolor, ...


           And so on all the way up to the main package, but with
           the application name ($0, a.k.a $PROGRAM_NAME in
           English) prepended in place of "main". See also the
           documentation of the "byclass" method below for some
           conditions under which this will not work properly.

           The new names are the ones to use when accessing these
           resources by name.

           Again, if a resource is already defined when merge is
           entered, than its values overrides the defaults. See
           also the EXAMPLES section.

           Returns 1 if OK, 0 if error.


 4.2. Looking up resources

   The values and documentation strings stored in a Resource object
   can be accessed by specifying their names in three basic ways:

   directly ("byname" methods)
           As in "my.nice.cosy.couch" .

   by a pattern ("bypattern" methods)
           As in "m??nice.*" .

   hierarchically ("byclass" methods)
           If class My is a Nice, and Nice is a Cosy, and if the
           current stack of method calls goes from package My to
           Cosy, then asking for "couch" in package Cosy gets you
           the value/doc of "my.nice.cosy.couch". This behaviour is
           essential to proper resource subclassing, as explained
           in detail below.


   The "bypattern" methods must search through the Resource object,
   while the "byclass" methods must work through call frames and
   ISA lists. Both ways tend to be slow in case of large resource
   databases, so the "byvalue" methods should always be used where
   appropriate. See the EXAMPLE section for more.

   It is also possible to retrieve the whole content of a resource
   database ("names" and "each" methods)

   Note that all the resource lookup methods return named (non
   "wildcarded") resources only. Wildcarded resources (i.e. those
   specified in resource files, and whose names contain one or more
   '*') are best thought as placeholders, to be used when the value
   of an actual named resource is set.

   For example, a line in a resource file like

             *background : yellow


   fixes to yellow the color of all resources whose name ends with
   "background". However, your actual packages will never worry
   about unless they really need a background. In this case they
   either have a "background" resource in their defaults hash, or
   subclass a package that has one.

   valbyname($name);

   Retrieves the value of a named resource from a Resource database. The $name
   argument is a string containing a resource name with no wildcards.
           The resource is first looked up with the program name
           ($0) automatically prepended to the passed name. If this
           fails, a second search is done using the passed name
           verbatim.

           Returns the undefined value if no such resource is
           defined.

   docbyname($name);
           Retrieves the documentation string of a named resource
           from a Resource database. The $name argument is a string
           containing a resource name with no wildcards.

           The resource is first looked up with the program name
           ($0) automatically prepended to the passed name. If this
           fails, a second search is done using the passed name
           verbatim.

           Returns the undefined value if no such resource is
           defined.

   bypattern($pattern);
           Retrieves the full names, values and documentation
           strings of all the named (non wildcarded) resources
           whose name matches the given $pattern. The pattern
           itself is string containing a Perl regular expression,
           *not* enclosed in slashes.

           Returns a new Resource object containing only the
           matching resources, or the undefined value if no matches
           are found.

   valbypattern($pattern);
           Retrieves the full names and values of all named (non
           wildcarded) resources whose name matches the given
           pattern.

           Returns a new Resource object containing only names and
           values of the matching resources (i.e. with undefined
           doc strings), or the undefined value if no matches are
           found.

   docbypattern($pattern);
           Retrieves the full names and documentation strings of
           all named (non wildcarded) resources whose name matches
           the given pattern.

           Returns a new Resource object containing only names and
           docs of the matching resources (i.e. with undefined
           resource values), or the undefined value if no matches
           are found.

   byclass($suffix);
           Resources are naturally ordered with respect to a
           hierarchy of classes, in that if two resource names
           share a common suffix, then the resource defined in the
           subclass overrides the one of a base class (unless the
           former is wildcarded in a resource file).

           For example, if class HotDog has a default for a
           resource named "hotdog.pickles", and class Taco (a
           subclass of HotDog) has a default for
           "taco.hotdog.pickles", then we expect that the latter
           should override the former in a Taco object.

           Note however that we do *not* want
           "mc.donalds.hotdog.pickles" to override
           "taco.hotdog.pickles", for a Mc class unrelated to Taco.
           This means that finding the right default in the
           database is not just a matter of counting dots, but of
           following a class hierarchy,

           This method returns a 3 element list containing the
           name/value/doc tuple of the the most subclassed resource
           from the current class, among those having a common
           suffix. In the above example, a call like

                   package HotDog
                   ...
                   ($name,$value,$doc) = $res->byclass("pickles");


           will set $name, $value and $doc equal to those of the
           "taco.hotdog.pickles" resource, if this HotDog is
           subclassed by Taco, and to those of
           "mc.donalds.hotdog.pickles", if it is subclassed by Mc
           via Donalds instead.

           To do this, the algorithm walks upward in the current
           subroutine call stack, and looks up the ISA list of each
           caller package to determine whether the callers are
           subclasses or not. Since it depends on the current call
           stack, it will work only when calls are really nested,
           i.e. with inherited methods or explicitly nested calls
           (e.g. in the "new" method of subclasses).

           The passed name suffix must not contain wildcards, nor
           start with a dot.

           Be careful not to confuse the "byclass" with the
           "byname" and "bypattern" retrieval methods: they are
           used for two radically different goals. See the EXAMPLES
           section for more.

           Returns the empty list if no resources are found for the
           given suffix, or if the suffix is incorrect.

   namebyclass($suffix);
           As the byclass method above, but returns just the
           resource name (i.e. the suffix with all the subclasses
           prepended).

   valbyclass($suffix);
           As the byclass method above, but returns just the
           resource value.

   docbyclass($suffix);
           As the byclass method above, but returns just the
           resource documentation.

   each;   Returns the next name/[value,doc] pair of the named (non
           wildcarded) resources in a resource database, exactly as
           the each Perl routine.

   names;  Returns a list of the names of all named (non-wildcarded)
           resources in a resource database, or undef if the
           databasee is empty.

 4.3. Assigning and removing Resources

   put($name, $value, $doc);
           Writes the value and doc of a resource in the database.
           It is possible to specify an empty documentation string,
           but name and value must be defined.

           Wildcards ('*' characters) are allowed in the $name, but
           the $doc is ignored in this case (documentation is
           intended for single resources, not for sets of them).

           The value is written unchanged unless the resource
           database already contains a wildcarded resource whose
           name includes $name (foo*bar includes foo.bar,
           foo.baz.bar, etc.). In this case the value of the
           wildcarded resource overrides the passed $value.

           Returns 1 if ok, 0 if error.

   removebyname($name);
           Removes the named (non wildcarded) resources from the
           database.

           Returns 1 if OK, 0 if the resource is not found in the
           database.

   removebypattern($name);
           Removes from the database all resources (both named
           *and* wildcarded) whose name mathes $pattern. An exactly
           matching name must be specified for wildcarded resources
           (foo*bar to remove foo*bar).

           Returns the number of removed resources.

 4.6. Viewing and editing resources.

   view;   Outputs the current content of a Resource object by piping
           to a pager program.

           The environment variable $ENV{RESPAGER}, the resource
           "resources.pager" and the environment variable
           $ENV{PAGER} are looked up, in this very order, to find
           the pager program. Defaults to /bin/more if none of them
           is found.

           The output format is the same of a resource file, with
           the resource names alphabetically ordered, and the
           resource documentation strings written as comments.

           Returns 1 if ok, 0 if error.

   edit($nonew);
           Provides dynamical resource editing of a Resource object
           via an external editor program. Only resource names and
           values can be edited (anyway, what is the point of
           editing a resource comment on the fly?).

           The environment variables $ENV{RESEDITOR}, the resource
           "resouces.editor", the environment variables
           $ENV{VISUAL} and $ENV{EDITOR} are looked up, in this
           very order, to find the editor program. Defaults to
           /bin/vi if none is found.

           The editor buffer is initialized in the same format of a
           resource file, with the resource names alphabetically
           ordered, and the resource documentation strings written
           as comments. The temporary file specified by the
           "resources.tmpfil" resource is used to initialize the
           editor, or '/tmp/resedit<pid>' if that resource is
           undefined.

           When the editor is exited (after saving the buffer) the
           method attempts to reload the edited resources. If an
           error is found the initial object is left unchanged, a
           warning with the first offending line in the file is
           printed, and the method returns with undef. Controlled
           resource loading is obtained by specifying a true value
           for the $nonew argument (see load).

           If the loading is successful, a new (edited) resource
           object is returned, which can be assigned to the old one
           for replacement.

           After a successful edit, the value of the resource
           "resources.updates" (which is always defined to 0
           whenever a new resource is created) is increased by one.
           This is meant to notify program the and/or packages of
           the resource change, so they can proceed accordingly if
           they wish.

 4.5. Miscellaneous methods

   write($filename);
           Outputs all resources of a resource database into a
           resource file (overwriting it).

           The resource documentation strings are normally written
           as comments, so the file itself is immediately available
           for resource loading. However, if the boolean resource
           "resources.writepod" is true, then the (non wildcarded)
           resources are output in POD format for your
           documentational pleasure.

           As usual in Perl, the filename can allo be of the form
           "|command", in which case the output is piped into
           "comma1nd".

           For resources whose value is a reference to an anon
           array or hash, it produces the appropriate constant Perl
           contructor by reverse parsing. The parser itself is
           available as a separate method named _parse (see package
           source for documentation).

           Returns 1 if ok, 0 if error.

 5. Resources of Resources

           As you may have guessed at this point, the default
           configuration of this package itself is defined by
           resources. The resource class is, of course, "resources"
           (meaning that all the names have a leading "resource.").

           To prevent chaos, however, these resources cannot be
           subclassed. This should not be a problem in normal
           applications, since the Resource package itself is not
           meant to be subclassed, but to help building a hierarchy
           of classes instead.

           The currently recognized resources, and their default
           values, are:

   resources.appname : ''
           The application name of this Resource object.

   resources.editor : /bin/vi
           Resource editor.

   resources.pager : /bin/more
           Resource pager.

   resources.separator : ':'
           Pattern separating names from values in resource files.

   resources.tmpfil : ''
           Editor temporary file.

   resources.updates : 0
           Number of resource updates.

   resources.verbosity : 1
           True to print warnings.

   resources.viewcols : 78
           Width of view/edit window.

   resources.writepod : false
           Boolean. True if the write method should output in POD
           format.


EXAMPLES
   Here is a more complex example of hyerarchical inheritance of
   resources. Package HotDog is subclassed from Junk and Food. The
   subclass has defaults for two resources defined by the base
   classes ("food.edible" and "junk.germs"), and their values will
   override the base class defaults.

   Remember that after merging all resources names are prefixed
   with the current class name.

      use Resources;
      package Food;
      %FoodDefaults = ( edible => "Sure" );

      sub new {
         my ($pack, $res) = @_;
         $res = new Resources unless $resources;
         $res->merge(\%FoodDefaults) || die ("can't merge defaults");

         my $food= bless {};
         $food->{Edible} = $res->valbyclass("edible");
         # Use valbyclass so a subclass like HotDog can change this by its
         # defaults.
      }

      # A Food method to say if it can be eaten.
      sub eat {
         my $food=shift;
         return $food->{Edible};
      }

      package HotDog;
      use Junk;
      use Food;
      use Carp;
      @ISA = qw( Junk Food );

      %HotDogDefaults =
         (
          taste         => "Yuck!",
          meatcolor     => "Cadaveric",
          stinks        => 1,
          'food.edible' => "Perhaps", # Quotes needed in these
          'junk.germs'  => "Amoeba"   #    names because of the dots
         );

      sub new {
         my ($package, $res) = @_;

         $res = new Resources unless $resources;
         $res->merge(\%HotDogDefaults) || die ("can't merge defaults");

         my $food   = new Food ($res); # Override Food's edible.
         my $junk   = new Junk ($res); # Override Junks's germs.
         my $hd = bless { %{food}, %{junk} }; # Merge and subclass.

         $hd->{Meatcolor} = $res->valbyclass("meatcolor");
         # Same reason as above

         return $hd;
      }

      # A HotDog method to get a taste via resources
      sub taste {
         my ($hd, $res) = @_;
         print $res->valbyname("hotdog.taste");
      }

      package main;
      # Whatever
      #
      $res = new Resources("AppDefltFile") || die;
      $snack = new HotDog($res);
      $gnam = $snack->eat();  # hotdog.food.edible overridees food.edible,
                              #   so here $gnam equals "Perhaps"

      $slurp = $snack->taste($res) # $slurp equals "Yuck!", unless
                                   # this resource too was overridden
                                   # by a subclass of HotDog , or
                                   # differently specified in
                                   # "AppDefltFile"


   Note the different use of valbyclass and valbyname to access
   resources:

   valbyclass
   Is used for the resources like "edible" in Food, i.e. resources
   which are defined by the current class in its defaults. This
   because a subclass of it (e.g. HotDog) might have overridden
   them (by having an entry for "food.edible" in its defaults.

   Generally speaking, you should not use valbyclass outside the
   new (creation and initialization) method of a class.

   valbyname
   Is used after the initialization, when all subclassed resources
   have been resolved nicely. In any case, its arguments is the
   complete resource name, with all its dots.

SEE ALSO
   Safe(3).

BUGS
   The underlying idea is to use a centralized resource database
   for the whole application. This ensures uniformity of behaviour
   across kin objects, but allow special characterizations only at
   the cost of subclassing.

AUTHOR
           Francesco Callari <[email protected]>
           Artifical Perception Laboratory,
           Center for Intelligent Machines,
           McGill University.

           WWW: http://www.cim.mcgill.ca/~franco/Home.html


COPYRIGHT
   Copyright 1996 Francesco Callari, McGill University

   Permission to use, copy, modify, and distribute this software
   and its documentation for any purpose without fee is hereby
   granted without fee, provided that the above copyright notice
   appear in all copies and that both that copyright notice and
   this permission notice appear in supporting documentation, and
   that the name of McGill not be used in advertising or publicity
   pertaining to distribution of the software without specific,
   written prior permission. McGill makes no representations about
   the suitability of this software for any purpose. It is provided
   "as is" without express or implied warranty.

   MCGILL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
   INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
   IN NO EVENT SHALL MCGILL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
   CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
   LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
   NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.




--
----------------------------------------------------------------------------
Franco Callari
Centre for Intelligent Machines          "Beati coloro che hanno fame e sete
McGill University, 3480 University        di giustizia, perche` saranno
Montreal, Quebec, Canada, H3A 2A7         giustiziati."      (P. Bellocchio)

email: [email protected] -- phone: +(514) 398 2185 -- fax: +(514) 398 7348
WWW: <a href="http://www.cim.mcgill.ca/~franco/Home.html> Franco </a>
-----------------------------------------------------------------------------