NAME

Config::Interactive - config module with support for interpolation, XML fragments and interactive UI

VERSION

Version 0.04

DESCRIPTION

This module opens a config file and parses it's contents for you. The new() method accepts several parameters. The method 'parse' returns a hash reference which contains all options and it's associated values of your config file as well as comments above. If the dialog mode is set then at the moment of parsing user will be prompted to enter different value and if validation pattern for this particular key was defined then it will be validated and user could be asked to enter different value if it failed. The format of config files supported by Config::Interactive is <name>=<value> pairs or XML fragments (by XML::Simple, namespaces are not supported) and comments are any line which starts with #. Comments inside of XML fragments will pop-up on top of the related fragment. It will interpolate any perl variable which looks as ${?[A-Za-z]\w+}? . Please not that interpolation works for XML fragments as well, BUT interpolated varialbles MUST be defined by key=value definition and NOT inside of other XML fragment! The order of appearance of such variables in the config file is not important, means you can use $bar variable anywhere in the config file but set it to something on the last line (or even skip setting it at all , then it will be undef). It stores internally config file contents as hash ref where data structure is: Please note that array ref is used to store XML text elements and scalar for attributes.

 ( 'key1' => {'comment' => "#some comment\n#more comments\n", 
              'value' => 'Value1',
              'order' => '1',
            },
 'key2' => {'comment' => "#some comment\n#more comments\n", 
            'value' =>  'Value2',
            'order' => '2'
           },
  
 'XMLRootKey' =>  {'comment' => "#some comment\n#more comments\n",
                   'order' => '3',
                   'value' =>  { 
                                 'xmlAttribute1' => 'attribute_value',
                                 'subXmlKey1' =>    ['sub_xml_value1'],
                                 'subXmlKey2' =>    ['sub_xml_value2'],
                                 'subXmlKey3'=>     ['sub_xml_value3'],	
                 }	      
   }
 ) 

The normalized ( flat hash with only key=value pairs ) view of the config could be obtained by getNormalizedData() call. All tree- like options will be flatted as key1_subkey1_subsubkey1. So the structure above will be converted into:

('key1' => 'Value1', 
 'key2' =>   'Value2', 
 'XMLRootKey_xmlAttribute1' => 'attribute_value',
 'XMLRootKey_subXmlKey1' =>  'sub_xml_value1' ,
 'XMLRootKey_subXmlKey2' =>   'sub_xml_value2',
 'XMLRootKey_subXmlKey3'=>    'sub_xml_value3' , )    

the case of the key will be preserved.

SYNOPSIS

Provides a convenient way for loading config values from a given file and returns it as a hash structure, allows interpolation for the simple perl scalars ( $xxxx ${xxx} ) Also, it can run interactive session with user, use predefined prompts, use validation patterns and store back into the file, preserving the order of original comments. Motivation behind this module was inspired by Config::General module which was missing required functionality (preservation of the comments order and positioining, prompts and validation for command line based UI ). Basically, this is Yet-Another-Config-Module with list of features found to be useful.

 use Config::Interactive;
 
 # define prompts for the keys
 my %CONF_prompts = ('username' =>  'your favorite username ',
                     'password'=>   'most secure password ever ', 
                     );
 
 my %validkeys = ('username' =>    ' your favorite username ',
                  'password'=>   '  most secure password ever ', 
                 );
 
 # Read in configuration information from some.config file 
 
 
 my $conf = Config::Interactive->new({file => 'some.conf', 
                                      prompts => \%CONF_prompts, 
                                      validkeys => \%validkeys,
                                      dialog => '1'}); 
 # OR
 # set interactive mode
   $conf->setDialog(1);
 #
 #   use dialog prompts from this hashref
   $conf->setPrompts(\%CONF_prompts); 
 #   
 #  set delimiter
 $conf->setDelimiter('='); # this is default delimiter
 #
 #   use validation patterns from this hashref
 $conf->setValidkeys(\%validkeys ); 			   
 #   parse it, interpolate variables and ask user abour username and password, validate entered values
  
 $conf->parse();

 # store config file back, preserving original order and comments  
 $conf->store; 			 

METHODS

new({})

creates new object, accepts hash ref as parameters

Possible ways to call new():

$conf = new Config::Interactive(); 

# create object and will parse/store it within the my.conf file
$conf = new Config::Interactive({file => "my.conf"}); 

# use current hash ref with options
$conf = new Config::Interactive({ file => "my.conf", data => $hashref });  

# prompt user to enter new value for every -key- which held inside of  %prompts_hash  
$conf = new Config::Interactive({ file => "my.conf", dialog => 'yes', prompts => \%promts_hash }); 
 
# set delimiter as '?'... and validate every new value against the validation pattern
$conf = new Config::Interactive({ file => "my.conf", dialog => 'yes', delimiter => '?',
                        prompts => \%promts_hash, validkeys => \%validation_patterns }); 

This method returns a Config::Interactive object (a hash blessed into Config::Interactive namespace. All further methods must be used from that returned object. see below. Please note that setting dialog option into the "true" is not enough, because the method will look only for the keys defined in the %prompts_hash An alternative way to call new({}) is supplying an option -hash with hash reference to the set of the options.

debug
prints a lot of internal stuff if set to something defined
file
name of the  config file

file => "my.conf"
data
A hash reference, which will be used as the config, i.e.:

data => \%somehash,  

where %somehash should be formatted as:

 ( 'key1' => {'comment' => "#some comment\n#more comments\n", 
              'value' => 'Value1',
              'order' => '1',
             },
                    
   'key2' => {'comment' => "#some comment\n#more comments\n", 
              'value' =>  'Value2',
              'order' => '2'
             },
  
   'XML_root_key' =>  {'comment' => "#some comment\n#more comments\n",
                       'order' => '3',
                       'value' =>  { 
                                    'xml_attribute_1' => 'attribute_value',
                                    'sub_xml_key1' =>    ['sub_xml_value1'],
                                    'sub_xml_key2' =>    ['sub_xml_value2'],
                                    'sub_xml_key3'=>     ['sub_xml_value3'],	  
                                   } 
                               
                     }
)
dialog

Set up an interactive mode, Please note that setting dialog option into the true is not enough, because this method will look only for the keys defined in the %prompts_hash ,

delimiter

Default delimiter is =. Any single character from this list = : ; + ! # ? - * is accepted. Please be careful with : since it could be part of some URL for example.

prompts

Hash ref with prompt text for particular -key- , where hash should be formatted as:

('key1' =>   ' Name of the key 1',
 'key2' =>   'Name of the key 2 ',
 'key3' =>  ' Name of the key 3 ', 
 'sub_xml_key1' =>  'Name of the key1   ',
 'sub_xml_key2' =>  ' Name of the key2 ' ,
 )

It will reuse the same prompt for the same key name.

validkeys

Hash ref with validation patterns for particular -key- where hash should be formatted as:

 ( 'key1' =>   '\w+',
   'key2' =>   '\d+',
   'key3' =>  '\w\w\:\w\w\:\w\w\:\w\w\:\w\w\:\w\w\', 
   'sub_xml_key1' =>  '\d+',
   'sub_xml_key2' =>  '\w+' ,
   
   
) 

It will reuse the same validation pattern for the same key name as well.

setDelimiter()

set delimiter from the list of supported delimiters  [\=\+\!\#\:\;\-\*] , 

setDialog()

set interactive mode (any defined value)
accepts: single parameter - any defined
returns: current state

setFile()

set  config file name
accepts: single parameter - filename
returns: current filename

setValidkeys()

set  vaildation patterns hash
accepts: single parameter - reference to hash with validation keys
returns: reference to hash with validation keys

setPrompts()

set  prompts hash
accepts: single parameter - reference to hash with prompts  
returns: reference to hash with  prompts 

getNormalizedData()

This method returns a  normalized hash ref, see explanation above.
the complex key will be normalized
     'key1' => { 'key2' =>   'value' }
 will be returned as 'key1_key2' => 'value'
 accepts; nothing
 returns: hash ref with normalized config data

store()

Store into the config file,  preserve all comments from the original file
Accepts filename as  argument
Possible ways to call B<store()>:

$conf->store("my.conf"); #store into the my.conf file, if -file was defined at the object creation time, then this will overwrite it
 
$conf->store();  

parse()

  Parse config file, return hash ref ( optional)
  Accepts filename as  argument

  Possible ways to call B<parse()>:

 $config_hashref = $conf->parse("my.conf"); # parse  my.conf file, if -file was defined at the object creation time, then this will overwrite -file option

 $config_hashref = $conf->parse();  
 
 This method returns a  a hash ref.

DEPENDENCIES

XML::Simple, Carp, Data::Dumper

EXAMPLES

For example this config file:

# username
USERNAME = user
PASSWORD = pass
#sql config
<SQL production="1">
    <DB_DRIVER>
              mysql
    </DB_DRIVER>
    <DB_NAME>
              database
    </DB_NAME>
</SQL>

SEE ALSO

Config::General

AUTHOR

Maxim Grigoriev <maxim |AT| fnal.gov>, 2007-2008, Fermilab

COPYRIGHT

Copyright(c) 2007-2008, Fermi Reasearch Alliance (FRA)

LICENSE

You should have received a copy of the Fermitools license with this software. If not, see http://fermitools.fnal.gov/about/terms.html