Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,32 @@ mstch::config::escape = [](const std::string& str) -> std::string {
};
```


### Handling missing keys

By default, mstch does not consider missing keys a problem but simply ignores
them. If the client expects all keys referenced by a template to exist, mstch
can be configured to throw an exception if a key is not found:

```c++
#include <iostream>
#include <mstch/mstch.hpp>
#include <string>

int main() {
mstch::config::throw_on_missing_key = true;
const std::string view{"{{a-missing-key}}"};
mstch::map context{{"an-existing-key", std::string{"a value"}}};
try {
std::cout << mstch::render(view, context) << std::endl;
} catch (const mstch::key_not_found& e) {
std::cout << "Failed to render the template: " << e.what() << std::endl;
}
return 0;
}
```


## Requirements

- A C++ compiler with decent C++11 support. Currently tested with:
Expand Down
18 changes: 18 additions & 0 deletions include/mstch/mstch.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,31 @@
#include <string>
#include <memory>
#include <functional>
#include <exception>

#include <boost/variant.hpp>

namespace mstch {

class key_not_found : public std::exception {
public:
key_not_found(const std::string& name):
description(std::string{"The key '"} + name + "' is missing")
{
}

const char* what() const noexcept override
{
return description.c_str();
}

private:
const std::string description;
};

struct config {
static std::function<std::string(const std::string&)> escape;
static bool throw_on_missing_key;
};

namespace internal {
Expand Down
1 change: 1 addition & 0 deletions src/mstch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using namespace mstch;

std::function<std::string(const std::string&)> mstch::config::escape;
bool mstch::config::throw_on_missing_key = false;

std::string mstch::render(
const std::string& tmplt,
Expand Down
2 changes: 2 additions & 0 deletions src/render_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ const mstch::node& render_context::find_node(
for (auto& node: current_nodes)
if (visit(has_token(token), *node))
return visit(get_token(token, *node), *node);
if (mstch::config::throw_on_missing_key)
throw key_not_found{token};
return null_node;
}

Expand Down
3 changes: 3 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ add_executable(mstch_test test_main.cpp)
target_link_libraries(mstch_test mstch)
add_dependencies(mstch_test test_data_hpp specs_data_hpp)

list(APPEND tests "missing_key_is_ignored")
list(APPEND tests "missing_key_is_reported")

foreach(test ${tests})
add_test(NAME ${test} COMMAND mstch_test ${test})
endforeach(test)
14 changes: 14 additions & 0 deletions test/test_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,3 +153,17 @@ SPECS_TEST(inverted)
SPECS_TEST(partials)
SPECS_TEST(sections)
SPECS_TEST(lambdas)

TEST_CASE("missing_key_is_ignored") {
mstch::config::throw_on_missing_key = false;
const std::string view{"{{a-non-existing-key}}"};
mstch::map context{{"an-existing-key", std::string{"a value"}}};
REQUIRE_NOTHROW(mstch::render(view, context));
}

TEST_CASE("missing_key_is_reported") {
mstch::config::throw_on_missing_key = true;
const std::string view{"{{a-missing-key}}"};
mstch::map context{{"an-existing-key", std::string{"a value"}}};
REQUIRE_THROWS_AS(mstch::render(view, context), mstch::key_not_found);
}