---
title: "Introduction to the formatters package"
author: "Gabriel Becker"
date: "`r Sys.Date()`"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Introduction to the formatters package}
  %\VignetteEncoding{UTF-8}
  %\VignetteEngine{knitr::rmarkdown}
editor_options: 
  chunk_output_type: console
  markdown: 
    wrap: 72
---

```{r, echo=FALSE}
knitr::opts_chunk$set(comment = "")
library(formatters)
```

# formatters

The `formatters` package provides two core pieces of functionality, both
related to ASCII rendering:

1.  `format_value` provides the ability to format single- and
    multi-valued elements into ASCII display-ready strings
2.  the `matrix_form` framework provides generics for implementing ASCII
    rendering support for display tables

**Both of these feature sets are used in the `rtables` package.**

# Formatting values

The core motivation for `formatters` is the rendering of reporting
tables into ASCII. In this context a 'value' is the raw content that to
appear in a single table cell. Most commonly this is a numeric vector of
length 1, 2 or -- occasionally -- 3.

## Format labels

`formatters` ships with a large number of pre-defined formats
appropriate for rendering values into ASCII strings. These existing
formats are specified by their labels. We can see the list of these by
calling the `list_valid_format_labels` function:

```{r}
list_valid_format_labels()
```

Each of these labels describes how the incoming (possibly multi-element)
raw value will be formatted. `xx` indicates that an element of the value
will be printed as is, with no modification. `xx.` indicates that a
numeric value element will be rounded to 0 decimal places, `xx.x`
indicates rounding to 1 decimal place, etc.

## Formatting values

Values are formatted via calls to `format_value`, like so:

```{r}
format_value(5.1235, format = "xx.xx")
```

```{r}
format_value(c(1.2355, 2.6789), "(xx.xx, xx.xx)")
```

# Table Rendering Framework

**Advanced Usage Only** These features are supported, and in fact are
used in `rtables` and the experimental `rlistings`. That said, the API
is currently very low-level and tailored to what `rtables` and
`rlistings` need. How useful this is to other table frameworks may vary.

The second major piece of functionality in `formatters` is the ability
to render tables into ASCII (and thus directly to the terminal) based on
a so-called `MatrixPrintForm` representation of the table.

To hook up `rtables`-style ASCII display for your tables, it suffices to
export a method for the exported `matrix_form` generic `formatters`
provides. This method must return a `MatrixPrintForm` object
representing your table.

We can build a baby example method for `data.frames` to illustrate this
process:

```{r}
## pagdfrow supports a large number of pieces of information regarding
## siblings and what information should be repeated after a pagination.
## we ignore all that here and just give the absolutely crucial info:
## nm (name), lab (label), rnum (absolute row position), pth ("path"),
## extent (how many lines it takes up), rclass ("class of row")
fake_pagdf_row <- function(i, rnms) {
  nm <- rnms[i]
  pagdfrow(
    nm = nm, lab = nm, rnum = i, pth = nm, extent = 1L,
    rclass = "NA"
  )
}

matrix_form.data.frame <- function(df) {
  fmts <- lapply(df, function(x) if (is.null(obj_format(x))) "xx" else obj_format(x))

  bodystrs <- mapply(function(x, fmt) {
    sapply(x, format_value, format = fmt)
  }, x = df, fmt = fmts)

  rnms <- row.names(df)
  if (is.null(rnms)) {
    rnms <- as.character(seq_len(NROW(df)))
  }

  cnms <- names(df)

  strings <- rbind(
    c("", cnms),
    cbind(rnms, bodystrs)
  )

  fnr <- nrow(strings)
  fnc <- ncol(strings)

  ## center alignment for column labels, left alignment for everything else
  aligns <- rbind(
    "center",
    matrix("left", nrow = NROW(df), ncol = fnc)
  )


  ## build up fake pagination df,
  rowdf <- basic_pagdf(row.names(df))
  MatrixPrintForm(
    strings = strings,
    aligns = aligns,
    spans = matrix(1, nrow = fnr, ncol = fnc),
    formats = matrix("", nrow = fnr, ncol = fnc),
    row_info = rowdf,
    has_topleft = FALSE,
    nlines_header = 1,
    nrow_header = 1
  )
}

cat(toString(matrix_form.data.frame(mtcars)))
```