---
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
---


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

# formatters

The `formatters` package provides two core pieces of functionality, both relatead 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 featuresets 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 desceribes 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))
    matrix_print_form(strings = strings,
                      aligns = aligns,
                      spans = matrix(1, nrow = fnr, ncol = fnc),
                      formats = NULL,
                      row_info = rowdf,
                      has_topleft = FALSE,
                      nlines_header = 1,
                      nrow_header = 1)
}
                      

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