
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.
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")On Windows ARM64, source installs require the Rust target used by Rtools45:
rustup target add aarch64-pc-windows-gnullvmThey 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.
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 TRUEvalue_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))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] 42YAML 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"))
)
))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