1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
| 通常,将Jsonnet对象看作一叠layers很有用。图层由字段组成。对象文字或对象理解是单层对象。对象继承A+B创建一个新的对象,该对象的B层位于顶层之上A。
对字段的引用self对应于从堆栈的顶部开始向底部寻找字段,直到找到该字段为止。通过super搜索从当前图层下面的图层开始的字段进行引用。 $ cat>test.jsonnet<<EOF local base = { f: 2, g: self.f + 100, }; base + { f: 5, old_f: super.f, old_g: super.g, } EOF $ jsonnet test.jsonnet { "f": 5, "g": 105, "old_f": 2, "old_g": 105 }
# 有时候我们希望一个对象中的字段在进行组合时不要 # 覆盖父对象中的字段, 而是与相同的字段继续进行组合
# 这时可以用 +: 来声明这个字段 (+:: 与 +: 的含义相同, # 但与 :: 一样的道理, +:: 定义的字段是隐藏的)
local Base = { f: 2, g: self.f + 100, };
local WrapperBase = { Base: Base, };
{ Derived: Base + { f: 5, old_f: super.f, old_g: super.g, }, WrapperDerived: WrapperBase + { Base+: { f: 5, c: 4 }, }, }
# output
{ "Derived": { "f": 5, "g": 105, "old_f": 2, "old_g": 105 }, "WrapperDerived": { "Base": { "c": 4, "f": 5, "g": 105 } } }
# 对于 JSON Object, 我们更希望进行组合而非覆盖, 因此在定义 Object # 字段时, 很多库都会选择使用 +: 和 +::, 但我们也要注意不能滥用 $ cat>test.jsonnet<<EOF local child = { override: { x: 1, }, composite+: { x: 1, }, }; { override: { y: 5, z: 10 }, composite: { y: 5, z: 10 }, } + child EOF $ jsonnet test.jsonnet { "composite": { "x": 1, "y": 5, "z": 10 }, "override": { "x": 1 } }
# 库与 import: # jsonnet 共享库复用方式其实就是将库里的代码整合到当前文件中来, # 引用方式也很暴力, 使用 -J 参数指定 lib 文件夹, 再在代码里 import 即可
# jsonnet 约定库文件的后缀名为 .libsonnet $ mkdir some-path $ cat>some-path/mylib.libsonnet<<EOF { newVPS(ip, region='cn-hangzhou', distribution='CentOS 7', cpu=4, memory='16GB'):: { ip: ip, distribution: distribution, cpu: cpu, memory: memory, vendor: 'Alei Cloud', os: 'linux', packages: [], install(package):: self + { packages+: [package], }, } } EOF $ cat>test.jsonnet<<EOF local vpsTemplate = import 'some-path/mylib.libsonnet'; vpsTemplate .newVPS(ip='10.10.44.144', cpu=8, memory='32GB') .install('docker') .install('jsonnet') EOF $ jsonnet -J . test.jsonnet { "cpu": 8, "distribution": "CentOS 7", "ip": "10.10.44.144", "memory": "32GB", "os": "linux", "packages": [ "docker", "jsonnet" ], "vendor": "Alei Cloud" }
# 上面这种 Builder 模式在 jsonnet 中非常常见, # 也就是先定义一个构造器, 构造出基础对象然后用各种方法进行修改. # 当对象非常复杂时, 这种模式比直接覆盖父对象字段更易维护
|