Commits

Brantley Harris committed bd8f8ba

Rearranged the make system.

  • Participants
  • Parent commits 38f576e

Comments (0)

Files changed (13)

builder/__init__.py

-import os, re
-from cStringIO import StringIO
-from jsmin import JavascriptMinify
-
-re_comment = re.compile(r'\/\*\*(.*?)\*\*\/', re.M | re.S)
-re_requires = re.compile(r'Requires:(.*)', re.M | re.S)
-re_test_name = re.compile(r'new Tea.Testing.Suite\({\s*name: (".*?"|\'.*?\')', re.M | re.S)
-re_require = re.compile(r'Tea.require\(.*?\);?', re.M | re.S)
-
-def get_requirements(comment):
-    m = re_requires.search(comment)
-    gather = set()
-    if (m):
-        reqs = m.group(1)
-        reqs = reqs.split('\n')
-        if (reqs[0].strip() == ''): del reqs[0]
-        for r in reqs:
-            r = r.strip()
-            if (r):
-                gather.add(r)
-            else:
-                break
-    return gather
-
-def get_name(comment):
-    name = comment.split('\n', 1)[0].strip()
-    return name.split('(', 1)[0].strip()
-
-def depth_sort(module, all, seen):
-    if id(module) in seen: return []
-    gather = []
-    
-    for n in module['reqs']:
-        gather.extend(depth_sort(n, all, seen))
-    
-    gather.append(module)
-    seen.add( id(module) )
-    return gather
-
-def sort_modules(required, modules):
-    gather = []
-    seen = set()
-    for k in required:
-        gather.extend(depth_sort(modules[k], modules, seen))
-    
-    return gather
-    
-def gather_modules(required):
-    required = set(['Tea'] + required)
-    
-    modules = {}
-    for file in os.listdir('src'):
-        path = os.path.join('src', file)
-        o = open(path)
-        
-        m = re_comment.search(o.read())
-        if (m):
-            comment = m.group(1).strip()
-            name = get_name(comment)
-            requirements = get_requirements(comment)
-            if (name != 'Tea'):
-                requirements.add('Tea')
-            modules[name] = {'name': name,
-                             'reqs': requirements,
-                             'path': path}
-        
-        o.close()
-    
-    for k, v in modules.items():
-        v['reqs'] = [modules[n] for n in v['reqs']]
-    
-    return sort_modules(required, modules)
-
-def build(required=[], minified = False, path = 'build/tea.js', tests = False):
-    modules = gather_modules(required)
-    buffer = StringIO()
-    
-    print "Building Tea:"
-    for module in modules:
-        print ' ', module['name'], '->', module['path']
-        o = open(module['path'])
-        buffer.write( o.read() + '\n\n' )
-        o.close()
-    
-    buffer.seek(0)
-    jsm = JavascriptMinify()
-    
-    dir = os.path.dirname(path)
-    if (dir):
-        try:
-            os.makedirs(dir)
-        except OSError:         # It's already made.
-            pass
-    
-    if (minified):
-        jsm.minify( buffer, open(path, 'w') )
-    else:
-        open(path, 'w').write(buffer.getvalue())
-    
-    print "\nTea built:", path
-    
-    if (tests):
-        build_tests(modules, path=os.path.join(os.path.dirname(path), 'tea.tests.js'))
-    
-def build_tests(modules, path='build/tea.tests.js'):
-    print "\nBuilding tests..."
-    
-    test_files = {}
-    for file in os.listdir('tests'):
-        file = os.path.join('tests', file)
-        o = open(file)
-        
-        src = o.read()
-        m = re_test_name.search(src)
-        if (m):
-            name = m.group(1).replace('"', '').replace("'", '')
-        else:
-            continue
-        src = re_require.sub('', src, 1)
-        test_files[name] = {'name': name, 'src': src, 'path': file}
-    
-    o = open(path, 'w')
-    for module in modules:
-        name = module['name']
-        if (name in test_files):
-            test = test_files[name]
-            print ' ', name, "->", test['path']
-            o.write( test['src'] + '\n\n' )
-        else:
-            print ' ', name, 'is NOT tested.'
-    o.close()
-    
-    o = open(os.path.join(os.path.dirname(path), 'tests.html'), 'w')
-    o.write(open(os.path.join('builder', 'tests.template.html')).read())
-    o.close()
-    
-    print '\nTests built:', path
+from base import *
+import os, re
+from cStringIO import StringIO
+from jsmin import JavascriptMinify
+
+re_comment = re.compile(r'\/\*\*(.*?)\*\*\/', re.M | re.S)
+re_requires = re.compile(r'Requires:(.*)', re.M | re.S)
+re_test_name = re.compile(r'new Tea.Testing.Suite\({\s*name: (".*?"|\'.*?\')', re.M | re.S)
+re_require = re.compile(r'Tea.require\(.*?\);?', re.M | re.S)
+
+def get_requirements(comment):
+    m = re_requires.search(comment)
+    gather = set()
+    if (m):
+        reqs = m.group(1)
+        reqs = reqs.split('\n')
+        if (reqs[0].strip() == ''): del reqs[0]
+        for r in reqs:
+            r = r.strip()
+            if (r):
+                gather.add(r)
+            else:
+                break
+    return gather
+
+def get_name(comment):
+    name = comment.split('\n', 1)[0].strip()
+    return name.split('(', 1)[0].strip()
+
+def depth_sort(module, all, seen):
+    if id(module) in seen: return []
+    gather = []
+    
+    for n in module['reqs']:
+        gather.extend(depth_sort(n, all, seen))
+    
+    gather.append(module)
+    seen.add( id(module) )
+    return gather
+
+def sort_modules(required, modules):
+    gather = []
+    seen = set()
+    for k in required:
+        gather.extend(depth_sort(modules[k], modules, seen))
+    
+    return gather
+    
+def gather_modules(required):
+    required = set(['Tea'] + required)
+    
+    modules = {}
+    for file in os.listdir('src'):
+        path = os.path.join('src', file)
+        o = open(path)
+        
+        m = re_comment.search(o.read())
+        if (m):
+            comment = m.group(1).strip()
+            name = get_name(comment)
+            requirements = get_requirements(comment)
+            if (name != 'Tea'):
+                requirements.add('Tea')
+            modules[name] = {'name': name,
+                             'reqs': requirements,
+                             'path': path}
+        
+        o.close()
+    
+    for k, v in modules.items():
+        v['reqs'] = [modules[n] for n in v['reqs']]
+    
+    return sort_modules(required, modules)
+
+def get_template(name):
+    return open(os.path.join(os.path.dirname(__file__), 'templates', name)).read()
+
+def build(required=[], path = 'build', minified = False, tests = True, docs = True):
+    modules = gather_modules(required)
+    buffer = StringIO()
+    full_path = os.path.join(path, 'tea.js')
+    
+    print "Building Tea:", full_path
+    
+    for module in modules:
+        print ' ', module['name'], '-', module['path']
+        o = open(module['path'])
+        buffer.write( o.read() + '\n\n' )
+        o.close()
+    
+    buffer.seek(0)
+    jsm = JavascriptMinify()
+    
+    if (path):
+        try:
+            os.makedirs(path)
+        except OSError:         # It's already made.
+            pass
+    
+    if (minified):
+        jsm.minify( buffer, open(full_path, 'w') )
+    else:
+        open(path, 'w').write(buffer.getvalue())
+    
+    
+    if (minified):
+        jsm.minify( open('jquery.js'), open(os.path.join(path, 'jquery.js'), 'w'))
+    else:
+        o = open(os.path.join(path, 'jquery.js'), 'w')
+        o.write( open('jquery.js').read() )
+        o.close()
+    
+    print ""
+    
+    if (tests):
+        build_tests(modules, path=path)
+        
+    if (docs):
+        build_docs(modules, path=path)
+    
+def build_tests(modules, path='build'):
+    full_path = os.path.join(path, 'tea.tests.js')
+    
+    print "Building tests:", full_path
+    
+    test_files = {}
+    for file in os.listdir('tests'):
+        file = os.path.join('tests', file)
+        o = open(file)
+        
+        src = o.read()
+        m = re_test_name.search(src)
+        if (m):
+            name = m.group(1).replace('"', '').replace("'", '')
+        else:
+            continue
+        src = re_require.sub('', src, 1)
+        test_files[name] = {'name': name, 'src': src, 'path': file}
+    
+    o = open(full_path, 'w')
+    for module in modules:
+        name = module['name']
+        if (name in test_files):
+            test = test_files[name]
+            # print ' ', name, "-", test['path']
+            o.write( test['src'] + '\n\n' )
+        else:
+            print ' ', name, 'is NOT tested.'
+    o.close()
+    
+    o = open(os.path.join(path, 'tests.html'), 'w')
+    o.write( get_template('tests.html') )
+    o.close()
+    
+    print ''
+
+import docs
+
+def build_docs(modules, path='build/docs.json'):
+    full_path = os.path.join(path, 'tea.docs.js')
+    src_path = os.path.join(os.path.dirname(__file__), '..', 'src')
+    
+    print "Building docs:", full_path
+    
+    roots = docs.scan(src_path)
+    
+    try:
+        import simplejson
+    except ImportError:
+        print "Unable to import simplejson, 'easy_install simplejson' to build the docs."
+        return
+        
+    simple = [r.simple() for r in roots]
+    simplejson.dump(simple, open(full_path, 'w'))
+    
+    o = open(os.path.join(path, 'docs.html'), 'w')
+    o.write( get_template('docs.html') )
+    o.close()
+    
+    print ''
+#!/usr/bin/env python
+
+import os
+import re
+
+re.comments = re.compile(r'\/\*\*(.*?)\*\*\/', re.M | re.S)
+
+class Section(object):
+    def __init__(self, name=None, description=None, args=None, important=False):
+        self.path = name.split('.')
+        self.name = self.path[-1]
+        self.description = description.strip()
+        self.children = {}
+        self.args = args
+        self.built = False
+        self.important = important
+    
+    def add(self, who):
+        self.children[who.name] = who
+    
+    @property
+    def sorted_children(self):
+        keys = self.children.keys()
+        keys.sort()
+        return [self.children[k] for k in keys]
+    
+    @property
+    def name_with_args(self):
+        return self.name + (self.args or '')
+    
+    def format(self, tabs=0):
+        spaces = tabs * '  '
+        children = "".join(child.format(tabs + 1) for child in self.sorted_children)
+        dashes = (3 - tabs) * '=' or '-'
+        return "%s%s %s %s\n%s%s\n\n%s" % (spaces, dashes, self.name_with_args, dashes, spaces, self.description.replace('\n', '\n' + spaces), children)
+        
+    __str__ = format
+    
+    def __repr__(self):
+        return "<Section: %s>" % self.name
+        
+    def simple(self, mode='html'):
+        return {
+            'path': self.path,
+            'name': self.name,
+            'args': self.args,
+            'description': self.description.replace('\n', '<br/>').replace('  ', ' &nbsp;'),
+            'children': [c.simple(mode) for c in self.sorted_children],
+            'important': self.important
+        }
+ 
+class Scanner(object):
+    def __init__(self):
+        self.parts = {}
+        
+    def parse_comment(self, src):
+        src = src.strip()
+        name, description = src.split('\n', 1)
+        
+        ## Get rid of spaces at the beginning of each line.
+        count = 0
+        while (description[count].isspace()):
+            if (description[count] == '\n'):
+                description = description[count+1:]
+                count = 0
+                continue
+            count += 1
+        description = description.replace('\n' + ' ' * count, '\n')
+        
+        important = False
+        if name.endswith('!important'):
+            name = name[:-len('!important')]
+            important = True
+        
+        args = None
+        ## Split up the name into name and args
+        if '(' in name:
+            name, args = name.split('(', 1)
+            args = '(' + args
+        
+        name = name.strip()
+        
+        self.parts[name] = Section(name=name, description=description, args=args, important=important)
+    
+    def build(self, sig):
+        section = self.parts[sig]
+        if section.built: return
+        
+        if len(section.path) == 1:
+            self.roots.append(section)
+        else:
+            parent_sig = ".".join(section.path[:-1])
+            self.parts[parent_sig].add(section)
+            
+        section.built = True
+    
+    def compile(self):
+        self.roots = []
+        keys = self.parts.keys()
+        keys.sort()
+        for sig in keys:
+            self.build(sig)
+        self.roots.sort(lambda a, b: cmp(a.name, b.name))
+        return self.roots
+    
+    def scan(self, path):
+        if os.path.isdir(path):
+            for l in os.listdir(path):
+                if l.endswith('.js') or os.path.isdir(l): 
+                    self.scan(os.path.join(path, l))
+        else:
+            for i in re.comments.findall(open(path).read()):
+                self.parse_comment(i)
+ 
+def scan(path):
+    scanner = Scanner()
+    scanner.scan(path)
+    return scanner.compile()

builder/templates/docs.html

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+	<title>
+        Green Tea - API Reference
+    </title>
+	
+	<style type='text/css'>
+        * {
+        	margin: 0;
+        	padding: 0;
+        }
+
+        body {
+        	margin: 0;
+        	padding: 0;
+        	font-family: Verdana, Arial, Helvetica, sans-serif;
+        	font-size: 12px;
+        	color: #444;
+        	background-color: #f6f6f6;
+        	text-align: center;
+        	line-height: 1.4;
+        }
+
+        pre {
+        	font-size: 1.2em;
+        	padding-left: 2em;
+        	padding-top: 1em;
+        	background-color: #F8F8F1;
+        }
+	
+        code {
+        	font-size: 1.2em;
+        	color: #006600;
+        }
+
+        img { border: 0; }
+	
+        h1, h2, h3, h4, h5, h6 { color: #888;  font-weight: bold; margin-bottom: 0px; padding-bottom: 0px ; margin-top: 0px;}
+        h1 { font-size: 2.5em; color: #8A8; letter-spacing: -2px; }
+        h2 { font-size: 1.2em }
+        h3 { font-size: 1.1em }
+        h4, h5, h6 { font-size: 1.0em }
+
+        p, ul, ol {
+        	margin-top: 1em;
+        }
+
+        h1 + p, h2 + p, h3 + p {
+        	margin-top: 0;
+        }
+
+        p + ul {
+        	margin-top: 0;
+        }
+
+        select { padding: 0px; margin: 0px }
+        select option { padding: 0px 4px }
+
+        .byline { margin-top: -6px; margin-left: 1px;}
+
+        /** Elements **/
+        #wrapper { margin-left: auto; 
+                   margin-right: auto;
+                   text-align: left; 
+                   width: 1000px;
+                   background-color: #fff; 
+                   position: relative; 
+                   padding-bottom: 4em; }
+
+        #top {
+            margin: 0px 6px; 
+            padding: 0px 12px 10px 12px; 
+            border-bottom: 1px solid #DDD;
+        }
+
+        #content { 
+            margin: 1em 18px; 
+            position: relative;
+            left: 300px;
+            width: 600px;
+        }
+
+        /** Specific **/
+        blockquote { 
+            margin-left: 1em;
+        }
+
+        .section {
+            margin-top: 1em;
+        }
+
+        .args {
+            margin-left: 4px;
+            color: #888;
+        }
+
+        .name + p {
+            margin-top: 0px;
+        }
+	</style>
+    
+	<script type='text/javascript' src='jquery.js'></script>
+	<script type='text/javascript' src='tea.js'></script>
+	<script type='text/javascript'>
+	    App = Tea.Application.subclass('App', {
+            init : function()
+            {
+                Tea.ajax({
+                    url: 'tea.docs.js',
+                    success: function(d) { this.setApi(d) }, 
+                    scope: this
+                });
+            },
+    
+            divSection : function(section)
+            {   
+                var div = $('<div class="section">');
+                var name = $('<div class="name">').append( $('<b>').append(section.name) ).appendTo(div);
+                var description = $('<p>').append(section.description).appendTo(div);
+                var children = $('<blockquote class="children">').appendTo(div);
+        
+                if (section.args)
+                    name.append($('<span class="args">').append(section.args));
+
+                // Then first
+                for(var i = 0; i < section.children.length; i++)
+                {
+                    if (section.children[i].name == 'options')
+                        this.divSection(section.children[i]).appendTo(children);
+                }
+
+                // Then !important
+                for(var i = 0; i < section.children.length; i++)
+                {
+                    if (section.children[i].important && section.children[i].name != 'options')
+                        this.divSection(section.children[i]).appendTo(children);
+                }
+
+                // Then the rest
+                for(var i = 0; i < section.children.length; i++)
+                {
+                    if (!section.children[i].important && section.children[i].name != 'options')
+                        this.divSection(section.children[i]).appendTo(children);
+                }
+        
+                return div;
+            },
+    
+            setApi : function(roots)
+            {
+                for(var i = 0; i < roots.length; i++)
+                {
+                    var section = roots[i];
+                    this.divSection(section).appendTo('#content');
+                }
+            }
+        })
+
+        $(function()
+        {
+            App.setup();
+        })
+	</script>
+</head>
+
+<body>
+	<div id='wrapper'>
+		<div id='top'>
+			<h1>Green Tea</h1>
+			<h3 class='byline'>API Reference</h3>
+		</div>
+    	<div id='content'>
+			
+	    </div>
+	</div>
+	<div>
+	</div>
+</body>
+</html>
+

builder/templates/tests.html

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+	<title>
+        Green Tea - Built Unit Testing
+    </title>
+	
+	<style>
+	    * {
+        	margin: 0;
+        	padding: 0;
+        }
+
+        body {
+        	margin: 0;
+        	padding: 0;
+        	font-family: Verdana, Arial, Helvetica, sans-serif;
+        	font-size: 12px;
+        	color: #444;
+        	background-color: #f6f6f6;
+        	text-align: center;
+        	line-height: 1.4;
+        }
+
+        pre {
+        	font-size: 1.2em;
+        	padding-left: 2em;
+        	padding-top: 1em;
+        	background-color: #F8F8F1;
+        }
+
+        code {
+        	font-size: 1.2em;
+        	color: #006600;
+        }
+
+        img { border: 0; }
+
+        h1, h2, h3, h4, h5, h6 { color: #888;  font-weight: bold; margin-bottom: 0px; padding-bottom: 0px ; margin-top: 0px;}
+        h1 { font-size: 2.5em; color: #8A8; letter-spacing: -2px; }
+        h2 { font-size: 1.2em }
+        h3 { font-size: 1.1em }
+        h4, h5, h6 { font-size: 1.0em }
+
+        p, ul, ol {
+        	margin-top: 1em;
+        }
+
+        h1 + p, h2 + p, h3 + p {
+        	margin-top: 0;
+        }
+
+        p + ul {
+        	margin-top: 0;
+        }
+
+        select { padding: 0px; margin: 0px }
+        select option { padding: 0px 4px }
+
+        .byline { margin-top: -6px; margin-left: 1px;}
+
+        /** Elements **/
+        #wrapper { margin-left: auto; 
+                   margin-right: auto;
+                   text-align: left; 
+                   width: 1000px;
+                   background-color: #fff; 
+                   position: relative; }
+        html, body, #wrapper { height: 100%; }
+
+        #top {
+            margin: 0px 6px; 
+            padding: 0px 12px 10px 12px; 
+            border-bottom: 1px solid #DDD;
+        }
+        #content { margin: 1em 18px; }
+    </style>
+    
+	<script type='text/javascript' src='../jquery.js'></script>
+	<script type='text/javascript' src='tea.js'></script>
+	<script type='text/javascript' src='tea.tests.js'></script>
+	
+	<script type='text/javascript'>
+	    $(function()
+        {
+            var results = Tea.Testing.run();
+
+            if (results.count > results.passed)
+            {
+                // This color (#FF0000) offends me, and is my punishment for failing tests.
+                // Just looked at it-- god it's awful.  Hopefully I won't skip writing tests to avoid it.
+                $('.byline').append(" - <span style='color: #FF0000'>Fail</span>"); 
+            }
+            else
+            {
+                $('.byline').append(" - <span style='color: #88AA88'>Pass</span>");
+            }
+        })
+	</script>
+</head>
+
+<body>
+	<div id='wrapper'>
+		<div id='top'>
+			<h1>Green Tea</h1>
+			<h3 class='byline'>Built Unit Tests</h3>
+		</div>
+    	<div id='content'>
+			
+	    </div>
+	</div>
+</body>
+</html>
+

builder/tests.template.html

-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-	<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
-	<title>
-        Green Tea - Built Unit Testing
-    </title>
-	
-	<style>
-	    * {
-        	margin: 0;
-        	padding: 0;
-        }
-
-        body {
-        	margin: 0;
-        	padding: 0;
-        	font-family: Verdana, Arial, Helvetica, sans-serif;
-        	font-size: 12px;
-        	color: #444;
-        	background-color: #f6f6f6;
-        	text-align: center;
-        	line-height: 1.4;
-        }
-
-        pre {
-        	font-size: 1.2em;
-        	padding-left: 2em;
-        	padding-top: 1em;
-        	background-color: #F8F8F1;
-        }
-
-        code {
-        	font-size: 1.2em;
-        	color: #006600;
-        }
-
-        img { border: 0; }
-
-        h1, h2, h3, h4, h5, h6 { color: #888;  font-weight: bold; margin-bottom: 0px; padding-bottom: 0px ; margin-top: 0px;}
-        h1 { font-size: 2.5em; color: #8A8; letter-spacing: -2px; }
-        h2 { font-size: 1.2em }
-        h3 { font-size: 1.1em }
-        h4, h5, h6 { font-size: 1.0em }
-
-        p, ul, ol {
-        	margin-top: 1em;
-        }
-
-        h1 + p, h2 + p, h3 + p {
-        	margin-top: 0;
-        }
-
-        p + ul {
-        	margin-top: 0;
-        }
-
-        select { padding: 0px; margin: 0px }
-        select option { padding: 0px 4px }
-
-        .byline { margin-top: -6px; margin-left: 1px;}
-
-        /** Elements **/
-        #wrapper { margin-left: auto; 
-                   margin-right: auto;
-                   text-align: left; 
-                   width: 1000px;
-                   background-color: #fff; 
-                   position: relative; }
-        html, body, #wrapper { height: 100%; }
-
-        #top {
-            margin: 0px 6px; 
-            padding: 0px 12px 10px 12px; 
-            border-bottom: 1px solid #DDD;
-        }
-        #content { margin: 1em 18px; }
-    </style>
-    
-	<script type='text/javascript' src='../jquery.js'></script>
-	<script type='text/javascript' src='tea.js'></script>
-	<script type='text/javascript' src='tea.tests.js'></script>
-	
-	<script type='text/javascript'>
-	    $(function()
-        {
-            var results = Tea.Testing.run();
-
-            if (results.count > results.passed)
-            {
-                // This color (#FF0000) offends me, and is my punishment for failing tests.
-                // Just looked at it-- god it's awful.  Hopefully I won't skip writing tests to avoid it.
-                $('.byline').append(" - <span style='color: #FF0000'>Fail</span>"); 
-            }
-            else
-            {
-                $('.byline').append(" - <span style='color: #88AA88'>Pass</span>");
-            }
-        })
-	</script>
-</head>
-
-<body>
-	<div id='wrapper'>
-		<div id='top'>
-			<h1>Green Tea</h1>
-			<h3 class='byline'>Built Unit Tests</h3>
-		</div>
-    	<div id='content'>
-			
-	    </div>
-	</div>
-</body>
-</html>
-

docs/app.js

-Tea.require('../src/ajax.js')
-
-App = Tea.Application.subclass('App', {
-    init : function()
-    {
-        Tea.ajax({
-            url: 'docs.json',
-            success: function(d) { this.setApi(d) }, 
-            scope: this
-        });
-    },
-    
-    divSection : function(section)
-    {
-        var div = $('<div class="section">');
-        var name = $('<div class="name">').append( $('<b>').append(section.name) ).appendTo(div);
-        var description = $('<p>').append(section.description).appendTo(div);
-        var children = $('<blockquote class="children">').appendTo(div);
-
-        if (section.args)
-            name.append($('<span class="args">').append(section.args));
-
-        // Then first
-        for(var i = 0; i < section.children.length; i++)
-        {
-            if (section.children[i].name == 'options')
-                this.divSection(section.children[i]).appendTo(children);
-        }
-
-        // Then !important
-        for(var i = 0; i < section.children.length; i++)
-        {
-            if (section.children[i].important && section.children[i].name != 'options')
-                this.divSection(section.children[i]).appendTo(children);
-        }
-
-        // Then the rest
-        for(var i = 0; i < section.children.length; i++)
-        {
-            if (!section.children[i].important && section.children[i].name != 'options')
-                this.divSection(section.children[i]).appendTo(children);
-        }
-
-        return div;
-    },
-    
-    setApi : function(roots)
-    {
-        for(var i = 0; i < roots.length; i++)
-        {
-            var section = roots[i];
-            this.divSection(section).appendTo('#content');
-        }
-    }
-})
-
-$(function()
-{
-    App.setup();
-})

docs/base.css

-* {
-	margin: 0;
-	padding: 0;
-}
-
-body {
-	margin: 0;
-	padding: 0;
-	font-family: Verdana, Arial, Helvetica, sans-serif;
-	font-size: 12px;
-	color: #444;
-	background-color: #f6f6f6;
-	text-align: center;
-	line-height: 1.4;
-}
-
-pre {
-	font-size: 1.2em;
-	padding-left: 2em;
-	padding-top: 1em;
-	background-color: #F8F8F1;
-}
-	
-code {
-	font-size: 1.2em;
-	color: #006600;
-}
-
-img { border: 0; }
-	
-h1, h2, h3, h4, h5, h6 { color: #888;  font-weight: bold; margin-bottom: 0px; padding-bottom: 0px ; margin-top: 0px;}
-h1 { font-size: 2.5em; color: #8A8; letter-spacing: -2px; }
-h2 { font-size: 1.2em }
-h3 { font-size: 1.1em }
-h4, h5, h6 { font-size: 1.0em }
-
-p, ul, ol {
-	margin-top: 1em;
-}
-
-h1 + p, h2 + p, h3 + p {
-	margin-top: 0;
-}
-
-p + ul {
-	margin-top: 0;
-}
-
-select { padding: 0px; margin: 0px }
-select option { padding: 0px 4px }
-
-.byline { margin-top: -6px; margin-left: 1px;}
-
-/** Elements **/
-#wrapper { margin-left: auto; 
-           margin-right: auto;
-           text-align: left; 
-           width: 1000px;
-           background-color: #fff; 
-           position: relative; 
-           padding-bottom: 4em; }
-
-#top {
-    margin: 0px 6px; 
-    padding: 0px 12px 10px 12px; 
-    border-bottom: 1px solid #DDD;
-}
-
-#content { margin: 1em 18px; }
-
-/** Specific **/
-blockquote { 
-    margin-left: 1em;
-}
-
-.section {
-    margin-top: 1em;
-}
-
-.args {
-    margin-left: 4px;
-    color: #888;
-}
-
-.name + p {
-    margin-top: 0px;
-}

docs/docs.json

-[{"name": "Tea", "args": null, "important": false, "path": ["Tea"], "children": [{"name": "Application", "args": null, "important": false, "path": ["Tea", "Application"], "children": [], "description": "Nice structured way to organize your app. &nbsp;init() is called when the page is ready, i.e. jQuery.ready.<br/><br/>To setup the app, use .setup([properties]), where properties are extra properties to set on the object.<br/><br/>Also note that any Tea.Application subclasses are immediately turned into singletons."}, {"name": "Class", "args": "(name, properties) ", "important": true, "path": ["Tea", "Class"], "children": [], "description": "Returns a new Class function with a defined prototype and options.<br/><br/>Example:<br/> &nbsp; &nbsp;App.Greeter = Tea.Class('App.Greeter', {<br/> &nbsp; &nbsp; &nbsp; &nbsp;options: {<br/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; recipient : \"world\"<br/> &nbsp; &nbsp; &nbsp; &nbsp;},<br/> &nbsp; &nbsp; &nbsp; &nbsp;greet : function()<br/> &nbsp; &nbsp; &nbsp; &nbsp;{<br/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;alert(\"Hello \" + this.options.recipient + \"!\");<br/> &nbsp; &nbsp; &nbsp; &nbsp;}<br/> &nbsp; &nbsp;})<br/> &nbsp; &nbsp;<br/> &nbsp; &nbsp;>>> var greeter = new App.Greeter();<br/> &nbsp; &nbsp;>>> greeter.greet();<br/> &nbsp; &nbsp;Hello world!<br/><br/> &nbsp; &nbsp;>>> var greeter = new App.Greeter({recipient: 'javascripter'});<br/> &nbsp; &nbsp;>>> greeter.greet();<br/> &nbsp; &nbsp;Hello javascripter!<br/><br/>See tests/test_core.js for more examples on usage."}, {"name": "Container", "args": null, "important": false, "path": ["Tea", "Container"], "children": [], "description": "An element that contains other elements.<br/><br/>Requires:<br/> &nbsp; &nbsp;Tea.Element<br/><br/>More comments."}, {"name": "Dialog", "args": null, "important": false, "path": ["Tea", "Dialog"], "children": [], "description": "A Panel that displays itself over the ui to prompt the user.<br/><br/>Requires:<br/> &nbsp; &nbsp;Tea.Panel"}, {"name": "Drag", "args": null, "important": false, "path": ["Tea", "Drag"], "children": [], "description": "Dragging and dropping."}, {"name": "Element", "args": null, "important": false, "path": ["Tea", "Element"], "children": [], "description": "Represents a basic ui element.<br/>Elements have sources, a jQuery expression that points to specific DOM elements.<br/>Elements have a skin, which builds the DOM element, and handle DOM element specific logic.<br/>Elements can have parents.<br/> &nbsp;<br/>options:<br/> &nbsp; &nbsp;source:<br/> &nbsp; &nbsp; &nbsp; &nbsp;A jQuery element that serves as the base for manipulating the object. &nbsp;In the case <br/> &nbsp; &nbsp; &nbsp; &nbsp;of a string or dom element, it is run through the jQuery ($) function."}, {"name": "Form", "args": null, "important": false, "path": ["Tea", "Form"], "children": [], "description": "Ajax and classic form creation and management.<br/><br/>Requires:<br/> &nbsp; &nbsp;Tea.Container"}, {"name": "List", "args": null, "important": false, "path": ["Tea", "List"], "children": [], "description": "A container that lists content as Tea.ListItem elements.<br/><br/>Requires:<br/> &nbsp; &nbsp;Tea.Container"}, {"name": "Model", "args": null, "important": false, "path": ["Tea", "Model"], "children": [{"name": "__class__", "args": null, "important": false, "path": ["Tea", "Model", "__class__"], "children": [{"name": "get", "args": "(pk, value)", "important": false, "path": ["Tea", "Model", "__class__", "get"], "children": [], "description": "Returns an instance, either existing, or new.<br/><br/>pk [optional]:<br/> &nbsp; &nbsp;Private key value for the instance to return.<br/><br/>value [optional]:<br/> &nbsp; &nbsp;Value dictionary to be merged onto the instance."}, {"name": "options", "args": null, "important": false, "path": ["Tea", "Model", "__class__", "options"], "children": [], "description": "url:<br/> &nbsp; &nbsp;The default url/route that will be connected to for ajax calls.<br/>save:<br/> &nbsp; &nbsp;The url/route to connect to for save() ajax calls.<br/>update:<br/> &nbsp; &nbsp;The url/route to connect to for update() ajax calls.<br/>del:<br/> &nbsp; &nbsp;The url/route to connect to for del() ajax calls."}], "description": "These class properties and methods are on the Model class itself."}, {"name": "__init__", "args": "(value)", "important": false, "path": ["Tea", "Model", "__init__"], "children": [], "description": "Constructor for model instances, takes a value to be merged onto the instance.<br/>Note: one should normally use .get() instead of new Model(), as .get makes sure that<br/>if an instance with the same pk already exists, that will be returned, but when a new<br/>instance is created, __init__ is called on it.<br/><br/>value:<br/> &nbsp; &nbsp;Value dictionary to be merged onto the new instance."}, {"name": "del", "args": "(options)", "important": false, "path": ["Tea", "Model", "del"], "children": [], "description": "Ajax call to delete this instance. &nbsp;<br/>Note: It doesn't actually do anything to this model instance on the javascript side.<br/><br/>options:<br/> &nbsp; &nbsp;Over-riding options to pass into Tea.ajax.<br/><br/>Events:<br/> &nbsp; &nbsp;- deleted"}, {"name": "getFields", "args": "()", "important": false, "path": ["Tea", "Model", "getFields"], "children": [], "description": "Return the fields for this instance appropriate for a form."}, {"name": "getListItem", "args": "(options)", "important": false, "path": ["Tea", "Model", "getListItem"], "children": [], "description": "Returns a default list item object."}, {"name": "getRef", "args": "()", "important": false, "path": ["Tea", "Model", "getRef"], "children": [], "description": "Gets a dictionary to use as a reference for this instance. &nbsp;It contains the model and pk<br/>of this instance."}, {"name": "getValue", "args": "()", "important": false, "path": ["Tea", "Model", "getValue"], "children": [], "description": "Get the value of this instance without functions and without any properties that start with<br/>an underscore except for _model and _pk."}, {"name": "save", "args": "(options)", "important": false, "path": ["Tea", "Model", "save"], "children": [], "description": "Ajax call to save this instance.<br/><br/>options:<br/> &nbsp; &nbsp;Over-riding options to pass into Tea.ajax.<br/><br/>Events:<br/> &nbsp; &nbsp;- saved<br/> &nbsp; &nbsp;- updated"}, {"name": "setValue", "args": "(value)", "important": false, "path": ["Tea", "Model", "setValue"], "children": [], "description": "Merges the given value dictionary onto this instance.<br/><br/>value:<br/> &nbsp; &nbsp;Value dictionary to be merged onto this instance."}, {"name": "toString", "args": "()", "important": false, "path": ["Tea", "Model", "toString"], "children": [], "description": "Returns a string representation of the model."}, {"name": "update", "args": "(options)", "important": false, "path": ["Tea", "Model", "update"], "children": [], "description": "Ajax call to update this instance.<br/><br/>options:<br/> &nbsp; &nbsp;Over-riding options to pass into Tea.ajax.<br/><br/>Events:<br/> &nbsp; &nbsp;- updated"}], "description": "Library for ORM-like interaction with the server."}, {"name": "Object", "args": null, "important": false, "path": ["Tea", "Object"], "children": [{"name": "extend", "args": "(interface)", "important": false, "path": ["Tea", "Object", "extend"], "children": [], "description": "Copies over the properties and options of the interface to this class."}, {"name": "prototype", "args": null, "important": false, "path": ["Tea", "Object", "prototype"], "children": [{"name": "bind", "args": "(types, [args], handler)", "important": false, "path": ["Tea", "Object", "prototype", "bind"], "children": [], "description": "Binds one or many events to this instance to the given function which will be called with the given args.<br/><br/>types:<br/> &nbsp; &nbsp;A list of strings, or one string of events to bind.<br/><br/>handler:<br/> &nbsp; &nbsp;The function to call when the event is triggered.<br/><br/>args (optional):<br/> &nbsp; &nbsp;A list of arguments to pass into when calling the handler."}, {"name": "setOptions", "args": "(instance, options)", "important": false, "path": ["Tea", "Object", "prototype", "setOptions"], "children": [], "description": "Sets the options of the instance, using the instance's constructor's options as a base."}, {"name": "trigger", "args": "(...)", "important": false, "path": ["Tea", "Object", "prototype", "trigger"], "children": [], "description": "Triggers all of the events given as arguments.<br/><br/>arguments:<br/> &nbsp; &nbsp;A series of event-names as strings."}, {"name": "unbind", "args": "(types, [handler])", "important": false, "path": ["Tea", "Object", "prototype", "unbind"], "children": [], "description": "Unbinds one or many events from this instance. &nbsp;If handler is given, only events pointing to that<br/>handler are unbound.<br/><br/>types:<br/> &nbsp; &nbsp;A list of strings, or one string of events to unbind.<br/><br/>handler:<br/> &nbsp; &nbsp;Only events pointing the given handler are unbound."}], "description": "All object instances have these functions:"}, {"name": "setOptions", "args": "(instance, options)", "important": false, "path": ["Tea", "Object", "setOptions"], "children": [], "description": "Sets the options of the instance, using the instance's constructor's options as a base.<br/>Note: this is a classmethod, not on the instance."}, {"name": "subclass", "args": "(name, properties)", "important": false, "path": ["Tea", "Object", "subclass"], "children": [], "description": "Creates a subclass of the class, copying over prototype properties and options."}], "description": "Base object that allows class/subclass behavior, events, and a regard for \"options\".<br/><br/>Tea.Class(name, properties) is a synonym for: Tea.Object.subclass(name, properties)"}, {"name": "Panel", "args": null, "important": false, "path": ["Tea", "Panel"], "children": [], "description": "A container that can may be closed, and may have a title bar, a top action bar, or a bottom action bar.<br/><br/>Requires:<br/> &nbsp; &nbsp;Tea.Container"}, {"name": "Resource", "args": null, "important": false, "path": ["Tea", "Resource"], "children": [], "description": "A remote resource."}, {"name": "StackContainer", "args": null, "important": false, "path": ["Tea", "StackContainer"], "children": [], "description": "A container that acts as a stack, showing only the top few elements. &nbsp;Pushing elements onto the stack moves<br/>the existing elements to the left.<br/><br/>Requires:<br/> &nbsp; &nbsp;Tea.Container"}, {"name": "Template", "args": null, "important": false, "path": ["Tea", "Template"], "children": [{"name": "__init__", "args": "(src, [options])", "important": false, "path": ["Tea", "Template", "__init__"], "children": [], "description": "Instantiate a template with the given source, and optionally options."}, {"name": "apply", "args": "(context)", "important": false, "path": ["Tea", "Template", "apply"], "children": [], "description": "Applies the template with the given context."}, {"name": "options", "args": null, "important": false, "path": ["Tea", "Template", "options"], "children": [], "description": "re:<br/> &nbsp; &nbsp;The regular expression used, defaults to: /{{\\s*(.*?)\\s*}}/g, which<br/> &nbsp; &nbsp;matches things like: something something {match} something.<br/>missing_throws:<br/> &nbsp; &nbsp;Throw an exception if a variable cannot be resolved, otherwise<br/> &nbsp; &nbsp;it merely replaces the variable with an empty string ''.<br/>html_encode:<br/> &nbsp; &nbsp;Converts \"&\", \"<\", and \">\" to \"&amp;\", \"&lt;\", and \"&gt;\", respectively."}], "description": "Naive template implementation.<br/>NOTE: There is no escaping done here.<br/><br/>Example:<br/> &nbsp; &nbsp;var context = {must: 'will'};<br/> &nbsp; &nbsp;var t = new Tea.Template('Bugs {{must}} go. &nbsp;They {{ must }}.');<br/> &nbsp; &nbsp;assertEqual(t.apply(context), 'Bugs will go. &nbsp;They will.');"}, {"name": "Testing", "args": null, "important": false, "path": ["Tea", "Testing"], "children": [], "description": "A testing framework."}, {"name": "Widget", "args": null, "important": false, "path": ["Tea", "Widget"], "children": [], "description": "A few ui widgets, like buttons, and... well that's it so far.<br/><br/>Requires:<br/> &nbsp; &nbsp;Tea.Element"}, {"name": "ajax", "args": "(options)", "important": false, "path": ["Tea", "ajax"], "children": [], "description": "Makes an ajax call to the given resource using jQuery.ajax. &nbsp;Some options are<br/>automatically configured for you to make things easier.<br/><br/>Tea.ajax will look up any Route with the name of the url you pass in. &nbsp;The route's url is then <br/>replaced. &nbsp;For instance if you had a route named 'document' that pointed to '/ajax/document/',<br/>you can use the options {url: 'document'}, which will then expand to: {url: '/ajax/document/'}.<br/><br/>For callbacks, one can either over-ride 'callback' or, if either 'success' or 'failure' is given, <br/>Tea will check the response object for a '__failure__' property. &nbsp;If there, 'failure' will be<br/>called. &nbsp;If not there, 'success' will be called.<br/><br/>options:<br/> &nbsp; &nbsp;Everything that jQuery.ajax <http://docs.jquery.com/Ajax/jQuery.ajax#options> takes and:<br/> &nbsp; &nbsp;post:<br/> &nbsp; &nbsp; &nbsp; &nbsp;If post is an object, the method will be set to 'post' and this will be used for the data.<br/> &nbsp; &nbsp;get:<br/> &nbsp; &nbsp; &nbsp; &nbsp;If get is an object, the method will be set to 'get' and this will be used for the data.<br/> &nbsp; &nbsp;dataType:<br/> &nbsp; &nbsp; &nbsp; &nbsp;Tea defaults this to 'json', to get raw textual data back use 'raw'.<br/> &nbsp; &nbsp;success:<br/> &nbsp; &nbsp; &nbsp; &nbsp;A callback matching the signature 'function(response)' when the response succeeds.<br/> &nbsp; &nbsp;failure:<br/> &nbsp; &nbsp; &nbsp; &nbsp;A callback matching the signature 'function(response)' when the response fails.<br/><br/>overriding:<br/> &nbsp; &nbsp;Shortcut to merge these overriding-options onto options."}, {"name": "compactJSON", "args": "( json-serializable )", "important": false, "path": ["Tea", "compactJSON"], "children": [], "description": "Creates a JSON representation like toJSON, but removes the extra spaces after ':' characters,<br/>and the like. &nbsp;Slightly reduces the size of the output, for all those space savers out there."}, {"name": "deselect", "args": "()", "important": false, "path": ["Tea", "deselect"], "children": [], "description": "Quick function to do a global deselect of all text that can pop-up during dragging or the like."}, {"name": "evalJSON", "args": "(src)", "important": false, "path": ["Tea", "evalJSON"], "children": [], "description": "Evaluates a given piece of json source."}, {"name": "getClass", "args": "(name)", "important": false, "path": ["Tea", "getClass"], "children": [], "description": "Returns a class with the given name."}, {"name": "getRoute", "args": "(name)", "important": false, "path": ["Tea", "getRoute"], "children": [], "description": "Returns the url of a named route.<br/><br/>name:<br/> &nbsp; &nbsp;Name of the route."}, {"name": "isInstance", "args": "(instance, cls)", "important": false, "path": ["Tea", "isInstance"], "children": [], "description": "If instance is an instance of cls, then we return true, otherwise false."}, {"name": "method", "args": "(context, function)", "important": false, "path": ["Tea", "method"], "children": [], "description": "Creates a callback that, when run, calls the given function with the given context as 'this'."}, {"name": "quoteString", "args": "(string)", "important": false, "path": ["Tea", "quoteString"], "children": [], "description": "Returns a string-repr of a string, escaping quotes intelligently. &nbsp;Mostly a support function for toJSON.<br/><br/>Examples:<br/> &nbsp; &nbsp;>>> Tea.quoteString(\"apple\")<br/> &nbsp; &nbsp;\"apple\"<br/> &nbsp; &nbsp;<br/> &nbsp; &nbsp;>>> Tea.quoteString('\"Where are we going?\", she asked.')<br/> &nbsp; &nbsp;\"\\\"Where are we going?\\\", she asked.\""}, {"name": "registerClass", "args": "(name, type)", "important": false, "path": ["Tea", "registerClass"], "children": [], "description": "Registeres a class with Tea, so that it can be found by name.<br/><br/>name:<br/> &nbsp; &nbsp;Name of the class.<br/> &nbsp; &nbsp;<br/>type:<br/> &nbsp; &nbsp;The class."}, {"name": "require", "args": "(...)", "important": false, "path": ["Tea", "require"], "children": [], "description": "Imports the given arguments by appending <script> or <style> tags to the head.<br/>Note: Perhaps it is too obvious: but importing is done relative to the page we're on.<br/>Note: The required script is loaded sometime AFTER the requiring script, so you can't use<br/> &nbsp; &nbsp; &nbsp;the provided namespace (functions and variables) right away.<br/><br/>arguments:<br/> &nbsp; &nbsp;Strings of urls to the given resource. &nbsp;If the string ends with .css, it is added with<br/> &nbsp; &nbsp;a <style> tag; if it's a .js, it is added with a <script> tag. &nbsp;If the string is in <br/> &nbsp; &nbsp;Tea"}, {"name": "route", "args": "([name, url] | object)", "important": false, "path": ["Tea", "route"], "children": [], "description": "Creates a route, or named url, that can be used in ajax calls rather than the full url.<br/><br/>name:<br/> &nbsp; &nbsp;Name of the route.<br/> &nbsp; &nbsp;<br/>url:<br/> &nbsp; &nbsp;Url to point to.<br/> &nbsp; &nbsp;<br/>object:<br/> &nbsp; &nbsp;A mapping of {name: url}."}, {"name": "toJSON", "args": "( json-serializble, compact )", "important": false, "path": ["Tea", "toJSON"], "children": [], "description": "Converts the given argument into a JSON respresentation.<br/><br/>If an object has a \"toJSON\" function, that will be used to get the representation.<br/>Non-integer/string keys are skipped in the object, as are keys that point to a function.<br/><br/>json-serializble:<br/> &nbsp; &nbsp;The *thing* to be converted.<br/><br/>compact:<br/> &nbsp; &nbsp;Set to true if the returned JSON should omit extra spaces that help readability."}], "description": "Complex UI framework based on jQuery.<br/><br/>Created by Brantley Harris on 2008-06-22.<br/>Copyright (c) 2008 Brantley Harris. All rights reserved."}]

docs/generator.py

-#!/usr/bin/env python
-
-import os
-import re
-
-re.comments = re.compile(r'\/\*\*(.*?)\*\*\/', re.M | re.S)
-
-class Section(object):
-    def __init__(self, name=None, description=None, args=None, important=False):
-        self.path = name.split('.')
-        self.name = self.path[-1]
-        self.description = description.strip()
-        self.children = {}
-        self.args = args
-        self.built = False
-        self.important = important
-    
-    def add(self, who):
-        self.children[who.name] = who
-    
-    @property
-    def sorted_children(self):
-        keys = self.children.keys()
-        keys.sort()
-        return [self.children[k] for k in keys]
-    
-    @property
-    def name_with_args(self):
-        return self.name + (self.args or '')
-    
-    def format(self, tabs=0):
-        spaces = tabs * '  '
-        children = "".join(child.format(tabs + 1) for child in self.sorted_children)
-        dashes = (3 - tabs) * '=' or '-'
-        return "%s%s %s %s\n%s%s\n\n%s" % (spaces, dashes, self.name_with_args, dashes, spaces, self.description.replace('\n', '\n' + spaces), children)
-        
-    __str__ = format
-    
-    def __repr__(self):
-        return "<Section: %s>" % self.name
-        
-    def simple(self, mode='html'):
-        return {
-            'path': self.path,
-            'name': self.name,
-            'args': self.args,
-            'description': self.description.replace('\n', '<br/>').replace('  ', ' &nbsp;'),
-            'children': [c.simple(mode) for c in self.sorted_children],
-            'important': self.important
-        }
- 
-class Scanner(object):
-    def __init__(self):
-        self.parts = {}
-        
-    def parse_comment(self, src):
-        src = src.strip()
-        name, description = src.split('\n', 1)
-        
-        ## Get rid of spaces at the beginning of each line.
-        count = 0
-        while (description[count].isspace()):
-            if (description[count] == '\n'):
-                description = description[count+1:]
-                count = 0
-                continue
-            count += 1
-        description = description.replace('\n' + ' ' * count, '\n')
-        
-        important = False
-        if name.endswith('!important'):
-            name = name[:-len('!important')]
-            important = True
-        
-        args = None
-        ## Split up the name into name and args
-        if '(' in name:
-            name, args = name.split('(', 1)
-            args = '(' + args
-        
-        name = name.strip()
-        print "  ", name
-        
-        self.parts[name] = Section(name=name, description=description, args=args, important=important)
-    
-    def build(self, sig):
-        section = self.parts[sig]
-        if section.built: return
-        
-        if len(section.path) == 1:
-            self.roots.append(section)
-        else:
-            parent_sig = ".".join(section.path[:-1])
-            self.parts[parent_sig].add(section)
-            
-        section.built = True
-    
-    def compile(self):
-        self.roots = []
-        keys = self.parts.keys()
-        keys.sort()
-        for sig in keys:
-            self.build(sig)
-        self.roots.sort(lambda a, b: cmp(a.name, b.name))
-        return self.roots
-    
-    def scan(self, path):
-        if os.path.isdir(path):
-            for l in os.listdir(path):
-                if l.endswith('.js') or os.path.isdir(l): 
-                    self.scan(os.path.join(path, l))
-        else:
-            for i in re.comments.findall(open(path).read()):
-                self.parse_comment(i)
- 
-def scan(path):
-    scanner = Scanner()
-    scanner.scan(path)
-    return scanner.compile()
- 
-print "Beggining scan..."
-roots = scan('../src')
-print "Done."
-
-import simplejson
-simple = [r.simple() for r in roots]
-simplejson.dump(simple, open('docs.json', 'w'))

docs/index.html

-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-	<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
-	<title>
-        Green Tea - API Reference
-    </title>
-	
-	<link rel="stylesheet" href="base.css" type="text/css"/>
-	<script type='text/javascript' src='../jquery.js'></script>
-	<script type='text/javascript' src='../src/core.js'></script>
-	<script type='text/javascript' src='app.js'></script>
-</head>
-
-<body>
-	<div id='wrapper'>
-		<div id='top'>
-			<h1>Green Tea</h1>
-			<h3 class='byline'>API Reference</h3>
-		</div>
-    	<div id='content'>
-			
-	    </div>
-	</div>
-	<div>
-	</div>
-</body>
-</html>
-
 function num(elem, prop) {
 	return elem[0] && parseInt( jQuery.curCSS(elem[0], prop, true), 10 ) || 0;
 }
-var expando = "jQuery" + now(), uuid = 0, windowData = {};
-
-jQuery.extend({
-	cache: {},
-
-	data: function( elem, name, data ) {
-		elem = elem == window ?
-			windowData :
-			elem;
-
-		var id = elem[ expando ];
-
-		// Compute a unique ID for the element
-		if ( !id )
-			id = elem[ expando ] = ++uuid;
-
-		// Only generate the data cache if we're
-		// trying to access or manipulate it
-		if ( name && !jQuery.cache[ id ] )
-			jQuery.cache[ id ] = {};
-
-		// Prevent overriding the named cache with undefined values
-		if ( data !== undefined )
-			jQuery.cache[ id ][ name ] = data;
-
-		// Return the named cache data, or the ID for the element
-		return name ?
-			jQuery.cache[ id ][ name ] :
-			id;
-	},
-
-	removeData: function( elem, name ) {
-		elem = elem == window ?
-			windowData :
-			elem;
-
-		var id = elem[ expando ];
-
-		// If we want to remove a specific section of the element's data
-		if ( name ) {
-			if ( jQuery.cache[ id ] ) {
-				// Remove the section of cache data
-				delete jQuery.cache[ id ][ name ];
-
-				// If we've removed all the data, remove the element's cache
-				name = "";
-
-				for ( name in jQuery.cache[ id ] )
-					break;
-
-				if ( !name )
-					jQuery.removeData( elem );
-			}
-
-		// Otherwise, we want to remove all of the element's data
-		} else {
-			// Clean up the element expando
-			try {
-				delete elem[ expando ];
-			} catch(e){
-				// IE has trouble directly removing the expando
-				// but it's ok with using removeAttribute
-				if ( elem.removeAttribute )
-					elem.removeAttribute( expando );
-			}
-
-			// Completely remove the data cache
-			delete jQuery.cache[ id ];
-		}
-	},
-	queue: function( elem, type, data ) {
-		if ( elem ){
-	
-			type = (type || "fx") + "queue";
-	
-			var q = jQuery.data( elem, type );
-	
-			if ( !q || jQuery.isArray(data) )
-				q = jQuery.data( elem, type, jQuery.makeArray(data) );
-			else if( data )
-				q.push( data );
-	
-		}
-		return q;
-	},
-
-	dequeue: function( elem, type ){
-		var queue = jQuery.queue( elem, type ),
-			fn = queue.shift();
-		
-		if( !type || type === "fx" )
-			fn = queue[0];
-			
-		if( fn !== undefined )
-			fn.call(elem);
-	}
-});
-
-jQuery.fn.extend({
-	data: function( key, value ){
-		var parts = key.split(".");
-		parts[1] = parts[1] ? "." + parts[1] : "";
-
-		if ( value === undefined ) {
-			var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);
-
-			if ( data === undefined && this.length )
-				data = jQuery.data( this[0], key );
-
-			return data === undefined && parts[1] ?
-				this.data( parts[0] ) :
-				data;
-		} else
-			return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function(){
-				jQuery.data( this, key, value );
-			});
-	},
-
-	removeData: function( key ){
-		return this.each(function(){
-			jQuery.removeData( this, key );
-		});
-	},
-	queue: function(type, data){
-		if ( typeof type !== "string" ) {
-			data = type;
-			type = "fx";
-		}
-
-		if ( data === undefined )
-			return jQuery.queue( this[0], type );
-
-		return this.each(function(){
-			var queue = jQuery.queue( this, type, data );
-			
-			 if( type == "fx" && queue.length == 1 )
-				queue[0].call(this);
-		});
-	},
-	dequeue: function(type){
-		return this.each(function(){
-			jQuery.dequeue( this, type );
-		});
-	}
+var expando = "jQuery" + now(), uuid = 0, windowData = {};
+
+jQuery.extend({
+	cache: {},
+
+	data: function( elem, name, data ) {
+		elem = elem == window ?
+			windowData :
+			elem;
+
+		var id = elem[ expando ];
+
+		// Compute a unique ID for the element
+		if ( !id )
+			id = elem[ expando ] = ++uuid;
+
+		// Only generate the data cache if we're
+		// trying to access or manipulate it
+		if ( name && !jQuery.cache[ id ] )
+			jQuery.cache[ id ] = {};
+
+		// Prevent overriding the named cache with undefined values
+		if ( data !== undefined )
+			jQuery.cache[ id ][ name ] = data;
+
+		// Return the named cache data, or the ID for the element
+		return name ?
+			jQuery.cache[ id ][ name ] :
+			id;
+	},
+
+	removeData: function( elem, name ) {
+		elem = elem == window ?
+			windowData :
+			elem;
+
+		var id = elem[ expando ];
+
+		// If we want to remove a specific section of the element's data
+		if ( name ) {
+			if ( jQuery.cache[ id ] ) {
+				// Remove the section of cache data
+				delete jQuery.cache[ id ][ name ];
+
+				// If we've removed all the data, remove the element's cache
+				name = "";
+
+				for ( name in jQuery.cache[ id ] )
+					break;
+
+				if ( !name )
+					jQuery.removeData( elem );
+			}
+
+		// Otherwise, we want to remove all of the element's data
+		} else {
+			// Clean up the element expando
+			try {
+				delete elem[ expando ];
+			} catch(e){
+				// IE has trouble directly removing the expando
+				// but it's ok with using removeAttribute
+				if ( elem.removeAttribute )
+					elem.removeAttribute( expando );
+			}
+
+			// Completely remove the data cache
+			delete jQuery.cache[ id ];
+		}
+	},
+	queue: function( elem, type, data ) {
+		if ( elem ){
+	
+			type = (type || "fx") + "queue";
+	
+			var q = jQuery.data( elem, type );
+	
+			if ( !q || jQuery.isArray(data) )
+				q = jQuery.data( elem, type, jQuery.makeArray(data) );
+			else if( data )
+				q.push( data );
+	
+		}
+		return q;
+	},
+
+	dequeue: function( elem, type ){
+		var queue = jQuery.queue( elem, type ),
+			fn = queue.shift();
+		
+		if( !type || type === "fx" )
+			fn = queue[0];
+			
+		if( fn !== undefined )
+			fn.call(elem);
+	}
+});
+
+jQuery.fn.extend({
+	data: function( key, value ){
+		var parts = key.split(".");
+		parts[1] = parts[1] ? "." + parts[1] : "";
+
+		if ( value === undefined ) {
+			var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);
+
+			if ( data === undefined && this.length )
+				data = jQuery.data( this[0], key );
+
+			return data === undefined && parts[1] ?
+				this.data( parts[0] ) :
+				data;
+		} else
+			return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function(){
+				jQuery.data( this, key, value );
+			});
+	},
+
+	removeData: function( key ){
+		return this.each(function(){
+			jQuery.removeData( this, key );
+		});
+	},
+	queue: function(type, data){
+		if ( typeof type !== "string" ) {
+			data = type;
+			type = "fx";
+		}
+
+		if ( data === undefined )
+			return jQuery.queue( this[0], type );
+
+		return this.each(function(){
+			var queue = jQuery.queue( this, type, data );
+			
+			 if( type == "fx" && queue.length == 1 )
+				queue[0].call(this);
+		});
+	},
+	dequeue: function(type){
+		return this.each(function(){
+			jQuery.dequeue( this, type );
+		});
+	}
 });/*!
  * Sizzle CSS Selector Engine - v0.9.1
  *  Copyright 2009, The Dojo Foundation
 ]
 
 import builder
-builder.build(modules, path='build/tea.js', minified=True, tests=True)
+builder.build(modules, path='build', minified=True, tests=True, docs=True)