hemplate

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

commit d25af86820fd01efb12416de44c93554d8a15321
parent 3236ff76f60e6d1df780edbbbe1a9904f70d6045
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date:   Sat, 22 Jun 2024 22:28:41 +0200

Add attributes and various constructors

* Working render for all different cases

Diffstat:
MCMakeLists.txt | 3++-
Ainclude/hemplate/attribute.hpp | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Minclude/hemplate/element.hpp | 25++++++++++++++++++++-----
Minclude/hemplate/elementAtomic.hpp | 15++++++++++-----
Minclude/hemplate/elementBoolean.hpp | 43+++++++++++++++++++++++++++++++++++--------
Asource/attribute.cpp | 41+++++++++++++++++++++++++++++++++++++++++
Msource/element.cpp | 45++++++++++++++++++++++++++++++++++++++-------
Mtest/source/hemplate_test.cpp | 13+++++++++++--
8 files changed, 227 insertions(+), 28 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt @@ -4,7 +4,7 @@ include(cmake/prelude.cmake) project( hemplate - VERSION 0.1.2 + VERSION 0.1.3 DESCRIPTION "Simple HTML template engine" HOMEPAGE_URL "https://git.dimitrijedobrota.com/hemplate.git" LANGUAGES CXX @@ -18,6 +18,7 @@ include(cmake/variables.cmake) add_library( hemplate_hemplate source/element.cpp + source/attribute.cpp ) add_library(hemplate::hemplate ALIAS hemplate_hemplate) diff --git a/include/hemplate/attribute.hpp b/include/hemplate/attribute.hpp @@ -0,0 +1,70 @@ +#pragma once + +#include <string> +#include <vector> + +#include "hemplate/hemplate_export.hpp" +#include "hemplate/streamable.hpp" + +namespace hemplate +{ + +class HEMPLATE_EXPORT attribute : public streamable +{ +public: + attribute() = default; + attribute(const attribute&) = default; + attribute(attribute&&) = default; + attribute& operator=(const attribute&) = default; + attribute& operator=(attribute&&) = default; + ~attribute() override = default; + + attribute(std::string name) // NOLINT + : m_name(std::move(name)) + { + } + + attribute(std::string name, std::string value) // NOLINT + : m_name(std::move(name)) + , m_value(std::move(value)) + { + } + + bool operator!=(const attribute& rhs) const; + bool operator==(const attribute& rhs) const; + + 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; } + + void render(std::ostream& out) const override; + +private: + std::string m_name; + std::string m_value; +}; + +class HEMPLATE_EXPORT attributeList : public streamable +{ +public: + attributeList() = default; + attributeList(const attributeList&) = default; + attributeList(attributeList&&) = default; + attributeList& operator=(const attributeList&) = default; + attributeList& operator=(attributeList&&) = default; + ~attributeList() override = default; + + attributeList& set(const std::string& name); + attributeList& set(const std::string& name, const std::string& value); + + bool empty() const { return m_attributes.empty(); } + + void render(std::ostream& out) const override; + +private: + std::vector<attribute> m_attributes; +}; + +} // namespace hemplate diff --git a/include/hemplate/element.hpp b/include/hemplate/element.hpp @@ -4,6 +4,7 @@ #include <string> #include <vector> +#include "hemplate/attribute.hpp" #include "hemplate/hemplate_export.hpp" #include "hemplate/streamable.hpp" @@ -44,8 +45,13 @@ public: Boolean, }; - explicit element(std::string data, Type type) - : m_data(std::move(data)) + explicit element(attributeList attributes, + elementList embedded, + std::string data, + Type type) + : m_attributes(std::move(attributes)) + , m_embeded(std::move(embedded)) + , m_data(std::move(data)) , m_type(type) { } @@ -59,23 +65,32 @@ public: Type get_type() const { return m_type; } std::string get_data() const { return m_data; } const elementList& get_embeded() const { return m_embeded; } + const attributeList& get_attributes() const { return m_attributes; } + + virtual bool get_state() const { return false; } + virtual const char* get_name() const = 0; void set_data(const std::string& data) { m_data = data; } void set_embedded(const elementList& embed) { m_embeded = embed; } + void set_attributes(const attributeList& attrs) { m_attributes = attrs; } + + virtual void tgl_state() const {} element& add(const element& elem); element& add(std::unique_ptr<element> elem); - virtual const char* get_name() const = 0; + element& set(const std::string& name); + element& set(const std::string& name, const std::string& value); + virtual std::unique_ptr<element> clone() const = 0; void render(std::ostream& out) const override; private: + attributeList m_attributes; + elementList m_embeded; std::string m_data; Type m_type; - - elementList m_embeded; }; } // namespace hemplate diff --git a/include/hemplate/elementAtomic.hpp b/include/hemplate/elementAtomic.hpp @@ -10,17 +10,22 @@ template<typename Tag> class HEMPLATE_EXPORT elementAtomic : public element { public: - elementAtomic() - : element("", Type::Atomic) - { - } - elementAtomic(const elementAtomic&) = default; elementAtomic(elementAtomic&&) noexcept = default; elementAtomic& operator=(const elementAtomic&) = default; elementAtomic& operator=(elementAtomic&&) noexcept = default; ~elementAtomic() override = default; + elementAtomic() + : element({}, {}, "", Type::Atomic) + { + } + + elementAtomic(attributeList attributes) // NOLINT + : element(std::move(attributes), {}, "", Type::Atomic) + { + } + const char* get_name() const override { return Tag::get_name(); } std::unique_ptr<element> clone() const override diff --git a/include/hemplate/elementBoolean.hpp b/include/hemplate/elementBoolean.hpp @@ -10,23 +10,46 @@ template<typename Tag> class HEMPLATE_EXPORT elementBoolean : public element { public: + elementBoolean(const elementBoolean&) = default; + elementBoolean(elementBoolean&&) noexcept = default; + elementBoolean& operator=(const elementBoolean&) = default; + elementBoolean& operator=(elementBoolean&&) noexcept = default; + ~elementBoolean() override = default; + elementBoolean() - : element("", Type::Boolean) + : element({}, {}, "", Type::Boolean) { } - elementBoolean(const std::string& text) // NOLINT - : element(text, Type::Boolean) + elementBoolean(std::string text) // NOLINT + : element({}, {}, std::move(text), Type::Boolean) { } - elementBoolean(const elementBoolean&) = default; - elementBoolean(elementBoolean&&) noexcept = default; - elementBoolean& operator=(const elementBoolean&) = default; - elementBoolean& operator=(elementBoolean&&) noexcept = default; - ~elementBoolean() override = default; + elementBoolean(attributeList attributes) // NOLINT + : element(std::move(attributes), {}, "", Type::Boolean) + { + } + + elementBoolean(elementList embedded) // NOLINT + : element({}, std::move(embedded), "", Type::Boolean) + { + } + + elementBoolean(std::string text, attributeList attributes) + : element(std::move(attributes), {}, std::move(text), Type::Boolean) + { + } + + elementBoolean(attributeList attributes, elementList embedded) + : element(std::move(attributes), std::move(embedded), "", Type::Boolean) + { + } const char* get_name() const override { return Tag::get_name(); } + bool get_state() const override { return m_state; } + + void tgl_state() const override { m_state = !m_state; } std::unique_ptr<element> clone() const override { @@ -34,6 +57,10 @@ public: } private: + static bool m_state; // NOLINT }; +template<typename Tag> +bool elementBoolean<Tag>::m_state = false; // NOLINT + } // namespace hemplate diff --git a/source/attribute.cpp b/source/attribute.cpp @@ -0,0 +1,41 @@ +#include "hemplate/attribute.hpp" + +namespace hemplate +{ + +bool attribute::operator!=(const attribute& rhs) const +{ + return !(*this == rhs); +} + +bool attribute::operator==(const attribute& rhs) const +{ + return m_name == rhs.m_name && m_value == rhs.m_value; +} + +void attribute::render(std::ostream& out) const +{ + out << get_name() << "=\"" << get_value() << "\""; +} + +attributeList& attributeList::set(const std::string& name) +{ + m_attributes.emplace_back(name); + return *this; +} + +attributeList& attributeList::set(const std::string& name, + const std::string& value) +{ + m_attributes.emplace_back(name, value); + return *this; +} + +void attributeList::render(std::ostream& out) const +{ + for (const auto& attr : m_attributes) { + out << attr << ' '; + } +} + +} // namespace hemplate diff --git a/source/element.cpp b/source/element.cpp @@ -15,24 +15,55 @@ element& element::add(std::unique_ptr<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(std::ostream& out) const { - if (get_type() == Type::Boolean && m_data.empty()) { - out << '<' << get_name() << '>'; + const auto open_tag = [this, &out](bool atomic) + { + out << '<' << get_name(); + if (!m_attributes.empty()) { + out << ' '; + m_attributes.render(out); + } + out << (atomic ? " />" : ">"); + }; - m_embeded.render(out); + const auto close_tag = [this, &out]() { out << "</" << get_name() << '>'; }; - out << "</" << get_name() << '>'; - } else { - out << '<' << get_name() << '>'; + if (m_type == Type::Atomic) { + open_tag(true); + return; + } + if (!m_data.empty()) { + open_tag(false); if (!m_embeded.empty()) { m_embeded.render(out); } else { out << m_data; } + close_tag(); + return; + } - out << "</" << get_name() << '>'; + if (m_embeded.empty()) { + tgl_state(); + get_state() ? open_tag(false) : close_tag(); + } else { + open_tag(false); + m_embeded.render(out); + close_tag(); } } diff --git a/test/source/hemplate_test.cpp b/test/source/hemplate_test.cpp @@ -4,10 +4,19 @@ int main() { - using namespace hemplate; // NOLINT + using namespace hemplate; // NOLINT - std::cout << ul("Won't see").add(li("Item 1")).add(li("Item 2")) << std::endl; + attributeList li_attrs; + li_attrs.set("class", "main_li"); + + std::cout << html() << std::endl; + std::cout << ul("Won't see") + .set("id", "main_ul") + .add(li("Item 1", li_attrs)) + .add(li("Item 2", li_attrs)) + << std::endl; std::cout << meta() << std::endl; + std::cout << html() << std::endl; return 0; }