Skip to content

Commit

Permalink
docs/tour/basics: simplicity and tone edit
Browse files Browse the repository at this point in the history
This and the following ~4 changes each revise one section of the
language tour. Their focus is on improving each page's approachability
and clarity for the non-technical newcomer.

They prioritise making the tour suitable for folks who are evaluating
CUE solely on the basis of reading that portion of the front page that
sits before the link to this tour, who left the front page upon reaching
that link, and are experiencing the tour having never read any other
site pages or seen any CUE before.

As a baseline, in pursuit of that aim, these changes revise and reword
most pages' prose and tone, and also modify the code examples by:

- eliminating the "result.txt" header on the right-hand side
- moving to TERMINAL blocks on the right-hand side, wherever visibility
  of the command being executed feels like it benefits the reader
- adding and expanding inline comments where they help clarify the code,
  especially if the code were being read in isolation by prose-averse
  users

Page-specific notes:

* json-superset:
  - include mention of field labels and values
  - introduce tour examples with info block
  - code comments added for unquoted field names
  - field names with capitals included to expand visibility of unquoted
    field name characteristics
  - struct added so curly braces are present, to help make sure the
    "outermost curly braces" convenience is contextualised
  - math stdlib import is included to allow this very first piece of CUE
    seen on the tour to whet the appetite of the reader as to its
    capabilities, but in a way which is believed trivially
    understandable even before imports/functions/etc are explained
  - cue command includes the unnecessary `--out json` to make it clear
    and explicit that the reader is viewing JSON
* types-are-values:
  - page title brought into prose to make it more obvious
  - linking prose added between first paragraph and examples
  - examples are re-ordered to flow more naturally from least to most
    specific constraints, which allows the second half of the page to be
    tidied up
  - larger capital city selected for data example
* duplicate-fields:
  - add simple discussion of unification, in a concrete data context, as
    we don't explicitly introduce it anywhere else
  - remove all mention of "duplicate" fields, except the page title, so
    we don't risk embedding the not-a-CUE--concept in readers'
    understanding
  - code example is expanded to demonstrate recursive unification in
    lists
* constraints:
  - introduce "&" operator
  - allow the example to do double duty: demo both explicit unification
    of types and values, and a field being templated
  - example's command updated to focus on the concrete data emission and
    its simpler specification
* definitions:
  - assorted tidyups
* validation:
  - introduce "cue vet"
  - assorted tidyups
* order-irrelevance:
  - linking order irrelevance back to duplicate fields helps to hint at
    CUE's firm theoretical basis
  - example field names altered to help them "pop" off the page better
* folding-structs:
  - change page title to reflect inclusion of two different syntaxes
  - lead the page with the a:b:c:value syntax
  - remove mention of JSON, as its comparison doesn't help the tour
    reader better understand /CUE/
  - demo mix of syntaxes
  - include a trivially-understood-in-context "fieldA:!fieldB" to whet
    the appetite for Things To Come, whilst allowing the point to be
    made that pattern constraints /aren't/ just single line constructs
    - this is needed because the single line form of a pattern
      constraint *also* needs to be shown

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

Preview-Path: /docs/tour/basics/json-superset/
Preview-Path: /docs/tour/basics/types-are-values/
Preview-Path: /docs/tour/basics/duplicate-fields/
Preview-Path: /docs/tour/basics/constraints/
Preview-Path: /docs/tour/basics/definitions/
Preview-Path: /docs/tour/basics/validation/
Preview-Path: /docs/tour/basics/order-irrelevance/
Preview-Path: /docs/tour/basics/folding-structs/
Signed-off-by: Jonathan Matthews <github@hello.jonathanmatthews.com>
Change-Id: Ibfd1a731131e181ee51d21d7ac3ce24a0c8ae8a8
  • Loading branch information
jpluscplusm committed Mar 19, 2024
1 parent 9190dd5 commit 338bbc8
Show file tree
Hide file tree
Showing 24 changed files with 516 additions and 358 deletions.
54 changes: 29 additions & 25 deletions content/docs/tour/basics/constraints/en.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,42 @@ title: Constraints
weight: 120
---

Constraints specify what values are allowed.
To CUE they are just values like anything else,
but conceptually they can be explained as something in between types and concrete values.
**Constraints** specify what values are allowed.
Constraints are values because
[all types are values]({{< relref "types-are-values" >}}).

Constraints can also reduce boilerplate.
If a constraint defines a concrete value, there is no need
to specify it in values to which this constraint applies.
Constraints can **reduce boilerplate** and simplify the specification of data.
If a constraint specifies a field then the field and its value are present
everywhere the constraint is unified, and don't need to be repeated.

{{{with code "en" "example"}}}
exec cue eval check.cue
cmp stdout result.txt
-- check.cue --
schema: {
In this example, the `cue export` output includes the data that Viola is a human.
This is because the `viola` field is specified as the unification of a struct
which declares Viola's name and age, and the `person` constraint which
additionally declares the `human` field.
This unification uses the **explicit unification operator `&`**.

{{{with code "en" "tour"}}}
exec cue export file.cue -e viola
cmp stdout out
-- file.cue --
person: {
name: string
age: int
human: true // always true
age: int & >=0
human: true // People are always humans
}

viola: schema
viola: {
viola: person & {
name: "Viola"
age: 38
}
-- result.txt --
schema: {
name: string
age: int
human: true
}
viola: {
name: "Viola"
age: 38
human: true
-- out --
{
"name": "Viola",
"age": 38,
"human": true
}
{{{end}}}

Unification succeeds because `person`'s `name` field constraint of `string`
doesn't conflict with the concrete value `"Viola"`, and `age`'s unified
constraint of `int & >=0` doesn't conflict with the value `38`.
2 changes: 1 addition & 1 deletion content/docs/tour/basics/constraints/gen_cache.cue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ package site
page: {
cache: {
code: {
example: "FDMAkkPUj9jo0U5gkFXtmB1zzgnkd73/OTjcMmPG1HE="
tour: "ReOt9QJDb8YuQvazgsaW7D1fZht0AkaepAyB1P8hZaM="
}
}
}
Expand Down
53 changes: 29 additions & 24 deletions content/docs/tour/basics/definitions/en.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,46 @@ title: Definitions
weight: 150
---

In CUE, schemas are typically written as Definitions.
A definition is a field which identifier starts with
`#` or `_#`.
This tells CUE that they are to be used for validation and should
not be output as data; it is okay for them to remain unspecified.
In CUE, schemas are typically written as **definitions**.
A definition is a field whose identifier starts with `#` or `_#`.

A definition also tells CUE the full set of allowed fields.
In other words, definitions define "closed" structs.
Including a `...` in struct keeps it open.
Because CUE knows that definitions are used for validation,
they aren't output as data.
It's normal for definitions to specify fields that don't have concrete values,
such as types.

{{{with code "en" "example"}}}
exec cue export schema.cue
cmp stdout result.txt
-- schema.cue --
A definition also tells CUE the complete set of allowed fields,
meaning that evaluations <!-- TODO: explain "evaluation" here, or before this point? Swap with "export"? -->
will fail if any additional fields are specified.
We say that such a definition defines a **closed** struct.
Including a `...` in a struct keeps it **open**.

{{{with code "en" "tour"}}}
! exec cue export file.cue
cmp stderr out
-- file.cue --
#Conn: {
address: string
port: int
protocol: string
// uncomment this to allow any field

// Uncomment this to allow any field.
// ...
}

lossy: #Conn & {
address: "1.2.3.4"
address: "203.0.113.42"
port: 8888
protocol: "udp"
// uncomment this to get an error
// foo: 2
}
-- result.txt --
{
"lossy": {
"address": "1.2.3.4",
"port": 8888,
"protocol": "udp"
}

// The timeout field is not specified in
// #Conn, and its presence causes an
// evaluation failure.
timeout: 30
}
-- out --
lossy.timeout: field not allowed:
./file.cue:1:8
./file.cue:10:8
./file.cue:18:2
{{{end}}}
2 changes: 1 addition & 1 deletion content/docs/tour/basics/definitions/gen_cache.cue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ package site
page: {
cache: {
code: {
example: "jrJjrL/H1/kD2J9fN3zSRjnsJXb9+pTa08Bnd8JXM8k="
tour: "VEjX3QIW/xrJbQ2SsaKLLy/dA18/wxgW+bbckZWOKGo="
}
}
}
Expand Down
53 changes: 29 additions & 24 deletions content/docs/tour/basics/duplicate-fields/en.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,37 @@ title: Duplicate Fields
weight: 90
---

CUE allows duplicated field definitions as long as they don't conflict.
CUE allows fields to be specified multiple times, so long as all the values
don’t conflict.
If the values don’t conflict we say they **unify** successfully.
**Unification** is the process of checking that values don't conflict,
and it happens implicitly whenever any field is redeclared.

For values of basic types this means they must be equal.
For concrete data, unification of basic types requires that
all values specified for a field must be equal.\
Within structs, fields are unified recursively.
Similarly, within lists, elements are unified recursively.

For structs, fields are merged and duplicated fields are handled recursively.
{{{with code "en" "tour"}}}
exec cue export file.cue --out yaml
cmp stdout out
-- file.cue --
A: 1
A: 1

For lists, all elements must match accordingly
<!-- ([we discuss open-ended lists later](/language-guide/data/lists/).) -->
B: {a: 2}
B: {b: 3}

{{{with code "en" "example"}}}
exec cue eval dup.cue
cmp stdout result.txt
-- dup.cue --
a: 4
a: 4

s: {b: 2}
s: {c: 2}

l: [1, 2]
l: [1, 2]
-- result.txt --
a: 4
s: {
b: 2
c: 2
}
l: [1, 2]
C: [4, 5, {c: 6}]
C: [4, 5, {d: 7}]
-- out --
A: 1
B:
a: 2
b: 3
C:
- 4
- 5
- c: 6
d: 7
{{{end}}}
2 changes: 1 addition & 1 deletion content/docs/tour/basics/duplicate-fields/gen_cache.cue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ package site
page: {
cache: {
code: {
example: "b8fDvOClnROx5BgQyj5NGTkffnunNSmZmfBGbC7oSYs="
tour: "wXs/jrCMbCD2fTvEmeBygnlK/WUE2vVUazqAslabHyQ="
}
}
}
Expand Down
73 changes: 44 additions & 29 deletions content/docs/tour/basics/folding-structs/en.md
Original file line number Diff line number Diff line change
@@ -1,43 +1,58 @@
---
title: Folding of Single-Field Structs
title: Concise Specifications
weight: 240
---

In JSON, one defines nested values one value at a time.
Another way to look at this is that a JSON configuration is a set of
path-value pairs.
CUE has a convenient **shorthand form** for specifying single fields concisely:
`a: b: c: value`\
It can be mixed freely with CUE's other syntaxes.

In CUE one defines a set of paths of which to apply
a concrete value or constraint all at once.
Because of CUE's order independence, values get merged
**Pattern constraints** apply values to multiple fields.\
They affect those fields which match a pattern: `[pattern]: value`

This example shows some path-value pairs, as well as
a constraint that is applied to those to validate them.
<!--
This also gives a handy shorthand for writing structs with single
members.
-->
A pattern constraint doesn't *specify* those fields which match its pattern.\
For instance, the pattern constraint "`[string]: 42`" doesn't bring *every* possible `string`
field into existence!

{{{with code "en" "example"}}}
#nofmt(fold.cue) https://github.com/cue-lang/cue/issues/722
{{{with code "en" "tour"}}}
#nofmt https://github.com/cue-lang/cue/issues/722

exec cue export fold.cue
cmp stdout result.txt
-- fold.cue --
// path-value pairs
outer: middle1: inner: 3
outer: middle2: inner: 7
exec cue export file.cue
cmp stdout out
-- file.cue --
// Specify fields concisely ...
fruit: apple: weight: 5
fruit: grape: weight: 2
// ... or don't. Mix and match forms as needed.
fruit: {
melon: weight: 9
}

// Pattern constraints match multiple fields.
fruit: [string]: weight: int & <10

// collection-constraint pair
outer: [string]: inner: int
-- result.txt --
// Pattern constraints can specify multiple fields.
fruit: [string]: {
isFruit: true
isVegetable: !isFruit
}
-- out --
{
"outer": {
"middle1": {
"inner": 3
"fruit": {
"apple": {
"weight": 5,
"isFruit": true,
"isVegetable": false
},
"grape": {
"weight": 2,
"isFruit": true,
"isVegetable": false
},
"middle2": {
"inner": 7
"melon": {
"weight": 9,
"isFruit": true,
"isVegetable": false
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion content/docs/tour/basics/folding-structs/gen_cache.cue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ package site
page: {
cache: {
code: {
example: "k4mcuuwmel7Vfif7aN7ziHZ3hGyrTyae9P4AoBhYVvI="
tour: "BWhPizXN8F8iyhmJmZFWrGU+TQMBnhzzU3lJh8vrJKM="
}
}
}
Expand Down
Loading

0 comments on commit 338bbc8

Please sign in to comment.