JayBeams  0.1
Another project to have fun coding.
config_object.hpp
Go to the documentation of this file.
1 #ifndef jb_config_object_hpp
2 #define jb_config_object_hpp
3 
4 #include <jb/merge_yaml.hpp>
5 #include <jb/usage.hpp>
6 
7 #include <boost/program_options/options_description.hpp>
8 #include <boost/program_options/variables_map.hpp>
9 #include <yaml-cpp/yaml.h>
10 #include <iosfwd>
11 #include <string>
12 #include <vector>
13 
14 namespace jb {
15 
16 // Forward declare because we need to make it a 'friend'
17 struct config_recurse;
18 
19 /**
20  * Base class for all configuration objects
21  *
22  * A configuration object is a class derived from jb::config_object
23  * and having only members of jb::config_attribute type.
24  * Configuration objects can read overrides to their defaults from a
25  * YAML file.
26  *
27  * Please @see listing:examples:configurations for some
28  * examples.
29  */
31 public:
32  // Forward declare the type
33  struct attribute_descriptor;
34 
35  /**
36  * Default constructor.
37  *
38  * Derived classes should initialize all their member attributes to
39  * their default values.
40  */
41  config_object();
42 
43  /**
44  * Copy constructor.
45  *
46  * Derived classes should implement member-by-member copying using
47  * the config_attribute(container*, config_attribute const&)
48  * constructor.
49  */
51  : config_object() {
52  }
53 
54  /**
55  * Move constructor.
56  *
57  * Derived classes should implement member-by-member move using the
58  * config_attribute(container*, config_attribute&&) constructor.
59  */
61  : config_object() {
62  }
63 
64  /// Destructor
65  virtual ~config_object() {
66  }
67 
68  /**
69  * Copy & swap assignment.
70  */
72  swap(rhs);
73  return *this;
74  }
75 
76  /**
77  * Derived classes should implement member by member swap.
78  */
79  void swap(config_object& rhs) {
80  }
81 
82  /**
83  * Read the configuration file and load the overrides defined
84  * therein.
85  *
86  * Find the correct configuration file to load using
87  * jb::config_files_locations, then load the configuration file and
88  * apply the overrides from that file.
89  *
90  * @param argc the number of command-line arguments
91  * @param argv the command-line arguments
92  * @param filename the basename of the file to load
93  * @param environment_variable_name the name of the *_ROOT to use
94  * when searching for the configuration file.
95  */
96  void load_overrides(
97  int& argc, char* argv[], std::string const& filename,
98  char const* environment_variable_name);
99 
100  /**
101  * Read the configuration file and load the overrides defined
102  * therein.
103  *
104  * Find the correct configuration file to load using
105  * jb::config_files_locations, then load the configuration file and
106  * apply the overrides from that file.
107  *
108  * @param argc the number of command-line arguments
109  * @param argv the command-line arguments
110  * @param filename the basename of the file to load
111  */
112  void load_overrides(int& argc, char* argv[], std::string const& filename);
113 
114  /**
115  * Read the configuration file and load the overrides defined
116  * therein.
117  *
118  * Find the correct configuration file to load using
119  * jb::config_files_locations, then load the configuration file and
120  * apply the overrides from that file.
121  *
122  * @param argc the number of command-line arguments
123  * @param argv the command-line arguments
124  * @param is the stream to load the configuration from.
125  */
126  void load_overrides(int& argc, char* argv[], std::istream& is);
127 
128  /**
129  * Process the command line.
130  */
131  void process_cmdline(int& argc, char* argv[]);
132 
133  /**
134  * Validate the settings
135  *
136  * @throws jb::usage if a problem is detected.
137  */
138  virtual void validate() const;
139 
140  /**
141  * Print out the settings
142  */
143  std::ostream& to_stream(std::ostream& os) const;
144 
145  /**
146  * An attribute descriptor.
147  */
150  : attribute_descriptor(std::string(), std::string()) {
151  }
152  explicit attribute_descriptor(std::string const& n)
153  : attribute_descriptor(n, std::string()) {
154  }
155  attribute_descriptor(std::string const& n, std::string const& c)
156  : name(n)
157  , class_name(c)
158  , helpmsg()
159  , is_positional(false) {
160  }
161 
162  attribute_descriptor& help(std::string const& h) {
163  helpmsg = h;
164  return *this;
165  }
166 
168  is_positional = true;
169  return *this;
170  }
171 
172  std::string name;
173  std::string class_name;
174  std::string helpmsg;
176  };
177 
178  /**
179  * Define the interface to manipulate and access configuration
180  * attributes embedded in a config_object.
181  */
183  protected:
184  /// Constructor
185  attribute_base(attribute_descriptor const& d, config_object* container);
186 
187  template <typename container_type>
188  explicit attribute_base(container_type*)
189  : descriptor_() {
190  }
191 
192  public:
193  /// Destructor
194  virtual ~attribute_base() = 0;
195 
196  /// Apply any overrides set in the YAML document
197  virtual void apply_overrides(
198  YAML::Node const& by_name, class_overrides const& by_class) = 0;
199 
200  /// Apply the necessary command-line options to the descriptors.
201  virtual void add_options(
202  boost::program_options::options_description& options,
203  std::string const& prefix, attribute_descriptor const& d) const = 0;
204 
205  /// Apply any overrides set in the command-line flags
206  virtual void apply_cmdline_values(
207  boost::program_options::variables_map const& vm,
208  std::string const& name) = 0;
209 
210  /// Validate the attribute, mostly a no-op except for embedded
211  /// config_objects
212  virtual void validate() const = 0;
213 
214  /// Convert to a YAML Node, useful to dump the configuration
215  virtual YAML::Node to_yaml() const = 0;
216 
218  return descriptor_;
219  }
220 
221  std::string const& name() const {
222  return descriptor_.name;
223  }
224  std::string const& class_name() const {
225  return descriptor_.class_name;
226  }
227  std::string const& help() const {
228  return descriptor_.helpmsg;
229  }
230  bool positional() const {
231  return descriptor_.is_positional;
232  }
233 
234  private:
236  };
237 
238 protected:
239  /// Convenience function to create attribute descriptors with less typing.
240  static attribute_descriptor desc(std::string const& name) {
241  return attribute_descriptor(name);
242  }
243 
244  /// Convenience function to create attribute descriptors with less typing.
245  static attribute_descriptor
246  desc(std::string const& name, std::string const& class_name) {
247  return attribute_descriptor(name, class_name);
248  }
249 
250 private:
251  /**
252  * Apply the overrides contained in the YAML document, compute the
253  * initial by_class overrides.
254  *
255  * @param by_name a YAML document describing what values (and
256  * classes) to override.
257  */
258  void apply_overrides(YAML::Node const& by_name);
259 
260  /**
261  * Apply the overrides contained in the YAML document.
262  *
263  * @param by_name a YAML document describing what values (and
264  * classes) to override.
265  * @param by_class the set of per-class overrides to apply
266  */
267  void
268  apply_overrides(YAML::Node const& by_name, class_overrides const& by_class);
269 
270  /**
271  * Compute the full name of a command-line argument, given its
272  * prefix and short name.
273  *
274  * @param prefix the prefix for the argument
275  * @param name the name of the argument
276  */
277  static std::string
278  cmdline_arg_name(std::string const& prefix, std::string const& name);
279 
281  void auto_register(attribute_base* a);
282 
283  /// Run validate() on each attribute contained by this config_object.
284  void validate_attributes() const;
285 
286  /// Validate both the config_object and each attribute.
287  friend struct config_recurse;
288  void validate_all() const;
289 
290  /**
291  * Add the attributes of this config_object as command-line options.
292  */
293  void add_options(
294  boost::program_options::options_description& options,
295  std::string const& prefix, attribute_descriptor const& d) const;
296 
297  /**
298  * Apply the values from the cmdline to this configuration object.
299  */
301  boost::program_options::variables_map const& vm,
302  std::string const& prefix);
303 
304  /// Print out the configuration settings in YAML format
305  YAML::Node to_yaml() const;
306 
307 private:
308  /// The list of attributes.
309  std::vector<attribute_base*> attributes_;
310 };
311 
312 inline std::ostream& operator<<(std::ostream& os, config_object const& x) {
313  return x.to_stream(os);
314 }
315 
316 } // namespace jb
317 
318 #define config_object_constructors(NAME) \
319  NAME(NAME&& rhs) \
320  : NAME() { \
321  operator=(std::move(rhs)); \
322  } \
323  NAME(NAME const& rhs) \
324  : NAME() { \
325  operator=(rhs); \
326  } \
327  NAME& operator=(NAME const& rhs) = default; \
328  NAME& operator=(NAME&& rhs) = default
329 
330 #include <jb/config_attribute.hpp>
331 
332 #endif // jb_config_object_hpp
config_object(config_object const &rhs)
Copy constructor.
void swap(config_object &rhs)
Derived classes should implement member by member swap.
Base class for all configuration objects.
friend class generic_config_attribute
virtual void validate() const
Validate the settings.
std::ostream & operator<<(std::ostream &os, as_hhmmssu const &x)
Format as_hhmmssu into an iostream.
Definition: as_hhmmss.cpp:8
void validate_attributes() const
Run validate() on each attribute contained by this config_object.
STL namespace.
Breakout some of the helper classes from jb/config_object.hpp.
std::map< std::string, YAML::Node > class_overrides
Store the overrides for each class.
Definition: merge_yaml.hpp:17
std::string const & name() const
attribute_descriptor const & descriptor() const
void load_overrides(int &argc, char *argv[], std::string const &filename, char const *environment_variable_name)
Read the configuration file and load the overrides defined therein.
attribute_descriptor const descriptor_
std::string const & class_name() const
config_object()
Default constructor.
config_object & operator=(config_object rhs)
Copy & swap assignment.
std::vector< attribute_base * > attributes_
The list of attributes.
static attribute_descriptor desc(std::string const &name, std::string const &class_name)
Convenience function to create attribute descriptors with less typing.
std::ostream & to_stream(std::ostream &os) const
Print out the settings.
void auto_register(attribute_base *a)
std::string const & help() const
Define the interface to manipulate and access configuration attributes embedded in a config_object...
virtual ~config_object()
Destructor.
void apply_cmdline_values(boost::program_options::variables_map const &vm, std::string const &prefix)
Apply the values from the cmdline to this configuration object.
config_object(config_object &&rhs)
Move constructor.
Recursively apply functions to config_object, attributes, and sequences of config objects...
void process_cmdline(int &argc, char *argv[])
Process the command line.
YAML::Node to_yaml() const
Print out the configuration settings in YAML format.
static attribute_descriptor desc(std::string const &name)
Convenience function to create attribute descriptors with less typing.
void apply_overrides(YAML::Node const &by_name)
Apply the overrides contained in the YAML document, compute the initial by_class overrides.
attribute_descriptor(std::string const &n, std::string const &c)
void validate_all() const
attribute_descriptor & help(std::string const &h)
static std::string cmdline_arg_name(std::string const &prefix, std::string const &name)
Compute the full name of a command-line argument, given its prefix and short name.
void add_options(boost::program_options::options_description &options, std::string const &prefix, attribute_descriptor const &d) const
Add the attributes of this config_object as command-line options.
The top-level namespace for the JayBeams library.
Definition: as_hhmmss.hpp:7