YS DRY
My friend Vadim Bauer
filed this GitHub issue
for the
helm-unittest
project, to
DRY (don't repeat yourself) out some of the repetitive test data.
He also pinged me to weigh in, so I decided to do that in this post!
Simplifying repetitive YAML is what YS was made for. Well, one of many things; but let's focus on that today.
Vadim proposed taking existing YAML data files and using YS variables to define repeated data once, then referring to it in the places it is needed. Solid idea.
Let's use a very simple example here for brevity sake. I'll leave it to you to expand the concepts to your soaking wet YAML files.
# example.yaml
people:
- name: Alice
likes:
- programming
- security
hates:
- bugs
- repetition
- name: Bob
likes:
- programming
- security
hates:
- bugs
- repetition
Vadim's approach:
# example1.ys
!ys-0 # Start YAML file in YS code mode
# Define vars:
likes-these =:: # likes-these is a var. :: needed to put value in data mode
- programming
- security
hates-these =:: # 'data mode' means normal YAML semantics (not code)
- bugs
- repetition
=>::
people:
- name: Alice
likes:: likes-these # Here :: toggles to code mode (a var)
hates:: hates-these
- name: Bob
likes:: likes-these
hates:: hates-these
I'll run this command to see if it works:
$ diff -u example.yaml <(ys -Y example1.ys) && echo OK
OK
It works!
Let's ignore for a minute the .ys file is bigger and more complicated than the .yaml file.
As we will see there are many ways to do this with YS.
One problem with this first approach is that we had to indent all our original
YAML under the => :: to get from code mode to data mode.
It would be nicer if we didn't need to change the original data much.
Some readers might be thinking, why not use YAML anchors and aliases. Let's try that…
# example2.yaml
vars:
- &likes-these
- programming
- security
- &hates-these
- bugs
- repetition
people:
- name: Alice
likes: *likes-these
hates: *hates-these
- name: Bob
likes: *likes-these
hates: *hates-these
That looks nicer. No extra indenting. We added a vars section with anchors on the reusable things.
Does it work?
$ diff -u example.yaml <(ys -Y example2.yaml) && echo OK
--- example.yaml 2026-06-17 06:59:16.545403994 -0400
+++ /dev/fd/63 2026-06-17 07:15:45.677692380 -0400
@@ -1,3 +1,8 @@
+vars:
+- - programming
+ - security
+- - bugs
+ - repetition
people:
- name: Alice
likes:
shell returned 1
Not quite. The constant problem with YAML's anchor alias feature is that there's no good place to define things to be used later without making them also be part of your data.
Hmmm… What if we put the definitions in a separate YAML document? Remember, YAML allows files with multiple documents.
# example3.yaml
vars:
- &likes-these
- programming
- security
- &hates-these
- bugs
- repetition
---
people:
- name: Alice
likes: *likes-these
hates: *hates-these
- name: Bob
likes: *likes-these
hates: *hates-these
If we can load the final document then this looks like it should work. YS does load the last document so let's try it out:
$ diff -u example.yaml <(ys -Y example3.yaml) && echo OK
Error: 1 Anchor not found: &likes-these
--- example.yaml 2026-06-17 06:59:16.545403994 -0400
+++ /dev/fd/63 2026-06-17 07:24:55.183089916 -0400
@@ -1,15 +0,0 @@
-people:
-- name: Alice
- likes:
- - programming
- - security
- hates:
- - bugs
- - repetition
-- name: Bob
- likes:
- - programming
- - security
- hates:
- - bugs
- - repetition
shell returned 1
Bummer! It didn't find the anchor.
The reason is that the YAML spec says that aliases can only refer to anchors that are defined before it in the same document.
We were breaking the law.
Can YAMLScript help us out here? I think it can!
# example4.ys
!ys-0:
vars:
- &likes-these
- programming
- security
- &hates-these
- bugs
- repetition
--- !ys:
people:
- name: Alice
likes: *likes-these
hates: *hates-these
- name: Bob
likes: *likes-these
hates: *hates-these
We just tagged the first doc with !ys-0:.
The extra : means start in data mode.
Then we tagged the second doc with !ys:.
Also data mode.
$ diff -u example.yaml <(ys -Y example4.ys) && echo OK
OK
Works!
YS knows the value of cross document referencing.
It obeys the YAML laws for existing YAML files.
But it changes the YAML laws (in small useful ways) when you turn on !ys.
Note: I've been using
.ysand.yamlextensions on the example files. This was just for clarity.ysdoesn't care about file extensions.
Let's go back to YS variables using multiple docs:
# example5.ys
!ys-0
likes-these =::
- programming
- security
hates-these =::
- bugs
- repetition
--- !ys:
people:
- name: Alice
likes:: likes-these
hates:: hates-these
- name: Bob
likes:: likes-these
hates:: hates-these
We start the first doc in code mode to define the vars.
$ diff -u example.yaml <(ys -Y example5.ys) && echo OK
OK
Still works and cleaner.
Can we put variables in another file? Certainly!
# vars.ys
!ys-0
likes-these =::
- programming
- security
hates-these =::
- bugs
- repetition
# example6.ys
!ys-0
load: 'vars.ys'
--- !ys:
people:
- name: Alice
likes:: likes-these
hates:: hates-these
- name: Bob
likes:: likes-these
hates:: hates-these
$ diff -u example.yaml <(ys -Y example6.ys) && echo OK
OK
We can even do this in one document:
# example7.ys
!ys-0:
=>:
load: 'vars.ys'
people:
- name: Alice
likes:: likes-these
hates:: hates-these
- name: Bob
likes:: likes-these
hates:: hates-these
YS has a special feature when you start in data mode and the first key is =>
then its value is code.
You can load files, define vars and functions etc.
Speaking of functions, load is a YS standard library function.
There are 100s more.
Can we use them in this example?
Definitely!
# example8.ys
!ys-0:
=>: load('vars.ys')
people:
- name: Alice
likes:: likes-these:reverse
hates:: hates-these + 'birds'
- name: Bob
likes:: sort(likes-these + 'repositories')
hates:: hates-these.take(1)
Let's see what we get:
$ ys -Y example8.ys
people:
- name: Alice
likes:
- security
- programming
hates:
- bugs
- repetition
- birds
- name: Bob
likes:
- programming
- repositories
- security
hates:
- bugs
Fun!
I'll stop here for now. There's a lot more I could say wrt to that issue and different way that YS could be wired into helm-unittest.
Vadim… Maybe we could work on a PR together! helm-unittest.