-
Notifications
You must be signed in to change notification settings - Fork 10
Possible API
Diego Perini edited this page May 13, 2015
·
5 revisions
Maybe this is some way to construct our API
int main(int argc, char **argv)
{
auto defaults = PropertyList{ { "time_to_run", "10" }, { "user_name", "Bob" } };
using FILE_t = std::unique_ptr<FILE, std::function<int(FILE*)>>;
FILE_t fromFile(fopen("myConfig.plist"), fclose);
auto myProgramConfig = ProgramConfig::CreateProgramConfig().
CreateProgramConfig(defaults, CONFIG_SCHEMA).
CreateProgramConfig(fromFile, CONFIG_SCHEMA).
CreateProgramConfig(argc, argv, CMDLINE_SCHEMA);
}
My dream interface (which maybe exposes me as a Python fanboy):
int main(int argc, char **argv)
{
// quick and dirty setup attribute addition
auto my_schema = Schema().
add_attribute<bool>("debug", false); // second param: default
// detailed version. Method names stolen from Python optparse
my_schema.add_attribute(Attribute<int>("timeout").set_help("Specify timeout in seconds").set_metavar("SECONDS"));
// hierarchy encoded in string names
my_schema.add_attribute<string>("network/smtp_server"); // no default: failure if not set
// let library add its attributes into a sub-hierarchy, i.e. all attribute names get a "some_lib/" prefix
my_schema.add_below("some_lib", some_lib::get_schema());
// -- verbose way to get data --
// if we want to re-load a config later we'll have to keep the original cmdline data separate
// generate reduced schema, select only toplevel entries (don't want everything on commandline)
auto cmdline_schema = my_schema.slice("*");
ConfigData cmdline_data = cmdline_configdata(argc, argv, cmdline_schema);
ConfigData conffile_data = inifile_configdata("some.conf");
// default values are in schema (which makes sense for doc & keeps everything together)
ConfigData final_data = fuse_configdata(my_schema, conffile_data, cmdline_data);
// user defined functions to check e.g. parameter compatibility
my_verify(final_data);
// delegate checks to some_lib
some_lib::verify_configdata(final_data.slice("some_lib/*"));
// ... now final_data can be used.
}
A useful approach I've been using for quite some time. (excuse my javascript)
Proposal from Diego Perini (see my pull request for implementation):
#include "confoost.hpp"
// These can be moved to hpp as defaults
using schema = confoost_config<confoost_node>;
using configuration = confoost<schema>;
int main(int argc, char** argv) {
auto config = configuration();
// Our parsers are added but not executed
auto xml_source = config.add_parser( xml_parser<schema>("config.xml") );
auto json_source = config.add_parser( json_parser<schema>("config.json") );
auto cli_source = config.add_parser( cli_parser<schema>(argc, argv) ) ;
// When we retrieve a value, all parsers with invalid cache lazily loads
auto a_value = config.retrieve<int>("some/path/to/some/int");
// Accessing the value reads from cache
a_value = config.retrieve<int>("some/path/to/some/int");
// We can invalidate our cache anywhere
xml_source().invalidate();
// Invalidated sources are reparsed
a_value = config.retrieve<int>("some/path/to/some/int");
return 0;
}