-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathGroovyBuilder.cpp
More file actions
105 lines (95 loc) · 3.03 KB
/
GroovyBuilder.cpp
File metadata and controls
105 lines (95 loc) · 3.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
/**
* @cite Groovy-Style Builder allows user to create objects of a Domain-Specific Language interpretation in the form of nested object intitialization. It uses the c++ feature of uniform initiailization to achieve this.
* Known as Groovy-Style builder because the creation of DSL was groovy only thing before.
* Intialization looks like `A{ B{ }, C{ D{ "Hello" } } }`
*
* @brief Groovy Style Builders can be exemplified by creating a DSL for HTML.
*/
#include <string>
#include <vector>
#include <iostream>
#include <sstream>
/**
* @brief Imitates basic <tag></tag> in html. Can have children, attributes as well innerText.
*/
class HtmlTag
{
protected:
std::string tag_name, innerText;
std::vector<HtmlTag> children;
std::vector<std::pair<std::string, std::string>> attributes;
/**
* @brief Construct a new Html Tag object with the required tag_name.
* Constructor is protected so that only Derived classes can make the object.
*
* @param tag name of the tag.
* @param innerText OPTIONAL - `innerText` of the tag
* @param children OPTIONAL - `HtmlTag` children of the tag
* @param attrs OPTION - pairs of attributes of the tag.
*/
HtmlTag(std::string tag, std::string innerText = "", std::initializer_list<HtmlTag> children = {}, std::initializer_list<std::pair<std::string, std::string>> attrs = {}) : tag_name(tag), innerText(innerText), children(children), attributes(attrs) {}
public:
std::string str(int indent = 0)
{
std::ostringstream os;
std::string indent_str(indent, '\t');
os << indent_str << "<" + tag_name;
if (attributes.size() == 0 && children.size() == 0 && innerText == "")
{
os << "/>\n";
return os.str();
}
for (auto attr : attributes)
{
os << " " << attr.first << "=\"" << attr.second << "\"";
}
if (children.size() == 0 && innerText == "")
{
os << "/>\n";
return os.str();
}
else
os << ">\n";
os << std::string(indent+1, '\t') << innerText << "\n";
for (auto child : children)
{
os << child.str(indent + 1);
}
os << indent_str << "</" + tag_name + ">\n";
return os.str();
}
friend std::ostream &operator<<(std::ostream &os, HtmlTag &&tag)
{
os << tag.str();
return os;
}
};
/**
* @brief Imitate <p> tag. Can have children, attributes as well as innerText
*/
class P : public HtmlTag
{
public:
P() : HtmlTag("p") {}
P(std::string innerText, std::initializer_list<HtmlTag> children) : HtmlTag("p", innerText, children) {}
P(std::initializer_list<HtmlTag> children) : HtmlTag("p", "", children) {}
};
/**
* @brief imitiates <img> tag. Only contains attributes.
*/
class IMG : public HtmlTag
{
public:
IMG(std::string src) : HtmlTag("img", "", {}, {{"src", src}}) {}
};
int main()
{
// Groovy-style initialization i.e nested initialization
std::cout << P{"Pika Pika !!!",{
IMG{"http://pokemon.com/pikachu.png"},
P{
IMG{"http://pokemon.com/pikachu.png"},
}}}
<< std::endl;
return 0;
}