Skip to content

Commit

Permalink
docs/tour/expressions: simplicity and tone edit
Browse files Browse the repository at this point in the history
See previous commit for context.

Page-specific notes:

* operators:
  - point to other docs for integer division and operator precedence
* interpolation:
  - include multi-line string example for completeness
* dynamic-fields (renamed from interpolfield):
  - align page title and path with spec ("dynamic fields")
  - include pointer to explanation of how generated fields can be
    referenced
  - amend example to demonstrate references to dynamic fields
* conditional:
  - remove "single field" limitation
  - remove evaluation failure prediction; allow cue error message to
    explain it
  - polish example; use multiple files for the first time, which
    required explanation
* listcomp:
  - expand example to show off single-/multi-line, let declarations, and
    nesting
* fieldcomp:
  - reference other pages so prose doesn't need to be repeated
  - replace and expand example
* query-projection: [new page]
  - demonstrate querying and projecting data using comprehensions
* regexp:
  - give more hints as to what "unary" means, for the less CompSci-aware
    reader
  - self-explanatory example definition names
  - link to pkg/regexp and RE2 for reference
* coalesce:
  - incorporate jba's in-page feedback
  - make example clearer

For cue-lang/docs-and-content#78

Preview-Path: /docs/tour/expressions/operators/
Preview-Path: /docs/tour/expressions/interpolation/
Preview-Path: /docs/tour/expressions/interpolfield/
Preview-Path: /docs/tour/expressions/conditional/
Preview-Path: /docs/tour/expressions/listcomp/
Preview-Path: /docs/tour/expressions/fieldcomp/
Preview-Path: /docs/tour/expressions/query-projection/
Preview-Path: /docs/tour/expressions/regexp/
Preview-Path: /docs/tour/expressions/coalesce/
Signed-off-by: Jonathan Matthews <github@hello.jonathanmatthews.com>
Change-Id: I065af2bb41cfe7ca4534cfafc625ac3bdf17a412
Reviewed-on: https://review.gerrithub.io/c/cue-lang/cuelang.org/+/1177830
Reviewed-by: Paul Jolly <paul@myitcv.io>
TryBot-Result: CUEcueckoo <cueckoo@gmail.com>
  • Loading branch information
jpluscplusm committed Mar 19, 2024
1 parent 501f81c commit 4eb5826
Show file tree
Hide file tree
Showing 32 changed files with 726 additions and 347 deletions.
62 changes: 29 additions & 33 deletions content/docs/tour/expressions/coalesce/en.md
@@ -1,44 +1,40 @@
---
title: "Null Coalescing"
title: Null Coalescing
weight: 80
---

<!-- jba: the terms here are confusing. "Null coalescing" is actually not
that, but then there is something called "actual null coalescing."
Just say that because _|_ | X evaluates to X, you can use disjunction
to represent fallback values.
And then you can use that to effectively type-check with a default value.
-->
**Null coalescing** is a technique that allows your CUE to evaluate successfully,
despite data having invalid, unexpected, or missing values.
By "null coalescing", we really mean error (or bottom) coalescing.

With null coalescing we really mean error, or bottom, coalescing.
The defaults mechanism for disjunctions can also be
used to provide fallback values in case an expression evaluates to bottom.
It uses a disjunction's default marker (`*`) to prefer the value of an
expression that *might* evaluate to bottom (`_|_`),
alongside an alternative, fallback value that the disjunction will select if
the expression *does* produce bottom.
This isn't a separate language feature, but is the expected outcome from CUE's
design that `_|_ | value` evaluates to `value`.

In the example the fallback values are specified
for `a` and `b` in case the list index is out of bounds.
This technique can guard against situations such as list indexes being out of
bounds, and type checks, with a fallback in the case of a type mismatch.

To do actual null coalescing one can unify a result with the desired type
to force an error.
In that case the default will be used if either the lookup fails or
the result is not of the desired type.
{{{with code "en" "tour"}}}
exec cue eval -c file.cue
cmp stdout out
-- file.cue --
#pets: ["Cat", "Mouse", "Dog"]

{{{with code "en" "coalesce"}}}
exec cue eval coalesce.cue
cmp stdout result.txt
-- coalesce.cue --
list: ["Cat", "Mouse", "Dog"]
// Guard against out of bounds list indexes.
pet0: *#pets[0] | "Pet not found"
pet5: *#pets[5] | "Pet not found"

a: *list[0] | "None"
b: *list[5] | "None"
#nums: [7, "8", "9"]

n: [null]
v: *(n[0] & string) | "default"
-- result.txt --
list: ["Cat", "Mouse", "Dog"]
a: "Cat"
b: "None"
n: [null]
v: "default"
// Perform a type check.
num0: *(#nums[0] & int) | "Not an integer"
num1: *(#nums[1] & int) | "Not an integer"
-- out --
pet0: "Cat"
pet5: "Pet not found"
num0: 7
num1: "Not an integer"
{{{end}}}
2 changes: 1 addition & 1 deletion content/docs/tour/expressions/coalesce/gen_cache.cue
Expand Up @@ -8,7 +8,7 @@ package site
page: {
cache: {
code: {
coalesce: "b+Ud+bRpYtj3i2IR7idusDqGDCG98pmn7Ucnz1PJwNI="
tour: "htSQvKFLSvKdz5tpKoLTTce41H42Ygz+RCnPYS3JdWc="
}
}
}
Expand Down
39 changes: 23 additions & 16 deletions content/docs/tour/expressions/conditional/en.md
@@ -1,27 +1,34 @@
---
title: "Conditional Fields"
weight: 60
title: Conditional Fields
weight: 40
---

Field comprehensions can also be used to
add a single field conditionally.
Field comprehensions can be used to add fields conditionally.

Converting the resulting configuration to JSON results in an error
as `justification` is required yet no concrete value is given.
{{< info >}}
When `cue export` processes multiple files it *unifies* their contents.
The value of the `price` field in `stock.yaml` is available inside `file.cue`,
and triggers the conditional inclusion of the required fields.
{{< /info >}}

{{{with code "en" "conditional"}}}
exec cue eval conditional.cue
cmp stdout result.txt
-- conditional.cue --
{{{with code "en" "tour"}}}
! exec cue export file.cue stock.yaml
cmp stderr out
-- file.cue --
price: number

// Require a justification if price is too high
// High prices require a reason and the name of
// the authorising person.
if price > 100 {
justification: string
reason!: string
authorisedBy!: string
}

-- stock.yaml --
price: 200
-- result.txt --
justification: string
price: 200
-- out --
authorisedBy: field is required but not present:
./file.cue:5:1
reason: field is required but not present:
./file.cue:5:1
{{{end}}}

2 changes: 1 addition & 1 deletion content/docs/tour/expressions/conditional/gen_cache.cue
Expand Up @@ -8,7 +8,7 @@ package site
page: {
cache: {
code: {
conditional: "+sq4Y79wIorrtrIx4PwN4ALZ0LOAZsLx/mfbnjJijj0="
tour: "OPztENE7KuLzMGw7Ep2u2VXHhTTTMtO9/KEwInHDEoo="
}
}
}
Expand Down
50 changes: 50 additions & 0 deletions content/docs/tour/expressions/dynamic-fields/en.md
@@ -0,0 +1,50 @@
---
title: Dynamic Fields
weight: 30
aliases:
- interpolfield
---

A **dynamic field** is a field whose name, or *label*, is determined by
an expression wrapped in parentheses
or through string interpolation:
`(a + b)` or `"\(a + b)"`.

A dynamic field's identifier is not available in the scope in which the field is defined.\
Referencing dynamic fields needs to be done using
[selectors, index expressions]({{< relref "docs/tour/references/selectors" >}}),
or [aliases]({{< relref "docs/tour/references/aliases" >}}).

{{{with code "en" "tour"}}}
exec cue eval file.cue
cmp stdout out
-- file.cue --
a: "foo"
b: "bar"
(a + b): "foobar"

s: X={
"\(a)_and_\(b)": "foobar"

// Valid references using a selector and
// an index expression.
FooAndBar: s.foo_and_bar
FooAndBar: X["foo_and_bar"]

// Invalid reference because the
// indentifer is not in scope.
//FooAndBar: foo_and_bar
}

// Valid reference using an index expression.
FooAndBar: s["foo_and_bar"]
-- out --
a: "foo"
b: "bar"
s: {
foo_and_bar: "foobar"
FooAndBar: "foobar"
}
foobar: "foobar"
FooAndBar: "foobar"
{{{end}}}
Expand Up @@ -4,11 +4,11 @@ package site
docs: {
tour: {
expressions: {
interpolfield: {
"dynamic-fields": {
page: {
cache: {
code: {
genfield: "ceE35p/M7uGYq1YGVtx3ezq1Y/FWZRiblUrV095K4jE="
tour: "eGgmZFfyWljBxXApr9+GwG5DU/ZqU2OKg0++i9QQW1I="
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions content/docs/tour/expressions/dynamic-fields/page.cue
@@ -0,0 +1,3 @@
package site

content: docs: tour: expressions: "dynamic-fields": page: _
91 changes: 61 additions & 30 deletions content/docs/tour/expressions/fieldcomp/en.md
@@ -1,42 +1,73 @@
---
title: "Field Comprehensions"
weight: 50
title: Field Comprehensions
weight: 60
---

CUE also supports comprehensions for fields.
Fields can be specified using **field comprehensions**.

One cannot refer to generated fields with references.
Instead, one must use indexing.
Just like
[list comprehensions]({{< relref "listcomp" >}}), they use
`for` loops, `if` guards, and `let` declarations,
combined in any order.

{{{with code "en" "fieldcomp"}}}
exec cue eval -c fieldcomp.cue
cmp stdout result.txt
-- fieldcomp.cue --
Because field comprehensions specify
[dynamic fields]({{< relref "dynamic-fields" >}}),
these fields can't be referenced directly
and need to be accessed using
[selectors, index expressions]({{< relref "docs/tour/references/selectors" >}}),
or [aliases]({{< relref "docs/tour/references/aliases" >}}).

{{{with code "en" "tour"}}}
exec cue eval -c file.cue
cmp stdout out
-- file.cue --
import "strings"

#a: ["Barcelona", "Shanghai", "Munich"]
#censusData: [
{name: "Kinshasa", pop: 16_315_534},
{name: "Lagos", pop: 15_300_000},
{name: "Cairo", pop: 10_100_166},
{name: "Giza", pop: 9_250_791},
]

for k, v in #a {
"\( strings.ToLower(v) )": {
pos: k + 1
name: v
nameLen: len(v)
// city maps from a city's name to its details.
city: {
for index, value in #censusData
let lower = strings.ToLower(value.name) {
"\(lower)": {
population: value.pop
name: value.name
position: index + 1
}
}
}
-- result.txt --
barcelona: {
pos: 1
name: "Barcelona"
nameLen: 9
}
shanghai: {
pos: 2
name: "Shanghai"
nameLen: 8
}
munich: {
pos: 3
name: "Munich"
nameLen: 6

// References via selector and index expression.
gizaPopulation: city.giza.population
cairoPopulation: city["cairo"].population
-- out --
city: {
kinshasa: {
population: 16315534
name: "Kinshasa"
position: 1
}
lagos: {
population: 15300000
name: "Lagos"
position: 2
}
cairo: {
population: 10100166
name: "Cairo"
position: 3
}
giza: {
population: 9250791
name: "Giza"
position: 4
}
}
gizaPopulation: 9250791
cairoPopulation: 10100166
{{{end}}}
2 changes: 1 addition & 1 deletion content/docs/tour/expressions/fieldcomp/gen_cache.cue
Expand Up @@ -8,7 +8,7 @@ package site
page: {
cache: {
code: {
fieldcomp: "KJxqeh4j0LX+g5W7+soUPtnZQWCod2sFitORzA8CuU0="
tour: "HjqyBNERg6j5/P1yIKbncqrpEzyzXd/hYK5dg8lN4w8="
}
}
}
Expand Down
39 changes: 26 additions & 13 deletions content/docs/tour/expressions/interpolation/en.md
@@ -1,23 +1,36 @@
---
title: "Interpolation"
title: Interpolation
weight: 20
---

String and bytes literals support interpolation.
String and bytes literals support **interpolation**,
in both their single- and multi-line forms.

Any valid CUE expression may be used inside the escaped parentheses.
Interpolation may also be used in multiline string and byte literals.
Any valid CUE expression may be used inside escaped parentheses.

{{{with code "en" "interpolation"}}}
exec cue eval interpolation.cue
cmp stdout result.txt
-- interpolation.cue --
"You are \( #cost-#budget ) dollars over budget!"
{{{with code "en" "tour"}}}
exec cue export file.cue --out yaml
cmp stdout out
-- file.cue --
m: "You are \(#cost-#budget) dollars over budget!"
email: """
Here is a message from the finance team:

\(m)

Regards,
Your friends on the 12th floor
"""

#cost: 102
#budget: 88
-- result.txt --
"You are 14 dollars over budget!"
#cost: 102
#budget: 88
-- out --
m: You are 14 dollars over budget!
email: |-
Here is a message from the finance team:

You are 14 dollars over budget!

Regards,
Your friends on the 12th floor
{{{end}}}
2 changes: 1 addition & 1 deletion content/docs/tour/expressions/interpolation/gen_cache.cue
Expand Up @@ -8,7 +8,7 @@ package site
page: {
cache: {
code: {
interpolation: "vXR3q5GjKYJl3AO3qThnTSpoJQm6PKz8WfidL0hPE8w="
tour: "i6ersAk2x5CtPH+6A5oB1wjVsEq4oY+lXgbqsm1+9vs="
}
}
}
Expand Down

0 comments on commit 4eb5826

Please sign in to comment.