hemplate

Simple XML template engine
git clone git://git.dimitrijedobrota.com/hemplate.git
Log | Files | Refs | README | LICENSE | HACKING | CONTRIBUTING | CODE_OF_CONDUCT | BUILDING

commit c5294d1c704cdb3f305970a2e3ef46fa98e6fda1
parent 7b79f6bda1d93c11b4e581d375b585cb9bbe9c63
author Dimitrije Dobrota < mail@dimitrijedobrota.com >
date Sat, 3 May 2025 11:26:24 +0200

Rename classes to common

Diffstat:
M CMakeLists.txt | ++ ---
M include/hemplate/atom.hpp | + -
D include/hemplate/classes.hpp | --------------------------------------------------------------
A include/hemplate/common.hpp | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
M include/hemplate/html.hpp | + -
M include/hemplate/rss.hpp | + -
M include/hemplate/sitemap.hpp | + -
D source/classes.cpp | ------------------------------------------------------------
A source/common.cpp | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
M test/CMakeLists.txt | + -
D test/source/classes_test.cpp | ---------------------------------------------------------------------------
A test/source/common_test.cpp | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

12 files changed, 204 insertions(+), 205 deletions(-)


diff --git a/ CMakeLists.txt b/ CMakeLists.txt

@@ -13,13 +13,13 @@ project(

include(cmake/project-is-top-level.cmake)
include(cmake/variables.cmake)

find_package(based 0.1 CONFIG REQUIRED)
find_package(based 0.1.1 CONFIG REQUIRED)

# ---- Declare library ----

add_library(
hemplate_hemplate
source/classes.cpp
source/common.cpp
source/attribute.cpp
)
target_link_libraries(hemplate_hemplate PUBLIC based::based)

@@ -76,7 +76,6 @@ if(PROJECT_IS_TOP_LEVEL)

endif()
endif()


# ---- Developer mode ----

if(NOT hemplate_DEVELOPER_MODE)

diff --git a/ include/hemplate/atom.hpp b/ include/hemplate/atom.hpp

@@ -1,6 +1,6 @@

#pragma once

#include "hemplate/classes.hpp"
#include "hemplate/common.hpp"
#include "hemplate/hemplate_export.hpp"

namespace hemplate::atom

diff --git a/ include/hemplate/classes.hpp b/ include/hemplate/classes.hpp

@@ -1,62 +0,0 @@

#pragma once

#include <array>

#include <based/string.hpp>
#include <based/type_traits.hpp>

#include "hemplate/element.hpp"
#include "hemplate/hemplate_export.hpp"

namespace hemplate
{

class HEMPLATE_EXPORT comment : public element
{
public:
explicit comment(std::string_view data)
: element(std::format("<-- {} -->", data))
{
}
};

class HEMPLATE_EXPORT xml : public element
{
static auto attrs(std::string_view version, std::string_view encoding)
{
return attribute_list {
{"version", version},
{"encoding", encoding},
};
}

public:
static constexpr const auto def_version = "1.0";
static constexpr const auto def_encoding = "UTF-8";

explicit xml(
std::string_view version = def_version,
std::string_view encoding = def_encoding
)
: element(std::format("<? xml {}?>", attrs(version, encoding)))
{
}
};

template<std::ranges::forward_range R>
element transform(
const R& range,
based::Procedure<element, std::ranges::range_value_t<R>> auto proc
)
{
std::vector<element> res;

res.reserve(std::size(range));
for (const auto& elem : range) {
res.emplace_back(proc(elem));
}

return element {res};
}

} // namespace hemplate

diff --git a/ include/hemplate/common.hpp b/ include/hemplate/common.hpp

@@ -0,0 +1,62 @@

#pragma once

#include <array>

#include <based/string.hpp>
#include <based/type_traits.hpp>

#include "hemplate/element.hpp"
#include "hemplate/hemplate_export.hpp"

namespace hemplate
{

class HEMPLATE_EXPORT comment : public element
{
public:
explicit comment(std::string_view data)
: element(std::format("<-- {} -->", data))
{
}
};

class HEMPLATE_EXPORT xml : public element
{
static auto attrs(std::string_view version, std::string_view encoding)
{
return attribute_list {
{"version", version},
{"encoding", encoding},
};
}

public:
static constexpr const auto def_version = "1.0";
static constexpr const auto def_encoding = "UTF-8";

explicit xml(
std::string_view version = def_version,
std::string_view encoding = def_encoding
)
: element(std::format("<? xml {}?>", attrs(version, encoding)))
{
}
};

template<std::ranges::forward_range R>
element transform(
const R& range,
based::Procedure<element, std::ranges::range_value_t<R>> auto proc
)
{
std::vector<element> res;

res.reserve(std::size(range));
for (const auto& elem : range) {
res.emplace_back(proc(elem));
}

return element {res};
}

} // namespace hemplate

diff --git a/ include/hemplate/html.hpp b/ include/hemplate/html.hpp

@@ -1,6 +1,6 @@

#pragma once

#include "hemplate/classes.hpp"
#include "hemplate/common.hpp"

namespace hemplate::html
{

diff --git a/ include/hemplate/rss.hpp b/ include/hemplate/rss.hpp

@@ -1,6 +1,6 @@

#pragma once

#include "hemplate/classes.hpp"
#include "hemplate/common.hpp"
#include "hemplate/hemplate_export.hpp"

namespace hemplate::rss

diff --git a/ include/hemplate/sitemap.hpp b/ include/hemplate/sitemap.hpp

@@ -1,6 +1,6 @@

#pragma once

#include "hemplate/classes.hpp"
#include "hemplate/common.hpp"
#include "hemplate/hemplate_export.hpp"

namespace hemplate::sitemap

diff --git a/ source/classes.cpp b/ source/classes.cpp

@@ -1,60 +0,0 @@

#include <chrono>
#include <ctime>
#include <format>
#include <string>

#include "hemplate/atom.hpp"
#include "hemplate/rss.hpp"

namespace
{

auto sec_since_epoch(int64_t sec)
{
return std::chrono::time_point_cast<std::chrono::seconds>(
std::chrono::system_clock::from_time_t(time_t {0})
+ std::chrono::seconds(sec)
);
}

auto get_time_now()
{
return std::chrono::current_zone()
->to_local(std::chrono::system_clock::now())
.time_since_epoch()
/ std::chrono::seconds(1);
}

} // namespace

namespace hemplate::atom
{

std::string format_time(int64_t sec)
{
static constexpr const char* rfc3339_f = "{:%FT%H:%M:%SZ}";
return std::format(rfc3339_f, sec_since_epoch(sec));
}

std::string format_time_now()
{
return format_time(get_time_now());
}

} // namespace hemplate::atom

namespace hemplate::rss
{

std::string format_time(int64_t sec)
{
static constexpr const char* rfc882_f = "{:%a, %d %b %Y %H:%M:%S %z}";
return std::format(rfc882_f, sec_since_epoch(sec));
}

std::string format_time_now()
{
return format_time(get_time_now());
}

} // namespace hemplate::rss

diff --git a/ source/common.cpp b/ source/common.cpp

@@ -0,0 +1,60 @@

#include <chrono>
#include <ctime>
#include <format>
#include <string>

#include "hemplate/atom.hpp"
#include "hemplate/rss.hpp"

namespace
{

auto sec_since_epoch(int64_t sec)
{
return std::chrono::time_point_cast<std::chrono::seconds>(
std::chrono::system_clock::from_time_t(time_t {0})
+ std::chrono::seconds(sec)
);
}

auto get_time_now()
{
return std::chrono::current_zone()
->to_local(std::chrono::system_clock::now())
.time_since_epoch()
/ std::chrono::seconds(1);
}

} // namespace

namespace hemplate::atom
{

std::string format_time(int64_t sec)
{
static constexpr const char* rfc3339_f = "{:%FT%H:%M:%SZ}";
return std::format(rfc3339_f, sec_since_epoch(sec));
}

std::string format_time_now()
{
return format_time(get_time_now());
}

} // namespace hemplate::atom

namespace hemplate::rss
{

std::string format_time(int64_t sec)
{
static constexpr const char* rfc882_f = "{:%a, %d %b %Y %H:%M:%S %z}";
return std::format(rfc882_f, sec_since_epoch(sec));
}

std::string format_time_now()
{
return format_time(get_time_now());
}

} // namespace hemplate::rss

diff --git a/ test/CMakeLists.txt b/ test/CMakeLists.txt

@@ -24,7 +24,7 @@ endfunction()

add_test(attribute_test)
add_test(attribute_list_test)
add_test(element_test)
add_test(classes_test)
add_test(common_test)
add_test(html_test)
add_test(atom_test)
add_test(rss_test)

diff --git a/ test/source/classes_test.cpp b/ test/source/classes_test.cpp

@@ -1,75 +0,0 @@

#include "hemplate/classes.hpp"

#include <catch2/catch_test_macros.hpp>

TEST_CASE("comment", "[classes/comment]")
{
const hemplate::comment comment {"hello world"};

REQUIRE(std::string(comment) == "<-- hello world -->\n");
}

TEST_CASE("xml", "[classes/xml]")
{
SECTION("default")
{
const hemplate::xml xml;

REQUIRE(
std::string(xml) == "<? xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
);
}

SECTION("version")
{
const hemplate::xml xml {"ver"};

REQUIRE(
std::string(xml) == "<? xml version=\"ver\" encoding=\"UTF-8\"?>\n"
);
}

SECTION("version encoding")
{
const hemplate::xml xml {"ver", "utf"};

REQUIRE(std::string(xml) == "<? xml version=\"ver\" encoding=\"utf\"?>\n");
}
}

TEST_CASE("transform", "[classes/transform]")
{
using tag = hemplate::element_boolean<"t">;
using child = hemplate::element_boolean<"c">;

SECTION("direct")
{
const std::vector<std::string> vec = {"1", "2"};
const auto t = tag {hemplate::transform(
vec,
[](const auto& e)
{
return child {e};
}
)};

REQUIRE(
std::string(t)
== "<t>\n <c>1</c>\n <c>2</c>\n</t>\n"
);
}

SECTION("indirect")
{
const std::vector<std::string> vec = {"1", "2"};
const auto t = tag {hemplate::transform(
vec,
[](const auto& e)
{
return hemplate::element {e};
}
)};

REQUIRE(std::string(t) == "<t>\n 1\n 2\n</t>\n");
}
}

diff --git a/ test/source/common_test.cpp b/ test/source/common_test.cpp

@@ -0,0 +1,75 @@

#include "hemplate/common.hpp"

#include <catch2/catch_test_macros.hpp>

TEST_CASE("comment", "[common/comment]")
{
const hemplate::comment comment {"hello world"};

REQUIRE(std::string(comment) == "<-- hello world -->\n");
}

TEST_CASE("xml", "[common/xml]")
{
SECTION("default")
{
const hemplate::xml xml;

REQUIRE(
std::string(xml) == "<? xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
);
}

SECTION("version")
{
const hemplate::xml xml {"ver"};

REQUIRE(
std::string(xml) == "<? xml version=\"ver\" encoding=\"UTF-8\"?>\n"
);
}

SECTION("version encoding")
{
const hemplate::xml xml {"ver", "utf"};

REQUIRE(std::string(xml) == "<? xml version=\"ver\" encoding=\"utf\"?>\n");
}
}

TEST_CASE("transform", "[common/transform]")
{
using tag = hemplate::element_boolean<"t">;
using child = hemplate::element_boolean<"c">;

SECTION("direct")
{
const std::vector<std::string> vec = {"1", "2"};
const auto t = tag {hemplate::transform(
vec,
[](const auto& e)
{
return child {e};
}
)};

REQUIRE(
std::string(t)
== "<t>\n <c>1</c>\n <c>2</c>\n</t>\n"
);
}

SECTION("indirect")
{
const std::vector<std::string> vec = {"1", "2"};
const auto t = tag {hemplate::transform(
vec,
[](const auto& e)
{
return hemplate::element {e};
}
)};

REQUIRE(std::string(t) == "<t>\n 1\n 2\n</t>\n");
}
}