Scarab  2.8.1
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 #include "version_semantic.hh"
16 
17 namespace scarab
18 {
19  typedef CLI::App app;
20 
21  class version_semantic;
22 
23  class main_app;
24 
53  {
54  public:
55  config_decorator( main_app* a_main, app* a_this_app );
56  config_decorator( const config_decorator& ) = delete;
57  config_decorator( config_decorator&& ) = delete;
58  virtual ~config_decorator();
59 
60  config_decorator& operator=( const config_decorator& ) = delete;
61  config_decorator& operator=( config_decorator&& ) = delete;
62 
63  main_app* main() const;
64  app* this_app() const;
65 
67  config_decorator* add_config_subcommand( std::string a_subcommand_name, std::string a_description="" );
68 
71  CLI::Option* add_config_option( std::string a_name,
72  std::string a_master_config_addr,
73  std::string a_description = "" );
74 
77  CLI::Option* add_config_multi_option( std::string a_name,
78  std::string a_master_config_addr,
79  std::string a_description = "" );
80 
84  CLI::Option* add_config_flag( std::string a_name,
85  std::string a_master_config_addr,
86  std::string a_description = "" );
87 
91  CLI::Option* add_config_flag( std::string a_name,
92  std::string a_master_config_addr,
93  std::string a_description = "" );
94 
95  public:
96  // these structs provide a type erasure mechanism that:
97  // - holds the actual value provided on the CL, and
98  // - adds the value to the f_app_options, and then to the global config, from the pre_callback function
100  {
101  virtual void add_to_app_options( param_node& a_app_options ) = 0;
103  std::string f_master_config_addr;
104  virtual ~app_option_holder() {}
105  };
106 
107  template< typename T >
109  {
110  void add_to_app_options( param_node& a_app_options )
111  {
112  if( ! (*f_option) ) return;
113  param_ptr_t t_new_config_ptr = simple_parser::parse_address(
114  f_master_config_addr,
115  param_ptr_t( new param_value(f_value) ) ); // throws scarab::error if top-level param object is not a node
116  a_app_options.merge( t_new_config_ptr->as_node() );
117  return;
118  }
121  };
122 
123  template< typename T >
125  {
126  void add_to_app_options( param_node& a_app_options )
127  {
128  if( ! (*f_option) ) return;
129  param_array t_array;
130  std::for_each( f_values.begin(), f_values.end(), [&t_array]( T a_value ){ t_array.push_back( a_value ); } );
131  param_ptr_t t_new_config_ptr = simple_parser::parse_address(
132  f_master_config_addr,
133  param_ptr_t( new param_array(std::move(t_array)) ) ); // throws scarab::error if top-level param object is not a node
134  a_app_options.merge( t_new_config_ptr->as_node() );
135  return;
136  }
137  std::vector< T > f_values;
139  };
140 
142  {
143  void add_to_app_options( param_node& a_app_options )
144  {
145  if( ! (*f_option) ) return;
146  param_ptr_t t_new_config_ptr = simple_parser::parse_address(
147  f_master_config_addr,
148  param_ptr_t( new param_value(*f_option) ) ); // throws scarab::error if top-level param object is not a node
149  a_app_options.merge( t_new_config_ptr->as_node() );
150  return;
151  }
153  };
154 
155  protected:
157  app* f_this;
158 
159  // config_decorator owns the decorators of subcommands just like app owns the apps of subcommands
160  using conf_dec_ptr_t = std::unique_ptr< config_decorator >;
161  std::vector< conf_dec_ptr_t > f_subcommand_decorators;
162  };
163 
164 
253  class SCARAB_API main_app : public config_decorator, public app
254  {
255  public:
256  main_app();
257  virtual ~main_app();
258 
259  public:
262  virtual void pre_callback();
263 
264  // Functions to perform each configuration stage
266  virtual void do_config_stage_1();
268  virtual void do_config_stage_2();
270  virtual void do_config_stage_3();
272  virtual void do_config_stage_4();
273 
274  void set_version( scarab::version_semantic_ptr_t a_ver );
275 
277  mv_referrable( param_node, master_config );
278 
279  // configuration stage 1
281  mv_referrable( param_node, default_config );
282 
283  // configuration stage 2
285  mv_referrable_const( std::string, config_filename );
287  mv_accessible( unsigned, global_verbosity );
288 
289  // configuration stage 3
291  mv_referrable( param_node, nonoption_kw_args );
293  mv_referrable( param_array, nonoption_ord_args );
294 
295  // configuration stage 4
297  mv_referrable( param_node, app_options );
298 
300  mv_referrable( std::vector< std::shared_ptr< app_option_holder > >, app_option_holders );
301  };
302 
303 
306  std::string a_master_config_addr,
307  std::string a_description )
308  {
309  auto t_opt_holder_ptr = std::make_shared< app_option_holder_typed<T> >();
310  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
311  t_opt_holder_ptr->f_master_config_addr = a_master_config_addr;
312  f_main->app_option_holders().push_back( t_opt_holder_ptr );
313  return t_opt_holder_ptr->f_option;
314  }
315 
318  std::string a_master_config_addr,
319  std::string a_description )
320  {
321  auto t_opt_holder_ptr = std::make_shared< app_option_holder_vector_typed<T> >();
322  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
323  t_opt_holder_ptr->f_master_config_addr = a_master_config_addr;
324  f_main->app_option_holders().push_back( t_opt_holder_ptr );
325  return t_opt_holder_ptr->f_option;
326  }
327 
330  std::string a_master_config_addr,
331  std::string a_description )
332  {
333  auto t_opt_holder_ptr = std::make_shared< app_option_holder_typed<T> >();
334  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
335  t_opt_holder_ptr->f_master_config_addr = a_master_config_addr;
336  f_main->app_option_holders().push_back( t_opt_holder_ptr );
337  return t_opt_holder_ptr->f_option;
338  }
339 
341  CLI::Option* config_decorator::add_config_flag( std::string a_name,
342  std::string a_master_config_addr,
343  std::string a_description )
344  {
345  auto t_opt_holder_ptr = std::make_shared< app_option_holder_bool_flag >();
346  t_opt_holder_ptr->f_option = f_this->add_flag( a_name, a_description ); // throws CLI::OptionAlreadyAdded if the option's already there
347  t_opt_holder_ptr->f_master_config_addr = a_master_config_addr;
348  f_main->app_option_holders().push_back( t_opt_holder_ptr );
349  return t_opt_holder_ptr->f_option;
350  }
351 
352  inline app* config_decorator::this_app() const
353  {
354  return f_this;
355  }
356 
358  {
359  return f_main;
360  }
361 
362 } /* namespace scarab */
363 
364 #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:910
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
std::shared_ptr< version_semantic > version_semantic_ptr_t
CLI::App app
Definition: application.hh:19
std::unique_ptr< config_decorator > conf_dec_ptr_t
Definition: application.hh:160
enabler
Simple empty scoped class.
Definition: CLI11.hpp:907
Adds the ability to create options and subcommands that are tied to a main_app&#39;s master config...
Definition: application.hh:52
CLI::Option * add_config_flag(std::string a_name, std::string a_master_config_addr, std::string a_description="")
Definition: application.hh:329
Creates a command line program, with very few defaults.
Definition: CLI11.hpp:3696
#define mv_referrable
std::vector< conf_dec_ptr_t > f_subcommand_decorators
Definition: application.hh:161
Check to see if something is bool (fail check by default)
Definition: CLI11.hpp:936
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:305
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:317
#define mv_accessible
std::unique_ptr< param > param_ptr_t
Definition: param_base.hh:23
detail::enable_if_t<!detail::move_never< T >::value, T > move(object &&obj)
Definition: cast.h:1685
#define mv_referrable_const
Primary application class.
Definition: application.hh:253
void add_to_app_options(param_node &a_app_options)
Definition: application.hh:143
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:110
main_app * main() const
Definition: application.hh:357