生成配置



CUE 有些灵感来源于函数式语言,然后有很多功能在我们写生成大量配置或数据的"代码"时非常有用。

当你融会贯通连接符、默认值以及条件保护之后,它们都将是你写 CUE 时非常有用的工具。

你可以在 patterns section 这一节找到更多例子。

List 和 Field 推导

List 和 field 推导可以让我们迭代一个 可迭代的对象 ,然后生成新的 list 或 field。

可迭代的对象是已存在的 list 或 struct 的 field。

import "strings"

band: {
	name: "Led Zeppelin"

	// List comprehension
	selfTitled: [ for i, I in _selfIndexAlbums {title: "\(name) \(I)"}]
	// nested list comprehension
	allAlbums: [
		for I in _selfIndexAlbums {title: "\(name) \(I)"},
		for N in _namedAlbums {title:     "\(N)"},
	]

	Albums: {
		// Field comprehension 
		for key, val in allAlbums {
			"\(strings.TrimSpace(val.title))": {
				pos:      key
				artist:   name
				title:    strings.TrimSpace(val.title)
				titleLen: len(val.title)
			}
		}
	}

	// Hidden fields
	_selfIndexAlbums: ["", "II", "III", "IV"]
	_namedAlbums: [
		"Houses of the Holy",
		"Physical Graffiti",
		"Presence",
		"In Through the Out Door",
		"Coda",
	]
}

我们之前已经介绍过文件中的一些用法:

  • list 推导: [ for key, val in iterable { ... } ],可以不使用 key,只用 value。
  • field 推导:[ for key, val in iterable { ... }],我们调用内置的函数插入一个 field,注意要用双引号包裹。
  • 字符串插入:"(<a cue expression)"`,这是基于 Swift 的字符串插入,而且当你想要兼容 JSON 时,这个是唯一的机制。
  • 隐藏字段:_hidden: "I'm hidden" 以下划线开头,CUE 也有隐藏定义 (_#
band:
  name: Led Zeppelin
  selfTitled:
  - title: 'Led Zeppelin '
  - title: Led Zeppelin II
  - title: Led Zeppelin III
  - title: Led Zeppelin IV
  allAlbums:
  - title: 'Led Zeppelin '
  - title: Led Zeppelin II
  - title: Led Zeppelin III
  - title: Led Zeppelin IV
  - title: Houses of the Holy
  - title: Physical Graffiti
  - title: Presence
  - title: In Through the Out Door
  - title: Coda
  Albums:
    Led Zeppelin:
      pos: 0
      artist: Led Zeppelin
      title: Led Zeppelin
      titleLen: 13
    Led Zeppelin II:
      pos: 1
      artist: Led Zeppelin
      title: Led Zeppelin II
      titleLen: 15
    Led Zeppelin III:
      pos: 2
      artist: Led Zeppelin
      title: Led Zeppelin III
      titleLen: 16
    Led Zeppelin IV:
      pos: 3
      artist: Led Zeppelin
      title: Led Zeppelin IV
      titleLen: 15
    Houses of the Holy:
      pos: 4
      artist: Led Zeppelin
      title: Houses of the Holy
      titleLen: 18
    Physical Graffiti:
      pos: 5
      artist: Led Zeppelin
      title: Physical Graffiti
      titleLen: 17
    Presence:
      pos: 6
      artist: Led Zeppelin
      title: Presence
      titleLen: 8
    In Through the Out Door:
      pos: 7
      artist: Led Zeppelin
      title: In Through the Out Door
      titleLen: 23
    Coda:
      pos: 8
      artist: Led Zeppelin
      title: Coda
      titleLen: 4

连接符 和 默认值

我们已经知道如何在验证中使用连接符了,你也可以在生成 value 和配置的时候使用它们。

#labels: [string]: string

#metadata: {
	name: string
	// we can explicitly prevent namespace by commenting it out and ensuring this definition is closed
	// namespace?: string
	labels: #labels
	annotations?: [string]: string
}

// require the following keys for labels
#requiredLabels: #labels & {
	app:  string
	env:  string
	team: string
}

// for env, limit the choices and default to dev with '*'
#defaultLabels: #requiredLabels & {
	env: *"dev" | "stg" | "prd"
}

// set concrete values to be reused
#myLabels: #defaultLabels & {
	app:  "cuetorials"
	team: "hofstadter"
}

// our Kubernetes definitions from before
#Schema: #Deployment | #Service | #Ingress

// Additionally apply our labels buildup to the resources
#Schema: {
	metadata: #metadata & {
		labels: #myLabels
	}
}

#Deployment: {
	apiVersion: "apps/v1"
	kind:       "Deployment"
	...
}

#Service: {
	apiVersion: "v1"
	kind:       "Service"
	...
}

#Ingress: {
	apiVersion: "extensions/v1beta1"
	kind:       "Ingress"
	...
}

条件守卫

CUE 有个 if 声明,被称为 守卫 ,用于保护某个代码区块。

这不是条件分支,而是包含或者排除某些 CUE 代码的一种方法,

回想一下,CUE 是 图灵非完备 的,因此没有循环或条件分支的概念。

guards.cue

// use if guard to get even numbers in a list comprehension
nums: [1, 2, 3, 4, 5, 6, 7, 8]
sqrs: [ for n in nums if mod(n, 2) == 0 {n * n}]

// use if guard to conditionally add fields
elems: [
	{name: "a", public: true},
	{name: "b", public: true},
	{name: "c", public: false},
	{name: "d"},
]

Elems: {
	hasPublicField: {
		for key, val in elems {
			// test against _|_ to see if a field exists
			if val.public != _|_ {
				"\(key)": val
			}
		}
	}
	stringifyPublic: {
		for key, val in elems {

			// there is no short-circuit, so we must nest guard instead
			if val.public != _|_ {

				// test conjunctions not equal to bottom for "truthiness"
				if (val.public & true) != _|_ {
					"\(key)": val & {PUB: "true"}
				}

				// note, there is no "else" clause
				if (val.public & false) != _|_ {
					"\(key)": val & {PUB: "false"}
				}
			}
		}
	}
}

cue eval guards.cue

nums: [1, 2, 3, 4, 5, 6, 7, 8]
sqrs: [4, 16, 36, 64]
elems: [{
	name:   "a"
	public: true
}, {
	name:   "b"
	public: true
}, {
	name:   "c"
	public: false
}, {
	name: "d"
}]
Elems: {
	hasPublicField: {
		"0": {
			name:   "a"
			public: true
		}
		"1": {
			name:   "b"
			public: true
		}
		"2": {
			name:   "c"
			public: false
		}
	}
	stringifyPublic: {
		"0": {
			name:   "a"
			PUB:    "true"
			public: true
		}
		"1": {
			name:   "b"
			PUB:    "true"
			public: true
		}
		"2": {
			name:   "c"
			PUB:    "false"
			public: false
		}
	}
}

如何获取到所有 elems 包含 public 字段的元素?

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