Explorar o código

refactor: use Impl directly in Action callback gen

Sam Jaffe %!s(int64=2) %!d(string=hai) anos
pai
achega
c6f998e176

+ 48 - 36
include/program_args/arguments.h

@@ -8,7 +8,8 @@
 namespace program {
 
 /**
- * @brief A string-literal object that requires input arguments to be two or more characters
+ * @brief A string-literal object that requires input arguments to be two or
+ * more characters
  */
 struct LongArg {
   template <size_t N> constexpr LongArg(char const (&str)[N]) : str(str) {
@@ -37,28 +38,33 @@ public:
 
 protected:
   /**
-   * @brief Define an "action"/"subcommand"/"verb" to be executed. An example of this pattern
-   * would be how git visualizes sub-commands in its interface, even though in implementation
-   * it appears different.
-   * @invariant Will fail to compile if bound to something that isn't a subtype of Arguments
+   * @brief Define an "action"/"subcommand"/"verb" to be executed. An example of
+   * this pattern would be how git visualizes sub-commands in its interface,
+   * even though in implementation it appears different.
+   * @invariant Will fail to compile if bound to something that isn't a subtype
+   * of Arguments
    * @param name A name of the action for usage messages
    * @param description An optional description object
    * @return A binding object that can implicitly cast to a subtype of Arguments
    *
-   * @throws ArgumentMixingError if both argument() and action() have been invoked in this
+   * @throws ArgumentMixingError if both argument() and action() have been
+   * invoked in this
    */
-  auto action(LongArg name, std::string const &description = "");
-  
+  auto action(LongArg name, std::string const & description = "");
+
   /**
    * @brief Define an argument to be passed in to this program
    *
    * @param index The 0-based index of this argument in the program args array.
    * @param name A name of the argument for usage messages
    * @param description An optional description object
-   * @return A binding object that will write its data in to an object of arity 1
+   * @return A binding object that will write its data in to an object of arity
+   * 1
    *
-   * @throws ArgumentMixingError if both argument() and action() have been invoked in this
-   * @throws ArgumentStructureError if this argument is required, but a prior argument was optional
+   * @throws ArgumentMixingError if both argument() and action() have been
+   * invoked in this
+   * @throws ArgumentStructureError if this argument is required, but a prior
+   * argument was optional
    * @throws IllegalPositionError if index is already in use in this
    * @throws IllegalPositionError if no argument is available at index
    */
@@ -70,37 +76,40 @@ protected:
    * @param description An optional description object
    * @returns All unbound arguments in {@sa Arguments::arguments}
 
-   * @throws ArgumentMixingError if both argument() and action() have been invoked in this
+   * @throws ArgumentMixingError if both argument() and action() have been
+   invoked in this
    * @throws ArgumentStructureError if rest is called with multiple names
    */
   std::vector<std::string> rest(LongArg name = "args",
                                 std::string const & description = "");
-  
+
   /**
    * @brief Define a flag (option with an arity of zero).
-   * If a flag binds to a boolean and has a name, then t will be invertable with "--no-" prefix.
-   * If a flag binds to an integer, then it increments the value with each repetition.
+   * If a flag binds to a boolean and has a name, then t will be invertable with
+   * "--no-" prefix. If a flag binds to an integer, then it increments the value
+   * with each repetition.
    * @invariant One or both of name and abbrev must be provided
-   * @param name The name of the flag, to be parsed from the commandline with a "--" prefix
-   * @param abbrev A single-character version of a flag, to be parsed from the commandline
-   * with a '-' prefix
+   * @param name The name of the flag, to be parsed from the commandline with a
+   * "--" prefix
+   * @param abbrev A single-character version of a flag, to be parsed from the
+   * commandline with a '-' prefix
    * @param description An optional description object
    */
   auto flag(LongArg name, char abbrev, std::string const & description = "");
   auto flag(LongArg name, std::string const & description = "");
   auto flag(char abbrev, std::string const & description = "");
-  
+
   /**
-   * @brief Define an option. If an option is repeated, then it can be used to fill out multiple
-   * entries in a map or vector.
+   * @brief Define an option. If an option is repeated, then it can be used to
+   * fill out multiple entries in a map or vector.
    * @invariant One or both of name and abbrev must be provided
-   * @param name The name of the option, to be parsed from the commandline with a "--" prefix
-   * @param abbrev A single-character version of an option, to be parsed from the commandline
-   * with a '-' prefix
+   * @param name The name of the option, to be parsed from the commandline with
+   * a "--" prefix
+   * @param abbrev A single-character version of an option, to be parsed from
+   * the commandline with a '-' prefix
    * @param description An optional description object
    */
-  auto option(LongArg name, char abbrev,
-              std::string const & description = "");
+  auto option(LongArg name, char abbrev, std::string const & description = "");
   auto option(LongArg name, std::string const & description = "");
   auto option(char abbrev, std::string const & description = "");
 
@@ -109,27 +118,31 @@ private:
   void add_options(std::string const & name, char abbrev,
                    std::string const & description,
                    std::vector<std::string> aliases = {});
-  
+
   bool has_actions() const { return !action_descriptions.empty(); }
-  bool has_arguments() const { return !(rest_name.empty() && argument_names.empty()); }
-  
+  bool has_arguments() const {
+    return !(rest_name.empty() && argument_names.empty());
+  }
+
   option_id id(std::string const & arg) const;
   option_id id(char arg) const { return id({'-', arg}); }
-  
+
   bool is_option(std::string const & arg) const;
   bool is_option(char arg) const { return is_option({'-', arg}); }
-  
+
   bool is_flag(std::string const & arg) const;
   bool is_flag(char arg) const { return is_flag({'-', arg}); }
 
 private:
-  // A helper for what limited introspection is required for handling actions in test
+  // A helper for what limited introspection is required for handling actions in
+  // test
   friend struct ArgumentTestHelper;
   friend int main(int, char const * const *);
-  
+
 private:
-  using main_callback_t = std::function<int(Arguments const &)>;
-  using make_hook_t = std::function<main_callback_t(size_t, char const * const *)>;
+  using main_callback_t = std::function<int(Impl const &)>;
+  using make_hook_t =
+      std::function<main_callback_t(size_t, char const * const *)>;
   // Metadata variables
   bool primed_{false};
   std::string rest_name;
@@ -219,7 +232,6 @@ struct Arguments<Impl>::WithDefault {
 
 #include "arguments_impl.hpp"
 
-
 template <typename Args, typename Action>
 int typed_main(Args const &, Action const &);
 

+ 6 - 11
include/program_args/arguments_impl.hpp

@@ -21,8 +21,8 @@ Arguments<Impl>::Action::operator T() const {
   static_assert(std::is_base_of_v<Arguments<T>, T>,
                 "Action can only bind to Arguments");
   if (!primed()) {
-    self->actions.emplace(name, [](int argc, char const * const *argv) {
-      return [action = T(argc, argv)](Arguments<Impl> const &args){
+    self->actions.emplace(name, [](int argc, char const * const * argv) {
+      return [action = T(argc, argv)](Impl const & args) {
         return typed_main(args, action);
       };
     });
@@ -112,9 +112,7 @@ template <typename Impl> auto Arguments<Impl>::Flag::operator=(bool && value) {
 template <typename Impl> bool Arguments<Impl>::Flag::primed(bool inv) const {
   if (self->primed_) { return self->flags.count(name); }
   std::vector<std::string> aliases;
-  if (name.size() > 1 && inv) {
-    aliases.push_back("no-" + name);
-  }
+  if (name.size() > 1 && inv) { aliases.push_back("no-" + name); }
   self->add_options(name, abbrev, description, aliases);
   self->flag_names.emplace(name);
   return false;
@@ -144,7 +142,6 @@ auto Arguments<Impl>::Option::operator=(T && value) {
   return WithDefault<Option, T>{*this, std::forward<T>(value)};
 }
 
-
 template <typename Impl>
 template <typename T>
 auto Arguments<Impl>::Option::operator=(std::initializer_list<T> value) {
@@ -224,9 +221,7 @@ template <typename Impl> void Arguments<Impl>::usage() const {
   for (auto & [index, name] : argument_names) {
     std::cout << " " << (index == optional_from ? "[" : "") << name;
   }
-  if (rest_name.size()) {
-    std::cout << " [" << rest_name << "...]";
-  }
+  if (rest_name.size()) { std::cout << " [" << rest_name << "...]"; }
   if (optional_from != no_optional_args) { std::cout << "]"; }
   std::cout << "\nArgument Arguments:\n";
   for (auto & [name, desc] : argument_descriptions) {
@@ -283,8 +278,8 @@ auto Arguments<Impl>::argument(size_t index, LongArg name,
 }
 
 template <typename Impl>
-std::vector<std::string> Arguments<Impl>::rest(LongArg name,
-                                               std::string const & description) {
+std::vector<std::string>
+Arguments<Impl>::rest(LongArg name, std::string const & description) {
   if (has_actions()) { throw ArgumentMixingError(); }
   if (!rest_name.empty() && rest_name != name.str) {
     throw ArgumentStructureError("duplicate rest() parameter", name);

+ 4 - 6
test/action_test.cpp

@@ -11,10 +11,10 @@
 
 namespace program {
 struct ArgumentTestHelper {
-  template <typename Impl> bool has_main(Arguments<Impl> const &args) const {
+  template <typename Impl> bool has_main(Impl const & args) const {
     return static_cast<bool>(args.main_callback);
   }
-  template <typename Impl> int main(Arguments<Impl> const &args) const {
+  template <typename Impl> int main(Impl const & args) const {
     return args.main_callback(args);
   }
 };
@@ -60,7 +60,7 @@ struct Git : program::Arguments<Git> {
   using Arguments::Arguments;
 
   bool verbose = flag("verbose", 'v');
-  
+
   Commit commit = action("commit");
   Checkout checkout = action("checkout");
 };
@@ -70,9 +70,7 @@ TEST(ActionTest, CannotMixActionAndArgument) {
   EXPECT_THROW(Bad2(), program::ArgumentMixingError);
 }
 
-TEST(ActionTest, CanRunWithMultipleActions) {
-  EXPECT_NO_THROW(Git());
-}
+TEST(ActionTest, CanRunWithMultipleActions) { EXPECT_NO_THROW(Git()); }
 
 TEST(ActionTest, ActionIsRouted) {
   Git git = parse<Git>({"", "-v", "commit", "-m", "this is a message"});