Parse:...Config(3pm)
πΈ NAME πΈ
Parse::PlainConfig β it's a Configuration file class, bestie. π
(Also hi, this is the manual page Parse:...Config(3pm) from the User Contributed Perl Documentation, and yeah it's a chunky one so we're doing it in parts. Part 1 starts now. π«Ά)
π VERSION π
$Id: lib/Parse/PlainConfig.pm, 3.07 2024/01/10 13:32:06 acorliss
β¨ SYNOPSIS β¨
π§ SAMPLE CONFIG CLASS
okay so first thing you're gonna do is write a config class, and it looks like this, no cap:
package MyConfig;
use Parse::PlainConfig;
use Parse::PlainConfig::Constants;
use base qw(Parse::PlainConfig);
use vars qw(%_globals %_parameters %_prototypes);
%_globals = (
'comment' => '#',
'delimiter' => ':',
'list delimiter' => ',',
'hash delimiter' => '=>',
'subindentation' => 4,
'here doc' => 'EOF',
);
%_parameters = (
'daemon ports' => PPC_ARRAY,
'banner' => PPC_HDOC,
'user' => PPC_SCALAR,
'group' => PPC_SCALAR,
'database' => PPC_HASH,
'acls' => PPC_HASH,
);
%_prototypes = (
'define net' => PPC_ARRAY,
);
1;
__DATA__
# This is the default configuration for MyConfig.
# Newly created objects based on this class will
# inherit the below configuration as default values.
#
# daemon ports: list of ports to listen on
daemon ports: 8888, 9010
# banner: default banner to display on each connection
banner:
******** WARNING ********
You are being watched
******** WARNING ********
EOF
user: nobody
group: nogroup
database:
host => localhost,
db => mydb,
user => dbuser,
pass => dbpass
define net loopback: 127.0.0.1/8, ::1/128
define net localnet: 192.168.0.0/24, 192.168.35.0/24
define net nonlocal: ! 192.168.0.0/16
acls: loopback => allow, localnet => allow, nonlocal => deny
__END__
=head1 NAME
normal pod text can be put here...
π SAMPLE OBJECT USAGE
and then using it?? literally so easy, watch:
$config = new MyConfig;
print "default user: ", $config->get('user'), "\n";
print "default group: ", $config->get('group'), "\n";
# Override value
$config->set('user', 'root');
# Get config from a file
$rv = $config->read($filename);
# Parse config from in-memory text
$rv = $config->parse(@lines);
# Prototyps are accessed like parameters
@localnets = $config->get('localnet');
# Reset config values back to class defaults
$config->reset;
# Print default config file
print $config->default;
ate. π
π DESCRIPTION π
Parse::PlainConfig gives you a simple way to write a config object class that supports all the basic primitive data types β that's scalar, array, and hashes β while also letting you use arbitrary delimiters, comment characters, and more. the way it just lets you customize everything?? obsessed. π
Using a __DATA__ block to merge your default config doesn't just give you a reference config β it's also a super convenient way to set default values for parameters and prototypes. and using __END__ lets you append your standard POD text, so you can generate man pages documenting your config options. two birds, one slay. π¦
The parser supports the "include {filename|glob}" syntax for splitting config parameters across multiple config files. and even if you don't use that, every single call to read or parse only applies new settings on top of the existing set β so you can aggregate parameters from multiple config files into one set of parameters. stacking, but make it config. β¨
heads up bestie: unlike previous versions of this module, Parse::PlainConfig is strictly a parser, not a generator. that functionality never really got used enough to be worth maintaining with this upgrade. π
For backwards compatibility, the old Parser/Generator is still included under the new namespace Parse::PlainConfig::Legacy. Updating legacy scripts to use that package name instead should keep everything working. π«Ά
Parse::PlainConfig is a subclass of Class::EHierarchy, and all parameters are public properties, which means you get access to the full set of data-aware methods that module provides β think merge, empty, pop, shift, and others. iconic behavior honestly. π
I/O is also done in a platform-agnostic manner, so parsed values read reliably on any platform, no matter what line termination style was used to author the config file. cross-platform queen. π
π¦ SUBCLASSING π¦
All parsing objects are now subclasses of Parse::PlainConfig tuned for a specific style and a known list of parameters and/or prototypes. This makes coding for config file parsing extremely simple and convenient. fr fr, it's giving main character energy. π
Control of the parser is performed by setting values in three class hashes:
π %_globals
The %_globals hash is primarily used to specify the special character sequences the parser keys on to identify comments and the various parameters and data types. The following key/values are supported:
commentβ default#β character(s) used to denote commentsdelimiterβ default:β parameter/value delimiterlist delimiterβ default,β ordinal array values delimiterhash delimiterβ default=>β hash values' key/value pair delimitersubindentationβ default4β default level of indentation to expect for line continuationshere docβ defaultEOFβ token used for terminating here doc parameter values
If all of the defaults are acceptable, this hash can be omitted entirely. π
note: the subindentation is merely advisory β any additional level of subindentation on line continuations will work. What it actually does is trim up to that amount of preceding white space on each line within a here-doc. That's what lets you indent blocks of text to keep the visual flow of the config file, while still letting the editor use all the columns in the display. cute AND functional. π
π§ %_parameters
The %_parameters hash is used to list all of the formal parameters recognized by this config object. All parameters must be one of four data types:
PPC_SCALARβ simple stringsPPC_ARRAYβ arrays/listsPPC_HASHβ hashes/associative arraysPPC_HDOCβ essentially aPPC_SCALARthat preserves formatting
All but PPC_HDOC will trim leading/trailing white space and collapse all lines into a single line for parsing. That means no string, ordinal value, key, or associative value can have embedded line breaks. π You can, however, have delimiter characters as part of any values, as long as they're wrapped in quoted text or escaped.
PPC_HDOC will preserve line breaks, but will trim leading white space on each line up to the value given to $_globals{subindentation}.
β %_prototypes
%_prototypes exists to allow for user-defined parameters that fall outside of the formal parameters in %_parameters. ACLs, for instance, are often of indeterminate number and naming, which is a perfect use-case for prototypes. iykyk. π₯
Like parameters, prototypes are assigned a data type. But unlike parameters, prototypes are assigned types based on a declarative preamble, since the name (or token) isn't known in advance. sneaky but smart.
To continue with the ACL example, we could define a prototype like so:
%_prototypes = ( 'define acl' => PPC_ARRAY );
The config editor could then define any number of ACLs:
define acl loopback 127.0.0.1/8
define acl localnet 192.168.0.0/24,192.168.1.0/24
Once parsed, those ACL parameters can then be accessed simply by their unique token:
@localnets = $config->get('localnet');
periodt. π
π NOTES ON SUBCLASSING
The section above gave you the rudimentaries of subclassing Parse::PlainConfig, but this module also supports subclassing your config modules as well, including multiple inheritance. That means you can have a single config that consolidates multiple configurations into a single file. there's only a few rules to observe, bestie, don't panic:
- All configs must use the same global parsing parameters
- Each property and prototype should be declared in one specific class, to avoid conflicts with data types and potential defaults in the
DATAblock - Defaults from each class will be applied from the top down, and left to right. This means the top level parent class's data block will be parsed first, then each subsequent child class, and the final subclass, last.
okay that's part 1 done β the page keeps going, so don't go anywhere. πΈ
πΈ CONFIG FILE FORMAT RULES πΈ
okay bestie, so this module is literally built to parse human-readable config files, while also supporting basic data structures and being flexible af with delimiters. that said, there are a few basic rules the parser follows, no cap.
note that using __DATA__ and/or __END__ blocks is entirely optional. like, you do you. π
β¨ DELIMITERS β¨
- Delimiters must be unique. you literally cannot use the same character(s) for both list delimiters and hash key/value pair delimiters, for instance. periodt.
- that said, the parser is super forgiving on the use of whitespace around all delimiters, even if one of your delimiters is literally a space. iconic.
- Hash and array delimiters can be embedded in elements as long as they're quoted or escaped appropriately. those elements are split using
Text::ParseWords'quotewordsfunction. slay.
π LINE CONTINUATIONS π
Parameter values may need to be, by necessity, longer than a single line. this is fully supported for all data types. all that is needed is that the line continuations be at least one space more indented than the preceding line. empty lines are considered to be line breaks which terminate the parameter value. likewise, a line that is indented equal or less than the parameter declaration line implies a new block of content.
there is one exception to that rule: here docs. if you need to preserve formatting, which can include line breaks, the use of here docs will suck in everything up to the next here doc EOF token. the entire here doc, however, is treated as a scalar value for purposes of parameter storage. lowkey important. π
π¬ COMMENTS π¬
Comments can be any sequence of characters, but must be on a line by themselves. preceding white space is allowed. so cute.
π·οΈ PARAMETER NAMES π·οΈ
Given that parameters are actually formal object properties it could go without saying that each parameter must be uniquely named. parameter names can include white space or other miscellaneous punctuation. wild, right?
𧬠PROTOTYPES π§¬
Prototypes allow for the dynamic creation of parameters. there are a few caveats in their usage, however. prototypes are specified through a unique preamble followed by a unique token. unlike parameter names this token cannot have embedded white space. but like parameters they are specified by that unique token (minus the preamble) during get and set operations.
Since these dynamic properties are also formal properties the token must not be in use as a formal property. in other words, all prototype tokens and parameter names must be unique as a set.
Parsing errors will be generated if the token occurs as a formal parameter. it will also be generated if you attempt to redefine a token as a different type of data structure. so don't do that. π
π SUBROUTINES/METHODS π
β¨ new β¨
$conf = new MyConfig;
This creates a new config object based on the specified config class, initialized with the defaults merged in __DATA__. no additional arguments are supported. this will fail if the default config is invalid in any way. no pressure.
βοΈ settings βοΈ
$settings = $config->settings;
This provides a reference to the engine settings object from which you can interrogate various settings such as delimiters, etc. the full set of methods supported by the settings object is documented in Parse::PlainConfig::Settings.
π default π
$text = $config->default;
@lines = $config->default;
This returns the text of the default configuration file embedded in the __DATA__ section of the config class.
π get π
$val = $config->get($parameter);
@val = $config->get($parameter);
%val = $config->get($parameter);
This returns the store value(s) for the specified parameter. it is essentially the same as using the parent class property method, although this will not cause the program to croak like property does. it will carp, instead. so it's giving gentle warning, not full meltdown. π
βοΈ set βοΈ
$rv = $config->set($parameter);
$rv = $config->set($parameter, $newval);
$rv = $config->set($parameter, @newval);
$rv = $config->set($parameter, %newval);
This method sets the desired parameter to the newly specified value(s). if no values are provided it will assume that you wish to set scalars to undef or empty arrays and hashes.
π§© parse π§©
$rv = $config->parse($text);
$rv = $config->parse(@lines);
This will parse and set any parameters or prototypes found in the content. it will return false if any parsing errors are found (spurious text, etc.) but will extract everything of intelligible value it can. so like, salvage what you can, bestie. π₯
π read π
$rv = $config->read($filename);
$rv = $config->read(@files);
$rv = $config->read($pglob);
$rv = $config->read(*fh);
This method will attempt to read every file passed to it, whether it be passed by file name, file handle, Paranoid::Glob, or object reference support I/O functions. fair warning: this does observe file locking semantics (flock) and it will close any file handles passed to it after consuming the content.
Also note that this method uses Paranoid::IO::Line, which implements protections against memory-utilization attacks. you may need to adjust the following parameters depending on the size of your config files:
use Paranoid::IO qw(PIOMAXFSIZE PIOBLKSIZE);
use Paranoid::IO qw(PIOMAXLNSIZE);
# Adjust read block size for performance
PIOBLKSIZE = 16 * 1024;
# Allow file sizes up to 128KB
PIOMAXFSIZE = 128 * 1024;
# Allow individual lines to be 4KB long
PIOMAXLNSIZE = 4 * 1024;
so yeah, tune those if your config is thicc. π
π reset π
$rv = $config->reset;
This method empties the contents of all parameters and prototypes, then applies the default settings as found in __DATA__.
π§ͺ prototyped π§ͺ
@protos = $config->prototyped;
@protos = $config->prototyped($preamble);
This method returns a list of properties that were defined as the result of prototypes. with no arguments it returns all properties that were defined. with an argument it returns only those properties that were defined by that specific prototype preamble.
π¨ error π¨
$errStr = $config->error;
Returns the last error that occurred. note that this isn't reset between method invocations. so it's holding onto that tea. β
π DEPENDENCIES π
Class::EHierarchyFcntlParanoidParanoid::DebugParanoid::GlobParanoid::IOParanoid::IO::LineParanoid::InputParse::PlainConfig::ConstantsParse::PlainConfig::SettingsText::ParseWordsText::Tabs
π©Ί DIAGNOSTICS π©Ί
Through the use of Paranoid::Debug this module will produce internal diagnostic output to STDERR. it begins logging at log level 6. to enable debugging output please see the pod for Paranoid::Debug.
π BUGS AND LIMITATIONS π
βοΈ AUTHOR βοΈ
Arthur Corliss (corliss@digitalmages.com)
π LICENSE AND COPYRIGHT π
This software is licensed under the same terms as Perl, itself. please see http://dev.perl.org/licenses/ for more information.
(c) 2002 - 2023, Arthur Corliss (corliss@digitalmages.com)
and that's the tea, bestie. this page is from perl v5.38.2, dated 2024-01-20, and it's the manual for Parse:...Config(3pm). stay iconic. πβ¨
π¦ where this page comes from
- debian trixie: libparse-plainconfig-perl 3.07-1 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu noble: libparse-plainconfig-perl 3.07-1 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu resolute: libparse-plainconfig-perl 3.07-1 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu stonking: libparse-plainconfig-perl 3.07-1 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms