首页

/ 入门 / 万物皆可生成

万物皆可生成

CUE 在配置管理方面非常出色,而且解决了大量目前我们其他选择的根本问题。

虽然这是大多数人使用 CUE 的主要使用场景,但是实际上可以用 CUE 生成任何东西。

怎么可能?可以用 text/template 包来渲染任何我们想要的文件。

用 CUE 生成

first.cue

package gen

import "text/template"

data: {

// meta info

name: *"tasks" | string @tag(name)

msg: "Hello \(name), welcome to Cuetorials"

// task list

tasks: [

{name: "t1", effort: 1, complete: true},

{name: "t2", effort: 4, complete: true},

{name: "t3", effort: 3, complete: false},

{name: "t4", effort: 2, complete: true},

{name: "t5", effort: 3, complete: false},

]

// grouped tasks

complete: [ for t in tasks if t.complete == true {t}]

incomplete: [ for t in tasks if t.complete == false {t}]

}

// Templates which use Go's template engine

templates: [

{

filename: "\(data.name)-todo.txt"

contents: """

{{ .msg }}

--- TODO ---

{{ range $T := .incomplete -}}

{{ printf "%-4s%v" $T.name $T.effort }}

{{ end }}

"""

}, {

filename: "\(data.name)-done.txt"

contents: """

Here's what you have finished \(data.name). Good job!

--- DONE ---

{{ range $T := .complete -}}

{{ $T.name }}

{{ end }}

"""

},

]

// The rendered output from data+templates

rendered: [ for T in templates {

filename: T.filename

contents: template.Execute(T.contents, data)

}]

first_tool.cue

package gen

import (

"tool/file"

)

command: "gen": {

for i, R in rendered {

// make a unique name when comprehending

"write-\(i)": file.Create & {

filename: R.filename

contents: R.contents

}

}

}

cue cmd -t "name=bob" gen

CUE 的模板系统使用的 Go 的模板系统,所以所有的兼容性和规则都是一样的。

我们使用了 list 和 field 推导分别渲染和写入我们的模板,使用复杂的 CUE 定义、值以及模板你可以生成任何输出。

使用 Hof 生成

在 Hofstadter,我们使用 hof 用于复杂的代码生成,

我们希望可以通过唯一的来源来生成数据库、后端以及前端的代码。

我们认为对于开发这来说是,这是 high code (low code)的解决方案,CUE 被选为 UX/DX 来写输入(设计)和生成器。

之前系统的两个问题是:

你总会在生成的代码中编写自定义的代码

设计发展了,但是你已经生成了样板代码

解决方案实际上非常简单,保留最初生成代码代码的副本,然后使用 3-way diff 工具来合并设计更新和自定义的代码。

将下面两个文件放到同一个文件夹,然后运行 hof mod vendor cue 和 hof gen

cue.mods

module cuetorials.com/gen-with-hof

cue 0.4.0

require (

github.com/hofstadter-io/hof v0.5.17

)

hof.cue

package gen

import (

// import hof's generator schema

"github.com/hofstadter-io/hof/schema/gen"

)

// A schema for our generator's input

#Input: {

name: string

todos: [...{

name: string

effort: int

complete: bool

}]

}

// create a generator

#Gen: gen.#HofGenerator & {

// We often have some input values for the user to provide.

// Use a Cue definition to enforce a schema

Input: #Input

// Required filed for generator definitions, details can be found in the hof docs

PackageName: "dummy"

// Required field for a generator to work, the list of files to generate

Out: [...gen.#HofGeneratorFile] & [

todo,

done,

debug,

]

// In is supplied as the root data object to every template

// pass user inputs to the tempaltes here, possibly modified, enhanced, or transformed

In: {

INPUT: Input

Completed: _C

Incomplete: _I

}

// calculate some internal data from the input

_C: [ for t in Input.todos if t.complete == true {t}]

_I: [ for t in Input.todos if t.complete == false {t}]

// the template files

todo: {

Template: """

Hello {{ .INPUT.name }}.

The items still on your todo list:

{{ range $T := .Incomplete -}}

{{ printf "%-4s%v" $T.name $T.effort }}

{{ end }}

"""

// The output filename, using string interpolation

Filepath: "\(Input.name)-todo.txt"

}

done: {

Template: """

Here's what you have finished {{ .INPUT.name }}. Good job!

{{ range $T := .Completed -}}

{{ $T.name }}

{{ end }}

"""

Filepath: "\(Input.name)-done.txt"

}

// useful helper

debug: {

Template: """

{{ yaml . }}

"""

Filepath: "debug.yaml"

}

}

// Add the @gen(,,...) to denote usage of a generator

Gen: _ @gen(todos)

// Construct the generator

Gen: #Gen & {

Input: {

name: "tasks"

todos: [

{name: "t1", effort: 1, complete: true},

{name: "t2", effort: 4, complete: true},

{name: "t3", effort: 3, complete: false},

{name: "t4", effort: 2, complete: true},

{name: "t5", effort: 3, complete: false},

]

}

}

你可以通过下面的链接了解更多 hof 相关的内容:

https://github.com/hofstadter-io/hof

https://docs.hofstadter.io

也有许多 hofmod 的仓库用于生成 CLI、API 以及更多其他内容,

hofmod 和 hof 工具的分离意味着你可以创建你自己的而不需要修改我们的代码。

因为它们也是 CUE 的模块,所以你可以使用 CUE 的所有功能,也可以引用它们来重用并扩展你自己的生成器和项目。

CUE 脚本

模版

Hofstadter CUE 支持和培训

发布时间: 2025-04-25

编辑本页

创建页面 issue

创建项目 issue

我们绝不会将你的邮箱分享给任何人。