.\" -*- mode: troff; coding: utf-8 -*- .\" Automatically generated by Pod::Man v6.0.2 (Pod::Simple 3.48) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" \*(C` and \*(C' are quotes in nroff, nothing in troff, for use with C<>. .ie n \{\ . ds C` "" . ds C' "" 'br\} .el\{\ . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" .\" Required to disable full justification in groff 1.23.0. .if n .ds AD l .\" ======================================================================== .\" .IX Title "Config::MVP 3" .TH Config::MVP 3 2026-09-10 "perl v5.44.0" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH SYNOPSIS .IX Header "SYNOPSIS" If you want a useful synopsis, consider this code which actually comes from Config::MVP::Assembler: .PP .Vb 1 \& my $assembler = Config::MVP::Assembler\->new; \& \& # Maybe you want a starting section: \& my $section = $assembler\->section_class\->new({ name => \*(Aq_\*(Aq }); \& $assembler\->sequence\->add_section($section); \& \& # We\*(Aqll add some values, which will go to the starting section: \& $assembler\->add_value(x => 10); \& $assembler\->add_value(y => 20); \& \& # Change to a new section... \& $assembler\->change_section($moniker); \& \& # ...and add values to that section. \& $assembler\->add_value(x => 100); \& $assembler\->add_value(y => 200); .Ve .PP This doesn\*(Aqt make sense? Well, read on. .PP (You can also read the 2009 RJBS Advent Calendar article on Config::MVP!) .SH DESCRIPTION .IX Header "DESCRIPTION" MVP is a mechanism for loading configuration (or other information) for libraries. It doesn\*(Aqt read a file or a database. It\*(Aqs a helper for things that do. .PP The idea is that you end up with a Config::MVP::Sequence object, and that you can use that object to fully configure your library or application. The sequence will contain a bunch of Config::MVP::Section objects, each of which is meant to provide configuration for a part of your program. Most of these sections will be directly related to a Perl library that you\*(Aqll use as a plugin or helper. Each section will have a name, and every name in the sequence will be unique. .PP This is a pretty abstract set of behaviors, so we\*(Aqll provide some more concrete examples that should help explain how things work. .SH EXAMPLE .IX Header "EXAMPLE" Imagine that we\*(Aqve got a program called DeliveryBoy that accepts mail and does stuff with it. The "stuff" is entirely up to the user\*(Aqs configuration. He can set up plugins that will be used on the message. He writes a config file that\*(Aqs read by Config::MVP::Reader::INI, which is a thin wrapper around Config::MVP used to load MVP\-style config from \fIINI\fR files. .PP Here\*(Aqs the user\*(Aqs configuration: .PP .Vb 2 \& [Whitelist] \& require_pgp = 1 \& \& file = whitelist\-family \& file = whitelist\-friends \& file = whitelist\-work \& \& [SpamFilter] \& filterset = standard \& max_score = 5 \& action = bounce \& \& [SpamFilter / SpamFilter_2] \& filterset = aggressive \& max_score = 5 \& action = tag \& \& [VerifyPGP] \& \& [Deliver] \& dest = Maildir .Ve .PP The user will end up with a sequence with five sections, which we can represent something like this: .PP .Vb 10 \& { name => \*(AqWhitelist\*(Aq, \& package => \*(AqDeliveryBoy::Plugin::Whitelist\*(Aq, \& payload => { \& require_pgp => 1, \& files => [ qw(whitelist\-family whitelist\-friends whitelist\-work) ] \& }, \& }, \& { name => \*(AqSpamFilter\*(Aq, \& package => \*(AqDeliveryBoy::Plugin::SpamFilter\*(Aq, \& payload => { \& filterset => \*(Aqstandard\*(Aq, \& max_score => 5, \& action => \*(Aqbounce\*(Aq, \& } \& }, \& { name => \*(AqSpamFilter_2\*(Aq, \& package => \*(AqDeliveryBoy::Plugin::SpamFilter\*(Aq, \& payload => { \& filterset => \*(Aqaggressive\*(Aq, \& max_score => 5, \& action => \*(Aqtag\*(Aq, \& }, \& }, \& { name => \*(AqVerifyPGP\*(Aq, \& package => \*(AqDeliveryBoy::Plugin::VerifyPGP\*(Aq, \& payload => { }, \& }, \& { name => \*(AqDeliver\*(Aq, \& package => \*(AqDeliveryBoy::Plugin::Deliver\*(Aq, \& payload => { dest => \*(AqMaildir\*(Aq }, \& }, .Ve .PP The INI reader uses Config::MVP::Assembler to build up configuration section by section as it goes, so that\*(Aqs how we\*(Aqll talk about what\*(Aqs going on. .PP Every section of the config file was converted into a section in the MVP sequence. Each section has a unique name, which defaults to the name of the INI section. Each section is also associated with a package, which was expanded from the INI section name. The way that names are expanded can be customized by subclassing the assembler. .PP Every section also has a payload \-\- a hashref of settings. Note that every entry in every payload is a simple scalar except for one. The \f(CW\*(C`files\*(C'\fR entry for the Whitelist section is an arrayref. Also, note that while it appears as \&\f(CW\*(C`files\*(C'\fR in the final output, it was given as \f(CW\*(C`file\*(C'\fR in the input. .PP Config::MVP provides a mechanism by which packages can define aliases for configuration names and an indication of what names correspond to "multi\-value parameters." (That\*(Aqs part of the meaning of the name "MVP.") When the MVP assembler is told to start a section for \f(CW\*(C`Whitelist\*(C'\fR it expands the section name, loads the package, and inspects it for aliases and multivalue parameters. Then if multiple entries for a non\-multivalue parameter are given, an exception can be raised. Multivalue parameters are always pushed onto arrayrefs and non\-multivalue parameters are left as found. .SS "...so what now?" .IX Subsection "...so what now?" So, once our DeliveryBoy program has loaded its configuration, it needs to initialize its plugins. It can do something like the following: .PP .Vb 1 \& my $sequence = $deliveryboy\->load_config; \& \& for my $section ($sequence\->sections) { \& my $plugin = $section\->package\->new( $section\->payload ); \& $deliveryboy\->add_plugin( $section\->name, $plugin ); \& } .Ve .PP That\*(Aqs it! In fact, allowing this very, very block of code to load configuration and initialize plugins is the goal of Config::MVP. .PP The one thing not depicted is the notion of a "root section" that you might expect to see in an INI file. This can be easily handled by starting your assembler off with a pre\-built section where root settings will end up. For more information on this, look at the docs for the specific components. .SH "WHAT NEXT?" .IX Header "WHAT NEXT?" .SS "Making Packages work with MVP" .IX Subsection "Making Packages work with MVP" Any package can be used as part of an MVP section. Packages can provide some methods to help MVP work with them. It isn\*(Aqt a problem if they are not defined .PP \fImvp_aliases\fR .IX Subsection "mvp_aliases" .PP This method should return a hashref of name remappings. For example, if it returned this hashref: .PP .Vb 4 \& { \& file => \*(Aqfiles\*(Aq, \& path => \*(Aqfiles\*(Aq, \& } .Ve .PP Then attempting to set either the "file" or "path" setting for the section would actually set the "files" setting. .PP \fImvp_multivalue_args\fR .IX Subsection "mvp_multivalue_args" .PP This method should return a list of setting names that may have multiple values and that will always be stored in an arrayref. .SS "The Assembler" .IX Subsection "The Assembler" Config::MVP::Assembler is a state machine that makes it easy to build up your MVP\-style configuration by firing off a series of events: new section, new setting, etc. You might want to subclass it to change the class of sequence or section that\*(Aqs used or to change how section names are expanded into packages. .SS "Sequences and Sections" .IX Subsection "Sequences and Sections" Config::MVP::Sequence and Config::MVP::Section are the two most important classes in MVP. They represent the overall configuration and each section of the configuration, respectively. They\*(Aqre both fairly simple classes, and you probably won\*(Aqt need to subclass them, but it\*(Aqs easy. .SS "Examples in the World" .IX Subsection "Examples in the World" For examples of Config::MVP in use, you can look at Dist::Zilla or App::Addex.