Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief
5 : *
6 : * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
7 : */
8 :
9 : #ifndef ELEKTRA_KDB_GEN_TEMPLATE_HPP
10 : #define ELEKTRA_KDB_GEN_TEMPLATE_HPP
11 :
12 : #include "mustache.hpp"
13 :
14 : #include <algorithm>
15 : #include <iostream>
16 : #include <memory>
17 : #include <unordered_map>
18 : #include <unordered_set>
19 :
20 : #include <kdb.hpp>
21 : #include <kdbmacros.h>
22 :
23 : class EmptyGenTemplate;
24 :
25 : /**
26 : * A template for the gen command.
27 : */
28 : class GenTemplate
29 : {
30 : protected:
31 : /**
32 : * Construct a new template for the gen command.
33 : *
34 : * A template may consist of multiple parts.
35 : * All mustache files for this template must start with @p templateBaseName,
36 : * and end with ".mustache". The part in between is determined by an entry in @p parts.
37 : *
38 : * @param templateBaseName The basename for all mustache files associated with this template.
39 : * @param parts The suffixes of the different parts associated with this template. Most of the time
40 : * a part corresponds to a mustache file. However, you may return false in
41 : * getTemplateData() for output files that do not have mustache templates and you can
42 : * override getParts() to remove parts. This argument should contain the full list of
43 : * possible parts.
44 : * Pass `{ "" }` if this template only uses a single file, identified by the @p templateBaseName.
45 : * @param parameters The list of parameters this template uses. The keys are the names, while the value
46 : * determines whether the parameter is required or not (true means required).
47 : */
48 : GenTemplate (std::string templateBaseName, std::vector<std::string> parts, std::vector<std::string> partials,
49 : const std::unordered_map<std::string, bool> & parameters);
50 :
51 : /**
52 : * Construct the mustache template data from the given snapshot of the KDB.
53 : *
54 : * @param outputName the basename of all output files. The output files are expected to use the same names
55 : * as the template files, except that `templateBaseName` is replaced by @p outputName.
56 : * @param part the part suffix for the current part
57 : * @param ks A KeySet containing the data for this template. All keys are below @p parentKey.
58 : * @param parentKey The parent key below which the data for this template resides.
59 : *
60 : * @return The mustache data needed to render this template.
61 : * If the returned data is false (i.e. kainjow::mustache::data::is_false() returns true), render() will
62 : * not invoke mustache rendering for this part. In this case you should write something to the output
63 : * file of this part before returning false.
64 : */
65 : virtual kainjow::mustache::data getTemplateData (const std::string & outputName, const std::string & part, const kdb::KeySet & ks,
66 : const std::string & parentKey) const = 0;
67 :
68 : /**
69 : * Get the value of a parameter.
70 : *
71 : * @param name The parameter name
72 : * @param defaultValue The default value
73 : *
74 : * @return the value of the parameter or @p defaultValue, if it wasn't set or is unknown
75 : */
76 : std::string getParameter (const std::string & name, const std::string & defaultValue = "") const;
77 :
78 : /**
79 : * Get the boolean value of a parameter.
80 : * The allowed values are 0 for false and 1 for true.
81 : *
82 : * @param name The parameter name
83 : * @param defaultValue The default value
84 : *
85 : * @return the value of the parameter or @p defaultValue, if it wasn't set or is unknown
86 : */
87 : bool getBoolParameter (const std::string & name, bool defaultValue = false) const;
88 :
89 : /**
90 : * Get the value of a parameter with limited allowed values.
91 : *
92 : * The value of the parameter will be searched in @p values. If found, the mapped value is returned,
93 : * otherwise a std::invalid_argument is thrown. If the parameter isn't set, or is unknown to the template,
94 : * this function looks for the empty string in @p values.
95 : *
96 : * @param name The parameter name
97 : * @param values The allowed values
98 : *
99 : * @return the mapped value of the parameter
100 : *
101 : * @throws std::invalid_argument
102 : */
103 : template <class T>
104 108 : T getParameter (const std::string & name, const std::unordered_map<std::string, T> & values) const
105 : {
106 : // has to be in header for template to work
107 540 : std::string param = getParameter (name);
108 108 : auto value = values.find (param);
109 216 : if (value == values.end ())
110 : {
111 0 : throw std::invalid_argument (param);
112 : }
113 216 : return value->second;
114 : }
115 :
116 : /**
117 : * The escape function used when instantiating the mustache templates. Override to customise.
118 : *
119 : * @param str an unescaped value
120 : *
121 : * @return the escaped version of @p str
122 : */
123 : virtual std::string escapeFunction (const std::string & str) const;
124 :
125 : /**
126 : * @return A list of parts of which this template consists.
127 : * By default this is the full list of parts given in the constructor. It may be overriden,
128 : * to dynamically remove parts based on the parameters for this template. Adding parts here
129 : * will not work, because render() only evaluates the parts given in the constructor.
130 : *
131 : * The returned list also dictates the order in which parts should be rendered.
132 : */
133 : virtual std::vector<std::string> getActualParts () const;
134 :
135 : public:
136 : /**
137 : * @retval true if this is the empty template
138 : * @retval false otherwise
139 : */
140 9 : virtual bool isEmpty () const
141 : {
142 9 : return false;
143 : }
144 :
145 : /**
146 : * Set the value of a parameter.
147 : *
148 : * @param name The parameter name
149 : * @param value The new parameter value
150 : */
151 : void setParameter (const std::string & name, const std::string & value);
152 :
153 : /**
154 : * Clears the parameters values set on this template.
155 : */
156 : void clearParameters ();
157 :
158 : /**
159 : * Loads the list of actual parts, based on the current parameters.
160 : * Must be called before rendering, if parameters have been set.
161 : */
162 : void loadParts ();
163 :
164 : /**
165 : * @return A list of parts of which this template consists.
166 : * The returned list dictates the order in which parts should be rendered.
167 : */
168 : const std::vector<std::string> & getParts () const;
169 :
170 : /**
171 : * Render a part of this template using the given snapshot of the KDB into the given stream.
172 : *
173 : * @param output The stream to which the render result shall be written.
174 : * @param outputName the basename of all output files. The output files are expected to use the same names
175 : * as the template files, except that `templateBaseName` is replaced by @p outputName.
176 : * @param part The name of the part to be rendered.
177 : * No output will be generated, if this isn't an element of getParts().
178 : * @param ks A KeySet containing the data for this template. Probably resulting from a call to KDB#get.
179 : * @param parentKey The parent key below which the data for this template resides.
180 : */
181 : void render (std::ostream & output, const std::string & outputName, const std::string & part, const kdb::KeySet & ks,
182 : const std::string & parentKey) const;
183 :
184 36 : virtual ~GenTemplate () = default;
185 :
186 : private:
187 : std::string _templateBaseName;
188 : std::vector<std::string> _allParts;
189 : std::vector<std::string> _parts;
190 : std::vector<std::string> _partials;
191 : std::unordered_map<std::string, std::string> _parameters;
192 : std::unordered_set<std::string> _requiredParameters;
193 :
194 : std::unordered_map<std::string, kainjow::mustache::partial> getPartials () const;
195 : };
196 :
197 : /**
198 : * Singleton class containing the list of known templates for the gen command.
199 : */
200 18 : class GenTemplateList
201 : {
202 : public:
203 : /**
204 : * @return the singleton instance of GenTemplateList
205 : */
206 9 : static GenTemplateList & getInstance ()
207 : {
208 9 : static GenTemplateList instance; // Guaranteed to be destroyed. Instantiated on first use.
209 9 : return instance;
210 : }
211 :
212 : /**
213 : * Find a template with a given name.
214 : *
215 : * @param name the unique name of the template
216 : * @param parameters the map of parameters passed to the template
217 : *
218 : * @return a pointer to the template with the given name initialized with the given parameters
219 : * or GenTemplate::empty, if the template wasn't found
220 : */
221 : const GenTemplate * getTemplate (const std::string & name, const std::unordered_map<std::string, std::string> & parameters) const;
222 :
223 : private:
224 : GenTemplateList ();
225 :
226 : template <class genClass>
227 : void addTemplate (const std::string & name);
228 : std::unordered_map<std::string, std::unique_ptr<GenTemplate>> _templates;
229 :
230 : public:
231 : // public for better error messages
232 : GenTemplateList (GenTemplateList const &) = delete;
233 : void operator= (GenTemplateList const &) = delete;
234 : };
235 :
236 0 : class EmptyGenTemplate : public GenTemplate
237 : {
238 : public:
239 : /**
240 : * @return the singleton instance of EmptyGenTemplate
241 : */
242 0 : static EmptyGenTemplate & getInstance ()
243 : {
244 0 : static EmptyGenTemplate instance; // Guaranteed to be destroyed. Instantiated on first use.
245 0 : return instance;
246 : }
247 :
248 0 : bool isEmpty () const override
249 : {
250 0 : return true;
251 : }
252 :
253 0 : kainjow::mustache::data getTemplateData (const std::string & outputName ELEKTRA_UNUSED, const std::string & part ELEKTRA_UNUSED,
254 : const kdb::KeySet & ks ELEKTRA_UNUSED,
255 : const std::string & parentKey ELEKTRA_UNUSED) const override
256 : {
257 0 : return {};
258 : }
259 :
260 : private:
261 0 : EmptyGenTemplate ()
262 0 : : GenTemplate ("", std::vector<std::string> (), std::vector<std::string> (), std::unordered_map<std::string, bool> ())
263 : {
264 0 : }
265 :
266 : public:
267 : // public for better error messages
268 : EmptyGenTemplate (EmptyGenTemplate const &) = delete;
269 : void operator= (EmptyGenTemplate const &) = delete;
270 : };
271 :
272 : #endif // ELEKTRA_KDB_GEN_TEMPLATE_HPP
|