mirror of
https://github.com/pantor/inja.git
synced 2026-05-30 15:55:23 +00:00
419c93c840
* throw exception if a file cannot be opened * Add a new function in utils.hpp: open_file_or_throw: This function returns an opened std::ifstream or throws by calling `inja_throw`. * Use this function in Parser::load_file which previously returned an empty string if the file couldn't be opened. * Use this function in Environment::load_json which previously threw a `nlohmann::detail::parse_error` if the file couldn't be opened. * In Parser::parse_statement: When including files through `include`, do not attempt to (re-)parse templates from files that were already included. Additionally, this prevents inja from attempting to load in-memory templates by their name from disk. * Add tests that check if an exception is thrown when attempting to open files that do not exist. * cmake: enable C++11 * cmake: require C++11 when depending on single_inja * code style
185 lines
5.5 KiB
C++
185 lines
5.5 KiB
C++
#ifndef PANTOR_INJA_ENVIRONMENT_HPP
|
|
#define PANTOR_INJA_ENVIRONMENT_HPP
|
|
|
|
#include <memory>
|
|
#include <fstream>
|
|
#include <sstream>
|
|
#include <string>
|
|
|
|
#include <nlohmann/json.hpp>
|
|
|
|
#include "config.hpp"
|
|
#include "function_storage.hpp"
|
|
#include "parser.hpp"
|
|
#include "polyfill.hpp"
|
|
#include "renderer.hpp"
|
|
#include "string_view.hpp"
|
|
#include "template.hpp"
|
|
#include "utils.hpp"
|
|
|
|
|
|
namespace inja {
|
|
|
|
using namespace nlohmann;
|
|
|
|
class Environment {
|
|
class Impl {
|
|
public:
|
|
std::string input_path;
|
|
std::string output_path;
|
|
|
|
LexerConfig lexer_config;
|
|
ParserConfig parser_config;
|
|
|
|
FunctionStorage callbacks;
|
|
TemplateStorage included_templates;
|
|
};
|
|
|
|
std::unique_ptr<Impl> m_impl;
|
|
|
|
public:
|
|
Environment(): Environment("") { }
|
|
|
|
explicit Environment(const std::string& global_path): m_impl(stdinja::make_unique<Impl>()) {
|
|
m_impl->input_path = global_path;
|
|
m_impl->output_path = global_path;
|
|
}
|
|
|
|
explicit Environment(const std::string& input_path, const std::string& output_path): m_impl(stdinja::make_unique<Impl>()) {
|
|
m_impl->input_path = input_path;
|
|
m_impl->output_path = output_path;
|
|
}
|
|
|
|
/// Sets the opener and closer for template statements
|
|
void set_statement(const std::string& open, const std::string& close) {
|
|
m_impl->lexer_config.statement_open = open;
|
|
m_impl->lexer_config.statement_close = close;
|
|
m_impl->lexer_config.update_open_chars();
|
|
}
|
|
|
|
/// Sets the opener for template line statements
|
|
void set_line_statement(const std::string& open) {
|
|
m_impl->lexer_config.line_statement = open;
|
|
m_impl->lexer_config.update_open_chars();
|
|
}
|
|
|
|
/// Sets the opener and closer for template expressions
|
|
void set_expression(const std::string& open, const std::string& close) {
|
|
m_impl->lexer_config.expression_open = open;
|
|
m_impl->lexer_config.expression_close = close;
|
|
m_impl->lexer_config.update_open_chars();
|
|
}
|
|
|
|
/// Sets the opener and closer for template comments
|
|
void set_comment(const std::string& open, const std::string& close) {
|
|
m_impl->lexer_config.comment_open = open;
|
|
m_impl->lexer_config.comment_close = close;
|
|
m_impl->lexer_config.update_open_chars();
|
|
}
|
|
|
|
/// Sets the element notation syntax
|
|
void set_element_notation(ElementNotation notation) {
|
|
m_impl->parser_config.notation = notation;
|
|
}
|
|
|
|
|
|
Template parse(nonstd::string_view input) {
|
|
Parser parser(m_impl->parser_config, m_impl->lexer_config, m_impl->included_templates);
|
|
return parser.parse(input);
|
|
}
|
|
|
|
Template parse_template(const std::string& filename) {
|
|
Parser parser(m_impl->parser_config, m_impl->lexer_config, m_impl->included_templates);
|
|
return parser.parse_template(m_impl->input_path + static_cast<std::string>(filename));
|
|
}
|
|
|
|
std::string render(nonstd::string_view input, const json& data) {
|
|
return render(parse(input), data);
|
|
}
|
|
|
|
std::string render(const Template& tmpl, const json& data) {
|
|
std::stringstream os;
|
|
render_to(os, tmpl, data);
|
|
return os.str();
|
|
}
|
|
|
|
std::string render_file(const std::string& filename, const json& data) {
|
|
return render(parse_template(filename), data);
|
|
}
|
|
|
|
std::string render_file_with_json_file(const std::string& filename, const std::string& filename_data) {
|
|
const json data = load_json(filename_data);
|
|
return render_file(filename, data);
|
|
}
|
|
|
|
void write(const std::string& filename, const json& data, const std::string& filename_out) {
|
|
std::ofstream file(m_impl->output_path + filename_out);
|
|
file << render_file(filename, data);
|
|
file.close();
|
|
}
|
|
|
|
void write(const Template& temp, const json& data, const std::string& filename_out) {
|
|
std::ofstream file(m_impl->output_path + filename_out);
|
|
file << render(temp, data);
|
|
file.close();
|
|
}
|
|
|
|
void write_with_json_file(const std::string& filename, const std::string& filename_data, const std::string& filename_out) {
|
|
const json data = load_json(filename_data);
|
|
write(filename, data, filename_out);
|
|
}
|
|
|
|
void write_with_json_file(const Template& temp, const std::string& filename_data, const std::string& filename_out) {
|
|
const json data = load_json(filename_data);
|
|
write(temp, data, filename_out);
|
|
}
|
|
|
|
std::ostream& render_to(std::ostream& os, const Template& tmpl, const json& data) {
|
|
Renderer(m_impl->included_templates, m_impl->callbacks).render_to(os, tmpl, data);
|
|
return os;
|
|
}
|
|
|
|
std::string load_file(const std::string& filename) {
|
|
Parser parser(m_impl->parser_config, m_impl->lexer_config, m_impl->included_templates);
|
|
return parser.load_file(m_impl->input_path + filename);
|
|
}
|
|
|
|
json load_json(const std::string& filename) {
|
|
std::ifstream file = open_file_or_throw(m_impl->input_path + filename);
|
|
json j;
|
|
file >> j;
|
|
return j;
|
|
}
|
|
|
|
void add_callback(const std::string& name, unsigned int numArgs, const CallbackFunction& callback) {
|
|
m_impl->callbacks.add_callback(name, numArgs, callback);
|
|
}
|
|
|
|
/** Includes a template with a given name into the environment.
|
|
* Then, a template can be rendered in another template using the
|
|
* include "<name>" syntax.
|
|
*/
|
|
void include_template(const std::string& name, const Template& tmpl) {
|
|
m_impl->included_templates[name] = tmpl;
|
|
}
|
|
};
|
|
|
|
/*!
|
|
@brief render with default settings to a string
|
|
*/
|
|
inline std::string render(nonstd::string_view input, const json& data) {
|
|
return Environment().render(input, data);
|
|
}
|
|
|
|
/*!
|
|
@brief render with default settings to the given output stream
|
|
*/
|
|
inline void render_to(std::ostream& os, nonstd::string_view input, const json& data) {
|
|
Environment env;
|
|
env.render_to(os, env.parse(input), data);
|
|
}
|
|
|
|
}
|
|
|
|
#endif // PANTOR_INJA_ENVIRONMENT_HPP
|