Skip to content

@mikelikespie /cheeseburger.py
Created

Embed URL

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
A DSL for html generation in python (I am a bad person and have been around ruby developers too long). It's just a prototype and the generation can't be controlled too well yet, but it is sweet. I am pretty sure this is violating most of the Zen of pyth
import sys
from functools import partial, wraps
from contextlib import contextmanager
from cStringIO import StringIO
###############################
# Should output the following
# <html>
# <head>
# <title>
# does this work?
# </title>
# </head>
# <body>
# <div style="color: green;font_size: 3px;" id="hi" class="there">
# <p class="big small">
# this is some text
# <br/>
# <div class="content">
# wrapped one
# </div>
# </p>
# </div>
# <div style="color: blue;font_size: 3px;" id="hi" class="there">
# <p class="big small">
# this is some text
# <br/>
# <div class="content">
# wrapped two
# </div>
# </p>
# </div>
# </body>
# <div id="link_3" class="link">
# <a href="http://google.com" title="google">
# google
# </a>
# </div>
# <div id="OMG">
# after
# </div>
# </html>
def main():
deferred_var = 'before'
@contextmanager
def big_wrapper(c, color):
with c.div('hi',
class_='there',
style=dict(
font_size='3px',
color=color)):
with c.p(None, ('big', 'small')):
c.text('this is some text').br()
with c.div(None, 'content'):
yield
def tiny_widget(c, link_id, url, title):
with c.div('link_%s' % link_id, 'link'):
with c.a(url, title=title):
c.text(title)
c = CheeseContext()
with c:
with c.html():
with c.head():
with c.title():
c.text('does this work?')
with c.body():
with big_wrapper(c, 'green'):
c.text('wrapped one')
with big_wrapper(c, 'blue'):
c.text('wrapped two')
tiny_widget(c, 3, 'http://google.com', 'google')
deferred_var = 'before' #
@c.defer
def omg(c):
with c.div('OMG'):
c.text(deferred_var)
deferred_var = 'after' # let's see if thsi shows up
################
# Library Code
################
def _maketags(*tags):
def maketag(tag):
def tfunc(self, id=None, class_=None, **attrs):
return self.tag(tag, id, class_, **attrs)
tfunc.__name__ = tag
return tfunc
return [maketag(tag) for tag in tags]
class CheeseContext(object):
indent_str = ' '
quote_str = '"'
def __init__(self, stream=sys.stdout, start_depth=0):
self.start_depth = start_depth
self.pending = None
self.tagstack = list()
self.lastwastext = False
self.streams = [stream]
self.deferreds = []
def tag(self, tag, id=None, class_=None, **attrs):
if id: attrs['id'] = id
if class_: attrs['class'] = class_
self.flush()
self.pending = (tag, attrs)
return self
div, span, br, body, html, p, head, title = _maketags('div', 'span', 'br', 'body', 'html', 'p', 'head', 'title')
def a(self, href=None, **attrs):
return self.tag('a', href=href, **attrs)
@property
def stream(self):
return self.streams[-1]
@property
def depth(self):
return self.start_depth + len(self.tagstack)
def _flush_pending(self, self_closing):
self._flushtext()
tag, attrs = self.pending
self.pending = None
self.indent()
self.write('<%s' % tag)
self._write_attrs(attrs)
self.write('/>\n' if self_closing else '>\n')
def defer(self, fn):
con = CheeseContext(stream=self.stream, start_depth=self.depth)
self.streams.append(StringIO()) ## todo propogate settings
def _gen():
yield
last_stream = self.streams.pop()
fn(con)
self.write(last_stream.getvalue())
self.deferreds.append(_gen())
return None
def flush(self):
if self.pending:
self._flush_pending(True)
def indent(self):
self.write(self.indent_str * self.depth) # YYY is it faster to multiply the string?
def write(self, obj, *args, **kwargs):
self.stream.write(obj, *args, **kwargs)
def text(self, text):
self.flush()
if not self.lastwastext:
self.lastwastext = True
self.indent()
self.write(text)
return self
def _flushtext(self):
if self.lastwastext:
self.lastwastext = False
self.write('\n')
def __enter__(self):
if self.pending:
tag = self.pending[0]
self._flush_pending(False)
self.tagstack.append(tag)
self._flushtext()
return self
def __exit__(self, exc_type, exc_value, traceback):
self._flushtext()
if self.pending:
self._flush_pending(True)
if self.tagstack:
tag = self.tagstack.pop()
self.indent()
self.write('</%s>\n' % tag)
elif self.deferreds:
while self.deferreds:
for d in self.deferreds.pop():
pass
def _write_attrs(self, attrs):
for k,v in attrs.iteritems():
if v is None:
continue
# we'll be nice and replace it with a string
self.write(' %s="' % k.replace('_', '-'))
# if its a list or something that looks like it
# separate it by spaces. Would be used for somethign like a class
if isinstance(v, (list, tuple, set)):
self.write(' '.join(v))
# if its dict like thing write it out like one would a thing
elif isinstance(v, (dict,)):
for k_, v_ in v.iteritems():
self.write('%s: %s;' % (k_, v_))
elif v is True:
self.write('true')
elif v is False:
self.write('false')
else: # ok, we don't know what it is. just assume its a string
self.write(v)
self.write('"')
if __name__ == '__main__':
main()
@mikelikespie

No description provided.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.