Scarab  v2.4.3
Project 8 C++ Utility Library
application.hh
Go to the documentation of this file.
1 /*
2  * application.hh
3  *
4  * Created on: Jul 20, 2018
5  * Author: N.S. Oblath
6  */
7 
8 #ifndef SCARAB_APPLICATION_HH_
9 #define SCARAB_APPLICATION_HH_
10 
11 #include "CLI11.hpp"
12 
13 #include "member_variables.hh"
14 #include "param_helpers.hh"
15 
16 namespace scarab
17 {
18  typedef CLI::App app;
19 
20  class version_semantic;
21 
22  class main_app;
23 
52  {
53  public:
54  config_decorator( main_app* a_main, app* a_this_app );
55  virtual ~config_decorator();
56 
57  main_app* main() const;
58  app* this_app() const;
59 
61  config_decorator* add_config_subcommand( std::string a_subcommand_name, std::string a_description="" );
62 
64  template< typename T, CLI::enable_if_t< ! CLI::is_vector<T>::value, CLI::detail::enabler > = CLI::detail::dummy >
65  CLI::Option* add_config_option( std::string a_name,
66  std::string a_master_config_addr,
67  std::string a_description = "" );
68 
70  template< typename T, CLI::enable_if_t< ! CLI::is_vector<T>::value, CLI::detail::enabler > = CLI::detail::dummy >
71  CLI::Option* add_config_multi_option( std::string a_name,
72  std::string a_master_config_addr,
73  std::string a_description = "" );
74 
77  template< typename T, CLI::enable_if_t< std::is_integral<T>::value && ! CLI::is_bool<T>::value, CLI::detail::enabler > = CLI::detail::dummy >
78  CLI::Option* add_config_flag( std::string a_name,
79  std::string a_master_config_addr,
80  std::string a_description = "" );
81 
84  template< typename T, CLI::enable_if_t< CLI::is_bool<T>::value, CLI::detail::enabler > = CLI::detail::dummy >
85  CLI::Option* add_config_flag( std::string a_name,
86  std::string a_master_config_addr,
87  std::string a_description = "" );
88 
89  public:
90  // these structs provide a type erasure mechanism that:
91  // - holds the actual value provided on the CL, and
92  // - adds the value to the f_app_options, and then to the global config, from the pre_callback function
94  {
95  virtual void add_to_app_options( param_node& a_app_options ) = 0;
96  CLI::Option* f_option;
97  std::string f_master_config_addr;
98  virtual ~app_option_holder() {}
99  };
100 
101  template< typename T >
103  {
104  void add_to_app_options( param_node& a_app_options )
105  {
106  if( ! (*f_option) ) return;
107  param_ptr_t t_new_config_ptr = simple_parser::parse_address(
108  f_master_config_addr,
109  param_ptr_t( new param_value(f_value) ) ); // throws scarab::error if top-level param object is not a node
110  a_app_options.merge( t_new_config_ptr->as_node() );
111  return;
112  }
115  };
116 
117  template< typename T >
119  {
120  void add_to_app_options( param_node& a_app_options )
121  {
122  if( ! (*f_option) ) return;
123  param_array t_array;
124  std::for_each( f_values.begin(), f_values.end(), [&t_array]( T a_value ){ t_array.push_back( a_value ); } );
125  param_ptr_t t_new_config_ptr = simple_parser::parse_address(
126  f_master_config_addr,
127  param_ptr_t( new param_array(std::move(t_array)) ) ); // throws scarab::error if top-level param object is not a node
128  a_app_options.merge( t_new_config_ptr->as_node() );
129  return;
130  }
131  std::vector< T > f_values;
133  };
134 
136  {
137  void add_to_app_options( param_node& a_app_options )
138  {
139  if( ! (*f_option) ) return;
140  param_ptr_t t_new_config_ptr = simple_parser::parse_address(
141  f_master_config_addr,
142  param_ptr_t( new param_value(*f_option) ) ); // throws scarab::error if top-level param object is not a node
143  a_app_options.merge( t_new_config_ptr->as_node() );
144  return;
145  }
147  };
148 
149  protected:
151  app* f_this;
152 
153  // config_decorator owns the decorators of subcommands just like app owns the apps of subcommands
154  using conf_dec_ptr_t = std::unique_ptr< config_decorator >;
155  std::vector< conf_dec_ptr_t > f_subcommand_decorators;
156  };
157 
158 
247  class SCARAB_API main_app : public config_decorator, public app
248  {
249  public:
250  main_app();
251  virtual ~main_app();
252 
253  public:
256  virtual void pre_callback();
257 
258  // Functions to perform each configuration stage
260  virtual void do_config_stage_1();
262  virtual void do_config_stage_2();
264  virtual void do_config_stage_3();
266  virtual void do_config_stage_4();
267 
268  void set_version( version_semantic* a_ver );
269 
271  mv_referrable( param_node, master_config );
272 
273  // configuration stage 1
275  mv_referrable( param_node, default_config );
276 
277  // configuration stage 2
279  mv_referrable_const( std::string, config_filename );
281  mv_accessible( unsigned, global_verbosity );
282 
283  // configuration stage 3
285  mv_referrable( param_node, nonoption_kw_args );
287  mv_referrable( param_array, nonoption_ord_args );
288 
289  // configuration stage 4
291  mv_referrable( param_node, app_options );
292 
294  mv_referrable( std::vector< std::shared_ptr< app_option_holder > >, app_option_holders );
295  };
296 
297 
298  template< typename T, CLI::enable_if_t< ! CLI::is_vector<T>::value, CLI::detail::enabler > >
299  CLI::Option* config_decorator::add_config_option( std::string a_name,
300  std::string a_master_config_addr,
301  std::string a_description )
302  {
303  auto t_opt_holder_ptr = std::make_shared< app_option_holder_typed<T> >();
304  t_opt_holder_ptr->f_option = f_this->add_option( a_name, t_opt_holder_ptr->f_value, a_description ); // throws CLI::OptionAlreadyAdded if the option's already there
305  t_opt_holder_ptr->f_master_config_addr = a_master_config_addr;
306  f_main->app_option_holders().push_back( t_opt_holder_ptr );
307  return t_opt_holder_ptr->f_option;
308  }
309 
310  template< typename T, CLI::enable_if_t< ! CLI::is_vector<T>::value, CLI::detail::enabler > >
311  CLI::Option* config_decorator::add_config_multi_option( std::string a_name,
312  std::string a_master_config_addr,
313  std::string a_description )
314  {
315  auto t_opt_holder_ptr = std::make_shared< app_option_holder_vector_typed<T> >();
316  t_opt_holder_ptr->f_option = f_this->add_option( a_name, t_opt_holder_ptr->f_values, a_description ); // throws CLI::OptionAlreadyAdded if the option's already there
317  t_opt_holder_ptr->f_master_config_addr = a_master_config_addr;
318  f_main->app_option_holders().push_back( t_opt_holder_ptr );
319  return t_opt_holder_ptr->f_option;
320  }
321 
322  template< typename T, CLI::enable_if_t< std::is_integral<T>::value && ! CLI::is_bool<T>::value, CLI::detail::enabler > >
323  CLI::Option* config_decorator::add_config_flag( std::string a_name,
324  std::string a_master_config_addr,
325  std::string a_description )
326  {
327  auto t_opt_holder_ptr = std::make_shared< app_option_holder_typed<T> >();
328  t_opt_holder_ptr->f_option = f_this->add_flag( a_name, t_opt_holder_ptr->f_value, a_description ); // throws CLI::OptionAlreadyAdded if the option's already there
329  t_opt_holder_ptr->f_master_config_addr = a_master_config_addr;
330  f_main->app_option_holders().push_back( t_opt_holder_ptr );
331  return t_opt_holder_ptr->f_option;
332  }
333 
334  template< typename T, CLI::enable_if_t< CLI::is_bool<T>::value, CLI::detail::enabler > >
335  CLI::Option* config_decorator::add_config_flag( std::string a_name,
336  std::string a_master_config_addr,
337  std::string a_description )
338  {
339  auto t_opt_holder_ptr = std::make_shared< app_option_holder_bool_flag >();
340  t_opt_holder_ptr->f_option = f_this->add_flag( a_name, a_description ); // throws CLI::OptionAlreadyAdded if the option's already there
341  t_opt_holder_ptr->f_master_config_addr = a_master_config_addr;
342  f_main->app_option_holders().push_back( t_opt_holder_ptr );
343  return t_opt_holder_ptr->f_option;
344  }
345 
346  inline app* config_decorator::this_app() const
347  {
348  return f_this;
349  }
350 
352  {
353  return f_main;
354  }
355 
356 } /* namespace scarab */
357 
358 #endif /* SCARAB_APPLICATION_HH_ */
void merge(const param_node &a_object)
Definition: param_node.cc:90
constexpr enabler dummy
An instance to use in EnableIf.
Definition: CLI11.hpp:717
static param_ptr_t parse_address(const std::string &an_addr, param_ptr_t a_value=param_ptr_t())
Converts an address into a nested param structure, and optionally attaches a value.
#define SCARAB_API
Definition: scarab_api.hh:24
int main(int argc, char **argv)
CLI::App app
Definition: application.hh:18
std::unique_ptr< config_decorator > conf_dec_ptr_t
Definition: application.hh:154
enabler
Simple empty scoped class.
Definition: CLI11.hpp:714
Adds the ability to create options and subcommands that are tied to a main_app&#39;s master config...
Definition: application.hh:51
CLI::Option * add_config_flag(std::string a_name, std::string a_master_config_addr, std::string a_description="")
Definition: application.hh:323
#define mv_referrable
std::vector< conf_dec_ptr_t > f_subcommand_decorators
Definition: application.hh:155
CLI::Option * add_config_option(std::string a_name, std::string a_master_config_addr, std::string a_description="")
Add an option that gets automatically added to the master config of a main_app.
Definition: application.hh:299
CLI::Option * add_config_multi_option(std::string a_name, std::string a_master_config_addr, std::string a_description="")
Add an option that gets automatically added to the master config of a main_app.
Definition: application.hh:311
#define mv_accessible
std::unique_ptr< param > param_ptr_t
Definition: param_base.hh:23
#define mv_referrable_const
Primary application class.
Definition: application.hh:247
void add_to_app_options(param_node &a_app_options)
Definition: application.hh:137
void push_back(const param &a_value)
Definition: param_array.hh:238
void add_to_app_options(param_node &a_app_options)
Definition: application.hh:104
main_app * main() const
Definition: application.hh:351