MonkeyCode做代码生成器:从模板引擎到AI辅助的完整实战

重复代码是程序员的天敌。MonkeyCode不仅能帮你写代码,还能帮你造"写代码的工具"——代码生成器。

代码生成器的价值

程序员的时间分配:
  写新代码:30%
  写重复代码:40%  ← 这里可以优化!
  调试代码:30%

代码生成器把40%的重复劳动变成1次模板配置。

场景1:CRUD代码生成器

痛点

每个数据表都要写:Model、Schema、CURD接口、单元测试……全是模板代码。

让MonkeyCode生成CRUD生成器

# generate_crud.py - 命令行工具
import yaml
import jinja2
import os
from pathlib import Path

# ─── 模板引擎 ───
env = jinja2.Environment(
    loader=jinja2.FileSystemLoader("templates/"),
    trim_blocks=True,
    lstrip_blocks=True
)

# ─── 模型定义(YAML)───
"""
# schema/user.yaml
model: User
table: users
fields:
  - name: id
    type: int
    primary_key: true
    auto_increment: true
  - name: email
    type: str
    unique: true
    nullable: false
  - name: nickname
    type: str
    nullable: true
  - name: created_at
    type: datetime
    default: "now()"
"""

def load_schema(yaml_path: str) -> dict:
    with open(yaml_path) as f:
        return yaml.safe_load(f)

def generate_model(schema: dict) -> str:
    """生成SQLAlchemy Model"""
    template = env.get_template("model.py.j2")
    return template.render(schema=schema)

def generate_router(schema: dict) -> str:
    """生成FastAPI Router"""
    template = env.get_template("router.py.j2")
    return template.render(schema=schema)

def generate_schemas(schema: dict) -> str:
    """生成Pydantic Schema"""
    template = env.get_template("schemas.py.j2")
    return template.render(schema=schema)

def generate_tests(schema: dict) -> str:
    """生成pytest单元测试"""
    template = env.get_template("tests.py.j2")
    return template.render(schema=schema)

def generate_all(schema_path: str, output_dir: str):
    schema = load_schema(schema_path)
    model_name = schema["model"]
    base = Path(output_dir) / model_name.lower()
    base.mkdir(parents=True, exist_ok=True)
    
    (base / "model.py").write_text(generate_model(schema))
    (base / "router.py").write_text(generate_router(schema))
    (base / "schemas.py").write_text(generate_schemas(schema))
    (base / "tests.py").write_text(generate_tests(schema))
    
    print(f"✅ 生成完成:{base}/")

if __name__ == "__main__":
    import sys
    generate_all(sys.argv[1], sys.argv[2])

Jinja2模板示例

{# templates/model.py.j2 #}
from sqlalchemy import Column, Integer, String, DateTime
from sqlalchemy.orm import declarative_base

Base = declarative_base()

class {{ schema.model }}(Base):
    __tablename__ = "{{ schema.table }}"
    
    {% for field in schema.fields %}
    {{ field.name }} = Column(
        {% if field.type == 'int' %}Integer()
        {% elif field.type == 'str' %}String()
        {% elif field.type == 'datetime' %}DateTime()
        {% endif %}
        {% if field.primary_key %}, primary_key=True{% endif %}
        {% if field.auto_increment %}, autoincrement=True{% endif %}
        {% if field.unique %}, unique=True{% endif %}
        {% if field.nullable == false %}, nullable=False{% endif %}
    )
    {% endfor %}
{# templates/router.py.j2 #}
from fastapi import APIRouter, Depends
from pydantic import BaseModel

router = APIRouter(prefix="/{{ schema.table }}")

@router.post("/")
async def create_{{ schema.table | singular }}(data: {{ schema.model }}Create):
    # TODO: 实现创建逻辑
    return {"id": 1}

@router.get("/")
async def list_{{ schema.table }}(skip: int = 0, limit: int = 100):
    # TODO: 实现列表查询
    return []

@router.get("/{id}")
async def get_{{ schema.table | singular }}(id: int):
    # TODO: 实现单条查询
    return {"id": id}

@router.put("/{id}")
async def update_{{ schema.table | singular }}(id: int, data: {{ schema.model }}Update):
    # TODO: 实现更新
    return {"id": id}

@router.delete("/{id}")
async def delete_{{ schema.table | singular }}(id: int):
    # TODO: 实现删除
    return {"deleted": True}

使用

python generate_crud.py schema/user.yaml ./app/
# 输出:
# ✅ 生成完成:./app/user/
#   ├── model.py
#   ├── router.py
#   ├── schemas.py
#   └── tests.py

场景2:GraphQL代码生成

GraphQL有一堆Boilerplate代码,用graphql-code-generator自动生成:

# codegen.yml
overwrite: true
schema: "http://localhost:8000/graphql"
documents: "src/**/*.graphql"
generates:
  src/generated/types.ts:
    plugins:
      - "typescript"
      - "typescript-operations"
      - "typescript-react-apollo"
  src/generated/api.ts:
    plugins:
      - "typescript-generator"

运行 npx graphql-codegen,自动生成TypeScript类型定义和API调用代码。

场景3:Protocol Buffers + gRPC

// api/order.proto
syntax = "proto3";
package order.v1;

service OrderService {
  rpc CreateOrder (CreateOrderRequest) returns (CreateOrderResponse);
  rpc GetOrder    (GetOrderRequest)    returns (GetOrderResponse);
}

message CreateOrderRequest {
  string user_id = 1;
  repeated OrderItem items = 2;
}

message OrderItem {
  string sku = 1;
  int32 qty = 2;
}

生成Python代码:

python -m grpc_tools.protoc \
  -I. \
  --python_out=. \
  --grpc_python_out=. \
  api/order.proto

场景4:AI辅助代码生成器(Swagger/OpenAPI)

从OpenAPI Spec自动生成SDK:

# 安装openapi-generator
# npm install @openapitools/openapi-generator-cli -g

# 生成Python SDK
openapi-generator-cli generate \
  -i http://localhost:8000/openapi.json \
  -g python \
  -o ./sdk/python \
  --additional-properties=packageName=myapi_sdk

# 生成TypeScript SDK
openapi-generator-cli generate \
  -i http://localhost:8000/openapi.json \
  -g typescript-fetch \
  -o ./sdk/ts

场景5:MonkeyCode生成MonkeyCode(元编程)

让AI帮你写代码生成器:

我的项目有20个数据表,每个表都要写:
- SQLAIchemy Model
- Pydantic Schema
- FastAPI CRUD接口
- pytest单元测试

请帮我写一个代码生成器:
1. 输入:YAML格式的表结构定义
2. 输出:上述4个文件
3. 使用Jinja2模板引擎
4. 支持一键生成+单表生成
5. 生成后运行pytest验证

高级技巧:模板继承

{# templates/base_api.py.j2 #}
from fastapi import APIRouter, HTTPException
from typing import List, Optional

router = APIRouter()

{% block list_endpoint %}{% endblock %}
{% block create_endpoint %}{% endblock %}
{% block get_endpoint %}{% endblock %}
{% block update_endpoint %}{% endblock %}
{% block delete_endpoint %}{% endblock %}
{# templates/custom_router.py.j2 #}
{% extends "base_api.py.j2" %}

{% block list_endpoint %}
@router.get("/")
async def list_items():
    return []
{% endblock %}

代码生成器的边界

适合生成:
  ✅ CRUD模板代码
  ✅ 类型定义(protobuf/GraphQL)
  ✅ SDK/客户端绑定
  ✅ 配置文件模板
  ✅ 单元测试模板

不适合生成:
  ❌ 复杂业务逻辑(会生成错误逻辑)
  ❌ 安全敏感代码(加密/认证)
  ❌ 性能关键路径(需人工优化)

MonkeyCode Prompt模板

用[Python/Go/TypeScript]写一个代码生成器,需求:
1. 输入格式:[YAML/JSON/Protobuf]
2. 生成目标:[CRUD代码/SDK/类型定义]
3. 使用[Jinja2/Go template] 模板引擎
4. 生成文件列表:[列出所有文件]
5. 生成后自动运行测试验证
6. 支持命令行参数:[参数列表]

总结

代码生成器的核心是识别重复模式,抽象为模板

MonkeyCode能帮你:

  1. 分析现有代码,识别可模板化的重复模式
  2. 设计YAML/JSON输入格式
  3. 编写Jinja2/Go template模板
  4. 生成完整的代码生成器(含CLI、测试、文档)

记住:代码生成器不是"一次性脚本",而是需要维护的基础设施。模板要清晰、可调试、可覆盖。

posted @ 2026-05-29 21:50  机房管理员  阅读(17)  评论(0)    收藏  举报