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

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

How can `sinew` help you?

`sinew` automates tasks that are part of `R` package documentation and maintance in order to help developers consistently create robust [roxygen2](https://cran.r-project.org/web/packages/roxygen2/vignettes/roxygen2.html) documentation and pass `R CMD check --as-cran`.

## Quick Turnaraound

Two common scenarios arise in package development

  - You start a new project and open a file to develop your idea. Many functions later at the end of the day you look up and you have created a mess of a file.

```{r, echo = FALSE}
if(file.exists('../reference/figures/Guy-Tangled-in-Lights.jpg')){
  knitr::include_graphics('../reference/figures/Guy-Tangled-in-Lights.jpg', dpi = 100)
}else{
  knitr::include_graphics('../man/figures/Guy-Tangled-in-Lights.jpg', dpi = 100)
}
```

  - You recieve a mammoth 10,000 line uncommented file to decipher for QC - good luck.

  <iframe src="https://giphy.com/embed/em438MSCPulkbd7Zvv" width="300" height="280" frameBorder="1" class="giphy-embed" allowFullScreen></iframe>

`sinew` can help turn the around that headache into a `CRAN` ready package in a few short steps

  1. Create a package project in `RStudio`.
  2. Place the file in the `data-raw` folder.
  3. Run `sinew::untangle` on the large script with the destination directory `pkg/R`. This will separate the core functions in the body into single function files (named as the function) and keep the body in `body.R`
  4. Run `sinew::pretty_namespace` to append namespaces in the function scripts.
  5. Run `sinew::makeOxyFile` to populate the Roxygen2 skeleton.
  6. Run `sinew::make_import` to populate the `Imports` field of the `DESCRIPTION` file.
  
This should get you far enough to make the impossible problem of understanding what is in that file to a manageable task, with the added benefit of producing a new package ready for distribution.

## Reproducible Example

Lets use a reproducible example - The goal is to convert raw script into a package.

The script includes two functions `yy` and `zz` and some general script that uses them

To start we create a package with [usethis](https://github.com/r-lib/usethis)

```{r}
library(sinew)

```
 
```{r}
pkg_dir <- file.path(tempdir(),'pkg')
usethis::create_package(path = pkg_dir, open = FALSE)
withr::with_dir(pkg_dir, usethis::use_data_raw(open = FALSE))
withr::with_dir(pkg_dir, usethis::use_mit_license(copyright_holder = "John Doe"))
withr::with_dir(pkg_dir, usethis::use_roxygen_md())
```

```{r}
withr::with_dir(pkg_dir,fs::dir_tree())
```

Lets create a temporary file that will contain the script.

```{r}

example_file <- tempfile(fileext = '.R',tmpdir = file.path(pkg_dir, 'data-raw'))

example_lines <- "#some comment
yy <- function(a=4){
  head(runif(10),a)
  # a comment
}

zz <- function(v=10,a=8){
  head(runif(v),a)
}


yy(6)

zz(30,3)
"

cat(example_lines,file = example_file)

```

## Untangling Files

One of the first tasks for new developers is to move from long scripts that are intertwined with functions and body code into single function files in a R subdirectory and a clean body script that is easier to read.

This task is probably a non-starter if you have more than a few hundered lines of code. This is where `sinew::untangle` can save you time. `sinew::untangle` will separate the long script into single function files in a subdirectory and keep the body script intact.

```{r}
pkg_dir_R <- file.path(pkg_dir,'R')
sinew::untangle(file = example_file,
                dir.out = pkg_dir_R, 
                dir.body = file.path(pkg_dir, 'data-raw'))
```

As we can see we got three new files. 

  - `body.R` in the data-raw directory 
  - `yy.R` in the R subdirectory 
  - `zz.R` in the `R` subdirectory

```{r}
withr::with_dir(pkg_dir,fs::dir_tree())
```

```{r, echo = FALSE}
details::details(file.path(pkg_dir, 'data-raw','body.R'), summary = 'Click to see body.R')
```

```{r, echo = FALSE}
details::details(file.path(pkg_dir_R,'yy.R'), summary = 'Click to see yy.R')
```

```{r, echo = FALSE}
details::details(file.path(pkg_dir_R,'zz.R'), summary = 'Click to see zz.R')
```

## Namespacing

It has become common practice to use the namespace in function calls, and it is obligatory in order to pass a cran check. But, not everyone does it and if you’re not use to it, it’s a pain to go back and update your script.

This is where `sinew::pretty_namespace` comes in. This function will go through your script and attach namespaces for you, with the same logic as the search path.

```{r}
sinew::pretty_namespace(pkg_dir_R,overwrite = TRUE)
```

So now we have separate files with functions appropriatly associated with namespaces, and now we can add [roxygen2](https://cran.r-project.org/web/packages/roxygen2/vignettes/roxygen2.html) headers.

## Documentation

Now we are ready to create the function documentation using [roxygen2](https://cran.r-project.org/web/packages/roxygen2/vignettes/roxygen2.html). We use `sinew::makeOxygen` to create a skeleton for [roxygen2](https://cran.r-project.org/web/packages/roxygen2/vignettes/roxygen2.html) documentation. This function returns a skeleton that includes title, description, return, import and other fields populated with information scraped from the function script. We can also run `sinew::makeOxygen` in batch mode using `sinew::makeOxyfile`.

```{r}
sinew::sinew_opts$set(markdown_links = TRUE)
```

```{r}
sinew::makeOxyFile(input = pkg_dir_R, overwrite = TRUE, verbose = FALSE)
```

```{r, echo = FALSE}
details::details(file.path(pkg_dir_R,'yy.R'), summary = 'Click to see yy.R')
```

```{r, echo = FALSE}
details::details(file.path(pkg_dir_R,'zz.R'), summary = 'Click to see zz.R')
```


The premise of `sinew::makeOxygen` is to expand on the default skeleton in `RStudio`, so basic fields are in the output by default. Each field is given with a relevant placeholder giving a hint what is expected. The following is the meat add to these bones:

  - param default values:
    - If a default value is set for a function parameter it will be added to the end `@param` line.
  - import/importFrom
    - The package scrapes the script with make_import looking for declared namespaces to create the proper calls for `@import` and `@importFrom` which are placed at the bottom of the output.
  - seealso
    - linking to other packages is also taken care of when adding the field `@seealso`. Any functions that are included in `@importFrom` will have a link to them by default.

## DESCRIPTION FILE

It is also important to update the package `DESCRIPTION` file `Imports` field. This can be done for you with `sinew::make_import`, by either creating a new `Imports` field or updating an existing one.

```{r}
sinew::make_import(pkg_dir_R,format = 'description',desc_loc = pkg_dir)
```


## Update documentation

An important part of maintaining a package is keeping the documentation updated. Using `sinew::moga` we can achieve this painlessly. `sinew::moga` runs the same underlying script as `sinew::makeOxygen` but appends new information found into the current [roxygen2](https://cran.r-project.org/web/packages/roxygen2/vignettes/roxygen2.html) header instead of creating a new one.

Lets say we updated `yy.R` to include another param and used another function from the `stats` package. So the [roxygen2](https://cran.r-project.org/web/packages/roxygen2/vignettes/roxygen2.html) header is now out of synch with the current script.

```{r}
new_yy <- "#some comment
#' @title FUNCTION_TITLE
#' @description FUNCTION_DESCRIPTION
#' @param a numeric, set the head to trim from random unif Default: 4
#' @return OUTPUT_DESCRIPTION
#' @details DETAILS
#' @examples 
#' \\dontrun{
#' if(interactive()){
#'  #EXAMPLE1
#'  }
#' }
#' @seealso 
#'  \\code{\\link[utils]{head}}
#'  \\code{\\link[stats]{runif}}
#' @rdname yy
#' @export 
#' @author Jonathan Sidi
#' @importFrom utils head
#' @importFrom stats runif
yy <- function(a=4,b=2){
  x <- utils::head(stats::runif(10*b),a)
  stats::quantile(x,probs=.95)
  # a comment
}"


cat(new_yy, file = file.path(pkg_dir_R,'yy.R'))

```

```{r}
moga(file.path(pkg_dir_R,'yy.R'),overwrite = TRUE)
```


```{r, echo = FALSE}
details::details(file.path(pkg_dir_R,'yy.R'), summary = 'Click to see yy.R')
```

## Oxygenize and Check

### Oxygenize

```{r}

r_env_vars <- function () {
    vars <- c(R_LIBS = paste(.libPaths(), collapse = .Platform$path.sep), 
        CYGWIN = "nodosfilewarning", R_TESTS = "", R_BROWSER = "false", 
        R_PDFVIEWER = "false")
    if (is.na(Sys.getenv("NOT_CRAN", unset = NA))) {
        vars[["NOT_CRAN"]] <- "true"
    }
    vars
}

withr::with_envvar(r_env_vars(), roxygen2::roxygenise(pkg_dir))
```

### R CMD Check

```{r,eval=interactive()}
check_res <- rcmdcheck::rcmdcheck(path = pkg_dir, args = '--as-cran',quiet = TRUE)
```

```{r,echo=FALSE,eval=interactive()}
details::details(check_res,summary = 'Check Results', open = TRUE)
```

### Cleanup

```{r}
unlink(pkg_dir, recursive = TRUE, force = TRUE)
```
