Scarab  v2.4.6
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  config_decorator( const config_decorator& ) = delete;
56  config_decorator( config_decorator&& ) = delete;
57  virtual ~config_decorator();
58 
59  config_decorator& operator=( const config_decorator& ) = delete;
60  config_decorator& operator=( config_decorator&& ) = delete;
61 
62  main_app* main() const;
63  app* this_app() const;
64 
66  config_decorator* add_config_subcommand( std::string a_subcommand_name, std::string a_description="" );
67 
69  template< typename T, CLI::enable_if_t< ! CLI::is_vector<T>::value, CLI::detail::enabler > = CLI::detail::dummy >
70  CLI::Option* add_config_option( std::string a_name,
71  std::string a_master_config_addr,
72  std::string a_description = "" );
73 
75  template< typename T, CLI::enable_if_t< ! CLI::is_vector<T>::value, CLI::detail::enabler > = CLI::detail::dummy >
76  CLI::Option* add_config_multi_option( std::string a_name,
77  std::string a_master_config_addr,
78  std::string a_description = "" );
79 
82  template< typename T, CLI::enable_if_t< std::is_integral<T>::value && ! CLI::is_bool<T>::value, CLI::detail::enabler > = CLI::detail::dummy >
83  CLI::Option* add_config_flag( std::string a_name,
84  std::string a_master_config_addr,
85  std::string a_description = "" );
86 
89  template< typename T, CLI::enable_if_t< CLI::is_bool<T>::value, CLI::detail::enabler > = CLI::detail::dummy >
90  CLI::Option* add_config_flag( std::string a_name,
91  std::string a_master_config_addr,
92  std::string a_description = "" );
93 
94  public:
95  // these structs provide a type erasure mechanism that:
96  // - holds the actual value provided on the CL, and
97  // - adds the value to the f_app_options, and then to the global config, from the pre_callback function
99  {
100  virtual void add_to_app_options( param_node& a_app_options ) = 0;
101  CLI::Option* f_option;
102  std::string f_master_config_addr;
103  virtual ~app_option_holder() {}
104  };
105 
106  template< typename T >
108  {
109  void add_to_app_options( param_node& a_app_options )
110  {
111  if( ! (*f_option) ) return;
112  param_ptr_t t_new_config_ptr = simple_parser::parse_address(
113  f_master_config_addr,
114  param_ptr_t( new param_value(f_value) ) ); // throws scarab::error if top-level param object is not a node
115  a_app_options.merge( t_new_config_ptr->as_node() );
116  return;
117  }
120  };
121 
122  template< typename T >
124  {
125  void add_to_app_options( param_node& a_app_options )
126  {
127  if( ! (*f_option) ) return;
128  param_array t_array;
129  std::for_each( f_values.begin(), f_values.end(), [&t_array]( T a_value ){ t_array.push_back( a_value ); } );
130  param_ptr_t t_new_config_ptr = simple_parser::parse_address(
131  f_master_config_addr,
132  param_ptr_t( new param_array(std::move(t_array)) ) ); // throws scarab::error if top-level param object is not a node
133  a_app_options.merge( t_new_config_ptr->as_node() );
134  return;
135  }
136  std::vector< T > f_values;
138  };
139 
141  {
142  void add_to_app_options( param_node& a_app_options )
143  {
144  if( ! (*f_option) ) return;
145  param_ptr_t t_new_config_ptr = simple_parser::parse_address(
146  f_master_config_addr,
147  param_ptr_t( new param_value(*f_option) ) ); // throws scarab::error if top-level param object is not a node
148  a_app_options.merge( t_new_config_ptr->as_node() );
149  return;
150  }
152  };
153 
154  protected:
156  app* f_this;
157 
158  // config_decorator owns the decorators of subcommands just like app owns the apps of subcommands
159  using conf_dec_ptr_t = std::unique_ptr< config_decorator >;
160  std::vector< conf_dec_ptr_t > f_subcommand_decorators;
161  };
162 
163 
252  class SCARAB_API main_app : public config_decorator, public app
253  {
254  public:
255  main_app();
256  virtual ~main_app();
257 
258  public:
261  virtual void pre_callback();
262 
263  // Functions to perform each configuration stage
265  virtual void do_config_stage_1();
267  virtual void do_config_stage_2();
269  virtual void do_config_stage_3();
271  virtual void do_config_stage_4();
272 
273  void set_version( version_semantic* a_ver );
274 
276  mv_referrable( param_node, master_config );
277 
278  // configuration stage 1
280  mv_referrable( param_node, default_config );
281 
282  // configuration stage 2
284  mv_referrable_const( std::string, config_filename );
286  mv_accessible( unsigned, global_verbosity );
287 
288  // configuration stage 3
290  mv_referrable( param_node, nonoption_kw_args );
292  mv_referrable( param_array, nonoption_ord_args );
293 
294  // configuration stage 4
296  mv_referrable( param_node, app_options );
297 
299  mv_referrable( std::vector< std::shared_ptr< app_option_holder > >, app_option_holders );
300  };
301 
302 
303  template< typename T, CLI::enable_if_t< ! CLI::is_vector<T>::value, CLI::detail::enabler > >
304  CLI::Option* config_decorator::add_config_option( std::string a_name,
305  std::string a_master_config_addr,
306  std::string a_description )
307  {
308  auto t_opt_holder_ptr = std::make_shared< app_option_holder_typed<T> >();
309  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
310  t_opt_holder_ptr->f_master_config_addr = a_master_config_addr;
311  f_main->app_option_holders().push_back( t_opt_holder_ptr );
312  return t_opt_holder_ptr->f_option;
313  }
314 
315  template< typename T, CLI::enable_if_t< ! CLI::is_vector<T>::value, CLI::detail::enabler > >
316  CLI::Option* config_decorator::add_config_multi_option( std::string a_name,
317  std::string a_master_config_addr,
318  std::string a_description )
319  {
320  auto t_opt_holder_ptr = std::make_shared< app_option_holder_vector_typed<T> >();
321  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
322  t_opt_holder_ptr->f_master_config_addr = a_master_config_addr;
323  f_main->app_option_holders().push_back( t_opt_holder_ptr );
324  return t_opt_holder_ptr->f_option;
325  }
326 
327  template< typename T, CLI::enable_if_t< std::is_integral<T>::value && ! CLI::is_bool<T>::value, CLI::detail::enabler > >
328  CLI::Option* config_decorator::add_config_flag( std::string a_name,
329  std::string a_master_config_addr,
330  std::string a_description )
331  {
332  auto t_opt_holder_ptr = std::make_shared< app_option_holder_typed<T> >();
333  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
334  t_opt_holder_ptr->f_master_config_addr = a_master_config_addr;
335  f_main->app_option_holders().push_back( t_opt_holder_ptr );
336  return t_opt_holder_ptr->f_option;
337  }
338 
339  template< typename T, CLI::enable_if_t< CLI::is_bool<T>::value, CLI::detail::enabler > >
340  CLI::Option* config_decorator::add_config_flag( std::string a_name,
341  std::string a_master_config_addr,
342  std::string a_description )
343  {
344  auto t_opt_holder_ptr = std::make_shared< app_option_holder_bool_flag >();
345  t_opt_holder_ptr->f_option = f_this->add_flag( a_name, a_description ); // throws CLI::OptionAlreadyAdded if the option's already there
346  t_opt_holder_ptr->f_master_config_addr = a_master_config_addr;
347  f_main->app_option_holders().push_back( t_opt_holder_ptr );
348  return t_opt_holder_ptr->f_option;
349  }
350 
351  inline app* config_decorator::this_app() const
352  {
353  return f_this;
354  }
355 
357  {
358  return f_main;
359  }
360 
361 } /* namespace scarab */
362 
363 #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:159
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:328
#define mv_referrable
std::vector< conf_dec_ptr_t > f_subcommand_decorators
Definition: application.hh:160
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:304
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:316
#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:252
void add_to_app_options(param_node &a_app_options)
Definition: application.hh:142
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:109
main_app * main() const
Definition: application.hh:356