Added mechanism to understand passed Option value.
authorRafał Długołęcki <rafal@dlugolecki.net.pl>
Sun, 3 May 2015 09:27:26 +0000 (11:27 +0200)
committerRafał Długołęcki <rafal@dlugolecki.net.pl>
Sun, 3 May 2015 09:27:26 +0000 (11:27 +0200)
include/argument.h
include/option.h
src/main.cpp

index 159f5eb3f258e284d45768dc657b0f54bcc9b299..82954eb6fd3a5b8fa2b46841f110973d2def3f6b 100644 (file)
@@ -51,16 +51,17 @@ namespace command {
 
         /**
          * Method used for checking if Argument understands user value.
-         * If so current Argument is flagged as used, and no more checks against
+         * If so current Argument is flagged as used and no more checks against
          * it will be done in future.
          *
-         * If conversion from passed value to ArgumentType is impossible, it is
-         * ignored.
+         * \attention If conversion from passed value to ArgumentType is
+         * impossible, it is ignored. It means that it is not understanded by
+         * Argument.
          *
          * @param argv command line value against which test will be made.
          *
          * @return If passed argv is succesfully converted to ArgumentType,
-         *  returns true, and Argument is set as used one. If there was an error
+         *  returns true and Argument is set as used one. If there was an error
          *  during conversion, method returns false and can be used to check
          *  against next value.
          */
index 270bb76410f3c8bfead32c44adf0a6928cea707c..dba1c16818c4aa65ce05fecd9b79b048e68cac4c 100644 (file)
@@ -2,6 +2,8 @@
 #define __COMMAND_OPTION_H
 
 #include <string>
+#include <sstream>
+#include <stdexcept>
 
 #include "parameter.h"
 
@@ -11,16 +13,26 @@ namespace command {
      * Options are non-required, named parameters of program.
      *
      * Example:
-     *  ./myprog OptionName OptionValue
+     *  ./myprog OptionName=OptionValue
      */
     template<typename OptionType>
     class Option
         : public Parameter, public Callable<OptionType>  {
+    public:
+        typedef std::string OptionName;
     protected:
         /**
-         * Option name
+         * Current Option name
+         */
+        OptionName name;
+
+        /**
+         * Current Option value
          */
-        std::string name;
+        OptionType value;
+
+        /** Variable indicating if current Option was already used or not */
+        bool used = false;
 
     public:
         /**
@@ -33,17 +45,66 @@ namespace command {
         Option(std::string name, const std::string & description, void (*function)(OptionType))
             : Parameter(description), Callable<OptionType>(function), name(name) {
         }
+
+        /**
+         *
+         */
         virtual ~Option() { }
 
+        /**
+         *
+         */
         virtual void handle() {
-            this->call(std::string("O"));
+            this->call(value);
         }
 
-        virtual bool understand(const std::string & argVal) {
-            if (argVal.find(name) != std::string::npos) {
+        /**
+         * Method used for checking if Option understands given user value.
+         * If so current Option is flagged as used and no more checks against
+         * it will be done in future.
+         *
+         * Passed value should be in form of:
+         *      OptionName=OptionValue
+         *
+         * If no equal sign is after OptionName part,
+         * std::invalid_argument exception with appropriate message is thrown
+         *
+         * If conversion of OptionValue part to OptionType failed,
+         * std::invalid_argument exception with appropriate message is thrown
+         *
+         * @param argv command line value against which test will be made.
+         *  User value should be in format: OptionName=OptionValue.
+         *
+         * @return If passed argv succesfully detected OptionName part as a
+         *  current option and its OptionValue part has been succesfully
+         *  converted to OptionType, returns true and Option is set as used one.
+         *  Otherwise returns false and can be used to check against next value.
+         *
+         * @throw std::invalid_argument when OptionName part has no equal sign
+         *  after itself
+         * @throw std::invalid_argument when OptionValue part failed conversion
+         *  to OptionType
+         */
+        virtual bool understand(const std::string & argv) {
+            if ((!used) &&
+                (argv.find(name) == 0)) {
+                std::size_t pos = argv.find("=");
+                if (pos != name.size()) {
+                    throw std::invalid_argument("Option: " + name + " requires value but no one has been provided");
+                }
+
+                std::stringstream ss;
+
+                ss << argv.substr(pos + 1);
+                ss >> value;
+
+                if (ss.fail()) {
+                    throw std::invalid_argument("Value for option: " + name + " failed conversion to the required type");
+                }
+
+                used = true;
                 return true;
             }
-
             return false;
         }
     };
index 813491aae3442b231841f2490d4faecae04200c4..017434559a71c9eca8c6e30f223d481c5d826f91 100644 (file)
@@ -9,11 +9,15 @@ void some_function(bool a) {
     std::cout << "Some function " << a << std::endl;
 }
 
+void help_function(std::string a) {
+    std::cout << "Some function " << a << std::endl;
+}
+
 int main(int argc, char *argv[]) {
     command::Command command(argc, argv, {
 //         new command::Argument<std::string>("File path", [](std::string value)->void { std::cout << "Hello from lambda " << value << std::endl; }),
-        new command::Argument<bool>("File path", some_function)/*,
-        new command::Option<std::string>("h", "Help", some_function)*/
+        new command::Argument<bool>("File path", some_function),
+        new command::Option<std::string>("h", "Help", help_function)
     });
 
     return 0;