Config::apiLayers - Auto-prototyping object properties in multiple configuration layers.
use Config::apiLayers; my $cfg = new Config::apiLayers({ autoproto => 1, attributes => [qw(length width area)] }); # Set the default values $cfg->config({ data => { 'length' => 6, 'width' => 10, 'area' => sub { my $cfg = shift; return ($cfg->apicall('length') * $cfg->apicall('width')) } } }); $cfg->length( 3 ); print ("This rectangle has length ".$cfg->length." by width ".$cfg->width. ", with an area of ".$cfg->area.".\n"); $cfg->width( 4 ); print ("This rectangle has length ".$cfg->length." by width ".$cfg->width. ", with an area of ".$cfg->area.".\n");
Resulting output:
This rectangle has length 3 by width 10, with an area of 30. This rectangle has length 3 by width 4, with an area of 12.
Used as a base module or on its own to manage configuration properties of an application. Its default behavior is to auto-prototype property attributes. Validators can be used to validate values to be set. Configuration can be used with Getopt::Long and Getopt::LongUsage for obtaining configuration.
Getopt::Long
Getopt::LongUsage
Properties that are imported or directly configured can be stored in one or multiple layers, and do not immediately affect each other. When retrieved, the values of properties are obtained from the layers in a top-down fashion.
The values of properties can also be functions. When the value is retrieved, the function is executed which can be used to combine multiple property values together, or do smoething entirely different.
None. This module is Pure Perl. This module does not use AUTOLOAD.
# Style 1 - Only set the attributes, and each attribute stores a value. Order is retained. my $cfg = new Config::apiLayers({ autoproto => 1, attributes => [qw(length width area)] }); # Style 2 - Only set the attributes with a validator. Attributes with undef valdiator # store a provided values without validation. Order is NOT retained. my $val_greater_than_zero = sub { my $cfg = shift; my $attribute_name = shift; my $value = shift; return undef unless $value > 0; return $value; }; my $cfg = new Config::apiLayers({ autoproto => 1, attributes => { 'length' => $val_greater_than_zero, 'width' => $val_greater_than_zero, 'area' => sub { return undef }, # do not allow storing any value 'store_any' => undef } }); # Style 3 - Same as Style 2, but retain the order of the attributes in configuration. my $cfg = new Config::apiLayers({ autoproto => 1, attributes => [ {'length' => $val_greater_than_zero}, {'width' => $val_greater_than_zero}, {'area' => sub { return undef }}, # do not allow storing any value {'store_any' => undef} ] }); # Style 3 gives the ability to provide additional attribute configuration. # Configure optional information for use with C<Getopt::Long> and # C<Getopt::LongUsage> modules, while retaining order of the attributes. my $cfg = new Config::apiLayers({ autoproto => 1, attributes => [ { name => 'length', validator => $val_greater_than_zero, getoptlong => 'length|l:i', description => "The length of a rectangle" }, { name => 'width', validator => $val_greater_than_zero, getoptlong => 'width|w:i', description => "The width of a rectangle" }, { name => 'area', validator => sub { return undef }, # do not allow storing any value getoptlong => 'area|a', description => "The area of the rectangle, length times width" }, { name => 'store_any', validator => undef, getoptlong => 'store_any_value:s', description => "Store a value of your choosing, unvalidated" } ] }); # Example use of configuration # Set the default values (the first layer is layer number 0) $cfg->config({ data => { 'length' => 6, 'width' => 10, 'area' => sub { my $cfg = shift; return ($cfg->apicall('length') * $cfg->apicall('width')) } } }); # Perform the computation $cfg->length(5); $cfg->width(8); my $area = $cfg->area; # $area == 40
Add configuration data to either the given index layer, or the highest layer if index is not provided. Data is NOT validated.
index
# Configure the 2nd layer (layer numbering starts at 0) $cfg->config({ index => 1, data => { 'length' => 6, 'width' => 10, 'area' => sub { my $cfg = shift; return ($cfg->apicall('length') * $cfg->apicall('width')) } } });
Import the data, performing validation as available. This method will import each attribute individually with apicall, which performs the validation if a validator was configured (see new for configuring a validator for an attribute).
apicall
new
$cfg->importdata({ data => { length => 4, width => 2 } });
Export the data or specific configuration information.
Getopt::LongUsage::ParseGetoptLongConfig
my $getoptlong_config = $cfg->exportdata({ cfg => 'getoptlong' }); my %options; GetOptions( \%options, @$getoptlong_config ); $cfg->importdata({ data => \%options }); # Export Data from layers. Data for each attribute in top most layer is exported. my $exported_data = $cfg->exportdata({ data => undef });
Add a new configuration layer. If index is provided, then configuration data layers are added until index number of layers exist. If data is provided, then the given configuration data is added to the highest configuration data layer. If both index and data are provided, the layers are added first, then the configuration data is added to the top most existing layer.
data
# Add one more layer to the existing layers. $cfg->add_layer(); # Add one more layer and set the data for that layer. $cfg->add_layer({ data => { 'length' => 6, 'width' => 10, 'area' => sub { my $cfg = shift; return ($cfg->apicall('length') * $cfg->apicall('width')) } } }); # Add 3 layers (layer numbering starts at 0) $cfg->add_layer({ 'index' => 2 });
Determine if the apiname is available to be called. Returns undef if false, or the referenced function if true.
my $subref = $cfg->apican("apiname");
Call the apiname to get or set the attribute.
# Both of these calls do the same thing my $res = $cfg->apicall("apiname" [, arguments ]); my $res = $cfg->apiname([ arguments ]);
The format of the validator is to return the value to store if the value is validated successfully, or return undef is not validated successfully.
Validators must be a function, or a string that can be evaluated as a regex. Validators that are hashes or arrays are invalid.
An undefined validator will allow any value passed in to be stored.
This allows a function that is used as the validator to change the value, as the stored value is whatever the function returns.
Validator Function Call Format:
# The Validator is called internally as follows: $validator->( <Config::apiLayers Object>, <attribute_name>, <attribute_value> )
Validator Function Example:
# Accept any value that is not a reference [{ "FirstName" => sub{ return $_[2] if !ref $_[2] } }]
If a string/scalar is provided as the validator, it is used as a regex to test the value. The value is considered to be validated successfully if the regex match test is true.
Validator Format: # The Validator is called similar to: if ($value =~ /$validator_string/) { <store the value> }
Validator Example:
# Accept any value that matches a word [{ "FirstName" => "\w" }] [{ name => "FirstName", validator => "\w" }] [{ name => "FirstName", validator => "\w", description => "The first name" }]
use Getopt::Long; use Getopt::LongUsage; use Config::apiLayers; # Note the missing getoptlong configuration and description for area attribute my $cfg = new Config::apiLayers({ autoproto => 1, attributes => [ { name => 'length', validator => sub { return $_[2] > 0 ? $_[2] : undef }, getoptlong => 'length|l:i', description => "The length of a rectangle" }, { name => 'width', validator => sub { return $_[2] > 0 ? $_[2] : undef }, getoptlong => 'width|w:i', description => "The width of a rectangle" }, { name => 'area', validator => sub { return undef } # do not allow storing any value } ] }); # Set the default values $cfg->config({ data => { 'length' => 6, 'width' => 10, 'area' => sub { my $cfg = shift; return ($cfg->apicall('length') * $cfg->apicall('width')) } } }); my $getoptlong_config = $cfg->exportdata({ cfg => 'getoptlong' }); my $attr_descriptions = $cfg->exportdata({ cfg => 'descriptions' }); my %options; my @getoptconf = ( \%options, @{$getoptlong_config}, 'verbose|v', 'help|h' ); my $usage = sub { my @getopt_long_configuration = @_; GetLongUsage ( 'cli_use' => ($0 ." [options]"), 'descriptions' => [ @{$attr_descriptions}, 'verbose' => "verbose", 'help' => "this help message" ], 'Getopt_Long' => \@getopt_long_configuration, ); }; GetOptions( @getoptconf ) || die ($usage->( @getoptconf ),"\n"); $cfg->add_layer(); $cfg->importdata({ data => \%options }) || die ($usage->( @getoptconf ),"\n"); print "Area is: ",$cfg->area,"\n";
Example outputs:
linux$ ./test_it.pl --not-an-option Unknown option: not-an-option ./test_it.pl [options] --length The length --width The width -v, --verbose verbose -h, --help this help message linux$ ./test_it.pl --width=101 Area is: 606
Russell E Glaue, http://russ.glaue.org
Copyright (c) 2015-2016 Russell E Glaue, All rights reserved.
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
To install Config::apiLayers, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Config::apiLayers
CPAN shell
perl -MCPAN -e shell install Config::apiLayers
For more information on module installation, please visit the detailed CPAN module installation guide.