The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Config::Strict - Add strict name- and type-checking to configuration data

VERSION

0.07 (alpha release)

SYNOPSIS

    use Config::Strict;
    use Declare::Constraints::Simple -All;               # For custom checks

    my $config = Config::Strict->new( {
        params => {                                      # Parameter types & names
            Bool     => [ qw( my_bool1 my_bool2 ) ],     # Multiple parameters
            Int      => 'my_i',                          # Single parameter
            Num      => 'my_n',
            HashRef  => 'my_href',
            Enum     => { 
                my_enum => [ qw( v1 v2 ), undef ] 
            },
            Anon   => {                                  # anonymous profiles
                my_pos2 =>                               # Positive number
                    And( IsNumber, Matches( qr/^[^-]+$/ ) ),
                my_nest => IsA( 'Config::Strict' ),      # Nested configuration
            }
        },
        required => [ qw( my_bool1 my_n ) ],             # Required parameters
        defaults => {                                    # Default values
            my_bool1    => 1,
            my_enum     => 'e2',
            my_n        => -1.1,
            my_pos2     => 1_000,
        },
    } );
    
    # Access and change the data
    
    # Retrieve a single value
    $got = $config->get( 'my_n' );                # $got = -1.1
    
    # Retrieve a list of values
    @got = $config->get( qw( my_bool1 my_n ) );   # @got = ( 1, -1.1 )
    
    # Set multiple parameters
    $config->set( my_bool1 => 1, 'my_pos2' => 2 );   
    
    # Unset parameters
    $config->unset( 'my_n' );
    $config->param_is_set( 'my_n' );              # false
    
    # The following will die:
    $config->get( 'foo' );                # foo doesn't exist
    $config->set( 'my_i' => 2.2 );        # my_i must be an integer
    $config->set( 'my_pos2' => -5 );      # my_pos2 must be positive
    $config->unset( 'my_n' );             # my_n is required
    

DESCRIPTION

Config::Strict wraps Declare::Constraints::Simple to enable strict parameter name- and type-checking on configuration data. That is, it will complain anytime an attempt is made to access a parameter with an invalid name or type; or if an attempt is made to unset a required parameter. Both built-in and custom types can be used to build a validation profile for the entire configuration.

This module is meant to be used alongside any configuration parser that hashes configuration data.

See Declare::Constraints::Simple::Library for an index to available constraints.

CONSTRUCTING A TYPE SYSTEM

Declare the configuration profile during construction:

new

    $config = Config::Strict->new( \%config_profile );

%config_profile is a multi-level hash with the following top-level keys:

params (Required)

Points to the hash of parameter types and names, where the keys are the built-in Config::Strict types (more below).

The values are either a single parameter name or an arrayref of parameter names, with the exception of the special types Enum and Anon which point to a uniquely defined hashref.

Any parameter not named here cannot be added later - any attempt to access a parameter that is not provided in the constructor will result in an error.

Built-In Parameter Types:

Bool => $param | [ $param1, $param2, ... ]

Parameters taking the value 0 or 1.

Int => $param | [ $param1, $param2, ... ]

Integer parameters.

Num => $param | [ $param1, $param2, ... ]

Generic number parameters.

Str => $param | [ $param1, $param2, ... ]

Generic string parameters.

Enum => { $enum1 => [ $val1, $val2, ... ], ... }

Enumerated parameters. The Enum key points to a hashref with parameter-values pairs, where valid values for the enumerated parameter are provided as an arrayref.

It may be cleaner to instead register your own named enum using IsOneOf. (more below)

This, along with Anon, is the only exception to the normal declaration syntax.

Regexp => $param | [ $param1, $param2, ... ]

Compiled regexp parameters (with qr//).

ArrayRef => $param | [ $param1, $param2, ... ]

Generic list parameters.

HashRef => $param | [ $param1, $param2, ... ]

Generic hash parameters.

CodeRef => $param | [ $param1, $param2, ... ]

Generic code parameters.

Anon => { $param1 => $profile1, ... }

Anonymous profiles. The Anon key points to a hashref with parameter-profile pairs, where profiles are declared via imported Declare::Constraints::Simple functions. These code profiles will in fact return a Declare::Constraints::Simple::Result which evaluate properly in boolean context along with other additional information when used as an object.

Note that, unlike registered profiles (below), anonymous code blocks cannot be used.

required (Optional)

Points to a arrayref of parameter names that must have valid values at all times. These parameters must also be given a default value.

The special value '*' (the literal scalar value; not an arrayref) is a shortcut to specify that all parameters are to be required.

defaults (Optional)

Points to a hashref of default values to any number of parameters. Those parameters listed in required must be present in this section.

USER TYPE REGISTRATION

Aside from the default type built-ins (Bool,Int,...) you can register your own named types to streamline construction and add your own validation logic:

register_types

    Config::Strict->register_types( 
        $name1 => $constraint1, 
        $name2 => $constraint2, 
        ... 
    );

An example:

        use Date::Calc qw(Decode_Month);        # For 'FirstQuarter'
        
        # Register user-defined types...
        Config::Strict->register_types(
            
            # Normal profiles:
            'Private'        => Matches( qr/^_/ ),
            'ArrayOfAllCaps' => IsArrayRef( Matches( qr/^[A-Z]+$/ ) ),
            'LessThan8Chars' => HasLength( 1, 8 ),
            'Size'           => IsOneOf( qw( small medium large ) ),
            
            # Custom routines:
            'FirstQuarter'   => sub { Decode_Month($_[0]) <= 4 },
            
            ...
        );
        
        # ...and use them to make a configuration profile:
        my $config = Config::Strict->new( {
                params => {
                    Private        => 'myvar',
                    ArrayOfAllCaps => 'caps',
                    LessThan8Chars => [ qw( short1 short2 ) ],
                    Size           => 'beverage',
                    FirstQuarter   => 'date_q1',
                    ...
                },
                ...
    } );

The parameters syntax is the same for that of any of the existing built-ins that take either a single name or arrayref of names. More importantly, they can be used in the same way.

Bare code blocks are automatically converted to named Declare::Constraints::Simple profiles so you can easily provide your own validation logic.

Names cannot duplicate an existing registered type name.

METHODS

GETTING AND SETTING PARAMETER VALUES

These methods will die with a stack trace if a given parameter doesn't exist in the configuration profile, or if an attempt is made to set a parameter with an invalid value.

get

    @values = $config->get( $param1, $param2, ... );

Returns the list of values corresponding to each parameter.

set

    $config->set( $param1 => $value1, $param2 => $value2, ... );

Sets each parameter-value configuration pair.

unset

    $config->unset( $param1, $param2, ... );

Unsets each parameter; internally deletes the parameter-value pair from the underlying parameter hash.

Required parameters cannot be unset.

PARAMETER CHECKING

The following methods can be used to check conditions on parameters without killing the program.

validate

    $ok = $config->validate( $param1 => $value1, $param2 => $value2, ... );

Returns true if all parameter-value pairs are valid; false otherwise.

param_exists

    $ok = $config->param_exists( $param );

Returns true if $param exists in the configuration; false otherwise.

param_is_set

    $ok = $config->param_is_set( $param );

Returns true if $param has been set; false otherwise.

param_is_required

    $ok = $config->param_is_required( $param );

Returns true if $param is a required parameter; false otherwise.

OTHER METHODS

all_params

    @params = $config->all_params();

Returns the list of all parameters in the configuration.

all_set_params

    @params = $config->all_set_params();

Returns the list of all set parameters in the configuration.

param_hash

    %data = $config->param_hash();

Returns a copy of the underlying configuration data as a list of key-value pairs.

param_array

    @data = $config->param_array();

Returns a copy of the underlying configuration data as an array of array references.

get_profile

    $profile = $config->get_profile( $param );

Returns the Declare::Constraints::Simple profile used to validate $param, or undef if $param isn't in the profile.

EXTENDING THE DEFAULT TYPES (OVERVIEW)

There are several ways to make your type system even more strict than the built-in parameter types:

1. Using "register_types" to register your own class-wide types.
2. Using the Anon key and combining any number of Declare::Constraints::Simple profiles.
3. Subclassing Config::Strict and overloading any of the _get_check, _set_check, and _unset_check validation methods to add your own general validation semantics. These methods are executed before "get", "set", and "unset", respectively.

SEE ALSO

Declare::Constraints::Simple

CAVEATS

This is an alpha release - the API is subject to change.

AUTHOR

Blake Willmarth

bwillmarth at gmail.com

BUGS

Please report any bugs or feature requests to bug-config-strict at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Config-Strict. I will be notified, and then you'll automatically be notified of progress on your bug as changes are made.

LICENSE AND COPYRIGHT

Copyright 2010 Blake Willmarth.

This program is free software; you can redistribute it and/or modify it under the terms of either:

  • the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version, or

  • the Artistic License version 2.0.