概要
CUE言語というのを最近知ったので、試しにCUEを使ってユーザーとグループのyamlファイルを作成してみます。CUE言語はjsonのスーパーセットという位置付けです。yamlも出力できますし、バリデーションも行うことができます。
公式サイトやチュートリアル
公式
Cuetorialsというチュートリアルサイトにいろいろテクニックが記述されています。基本的な使い方は公式サイトを見て、こちらでテクニカルな使い方を探すのが良いでしょう。
このサイトは非公式なのでしょうか。ちょっとわかりません。
プログラム
構成
cue
├── groups.cue
└── users.cue
ソース
package directory
#prefectures_constraints: "北海道"|"青森県"|"岩手県"|"宮城県"|"秋田県"|"山形県"|"福島県"|"茨城県"|"栃木県"|"群馬県"|"埼玉県"|"千葉県"|"東京都"|
"神奈川県"|"新潟県"|"富山県"|"石川県"|"福井県"|"山梨県"|"長野県"|"岐阜県"|"静岡県"|"愛知県"|"三重県"|"滋賀県"|"京都府"|"大阪府"|"兵庫県"|"奈良県"|
"和歌山県"|"鳥取県"|"島根県"|"岡山県"|"広島県"|"山口県"|"徳島県"|"香川県"|"愛媛県"|"高知県"|"福岡県"|"佐賀県"|"長崎県"|"熊本県"|"大分県"|"宮崎県"|"鹿児島県"|"沖縄県"
#User: {
first_name!: string
last_name!: string
name: string | *"\(first_name) \(last_name)"
email: string
date_of_birth: =~"[0-9]{8}"
prefectures: #prefectures_constraints
}
users: [...#User] & _data
_data: [
{
name: "ウルシバタ"
first_name: "Shinya"
last_name: "Urushibata"
email: "urushibata@example.com"
date_of_birth: "19000101"
prefectures: "東京都"
},
{
name: "開発 太郎"
first_name: "太郎"
last_name: "開発"
email: "t-kaihatu@exsample.com"
date_of_birth: "19990919"
prefectures: "大阪府"
},
{
name: "営業 花子"
first_name: "花子"
last_name: "営業"
email: "h-eigyo@exsample.com"
date_of_birth: "20000101"
prefectures: "北海道"
},
{
first_name: "Thomas"
last_name: "Platz"
email: "tom@exsample.com"
date_of_birth: "19700801"
prefectures: "バージニア州"
},
]
package directory
#Group: {
name: string
description?: string
}
groups: [...#Group] & [
{
name: "営業部"
},
{
name: "DX部"
},
{
name: "開発部"
},
]
説明
プログラムで使っている文法など説明します。
package
CUEでは通常1ファイル単位で扱われますが、package
句を使うことで同じパッケージ名のファイルを1つのファイルとして扱うことができます。1つのディレクトリでパッケージ名を複数定義することはできません。例えば、package directory
とpackage directory2
を同じ階層のファイルに定義するとエラーとなります。
$ cue export
found packages "directory2" (group.cue) and directory (users.cue) in "/home/s-urushibata/work/terraform/cue"
Definitions
フィールドの先頭に#
を付けるとDefinitions
になります。Definitions
で定義した部分はファイルに出力されません。オブジェクト指向言語で言うところのクラスのようなイメージです。
#User: {
first_name!: string
last_name!: string
name: string | *"\(first_name) \(last_name)"
email: string
date_of_birth: =~"[0-9]{8}"
prefectures: _#prefectures_constraints
}
usersフィールドは#User
の配列といったように使用します。
users: [...#User]
Constraints
フィールドの型や許可する値の制約を指定できます。今回は使用していませんが、int
などの数値型も指定できます。
//文字列で必須。フィールド名の後ろに"!"を付けると必須になります。
first_name!: string
last_name!: string
//文字列で未設定の場合、"first_name last_name"を自動設定します。
//"|"はORです。ORで複数定義した場合、"*"が付いたものをデフォルト値として指定できます。
name: string | *"\(first_name) \(last_name)"
//=~で正規表現を使用できます。
date_of_birth: =~"[0-9]{8}"
//#Userの外で定義したをDefinitionsを指定できます。
prefectures: #prefectures_constraints
//フィールドを省略できます(オプショナル)。フィールド名の後ろに"?"を付けます。
description?: string
hidden (definition)
_data
のように先頭の文字をアンダーバーにするとhidden項目となり、ファイルに出力されなくなります。もしこれにアンダーバーを付けない場合、代入先のusers
とdata
で同じ内容が2つ出力されることになります。
users: [...#User] & _data
_data: [
{
...
エクスポート
それでは出力してみます。デフォルトではjsonで出力されるので、--out yaml
を指定します。
$ cue export --out yaml
users.3.prefectures: 47 errors in empty disjunction:
users.3.prefectures: conflicting values "三重県" and "バージニア州":
./users.cue:4:124
./users.cue:13:17
./users.cue:16:9
./users.cue:16:12
./users.cue:16:21
./users.cue:51:18
...
users.3.prefectures: conflicting values "鹿児島県" and "バージニア州":
./users.cue:5:196
./users.cue:13:17
./users.cue:16:9
./users.cue:16:12
./users.cue:16:21
./users.cue:51:18
4人目の都道府県がバージニア州となっているのでエラーとなりました。修正して再実行します。
$ cue export --out yaml
users:
- name: ウルシバタ
first_name: Shinya
last_name: Urushibata
email: urushibata@example.com
date_of_birth: "19000101"
prefectures: 東京都
- name: 開発 太郎
first_name: 太郎
last_name: 開発
email: t-kaihatu@exsample.com
date_of_birth: "19990919"
prefectures: 大阪府
- name: 営業 花子
first_name: 花子
last_name: 営業
email: h-eigyo@exsample.com
date_of_birth: "20000101"
prefectures: 北海道
- first_name: Thomas
last_name: Platz
name: Thomas Platz
email: tom@exsample.com
date_of_birth: "19700801"
prefectures: 鹿児島県
groups:
- name: 営業部
- name: DX部
- name: 開発部
出力されました。
感想
都道府県のエラーですが、ORを使ってしまうとORの個数分(47件)がエラーになってしまうのはちょっと使いずらいかなと思いました。ORの個数が多い場合は、正規表現の方が良いかもしれません。
文法も簡単ですし、これは便利だと感じました。但し、まだバージョンが0.8なので本格導入するかは迷いますね。よく比較されるjsonnetを試してみた方がいいのかなぁと思いました。