vbuterin

Fix for mixins with blocks for pyjade

Mar 31st, 2013
248
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.56 KB | None | 0 0
  1. # -*- coding: utf-8 -*-
  2.  
  3. import contextlib
  4.  
  5. import pyjade
  6. from pyjade.runtime import is_mapping, iteration
  7.  
  8.  
  9. def process_param(key, value, terse=False):
  10.     if terse:
  11.         if (key == value) or (value is True):
  12.             return key
  13.     if isinstance(value, basestring):
  14.         value = value.decode('utf8')
  15.     return '''%s="%s"''' % (key, value)
  16.  
  17.  
  18. TYPE_CODE = {
  19.     'if': lambda v: bool(v),
  20.     'unless': lambda v: not bool(v),
  21.     'elsif': lambda v: bool(v),
  22.     'else': lambda v: True}
  23.  
  24.  
  25. @contextlib.contextmanager
  26. def local_context_manager(compiler, local_context):
  27.     old_local_context = compiler.local_context
  28.     new_local_context = dict(compiler.local_context)
  29.     new_local_context.update(local_context)
  30.     compiler.local_context = new_local_context
  31.     yield
  32.     compiler.local_context = old_local_context
  33.  
  34.  
  35. class HTMLCompiler(pyjade.compiler.Compiler):
  36.     global_context = dict()
  37.     local_context = dict()
  38.     mixins = dict()
  39.     useRuntime = True
  40.     def _do_eval(self, value):
  41.         if isinstance(value, basestring):
  42.             value = value.encode('utf-8')
  43.         try:
  44.             value = eval(value, self.global_context, self.local_context)
  45.         except:
  46.             return ''
  47.         return value
  48.  
  49.    
  50.     def compile(self):
  51.         self.buf = [self.compile_top()]
  52.         self.lastBufferedIdx = -1
  53.         self.local_context = dict()
  54.         self.global_context = dict()
  55.         self.mixins = dict()
  56.         self.visit(self.node)
  57.         return unicode(u''.join(self.buf))
  58.  
  59.     def _get_value(self, attr):
  60.         value = attr['val']
  61.         if attr['static']:
  62.             return attr['val']
  63.         if isinstance(value, basestring):
  64.             return self._do_eval(value)
  65.         else:
  66.             return attr['name']
  67.  
  68.     def _make_mixin(self, mixin):
  69.         arg_names = [arg.strip() for arg in mixin.args.split(",")]
  70.         def _mixin(self, args, block=None):
  71.             if args:
  72.                 arg_values = self._do_eval(args)
  73.             else:
  74.                 arg_values = []
  75.             if '__iter__' not in dir(arg_values):
  76.                 arg_values = [arg_values]
  77.             local_context = dict(zip(arg_names, arg_values))
  78.             if block: local_context['block'] = block
  79.             with local_context_manager(self, local_context):
  80.                 self.visitBlock(mixin.block)
  81.         return _mixin
  82.  
  83.     def visitCodeBlock(self,block,mixing=None):
  84.         if 'block' in self.local_context:
  85.             self.visitBlock(self.local_context['block'])
  86.         else:
  87.             self.visitBlock(block)
  88.  
  89.     def interpolate(self,text):
  90.         return self._interpolate(text, lambda x: str(self._do_eval(x)))
  91.  
  92.     def visitInclude(self, node):
  93.         raise pyjade.exceptions.CurrentlyNotSupported()
  94.  
  95.     def visitExtends(self, node):
  96.         raise pyjade.exceptions.CurrentlyNotSupported()
  97.  
  98.     def visitMixin(self, mixin):
  99.         if mixin.name in self.mixins:
  100.             self.mixins[mixin.name](self, mixin.args, mixin.block)
  101.         else:
  102.             self.mixins[mixin.name] = self._make_mixin(mixin)
  103.  
  104.     def visitAssignment(self, assignment):
  105.         self.global_context[assignment.name] = eval(assignment.val)
  106.  
  107.     def visitConditional(self, conditional):
  108.         if not conditional.sentence:
  109.             value = False
  110.         else:
  111.             value = self._do_eval(conditional.sentence)
  112.         if TYPE_CODE[conditional.type](value):
  113.             self.visit(conditional.block)
  114.         elif conditional.next:
  115.             for item in conditional.next:
  116.                 self.visitConditional(item)
  117.  
  118.     def visitCode(self, code):
  119.         if code.buffer:
  120.             val = code.val.lstrip()
  121.             val = self._do_eval(val)
  122.             if code.escape:
  123.                 val = str(val).replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;')
  124.             self.buf.append(val)
  125.         if code.block:
  126.             self.visit(code.block)
  127.         if not code.buffer and not code.block:
  128.             exec code.val.lstrip() in self.global_context, self.local_context
  129.  
  130.     def visitEach(self, each):
  131.         obj = iteration(self._do_eval(each.obj), len(each.keys))
  132.         for item in obj:
  133.             local_context = dict()
  134.             if len(each.keys) > 1:
  135.                 for (key, value) in zip(each.keys, item):
  136.                     local_context[key] = value
  137.             else:
  138.                 local_context[each.keys[0]] = item
  139.             with local_context_manager(self, local_context):
  140.                 self.visit(each.block)
  141.  
  142.     def attributes(self, attrs):
  143.         return " ".join(['''%s="%s"''' % (k,v) for (k,v) in attrs.items()])
  144.  
  145.     def visitDynamicAttributes(self, attrs):
  146.         classes = []
  147.         params = []
  148.         for attr in attrs:
  149.             if attr['name'] == 'class':
  150.                 value = self._get_value(attr)
  151.                 if isinstance(value, list):
  152.                     classes.extend(value)
  153.                 else:
  154.                     classes.append(value)
  155.             else:
  156.                 value = self._get_value(attr)
  157.  
  158.                 if value not in (None,False):
  159.                     params.append((attr['name'], value))
  160.         if classes:
  161.             classes = [unicode(c) for c in classes]
  162.             params.append(('class', " ".join(classes)))
  163.         if params:
  164.             self.buf.append(" "+" ".join([process_param(k, v, self.terse) for (k,v) in params]))
  165.  
  166. def process_jade(src):
  167.     parser = pyjade.parser.Parser(src)
  168.     block = parser.parse()
  169.     compiler = HTMLCompiler(block, pretty=True)
  170.     return compiler.compile()
Advertisement
Add Comment
Please, Sign In to add comment