---
title: "Use S7schema in your package"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Use S7schema in your package}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)

library(S7schema)
```

## Introduction

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.

## Define a schema

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:

```{r}
schema_path <- system.file("examples/schema.json", package = "S7schema")
```

``` json
`r paste(readLines(schema_path), collapse = "\n")`
```

## Create a child class

The core pattern is to create an S7 class that inherits from `S7schema`
and hard-codes the schema path in its constructor:

```{r}
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.

## Use the child class

### Construction

Creating an instance loads and validates the YAML file automatically:

```{r}
config_path <- system.file("examples/config.yml", package = "S7schema")
x <- my_config_class(file = config_path)
print(x)
```

### Accessing values

Since `S7schema` objects are lists, values are accessed directly:

```{r}
x$my_config_var
```

### Class hierarchy

The child class inherits from `S7schema`:

```{r}
class(x)
```

### Validation

`S7::validate()` works on the child class just like on the parent:

```{r, error = TRUE}
x$my_config_var <- "not a number"
S7::validate(x)
```

### Method dispatch

Methods defined for `S7schema` work on child classes without extra code.

`write_config()` validates and writes to YAML:

```{r}
tmp <- tempfile(fileext = ".yml")
x$my_config_var <- 42
write_config(x, file = tmp)
readLines(tmp)
```

`document_schema()` generates markdown documentation from the schema:

```{r}
md <- document_schema(schema_path)
cat(md)
```

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:

```{r}
md <- document_schema(schema_path, header_start_level = 3)
cat(md)
```
