美文网首页程序员
撸一个简单的Python模板引擎来生成代码

撸一个简单的Python模板引擎来生成代码

作者: 淡定小问题 | 来源:发表于2017-07-26 20:15 被阅读165次

模板

利用python的动态性,动态生成脚本代码
利用python的语法,支持一定的结构:for ,if ;方法调用等

package  *.*;

import *.ProguardKeep;
import *.LogType;
import *.Track;

/**
 * {% for comment in idl.cls_comments: %}
 * {{comment.strip()}}
 * {% end %}
 * schema: {{ idl.file }}
 * Created by AUTO_GEN_CODE on {{ idl.date }}.
 */
@Track(isRealTime = {{ 'true' if idl.is_real_time else 'false' }}, md_etype = LogType.{{idl.etype.title()}}, md_eid = "{{idl.eid}}", isCarryPathInfo = {{ 'true' if idl.is_with_path else 'false'}})
public class {{ idl.cls_name }} implements ProguardKeep {

    {% for field in idl.fields: %}
    public String {{ field.name }} = ""; // {{ field.comment }}
    {% end %}
}

简单的模板引擎

import re

TEMPLATE_PATTERN = re.compile("{{(?P<var>.*?)}}|{%(?P<code>.*?)%}")


def parse_template(template):
    start = 0
    find_pattern = TEMPLATE_PATTERN.search(template, 0)

    while find_pattern:
        segment = template[start: find_pattern.start()]
        var = find_pattern.group('var')
        _code = find_pattern.group('code')

        yield segment, var, _code

        start = find_pattern.end()
        find_pattern = TEMPLATE_PATTERN.search(template, start)

    yield template[start:], None, None


class CodeBuilder:
    INDENT = ' ' * 4

    def __init__(self):
        self.codes = []
        self.cur_intent = 0
        pass

    def __repr__(self):
        return '\n'.join(self.codes)

    def add(self, string):
        self.codes.append(self.cur_intent * CodeBuilder.INDENT + string)
        return self

    def indent(self):
        self.cur_intent += 1
        return self

    def dedent(self):
        self.cur_intent -= 1
        return self


def compile_2_code(template):
    builder = CodeBuilder()

    builder.add('def gen_code(idl):')
    builder.indent()

    builder.add('render_result = []')
    builder.add('__append = render_result.append')

    for segment, var, _code in parse_template(template):

        builder.add(f"__append('''{segment}''')")
        if var:
            builder.add(f'__append({var.strip()})')
        if _code:
            if _code.strip() == 'end':
                builder.dedent()
            else:
                builder.add(f'{_code.strip()}')
                builder.indent()

    builder.add('java_code = "".join(render_result)')
    builder.add('return java_code')
    builder.dedent()
    return repr(builder)


if __name__ == '__main__':
    with open('track_code.schema', encoding='utf-8') as f:
        print(compile_2_code(f.read()), file=open('gen_code.py', 'w'))

模板引擎生成的代码

def gen_code(idl):
    render_result = []
    __append = render_result.append
    __append('''package com.meelive.ingkee.mechanism.track.codegen;

import com.meelive.ingkee.base.utils.ProguardKeep;
import com.meelive.inke.base.track.LogType;
import com.meelive.inke.base.track.Track;

/**
 * ''')
    for comment in idl.cls_comments:
        __append('''
 * ''')
        __append(comment.strip())
        __append('''
 * ''')
    __append('''
 * schema: ''')
    __append(idl.file)
    __append('''
 * Created by AUTO_GEN_CODE on ''')
    __append(idl.date)
    __append('''.
 */
@Track(isRealTime = ''')
    __append('true' if idl.is_real_time else 'false')
    __append(''', md_etype = LogType.''')
    __append(idl.etype.title())
    __append(''', md_eid = "''')
    __append(idl.eid)
    __append('''", isCarryPathInfo = ''')
    __append('true' if idl.is_with_path else 'false')
    __append(''')
public class ''')
    __append(idl.cls_name)
    __append(''' implements ProguardKeep {

    ''')
    for field in idl.fields:
        __append('''
    public String ''')
        __append(field.name)
        __append(''' = ""; // ''')
        __append(field.comment)
        __append('''
    ''')
    __append('''
}
''')
    java_code = "".join(render_result)
    return java_code

相关文章

网友评论

    本文标题:撸一个简单的Python模板引擎来生成代码

    本文链接:https://www.haomeiwen.com/subject/nzwokxtx.html