from pyparsing import Word, OneOrMore, Group, Suppress, alphanums, oneOf, alphas, Optional, lineEnd
def convert_prop_to_dict(tokens):
prop_dict = {}
for token in tokens:
prop_dict[token[0]] = token[1]
return prop_dict
newline = Suppress(lineEnd)
colon = Suppress(":")
arrow = Suppress("->")
semicolon = Suppress(";")
word = Word(alphas)
key = word
value = Word(alphanums)
field_type = oneOf("CharField EmailField PasswordField")
field_name = word
form_name = word.setResultsName("form_name")
field_property = Group(key + colon + value)
field = Group(field_name + colon + field_type + Optional(arrow + OneOrMore(field_property) + semicolon).setParseAction(
convert_prop_to_dict))
form = form_name + newline + OneOrMore(field).setResultsName("form_field")
input_form = '''
UserForm
username:CharField -> label:Username size:25;
email:EmailField -> size:32;
password:PasswordField;
'''
'''
External DSL
'''
def get_field_html(field):
properties = field[2]
label = properties["label"] if "label" in properties else field[0]
label_html = "<label>" + label + "</label>"
attributes = {"name": field[0]}
attributes.update(properties)
if field[1] == "CharField" or field[1] == "EmailField":
attributes["type"] = "text"
else:
attributes["type"] = "password"
if "label" in attributes:
del attributes["label"]
attributes_html = " ".join([name + "='" + value + "'" for name, value in attributes.items()])
field_html = "<input " + attributes_html + "/>"
return label_html + field_html + "<br/>"
def render(form):
fields_html = "".join([get_field_html(field) for field in form.form_field])
return "<form id='" + form.form_name.lower() + "'>" + fields_html + "</form>"
print(render(form.parseString(input_form)))
'''
Internal DSL
'''
class HtmlElement(object):
default_attributes = {}
tag = "unknown_tag"
def __init__(self, *args, **kwargs):
self.attributes = kwargs
self.attributes.update(self.default_attributes)
self.children = args
def __str__(self):
attribute_html = " ".join(["{}='{}'".format(name, value)
for name, value in self.attributes.items()])
if not self.children:
return "<{} {}/>".format(self.tag, attribute_html)
else:
children_html = "".join([str(child) for child in self.children])
return "<{} {}>{}</{}>".format(self.tag, attribute_html, children_html, self.tag)
class InputElement(HtmlElement):
tag = "input"
def __init__(self, *args, **kwargs):
HtmlElement.__init__(self, *args, **kwargs)
self.label = self.attributes["label"] if "label" in self.attributes else self.attributes["name"]
if "label" in self.attributes:
del self.attributes["label"]
def __str__(self):
label_html = "<label>{}</label>".format(self.label)
return label_html + HtmlElement.__str__(self) + "<br/>"
class Form(HtmlElement):
tag = "form"
class CharField(InputElement):
default_attributes = {"type": "text"}
class EmailField(CharField):
pass
class PasswordField(InputElement):
default_attributes = {"type": "password"}
def render(form):
field_dict = {"CharField": CharField, "EmailField":
EmailField, "PasswordField": PasswordField}
fields = [field_dict[field[1]](name=field[0], **field[2]) for field in form.form_field]
return Form(*fields, id=form.form_name.lower())
print(render(form.parseString(input_form)))