Created
September 16, 2011 06:33
-
-
Save siddhi/1221363 to your computer and use it in GitHub Desktop.
Revisions
-
Siddharta Govindaraj created this gist
Sep 16, 2011 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,118 @@ from pyparsing import * # By default, PyParsing treats \n as whitespace and ignores it # In our grammer, \n is significant, so tell PyParsing not to ignore it ParserElement.setDefaultWhitespaceChars(" \t") def parse(input_string): def convert_prop_to_dict(tokens): """Convert a list of field property tokens to a dict""" prop_dict = {} for token in tokens: prop_dict[token.property_key] = token.property_value return prop_dict # The form DSL grammar expressed in PyParsing notation # PyParsing has a brilliant DSL syntax word = Word(alphas) newline = Suppress("\n") colon = Suppress(":") arrow = Suppress("->") key = word.setResultsName("property_key") value = Word(alphanums).setResultsName("property_value") field_property = Group(key + colon + value).setResultsName("field_property") field_type = oneOf("CharField EmailField PasswordField").setResultsName("field_type") field_name = word.setResultsName("field_name") field = Group(field_name + colon + field_type + Optional(arrow + OneOrMore(field_property)).setParseAction(convert_prop_to_dict) + newline).setResultsName("form_field") form_name = word.setResultsName("form_name") form = form_name + newline + OneOrMore(field).setResultsName("fields") return form.parseString(input_string) # Code to create an Internal DSL to make outputting HTML easy class HtmlElement(object): """The base element used by all the other classes""" default_attributes = {} # If the element has any default attributes tag = "unknown_tag" # Name of the tag def __init__(self, *args, **kwargs): """Children are passed in as args, attributes as kwargs""" self.attributes = kwargs self.attributes.update(self.default_attributes) self.children = args def __str__(self): """Render the tag contents as HTML""" # Convert the attributes into HTML representation attribute_html = " ".join(["{}='{}'".format(name, value) for name,value in self.attributes.items()]) if not self.children: # If there are no children, render in empty tag format return "<{} {}/>".format(self.tag, attribute_html) else: # Otherwise render an open tag, followed by the children, followed by close tag children_html = "".join([str(child) for child in self.children]) return "<{} {}>{}</{}>".format(self.tag, attribute_html, children_html, self.tag) class Form(HtmlElement): """Form tag""" tag = "form" class Input(HtmlElement): """Input tag""" tag = "input" def __init__(self, *args, **kwargs): """The name parameter is compulary for input tags""" HtmlElement.__init__(self, *args, **kwargs) # If there is a label attribute, then store that and delete it # Otherwise use the name attribute for the label 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): """The string representation also renders the label tag""" label_html = "<label>{}</label>".format(self.label) return label_html + HtmlElement.__str__(self) + "<br/>" class CharField(Input): """Char field""" default_attributes = {"type":"text"} class EmailField(CharField): """Email field (same as CharField for now)""" pass class PasswordField(Input): """Password field, set type='password' for this field""" default_attributes = {"type":"password"} def render(form): """Render the parsed form into HTML""" # Map the field name string to a field class field_dict = {"CharField": CharField, "EmailField": EmailField, "PasswordField": PasswordField} # Create the field classes fields = [field_dict[field.field_type](name=field.field_name, **field[2]) for field in form.fields] # Create the form return Form(*fields, id=form.form_name.lower()) input_form = """UserForm name:CharField -> label:Username size:25 email:EmailField -> size:32 password:PasswordField """ print render(parse(input_form))