Skip to content
This repository has been archived by the owner on Oct 28, 2021. It is now read-only.

Optional arguments to Opt using std::optional #89

Open
parnmatt opened this issue Apr 10, 2019 · 1 comment
Open

Optional arguments to Opt using std::optional #89

parnmatt opened this issue Apr 10, 2019 · 1 comment

Comments

@parnmatt
Copy link

There is code to handle std::optional via CLARA_CONFIG_OPTIONAL_TYPE; however Opt still is expecting an argument if none is given.

For example for logging: ./program, run with no logging (default), ./program -l enable logging, ./program -l file.log enable logging to named file.

This would make sense to use std::optional here.

For example, the default will not do anything; giving the "flag" -l will act like a pass the log through to std::clog; giving the optional with a filename -l /path/to/file.log will pass through to the /path/to/file.log.

std::ostream m_log{nullptr};
std::ofstream m_log_{};

clara::Opt{[&](std::optional<fs::path> filename) {
	           if (!filename) {
		           m_log.rdbuf(std::clog.rdbuf());
		           return clara::ParserResult::ok(clara::ParseResultType::Matched);
	           }
	           m_log_.open(*filename);
	           m_log.rdbuf(m_log_.rdbuf());
	           return clara::ParserResult::ok(clara::ParseResultType::Matched);
           },
           "filename"s}["-l"s]["--log"s]("enable logging [set log file {stderr}]"s);
@parnmatt
Copy link
Author

My current work around is to use a class with a set of stream operators.

edited slightly to only show the logging

namespace utils {

	// in utils.hxx
	class log {
	public:
		log() = default;

		explicit log(std::ostream& os)
		    : m_log{os.rdbuf()} {}

		explicit log(fs::path const& path)
		    : m_log_{path}
		    , m_log{m_log_.rdbuf()} {}

		template <typename T>
		friend auto inline operator<<(utils::log& log, T const& value) -> utils::log& {
			log.m_log << value;
			return log;
		}

		friend auto operator>>(std::istream& is, log& log) -> std::istream&;


	private:
		std::ofstream m_log_{};
		std::ostream m_log{nullptr};
	};

	// in utils.cxx
	auto operator>>(std::istream& is, log& log) -> std::istream& {
		auto buf = std::string{};
		is >> buf;

		// check if boolean value
		auto const static negative = std::array{"0"s, "false"s, "off"s, "n"s, "no"s};
		auto const static positive = std::array{"1"s, "true"s, "on"s, "y"s, "yes"s};
		auto boolean = buf;
		std::transform(std::begin(boolean), std::end(boolean), std::begin(boolean),
		               [](unsigned char c) { return std::tolower(c); });

		if (std::find(std::begin(negative), std::end(negative), boolean) != std::end(negative)) {
			// disable logging

		} else if (std::find(std::begin(positive), std::end(positive), boolean) != std::end(positive)) {
			// enable logging to stderr
			log.m_log.rdbuf(std::clog.rdbuf());

		} else {
			// enable logging to file
			auto const filename = fs::path{buf};
			log.m_log_.open(filename);
			log.m_log.rdbuf(log.m_log_.rdbuf());
		}

		return is;
	}

}  // namespace utils

// relevant bit of parser
bool m_help{false};
utils::log m_log{};

auto args = clara::Help(m_help)
            | clara::Opt{m_log, "false|true|filename"s}["-l"s]["--log"s](
                "<false> disable logging\n"
                "<true> enable logging to stderr\n"
                "<filename> enable logging to filename\t{false}"s);

As you can see it's not quite ideal; I also have to call it ./program -l true rather than ./program -l.
Considering Clara also has bool parsing, and std::optional, I think it would be a nice addition to the library.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant