If you maintain a package that requires a specific configuration
format, S7schema lets you define a validated config class with minimal
code. By extending S7schema, your package gets schema
validation, YAML reading/writing, and schema documentation for free.
A JSON schema describes the structure and constraints of your
configuration. In a real package, the schema should live in
inst/ (e.g. inst/schema/my_schema.json) so it
ships with the package and can be found via
system.file().
For this vignette we use the example schema bundled with S7schema:
{
"$schema": "http://json-schema.org/draft-07/schema",
"title": "My config schema",
"description": "Simple example schema with one allowed entry",
"type": "object",
"properties": {
"my_config_var": {
"description": "My only configuration variable",
"type": "number"
}
},
"additionalProperties": false
}The core pattern is to create an S7 class that inherits from
S7schema and hard-codes the schema path in its
constructor:
my_config_class <- S7::new_class(
name = "my_config_class",
parent = S7schema::S7schema,
constructor = function(file) {
S7::new_object(
.parent = S7schema::S7schema(
file = file,
schema = system.file("examples/schema.json", package = "S7schema")
)
)
}
)Users of your package only need to supply the config file path — the schema is handled internally.
Creating an instance loads and validates the YAML file automatically:
config_path <- system.file("examples/config.yml", package = "S7schema")
x <- my_config_class(file = config_path)
print(x)
#> <my_config_class> List of 1
#> $ my_config_var: int 1
#> @ schema : chr "/private/var/folders/fx/71by3f551qzb5wkxt82cv15m0000gp/T/RtmpapwPJP/Rinstdccf75252863/S7schema/examples/schema.json"
#> @ validator: <S7schema::validator>
#> .. @ context:Classes 'V8', 'environment' <environment: 0x106f16710>
#> @ file : chr "/private/var/folders/fx/71by3f551qzb5wkxt82cv15m0000gp/T/RtmpapwPJP/Rinstdccf75252863/S7schema/examples/config.yml"Since S7schema objects are lists, values are accessed
directly:
The child class inherits from S7schema:
S7::validate() works on the child class just like on the
parent:
Methods defined for S7schema work on child classes
without extra code.
write_config() validates and writes to YAML:
tmp <- tempfile(fileext = ".yml")
x$my_config_var <- 42
write_config(x, file = tmp)
readLines(tmp)
#> [1] "my_config_var: 42.0"document_schema() generates markdown documentation from
the schema:
md <- document_schema(schema_path)
cat(md)
#> # My config schema
#>
#> Simple example schema with one allowed entry
#>
#> |Type |Additional Properties |
#> |:------|:---------------------|
#> |object |No |
#>
#> ## Properties
#>
#> |Name |Description |Type |Required |
#> |:-------------|:------------------------------|:------|:--------|
#> |my_config_var |My only configuration variable |number |No |Note that if printed directly, the return of
document_schema() is displayed as-is.
The header_start_level parameter controls the depth of
the generated headings:
md <- document_schema(schema_path, header_start_level = 3)
cat(md)
#> ### My config schema
#>
#> Simple example schema with one allowed entry
#>
#> |Type |Additional Properties |
#> |:------|:---------------------|
#> |object |No |
#>
#> #### Properties
#>
#> |Name |Description |Type |Required |
#> |:-------------|:------------------------------|:------|:--------|
#> |my_config_var |My only configuration variable |number |No |