# Introduction to yaml

    library(yaml)

## What is YAML?

YAML is a human-readable data serialization language. With it, you can create easily readable documents that can be consumed by a variety of programming languages.

For example, here’s a map of baseball teams per league:

    american:
    - Boston Red Sox
    - Detroit Tigers
    - New York Yankees
    national:
    - New York Mets
    - Chicago Cubs
    - Atlanta Braves

And a data dictionary specification:

    - field: ID
      description: primary identifier
      type: integer
      primary key: yes
    - field: DOB
      description: date of birth
      type: date
      format: yyyy-mm-dd
    - field: State
      description: state of residence
      type: string

## Parsing YAML

`yaml.load()` parses a YAML document from a string:

    yaml.load("
    - 1
    - 2
    - 3
    ")
    #> [1] 1 2 3

`yaml.load_file()` and `read_yaml()` read YAML from a file or connection.

### Scalars

A YAML scalar is the basic building block of YAML documents. The parser automatically determines the type:

    yaml.load("1.2345")
    #> [1] 1.2345
    yaml.load("true")
    #> [1] TRUE
    yaml.load("hello")
    #> [1] "hello"

### Sequences

A YAML sequence is a list of elements. If all elements are uniform, `yaml.load()` returns a vector of that type. Otherwise, it returns a list:

    # Uniform sequence -> vector
    yaml.load("
    - 1
    - 2
    - 3
    ")
    #> [1] 1 2 3

    # Mixed sequence -> list
    yaml.load("
    - 1
    - hello
    - true
    ")
    #> [[1]]
    #> [1] 1
    #>
    #> [[2]]
    #> [1] "hello"
    #>
    #> [[3]]
    #> [1] TRUE

### Maps

A YAML map is a list of paired keys and values. By default, `yaml.load()` returns a named list:

    yaml.load("
    one: 1
    two: 2
    three: 3
    ")
    #> $one
    #> [1] 1
    #>
    #> $two
    #> [1] 2
    #>
    #> $three
    #> [1] 3

Since YAML map keys can be almost anything (not just strings), you can preserve the data type of keys with `as.named.list = FALSE`. This creates a `keys` attribute instead of coercing keys to strings:

    yaml.load("
    1: one
    2: two
    ", as.named.list = FALSE)
    #> [[1]]
    #> [1] "one"
    #>
    #> [[2]]
    #> [1] "two"
    #>
    #> attr(,"keys")
    #> attr(,"keys")[[1]]
    #> [1] 1
    #>
    #> attr(,"keys")[[2]]
    #> [1] 2

### Custom handlers

You can customize parsing with handler functions. Handlers are passed to `yaml.load()` as a named list, where each name is the YAML type to handle:

    # Add 100 to all integers
    yaml.load("123", handlers = list(int = function(x) as.integer(x) + 100))
    #> [1] 223

#### Sequence handlers

Sequence handlers receive a list and can transform it:

    yaml.load("
    - 1
    - 2
    - 3
    ", handlers = list(seq = function(x) sum(as.numeric(x))))
    #> [1] 6

#### Map handlers

Map handlers receive a named list (or a list with a `keys` attribute):

    yaml.load("
    a:
    - 1
    - 2
    b:
    - 3
    - 4
    ", handlers = list(map = function(x) as.data.frame(x)))
    #>   a b
    #> 1 1 3
    #> 2 2 4

## Emitting YAML

`as.yaml()` converts R objects to YAML strings:

    cat(as.yaml(1:5))
    #> - 1
    #> - 2
    #> - 3
    #> - 4
    #> - 5

`write_yaml()` writes the result directly to a file or connection.

### Formatting options

#### indent

Control indentation depth (default is 2):

    cat(as.yaml(list(foo = list(bar = "baz")), indent = 4))
    #> foo:
    #>     bar: baz

#### indent.mapping.sequence

By default, sequences within a mapping are not indented:

    cat(as.yaml(list(foo = 1:3)))
    #> foo:
    #> - 1
    #> - 2
    #> - 3

Set `indent.mapping.sequence = TRUE` to indent them:

    cat(as.yaml(list(foo = 1:3), indent.mapping.sequence = TRUE))
    #> foo:
    #>   - 1
    #>   - 2
    #>   - 3

#### column.major

Controls how data frames are converted. When `TRUE` (default), data frames are emitted column-wise:

    x <- data.frame(a = 1:2, b = 3:4)
    cat(as.yaml(x, column.major = TRUE))
    #> a:
    #> - 1
    #> - 2
    #> b:
    #> - 3
    #> - 4

When `FALSE`, data frames are emitted row-wise:

    cat(as.yaml(x, column.major = FALSE))
    #> - a: 1
    #>   b: 3
    #> - a: 2
    #>   b: 4

### Custom handlers

Specify custom handler functions for R object classes:

    cat(as.yaml(
      Sys.Date(),
      handlers = list(Date = function(x) format(x, "%Y/%m/%d"))
    ))
    #> 2025/12/08

### YAML 1.2 logical handling

For YAML 1.2-like logical output, use `verbatim_logical`:

    cat(as.yaml(c(TRUE, FALSE), handlers = list(logical = verbatim_logical)))
    #> - true
    #> - false

### Verbatim text

Character vectors with class `"verbatim"` are not quoted except when required by the YAML specification:

    result <- c("true", "false")
    class(result) <- "verbatim"
    cat(as.yaml(result))
    #> - true
    #> - false

### Quoted strings

Force quoting with the `"quoted"` attribute:

    port <- "80:80"
    attr(port, "quoted") <- TRUE
    cat(as.yaml(list(ports = list(port))))
    #> ports:
    #> - "80:80"

### Custom tags

Set YAML tags with the `"tag"` attribute:

    x <- 1:3
    attr(x, "tag") <- "!custom"
    cat(as.yaml(x))
    #> !custom
    #> - 1
    #> - 2
    #> - 3