diff --git a/include/openspace/util/documentation.h b/include/openspace/util/documentation.h index 5cec2aee9a..ec06629316 100644 --- a/include/openspace/util/documentation.h +++ b/include/openspace/util/documentation.h @@ -37,325 +37,185 @@ namespace openspace { namespace documentation { -struct AbstractVerifier { - using Success = bool; - using Offender = std::vector; - using TestResult = std::tuple; +struct TestResult { + bool success; + std::vector offenders; +}; - virtual TestResult operator()(const ghoul::Dictionary& dict, const std::string& key) const { - bool testSuccess = test(dict, key); - if (testSuccess) { - return { testSuccess, {} }; - } - else { - return { testSuccess, {key} }; - } - } +struct Verifier { + virtual TestResult operator()(const ghoul::Dictionary& dict, + const std::string& key) const; - virtual bool test(const ghoul::Dictionary& dict, const std::string& key) const { - return false; - }; + virtual bool test(const ghoul::Dictionary& dict, const std::string& key) const; virtual std::string documentation() const = 0; }; struct DocumentationEntry { - DocumentationEntry(std::string key, AbstractVerifier* t, bool optional = false, std::string doc = "") - : key(std::move(key)) - , tester(std::move(t)) - , optional(optional) - , documentation(std::move(doc)) {} + DocumentationEntry(std::string key, Verifier* t, bool optional = false, + std::string doc = ""); std::string key; - std::unique_ptr tester; + std::shared_ptr tester; bool optional; std::string documentation; }; using Documentation = std::vector; +TestResult testSpecification(const Documentation& d, const ghoul::Dictionary& dictionary); -std::tuple> testSpecification(const Documentation& d, const ghoul::Dictionary& dictionary) { - bool success = true; - std::vector offenders; - - for (const auto& p : d) { - AbstractVerifier& verifier = *(p.tester); - AbstractVerifier::TestResult res = verifier(dictionary, p.key); - if (!std::get<0>(res)) { - success = false; - offenders.insert( - offenders.end(), - std::get<1>(res).begin(), - std::get<1>(res).end() - ); - } - } - return { success, offenders }; -} - -std::string generateDocumentation(const Documentation& d) { - using namespace std::string_literals; - std::string result; - - for (const auto& p : d) { - result += p.key + '\n'; - result += "Optional: "s + (p.optional ? "true" : "false") + '\n'; - result += p.tester->documentation() + '\n'; - result += '\n'; - result += p.documentation + '\n'; - } - - return result; -} +std::string generateDocumentation(const Documentation& d); +// General verifiers template -struct TemplateVerifier : public AbstractVerifier { +struct TemplateVerifier : public Verifier { using Type = T; }; struct BoolVerifier : public TemplateVerifier { - bool test(const ghoul::Dictionary& dict, const std::string& key) const override { - return dict.hasKeyAndValue(key); - } + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - std::string documentation() const override { - return "Type: Boolean"; - } + std::string documentation() const override; }; struct DoubleVerifier : public TemplateVerifier { - bool test(const ghoul::Dictionary& dict, const std::string& key) const override { - return dict.hasKeyAndValue(key); - } + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - std::string documentation() const override { - return "Type: Double"; - } + std::string documentation() const override; }; struct IntVerifier : public TemplateVerifier { - bool test(const ghoul::Dictionary& dict, const std::string& key) const override { - if (dict.hasKeyAndValue(key)) { - return true; - } - else { - if (dict.hasKeyAndValue(key)) { - // If we have a double value, we need to check if it is integer - double value = dict.value(key); - double intPart; - return modf(value, &intPart) == 0.0; - } - else { - // If we don't have a double value, we cannot have an int value - return false; - } - } - } + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - std::string documentation() const override { - return "Type: Integer"; - } + std::string documentation() const override; }; struct StringVerifier : public TemplateVerifier { - bool test(const ghoul::Dictionary& dict, const std::string& key) const override { - return dict.hasKeyAndValue(key); - } + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - std::string documentation() const override { - return "Type: String"; - } + std::string documentation() const override; }; struct TableVerifier : public TemplateVerifier { - TableVerifier(Documentation d) : doc(std::move(d)) {} + TableVerifier(Documentation d); - TestResult operator()(const ghoul::Dictionary& dict, const std::string& key) const override { - if (dict.hasKeyAndValue(key)) { - ghoul::Dictionary d = dict.value(key); - AbstractVerifier::TestResult res = testSpecification(doc, d); - - for (std::string& s : std::get<1>(res)) { - s = key + "." + s; - } + TestResult operator()(const ghoul::Dictionary& dict, const std::string& key) const override; - return res; - } - return{ dict.hasKeyAndValue(key), {} }; - } - - std::string documentation() const override { - return "Type: Table" + '\n' + generateDocumentation(doc); - } + std::string documentation() const override; Documentation doc; }; +// Operator Verifiers + template struct LessVerifier : public T { - LessVerifier(typename T::Type value) : value(std::move(value)) {} + LessVerifier(typename T::Type value); - bool test(const ghoul::Dictionary& dict, const std::string& key) const override { - return T::test(dict, key) && dict.value(key) < value; - } + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - std::string documentation() const override { - return T::documentation() + '\n' + "Less than: " + std::to_string(value); - } + std::string documentation() const; typename T::Type value; }; template struct LessEqualVerifier : public T { - LessEqualVerifier(typename T::Type value) : value(std::move(value)) {} + LessEqualVerifier(typename T::Type value); - bool test(const ghoul::Dictionary& dict, const std::string& key) const override { - return T::test(dict, key) && dict.value(key) <= value; - } + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - std::string documentation() const override { - return T::documentation() + '\n' + "Less or equal to: " + std::to_string(value); - } + std::string documentation() const override; typename T::Type value; }; template struct GreaterVerifier : public T { - GreaterVerifier(typename T::Type value) : value(std::move(value)) {} + GreaterVerifier(typename T::Type value); - bool test(const ghoul::Dictionary& dict, const std::string& key) const override { - return T::test(dict, key) && dict.value(key) > value; - } + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - std::string documentation() const override { - return T::documentation() + '\n' + "Greater than: " + std::to_string(value); - } + std::string documentation() const override; typename T::Type value; }; template struct GreaterEqualVerifier : public T { - GreaterEqualVerifier(typename T::Type value) : value(std::move(value)) {} + GreaterEqualVerifier(typename T::Type value); - bool test(const ghoul::Dictionary& dict, const std::string& key) const override { - return T::test(dict, key) && dict.value(key) >= value; - } + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - std::string documentation() const override { - return T::documentation() + '\n' + "Greater or equal to: " + std::to_string(value); - } + std::string documentation() const override; typename T::Type value; }; template struct EqualVerifier : public T { - EqualVerifier(typename T::Type value) : value(std::move(value)) {} + EqualVerifier(typename T::Type value); - bool test(const ghoul::Dictionary& dict, const std::string& key) const override { - return T::test(dict, key) && dict.value(key) == value; - } + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - std::string documentation() const override { - return T::documentation() + '\n' + "Equal to: " + std::to_string(value); - } + std::string documentation() const override; typename T::Type value; }; template struct UnequalVerifier : public T { - UnequalVerifier(typename T::Type value) : value(std::move(value)) {} + UnequalVerifier(typename T::Type value); - bool test(const ghoul::Dictionary& dict, const std::string& key) const override { - return T::test(dict, key) && dict.value(key) != value; - } + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - std::string documentation() const override { - return T::documentation() + '\n' + "Unequal to: " + std::to_string(value); - } + std::string documentation() const override; typename T::Type value; }; +// List Verifiers + template struct InListVerifier : public T { - InListVerifier(std::vector values) : values(std::move(values)) {} + InListVerifier(std::vector values); - bool test(const ghoul::Dictionary& dict, const std::string& key) const override { - if (T::test(dict, key)) { - typename T::Type value = dict.value(key); + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - auto it = std::find(values.begin(), values.end(), value); - return it != values.end(); - } - else { - return false; - } - } - - std::string documentation() const override { - std::string result = T::documentation() + '\n' + "In list {"; - - std::stringstream s; - std::copy(values.begin(), values.end(), std::ostream_iterator(s, ",")); - - std::string joined = s.str(); - // We need to remove a trailing ',' at the end of the string - result += joined.substr(0, joined.size() - 1); - - result += "}"; - return result; - } + std::string documentation() const override; std::vector values; }; template struct NotInListVerifier : public T { - NotInListVerifier(std::vector values) : values(std::move(values)) {} + NotInListVerifier(std::vector values); - bool test(const ghoul::Dictionary& dict, const std::string& key) const override { - if (T::test(dict, key)) { - typename T::Type value = dict.value(key); + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; - auto it = std::find(values.begin(), values.end(), value); - return it == values.end(); - } - else { - return false; - } - } - - std::string documentation() const override { - std::string result = T::documentation() + '\n' + "Not in list {"; - - std::stringstream s; - std::copy(values.begin(), values.end(), std::ostream_iterator(s, ",")); - - std::string joined = s.str(); - // We need to remove a trailing ',' at the end of the string - result += joined.substr(0, joined.size() - 1); - - - result += "}"; - return result; - } + std::string documentation() const override; std::vector values; }; +// Misc Verifiers +template +struct AnnotationVerifier : public T { + AnnotationVerifier(std::string annotation); + bool test(const ghoul::Dictionary& dict, const std::string& key) const override; + std::string documentation() const override; + std::string annotation; +}; } // namespace documentation } // namespace openspace +#include "documentation.inl" + #endif // __DOCUMENTATION_H__ diff --git a/include/openspace/util/documentation.inl b/include/openspace/util/documentation.inl new file mode 100644 index 0000000000..4fbf6f40f1 --- /dev/null +++ b/include/openspace/util/documentation.inl @@ -0,0 +1,188 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +namespace openspace { +namespace documentation { + +template +LessVerifier::LessVerifier(typename T::Type value) : value(std::move(value)) {} + +template +bool LessVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { + return T::test(dict, key) && dict.value(key) < value; +} + +template +std::string LessVerifier::documentation() const { + return T::documentation() + '\n' + "Less than: " + std::to_string(value); +} + + +template +LessEqualVerifier::LessEqualVerifier(typename T::Type value) : value(std::move(value)) {} + +template +bool LessEqualVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { + return T::test(dict, key) && dict.value(key) <= value; +} + +template +std::string LessEqualVerifier::documentation() const { + return T::documentation() + '\n' + "Less or equal to: " + std::to_string(value); +} + +template +GreaterVerifier::GreaterVerifier(typename T::Type value) : value(std::move(value)) {} + +template +bool GreaterVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { + return T::test(dict, key) && dict.value(key) > value; +} + +template +std::string GreaterVerifier::documentation() const { + return T::documentation() + '\n' + "Greater than: " + std::to_string(value); +} + +template +GreaterEqualVerifier::GreaterEqualVerifier(typename T::Type value) : value(std::move(value)) {} + +template +bool GreaterEqualVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { + return T::test(dict, key) && dict.value(key) >= value; +} + +template +std::string GreaterEqualVerifier::documentation() const { + return T::documentation() + '\n' + "Greater or equal to: " + std::to_string(value); +} + +template +EqualVerifier::EqualVerifier(typename T::Type value) : value(std::move(value)) {} + +template +bool EqualVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { + return T::test(dict, key) && dict.value(key) == value; +} + +template +std::string EqualVerifier::documentation() const { + return T::documentation() + '\n' + "Equal to: " + std::to_string(value); +} + +template +UnequalVerifier::UnequalVerifier(typename T::Type value) : value(std::move(value)) {} + +template +bool UnequalVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { + return T::test(dict, key) && dict.value(key) != value; +} + +template +std::string UnequalVerifier::documentation() const override { + return T::documentation() + '\n' + "Unequal to: " + std::to_string(value); +} + +template +InListVerifier::InListVerifier(std::vector values) : values(std::move(values)) {} + +template +bool InListVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { + if (T::test(dict, key)) { + typename T::Type value = dict.value(key); + + auto it = std::find(values.begin(), values.end(), value); + return it != values.end(); + } + else { + return false; + } +} + +template +std::string InListVerifier::documentation() const { + std::string result = T::documentation() + '\n' + "In list {"; + + std::stringstream s; + std::copy(values.begin(), values.end(), std::ostream_iterator(s, ",")); + + std::string joined = s.str(); + // We need to remove a trailing ',' at the end of the string + result += joined.substr(0, joined.size() - 1); + + result += "}"; + return result; +} + +template +NotInListVerifier::NotInListVerifier(std::vector values) : values(std::move(values)) {} + +template +bool NotInListVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { + if (T::test(dict, key)) { + typename T::Type value = dict.value(key); + + auto it = std::find(values.begin(), values.end(), value); + return it == values.end(); + } + else { + return false; + } +} + +template +std::string NotInListVerifier::documentation() const { + std::string result = T::documentation() + '\n' + "Not in list {"; + + std::stringstream s; + std::copy(values.begin(), values.end(), std::ostream_iterator(s, ",")); + + std::string joined = s.str(); + // We need to remove a trailing ',' at the end of the string + result += joined.substr(0, joined.size() - 1); + + + result += "}"; + return result; +} + +template +AnnotationVerifier::AnnotationVerifier(std::string annotation) + : annotation(std::move(annotation)) +{} + +template +bool AnnotationVerifier::test(const ghoul::Dictionary& dict, + const std::string& key) const +{ + return T::test(dict, key); +} + +template +std::string AnnotationVerifier::documentation() const { + return T::documentation() + '\n' + annotation; +} + +} // namespace documentation +} // namespace openspace diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9b0a640699..c50e7a7561 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -86,6 +86,7 @@ set(OPENSPACE_SOURCE ${OPENSPACE_BASE_DIR}/src/util/blockplaneintersectiongeometry.cpp ${OPENSPACE_BASE_DIR}/src/util/boxgeometry.cpp ${OPENSPACE_BASE_DIR}/src/util/camera.cpp + ${OPENSPACE_BASE_DIR}/src/util/documentation.cpp ${OPENSPACE_BASE_DIR}/src/util/factorymanager.cpp ${OPENSPACE_BASE_DIR}/src/util/keys.cpp ${OPENSPACE_BASE_DIR}/src/util/openspacemodule.cpp @@ -173,6 +174,7 @@ set(OPENSPACE_HEADER ${OPENSPACE_BASE_DIR}/include/openspace/util/boxgeometry.h ${OPENSPACE_BASE_DIR}/include/openspace/util/camera.h ${OPENSPACE_BASE_DIR}/include/openspace/util/documentation.h + ${OPENSPACE_BASE_DIR}/include/openspace/util/documentation.inl ${OPENSPACE_BASE_DIR}/include/openspace/util/factorymanager.h ${OPENSPACE_BASE_DIR}/include/openspace/util/factorymanager.inl ${OPENSPACE_BASE_DIR}/include/openspace/util/keys.h diff --git a/src/util/documentation.cpp b/src/util/documentation.cpp new file mode 100644 index 0000000000..33e9f2b94c --- /dev/null +++ b/src/util/documentation.cpp @@ -0,0 +1,154 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +namespace openspace { +namespace documentation { + +TestResult Verifier::operator()(const ghoul::Dictionary& dict, + const std::string& key) const { + bool testSuccess = test(dict, key); + if (testSuccess) { + return{ testSuccess, {} }; + } + else { + return{ testSuccess, { key } }; + } +} + +bool Verifier::test(const ghoul::Dictionary& dict, const std::string& key) const { + return false; +}; + +DocumentationEntry::DocumentationEntry(std::string key, Verifier* t, + bool optional, std::string doc) + : key(std::move(key)) + , tester(std::move(t)) + , optional(optional) + , documentation(std::move(doc)) {} + +TestResult testSpecification(const Documentation& d, const ghoul::Dictionary& dictionary) { + TestResult result; + result.success = true; + + for (const auto& p : d) { + Verifier& verifier = *(p.tester); + TestResult res = verifier(dictionary, p.key); + if (!res.success) { + result.success = false; + result.offenders.insert( + result.offenders.end(), + res.offenders.begin(), + res.offenders.end() + ); + } + } + return result; +} + +std::string generateDocumentation(const Documentation& d) { + using namespace std::string_literals; + std::string result; + + for (const auto& p : d) { + result += p.key + '\n'; + result += "Optional: "s + (p.optional ? "true" : "false") + '\n'; + result += p.tester->documentation() + '\n'; + result += '\n'; + result += p.documentation + '\n'; + } + + return result; +} + +bool BoolVerifier::test(const ghoul::Dictionary& dict, const std::string& key) const { + return dict.hasKeyAndValue(key); +} + +inline std::string BoolVerifier::documentation() const { + return "Type: Boolean"; +} + + +inline bool DoubleVerifier::test(const ghoul::Dictionary & dict, const std::string & key) const { + return dict.hasKeyAndValue(key); +} + +inline std::string DoubleVerifier::documentation() const { + return "Type: Double"; +} + +inline bool IntVerifier::test(const ghoul::Dictionary & dict, const std::string & key) const { + if (dict.hasKeyAndValue(key)) { + return true; + } + else { + if (dict.hasKeyAndValue(key)) { + // If we have a double value, we need to check if it is integer + double value = dict.value(key); + double intPart; + return modf(value, &intPart) == 0.0; + } + else { + // If we don't have a double value, we cannot have an int value + return false; + } + } +} + +inline std::string IntVerifier::documentation() const { + return "Type: Integer"; +} + +inline bool StringVerifier::test(const ghoul::Dictionary & dict, const std::string & key) const { + return dict.hasKeyAndValue(key); +} + +inline std::string StringVerifier::documentation() const { + return "Type: String"; +} + +inline TableVerifier::TableVerifier(Documentation d) : doc(std::move(d)) {} + +TestResult TableVerifier::operator()(const ghoul::Dictionary& dict, const std::string& key) const { + if (dict.hasKeyAndValue(key)) { + ghoul::Dictionary d = dict.value(key); + TestResult res = testSpecification(doc, d); + + for (std::string& s : res.offenders) { + s = key + "." + s; + } + + return res; + } + return{ dict.hasKeyAndValue(key),{} }; +} + +inline std::string TableVerifier::documentation() const { + return "Type: Table" + '\n' + generateDocumentation(doc); +} + +} // namespace documentation +} // namespace openspace