|
|
@@ -0,0 +1,109 @@
|
|
|
+import _io
|
|
|
+
|
|
|
+class template_exception(Exception):
|
|
|
+ pass
|
|
|
+
|
|
|
+class template:
|
|
|
+ def __init__(self, content: str | _io.TextIOWrapper, check: bool = True):
|
|
|
+ self.__template = None
|
|
|
+ self.__rendered = None
|
|
|
+ self.__properties = dict()
|
|
|
+
|
|
|
+ if type(content) is str:
|
|
|
+ self.__template = content
|
|
|
+
|
|
|
+ if type(content) is _io.TextIOWrapper:
|
|
|
+ self.__template = content.read()
|
|
|
+
|
|
|
+ if self.__template is None:
|
|
|
+ raise Exception("Template content must be string or file.")
|
|
|
+
|
|
|
+ if check is True:
|
|
|
+ self.__prepare_template()
|
|
|
+
|
|
|
+ @property
|
|
|
+ def separators(self) -> [str, str]:
|
|
|
+ return "<<!", "!>>"
|
|
|
+
|
|
|
+ def __prepare_template(self) -> None:
|
|
|
+ template = self.template
|
|
|
+ start, end = self.separators
|
|
|
+
|
|
|
+ count = 0
|
|
|
+ current = 0
|
|
|
+
|
|
|
+ while True:
|
|
|
+ current_start = template.find(start, count)
|
|
|
+
|
|
|
+ if current_start == -1:
|
|
|
+ break
|
|
|
+
|
|
|
+ current = current_start + len(start)
|
|
|
+ current_end = template.find(end, count)
|
|
|
+ current_after = current_end + len(end)
|
|
|
+
|
|
|
+ if current > current_end:
|
|
|
+ found = "Close char before start char on " + str(current)
|
|
|
+ raise template_exception(found)
|
|
|
+
|
|
|
+ key = template[current:current_end]
|
|
|
+ key = key.strip()
|
|
|
+
|
|
|
+ if len(key) == 0:
|
|
|
+ raise template_exception("Empty key on " + str(current))
|
|
|
+
|
|
|
+ before = template[:current_start]
|
|
|
+ after = template[current_after:]
|
|
|
+
|
|
|
+ template = before + start + key + end + after
|
|
|
+ count = current + len(key) + len(end)
|
|
|
+
|
|
|
+ self.__template = template
|
|
|
+
|
|
|
+ @property
|
|
|
+ def template(self) -> str:
|
|
|
+ return self.__template
|
|
|
+
|
|
|
+ def get(self, name: str) -> str:
|
|
|
+ if not type(name) is str:
|
|
|
+ raise Exception("Name of the key must be str.")
|
|
|
+
|
|
|
+ if not name in self.__properties:
|
|
|
+ raise Exception("Key " + name + " not exists in properties.")
|
|
|
+
|
|
|
+ return self.__properties[name]
|
|
|
+
|
|
|
+ def set(self, name: str, value: str | int | float) -> template:
|
|
|
+ if not type(name) is str:
|
|
|
+ raise Exception("Name of the attribute must be str.")
|
|
|
+
|
|
|
+ if type(value) is str:
|
|
|
+ self.__properties[name] = value
|
|
|
+ return self
|
|
|
+
|
|
|
+ if type(value) is int or type(value) is float:
|
|
|
+ self.__properties[name] = str(value)
|
|
|
+ return self
|
|
|
+
|
|
|
+ raise Exception("Value to set must be str, int or float.")
|
|
|
+
|
|
|
+ def clone(self) -> template:
|
|
|
+ return template(self.template, False)
|
|
|
+
|
|
|
+ def __key(self, target: str) -> str:
|
|
|
+ start, end = self.separators
|
|
|
+
|
|
|
+ return start + target + end
|
|
|
+
|
|
|
+ def render(self) -> str:
|
|
|
+ if not self.__rendered is None:
|
|
|
+ return self.__rendered
|
|
|
+
|
|
|
+ template = self.template
|
|
|
+
|
|
|
+ for name, value in self.__properties.items():
|
|
|
+ template = template.replace(self.__key(name), value)
|
|
|
+
|
|
|
+ self.__rendered = template
|
|
|
+
|
|
|
+ return self.render()
|