yaml12 yaml12 website

R-CMD-check

A YAML 1.2 parser/formatter for R, implemented in Rust for speed and correctness. Built on the excellent saphyr crate.

Compared with YAML 1.1’s type library, YAML 1.2’s recommended core schema uses more conservative type inference for unquoted values. The YAML 1.1 versus 1.2 quick reference summarizes the differences.

Installation

You can install yaml12 from CRAN with:

install.packages("yaml12")

You can install the development version of yaml12 from GitHub with:

# install.packages("pak")
pak::pak("posit-dev/r-yaml12")

Windows ARM64 source installs

On Windows ARM64, source installs require the Rust target used by Rtools45:

rustup target add aarch64-pc-windows-gnullvm

They also require Microsoft C++ Build Tools with ARM64 components. Cargo uses the Microsoft linker for host-side Rust procedural macros during the source build. Binary installs do not run Cargo and do not need this setup.

Quick start

library(yaml12)

yaml <- "
title: A modern YAML parser and emitter written in Rust
properties: [fast, correct, safe, simple]
sequences:
  simplify: true
"

doc <- parse_yaml(yaml)
str(doc)
#> List of 3
#>  $ title     : chr "A modern YAML parser and emitter written in Rust"
#>  $ properties: chr [1:4] "fast" "correct" "safe" "simple"
#>  $ sequences :List of 1
#>   ..$ simplify: logi TRUE

Reading and writing files

value_out <- list(alpha = 1L, nested = c(TRUE, NA))

write_yaml(value_out, "my.yaml")
value_in <- read_yaml("my.yaml")

stopifnot(identical(value_out, value_in))

# Multi-document streams
docs_out <- list(list(foo = 1L), list(bar = c(2L, NA)))

write_yaml(docs_out, "my-multi.yaml", multi = TRUE)
docs_in <- read_yaml("my-multi.yaml", multi = TRUE)

stopifnot(identical(docs_in, docs_out))

Tag handlers

Handlers let you opt into custom behavior for tagged nodes while keeping the default parser strict and safe.

yaml <- "
- !upper [rust, r]
- !expr 6 * 7
"

handlers <- list(
  "!expr"  = function(x) eval(str2lang(x), baseenv()),
  "!upper" = toupper
)

parse_yaml(yaml, handlers = handlers)
#> [[1]]
#> [1] "RUST" "R"   
#> 
#> [[2]]
#> [1] 42

Non-string mapping keys

YAML mappings can use keys that R cannot store directly as names (for example, booleans, numbers, or tagged strings). When that happens, parse_yaml() still returns a named list but also attaches a yaml_keys attribute containing the original YAML keys:

yaml <- "
true: a
null: b
!custom foo: c
"

parsed <- parse_yaml(yaml)

stopifnot(identical(
  parsed,
  structure(
    list("a", "b", "c"),
    names = c("", "", ""),
    yaml_keys = list(TRUE, NULL, structure("foo", yaml_tag = "!custom"))
  )
))

Formatting and round-tripping

The yaml_tag and yaml_keys attributes are also hooks for customizing output: tags on values round-trip, and yaml_keys allows you to emit mappings with non-string or tagged keys that can’t be represented as an R name.

obj <- list(
  seq = 1:2,
  map = list(key = "value"),
  tagged = structure("1 + 1", yaml_tag = "!expr"),
  keys = structure(
    list("a", "b", "c"),
    names = c("plain", "", ""),
    yaml_keys = list("plain", TRUE, structure("foo", yaml_tag = "!custom"))
  )
)

yaml <- format_yaml(obj)
cat(yaml)
#> seq:
#>   - 1
#>   - 2
#> map:
#>   key: value
#> tagged: !expr 1 + 1
#> keys:
#>   plain: a
#>   true: b
#>   !custom foo: c

roundtripped <- parse_yaml(yaml)
identical(obj, roundtripped)
#> [1] TRUE

Documentation