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:
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;
}