Misc::DmUtil::ValidatedConfig

The ValidatedConfig class builds on ConfigFile to provide a representation of a config file which has defined rules around the structure and data.

Basic use

Create with API

use Misc::DmUtil::ValidatedConfig;

my $reg = {
  name  => { },
  age   => { format  => "int" },
  alias => { max     => "unlimited" }
  };
  
my $vc = new Misc::DmUtil::ValidatedConfig(registry => $reg);

# OK
$vc->valuesSet("name", "Bob");

# Not OK, too many values
$vc->valuesSet("name", ["Bob", "John"]);

# OK
$vc->valuesSet("age", 38);

# Not OK, incorrect format
$vc->valuesSet("age", "late thirties");

# OK
$vc->valuesSet("alias", ["Kipper", "Flipper"]);

# "kipper"
print $vc->valueFirst("alias");

# "kipper:flipper"
print join(":", @{$vc->values("alias")});

# Write to file
$vc->write(file => "output.config");

Create from file

my $vc = new Misc::DmUtil::ValidatedConfig(
  file      => "input.config",
  registry  => $reg);

$vc->valuesSet("alias", ["Kipper", "Flipper"]);

$vc->write();

Access

Use valuesFirst() to return the first (and maybe only) value at a specified address, will return undef if not-set. =values()= returns all entries as an array reference.

The valuesMap() method returns a hash ref of all children, given the address of a group. Values are always returned as arrays, even if only a single value is allowed. valuesMap("") will return the whole config structure as a hash.

name  => ["Bob"],
age   => [38],
alias => ["Kipper", "Flipper"],
transport => {
  car => {
    make => ["Audi"],
    age  => [2]}}

The variant valuesMapFlat() returns a single level hash with the full address as the key.

name  => ["Bob"],
age   => [38],
alias => ["Kipper", "Flipper"],
transport/car/make => ["Audi"],
transport/car/age  => [2]

THe method valuesSet() will set all values at the specified address.

Registry

Structure

The registry hash defines the allowed structure and data values. The first level of the hash represents the first level of the file.


$reg = {
  name  => {},
  users => { format => "int" }};
  

name   = MyServer
users  = 10

The address of the name attribute is simply name, e.g.

print $obj->valueFirst("name");

The format allows for hierarchical groupings.


$reg = {
  name        => {},
  users       => { format => "int" }};
  peers => {
    type      => "group",
    key       => "never",
    children  => {
      host    => { max => "unlimited" }}}};
      ip      => { max => "unlimited" }}}};
      

name  = MyServer
users = 10      

[peers]
  ip    = 192.168.0.1
  ip    = 192.168.0.2
  host  = server2
  host  = server3
[/peers]

To get all of the IP values for the peers the address is peers//ip (note the double slash).

Some groups may have names (known as a key). The key attribute can be never, always or optional.


$reg = {
  name        => {},
  users       => { format => "int" }};
  share => {
    type      => "group",
    key       => "always",
    children  => {
      path    => { };
      read    => { max => "unlimited" }
      write   => { max => "unlimited" }}}};
      

name  = MyServer
users = 10      

[share public]
  read  = all
  write = admin
[/share]


[share private]
  read  = bob
  read  = fred
  write = bob
[/share]

The address for the users who can read the private share is share/private/read.

Formats

The format attribute determines how the input value is parsed. If the input cannot be parsed as the stated format the configuration is invalid.

Format

Returns

Description

bool

0 or 1

Attempts to parse as boolean, e.g. true, false, yes, no, 1, 0

dir

FilePath

A directory, will always tag as a directory regardless of trailing slash

datetime

DateTime

A date with optional time

filepath

FilePath

A filepath, may be tagged as a file location or directory location depending on input string

int

scalar

An integer, positive or negative

number

scalar

An integer or real number

string

scalar

Simple string reading, no special requirements. Default

Structure validation

Attribute

Description

Values

Groups

allowed

Arrayref of values that are allowed

Yes

No

allowedKeys

Arrayref of permissable keys for groups

No

Yes

max

Maximum number of values that can be set. "unlimited" means no limit. Default is 1

Yes

Yes

min

At least this many values must be set. So setting to 1 means that a value is required. Default is 0

Yes

Yes

Defaults

For values the default attribute provides values that will be set unless overriding by the file or API. The value can be a scalar or an array ref. If any value is a code reference that will be executed and the values added to the defaults.

  type  => { default => "file"              }, 
  uuid  => { default => \&getUniqueId()     },
  users => { max => 10, default => ["public", "admin"] },

For groups the default specifies which keys will be generated by default. Note that values in a group will only be defaulted if the group itself exists.

$reg = {
  share => {
    type      => "group",
    children  => {
      description   => { },
      user          => { default => "admin" }}}};
      
$obj = new Misc::DmUtil::ValidatedConfig(registry => $reg);

# undef
print $obj->valueFirst("share/public/user");

$obj->valuesSet("share/public/description", "Test");

# "admin"
print $obj->valueFirst("share/public/user");

In some files you may not care about the named groups feature and just want a simple nested file. In this case you can just create a default group of "".

$reg = {
  access => {
    type      => "group",
    key       => "never",
    default   => "",
    children  => {
      read  => { max => 10, default => ["public", "admin"]},
      write => { max => 10, default => "admin" }}}};

$obj = new Misc::DmUtil::ValidatedConfig(registry => $reg);

# "public, admin"
print join(", ", @{$obj->values("access//read")});

Methods

Method

Description

bool defaultUsed()

Was any default value used

scalar file()

Filename passed into constructor

scalar valueFirst(address)

First value at address

arrayref values(address)

All values at address

hashref valuesMap(address)

Map of all values at address and below

hashref valuesMapFlat(address)

Flattened map of all values at address and below

bool valuesSet(address, values)

Set/replace all values at address. Will return false on address/validation error

bool write()

Write file. Will return false on validation error