Config

Denys Duchier

provides
x-ozlib://duchier/ap/Config.ozf
x-ozlib://duchier/ap/Config.exe

Purpose

This package permits to configure application parameters in very flexible ways. Every parameter is explicitly declared with a descriptor explaining how to compute its value.

Usage

A parameter is denoted by a `key' which is a literal. We recommend that a package parameter be denoted by a URI derived e.g. from the package MOGUL URI or the package URI. For example, parameter p1 in a package with URI x-ozlib://foo/bar might be given the key x-ozlib://foo/bar/p1. This way you can easily avoid collision with parameters from other packages.

You would normally import the Config module as follows: import Config at 'x-ozlib://duchier/ap/Config.ozf'

Declaring Parameters

Every package parameter must be declared by invoking Config.decl with the parameter's key and a descriptor explaining how to compute its value. {Config.decl Key Descriptor} A descriptor D is a term of one of the forms listed below. A descriptor may or may not be defined. When it is defined, it has a value.

[D1 ... Dn]
where Di is a descriptor. Each descriptor is tried in turn until one is found that is defined. Its value is returned.
property(P)
is defined when {Property.get P} exists, in which case its value is returned.
environ(V)
is defined when environment variable V is set, in which case its value is returned.
call(F)
is defined when {F} doesn't raise an exception, in which case the value of {F} is returned. When {F} raises an exception, the latter is caught and ignored, but call(F) is known to be undefined.
value(V)
is always defined and has value V
platform(P D)
is defined when {Property.get 'platform.os'} is P and descriptor D is defined, in which its value is returned. P may also be a list of platforms.
when(D F)
is defined when D is defined, in which case, supposing D has value V, when(D F) evaluates to {F V}.
ask(Msg [width:W] [type:{file,openfile,savefile}])
is always defined. Evaluation first checks the user's persistent answer database for the desired parameter. If a value is found, it is returned. Else the user is prompted using a dialog showing message Msg and with an entry for typing the reply of width W (default 30). If {Config.getConfirm} is true then the user is prompted even if a value is found in the persistent database. This value is simply used to initialize the dialog's entry. The value typed by the user is returned as the value, it is also saved in the user's persistent database.

The type option makes it possible to obtain a more specialized gui. Currently, this is only available for files. Specifying type:file prompts the user with a file selector widget. type:savefile also asks whether the user wants to overwrite the file, in case it already exists.

Evaluating Parameters

You can obtain the value of a parameter by invoking Config.get with the parameter's key as an argument: {Config.get +Key ?Value} If the parameter's value has previously been computed, then the cached value is returned. Otherwise the parameter's descriptor is evaluated. If the descriptor is defined, its value is returned, otherwise an exception is raised.

Saving the persistent database

Whenever the user is prompted for a parameter's value, this answer is written into a database of answers. In order to save this database, you must invoke: {Config.save} The database is only really written if it has been modified.

Export

{Config.confirm.get}
is the user always prompted for confirmation when evaluating an ask(...) descriptor? Default is false.
{Config.confirm.set +B}
set the confirmation flag.
{Config.decl +Key +Descriptor}
declare a parameter identified by Key and with the given Descriptor.
{Config.get +Key ?Value}
get the value of a parameter identified by Key.
{Config.save}
if the persistent database of answers has been modified, try to write it back. This will never raise an exception, even if it is not possible to write back the database.
{Config.getRecord}
Return the current contents of the persistent answer database as a record.

Example

Suppose that your `sherlock' application needs to be able to invoke the `pipe' helper application. You could declare a x-ozlib://sherlock/pipe key as follows {Config.decl 'x-ozlib://sherlock/pipe' [property('sherlock.pipe') environ('SHERLOCK_PIPE') when([property('sherlock.home') environ('SHERLOCK_HOME')] fun {$ Home} Home#'/'#'pipe.exe' end) ask("Enter path to Sherlock's pipe executable")]} First checking property('sherlock.pipe') makes it possible for example to override the path to the pipe application using an option argument when invoking the application. Just allow an option argument of the form: --pipe=PATH and when it is provided, set property sherlock.pipe to PATH. You can also override using environment variable SHERLOCK_PIPE. Else you can try to construct the path to the pipe.exe executable using a `home' prefix which may be specified by property sherlock.home (haha! :-) (again can be specified by an option argument) or by environment variable SHERLOCK_HOME. If all else fails. Look up in the user's persistent database to see whether the user has already answered this question before. Otherwise, prompt the user using an interactive dialog.

Config.exe

x-ozlib://duchier/ap/Config.exe is a graphical application to visualize the contents of the persistent database and delete entries no longer desired.

Installation

This package can be installed by following the usual configure, build, install procedure, i.e. by executing a the shell: ./configure make install By default, all files of the package are installed in the user's ~/.oz directory tree. In particular, all modules are installed in the user's private cache.


Denys Duchier