SUPL

The Smoothly Unfolding Project Language
by

How does one create an example program in a new language, or an example sequence on a new platform, or a sequence intended to demonstrate best practices, of the smoothest unfolding of a solution to a particular problem? Is there sufficient tooling for "working over" that "unfolding example", rewriting it, over and over again, until it is smooth?

SUPL was an early attempt to do this. I created a working version in 2009, but it inspired me to do something quite different (www.grogix.org) so this work remained unpublished.

SUPL lets you create a documented, unfolding description, of any type, and compile, run and edit all the steps, continually, while improving the sequence. It ensures the development of differentiating, structure-preserving code from step-to-step.

As an example of a Grogix description, here's ListItem.supl, which produces the working Google App Engine webapp described in detail here.

The goals for SUPL 2.0 include a web-based IDE which enables the editing, smoothing and running of a sequence online, in the sort of format clear below.



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 %}
      &nbsp;&nbsp;&nbsp;<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>&nbsp;<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
>>>