hemplateSimple XML template engine |
git clone git://git.dimitrijedobrota.com/hemplate.git |
Log | Files | Refs | README | LICENSE | HACKING | CONTRIBUTING | CODE_OF_CONDUCT | BUILDING |
commit | 5dbbc906fba4ffb4aac3d9d2ca4b28529573ec48 |
parent | a536f3b212a1990caa284a84ddc005384f9b4d1b |
author | Dimitrije Dobrota < mail@dimitrijedobrota.com > |
date | Wed, 23 Apr 2025 11:20:09 +0200 |
Streamline attribute and everything using it
M | .clang-tidy | | | + |
M | example/html.cpp | | | ++++ --- |
M | include/hemplate/atom.hpp | | | ++++++++++++ ------ |
M | include/hemplate/attribute.hpp | | | +++++++++++++++++++ ----------------------------- |
M | include/hemplate/classes.hpp | | | ++ -- |
M | include/hemplate/element.hpp | | | ++++++++++++++++++++ --------------------------------------- |
M | include/hemplate/rss.hpp | | | +++++++++++++++++++++++++++++++++++++++++++ ----------------------------------- |
M | include/hemplate/sitemap.hpp | | | ++++++++++++++++++ ------ |
M | source/attribute.cpp | | | ++++++++++++++++++++++++++++ ---------------------------------------------- |
M | source/element.cpp | | | ++++++++++++++++++++++ ------------ |
10 files changed, 169 insertions(+), 178 deletions(-)
diff --git a/ .clang-tidy b/ .clang-tidy
@@ -12,6 +12,7 @@
Checks: "*,\
-llvmlibc-*,\
-cppcoreguidelines-avoid-do-while,\
-cppcoreguidelines-pro-bounds-constant-array-index,\
-bugprone-easily-swappable-parameters,\
-misc-include-cleaner,\
-misc-non-private-member-variables-in-classes,\
-misc-no-recursion,\
diff --git a/ example/html.cpp b/ example/html.cpp
@@ -1,8 +1,9 @@
#include <iostream>
#include "hemplate/attribute.hpp"
#include "hemplate/html.hpp"
#include "hemplate/attribute.hpp"
int main()
{
using namespace hemplate; // NOLINT
@@ -19,11 +20,11 @@
int main()
html::ul {
ul_attrs,
html::li {
li_attrs.add("class", "item1"),
li_attrs.add({"class", "item1"}),
"Item 1",
},
html::li {
li_attrs.add("class", "item2"),
li_attrs.add({"class", "item2"}),
"Item 2",
},
},
diff --git a/ include/hemplate/atom.hpp b/ include/hemplate/atom.hpp
@@ -12,21 +12,27 @@
std::string format_time_now();
class HEMPLATE_EXPORT feed
: public element_builder<"feed", element::Type::Boolean>
{
static auto attributes(std::string_view xmlns)
{
return attribute_list {
{"xmlns", xmlns},
};
}
public:
static constexpr const auto default_xmlns = "http://www.w3.org/2005/Atom";
explicit feed(std::string xmlns,
const std::derived_from<element> auto&... children)
: element_builder({{"xmlns", std::move(xmlns)}}, children...)
explicit feed(std::string_view xmlns, const is_element auto&... children)
: element_builder(attributes(xmlns), children...)
{
}
explicit feed(std::string xmlns, std::span<const element> children)
: element_builder({{"xmlns", std::move(xmlns)}}, children)
explicit feed(std::string_view xmlns, std::span<const element> children)
: element_builder(attributes(xmlns), children)
{
}
explicit feed(const std::derived_from<element> auto&... children)
explicit feed(const is_element auto&... children)
: feed(default_xmlns, children...)
{
}
diff --git a/ include/hemplate/attribute.hpp b/ include/hemplate/attribute.hpp
@@ -2,7 +2,6 @@
#include <format>
#include <string>
#include <utility>
#include <vector>
#include "hemplate/hemplate_export.hpp"
@@ -10,39 +9,32 @@
namespace hemplate
{
class HEMPLATE_EXPORT attribute
struct HEMPLATE_EXPORT attribute
{
public:
attribute(std::string name) // NOLINT
: m_name(std::move(name))
std::string name;
std::string value;
explicit attribute(std::string_view namee)
: name(namee)
{
}
attribute(std::string name, std::string value) // NOLINT
: m_name(std::move(name))
, m_value(std::move(value))
attribute(std::string_view namee, std::string_view val)
: name(namee)
, value(val)
{
}
bool operator==(const attribute& rhs) const = default;
const std::string& get_name() const { return m_name; }
const std::string& get_value() const { return m_value; }
void set_name(const std::string& name) { m_name = name; }
void set_value(const std::string& value) { m_value = value; }
bool empty() const { return get_value().empty(); }
// NOLINTNEXTLINE *-explicit-constructor
operator std::string() const
operator std::string() const // NOLINT *-explicit-constructor
{
return get_name() + "=\"" + get_value() + "\"";
return name + "=\"" + value + "\"";
}
private:
std::string m_name;
std::string m_value;
bool operator==(const attribute& rhs) const = default;
bool empty() const { return value.empty(); }
attribute& append(std::string_view delim, const std::string& val);
};
class HEMPLATE_EXPORT attribute_list
@@ -51,15 +43,13 @@
public:
attribute_list() = default;
attribute_list(std::initializer_list<attribute> list);
attribute_list(attribute attr); // NOLINT
attribute_list(attribute attr); // NOLINT *-explicit-constructor
attribute_list& set(const attribute_list& list);
attribute_list& set(const std::string& name);
attribute_list& set(const std::string& name, const std::string& value);
attribute_list& set(attribute attr);
attribute_list add(const attribute_list& list) const;
attribute_list add(const std::string& name) const;
attribute_list add(const std::string& name, const std::string& value) const;
attribute_list add(attribute attr) const;
bool empty() const;
diff --git a/ include/hemplate/classes.hpp b/ include/hemplate/classes.hpp
@@ -22,8 +22,8 @@
public:
explicit xml(std::string version = default_version,
std::string encoding = default_encoding)
: element_builder({{"version", std::move(version)},
{"encoding", std::move(encoding)}})
: element_builder(attribute_list {{"version", std::move(version)},
{"encoding", std::move(encoding)}})
{
}
};
diff --git a/ include/hemplate/element.hpp b/ include/hemplate/element.hpp
@@ -1,5 +1,4 @@
#pragma once
#include <span>
#include <string>
#include <vector>
@@ -12,6 +11,11 @@
namespace hemplate
{
class element;
template<typename T>
concept is_element = std::derived_from<T, element>;
class HEMPLATE_EXPORT element
{
public:
@@ -36,7 +40,7 @@
private:
explicit element(bool& state,
Type type,
std::string_view name,
const std::derived_from<element> auto&... children)
const is_element auto&... children)
: m_state(&state)
, m_type(type)
, m_name(name)
@@ -44,11 +48,10 @@
private:
{
}
explicit element(
bool& state,
Type type,
std::string_view name, // NOLINT *-easily-swappable-parameters
std::string_view data)
explicit element(bool& state,
Type type,
std::string_view name,
std::string_view data)
: m_state(&state)
, m_type(type)
, m_name(name)
@@ -71,7 +74,7 @@
private:
Type type,
std::string_view name,
attribute_list attributes,
const std::derived_from<element> auto&... children)
const is_element auto&... children)
: m_state(&state)
, m_type(type)
, m_name(name)
@@ -125,8 +128,11 @@
public:
element& add(const element& elem);
element& set(const std::string& name);
element& set(const std::string& name, const std::string& value);
element& set(const attribute_list& list);
element& set(attribute attr);
element add(const attribute_list& list) const;
element add(attribute attr) const;
bool get_state() const { return *m_state; }
bool tgl_state() const { return *m_state = !*m_state; }
@@ -138,35 +144,10 @@
class HEMPLATE_EXPORT element_builder : public element
static bool m_state; // NOLINT
public:
explicit element_builder(std::string_view data)
: element(m_state, MyType, Tag.data(), data)
{
}
explicit element_builder(const std::derived_from<element> auto&... children)
: element(m_state, MyType, Tag.data(), children...)
{
}
explicit element_builder(std::span<const element> children)
: element(m_state, MyType, Tag.data(), children)
{
}
explicit element_builder(attribute_list attributes, std::string_view data)
: element(m_state, MyType, Tag.data(), std::move(attributes), data)
{
}
explicit element_builder(attribute_list attributes,
const std::derived_from<element> auto&... children)
: element(m_state, MyType, Tag.data(), std::move(attributes), children...)
{
}
explicit element_builder(attribute_list attributes,
std::span<const element> children)
: element(m_state, MyType, Tag.data(), std::move(attributes), children)
template<typename... Args>
explicit element_builder(Args&&... args)
// NOLINTNEXTLINE *-no-array-decay
: element(m_state, MyType, Tag.data(), std::forward<Args>(args)...)
{
}
};
diff --git a/ include/hemplate/rss.hpp b/ include/hemplate/rss.hpp
@@ -12,29 +12,33 @@
std::string format_time_now();
class HEMPLATE_EXPORT rss
: public element_builder<"rss", element::Type::Boolean>
{
static auto attributes(std::string_view version, std::string_view xmlns)
{
return attribute_list {
{"version", version},
{"xmlns", xmlns},
};
}
public:
static constexpr const auto default_version = "2.0";
static constexpr const auto default_xmlns = "http://www.w3.org/2005/Atom";
explicit rss(std::string version,
std::string xmlns,
const std::derived_from<element> auto&... children)
: element_builder(
{{"version", std::move(version)}, {"xmlns:atom", std::move(xmlns)}},
children...)
explicit rss(std::string_view version,
std::string_view xmlns,
const is_element auto&... children)
: element_builder(attributes(version, xmlns), children...)
{
}
explicit rss(std::string version,
std::string xmlns,
explicit rss(std::string_view version,
std::string_view xmlns,
std::span<const element> children)
: element_builder(
{{"version", std::move(version)}, {"xmlns:atom", std::move(xmlns)}},
children)
: element_builder(attributes(version, xmlns), children)
{
}
explicit rss(const std::derived_from<element> auto&... children)
explicit rss(const is_element auto&... children)
: rss(default_version, default_xmlns, children...)
{
}
@@ -48,49 +52,53 @@
public:
class HEMPLATE_EXPORT atomLink // NOLINT *-identifier-naming
: public element_builder<"atom:link", element::Type::Boolean>
{
static auto attributes(attribute_list& list,
std::string_view rel,
std::string_view type)
{
return list.set({
{"rel", rel},
{"type", type},
});
}
public:
static constexpr const auto default_rel = "self";
static constexpr const auto default_type = "application/rss+xml";
explicit atomLink(std::string rel,
std::string type,
const attribute_list& attributes,
const std::derived_from<element> auto&... children)
: element_builder(attributes.add({{"rel", std::move(rel)},
{"type", std::move(type)}}),
children...)
explicit atomLink(std::string_view rel,
std::string_view type,
attribute_list attrs,
const is_element auto&... children)
: element_builder(attributes(attrs, rel, type), children...)
{
}
explicit atomLink(std::string rel,
std::string type,
const attribute_list& attributes,
explicit atomLink(std::string_view rel,
std::string_view type,
attribute_list attrs,
std::span<const element> children)
: element_builder(attributes.add({{"rel", std::move(rel)},
{"type", std::move(type)}}),
children)
: element_builder(attributes(attrs, rel, type), children)
{
}
explicit atomLink(const std::derived_from<element> auto&... children)
: atomLink(default_rel, default_type, {}, children...)
explicit atomLink(attribute_list attrs, const is_element auto&... children)
: atomLink(default_rel, default_type, std::move(attrs), children...)
{
}
explicit atomLink(std::span<const element> children)
: atomLink(default_rel, default_type, {}, children)
explicit atomLink(attribute_list attrs, std::span<const element> children)
: atomLink(default_rel, default_type, std::move(attrs), children)
{
}
explicit atomLink(const attribute_list& attributes,
const std::derived_from<element> auto&... children)
: atomLink(default_rel, default_type, attributes, children...)
explicit atomLink(const is_element auto&... children)
: atomLink({}, children...)
{
}
explicit atomLink(const attribute_list& attributes,
std::span<const element> children)
: atomLink(default_rel, default_type, attributes, children)
explicit atomLink(std::span<const element> children)
: atomLink({}, children)
{
}
};
diff --git a/ include/hemplate/sitemap.hpp b/ include/hemplate/sitemap.hpp
@@ -9,22 +9,28 @@
namespace hemplate::sitemap
class HEMPLATE_EXPORT urlset
: public element_builder<"urlset", element::Type::Boolean>
{
static auto attributes(std::string_view xmlns)
{
return attribute_list {
{"xmlns", xmlns},
};
}
public:
static constexpr const auto default_xmlns =
"http://www.sitemaps.org/schemas/sitemap/0.9";
explicit urlset(std::string xmlns,
const std::derived_from<element> auto&... children)
: element_builder({{"xmlns", std::move(xmlns)}}, children...)
explicit urlset(std::string_view xmlns, const is_element auto&... children)
: element_builder(attributes(xmlns), children...)
{
}
explicit urlset(std::string xmlns, std::span<const element> children)
: element_builder({{"xmlns", std::move(xmlns)}}, children)
explicit urlset(std::string_view xmlns, std::span<const element> children)
: element_builder(attributes(xmlns), children)
{
}
explicit urlset(const std::derived_from<element> auto&... children)
explicit urlset(const is_element auto&... children)
: urlset(default_xmlns, children...)
{
}
@@ -35,6 +41,12 @@
public:
}
};
using hemplate::comment;
using hemplate::element;
using hemplate::transform;
using hemplate::transparent;
using hemplate::xml;
// clang-format off
// NOLINTBEGIN *-identifier-naming
using changefreq = element_builder<"changefreq", element::Type::Boolean>;
diff --git a/ source/attribute.cpp b/ source/attribute.cpp
@@ -3,60 +3,54 @@
namespace hemplate
{
attribute& attribute::append(std::string_view delim, const std::string& val)
{
if (!value.empty()) {
if (!empty()) {
value += std::string(delim);
}
value += val;
}
return *this;
}
attribute_list::attribute_list(std::initializer_list<attribute> list)
{
for (const auto& attr : list) {
set(attr.get_name(), attr.get_value());
set(attr);
}
}
attribute_list::attribute_list(attribute attr) // NOLINT
attribute_list::attribute_list(attribute attr)
{
set(attr.get_name(), attr.get_value());
set(std::move(attr));
}
bool attribute_list::empty() const
{
return m_attributes.empty() && m_class.get_value().empty()
&& m_style.get_value().empty();
return m_attributes.empty() && m_class.value.empty() && m_style.value.empty();
}
attribute_list& attribute_list::set(const attribute_list& list)
{
for (const auto& attr : list.m_attributes) {
set(attr.get_name(), attr.get_value());
set(attr);
}
set("class", list.m_class);
set("style", list.m_style);
return (*this);
}
set(m_class);
set(m_style);
attribute_list& attribute_list::set(const std::string& name)
{
if (name != "class" && name != "style") {
m_attributes.emplace_back(name);
}
return *this;
return (*this);
}
attribute_list& attribute_list::set(const std::string& name,
const std::string& value)
attribute_list& attribute_list::set(attribute attr)
{
if (name == "class") {
if (m_class.get_value().empty()) {
m_class.set_value(value);
} else {
m_class.set_value(m_class.get_value() + " " + value);
}
} else if (name == "style") {
if (m_style.get_value().empty()) {
m_style.set_value(value);
} else {
m_style.set_value(m_style.get_value() + "; " + value);
}
if (attr.name == "class") {
m_class.append(" ", attr.value);
} else if (attr.name == "style") {
m_class.append("; ", attr.value);
} else {
m_attributes.emplace_back(name, value);
m_attributes.emplace_back(std::move(attr));
}
return *this;
@@ -64,24 +58,12 @@
attribute_list& attribute_list::set(const std::string& name,
attribute_list attribute_list::add(const attribute_list& list) const
{
attribute_list res = *this;
res.set(list);
return res;
}
attribute_list attribute_list::add(const std::string& name) const
{
attribute_list res = *this;
res.set(name);
return res;
return attribute_list(*this).set(list);
}
attribute_list attribute_list::add(const std::string& name,
const std::string& value) const
attribute_list attribute_list::add(attribute attr) const
{
attribute_list res = *this;
res.set(name, value);
return res;
return attribute_list(*this).set(std::move(attr));
}
} // namespace hemplate
diff --git a/ source/element.cpp b/ source/element.cpp
@@ -13,18 +13,6 @@
element& element::add(const element& elem)
return *this;
}
element& element::set(const std::string& name)
{
m_attributes.set(name);
return *this;
}
element& element::set(const std::string& name, const std::string& value)
{
m_attributes.set(name, value);
return *this;
}
void element::render_comment(std::ostream& out, std::size_t indent_value) const
{
const std::string indent(indent_value, ' ');
@@ -104,4 +92,26 @@
void element::render(std::ostream& out, std::size_t indent_value) const
}
}
element& element::set(const attribute_list& list)
{
m_attributes.set(list);
return *this;
}
element& element::set(attribute attr)
{
m_attributes.set(std::move(attr));
return *this;
}
element element::add(const attribute_list& list) const
{
return element(*this).set(list);
}
element element::add(attribute attr) const
{
return element(*this).set(std::move(attr));
}
} // namespace hemplate