---
title: "Advanced Customization"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Advanced Customization}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

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

```{r setup}
library(RJSONIO)
```

`RJSONIO` exposes customization points for parser events, string conversion,
JavaScript variable output, and S4 serialization.

## Parser handlers

`basicJSONHandler()` returns an object with `update()` and `value()` functions.
The parser calls `update()` for each JSON token.

```{r basic-handler}
handler <- basicJSONHandler()
fromJSON("[1, 3, 10, 19]", handler$update)

handler$value()
```

A callback can also collect token names directly.

```{r callback-handler}
events <- character()

fromJSON('{"a": 1, "b": "x"}', function(type, value) {
  events <<- c(events, names(type))
  TRUE
})

unique(events)
```

## String callbacks

Use `stringFun` to transform strings while parsing.

```{r string-fun}
fromJSON('[1, "abc", "xyz"]',
         stringFun = function(value) sprintf("parsed_%s", value))

fromJSON('["1", "2.3", "3.1415"]',
         stringFun = function(value) as.numeric(value))
```

## JavaScript variable output

`asJSVars()` formats named values as JavaScript-style assignments and returns
the generated text invisibly.

```{r as-js-vars}
js <- asJSVars(a = 1:3, b = "x")
cat(js)
```

Type annotations can be requested for common scalar values.

```{r as-js-vars-types}
cat(asJSVars(.vars = list(count = 3L, label = "x"), types = TRUE))
```

## S4 objects

S4 objects are serialized by their slots unless a more specific method is
defined.

```{r s4}
setClass("RJSONIOVignetteClass",
         representation(id = "integer", label = "character"))

object <- new("RJSONIOVignetteClass", id = 1L, label = "example")
cat(toJSON(object))
```

Packages can define class-specific `toJSON()` methods when a different JSON
shape is needed.

```{r custom-method}
setClass("RJSONIOPoint", representation(x = "numeric", y = "numeric"))

setMethod("toJSON", "RJSONIOPoint",
          function(x, container = TRUE, collapse = "\n", ...,
                   .level = 1L, .withNames = TRUE, .na = "null",
                   .escapeEscapes = TRUE, pretty = FALSE, asIs = NA,
                   .inf = " Infinity") {
            toJSON(list(x = x@x, y = x@y),
                   container = container, collapse = collapse, ...,
                   .level = .level, .withNames = .withNames, .na = .na,
                   .escapeEscapes = .escapeEscapes, pretty = pretty,
                   asIs = asIs, .inf = .inf)
          })

point <- new("RJSONIOPoint", x = 1, y = 2)
fromJSON(toJSON(point))
```
