Browse Source

Merge branch 'feat/query'

* feat/query:
  Move type inspectors to own file.
  Automatically print containers.
  Add a no-args query option.
Sam Jaffe 5 years ago
parent
commit
c748d5cf9c
3 changed files with 59 additions and 0 deletions
  1. 28 0
      include/cli/cli.h
  2. 20 0
      include/cli/types.h
  3. 11 0
      test/cli_test.cxx

+ 28 - 0
include/cli/cli.h

@@ -16,6 +16,7 @@
 #include <vector>
 
 #include "lambda_cast.h"
+#include "types.h"
 
 namespace cli {
 
@@ -41,6 +42,12 @@ public:
   cli & register_callback(std::string const & handle, F && cb) {
     return register_callback(handle, lambdas::FFL(cb));
   }
+  template <typename T>
+  cli & register_query(std::string const & handle, std::function<T()> cb);
+  template <typename F>
+  cli & register_query(std::string const & handle, F && cb) {
+    return register_query(handle, lambdas::FFL(cb));
+  }
   
   void run() const;
   template <typename T, size_t I>
@@ -77,4 +84,25 @@ cli & cli::register_callback(std::string const & handle,
   return *this;
 }
 
+template <typename T> void cli_print(T const & value) {
+  if constexpr (detail::is_container_v<T> && !detail::is_string_v<T>) {
+    using ::cli::cli_print;
+    for (auto & elem : value) {
+      cli_print(elem);
+    }
+  } else {
+    std::cout << "  " << value << "\n";
+  }
+}
+
+template <typename T>
+cli & cli::register_query(std::string const & handle, std::function<T()> cb) {
+  arguments_.emplace(handle, 0);
+  callbacks_.emplace(handle, [=](args_t const & args) {
+    using ::cli::cli_print;
+    cli_print(cb());
+  });
+  return *this;
+}
+
 }

+ 20 - 0
include/cli/types.h

@@ -0,0 +1,20 @@
+#pragma once
+
+namespace cli::detail {
+template <typename T> struct is_string : std::false_type {};
+template <typename T>
+struct is_string<T*> : std::is_same<std::remove_cv_t<T>, char> {};
+template <typename T>
+struct is_string<T[]> : std::is_same<std::remove_cv_t<T>, char> {};
+template <typename...Ts>
+struct is_string<std::basic_string<Ts...>> : std::true_type {};
+
+template <typename T, typename = void> struct is_container : std::false_type {};
+template <typename T>
+struct is_container<T, std::enable_if_t<!std::is_void_v<typename T::value_type>>> : std::true_type {};
+
+template <typename T>
+static constexpr bool const is_string_v = is_string<T>::value;
+template <typename T>
+static constexpr bool const is_container_v = is_container<T>::value;
+}

+ 11 - 0
test/cli_test.cxx

@@ -16,6 +16,8 @@
 // unit tests.
 #undef EXPECT_THAT
 #define EXPECT_THAT ASSERT_THAT
+#undef EXPECT_THROW
+#define EXPECT_THROW ASSERT_THROW
 #undef EXPECT_TRUE
 #define EXPECT_TRUE ASSERT_TRUE
 #undef EXPECT_FALSE
@@ -40,3 +42,12 @@ TEST(CliTest, WillSkipCallbackIfNotEnoughArgs) {
   cli::cli(input).register_callback("act", [&](int){ was_hit = true; }).run();
   EXPECT_FALSE(was_hit);
 }
+
+struct example {};
+void cli_print(example const &) { throw example{}; }
+
+TEST(CliTest, QueryInvokesADLFunction) {
+  std::stringstream input{R"(query)"};
+  auto func = [](){ return example{}; };
+  EXPECT_THROW(cli::cli(input).register_query("query", func).run(), example);
+}