SUPL ListItem
This was the first worked example of SUPL, based on the passing-key list item sequence. It included an interesting but confusing namespace experiment for productions -- the "P" and "Pmore" notation.
Key to SUPL:
.P is a grammar production, almost always of a previously declared non-terminal
.Pmore is a further dereference, for grouped non-terminals
.nt is a non-terminal
.t is a terminal
.Sequence : 'ListItem'
A trivial Google App Engine web application
enabling the user to create lists with items
(This automatically puts everything in a directory gen__)
--------------------------------------------------------------------------
.step 1 : 'form'
Starting morphology: overall shape
.P : 'start'
.nt : 'form main file'
.nt : 'form other files'
--------------------------------------------------------------------------
.step 2 : 'form: the GAE target morphology'
Starting Morphology (position)
POSITIONS / PRODUCTIONS / MORPHOLOGY
.P : 'form main file'
.file : 'ListItem.py'
.t : 'name'
<<<
# ListItem.py
>>>
.t : 'import'
<<<
import cgi
import os
from google.appengine.ext import db
from google.appengine.ext import webapp
from google.appengine.ext.webapp import template
from google.appengine.ext.webapp.util import run_wsgi_app
>>>
.nt : 'db'
.nt : 'pages'
.nt : 'handler map'
.t : 'main'
<<<
def main():
run_wsgi_app(application)
if __name__ == "__main__":
main()
>>>
.P : 'form other files'
.nt : 'homepage template'
.nt : 'launch file'
--------------------------------------------------------------------------
.step 3 : 'data and purpose'
There is a simple data model that reflects the purpose of the application
In our case, two types of data, one forming a List of the others. A List key is then required for the Item members.
PRINCIPLES
.template : 'db_model' : 'NAME'
<<<
class NAME(db.Model):
name = db.StringProperty(multiline=True)
>>>
.template : 'db_model_ref' : 'NAME', 'REF', 'KEY_LABEL'
<<<
class NAME(db.Model):
KEY_LABEL = db.ReferenceProperty(REF)
name = db.StringProperty(multiline=True)
>>>
(POSITIONS / PRODUCTIONS / MORPHOLOGY) + (PARAMETERS)
.P : 'db'
.t : db_model('List')
.t : db_model_ref ('Item', 'List', 'list_key')
--------------------------------------------------------------------------
.step 4 : 'Functional Centers and the First Bridge'
There are functional centers, which reflect the primary actions of the application, and the technology in which the application runs.
POSITIONS / PRODUCTIONS / MORPHOLOGY
.P : 'pages'
.nt : 'home page'
.nt : 'creating lists'
.nt : 'creating items'
--------------------------------------------------------------------------
.step 5 : 'A page and its renderer'
A page consists of handlers and a renderer
POSITIONS / PRODUCTIONS / MORPHOLOGY
.P : 'home page'
.nt : 'render'
.nt : 'handler'
--------------------------------------------------------------------------
.step 6 : 'Class and Method Morphology: Pages'
One page, the home page, in this case
.P : 'home page'
.Pmore : 'handler'
.t : 'code'
<<<
class HomePage(webapp.RequestHandler):
def get(self):
template_values = {
'list_form': 0,
'item_form': 0
}
self.response.out.write(render(template_values))
>>>
.P : 'home page'
.Pmore : 'render'
.nt : 'title'
.nt : 'parameters'
.nt : 'body'
--------------------------------------------------------------------------
.step 7 : 'Class and Method Morphology: Feature handlers'
Non-page handlers: for the web, has a GET handler, which sets up the feature and a POST handler, which does it.
.P : 'creating lists'
.nt : 'title'
.nt : 'parameters'
.nt : 'get handler'
.nt : 'post handler'
.P : 'creating items'
.nt : 'title'
.nt : 'parameters'
.nt : 'get handler'
.nt : 'post handler'
--------------------------------------------------------------------------
.step 8 : 'Titles: The Class and Method Bridge'
The functional centers are expressed in the form of methods and classes. Among these, the Handlers form a distinct group.
.template : 'class_title' : 'NAME'
<<<
class NAME
>>>
.template : 'method_title' : 'NAME'
<<<
def NAME
>>>
.P : 'home page'
.Pmore : 'render'
.Pmore : 'title'
.t : method_title ('render')
.P : 'home page'
.Pmore : 'handler'
.Pmore : 'title'
.t : class_title ('HomePage')
.P : 'creating lists'
.Pmore : 'title'
.t : class_title ('CreateList')
.P : 'creating items'
.Pmore : 'title'
.t : class_title ('CreateItem')
--------------------------------------------------------------------------
.step 9 : 'Parameters: for Render and Handler Shells'
The handler classes, the calls to render, have explicit arguments.
This is for all the 'parameter' non-teminals above.
.P : 'home page'
.Pmore : 'render'
.Pmore : 'parameters'
.t : 'for populating templates'
<<<
(template_values):
>>>
.P : 'home page'
.Pmore : 'handler'
.Pmore : 'parameters'
.t : 'handler class'
<<<
(webapp.RequestHandler):
>>>
.P : 'creating lists'
.Pmore : 'parameters'
.t : 'handler class'
<<<
(webapp.RequestHandler):
>>>
.P : 'creating items'
.Pmore : 'parameters'
.t : 'handler class'
<<<
(webapp.RequestHandler):
>>>
--------------------------------------------------------------------------
.step 10 : 'Shape of a handler map'
.P : 'handler map'
.t : 'app instantiation'
<<<
application = webapp.WSGIApplication([
>>>
.nt : 'URL handler list'
.t : 'debug flag'
<<<
],debug=True)
>>>
--------------------------------------------------------------------------
.step 11 : 'handler list'
.P : 'URL handler list'
.t : 'pages'
<<<
('/', HomePage),
>>>
.t : 'forms with keys'
<<<
('/item_form/(.*)/', CreateItem),
>>>
.t : 'forms without keys'
<<<
('/list_form/', CreateList),
>>>
.t : 'posts'
<<<
('/create_list/', CreateList),
('/create_item/', CreateItem)
>>>
--------------------------------------------------------------------------
.step 12 : 'template valve'
.P : 'render'
.Pmore : 'body'
.t : 'name and parameters'
<<<
def render (template_values):
>>>
.nt : 'template payload'
.t : 'get template file'
<<<
path = os.path.join(os.path.dirname(__file__), 'index.html')
>>>
.t : 'return popluated template'
<<<
return(template.render(path, template_values))
>>>
--------------------------------------------------------------------------
.step 13 : 'Form Get Methods'
.P : 'creating lists'
.Pmore : 'get handler'
.t : 'call with self'
<<<
def get (self):
>>>
.t : 'template dictionary'
<<<
template_values = {
'list_form': 1
}
>>>
.t : 'http response with render'
<<<
self.response.out.write (render(template_values))
>>>
.P : 'creating items'
.Pmore : 'get handler'
.t : 'call with self and key'
<<<
def get (self, list_key):
>>>
.t : 'template dictionary'
<<<
template_values = {
'item_form': 1,
'list_key': list_key
}
>>>
.t : 'http response with render'
<<<
self.response.out.write (render(template_values))
>>>
--------------------------------------------------------------------------
.step 14 : 'Template outline'
.P : 'homepage template'
.file : 'index.html'
.t : 'html top'
<<<
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Passing Keys</title>
<meta http-equiv="Content-Type" content="text/html;
charset=UTF-8" >
</head>
<body>
<a href="/"><font size="+3"><b>Passing Keys</b></font></a><br>
<br><br>
>>>
.nt: 'list form'
.t : 'list iteration'
<<<
{% for list in lists %}
<font size="+3"><b>{{ list.name }}</b></font><br>
{% for item in list.items %}
<b>*</b> {{ item.name }} <br>
{% endfor %}
>>>
.nt : 'item form'
.t : 'html tail'
<<<
{% endfor %}
</body>
</html>
>>>
--------------------------------------------------------------------------
.step 15 : 'List Form Pathway'
.P : 'homepage template'
.Pmore : 'list form'
.t : 'condition and html'
<<<
{% if list_form %}
<form action="/create_list/" method="post">
<textarea style="background:#eeee00" name="name" rows=1 cols=33></textarea><br>
<span align="left"><input type="Submit" name="button" value="Create list"></span>
<span style="padding-left:138px"><a href="/">cancel</a></span><br>
</form>
{% else %}
<br> <a href="/list_form/">Create a List</a><br><br>
{% endif %}
>>>
--------------------------------------------------------------------------
.step 16 : 'Item Form Pathway'
.P : 'homepage template'
.Pmore : 'item form'
.t : 'if form and this item'
<<<
{% if item_form %}
{% ifequal list.key list_key %}
<a name="form"></a>
<form action="/create_item/" method="post">
<span style="padding-left:15px">
<textarea style="background:#eeee00" name="name"
rows=1 cols=33></textarea><br>
</span>
<span style="padding-left:15px">
<input type="Submit" name="button" value="Create an item">
</span>
<span style="padding-left:130px">
<a href="/">cancel</a>
</span>
<br>
<input type="hidden" name="list_key"
value="{{ list_key }}">
</form>
{% else %}
<br>
<span style="padding-left:15px">
<a href="/item_form/{{ list.key }}/#form">
Create an item
</a>
</span>
<br><br>
{% endifequal %}
{% else %}
<br>
<span style="padding-left:15px">
<a href="/item_form/{{ list.key }}/#form">Create an item</a>
</span>
<br><br>
{% endif %}
>>>
--------------------------------------------------------------------------
.step 17 : 'Pathway posts'
.P : 'creating lists'
.Pmore: 'post handler'
.t : 'cl code'
<<<
def post(self):
list = List()
list.name = self.request.get('name')
list.put()
self.redirect("/")
>>>
.P : 'creating items'
.Pmore : 'post handler'
.t : 'ci code'
<<<
def post(self):
item = Item()
list_key = self.request.get('list_key')
item.list_key = List.get(list_key)
item.name = self.request.get('name')
item.put()
self.redirect("/")
>>>
--------------------------------------------------------------------------
.step 18 : 'Template Payload'
.P : 'template payload'
.t : 'code'
<<<
lists = db.GqlQuery("SELECT * FROM List")
new_lists = []
for list in lists:
items = db.GqlQuery("SELECT * FROM Item Where list_key = :1",
list.key())
new_list = {
'name': list.name,
'key': str(list.key()),
'items': items
}
new_lists.append(new_list)
template_values['lists'] = new_lists
>>>
--------------------------------------------------------------------------
.step 19 : 'Launch file'
.P : 'launch file'
.file : 'app.yaml'
.t : 'app.yaml'
<<<
application: listitem
version: 1
runtime: python
api_version: 1
handlers:
- url: /(.*).txt
static_files: \1.txt
upload: (.*).txt
- url: /.*
script: ListItem.py
>>>