boB Rudis 4 years ago
commit
abe52298dd
No known key found for this signature in database GPG Key ID: 1D7529BE14E2BBA9
  1. 44
      01-intro.Rmd
  2. 284
      02-first-package.Rmd
  3. 1
      README.md
  4. 510
      _book/basic-r-package.html
  5. 241
      _book/index.html
  6. 280
      _book/intro.html
  7. 20
      _book/libs/elevate-section-attrs-2.0/elevate-section-attrs.js
  8. BIN
      _book/libs/gitbook-2.6.7/css/fontawesome/fontawesome-webfont.ttf
  9. 99
      _book/libs/gitbook-2.6.7/css/plugin-bookdown.css
  10. 18
      _book/libs/gitbook-2.6.7/css/plugin-clipboard.css
  11. 292
      _book/libs/gitbook-2.6.7/css/plugin-fontsettings.css
  12. 426
      _book/libs/gitbook-2.6.7/css/plugin-highlight.css
  13. 31
      _book/libs/gitbook-2.6.7/css/plugin-search.css
  14. 1
      _book/libs/gitbook-2.6.7/css/plugin-table.css
  15. 10
      _book/libs/gitbook-2.6.7/css/style.css
  16. 1
      _book/libs/gitbook-2.6.7/js/app.min.js
  17. 7
      _book/libs/gitbook-2.6.7/js/clipboard.min.js
  18. 86
      _book/libs/gitbook-2.6.7/js/jquery.highlight.js
  19. 7
      _book/libs/gitbook-2.6.7/js/lunr.js
  20. 259
      _book/libs/gitbook-2.6.7/js/plugin-bookdown.js
  21. 29
      _book/libs/gitbook-2.6.7/js/plugin-clipboard.js
  22. 152
      _book/libs/gitbook-2.6.7/js/plugin-fontsettings.js
  23. 223
      _book/libs/gitbook-2.6.7/js/plugin-search.js
  24. 105
      _book/libs/gitbook-2.6.7/js/plugin-sharing.js
  25. 4
      _book/libs/jquery-2.2.3/jquery.min.js
  26. 5
      _book/search_index.json
  27. 14
      _book/style.css
  28. BIN
      _book/writing-frictionless-r-package-wrappers.epub
  29. BIN
      _book/writing-frictionless-r-package-wrappers.pdf
  30. 521
      _book/writing-frictionless-r-package-wrappers.tex
  31. 5
      _bookdown.yml
  32. 16
      _output.yml
  33. 10
      book.bib
  34. 16
      index.Rmd
  35. 1
      preamble.tex
  36. 1
      publish.sh
  37. 14
      style.css
  38. 17
      writing-frictionless-r-package-wrappers.Rproj

44
01-intro.Rmd

@ -0,0 +1,44 @@
# Introduction {#intro}
The R language and RStudio IDE are a powerful combination for "getting stuff done", and one aspect of R itself that makes it especially useful is the ability to use it with other programming languages via a robust _foreign language interface_ capability^["Writing R Extensions"; Chapter 5, "System and foreign language interfaces"; (<https://cran.r-project.org/doc/manuals/r-release/R-exts.html#System-and-foreign-language-interfaces>)]. The term "foreign language" refers to another programming language such as C, C++, Fortran, Java, Python, Rust, etc. A common way of referring the this idiom of using functionality written in another programming language from directly within R is "wrapping" since we're putting an R "shell" around the code from the other language. Another term you may see used is "extending" (hence the title of the "Writing R Extensions" R manual).
While R supports using this this extension mechanism from any R script leaving tiny trails of R and other language source and binary files all across your filesystem is not exactly the best way to keep these components organized and creates other challenges when you come across the need to use them in other projects or share them with others. Thankfully, the R Core team, along with many individual contributors over the years, has made it pretty straightforward to incorporate this extension capability into R packages which are much easier (honest!) to organize and share.
The goal of this book is to help you get up to speed using R and RStudio to write R packages that wrap code from many different languages to help you "get stuff done" with as little friction as possible.
## Base Requirements {#intro-reqs}
It is assumed that readers are familiar with the R programming language, RStudio IDE, and are comfortable installing and using packages. Since this work is about extending R with other programming languages, you should also have some knowledge of one or more of the target languages being covered.
To follow along with the series you'll need to ensure you have the necessary components installed along the way. Rather than overwhelm you with all of them up front, each new section will introduce requirements specific to the language or situation being covered. However, there are some fundamentals you'll need to ensure are available.
- An R^[R Project Home (<https://www.r-project.org/>)] environment, preferably R 3.6.x which is what was used for this series.
- RStudio^[RStudio Home (<http://rstudio.com/>)], as we'll be using many of the features provided in it to help reduce development friction
- The {pkgbuild}^[{pkgbuild} CRAN page (<https://cran.rstudio.com/web/packages/pkgbuild/>)] package installed
Once you've gotten through those steps, you should fire up RStudio and run:
```{r eval=FALSE}
pkgbuild::check_build_tools(debug = TRUE)
```
which will help you make sure your particular system is ready to build packages.
After performing the build tool check and/or installation of the necessary core tools, you will then need to install the {devtools}^[{devtools} Home (<https://devtools.r-lib.org/>)] package, which will help ensure that the remaining core packages required are installed.
We're also going to use the `git`^[`git` Home (<https://git-scm.com/>)] source code version control system. The `git` ecosystem is _not_ "GitHub", which is just a public (or, potentially somewhat private) place to house source code repositories, just like other hosted services such as Bitbucket, GitLab, or SourceHut. You can use the excellent "Happy Git with R"^[Happy Git with R (<https://happygitwithr.com/>)
] resource to help ensure you're source code control environment is also ready to use.
## Supplemental References {#intro-refs}
It may be helpful to create a browser bookmark folder for supplemental reference material that will be referred to from time-to-time across the sections (we'll be adding to this list in each chapter, too):
- Writing R Extensions (<https://cran.r-project.org/doc/manuals/r-release/R-exts.html>)
- Advanced R (<http://adv-r.had.co.nz/>)
- R Packaged (<http://r-pkgs.had.co.nz/>)
## Up Next {#intro-up-next}
If you've been a user of "development versions" of R packages or have authored R packages you likely made quick work of this first installment. Those new to creating packages with R, those who tend to only use fully-baked CRAN versions of R packages, and/or those who have not worked with `git` before likely had to do quite a bit of work to get down to this point (if this describes you, you definitely deserve both a break and kudos for getting this far!).
In the next installment we'll make sure the package building infrastructure is ready to roll by creating a basic R package that we'll use as a building block for future work.

284
02-first-package.Rmd

@ -0,0 +1,284 @@
# Building A Basic R Package {#basic-r-package}
```{r echo=FALSE, include=FALSE}
knitr::opts_chunk$set(echo = TRUE, eval = FALSE)
```
Before we start wrapping foreign language code we need to make sure that basic R packages can be created. If you've followed along from the previous chapter you have everything you need to get started here. _Just to make sure_, you should be able to fire up a new RStudio session and execute the following R code and see similar output. If not, you'll need to go through the steps and resources outlined there before continuing.
```{r}
pkgbuild::check_build_tools()
## Your system is ready to build packages!
```
## Configuring \{devtools} {#config-devtools}
We're going to rely on the {devtools} package for many operations and the first thing you should do now is execute `help("create", "devtools")` in an RStudio R console to see the package documentation page where you'll see guidance pointing you to `devtools::use_description()` that lists some R session `options()` that you can set to make your package development life much easier and quicker. Specifically, it lets you know that you can setup your `~/.Rprofile` to include the certain options settings which will automatically fill in fields each time you create a new package vs you either specifying these fields manually in the package creation GUI or as parameters to `devtools::create()`.
A good, minimal setup would be something like:
```{r}
options(
usethis.description = list(
`Authors@R` = 'person("Some", "One", email = "someone@example.com", role = c("aut", "cre"),
comment = c(ORCID = "YOUR-ORCID-ID"))',
License = "MIT + file LICENSE"
)
)
```
NOTE: If you do not have an "ORCID" you really should get one (they're free!) by heading over to
--- <https://orcid.org/> --- and filling in some basic information.
Take a moment to edit your `~/.Rprofile`. If you're not sure about how to do that there is an excellent chapter in Efficient R Programming^[Efficient R Programming, "3.3 R Startup"; (<https://csgillespie.github.io/efficientR/3-3-r-startup.html#r-startup>)] which walks you through the process.
Once you've added or verified these new `options()` settings, restart your R session.
## Creating A Package {#create-a-package}
We're _almost_ ready to create and build a basic R package. All R packages live in a package directory and I highly suggest creating a `packages` directory right off your home directory (e.g. "`~/packages`") or someplace where you'll be able to keep them all organized and accessible. The rest of these chapters will assume you're using "`~/packages`" as the
With {devtools} now pre-configured, use the RStudio R Console pane to execute the following code which should produce similar output and open up a new RStudio session with the new package directory:
```{r}
devtools::create("~/packages/myfirstpackage")
## ✔ Creating '/Users/someuser/packages/myfirstpackage/'
## ✔ Setting active project to '/Users/someuser/packages/myfirstpackage'
## ✔ Creating 'R/'
## ✔ Writing 'DESCRIPTION'
## Package: myfirstpackage
## Title: What the Package Does (One Line, Title Case)
## Version: 0.0.0.9000
## Authors@R (parsed):
## * Bob Rudis <bob@rud.is> [aut, cre] (<https://orcid.org/0000-0001-5670-2640>)
## Description: What the package does (one paragraph).
## License: MIT + file LICENSE
## Encoding: UTF-8
## LazyData: true
## ✔ Writing 'NAMESPACE'
## ✔ Writing 'myfirstpackage.Rproj'
## ✔ Adding '.Rproj.user' to '.gitignore'
## ✔ Adding '^myfirstpackage\\.Rproj$', '^\\.Rproj\\.user$' to '.Rbuildignore'
## ✔ Opening '/Users/someuser/packages/myfirstpackage/' in new RStudio session
## ✔ Setting active project to '<no active project>'
```
The directory structure will look like this:
```
.
├── DESCRIPTION
├── NAMESPACE
├── R/
└── myfirstpackage.Rproj
```
At this point we still do not have a "perfect" R package. To prove this, use the R console to run `devtools::check()` and --- after some rather verbose output --- you'll see the following lines at the end:
```
> checking DESCRIPTION meta-information ... WARNING
Invalid license file pointers: LICENSE
0 errors ✓ | 1 warning x | 0 notes ✓
```
Since we're saying that our package will be using the MIT license, we need to ensure there's an associated `LICENSE` file which we can do by executing `usethis::use_mit_license()` which will create the necessary files and ensure the `License` field in the `DESCRIPTION` file is formatted properly.
If you run `devtools::check()` again, now, your final line should report:
```{r}
## 0 errors ✓ | 0 warnings ✓ | 0 notes ✓
```
and the package directory tree should look like this:
```
├── DESCRIPTION
├── LICENSE
├── LICENSE.md
├── NAMESPACE
├── R/
└── myfirstpackage.Rproj
```
## Rounding Out The Corners {#round-out-corners}
While we have a minimum viable package there are a few other steps we should take during this setup phase. First we'll setup our package to use `{roxygen2}`^[{roxygen2} Home; (<https://roxygen2.r-lib.org/>)] for documenting functions, declaring `NAMESPACE` imports, and other helper-features that will be introduced in later chapters. We can do this via `usethis::use_roxygen_md()`:
```{r}
usethis::use_roxygen_md()
## ✔ Setting Roxygen field in DESCRIPTION to 'list(markdown = TRUE)'
## ✔ Setting RoxygenNote field in DESCRIPTION to '7.0.2'
## ● Run `devtools::document()`
```
We won't run `devtools::document()` _just yet_, though. Before we do that we'll also create an R file where we can store top-level package introduction/meta-information:
```{r}
usethis::use_package_doc()
## ✔ Writing 'R/myfirstpackage-package.R'
```
Now, our directory tree should look like:
```
.
├── DESCRIPTION
├── LICENSE
├── LICENSE.md
├── NAMESPACE
├── R
│ └── myfirstpackage-package.R
└── myfirstpackage.Rproj
```
Now, run `devtools::document()` which will translate the {roxygen2} comments into a properly-formatted R documentation file and regenerate the `NAMESPACE` file (as we'll be managing package imports and exports via {roxygen2} comments). The directory tree will now look like:
```
.
├── DESCRIPTION
├── LICENSE
├── LICENSE.md
├── NAMESPACE
├── R
│ └── myfirstpackage-package.R
├── man
│ └── myfirstpackage-package.Rd
└── myfirstpackage.Rproj
```
and, we can now re-run `devtools::check()` to make sure we have the three "0's" we're aiming for each time we check our package for errors.
## Passing The Test {#pass-the-test}
We're going to want to write and use tests to ensure our package works properly. There are many R package testing frameworks available. To ease the introduction into this process, we'll use one of the frameworks that came along for the ride when you installed the various packages outlined in the previous chapter: {testthat}^[{testthat} Home; (<https://testthat.r-lib.org/>)]. Setting up {testthat} is also pretty painless thanks to the {usethis} package we've been taking advantage of quite a bit so far. We'll create the {testthat} overall infrastructure then add a placeholder test script since `devtools::check()` will complain about no tests being available if we do not have at least a single script it can execute during the test phase of the package checking process.
```{r}
usethis::use_testthat()
## ✔ Adding 'testthat' to Suggests field in DESCRIPTION
## ✔ Creating 'tests/testthat/'
## ✔ Writing 'tests/testthat.R'
## ● Call `use_test()` to initialize a basic test file and open it for editing.
usethis::use_test("placeholder")
## ✔ Increasing 'testthat' version to '>= 2.1.0' in DESCRIPTION
## ✔ Writing 'tests/testthat/test-placeholder.R'
## ● Modify 'tests/testthat/test-placeholder.R'
```
The directory tree will now look like this:
```
.
├── DESCRIPTION
├── LICENSE
├── LICENSE.md
├── NAMESPACE
├── R
│ └── myfirstpackage-package.R
├── man
│ └── myfirstpackage-package.Rd
├── myfirstpackage.Rproj
└── tests
├── testthat
│ └── test-placeholder.R
└── testthat.R
```
Run `devtools::check()` one more time to make sure we've got those precious 3 "0's" one last time.
## Getting Things Under Control {#get-under-control}
We're _almost_ done! One final step is to turn this directory into a git-managed directory so we can work a bit more safely and eventually share our development work with a broader audience. Provided you followed the outline in the previous chapter, setting up git is as straightforward as one {usethis} function call:
```{r}
usethis::use_git()
## ✔ Setting active project to '/Users/someuser/packages/myfirstpackage'
## ✔ Initialising Git repo
## ✔ Adding '.Rhistory', '.RData' to '.gitignore'
## There are 10 uncommitted files:
## * '.gitignore'
## * '.Rbuildignore'
## * 'DESCRIPTION'
## * 'LICENSE'
## * 'LICENSE.md'
## * 'man/'
## * 'myfirstpackage.Rproj'
## * 'NAMESPACE'
## * 'R/'
## * 'tests/'
## Is it ok to commit them?
##
## 1: For sure
## 2: Negative
## 3: Not now
##
## Selection: 1
## ✔ Adding files
## ✔ Commit with message 'Initial commit'
## ● A restart of RStudio is required to activate the Git pane
## Restart now?
##
## 1: Negative
## 2: Not now
## 3: Yup
##
## Selection: 3
```
RStudio should have been restarted (so it can add a "Git" pane in case you want to use the GUI to manage git) and the directory tree will now have a `.git/` subdirectory that you should (almost) never touch by hand.
The last thing to do is to "vaccinate" your git setup so you don't leak sensitive or unnecessary files when you (eventually) share your creation with the world:
```{r}
usethis::git_vaccinate()
## ✔ Adding '.Rproj.user', '.Rhistory', '.Rdata' to '/Users/someuser/.gitignore'
```
We now have a basic, working R package that is devoid of any real functionality other than that of getting us familiar with the package setup and validation processes. We'll be building upon this experience in most of the coming chapters.
## Quick Reference {#quick-reference}
After ensuring you've got the recommended `options()` in place, here are the steps to setup a new package:
```{r}
# in any RStudio R Console session
devtools::create("~/packages/THE-PACKAGE-NAME")
# in the newly created package RStudio R Console session:
usethis::use_mit_license() # need a LICENSE file
usethis::use_roxygen_md() # use {roxygen2} for documentation and configuration
usethis::use_package_doc() # setup a package-level manual page
usethis::use_testthat() # setup testing infrastructure
usethis::use_test("placeholder") # setup a placeholder test file
devtools::document() # Let {roxygen2} create NAMESPACE entries, build manual pages (and, more later on)
devtools::check() # looking for the three "0's" that tell us we're ready to roll!
usethis::use_git() # put the directory under git version control
usethis::git_vaccinate() # Prevent leaking credentials and other unnecessary filesystem cruft
```
Rather than re-type `devtools::document()` (et al) whenever you need to run {roxygen2} or build/check a package you can use RStudio keyboard shortcuts that are designed to seamlessly integrate with the {devtools} ecosystem:
| Operation | Windows & Linux | Mac | {devtools} equivalent |
|------------------------|-----------------|-------------|-----------------------|
| Install and Restart | Ctrl+Shift+B | Cmd+Shift+B | devtools::install() |
| Load All (devtools) | Ctrl+Shift+L | Cmd+Shift+L | devtools::load_all() |
| Test Package (Desktop) | Ctrl+Shift+T | Cmd+Shift+T | devtools::test() |
| Test Package (Web) | Ctrl+Alt+F7 | Cmd+Alt+F7 | devtools::test() |
| Check Package | Ctrl+Shift+E | Cmd+Shift+E | devtools::check() |
| Document Package | Ctrl+Shift+D | Cmd+Shift+D | devtools::document() |
We'll refer to these operations as "install" (or "build"), "load all", "test", "check", and "document" from now on so you can choose to use the console or the shortcuts as you prefer.
## Exercises {#exercises}
Our package may be kinda, well, _useless_ for the moment but that doesn't mean you can't show it some love and get some practice in at the same time while things are still relatively straightforward.
- Modify the `Title`, `Version`, and `Description` fields of the `DESCRIPTION` file and refine them as needed until package checks pass.
- Deliberately mangle parts of the `DESCRIPTION` file to see what errors or warnings you receive during the package check process.
- Read up on {roxygen2} and add some `Section`s to it formatted with markdown and/or LaTeX. Re-"document" the package and see how your changes look.
- Edit the `test-placeholder.R` file and change the placeholder test it created so it fails and then re-check the package to see what warnings or errors show up.
- After you've made (valid, working) modifications to any/all of the above _and package checks pass_, use either the git command line tools or the RStudio Git pane to add your updates to the git tree. Use the resources linked to in the previous chapter if you need a refresher on how to do that.
- Re-run through all the steps with a brand new package name just to make sure you're comfortable with the package creation process.
## Up Next {#basic-up-next}
In the next installment in the series we will start wrapping by creating a basic wrapper that just calls out to the operating system shell to run commands.

1
README.md

@ -0,0 +1 @@
This is a minimal example of a book based on R Markdown and **bookdown** (https://github.com/rstudio/bookdown). Please see the page "Get Started" at https://bookdown.org/home/about/ for how to compile this example.

510
_book/basic-r-package.html

@ -0,0 +1,510 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>3 Building A Basic R Package | Writing Frictionless R Package Wrappers</title>
<meta name="description" content="Extending the functionality of R via R’s foreign language interfaces." />
<meta name="generator" content="bookdown 0.16 and GitBook 2.6.7" />
<meta property="og:title" content="3 Building A Basic R Package | Writing Frictionless R Package Wrappers" />
<meta property="og:type" content="book" />
<meta property="og:url" content="https://rud.is/books/writing-frictionless-r-package-wrappers/" />
<meta property="og:description" content="Extending the functionality of R via R’s foreign language interfaces." />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="3 Building A Basic R Package | Writing Frictionless R Package Wrappers" />
<meta name="twitter:description" content="Extending the functionality of R via R’s foreign language interfaces." />
<meta name="author" content="Bob Rudis" />
<meta name="date" content="2020-01-02" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<link rel="prev" href="intro.html"/>
<script src="libs/jquery-2.2.3/jquery.min.js"></script>
<script src="libs/elevate-section-attrs-2.0/elevate-section-attrs.js"></script>
<link href="libs/gitbook-2.6.7/css/style.css" rel="stylesheet" />
<link href="libs/gitbook-2.6.7/css/plugin-table.css" rel="stylesheet" />
<link href="libs/gitbook-2.6.7/css/plugin-bookdown.css" rel="stylesheet" />
<link href="libs/gitbook-2.6.7/css/plugin-highlight.css" rel="stylesheet" />
<link href="libs/gitbook-2.6.7/css/plugin-search.css" rel="stylesheet" />
<link href="libs/gitbook-2.6.7/css/plugin-fontsettings.css" rel="stylesheet" />
<link href="libs/gitbook-2.6.7/css/plugin-clipboard.css" rel="stylesheet" />
<style type="text/css">
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
color: #aaaaaa;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
div.sourceCode
{ }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code span.at { color: #7d9029; } /* Attribute */
code span.bn { color: #40a070; } /* BaseN */
code span.bu { } /* BuiltIn */
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code span.ch { color: #4070a0; } /* Char */
code span.cn { color: #880000; } /* Constant */
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
code span.dt { color: #902000; } /* DataType */
code span.dv { color: #40a070; } /* DecVal */
code span.er { color: #ff0000; font-weight: bold; } /* Error */
code span.ex { } /* Extension */
code span.fl { color: #40a070; } /* Float */
code span.fu { color: #06287e; } /* Function */
code span.im { } /* Import */
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
code span.op { color: #666666; } /* Operator */
code span.ot { color: #007020; } /* Other */
code span.pp { color: #bc7a00; } /* Preprocessor */
code span.sc { color: #4070a0; } /* SpecialChar */
code span.ss { color: #bb6688; } /* SpecialString */
code span.st { color: #4070a0; } /* String */
code span.va { color: #19177c; } /* Variable */
code span.vs { color: #4070a0; } /* VerbatimString */
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
</style>
<link rel="stylesheet" href="style.css" type="text/css" />
</head>
<body>
<div class="book without-animation with-summary font-size-2 font-family-1" data-basepath=".">
<div class="book-summary">
<nav role="navigation">
<ul class="summary">
<li><a href="./">Writing Frictionless R Package Wrappers</a></li>
<li class="divider"></li>
<li class="chapter" data-level="1" data-path="index.html"><a href="index.html"><i class="fa fa-check"></i><b>1</b> Preface</a></li>
<li class="chapter" data-level="2" data-path="intro.html"><a href="intro.html"><i class="fa fa-check"></i><b>2</b> Introduction</a>
<ul>
<li class="chapter" data-level="2.1" data-path="intro.html"><a href="intro.html#intro-reqs"><i class="fa fa-check"></i><b>2.1</b> Base Requirements</a></li>
<li class="chapter" data-level="2.2" data-path="intro.html"><a href="intro.html#intro-refs"><i class="fa fa-check"></i><b>2.2</b> Supplemental References</a></li>
<li class="chapter" data-level="2.3" data-path="intro.html"><a href="intro.html#intro-up-next"><i class="fa fa-check"></i><b>2.3</b> Up Next</a></li>
</ul></li>
<li class="chapter" data-level="3" data-path="basic-r-package.html"><a href="basic-r-package.html"><i class="fa fa-check"></i><b>3</b> Building A Basic R Package</a>
<ul>
<li class="chapter" data-level="3.1" data-path="basic-r-package.html"><a href="basic-r-package.html#config-devtools"><i class="fa fa-check"></i><b>3.1</b> Configuring {devtools}</a></li>
<li class="chapter" data-level="3.2" data-path="basic-r-package.html"><a href="basic-r-package.html#create-a-package"><i class="fa fa-check"></i><b>3.2</b> Creating A Package</a></li>
<li class="chapter" data-level="3.3" data-path="basic-r-package.html"><a href="basic-r-package.html#round-out-corners"><i class="fa fa-check"></i><b>3.3</b> Rounding Out The Corners</a></li>
<li class="chapter" data-level="3.4" data-path="basic-r-package.html"><a href="basic-r-package.html#pass-the-test"><i class="fa fa-check"></i><b>3.4</b> Passing The Test</a></li>
<li class="chapter" data-level="3.5" data-path="basic-r-package.html"><a href="basic-r-package.html#get-under-control"><i class="fa fa-check"></i><b>3.5</b> Getting Things Under Control</a></li>
<li class="chapter" data-level="3.6" data-path="basic-r-package.html"><a href="basic-r-package.html#quick-reference"><i class="fa fa-check"></i><b>3.6</b> Quick Reference</a></li>
<li class="chapter" data-level="3.7" data-path="basic-r-package.html"><a href="basic-r-package.html#exercises"><i class="fa fa-check"></i><b>3.7</b> Exercises</a></li>
<li class="chapter" data-level="3.8" data-path="basic-r-package.html"><a href="basic-r-package.html#basic-up-next"><i class="fa fa-check"></i><b>3.8</b> Up Next</a></li>
</ul></li>
<li class="divider"></li>
<li><a href="https://github.com/rstudio/bookdown" target="blank">Published with bookdown</a></li>
</ul>
</nav>
</div>
<div class="book-body">
<div class="body-inner">
<div class="book-header" role="navigation">
<h1>
<i class="fa fa-circle-o-notch fa-spin"></i><a href="./">Writing Frictionless R Package Wrappers</a>
</h1>
</div>
<div class="page-wrapper" tabindex="-1" role="main">
<div class="page-inner">
<section class="normal" id="section-">
<div id="basic-r-package" class="section level1" number="3">
<h1 number="3"><span class="header-section-number">3</span> Building A Basic R Package</h1>
<p>Before we start wrapping foreign language code we need to make sure that basic R packages can be created. If you’ve followed along from the previous chapter you have everything you need to get started here. <em>Just to make sure</em>, you should be able to fire up a new RStudio session and execute the following R code and see similar output. If not, you’ll need to go through the steps and resources outlined there before continuing.</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb2-1"><a href="basic-r-package.html#cb2-1"></a>pkgbuild<span class="op">::</span><span class="kw">check_build_tools</span>()</span>
<span id="cb2-2"><a href="basic-r-package.html#cb2-2"></a><span class="co">## Your system is ready to build packages!</span></span></code></pre></div>
<div id="config-devtools" class="section level2" number="3.1">
<h2 number="3.1"><span class="header-section-number">3.1</span> Configuring {devtools}</h2>
<p>We’re going to rely on the {devtools} package for many operations and the first thing you should do now is execute <code>help("create", "devtools")</code> in an RStudio R console to see the package documentation page where you’ll see guidance pointing you to <code>devtools::use_description()</code> that lists some R session <code>options()</code> that you can set to make your package development life much easier and quicker. Specifically, it lets you know that you can setup your <code>~/.Rprofile</code> to include the certain options settings which will automatically fill in fields each time you create a new package vs you either specifying these fields manually in the package creation GUI or as parameters to <code>devtools::create()</code>.</p>
<p>A good, minimal setup would be something like:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb3-1"><a href="basic-r-package.html#cb3-1"></a><span class="kw">options</span>(</span>
<span id="cb3-2"><a href="basic-r-package.html#cb3-2"></a> <span class="dt">usethis.description =</span> <span class="kw">list</span>(</span>
<span id="cb3-3"><a href="basic-r-package.html#cb3-3"></a> <span class="st">`</span><span class="dt">Authors@R</span><span class="st">`</span> =<span class="st"> &#39;person(&quot;Some&quot;, &quot;One&quot;, email = &quot;someone@example.com&quot;, role = c(&quot;aut&quot;, &quot;cre&quot;),</span></span>
<span id="cb3-4"><a href="basic-r-package.html#cb3-4"></a><span class="st"> comment = c(ORCID = &quot;YOUR-ORCID-ID&quot;))&#39;</span>,</span>
<span id="cb3-5"><a href="basic-r-package.html#cb3-5"></a> <span class="dt">License =</span> <span class="st">&quot;MIT + file LICENSE&quot;</span></span>
<span id="cb3-6"><a href="basic-r-package.html#cb3-6"></a> )</span>
<span id="cb3-7"><a href="basic-r-package.html#cb3-7"></a>)</span></code></pre></div>
<p>NOTE: If you do not have an “ORCID” you really should get one (they’re free!) by heading over to
<a href="https://orcid.org/" class="uri">https://orcid.org/</a> — and filling in some basic information.</p>
<p>Take a moment to edit your <code>~/.Rprofile</code>. If you’re not sure about how to do that there is an excellent chapter in Efficient R Programming<a href="#fn8" class="footnote-ref" id="fnref8"><sup>8</sup></a> which walks you through the process.</p>
<p>Once you’ve added or verified these new <code>options()</code> settings, restart your R session.</p>
</div>
<div id="create-a-package" class="section level2" number="3.2">
<h2 number="3.2"><span class="header-section-number">3.2</span> Creating A Package</h2>
<p>We’re <em>almost</em> ready to create and build a basic R package. All R packages live in a package directory and I highly suggest creating a <code>packages</code> directory right off your home directory (e.g. “<code>~/packages</code>”) or someplace where you’ll be able to keep them all organized and accessible. The rest of these chapters will assume you’re using “<code>~/packages</code>” as the</p>
<p>With {devtools} now pre-configured, use the RStudio R Console pane to execute the following code which should produce similar output and open up a new RStudio session with the new package directory:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb4-1"><a href="basic-r-package.html#cb4-1"></a>devtools<span class="op">::</span><span class="kw">create</span>(<span class="st">&quot;~/packages/myfirstpackage&quot;</span>) </span>
<span id="cb4-2"><a href="basic-r-package.html#cb4-2"></a><span class="co">## ✔ Creating &#39;/Users/someuser/packages/myfirstpackage/&#39;</span></span>
<span id="cb4-3"><a href="basic-r-package.html#cb4-3"></a><span class="co">## ✔ Setting active project to &#39;/Users/someuser/packages/myfirstpackage&#39;</span></span>
<span id="cb4-4"><a href="basic-r-package.html#cb4-4"></a><span class="co">## ✔ Creating &#39;R/&#39;</span></span>
<span id="cb4-5"><a href="basic-r-package.html#cb4-5"></a><span class="co">## ✔ Writing &#39;DESCRIPTION&#39;</span></span>
<span id="cb4-6"><a href="basic-r-package.html#cb4-6"></a><span class="co">## Package: myfirstpackage</span></span>
<span id="cb4-7"><a href="basic-r-package.html#cb4-7"></a><span class="co">## Title: What the Package Does (One Line, Title Case)</span></span>
<span id="cb4-8"><a href="basic-r-package.html#cb4-8"></a><span class="co">## Version: 0.0.0.9000</span></span>
<span id="cb4-9"><a href="basic-r-package.html#cb4-9"></a><span class="co">## Authors@R (parsed):</span></span>
<span id="cb4-10"><a href="basic-r-package.html#cb4-10"></a><span class="co">## * Bob Rudis &lt;bob@rud.is&gt; [aut, cre] (&lt;https://orcid.org/0000-0001-5670-2640&gt;)</span></span>
<span id="cb4-11"><a href="basic-r-package.html#cb4-11"></a><span class="co">## Description: What the package does (one paragraph).</span></span>
<span id="cb4-12"><a href="basic-r-package.html#cb4-12"></a><span class="co">## License: MIT + file LICENSE</span></span>
<span id="cb4-13"><a href="basic-r-package.html#cb4-13"></a><span class="co">## Encoding: UTF-8</span></span>
<span id="cb4-14"><a href="basic-r-package.html#cb4-14"></a><span class="co">## LazyData: true</span></span>
<span id="cb4-15"><a href="basic-r-package.html#cb4-15"></a><span class="co">## ✔ Writing &#39;NAMESPACE&#39;</span></span>
<span id="cb4-16"><a href="basic-r-package.html#cb4-16"></a><span class="co">## ✔ Writing &#39;myfirstpackage.Rproj&#39;</span></span>
<span id="cb4-17"><a href="basic-r-package.html#cb4-17"></a><span class="co">## ✔ Adding &#39;.Rproj.user&#39; to &#39;.gitignore&#39;</span></span>
<span id="cb4-18"><a href="basic-r-package.html#cb4-18"></a><span class="co">## ✔ Adding &#39;^myfirstpackage\\.Rproj$&#39;, &#39;^\\.Rproj\\.user$&#39; to &#39;.Rbuildignore&#39;</span></span>
<span id="cb4-19"><a href="basic-r-package.html#cb4-19"></a><span class="co">## ✔ Opening &#39;/Users/someuser/packages/myfirstpackage/&#39; in new RStudio session</span></span>
<span id="cb4-20"><a href="basic-r-package.html#cb4-20"></a><span class="co">## ✔ Setting active project to &#39;&lt;no active project&gt;&#39;</span></span></code></pre></div>
<p>The directory structure will look like this:</p>
<pre><code>.
├── DESCRIPTION
├── NAMESPACE
├── R/
└── myfirstpackage.Rproj</code></pre>
<p>At this point we still do not have a “perfect” R package. To prove this, use the R console to run <code>devtools::check()</code> and — after some rather verbose output — you’ll see the following lines at the end:</p>
<pre><code>&gt; checking DESCRIPTION meta-information ... WARNING
Invalid license file pointers: LICENSE
0 errors ✓ | 1 warning x | 0 notes ✓</code></pre>
<p>Since we’re saying that our package will be using the MIT license, we need to ensure there’s an associated <code>LICENSE</code> file which we can do by executing <code>usethis::use_mit_license()</code> which will create the necessary files and ensure the <code>License</code> field in the <code>DESCRIPTION</code> file is formatted properly.</p>
<p>If you run <code>devtools::check()</code> again, now, your final line should report:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb7-1"><a href="basic-r-package.html#cb7-1"></a><span class="co">## 0 errors ✓ | 0 warnings ✓ | 0 notes ✓</span></span></code></pre></div>
<p>and the package directory tree should look like this:</p>
<pre><code>├── DESCRIPTION
├── LICENSE
├── LICENSE.md
├── NAMESPACE
├── R/
└── myfirstpackage.Rproj</code></pre>
</div>
<div id="round-out-corners" class="section level2" number="3.3">
<h2 number="3.3"><span class="header-section-number">3.3</span> Rounding Out The Corners</h2>
<p>While we have a minimum viable package there are a few other steps we should take during this setup phase. First we’ll setup our package to use <code>{roxygen2}</code><a href="#fn9" class="footnote-ref" id="fnref9"><sup>9</sup></a> for documenting functions, declaring <code>NAMESPACE</code> imports, and other helper-features that will be introduced in later chapters. We can do this via <code>usethis::use_roxygen_md()</code>:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb9-1"><a href="basic-r-package.html#cb9-1"></a>usethis<span class="op">::</span><span class="kw">use_roxygen_md</span>()</span>
<span id="cb9-2"><a href="basic-r-package.html#cb9-2"></a><span class="co">## ✔ Setting Roxygen field in DESCRIPTION to &#39;list(markdown = TRUE)&#39;</span></span>
<span id="cb9-3"><a href="basic-r-package.html#cb9-3"></a><span class="co">## ✔ Setting RoxygenNote field in DESCRIPTION to &#39;7.0.2&#39;</span></span>
<span id="cb9-4"><a href="basic-r-package.html#cb9-4"></a><span class="co">## ● Run `devtools::document()`</span></span></code></pre></div>
<p>We won’t run <code>devtools::document()</code> <em>just yet</em>, though. Before we do that we’ll also create an R file where we can store top-level package introduction/meta-information:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb10-1"><a href="basic-r-package.html#cb10-1"></a>usethis<span class="op">::</span><span class="kw">use_package_doc</span>()</span>
<span id="cb10-2"><a href="basic-r-package.html#cb10-2"></a><span class="co">## ✔ Writing &#39;R/myfirstpackage-package.R&#39;</span></span></code></pre></div>
<p>Now, our directory tree should look like:</p>
<pre><code>.
├── DESCRIPTION
├── LICENSE
├── LICENSE.md
├── NAMESPACE
├── R
│ └── myfirstpackage-package.R
└── myfirstpackage.Rproj</code></pre>
<p>Now, run <code>devtools::document()</code> which will translate the {roxygen2} comments into a properly-formatted R documentation file and regenerate the <code>NAMESPACE</code> file (as we’ll be managing package imports and exports via {roxygen2} comments). The directory tree will now look like:</p>
<pre><code>.
├── DESCRIPTION
├── LICENSE
├── LICENSE.md
├── NAMESPACE
├── R
│ └── myfirstpackage-package.R
├── man
│ └── myfirstpackage-package.Rd
└── myfirstpackage.Rproj</code></pre>
<p>and, we can now re-run <code>devtools::check()</code> to make sure we have the three “0’s” we’re aiming for each time we check our package for errors.</p>
</div>
<div id="pass-the-test" class="section level2" number="3.4">
<h2 number="3.4"><span class="header-section-number">3.4</span> Passing The Test</h2>
<p>We’re going to want to write and use tests to ensure our package works properly. There are many R package testing frameworks available. To ease the introduction into this process, we’ll use one of the frameworks that came along for the ride when you installed the various packages outlined in the previous chapter: {testthat}<a href="#fn10" class="footnote-ref" id="fnref10"><sup>10</sup></a>. Setting up {testthat} is also pretty painless thanks to the {usethis} package we’ve been taking advantage of quite a bit so far. We’ll create the {testthat} overall infrastructure then add a placeholder test script since <code>devtools::check()</code> will complain about no tests being available if we do not have at least a single script it can execute during the test phase of the package checking process.</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb13-1"><a href="basic-r-package.html#cb13-1"></a>usethis<span class="op">::</span><span class="kw">use_testthat</span>()</span>
<span id="cb13-2"><a href="basic-r-package.html#cb13-2"></a><span class="co">## ✔ Adding &#39;testthat&#39; to Suggests field in DESCRIPTION</span></span>
<span id="cb13-3"><a href="basic-r-package.html#cb13-3"></a><span class="co">## ✔ Creating &#39;tests/testthat/&#39;</span></span>
<span id="cb13-4"><a href="basic-r-package.html#cb13-4"></a><span class="co">## ✔ Writing &#39;tests/testthat.R&#39;</span></span>
<span id="cb13-5"><a href="basic-r-package.html#cb13-5"></a><span class="co">## ● Call `use_test()` to initialize a basic test file and open it for editing.</span></span>
<span id="cb13-6"><a href="basic-r-package.html#cb13-6"></a></span>
<span id="cb13-7"><a href="basic-r-package.html#cb13-7"></a>usethis<span class="op">::</span><span class="kw">use_test</span>(<span class="st">&quot;placeholder&quot;</span>)</span>
<span id="cb13-8"><a href="basic-r-package.html#cb13-8"></a><span class="co">## ✔ Increasing &#39;testthat&#39; version to &#39;&gt;= 2.1.0&#39; in DESCRIPTION</span></span>
<span id="cb13-9"><a href="basic-r-package.html#cb13-9"></a><span class="co">## ✔ Writing &#39;tests/testthat/test-placeholder.R&#39;</span></span>
<span id="cb13-10"><a href="basic-r-package.html#cb13-10"></a><span class="co">## ● Modify &#39;tests/testthat/test-placeholder.R&#39;</span></span></code></pre></div>
<p>The directory tree will now look like this:</p>
<pre><code>.
├── DESCRIPTION
├── LICENSE
├── LICENSE.md
├── NAMESPACE
├── R
│ └── myfirstpackage-package.R
├── man
│ └── myfirstpackage-package.Rd
├── myfirstpackage.Rproj
└── tests
├── testthat
│ └── test-placeholder.R
└── testthat.R</code></pre>
<p>Run <code>devtools::check()</code> one more time to make sure we’ve got those precious 3 “0’s” one last time.</p>
</div>
<div id="get-under-control" class="section level2" number="3.5">
<h2 number="3.5"><span class="header-section-number">3.5</span> Getting Things Under Control</h2>
<p>We’re <em>almost</em> done! One final step is to turn this directory into a git-managed directory so we can work a bit more safely and eventually share our development work with a broader audience. Provided you followed the outline in the previous chapter, setting up git is as straightforward as one {usethis} function call:</p>
<div class="sourceCode" id="cb15"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb15-1"><a href="basic-r-package.html#cb15-1"></a>usethis<span class="op">::</span><span class="kw">use_git</span>()</span>
<span id="cb15-2"><a href="basic-r-package.html#cb15-2"></a><span class="co">## ✔ Setting active project to &#39;/Users/someuser/packages/myfirstpackage&#39;</span></span>
<span id="cb15-3"><a href="basic-r-package.html#cb15-3"></a><span class="co">## ✔ Initialising Git repo</span></span>
<span id="cb15-4"><a href="basic-r-package.html#cb15-4"></a><span class="co">## ✔ Adding &#39;.Rhistory&#39;, &#39;.RData&#39; to &#39;.gitignore&#39;</span></span>
<span id="cb15-5"><a href="basic-r-package.html#cb15-5"></a><span class="co">## There are 10 uncommitted files:</span></span>
<span id="cb15-6"><a href="basic-r-package.html#cb15-6"></a><span class="co">## * &#39;.gitignore&#39;</span></span>
<span id="cb15-7"><a href="basic-r-package.html#cb15-7"></a><span class="co">## * &#39;.Rbuildignore&#39;</span></span>
<span id="cb15-8"><a href="basic-r-package.html#cb15-8"></a><span class="co">## * &#39;DESCRIPTION&#39;</span></span>
<span id="cb15-9"><a href="basic-r-package.html#cb15-9"></a><span class="co">## * &#39;LICENSE&#39;</span></span>
<span id="cb15-10"><a href="basic-r-package.html#cb15-10"></a><span class="co">## * &#39;LICENSE.md&#39;</span></span>
<span id="cb15-11"><a href="basic-r-package.html#cb15-11"></a><span class="co">## * &#39;man/&#39;</span></span>
<span id="cb15-12"><a href="basic-r-package.html#cb15-12"></a><span class="co">## * &#39;myfirstpackage.Rproj&#39;</span></span>
<span id="cb15-13"><a href="basic-r-package.html#cb15-13"></a><span class="co">## * &#39;NAMESPACE&#39;</span></span>
<span id="cb15-14"><a href="basic-r-package.html#cb15-14"></a><span class="co">## * &#39;R/&#39;</span></span>
<span id="cb15-15"><a href="basic-r-package.html#cb15-15"></a><span class="co">## * &#39;tests/&#39;</span></span>
<span id="cb15-16"><a href="basic-r-package.html#cb15-16"></a><span class="co">## Is it ok to commit them?</span></span>
<span id="cb15-17"><a href="basic-r-package.html#cb15-17"></a><span class="co">## </span></span>
<span id="cb15-18"><a href="basic-r-package.html#cb15-18"></a><span class="co">## 1: For sure</span></span>
<span id="cb15-19"><a href="basic-r-package.html#cb15-19"></a><span class="co">## 2: Negative</span></span>
<span id="cb15-20"><a href="basic-r-package.html#cb15-20"></a><span class="co">## 3: Not now</span></span>
<span id="cb15-21"><a href="basic-r-package.html#cb15-21"></a><span class="co">## </span></span>
<span id="cb15-22"><a href="basic-r-package.html#cb15-22"></a><span class="co">## Selection: 1</span></span>
<span id="cb15-23"><a href="basic-r-package.html#cb15-23"></a><span class="co">## ✔ Adding files</span></span>
<span id="cb15-24"><a href="basic-r-package.html#cb15-24"></a><span class="co">## ✔ Commit with message &#39;Initial commit&#39;</span></span>
<span id="cb15-25"><a href="basic-r-package.html#cb15-25"></a><span class="co">## ● A restart of RStudio is required to activate the Git pane</span></span>
<span id="cb15-26"><a href="basic-r-package.html#cb15-26"></a><span class="co">## Restart now?</span></span>
<span id="cb15-27"><a href="basic-r-package.html#cb15-27"></a><span class="co">## </span></span>
<span id="cb15-28"><a href="basic-r-package.html#cb15-28"></a><span class="co">## 1: Negative</span></span>
<span id="cb15-29"><a href="basic-r-package.html#cb15-29"></a><span class="co">## 2: Not now</span></span>
<span id="cb15-30"><a href="basic-r-package.html#cb15-30"></a><span class="co">## 3: Yup</span></span>
<span id="cb15-31"><a href="basic-r-package.html#cb15-31"></a><span class="co">## </span></span>
<span id="cb15-32"><a href="basic-r-package.html#cb15-32"></a><span class="co">## Selection: 3</span></span></code></pre></div>
<p>RStudio should have been restarted (so it can add a “Git” pane in case you want to use the GUI to manage git) and the directory tree will now have a <code>.git/</code> subdirectory that you should (almost) never touch by hand.</p>
<p>The last thing to do is to “vaccinate” your git setup so you don’t leak sensitive or unnecessary files when you (eventually) share your creation with the world:</p>
<div class="sourceCode" id="cb16"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb16-1"><a href="basic-r-package.html#cb16-1"></a>usethis<span class="op">::</span><span class="kw">git_vaccinate</span>()</span>
<span id="cb16-2"><a href="basic-r-package.html#cb16-2"></a><span class="co">## ✔ Adding &#39;.Rproj.user&#39;, &#39;.Rhistory&#39;, &#39;.Rdata&#39; to &#39;/Users/someuser/.gitignore&#39;</span></span></code></pre></div>
<p>We now have a basic, working R package that is devoid of any real functionality other than that of getting us familiar with the package setup and validation processes. We’ll be building upon this experience in most of the coming chapters.</p>
</div>
<div id="quick-reference" class="section level2" number="3.6">
<h2 number="3.6"><span class="header-section-number">3.6</span> Quick Reference</h2>
<p>After ensuring you’ve got the recommended <code>options()</code> in place, here are the steps to setup a new package:</p>
<div class="sourceCode" id="cb17"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb17-1"><a href="basic-r-package.html#cb17-1"></a><span class="co"># in any RStudio R Console session</span></span>
<span id="cb17-2"><a href="basic-r-package.html#cb17-2"></a>devtools<span class="op">::</span><span class="kw">create</span>(<span class="st">&quot;~/packages/THE-PACKAGE-NAME&quot;</span>)</span>
<span id="cb17-3"><a href="basic-r-package.html#cb17-3"></a></span>
<span id="cb17-4"><a href="basic-r-package.html#cb17-4"></a><span class="co"># in the newly created package RStudio R Console session:</span></span>
<span id="cb17-5"><a href="basic-r-package.html#cb17-5"></a>usethis<span class="op">::</span><span class="kw">use_mit_license</span>() <span class="co"># need a LICENSE file</span></span>
<span id="cb17-6"><a href="basic-r-package.html#cb17-6"></a>usethis<span class="op">::</span><span class="kw">use_roxygen_md</span>() <span class="co"># use {roxygen2} for documentation and configuration</span></span>
<span id="cb17-7"><a href="basic-r-package.html#cb17-7"></a>usethis<span class="op">::</span><span class="kw">use_package_doc</span>() <span class="co"># setup a package-level manual page</span></span>
<span id="cb17-8"><a href="basic-r-package.html#cb17-8"></a>usethis<span class="op">::</span><span class="kw">use_testthat</span>() <span class="co"># setup testing infrastructure</span></span>
<span id="cb17-9"><a href="basic-r-package.html#cb17-9"></a>usethis<span class="op">::</span><span class="kw">use_test</span>(<span class="st">&quot;placeholder&quot;</span>) <span class="co"># setup a placeholder test file</span></span>
<span id="cb17-10"><a href="basic-r-package.html#cb17-10"></a>devtools<span class="op">::</span><span class="kw">document</span>() <span class="co"># Let {roxygen2} create NAMESPACE entries, build manual pages (and, more later on)</span></span>
<span id="cb17-11"><a href="basic-r-package.html#cb17-11"></a>devtools<span class="op">::</span><span class="kw">check</span>() <span class="co"># looking for the three &quot;0&#39;s&quot; that tell us we&#39;re ready to roll!</span></span>
<span id="cb17-12"><a href="basic-r-package.html#cb17-12"></a>usethis<span class="op">::</span><span class="kw">use_git</span>() <span class="co"># put the directory under git version control</span></span>
<span id="cb17-13"><a href="basic-r-package.html#cb17-13"></a>usethis<span class="op">::</span><span class="kw">git_vaccinate</span>() <span class="co"># Prevent leaking credentials and other unnecessary filesystem cruft</span></span></code></pre></div>
<p>Rather than re-type <code>devtools::document()</code> (et al) whenever you need to run {roxygen2} or build/check a package you can use RStudio keyboard shortcuts that are designed to seamlessly integrate with the {devtools} ecosystem:</p>
<table>
<thead>
<tr class="header">
<th>Operation</th>
<th>Windows &amp; Linux</th>
<th>Mac</th>
<th>{devtools} equivalent</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Install and Restart</td>
<td>Ctrl+Shift+B</td>
<td>Cmd+Shift+B</td>
<td>devtools::install()</td>
</tr>
<tr class="even">
<td>Load All (devtools)</td>
<td>Ctrl+Shift+L</td>
<td>Cmd+Shift+L</td>
<td>devtools::load_all()</td>
</tr>
<tr class="odd">
<td>Test Package (Desktop)</td>
<td>Ctrl+Shift+T</td>
<td>Cmd+Shift+T</td>
<td>devtools::test()</td>
</tr>
<tr class="even">
<td>Test Package (Web)</td>
<td>Ctrl+Alt+F7</td>
<td>Cmd+Alt+F7</td>
<td>devtools::test()</td>
</tr>
<tr class="odd">
<td>Check Package</td>
<td>Ctrl+Shift+E</td>
<td>Cmd+Shift+E</td>
<td>devtools::check()</td>
</tr>
<tr class="even">
<td>Document Package</td>
<td>Ctrl+Shift+D</td>
<td>Cmd+Shift+D</td>
<td>devtools::document()</td>
</tr>
</tbody>
</table>
<p>We’ll refer to these operations as “install” (or “build”), “load all”, “test”, “check”, and “document” from now on so you can choose to use the console or the shortcuts as you prefer.</p>
</div>
<div id="exercises" class="section level2" number="3.7">
<h2 number="3.7"><span class="header-section-number">3.7</span> Exercises</h2>
<p>Our package may be kinda, well, <em>useless</em> for the moment but that doesn’t mean you can’t show it some love and get some practice in at the same time while things are still relatively straightforward.</p>
<ul>
<li>Modify the <code>Title</code>, <code>Version</code>, and <code>Description</code> fields of the <code>DESCRIPTION</code> file and refine them as needed until package checks pass.</li>
<li>Deliberately mangle parts of the <code>DESCRIPTION</code> file to see what errors or warnings you receive during the package check process.</li>
<li>Read up on {roxygen2} and add some <code>Section</code>s to it formatted with markdown and/or LaTeX. Re-“document” the package and see how your changes look.</li>
<li>Edit the <code>test-placeholder.R</code> file and change the placeholder test it created so it fails and then re-check the package to see what warnings or errors show up.</li>
<li>After you’ve made (valid, working) modifications to any/all of the above <em>and package checks pass</em>, use either the git command line tools or the RStudio Git pane to add your updates to the git tree. Use the resources linked to in the previous chapter if you need a refresher on how to do that.</li>
<li>Re-run through all the steps with a brand new package name just to make sure you’re comfortable with the package creation process.</li>
</ul>
</div>
<div id="basic-up-next" class="section level2" number="3.8">
<h2 number="3.8"><span class="header-section-number">3.8</span> Up Next</h2>
<p>In the next installment in the series we will start wrapping by creating a basic wrapper that just calls out to the operating system shell to run commands.</p>
</div>
</div>
<div class="footnotes">
<hr />
<ol start="8">
<li id="fn8"><p>Efficient R Programming, “3.3 R Startup”; (<a href="https://csgillespie.github.io/efficientR/3-3-r-startup.html#r-startup" class="uri">https://csgillespie.github.io/efficientR/3-3-r-startup.html#r-startup</a>)<a href="basic-r-package.html#fnref8" class="footnote-back">↩︎</a></p></li>
<li id="fn9"><p>{roxygen2} Home; (<a href="https://roxygen2.r-lib.org/" class="uri">https://roxygen2.r-lib.org/</a>)<a href="basic-r-package.html#fnref9" class="footnote-back">↩︎</a></p></li>
<li id="fn10"><p>{testthat} Home; (<a href="https://testthat.r-lib.org/" class="uri">https://testthat.r-lib.org/</a>)<a href="basic-r-package.html#fnref10" class="footnote-back">↩︎</a></p></li>
</ol>
</div>
</section>
</div>
</div>
</div>
<a href="intro.html" class="navigation navigation-prev navigation-unique" aria-label="Previous page"><i class="fa fa-angle-left"></i></a>
</div>
</div>
<script src="libs/gitbook-2.6.7/js/app.min.js"></script>
<script src="libs/gitbook-2.6.7/js/lunr.js"></script>
<script src="libs/gitbook-2.6.7/js/clipboard.min.js"></script>
<script src="libs/gitbook-2.6.7/js/plugin-search.js"></script>
<script src="libs/gitbook-2.6.7/js/plugin-sharing.js"></script>
<script src="libs/gitbook-2.6.7/js/plugin-fontsettings.js"></script>
<script src="libs/gitbook-2.6.7/js/plugin-bookdown.js"></script>
<script src="libs/gitbook-2.6.7/js/jquery.highlight.js"></script>
<script src="libs/gitbook-2.6.7/js/plugin-clipboard.js"></script>
<script>
gitbook.require(["gitbook"], function(gitbook) {
gitbook.start({
"sharing": {
"github": false,
"facebook": true,
"twitter": true,
"linkedin": false,
"weibo": false,
"instapaper": false,
"vk": false,
"all": ["facebook", "twitter", "linkedin", "weibo", "instapaper"]
},
"fontsettings": {
"theme": "white",
"family": "sans",
"size": 2
},
"edit": {
"link": null,
"text": null
},
"history": {
"link": null,
"text": null
},
"view": {
"link": null,
"text": null
},
"download": ["writing-frictionless-r-package-wrappers.pdf", "writing-frictionless-r-package-wrappers.epub"],
"toc": {
"collapse": "subsection"
}
});
});
</script>
</body>
</html>

241
_book/index.html

@ -0,0 +1,241 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Writing Frictionless R Package Wrappers</title>
<meta name="description" content="Extending the functionality of R via R’s foreign language interfaces." />
<meta name="generator" content="bookdown 0.16 and GitBook 2.6.7" />
<meta property="og:title" content="Writing Frictionless R Package Wrappers" />
<meta property="og:type" content="book" />
<meta property="og:url" content="https://rud.is/books/writing-frictionless-r-package-wrappers/" />
<meta property="og:description" content="Extending the functionality of R via R’s foreign language interfaces." />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="Writing Frictionless R Package Wrappers" />
<meta name="twitter:description" content="Extending the functionality of R via R’s foreign language interfaces." />
<meta name="author" content="Bob Rudis" />
<meta name="date" content="2020-01-02" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<link rel="next" href="intro.html"/>
<script src="libs/jquery-2.2.3/jquery.min.js"></script>
<script src="libs/elevate-section-attrs-2.0/elevate-section-attrs.js"></script>
<link href="libs/gitbook-2.6.7/css/style.css" rel="stylesheet" />
<link href="libs/gitbook-2.6.7/css/plugin-table.css" rel="stylesheet" />
<link href="libs/gitbook-2.6.7/css/plugin-bookdown.css" rel="stylesheet" />
<link href="libs/gitbook-2.6.7/css/plugin-highlight.css" rel="stylesheet" />
<link href="libs/gitbook-2.6.7/css/plugin-search.css" rel="stylesheet" />
<link href="libs/gitbook-2.6.7/css/plugin-fontsettings.css" rel="stylesheet" />
<link href="libs/gitbook-2.6.7/css/plugin-clipboard.css" rel="stylesheet" />
<style type="text/css">
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
color: #aaaaaa;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
div.sourceCode
{ }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code span.at { color: #7d9029; } /* Attribute */
code span.bn { color: #40a070; } /* BaseN */
code span.bu { } /* BuiltIn */
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code span.ch { color: #4070a0; } /* Char */
code span.cn { color: #880000; } /* Constant */
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
code span.dt { color: #902000; } /* DataType */
code span.dv { color: #40a070; } /* DecVal */
code span.er { color: #ff0000; font-weight: bold; } /* Error */
code span.ex { } /* Extension */
code span.fl { color: #40a070; } /* Float */
code span.fu { color: #06287e; } /* Function */
code span.im { } /* Import */
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
code span.op { color: #666666; } /* Operator */
code span.ot { color: #007020; } /* Other */
code span.pp { color: #bc7a00; } /* Preprocessor */
code span.sc { color: #4070a0; } /* SpecialChar */
code span.ss { color: #bb6688; } /* SpecialString */
code span.st { color: #4070a0; } /* String */
code span.va { color: #19177c; } /* Variable */
code span.vs { color: #4070a0; } /* VerbatimString */
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
</style>
<link rel="stylesheet" href="style.css" type="text/css" />
</head>
<body>
<div class="book without-animation with-summary font-size-2 font-family-1" data-basepath=".">
<div class="book-summary">
<nav role="navigation">
<ul class="summary">
<li><a href="./">Writing Frictionless R Package Wrappers</a></li>
<li class="divider"></li>
<li class="chapter" data-level="1" data-path="index.html"><a href="index.html"><i class="fa fa-check"></i><b>1</b> Preface</a></li>
<li class="chapter" data-level="2" data-path="intro.html"><a href="intro.html"><i class="fa fa-check"></i><b>2</b> Introduction</a>
<ul>
<li class="chapter" data-level="2.1" data-path="intro.html"><a href="intro.html#intro-reqs"><i class="fa fa-check"></i><b>2.1</b> Base Requirements</a></li>
<li class="chapter" data-level="2.2" data-path="intro.html"><a href="intro.html#intro-refs"><i class="fa fa-check"></i><b>2.2</b> Supplemental References</a></li>
<li class="chapter" data-level="2.3" data-path="intro.html"><a href="intro.html#intro-up-next"><i class="fa fa-check"></i><b>2.3</b> Up Next</a></li>
</ul></li>
<li class="chapter" data-level="3" data-path="basic-r-package.html"><a href="basic-r-package.html"><i class="fa fa-check"></i><b>3</b> Building A Basic R Package</a>
<ul>
<li class="chapter" data-level="3.1" data-path="basic-r-package.html"><a href="basic-r-package.html#config-devtools"><i class="fa fa-check"></i><b>3.1</b> Configuring {devtools}</a></li>
<li class="chapter" data-level="3.2" data-path="basic-r-package.html"><a href="basic-r-package.html#create-a-package"><i class="fa fa-check"></i><b>3.2</b> Creating A Package</a></li>
<li class="chapter" data-level="3.3" data-path="basic-r-package.html"><a href="basic-r-package.html#round-out-corners"><i class="fa fa-check"></i><b>3.3</b> Rounding Out The Corners</a></li>
<li class="chapter" data-level="3.4" data-path="basic-r-package.html"><a href="basic-r-package.html#pass-the-test"><i class="fa fa-check"></i><b>3.4</b> Passing The Test</a></li>
<li class="chapter" data-level="3.5" data-path="basic-r-package.html"><a href="basic-r-package.html#get-under-control"><i class="fa fa-check"></i><b>3.5</b> Getting Things Under Control</a></li>
<li class="chapter" data-level="3.6" data-path="basic-r-package.html"><a href="basic-r-package.html#quick-reference"><i class="fa fa-check"></i><b>3.6</b> Quick Reference</a></li>
<li class="chapter" data-level="3.7" data-path="basic-r-package.html"><a href="basic-r-package.html#exercises"><i class="fa fa-check"></i><b>3.7</b> Exercises</a></li>
<li class="chapter" data-level="3.8" data-path="basic-r-package.html"><a href="basic-r-package.html#basic-up-next"><i class="fa fa-check"></i><b>3.8</b> Up Next</a></li>
</ul></li>
<li class="divider"></li>
<li><a href="https://github.com/rstudio/bookdown" target="blank">Published with bookdown</a></li>
</ul>
</nav>
</div>
<div class="book-body">
<div class="body-inner">
<div class="book-header" role="navigation">
<h1>
<i class="fa fa-circle-o-notch fa-spin"></i><a href="./">Writing Frictionless R Package Wrappers</a>
</h1>
</div>
<div class="page-wrapper" tabindex="-1" role="main">
<div class="page-inner">
<section class="normal" id="section-">
<div id="header">
<h1 class="title">Writing Frictionless R Package Wrappers</h1>
<p class="author"><em>Bob Rudis</em></p>
<p class="date"><em>2020-01-02</em></p>
</div>
<div id="preface" class="section level1" number="1">
<h1 number="1"><span class="header-section-number">1</span> Preface</h1>
</div>
</section>
</div>
</div>
</div>
<a href="intro.html" class="navigation navigation-next navigation-unique" aria-label="Next page"><i class="fa fa-angle-right"></i></a>
</div>
</div>
<script src="libs/gitbook-2.6.7/js/app.min.js"></script>
<script src="libs/gitbook-2.6.7/js/lunr.js"></script>
<script src="libs/gitbook-2.6.7/js/clipboard.min.js"></script>
<script src="libs/gitbook-2.6.7/js/plugin-search.js"></script>
<script src="libs/gitbook-2.6.7/js/plugin-sharing.js"></script>
<script src="libs/gitbook-2.6.7/js/plugin-fontsettings.js"></script>
<script src="libs/gitbook-2.6.7/js/plugin-bookdown.js"></script>
<script src="libs/gitbook-2.6.7/js/jquery.highlight.js"></script>
<script src="libs/gitbook-2.6.7/js/plugin-clipboard.js"></script>
<script>
gitbook.require(["gitbook"], function(gitbook) {
gitbook.start({
"sharing": {
"github": false,
"facebook": true,
"twitter": true,
"linkedin": false,
"weibo": false,
"instapaper": false,
"vk": false,
"all": ["facebook", "twitter", "linkedin", "weibo", "instapaper"]
},
"fontsettings": {
"theme": "white",
"family": "sans",
"size": 2
},
"edit": {
"link": null,
"text": null
},
"history": {
"link": null,
"text": null
},
"view": {
"link": null,
"text": null
},
"download": ["writing-frictionless-r-package-wrappers.pdf", "writing-frictionless-r-package-wrappers.epub"],
"toc": {
"collapse": "subsection"
}
});
});
</script>
</body>
</html>

280
_book/intro.html

@ -0,0 +1,280 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>2 Introduction | Writing Frictionless R Package Wrappers</title>
<meta name="description" content="Extending the functionality of R via R’s foreign language interfaces." />
<meta name="generator" content="bookdown 0.16 and GitBook 2.6.7" />
<meta property="og:title" content="2 Introduction | Writing Frictionless R Package Wrappers" />
<meta property="og:type" content="book" />
<meta property="og:url" content="https://rud.is/books/writing-frictionless-r-package-wrappers/" />
<meta property="og:description" content="Extending the functionality of R via R’s foreign language interfaces." />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="2 Introduction | Writing Frictionless R Package Wrappers" />
<meta name="twitter:description" content="Extending the functionality of R via R’s foreign language interfaces." />
<meta name="author" content="Bob Rudis" />
<meta name="date" content="2020-01-02" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<link rel="prev" href="index.html"/>
<link rel="next" href="basic-r-package.html"/>
<script src="libs/jquery-2.2.3/jquery.min.js"></script>
<script src="libs/elevate-section-attrs-2.0/elevate-section-attrs.js"></script>
<link href="libs/gitbook-2.6.7/css/style.css" rel="stylesheet" />
<link href="libs/gitbook-2.6.7/css/plugin-table.css" rel="stylesheet" />
<link href="libs/gitbook-2.6.7/css/plugin-bookdown.css" rel="stylesheet" />
<link href="libs/gitbook-2.6.7/css/plugin-highlight.css" rel="stylesheet" />
<link href="libs/gitbook-2.6.7/css/plugin-search.css" rel="stylesheet" />
<link href="libs/gitbook-2.6.7/css/plugin-fontsettings.css" rel="stylesheet" />
<link href="libs/gitbook-2.6.7/css/plugin-clipboard.css" rel="stylesheet" />
<style type="text/css">
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
color: #aaaaaa;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
div.sourceCode
{ }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code span.at { color: #7d9029; } /* Attribute */
code span.bn { color: #40a070; } /* BaseN */
code span.bu { } /* BuiltIn */
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code span.ch { color: #4070a0; } /* Char */
code span.cn { color: #880000; } /* Constant */
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
code span.dt { color: #902000; } /* DataType */
code span.dv { color: #40a070; } /* DecVal */
code span.er { color: #ff0000; font-weight: bold; } /* Error */
code span.ex { } /* Extension */
code span.fl { color: #40a070; } /* Float */
code span.fu { color: #06287e; } /* Function */
code span.im { } /* Import */
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
code span.op { color: #666666; } /* Operator */
code span.ot { color: #007020; } /* Other */
code span.pp { color: #bc7a00; } /* Preprocessor */
code span.sc { color: #4070a0; } /* SpecialChar */
code span.ss { color: #bb6688; } /* SpecialString */
code span.st { color: #4070a0; } /* String */
code span.va { color: #19177c; } /* Variable */
code span.vs { color: #4070a0; } /* VerbatimString */
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
</style>
<link rel="stylesheet" href="style.css" type="text/css" />
</head>
<body>
<div class="book without-animation with-summary font-size-2 font-family-1" data-basepath=".">
<div class="book-summary">
<nav role="navigation">
<ul class="summary">
<li><a href="./">Writing Frictionless R Package Wrappers</a></li>
<li class="divider"></li>
<li class="chapter" data-level="1" data-path="index.html"><a href="index.html"><i class="fa fa-check"></i><b>1</b> Preface</a></li>
<li class="chapter" data-level="2" data-path="intro.html"><a href="intro.html"><i class="fa fa-check"></i><b>2</b> Introduction</a>
<ul>
<li class="chapter" data-level="2.1" data-path="intro.html"><a href="intro.html#intro-reqs"><i class="fa fa-check"></i><b>2.1</b> Base Requirements</a></li>
<li class="chapter" data-level="2.2" data-path="intro.html"><a href="intro.html#intro-refs"><i class="fa fa-check"></i><b>2.2</b> Supplemental References</a></li>
<li class="chapter" data-level="2.3" data-path="intro.html"><a href="intro.html#intro-up-next"><i class="fa fa-check"></i><b>2.3</b> Up Next</a></li>
</ul></li>
<li class="chapter" data-level="3" data-path="basic-r-package.html"><a href="basic-r-package.html"><i class="fa fa-check"></i><b>3</b> Building A Basic R Package</a>
<ul>
<li class="chapter" data-level="3.1" data-path="basic-r-package.html"><a href="basic-r-package.html#config-devtools"><i class="fa fa-check"></i><b>3.1</b> Configuring {devtools}</a></li>
<li class="chapter" data-level="3.2" data-path="basic-r-package.html"><a href="basic-r-package.html#create-a-package"><i class="fa fa-check"></i><b>3.2</b> Creating A Package</a></li>
<li class="chapter" data-level="3.3" data-path="basic-r-package.html"><a href="basic-r-package.html#round-out-corners"><i class="fa fa-check"></i><b>3.3</b> Rounding Out The Corners</a></li>
<li class="chapter" data-level="3.4" data-path="basic-r-package.html"><a href="basic-r-package.html#pass-the-test"><i class="fa fa-check"></i><b>3.4</b> Passing The Test</a></li>
<li class="chapter" data-level="3.5" data-path="basic-r-package.html"><a href="basic-r-package.html#get-under-control"><i class="fa fa-check"></i><b>3.5</b> Getting Things Under Control</a></li>
<li class="chapter" data-level="3.6" data-path="basic-r-package.html"><a href="basic-r-package.html#quick-reference"><i class="fa fa-check"></i><b>3.6</b> Quick Reference</a></li>
<li class="chapter" data-level="3.7" data-path="basic-r-package.html"><a href="basic-r-package.html#exercises"><i class="fa fa-check"></i><b>3.7</b> Exercises</a></li>
<li class="chapter" data-level="3.8" data-path="basic-r-package.html"><a href="basic-r-package.html#basic-up-next"><i class="fa fa-check"></i><b>3.8</b> Up Next</a></li>
</ul></li>
<li class="divider"></li>
<li><a href="https://github.com/rstudio/bookdown" target="blank">Published with bookdown</a></li>
</ul>
</nav>
</div>
<div class="book-body">
<div class="body-inner">
<div class="book-header" role="navigation">
<h1>
<i class="fa fa-circle-o-notch fa-spin"></i><a href="./">Writing Frictionless R Package Wrappers</a>
</h1>
</div>
<div class="page-wrapper" tabindex="-1" role="main">
<div class="page-inner">
<section class="normal" id="section-">
<div id="intro" class="section level1" number="2">
<h1 number="2"><span class="header-section-number">2</span> Introduction</h1>
<p>The R language and RStudio IDE are a powerful combination for “getting stuff done”, and one aspect of R itself that makes it especially useful is the ability to use it with other programming languages via a robust <em>foreign language interface</em> capability<a href="#fn1" class="footnote-ref" id="fnref1"><sup>1</sup></a>. The term “foreign language” refers to another programming language such as C, C++, Fortran, Java, Python, Rust, etc. A common way of referring the this idiom of using functionality written in another programming language from directly within R is “wrapping” since we’re putting an R “shell” around the code from the other language. Another term you may see used is “extending” (hence the title of the “Writing R Extensions” R manual).</p>
<p>While R supports using this this extension mechanism from any R script leaving tiny trails of R and other language source and binary files all across your filesystem is not exactly the best way to keep these components organized and creates other challenges when you come across the need to use them in other projects or share them with others. Thankfully, the R Core team, along with many individual contributors over the years, has made it pretty straightforward to incorporate this extension capability into R packages which are much easier (honest!) to organize and share.</p>
<p>The goal of this book is to help you get up to speed using R and RStudio to write R packages that wrap code from many different languages to help you “get stuff done” with as little friction as possible.</p>
<div id="intro-reqs" class="section level2" number="2.1">
<h2 number="2.1"><span class="header-section-number">2.1</span> Base Requirements</h2>
<p>It is assumed that readers are familiar with the R programming language, RStudio IDE, and are comfortable installing and using packages. Since this work is about extending R with other programming languages, you should also have some knowledge of one or more of the target languages being covered.</p>
<p>To follow along with the series you’ll need to ensure you have the necessary components installed along the way. Rather than overwhelm you with all of them up front, each new section will introduce requirements specific to the language or situation being covered. However, there are some fundamentals you’ll need to ensure are available.</p>
<ul>
<li>An R<a href="#fn2" class="footnote-ref" id="fnref2"><sup>2</sup></a> environment, preferably R 3.6.x which is what was used for this series.</li>
<li>RStudio<a href="#fn3" class="footnote-ref" id="fnref3"><sup>3</sup></a>, as we’ll be using many of the features provided in it to help reduce development friction</li>
<li>The {pkgbuild}<a href="#fn4" class="footnote-ref" id="fnref4"><sup>4</sup></a> package installed</li>
</ul>
<p>Once you’ve gotten through those steps, you should fire up RStudio and run:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb1-1"><a href="intro.html#cb1-1"></a>pkgbuild<span class="op">::</span><span class="kw">check_build_tools</span>(<span class="dt">debug =</span> <span class="ot">TRUE</span>)</span></code></pre></div>
<p>which will help you make sure your particular system is ready to build packages.</p>
<p>After performing the build tool check and/or installation of the necessary core tools, you will then need to install the {devtools}<a href="#fn5" class="footnote-ref" id="fnref5"><sup>5</sup></a> package, which will help ensure that the remaining core packages required are installed.</p>
<p>We’re also going to use the <code>git</code><a href="#fn6" class="footnote-ref" id="fnref6"><sup>6</sup></a> source code version control system. The <code>git</code> ecosystem is <em>not</em> “GitHub”, which is just a public (or, potentially somewhat private) place to house source code repositories, just like other hosted services such as Bitbucket, GitLab, or SourceHut. You can use the excellent “Happy Git with R”<a href="#fn7" class="footnote-ref" id="fnref7"><sup>7</sup></a> resource to help ensure you’re source code control environment is also ready to use.</p>
</div>
<div id="intro-refs" class="section level2" number="2.2">
<h2 number="2.2"><span class="header-section-number">2.2</span> Supplemental References</h2>
<p>It may be helpful to create a browser bookmark folder for supplemental reference material that will be referred to from time-to-time across the sections (we’ll be adding to this list in each chapter, too):</p>
<ul>
<li>Writing R Extensions (<a href="https://cran.r-project.org/doc/manuals/r-release/R-exts.html" class="uri">https://cran.r-project.org/doc/manuals/r-release/R-exts.html</a>)</li>
<li>Advanced R (<a href="http://adv-r.had.co.nz/" class="uri">http://adv-r.had.co.nz/</a>)</li>
<li>R Packaged (<a href="http://r-pkgs.had.co.nz/" class="uri">http://r-pkgs.had.co.nz/</a>)</li>
</ul>
</div>
<div id="intro-up-next" class="section level2" number="2.3">
<h2 number="2.3"><span class="header-section-number">2.3</span> Up Next</h2>
<p>If you’ve been a user of “development versions” of R packages or have authored R packages you likely made quick work of this first installment. Those new to creating packages with R, those who tend to only use fully-baked CRAN versions of R packages, and/or those who have not worked with <code>git</code> before likely had to do quite a bit of work to get down to this point (if this describes you, you definitely deserve both a break and kudos for getting this far!).</p>
<p>In the next installment we’ll make sure the package building infrastructure is ready to roll by creating a basic R package that we’ll use as a building block for future work.</p>
</div>
</div>
<div class="footnotes">
<hr />
<ol start="1">
<li id="fn1"><p>“Writing R Extensions”; Chapter 5, “System and foreign language interfaces”; (<a href="https://cran.r-project.org/doc/manuals/r-release/R-exts.html#System-and-foreign-language-interfaces" class="uri">https://cran.r-project.org/doc/manuals/r-release/R-exts.html#System-and-foreign-language-interfaces</a>)<a href="intro.html#fnref1" class="footnote-back">↩︎</a></p></li>
<li id="fn2"><p>R Project Home (<a href="https://www.r-project.org/" class="uri">https://www.r-project.org/</a>)<a href="intro.html#fnref2" class="footnote-back">↩︎</a></p></li>
<li id="fn3"><p>RStudio Home (<a href="http://rstudio.com/" class="uri">http://rstudio.com/</a>)<a href="intro.html#fnref3" class="footnote-back">↩︎</a></p></li>
<li id="fn4"><p>{pkgbuild} CRAN page (<a href="https://cran.rstudio.com/web/packages/pkgbuild/" class="uri">https://cran.rstudio.com/web/packages/pkgbuild/</a>)<a href="intro.html#fnref4" class="footnote-back">↩︎</a></p></li>
<li id="fn5"><p>{devtools} Home (<a href="https://devtools.r-lib.org/" class="uri">https://devtools.r-lib.org/</a>)<a href="intro.html#fnref5" class="footnote-back">↩︎</a></p></li>
<li id="fn6"><p><code>git</code> Home (<a href="https://git-scm.com/" class="uri">https://git-scm.com/</a>)<a href="intro.html#fnref6" class="footnote-back">↩︎</a></p></li>
<li id="fn7"><p>Happy Git with R (<a href="https://happygitwithr.com/" class="uri">https://happygitwithr.com/</a>)<a href="intro.html#fnref7" class="footnote-back">↩︎</a></p></li>
</ol>
</div>
</section>
</div>
</div>
</div>
<a href="index.html" class="navigation navigation-prev " aria-label="Previous page"><i class="fa fa-angle-left"></i></a>
<a href="basic-r-package.html" class="navigation navigation-next " aria-label="Next page"><i class="fa fa-angle-right"></i></a>
</div>
</div>
<script src="libs/gitbook-2.6.7/js/app.min.js"></script>
<script src="libs/gitbook-2.6.7/js/lunr.js"></script>
<script src="libs/gitbook-2.6.7/js/clipboard.min.js"></script>
<script src="libs/gitbook-2.6.7/js/plugin-search.js"></script>
<script src="libs/gitbook-2.6.7/js/plugin-sharing.js"></script>
<script src="libs/gitbook-2.6.7/js/plugin-fontsettings.js"></script>
<script src="libs/gitbook-2.6.7/js/plugin-bookdown.js"></script>
<script src="libs/gitbook-2.6.7/js/jquery.highlight.js"></script>
<script src="libs/gitbook-2.6.7/js/plugin-clipboard.js"></script>
<script>
gitbook.require(["gitbook"], function(gitbook) {
gitbook.start({
"sharing": {
"github": false,
"facebook": true,
"twitter": true,
"linkedin": false,
"weibo": false,
"instapaper": false,
"vk": false,
"all": ["facebook", "twitter", "linkedin", "weibo", "instapaper"]
},
"fontsettings": {
"theme": "white",
"family": "sans",
"size": 2
},
"edit": {
"link": null,
"text": null
},
"history": {
"link": null,
"text": null
},
"view": {
"link": null,
"text": null
},
"download": ["writing-frictionless-r-package-wrappers.pdf", "writing-frictionless-r-package-wrappers.epub"],
"toc": {
"collapse": "subsection"
}
});
});
</script>
</body>
</html>

20
_book/libs/elevate-section-attrs-2.0/elevate-section-attrs.js

@ -0,0 +1,20 @@
$(function() {
$("div.section[class*='level'], section[class*='level']").each(function(i, el) {
var $section = $(el);
var $header = $section.children().filter(":header").first();
if ($header.length === 0) return;
var attrs = $header[0].attributes;
for (var a = 0; a < attrs.length; a++) {
var nm = attrs[a].name;
var val = attrs[a].value;
if (nm === "class") {
$section.addClass(val);
$header.removeClass(val);
continue;
}
$section.attr(nm, val);
$header.attr(nm, null);
}
});
});

BIN
_book/libs/gitbook-2.6.7/css/fontawesome/fontawesome-webfont.ttf

Binary file not shown.

99
_book/libs/gitbook-2.6.7/css/plugin-bookdown.css

@ -0,0 +1,99 @@
.book .book-header h1 {
padding-left: 20px;
padding-right: 20px;
}
.book .book-header.fixed {
position: fixed;
right: 0;
top: 0;
left: 0;
border-bottom: 1px solid rgba(0,0,0,.07);
}
span.search-highlight {
background-color: #ffff88;
}
@media (min-width: 600px) {
.book.with-summary .book-header.fixed {
left: 300px;
}
}
@media (max-width: 1240px) {
.book .book-body.fixed {
top: 50px;
}
.book .book-body.fixed .body-inner {
top: auto;
}
}
@media (max-width: 600px) {
.book.with-summary .book-header.fixed {
left: calc(100% - 60px);
min-width: 300px;
}
.book.with-summary .book-body {
transform: none;
left: calc(100% - 60px);
min-width: 300px;
}
.book .book-body.fixed {
top: 0;
}
}
.book .book-body.fixed .body-inner {
top: 50px;
}
.book .book-body .page-wrapper .page-inner section.normal sub, .book .book-body .page-wrapper .page-inner section.normal sup {
font-size: 85%;
}
@media print {
.book .book-summary, .book .book-body .book-header, .fa {
display: none !important;
}
.book .book-body.fixed {
left: 0px;
}
.book .book-body,.book .book-body .body-inner, .book.with-summary {
overflow: visible !important;
}
}
.kable_wrapper {
border-spacing: 20px 0;
border-collapse: separate;
border: none;
margin: auto;
}
.kable_wrapper > tbody > tr > td {
vertical-align: top;
}
.book .book-body .page-wrapper .page-inner section.normal table tr.header {
border-top-width: 2px;
}
.book .book-body .page-wrapper .page-inner section.normal table tr:last-child td {
border-bottom-width: 2px;
}
.book .book-body .page-wrapper .page-inner section.normal table td, .book .book-body .page-wrapper .page-inner section.normal table th {
border-left: none;
border-right: none;
}
.book .book-body .page-wrapper .page-inner section.normal table.kable_wrapper > tbody > tr, .book .book-body .page-wrapper .page-inner section.normal table.kable_wrapper > tbody > tr > td {
border-top: none;
}
.book .book-body .page-wrapper .page-inner section.normal table.kable_wrapper > tbody > tr:last-child > td {
border-bottom: none;
}
div.theorem, div.lemma, div.corollary, div.proposition, div.conjecture {
font-style: italic;
}
span.theorem, span.lemma, span.corollary, span.proposition, span.conjecture {
font-style: normal;
}
div.proof:after {
content: "\25a2";
float: right;
}
.header-section-number {
padding-right: .5em;
}

18
_book/libs/gitbook-2.6.7/css/plugin-clipboard.css

@ -0,0 +1,18 @@
div.sourceCode {
position: relative;
}
.copy-to-clipboard-button {
position: absolute;
right: 0;
top: 0;
visibility: hidden;
}
.copy-to-clipboard-button:focus {
outline: 0;
}
div.sourceCode:hover > .copy-to-clipboard-button {
visibility: visible;
}

292
_book/libs/gitbook-2.6.7/css/plugin-fontsettings.css

@ -0,0 +1,292 @@
/*
* Theme 1
*/
.color-theme-1 .dropdown-menu {
background-color: #111111;
border-color: #7e888b;
}
.color-theme-1 .dropdown-menu .dropdown-caret .caret-inner {
border-bottom: 9px solid #111111;
}
.color-theme-1 .dropdown-menu .buttons {
border-color: #7e888b;
}
.color-theme-1 .dropdown-menu .button {
color: #afa790;
}
.color-theme-1 .dropdown-menu .button:hover {
color: #73553c;
}
/*
* Theme 2
*/
.color-theme-2 .dropdown-menu {
background-color: #2d3143;
border-color: #272a3a;
}
.color-theme-2 .dropdown-menu .dropdown-caret .caret-inner {
border-bottom: 9px solid #2d3143;
}
.color-theme-2 .dropdown-menu .buttons {
border-color: #272a3a;
}
.color-theme-2 .dropdown-menu .button {
color: #62677f;
}
.color-theme-2 .dropdown-menu .button:hover {
color: #f4f4f5;
}
.book .book-header .font-settings .font-enlarge {
line-height: 30px;
font-size: 1.4em;
}
.book .book-header .font-settings .font-reduce {
line-height: 30px;
font-size: 1em;
}
.book.color-theme-1 .book-body {
color: #704214;
background: #f3eacb;
}
.book.color-theme-1 .book-body .page-wrapper .page-inner section {
background: #f3eacb;
}
.book.color-theme-2 .book-body {
color: #bdcadb;
background: #1c1f2b;
}
.book.color-theme-2 .book-body .page-wrapper .page-inner section {
background: #1c1f2b;
}
.book.font-size-0 .book-body .page-inner section {
font-size: 1.2rem;
}
.book.font-size-1 .book-body .page-inner section {
font-size: 1.4rem;
}
.book.font-size-2 .book-body .page-inner section {
font-size: 1.6rem;
}
.book.font-size-3 .book-body .page-inner section {
font-size: 2.2rem;
}
.book.font-size-4 .book-body .page-inner section {
font-size: 4rem;
}
.book.font-family-0 {
font-family: Georgia, serif;
}
.book.font-family-1 {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal {
color: #704214;
}
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal a {
color: inherit;
}
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal h1,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal h2,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal h3,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal h4,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal h5,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal h6 {
color: inherit;
}
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal h1,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal h2 {
border-color: inherit;
}
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal h6 {
color: inherit;
}
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal hr {
background-color: inherit;
}
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal blockquote {
border-color: #c4b29f;
opacity: 0.9;
}
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code {
background: #fdf6e3;
color: #657b83;
border-color: #f8df9c;
}
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal .highlight {
background-color: inherit;
}
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal table th,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal table td {
border-color: #f5d06c;
}
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal table tr {
color: inherit;
background-color: #fdf6e3;
border-color: #444444;
}
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal table tr:nth-child(2n) {
background-color: #fbeecb;
}
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal {
color: #bdcadb;
}
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal a {
color: #3eb1d0;
}
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal h1,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal h2,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal h3,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal h4,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal h5,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal h6 {
color: #fffffa;
}
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal h1,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal h2 {
border-color: #373b4e;
}
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal h6 {
color: #373b4e;
}
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal hr {
background-color: #373b4e;
}
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal blockquote {
border-color: #373b4e;
}
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code {
color: #9dbed8;
background: #2d3143;
border-color: #2d3143;
}
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal .highlight {
background-color: #282a39;
}
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal table th,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal table td {
border-color: #3b3f54;
}
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal table tr {
color: #b6c2d2;
background-color: #2d3143;
border-color: #3b3f54;
}
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal table tr:nth-child(2n) {
background-color: #35394b;
}
.book.color-theme-1 .book-header {
color: #afa790;
background: transparent;
}
.book.color-theme-1 .book-header .btn {
color: #afa790;
}
.book.color-theme-1 .book-header .btn:hover {
color: #73553c;
background: none;
}
.book.color-theme-1 .book-header h1 {
color: #704214;
}
.book.color-theme-2 .book-header {
color: #7e888b;
background: transparent;
}
.book.color-theme-2 .book-header .btn {
color: #3b3f54;
}
.book.color-theme-2 .book-header .btn:hover {
color: #fffff5;
background: none;
}
.book.color-theme-2 .book-header h1 {
color: #bdcadb;
}
.book.color-theme-1 .book-body .navigation {
color: #afa790;
}
.book.color-theme-1 .book-body .navigation:hover {
color: #73553c;
}
.book.color-theme-2 .book-body .navigation {
color: #383f52;
}
.book.color-theme-2 .book-body .navigation:hover {
color: #fffff5;
}
/*
* Theme 1
*/
.book.color-theme-1 .book-summary {
color: #afa790;
background: #111111;
border-right: 1px solid rgba(0, 0, 0, 0.07);
}
.book.color-theme-1 .book-summary .book-search {
background: transparent;
}
.book.color-theme-1 .book-summary .book-search input,
.book.color-theme-1 .book-summary .book-search input:focus {
border: 1px solid transparent;
}
.book.color-theme-1 .book-summary ul.summary li.divider {
background: #7e888b;
box-shadow: none;
}
.book.color-theme-1 .book-summary ul.summary li i.fa-check {
color: #33cc33;
}
.book.color-theme-1 .book-summary ul.summary li.done > a {
color: #877f6a;
}
.book.color-theme-1 .book-summary ul.summary li a,
.book.color-theme-1 .book-summary ul.summary li span {
color: #877f6a;
background: transparent;
font-weight: normal;
}
.book.color-theme-1 .book-summary ul.summary li.active > a,
.book.color-theme-1 .book-summary ul.summary li a:hover {
color: #704214;
background: transparent;
font-weight: normal;
}
/*
* Theme 2
*/
.book.color-theme-2 .book-summary {
color: #bcc1d2;
background: #2d3143;
border-right: none;
}
.book.color-theme-2 .book-summary .book-search {
background: transparent;
}
.book.color-theme-2 .book-summary .book-search input,
.book.color-theme-2 .book-summary .book-search input:focus {
border: 1px solid transparent;
}
.book.color-theme-2 .book-summary ul.summary li.divider {
background: #272a3a;
box-shadow: none;
}
.book.color-theme-2 .book-summary ul.summary li i.fa-check {
color: #33cc33;
}
.book.color-theme-2 .book-summary ul.summary li.done > a {
color: #62687f;
}
.book.color-theme-2 .book-summary ul.summary li a,
.book.color-theme-2 .book-summary ul.summary li span {
color: #c1c6d7;
background: transparent;
font-weight: 600;
}
.book.color-theme-2 .book-summary ul.summary li.active > a,
.book.color-theme-2 .book-summary ul.summary li a:hover {
color: #f4f4f5;
background: #252737;
font-weight: 600;
}

426
_book/libs/gitbook-2.6.7/css/plugin-highlight.css

@ -0,0 +1,426 @@
.book .book-body .page-wrapper .page-inner section.normal pre,
.book .book-body .page-wrapper .page-inner section.normal code {
/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */
/* Tomorrow Comment */
/* Tomorrow Red */
/* Tomorrow Orange */
/* Tomorrow Yellow */
/* Tomorrow Green */
/* Tomorrow Aqua */
/* Tomorrow Blue */
/* Tomorrow Purple */
}
.book .book-body .page-wrapper .page-inner section.normal pre .hljs-comment,
.book .book-body .page-wrapper .page-inner section.normal code .hljs-comment,
.book .book-body .page-wrapper .page-inner section.normal pre .hljs-title,
.book .book-body .page-wrapper .page-inner section.normal code .hljs-title {
color: #8e908c;
}
.book .book-body .page-wrapper .page-inner section.normal pre .hljs-variable,
.book .book-body .page-wrapper .page-inner section.normal code .hljs-variable,
.book .book-body .page-wrapper .page-inner section.normal pre .hljs-attribute,
.book .book-body .page-wrapper .page-inner section.normal code .hljs-attribute,
.book .book-body .page-wrapper .page-inner section.normal pre .hljs-tag,
.book .book-body .page-wrapper .page-inner section.normal code .hljs-tag,
.book .book-body .page-wrapper .page-inner section.normal pre .hljs-regexp,
.book .book-body .page-wrapper .page-inner section.normal code .hljs-regexp,
.book .book-body .page-wrapper .page-inner section.normal pre .ruby .hljs-constant,
.book .book-body .page-wrapper .page-inner section.normal code .ruby .hljs-constant,
.book .book-body .page-wrapper .page-inner section.normal pre .xml .hljs-tag .hljs-title,
.book .book-body .page-wrapper .page-inner section.normal code .xml .hljs-tag .hljs-title,
.book .book-body .page-wrapper .page-inner section.normal pre .xml .hljs-pi,
.book .book-body .page-wrapper .page-inner section.normal code .xml .hljs-pi,
.book .book-body .page-wrapper .page-inner section.normal pre .xml .hljs-doctype,
.book .book-body .page-wrapper .page-inner section.normal code .xml .hljs-doctype,
.book .book-body .page-wrapper .page-inner section.normal pre .html .hljs-doctype,
.book .book-body .page-wrapper .page-inner section.normal code .html .hljs-doctype,
.book .book-body .page-wrapper .page-inner section.normal pre .css .hljs-id,
.book .book-body .page-wrapper .page-inner section.normal code .css .hljs-id,
.book .book-body .page-wrapper .page-inner section.normal pre .css .hljs-class,
.book .book-body .page-wrapper .page-inner section.normal code .css .hljs-class,
.book .book-body .page-wrapper .page-inner section.normal pre .css .hljs-pseudo,
.book .book-body .page-wrapper .page-inner section.normal code .css .hljs-pseudo {
color: #c82829;
}
.book .book-body .page-wrapper .page-inner section.normal pre .hljs-number,
.book .book-body .page-wrapper .page-inner section.normal code .hljs-number,
.book .book-body .page-wrapper .page-inner section.normal pre .hljs-preprocessor,
.book .book-body .page-wrapper .page-inner section.normal code .hljs-preprocessor,
.book .book-body .page-wrapper .page-inner section.normal pre .hljs-pragma,
.book .book-body .page-wrapper .page-inner section.normal code .hljs-pragma,
.book .book-body .page-wrapper .page-inner section.normal pre .hljs-built_in,
.book .book-body .page-wrapper .page-inner section.normal code .hljs-built_in,
.book .book-body .page-wrapper .page-inner section.normal pre .hljs-literal,
.book .book-body .page-wrapper .page-inner section.normal code .hljs-literal,
.book .book-body .page-wrapper .page-inner section.normal pre .hljs-params,
.book .book-body .page-wrapper .page-inner section.normal code .hljs-params,
.book .book-body .page-wrapper .page-inner section.normal pre .hljs-constant,
.book .book-body .page-wrapper .page-inner section.normal code .hljs-constant {
color: #f5871f;
}
.book .book-body .page-wrapper .page-inner section.normal pre .ruby .hljs-class .hljs-title,
.book .book-body .page-wrapper .page-inner section.normal code .ruby .hljs-class .hljs-title,
.book .book-body .page-wrapper .page-inner section.normal pre .css .hljs-rules .hljs-attribute,
.book .book-body .page-wrapper .page-inner section.normal code .css .hljs-rules .hljs-attribute {
color: #eab700;
}
.book .book-body .page-wrapper .page-inner section.normal pre .hljs-string,
.book .book-body .page-wrapper .page-inner section.normal code .hljs-string,
.book .book-body .page-wrapper .page-inner section.normal pre .hljs-value,
.book .book-body .page-wrapper .page-inner section.normal code .hljs-value,
.book .book-body .page-wrapper .page-inner section.normal pre .hljs-inheritance,
.book .book-body .page-wrapper .page-inner section.normal code .hljs-inheritance,
.book .book-body .page-wrapper .page-inner section.normal pre .hljs-header,
.book .book-body .page-wrapper .page-inner section.normal code .hljs-header,
.book .book-body .page-wrapper .page-inner section.normal pre .ruby .hljs-symbol,
.book .book-body .page-wrapper .page-inner section.normal code .ruby .hljs-symbol,
.book .book-body .page-wrapper .page-inner section.normal pre .xml .hljs-cdata,
.book .book-body .page-wrapper .page-inner section.normal code .xml .hljs-cdata {
color: #718c00;
}
.book .book-body .page-wrapper .page-inner section.normal pre .css .hljs-hexcolor,
.book .book-body .page-wrapper .page-inner section.normal code .css .hljs-hexcolor {
color: #3e999f;
}
.book .book-body .page-wrapper .page-inner section.normal pre .hljs-function,
.book .book-body .page-wrapper .page-inner section.normal code .hljs-function,
.book .book-body .page-wrapper .page-inner section.normal pre .python .hljs-decorator,
.book .book-body .page-wrapper .page-inner section.normal code .python .hljs-decorator,
.book .book-body .page-wrapper .page-inner section.normal pre .python .hljs-title,
.book .book-body .page-wrapper .page-inner section.normal code .python .hljs-title,
.book .book-body .page-wrapper .page-inner section.normal pre .ruby .hljs-function .hljs-title,
.book .book-body .page-wrapper .page-inner section.normal code .ruby .hljs-function .hljs-title,
.book .book-body .page-wrapper .page-inner section.normal pre .ruby .hljs-title .hljs-keyword,
.book .book-body .page-wrapper .page-inner section.normal code .ruby .hljs-title .hljs-keyword,
.book .book-body .page-wrapper .page-inner section.normal pre .perl .hljs-sub,
.book .book-body .page-wrapper .page-inner section.normal code .perl .hljs-sub,
.book .book-body .page-wrapper .page-inner section.normal pre .javascript .hljs-title,
.book .book-body .page-wrapper .page-inner section.normal code .javascript .hljs-title,
.book .book-body .page-wrapper .page-inner section.normal pre .coffeescript .hljs-title,
.book .book-body .page-wrapper .page-inner section.normal code .coffeescript .hljs-title {
color: #4271ae;
}
.book .book-body .page-wrapper .page-inner section.normal pre .hljs-keyword,
.book .book-body .page-wrapper .page-inner section.normal code .hljs-keyword,
.book .book-body .page-wrapper .page-inner section.normal pre .javascript .hljs-function,
.book .book-body .page-wrapper .page-inner section.normal code .javascript .hljs-function {
color: #8959a8;
}
.book .book-body .page-wrapper .page-inner section.normal pre .hljs,
.book .book-body .page-wrapper .page-inner section.normal code .hljs {
display: block;
background: white;
color: #4d4d4c;
padding: 0.5em;
}
.book .book-body .page-wrapper .page-inner section.normal pre .coffeescript .javascript,
.book .book-body .page-wrapper .page-inner section.normal code .coffeescript .javascript,
.book .book-body .page-wrapper .page-inner section.normal pre .javascript .xml,
.book .book-body .page-wrapper .page-inner section.normal code .javascript .xml,
.book .book-body .page-wrapper .page-inner section.normal pre .tex .hljs-formula,
.book .book-body .page-wrapper .page-inner section.normal code .tex .hljs-formula,
.book .book-body .page-wrapper .page-inner section.normal pre .xml .javascript,
.book .book-body .page-wrapper .page-inner section.normal code .xml .javascript,
.book .book-body .page-wrapper .page-inner section.normal pre .xml .vbscript,
.book .book-body .page-wrapper .page-inner section.normal code .xml .vbscript,
.book .book-body .page-wrapper .page-inner section.normal pre .xml .css,
.book .book-body .page-wrapper .page-inner section.normal code .xml .css,
.book .book-body .page-wrapper .page-inner section.normal pre .xml .hljs-cdata,
.book .book-body .page-wrapper .page-inner section.normal code .xml .hljs-cdata {
opacity: 0.5;
}
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code {
/*
Orginal Style from ethanschoonover.com/solarized (c) Jeremy Hull <sourdrums@gmail.com>
*/
/* Solarized Green */
/* Solarized Cyan */
/* Solarized Blue */
/* Solarized Yellow */
/* Solarized Orange */
/* Solarized Red */
/* Solarized Violet */
}
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs {
display: block;
padding: 0.5em;
background: #fdf6e3;
color: #657b83;
}
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-comment,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-comment,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-template_comment,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-template_comment,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .diff .hljs-header,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .diff .hljs-header,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-doctype,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-doctype,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-pi,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-pi,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .lisp .hljs-string,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .lisp .hljs-string,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-javadoc,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-javadoc {
color: #93a1a1;
}
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-keyword,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-keyword,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-winutils,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-winutils,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .method,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .method,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-addition,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-addition,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .css .hljs-tag,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .css .hljs-tag,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-request,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-request,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-status,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-status,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .nginx .hljs-title,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .nginx .hljs-title {
color: #859900;
}
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-number,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-number,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-command,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-command,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-string,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-string,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-tag .hljs-value,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-tag .hljs-value,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-rules .hljs-value,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-rules .hljs-value,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-phpdoc,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-phpdoc,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .tex .hljs-formula,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .tex .hljs-formula,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-regexp,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-regexp,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-hexcolor,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-hexcolor,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-link_url,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-link_url {
color: #2aa198;
}
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-title,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-title,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-localvars,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-localvars,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-chunk,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-chunk,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-decorator,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-decorator,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-built_in,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-built_in,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-identifier,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-identifier,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .vhdl .hljs-literal,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .vhdl .hljs-literal,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-id,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-id,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .css .hljs-function,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .css .hljs-function {
color: #268bd2;
}
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-attribute,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-attribute,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-variable,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-variable,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .lisp .hljs-body,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .lisp .hljs-body,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .smalltalk .hljs-number,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .smalltalk .hljs-number,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-constant,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-constant,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-class .hljs-title,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-class .hljs-title,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-parent,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-parent,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .haskell .hljs-type,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .haskell .hljs-type,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-link_reference,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-link_reference {
color: #b58900;
}
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-preprocessor,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-preprocessor,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-preprocessor .hljs-keyword,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-preprocessor .hljs-keyword,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-pragma,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-pragma,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-shebang,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-shebang,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-symbol,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-symbol,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-symbol .hljs-string,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-symbol .hljs-string,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .diff .hljs-change,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .diff .hljs-change,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-special,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-special,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-attr_selector,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-attr_selector,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-subst,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-subst,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-cdata,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-cdata,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .clojure .hljs-title,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .clojure .hljs-title,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .css .hljs-pseudo,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .css .hljs-pseudo,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-header,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-header {
color: #cb4b16;
}
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-deletion,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-deletion,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-important,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-important {
color: #dc322f;
}
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .hljs-link_label,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .hljs-link_label {
color: #6c71c4;
}
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal pre .tex .hljs-formula,
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal code .tex .hljs-formula {
background: #eee8d5;
}
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code {
/* Tomorrow Night Bright Theme */
/* Original theme - https://github.com/chriskempson/tomorrow-theme */
/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */
/* Tomorrow Comment */
/* Tomorrow Red */
/* Tomorrow Orange */
/* Tomorrow Yellow */
/* Tomorrow Green */
/* Tomorrow Aqua */
/* Tomorrow Blue */
/* Tomorrow Purple */
}
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs-comment,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs-comment,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs-title,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs-title {
color: #969896;
}
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs-variable,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs-variable,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs-attribute,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs-attribute,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs-tag,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs-tag,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs-regexp,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs-regexp,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .ruby .hljs-constant,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .ruby .hljs-constant,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .xml .hljs-tag .hljs-title,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .xml .hljs-tag .hljs-title,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .xml .hljs-pi,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .xml .hljs-pi,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .xml .hljs-doctype,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .xml .hljs-doctype,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .html .hljs-doctype,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .html .hljs-doctype,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .css .hljs-id,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .css .hljs-id,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .css .hljs-class,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .css .hljs-class,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .css .hljs-pseudo,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .css .hljs-pseudo {
color: #d54e53;
}
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs-number,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs-number,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs-preprocessor,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs-preprocessor,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs-pragma,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs-pragma,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs-built_in,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs-built_in,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs-literal,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs-literal,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs-params,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs-params,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs-constant,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs-constant {
color: #e78c45;
}
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .ruby .hljs-class .hljs-title,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .ruby .hljs-class .hljs-title,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .css .hljs-rules .hljs-attribute,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .css .hljs-rules .hljs-attribute {
color: #e7c547;
}
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs-string,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs-string,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs-value,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs-value,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs-inheritance,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs-inheritance,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs-header,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs-header,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .ruby .hljs-symbol,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .ruby .hljs-symbol,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .xml .hljs-cdata,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .xml .hljs-cdata {
color: #b9ca4a;
}
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .css .hljs-hexcolor,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .css .hljs-hexcolor {
color: #70c0b1;
}
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs-function,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs-function,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .python .hljs-decorator,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .python .hljs-decorator,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .python .hljs-title,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .python .hljs-title,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .ruby .hljs-function .hljs-title,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .ruby .hljs-function .hljs-title,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .ruby .hljs-title .hljs-keyword,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .ruby .hljs-title .hljs-keyword,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .perl .hljs-sub,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .perl .hljs-sub,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .javascript .hljs-title,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .javascript .hljs-title,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .coffeescript .hljs-title,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .coffeescript .hljs-title {
color: #7aa6da;
}
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs-keyword,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs-keyword,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .javascript .hljs-function,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .javascript .hljs-function {
color: #c397d8;
}
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .hljs,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .hljs {
display: block;
background: black;
color: #eaeaea;
padding: 0.5em;
}
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .coffeescript .javascript,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .coffeescript .javascript,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .javascript .xml,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .javascript .xml,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .tex .hljs-formula,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .tex .hljs-formula,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .xml .javascript,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .xml .javascript,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .xml .vbscript,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .xml .vbscript,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .xml .css,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .xml .css,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal pre .xml .hljs-cdata,
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal code .xml .hljs-cdata {
opacity: 0.5;
}

31
_book/libs/gitbook-2.6.7/css/plugin-search.css

@ -0,0 +1,31 @@
.book .book-summary .book-search {
padding: 6px;
background: transparent;
position: absolute;
top: -50px;
left: 0px;
right: 0px;
transition: top 0.5s ease;
}
.book .book-summary .book-search input,
.book .book-summary .book-search input:focus,
.book .book-summary .book-search input:hover {
width: 100%;
background: transparent;
border: 1px solid #ccc;
box-shadow: none;
outline: none;
line-height: 22px;
padding: 7px 4px;
color: inherit;
box-sizing: border-box;
}
.book.with-search .book-summary .book-search {
top: 0px;
}
.book.with-search .book-summary ul.summary {
top: 50px;
}
.with-search .summary li[data-level] a[href*=".html#"] {
display: none;
}

1
_book/libs/gitbook-2.6.7/css/plugin-table.css

@ -0,0 +1 @@
.book .book-body .page-wrapper .page-inner section.normal table{display:table;width:100%;border-collapse:collapse;border-spacing:0;overflow:auto}.book .book-body .page-wrapper .page-inner section.normal table td,.book .book-body .page-wrapper .page-inner section.normal table th{padding:6px 13px;border:1px solid #ddd}.book .book-body .page-wrapper .page-inner section.normal table tr{background-color:#fff;border-top:1px solid #ccc}.book .book-body .page-wrapper .page-inner section.normal table tr:nth-child(2n){background-color:#f8f8f8}.book .book-body .page-wrapper .page-inner section.normal table th{font-weight:700}

10
_book/libs/gitbook-2.6.7/css/style.css

File diff suppressed because one or more lines are too long

1
_book/libs/gitbook-2.6.7/js/app.min.js

File diff suppressed because one or more lines are too long

7
_book/libs/gitbook-2.6.7/js/clipboard.min.js

File diff suppressed because one or more lines are too long

86
_book/libs/gitbook-2.6.7/js/jquery.highlight.js

@ -0,0 +1,86 @@
gitbook.require(["jQuery"], function(jQuery) {
/*
* jQuery Highlight plugin
*
* Based on highlight v3 by Johann Burkard
* http://johannburkard.de/blog/programming/javascript/highlight-javascript-text-higlighting-jquery-plugin.html
*
* Code a little bit refactored and cleaned (in my humble opinion).
* Most important changes:
* - has an option to highlight only entire words (wordsOnly - false by default),
* - has an option to be case sensitive (caseSensitive - false by default)
* - highlight element tag and class names can be specified in options
*
* Copyright (c) 2009 Bartek Szopka
*
* Licensed under MIT license.
*
*/
jQuery.extend({
highlight: function (node, re, nodeName, className) {
if (node.nodeType === 3) {
var match = node.data.match(re);
if (match) {
var highlight = document.createElement(nodeName || 'span');
highlight.className = className || 'highlight';
var wordNode = node.splitText(match.index);
wordNode.splitText(match[0].length);
var wordClone = wordNode.cloneNode(true);
highlight.appendChild(wordClone);
wordNode.parentNode.replaceChild(highlight, wordNode);
return 1; //skip added node in parent
}
} else if ((node.nodeType === 1 && node.childNodes) && // only element nodes that have children
!/(script|style)/i.test(node.tagName) && // ignore script and style nodes
!(node.tagName === nodeName.toUpperCase() && node.className === className)) { // skip if already highlighted
for (var i = 0; i < node.childNodes.length; i++) {
i += jQuery.highlight(node.childNodes[i], re, nodeName, className);
}
}
return 0;
}
});
jQuery.fn.unhighlight = function (options) {
var settings = { className: 'highlight', element: 'span' };
jQuery.extend(settings, options);
return this.find(settings.element + "." + settings.className).each(function () {
var parent = this.parentNode;
parent.replaceChild(this.firstChild, this);
parent.normalize();
}).end();
};
jQuery.fn.highlight = function (words, options) {
var settings = { className: 'highlight', element: 'span', caseSensitive: false, wordsOnly: false };
jQuery.extend(settings, options);
if (words.constructor === String) {
words = [words];
// also match 'foo-bar' if search for 'foo bar'
if (/\s/.test(words[0])) words.push(words[0].replace(/\s+/, '-'));
}
words = jQuery.grep(words, function(word, i){
return word !== '';
});
words = jQuery.map(words, function(word, i) {
return word.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
});
if (words.length === 0) { return this; }
var flag = settings.caseSensitive ? "" : "i";
var pattern = "(" + words.join("|") + ")";
if (settings.wordsOnly) {
pattern = "\\b" + pattern + "\\b";
}
var re = new RegExp(pattern, flag);
return this.each(function () {
jQuery.highlight(this, re, settings.element, settings.className);
});
};
});

7
_book/libs/gitbook-2.6.7/js/lunr.js

File diff suppressed because one or more lines are too long

259
_book/libs/gitbook-2.6.7/js/plugin-bookdown.js

@ -0,0 +1,259 @@
gitbook.require(["gitbook", "lodash", "jQuery"], function(gitbook, _, $) {
var gs = gitbook.storage;
gitbook.events.bind("start", function(e, config) {
// add the Edit button (edit on Github)
var edit = config.edit;
if (edit && edit.link) gitbook.toolbar.createButton({
icon: 'fa fa-edit',
label: edit.text || 'Edit',
position: 'left',
onClick: function(e) {
e.preventDefault();
window.open(edit.link);
}
});
// add the History button (file history on Github)
var history = config.history;
if (history && history.link) gitbook.toolbar.createButton({
icon: 'fa fa-history',
label: history.text || 'History',
position: 'left',
onClick: function(e) {
e.preventDefault();
window.open(history.link);
}
});
// add the View button (file view on Github)
var view = config.view;
if (view && view.link) gitbook.toolbar.createButton({
icon: 'fa fa-eye',
label: view.text || 'View Source',
position: 'left',
onClick: function(e) {
e.preventDefault();
window.open(view.link);
}
});
// add the Download button
var down = config.download;
var normalizeDownload = function() {
if (!down || !(down instanceof Array) || down.length === 0) return;
if (down[0] instanceof Array) return down;
return $.map(down, function(file, i) {
return [[file, file.replace(/.*[.]/g, '').toUpperCase()]];
});
};
down = normalizeDownload(down);
if (down) if (down.length === 1 && /[.]pdf$/.test(down[0][0])) {
gitbook.toolbar.createButton({
icon: 'fa fa-file-pdf-o',
label: down[0][1],
position: 'left',
onClick: function(e) {
e.preventDefault();
window.open(down[0][0]);
}
});
} else {
gitbook.toolbar.createButton({
icon: 'fa fa-download',
label: 'Download',
position: 'left',
dropdown: $.map(down, function(item, i) {
return {
text: item[1],
onClick: function(e) {
e.preventDefault();
window.open(item[0]);
}
};
})
});
}
// add the Information button
var info = ['Keyboard shortcuts (<> indicates arrow keys):',
'<left>/<right>: navigate to previous/next page',
's: Toggle sidebar'];
if (config.search !== false) info.push('f: Toggle search input ' +
'(use <up>/<down>/Enter in the search input to navigate through search matches; ' +
'press Esc to cancel search)');
if (config.info !== false) gitbook.toolbar.createButton({
icon: 'fa fa-info',
label: 'Information about the toolbar',
position: 'left',
onClick: function(e) {
e.preventDefault();
window.alert(info.join('\n\n'));
}
});
// highlight the current section in TOC
var href = window.location.pathname;
href = href.substr(href.lastIndexOf('/') + 1);
// accentuated characters need to be decoded (#819)
href = decodeURIComponent(href);
if (href === '') href = 'index.html';
var li = $('a[href^="' + href + location.hash + '"]').parent('li.chapter').first();
var summary = $('ul.summary'), chaps = summary.find('li.chapter');
if (li.length === 0) li = chaps.first();
li.addClass('active');
chaps.on('click', function(e) {
chaps.removeClass('active');
$(this).addClass('active');
gs.set('tocScrollTop', summary.scrollTop());
});
var toc = config.toc;
// collapse TOC items that are not for the current chapter
if (toc && toc.collapse) (function() {
var type = toc.collapse;
if (type === 'none') return;
if (type !== 'section' && type !== 'subsection') return;
// sections under chapters
var toc_sub = summary.children('li[data-level]').children('ul');
if (type === 'section') {
toc_sub.hide()
.parent().has(li).children('ul').show();
} else {
toc_sub.children('li').children('ul').hide()
.parent().has(li).children('ul').show();
}
li.children('ul').show();
var toc_sub2 = toc_sub.children('li');
if (type === 'section') toc_sub2.children('ul').hide();
summary.children('li[data-level]').find('a')
.on('click.bookdown', function(e) {
if (href === $(this).attr('href').replace(/#.*/, ''))
$(this).parent('li').children('ul').toggle();
});
})();
// add tooltips to the <a>'s that are truncated
$('a').each(function(i, el) {
if (el.offsetWidth >= el.scrollWidth) return;
if (typeof el.title === 'undefined') return;
el.title = el.text;
});
// restore TOC scroll position
var pos = gs.get('tocScrollTop');
if (typeof pos !== 'undefined') summary.scrollTop(pos);
// highlight the TOC item that has same text as the heading in view as scrolling
if (toc && toc.scroll_highlight !== false) (function() {
// scroll the current TOC item into viewport
var ht = $(window).height(), rect = li[0].getBoundingClientRect();
if (rect.top >= ht || rect.top <= 0 || rect.bottom <= 0) {
summary.scrollTop(li[0].offsetTop);
}
// current chapter TOC items
var items = $('a[href^="' + href + '"]').parent('li.chapter'),
m = items.length;
if (m === 0) {
items = summary.find('li.chapter');
m = items.length;
}
if (m === 0) return;
// all section titles on current page
var hs = bookInner.find('.page-inner').find('h1,h2,h3'), n = hs.length,
ts = hs.map(function(i, el) { return $(el).text(); });
if (n === 0) return;
var scrollHandler = function(e) {
var ht = $(window).height();
clearTimeout($.data(this, 'scrollTimer'));
$.data(this, 'scrollTimer', setTimeout(function() {
// find the first visible title in the viewport
for (var i = 0; i < n; i++) {
var rect = hs[i].getBoundingClientRect();
if (rect.top >= 0 && rect.bottom <= ht) break;
}
if (i === n) return;
items.removeClass('active');
for (var j = 0; j < m; j++) {
if (items.eq(j).children('a').first().text() === ts[i]) break;
}
if (j === m) j = 0; // highlight the chapter title
// search bottom-up for a visible TOC item to highlight; if an item is
// hidden, we check if its parent is visible, and so on
while (j > 0 && items.eq(j).is(':hidden')) j--;
items.eq(j).addClass('active');
}, 250));
};
bookInner.on('scroll.bookdown', scrollHandler);
bookBody.on('scroll.bookdown', scrollHandler);
})();
// do not refresh the page if the TOC item points to the current page
$('a[href="' + href + '"]').parent('li.chapter').children('a')
.on('click', function(e) {
bookInner.scrollTop(0);
bookBody.scrollTop(0);
return false;
});
var toolbar = config.toolbar;
if (!toolbar || toolbar.position !== 'static') {
var bookHeader = $('.book-header');
bookBody.addClass('fixed');
bookHeader.addClass('fixed')
.css('background-color', bookBody.css('background-color'))
.on('click.bookdown', function(e) {
// the theme may have changed after user clicks the theme button
bookHeader.css('background-color', bookBody.css('background-color'));
});
}
});
gitbook.events.bind("page.change", function(e) {
// store TOC scroll position
var summary = $('ul.summary');
gs.set('tocScrollTop', summary.scrollTop());
});
var bookBody = $('.book-body'), bookInner = bookBody.find('.body-inner');
var chapterTitle = function() {
return bookInner.find('.page-inner').find('h1,h2').first().text();
};
var saveScrollPos = function(e) {
// save scroll position before page is reloaded
gs.set('bodyScrollTop', {
body: bookBody.scrollTop(),
inner: bookInner.scrollTop(),
focused: document.hasFocus(),
title: chapterTitle()
});
};
$(document).on('servr:reload', saveScrollPos);
// check if the page is loaded in an iframe (e.g. the RStudio preview window)
var inIFrame = function() {
var inIframe = true;
try { inIframe = window.self !== window.top; } catch (e) {}
return inIframe;
};
if (inIFrame()) {
$(window).on('blur unload', saveScrollPos);
}
$(function(e) {
var pos = gs.get('bodyScrollTop');
if (pos) {
if (pos.title === chapterTitle()) {
if (pos.body !== 0) bookBody.scrollTop(pos.body);
if (pos.inner !== 0) bookInner.scrollTop(pos.inner);
}
}
if ((pos && pos.focused) || !inIFrame()) bookInner.find('.page-wrapper').focus();
// clear book body scroll position
gs.remove('bodyScrollTop');
});
});

29
_book/libs/gitbook-2.6.7/js/plugin-clipboard.js

@ -0,0 +1,29 @@
gitbook.require(["gitbook", "jQuery"], function(gitbook, $) {
var copyButton = '<button type="button" class="copy-to-clipboard-button" title="Copy to clipboard" aria-label="Copy to clipboard"><i class="fa fa-copy"></i></button>';
var clipboard;
gitbook.events.bind("page.change", function() {
if (!ClipboardJS.isSupported()) return;
// the page.change event is thrown twice: before and after the page changes
if (clipboard) {
// clipboard is already defined
// we can deduct that we are before page changes
clipboard.destroy(); // destroy the previous events listeners
clipboard = undefined; // reset the clipboard object
return;
}
$(copyButton).prependTo("div.sourceCode");
clipboard = new ClipboardJS(".copy-to-clipboard-button", {
text: function(trigger) {
return trigger.parentNode.textContent;
}
});
});
});

152
_book/libs/gitbook-2.6.7/js/plugin-fontsettings.js

@ -0,0 +1,152 @@
gitbook.require(["gitbook", "lodash", "jQuery"], function(gitbook, _, $) {
var fontState;
var THEMES = {
"white": 0,
"sepia": 1,
"night": 2
};
var FAMILY = {
"serif": 0,
"sans": 1
};
// Save current font settings
function saveFontSettings() {
gitbook.storage.set("fontState", fontState);
update();
}
// Increase font size
function enlargeFontSize(e) {
e.preventDefault();
if (fontState.size >= 4) return;
fontState.size++;
saveFontSettings();
};
// Decrease font size
function reduceFontSize(e) {
e.preventDefault();
if (fontState.size <= 0) return;
fontState.size--;
saveFontSettings();
};
// Change font family
function changeFontFamily(index, e) {
e.preventDefault();
fontState.family = index;
saveFontSettings();
};
// Change type of color
function changeColorTheme(index, e) {
e.preventDefault();
var $book = $(".book");
if (fontState.theme !== 0)
$book.removeClass("color-theme-"+fontState.theme);
fontState.theme = index;
if (fontState.theme !== 0)
$book.addClass("color-theme-"+fontState.theme);
saveFontSettings();
};
function update() {
var $book = gitbook.state.$book;
$(".font-settings .font-family-list li").removeClass("active");
$(".font-settings .font-family-list li:nth-child("+(fontState.family+1)+")").addClass("active");
$book[0].className = $book[0].className.replace(/\bfont-\S+/g, '');
$book.addClass("font-size-"+fontState.size);
$book.addClass("font-family-"+fontState.family);
if(fontState.theme !== 0) {
$book[0].className = $book[0].className.replace(/\bcolor-theme-\S+/g, '');
$book.addClass("color-theme-"+fontState.theme);
}
};
function init(config) {
var $bookBody, $book;
//Find DOM elements.
$book = gitbook.state.$book;
$bookBody = $book.find(".book-body");
// Instantiate font state object
fontState = gitbook.storage.get("fontState", {
size: config.size || 2,
family: FAMILY[config.family || "sans"],
theme: THEMES[config.theme || "white"]
});
update();
};
gitbook.events.bind("start", function(e, config) {
var opts = config.fontsettings;
if (!opts) return;
// Create buttons in toolbar
gitbook.toolbar.createButton({
icon: 'fa fa-font',
label: 'Font Settings',
className: 'font-settings',
dropdown: [
[
{
text: 'A',
className: 'font-reduce',
onClick: reduceFontSize
},
{
text: 'A',
className: 'font-enlarge',
onClick: enlargeFontSize
}
],
[
{
text: 'Serif',
onClick: _.partial(changeFontFamily, 0)
},
{
text: 'Sans',
onClick: _.partial(changeFontFamily, 1)
}
],
[
{
text: 'White',
onClick: _.partial(changeColorTheme, 0)
},
{
text: 'Sepia',
onClick: _.partial(changeColorTheme, 1)
},
{
text: 'Night',
onClick: _.partial(changeColorTheme, 2)
}
]
]
});
// Init current settings
init(opts);
});
});

223
_book/libs/gitbook-2.6.7/js/plugin-search.js

@ -0,0 +1,223 @@
gitbook.require(["gitbook", "lodash", "jQuery"], function(gitbook, _, $) {
var index = null;
var $searchInput, $searchLabel, $searchForm;
var $highlighted = [], hi, hiOpts = { className: 'search-highlight' };
var collapse = false, toc_visible = [];
// Use a specific index
function loadIndex(data) {
// [Yihui] In bookdown, I use a character matrix to store the chapter
// content, and the index is dynamically built on the client side.
// Gitbook prebuilds the index data instead: https://github.com/GitbookIO/plugin-search
// We can certainly do that via R packages V8 and jsonlite, but let's
// see how slow it really is before improving it. On the other hand,
// lunr cannot handle non-English text very well, e.g. the default
// tokenizer cannot deal with Chinese text, so we may want to replace
// lunr with a dumb simple text matching approach.
index = lunr(function () {
this.ref('url');
this.field('title', { boost: 10 });
this.field('body');
});
data.map(function(item) {
index.add({
url: item[0],
title: item[1],
body: item[2]
});
});
}
// Fetch the search index
function fetchIndex() {
return $.getJSON(gitbook.state.basePath+"/search_index.json")
.then(loadIndex); // [Yihui] we need to use this object later
}
// Search for a term and return results
function search(q) {
if (!index) return;
var results = _.chain(index.search(q))
.map(function(result) {
var parts = result.ref.split("#");
return {
path: parts[0],
hash: parts[1]
};
})
.value();
// [Yihui] Highlight the search keyword on current page
$highlighted = results.length === 0 ? [] : $('.page-inner')
.unhighlight(hiOpts).highlight(q, hiOpts).find('span.search-highlight');
scrollToHighlighted(0);
return results;
}
// [Yihui] Scroll the chapter body to the i-th highlighted string
function scrollToHighlighted(d) {
var n = $highlighted.length;
hi = hi === undefined ? 0 : hi + d;
// navignate to the previous/next page in the search results if reached the top/bottom
var b = hi < 0;
if (d !== 0 && (b || hi >= n)) {
var path = currentPath(), n2 = toc_visible.length;
if (n2 === 0) return;
for (var i = b ? 0 : n2; (b && i < n2) || (!b && i >= 0); i += b ? 1 : -1) {
if (toc_visible.eq(i).data('path') === path) break;
}
i += b ? -1 : 1;
if (i < 0) i = n2 - 1;
if (i >= n2) i = 0;
var lnk = toc_visible.eq(i).find('a[href$=".html"]');
if (lnk.length) lnk[0].click();
return;
}
if (n === 0) return;
var $p = $highlighted.eq(hi);
$p[0].scrollIntoView();
$highlighted.css('background-color', '');
// an orange background color on the current item and removed later
$p.css('background-color', 'orange');
setTimeout(function() {
$p.css('background-color', '');
}, 2000);
}
function currentPath() {
var href = window.location.pathname;
href = href.substr(href.lastIndexOf('/') + 1);
return href === '' ? 'index.html' : href;
}
// Create search form
function createForm(value) {
if ($searchForm) $searchForm.remove();
if ($searchLabel) $searchLabel.remove();
if ($searchInput) $searchInput.remove();
$searchForm = $('<div>', {
'class': 'book-search',
'role': 'search'
});
$searchLabel = $('<label>', {
'for': 'search-box',
'aria-hidden': 'false',
'hidden': ''
});
$searchInput = $('<input>', {
'id': 'search-box',
'type': 'search',
'class': 'form-control',
'val': value,
'placeholder': 'Type to search (Enter for navigation)',
'title': 'Use Enter or the <Down> key to navigate to the next match, or the <Up> key to the previous match'
});
$searchLabel.append("Type to search");
$searchLabel.appendTo($searchForm);
$searchInput.appendTo($searchForm);
$searchForm.prependTo(gitbook.state.$book.find('.book-summary'));
}
// Return true if search is open
function isSearchOpen() {
return gitbook.state.$book.hasClass("with-search");
}
// Toggle the search
function toggleSearch(_state) {
if (isSearchOpen() === _state) return;
if (!$searchInput) return;
gitbook.state.$book.toggleClass("with-search", _state);
// If search bar is open: focus input
if (isSearchOpen()) {
gitbook.sidebar.toggle(true);
$searchInput.focus();
} else {
$searchInput.blur();
$searchInput.val("");
gitbook.storage.remove("keyword");
gitbook.sidebar.filter(null);
$('.page-inner').unhighlight(hiOpts);
}
}
function sidebarFilter(results) {
gitbook.sidebar.filter(_.pluck(results, "path"));
toc_visible = $('ul.summary').find('li:visible');
}
// Recover current search when page changed
function recoverSearch() {
var keyword = gitbook.storage.get("keyword", "");
createForm(keyword);
if (keyword.length > 0) {
if(!isSearchOpen()) {
toggleSearch(true); // [Yihui] open the search box
}
sidebarFilter(search(keyword));
}
}
gitbook.events.bind("start", function(e, config) {
// [Yihui] disable search
if (config.search === false) return;
collapse = !config.toc || config.toc.collapse === 'section' ||
config.toc.collapse === 'subsection';
// Pre-fetch search index and create the form
fetchIndex()
// [Yihui] recover search after the page is loaded
.then(recoverSearch);
// Type in search bar
$(document).on("keyup", ".book-search input", function(e) {
var key = (e.keyCode ? e.keyCode : e.which);
// [Yihui] Escape -> close search box; Up/Down/Enter: previous/next highlighted
if (key == 27) {
e.preventDefault();
toggleSearch(false);
} else if (key == 38) {
scrollToHighlighted(-1);
} else if (key == 40 || key == 13) {
scrollToHighlighted(1);
}
}).on("input", ".book-search input", function(e) {
var q = $(this).val().trim();
if (q.length === 0) {
gitbook.sidebar.filter(null);
gitbook.storage.remove("keyword");
$('.page-inner').unhighlight(hiOpts);
} else {
var results = search(q);
sidebarFilter(results);
gitbook.storage.set("keyword", q);
}
});
// Create the toggle search button
gitbook.toolbar.createButton({
icon: 'fa fa-search',
label: 'Search',
position: 'left',
onClick: toggleSearch
});
// Bind keyboard to toggle search
gitbook.keyboard.bind(['f'], toggleSearch);
});
// [Yihui] do not try to recover search; always start fresh
// gitbook.events.bind("page.change", recoverSearch);
});

105
_book/libs/gitbook-2.6.7/js/plugin-sharing.js

@ -0,0 +1,105 @@
gitbook.require(["gitbook", "lodash", "jQuery"], function(gitbook, _, $) {
var SITES = {
'github': {
'label': 'Github',
'icon': 'fa fa-github',
'onClick': function(e) {
e.preventDefault();
var repo = $('meta[name="github-repo"]').attr('content');
if (typeof repo === 'undefined') throw("Github repo not defined");
window.open("https://github.com/"+repo);
}
},
'facebook': {
'label': 'Facebook',
'icon': 'fa fa-facebook',
'onClick': function(e) {
e.preventDefault();
window.open("http://www.facebook.com/sharer/sharer.php?u="+encodeURIComponent(location.href));
}
},
'twitter': {
'label': 'Twitter',
'icon': 'fa fa-twitter',
'onClick': function(e) {
e.preventDefault();
window.open("http://twitter.com/intent/tweet?text="+document.title+"&url="+encodeURIComponent(location.href)+"&hashtags=rmarkdown,bookdown");
}
},
'linkedin': {
'label': 'LinkedIn',
'icon': 'fa fa-linkedin',
'onClick': function(e) {
e.preventDefault();
window.open("https://www.linkedin.com/shareArticle?mini=true&url="+encodeURIComponent(location.href)+"&title="+encodeURIComponent(document.title));
}
},
'weibo': {
'label': 'Weibo',
'icon': 'fa fa-weibo',
'onClick': function(e) {
e.preventDefault();
window.open("http://service.weibo.com/share/share.php?content=utf-8&url="+encodeURIComponent(location.href)+"&title="+encodeURIComponent(document.title));
}
},
'instapaper': {
'label': 'Instapaper',
'icon': 'fa fa-italic',
'onClick': function(e) {
e.preventDefault();
window.open("http://www.instapaper.com/text?u="+encodeURIComponent(location.href));
}
},
'vk': {
'label': 'VK',
'icon': 'fa fa-vk',
'onClick': function(e) {
e.preventDefault();
window.open("http://vkontakte.ru/share.php?url="+encodeURIComponent(location.href));
}
}
};
gitbook.events.bind("start", function(e, config) {
var opts = config.sharing;
if (!opts) return;
// Create dropdown menu
var menu = _.chain(opts.all)
.map(function(id) {
var site = SITES[id];
if (!site) return;
return {
text: site.label,
onClick: site.onClick
};
})
.compact()
.value();
// Create main button with dropdown
if (menu.length > 0) {
gitbook.toolbar.createButton({
icon: 'fa fa-share-alt',
label: 'Share',
position: 'right',
dropdown: [menu]
});
}
// Direct actions to share
_.each(SITES, function(site, sideId) {
if (!opts[sideId]) return;
gitbook.toolbar.createButton({
icon: site.icon,
label: site.label,
title: site.label,
position: 'right',
onClick: site.onClick
});
});
});
});

4
_book/libs/jquery-2.2.3/jquery.min.js

File diff suppressed because one or more lines are too long

5
_book/search_index.json

File diff suppressed because one or more lines are too long

14
_book/style.css

@ -0,0 +1,14 @@
p.caption {
color: #777;
margin-top: 10px;
}
p code {
white-space: inherit;
}
pre {
word-break: normal;
word-wrap: normal;
}
pre code {
white-space: inherit;
}

BIN
_book/writing-frictionless-r-package-wrappers.epub

Binary file not shown.

BIN
_book/writing-frictionless-r-package-wrappers.pdf

Binary file not shown.

521
_book/writing-frictionless-r-package-wrappers.tex

@ -0,0 +1,521 @@
% Options for packages loaded elsewhere
\PassOptionsToPackage{unicode}{hyperref}
\PassOptionsToPackage{hyphens}{url}
%
\documentclass[
]{book}
\usepackage{lmodern}
\usepackage{amssymb,amsmath}
\usepackage{ifxetex,ifluatex}
\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{textcomp} % provide euro and other symbols
\else % if luatex or xetex
\usepackage{unicode-math}
\defaultfontfeatures{Scale=MatchLowercase}
\defaultfontfeatures[\rmfamily]{Ligatures=TeX,Scale=1}
\fi
% Use upquote if available, for straight quotes in verbatim environments
\IfFileExists{upquote.sty}{\usepackage{upquote}}{}
\IfFileExists{microtype.sty}{% use microtype if available
\usepackage[]{microtype}
\UseMicrotypeSet[protrusion]{basicmath} % disable protrusion for tt fonts
}{}
\makeatletter
\@ifundefined{KOMAClassName}{% if non-KOMA class
\IfFileExists{parskip.sty}{%
\usepackage{parskip}
}{% else
\setlength{\parindent}{0pt}
\setlength{\parskip}{6pt plus 2pt minus 1pt}}
}{% if KOMA class
\KOMAoptions{parskip=half}}
\makeatother
\usepackage{xcolor}
\IfFileExists{xurl.sty}{\usepackage{xurl}}{} % add URL line breaks if available
\IfFileExists{bookmark.sty}{\usepackage{bookmark}}{\usepackage{hyperref}}
\hypersetup{
pdftitle={Writing Frictionless R Package Wrappers},
pdfauthor={Bob Rudis},
hidelinks,
pdfcreator={LaTeX via pandoc}}
\urlstyle{same} % disable monospaced font for URLs
\usepackage{color}
\usepackage{fancyvrb}
\newcommand{\VerbBar}{|}
\newcommand{\VERB}{\Verb[commandchars=\\\{\}]}
\DefineVerbatimEnvironment{Highlighting}{Verbatim}{commandchars=\\\{\}}
% Add ',fontsize=\small' for more characters per line
\usepackage{framed}
\definecolor{shadecolor}{RGB}{248,248,248}
\newenvironment{Shaded}{\begin{snugshade}}{\end{snugshade}}
\newcommand{\AlertTok}[1]{\textcolor[rgb]{0.94,0.16,0.16}{#1}}
\newcommand{\AnnotationTok}[1]{\textcolor[rgb]{0.56,0.35,0.01}{\textbf{\textit{#1}}}}
\newcommand{\AttributeTok}[1]{\textcolor[rgb]{0.77,0.63,0.00}{#1}}
\newcommand{\BaseNTok}[1]{\textcolor[rgb]{0.00,0.00,0.81}{#1}}
\newcommand{\BuiltInTok}[1]{#1}
\newcommand{\CharTok}[1]{\textcolor[rgb]{0.31,0.60,0.02}{#1}}
\newcommand{\CommentTok}[1]{\textcolor[rgb]{0.56,0.35,0.01}{\textit{#1}}}
\newcommand{\CommentVarTok}[1]{\textcolor[rgb]{0.56,0.35,0.01}{\textbf{\textit{#1}}}}
\newcommand{\ConstantTok}[1]{\textcolor[rgb]{0.00,0.00,0.00}{#1}}
\newcommand{\ControlFlowTok}[1]{\textcolor[rgb]{0.13,0.29,0.53}{\textbf{#1}}}
\newcommand{\DataTypeTok}[1]{\textcolor[rgb]{0.13,0.29,0.53}{#1}}
\newcommand{\DecValTok}[1]{\textcolor[rgb]{0.00,0.00,0.81}{#1}}
\newcommand{\DocumentationTok}[1]{\textcolor[rgb]{0.56,0.35,0.01}{\textbf{\textit{#1}}}}
\newcommand{\ErrorTok}[1]{\textcolor[rgb]{0.64,0.00,0.00}{\textbf{#1}}}
\newcommand{\ExtensionTok}[1]{#1}
\newcommand{\FloatTok}[1]{\textcolor[rgb]{0.00,0.00,0.81}{#1}}
\newcommand{\FunctionTok}[1]{\textcolor[rgb]{0.00,0.00,0.00}{#1}}
\newcommand{\ImportTok}[1]{#1}
\newcommand{\InformationTok}[1]{\textcolor[rgb]{0.56,0.35,0.01}{\textbf{\textit{#1}}}}
\newcommand{\KeywordTok}[1]{\textcolor[rgb]{0.13,0.29,0.53}{\textbf{#1}}}
\newcommand{\NormalTok}[1]{#1}
\newcommand{\OperatorTok}[1]{\textcolor[rgb]{0.81,0.36,0.00}{\textbf{#1}}}
\newcommand{\OtherTok}[1]{\textcolor[rgb]{0.56,0.35,0.01}{#1}}
\newcommand{\PreprocessorTok}[1]{\textcolor[rgb]{0.56,0.35,0.01}{\textit{#1}}}
\newcommand{\RegionMarkerTok}[1]{#1}
\newcommand{\SpecialCharTok}[1]{\textcolor[rgb]{0.00,0.00,0.00}{#1}}
\newcommand{\SpecialStringTok}[1]{\textcolor[rgb]{0.31,0.60,0.02}{#1}}
\newcommand{\StringTok}[1]{\textcolor[rgb]{0.31,0.60,0.02}{#1}}
\newcommand{\VariableTok}[1]{\textcolor[rgb]{0.00,0.00,0.00}{#1}}
\newcommand{\VerbatimStringTok}[1]{\textcolor[rgb]{0.31,0.60,0.02}{#1}}
\newcommand{\WarningTok}[1]{\textcolor[rgb]{0.56,0.35,0.01}{\textbf{\textit{#1}}}}
\usepackage{longtable,booktabs}
% Correct order of tables after \paragraph or \subparagraph
\usepackage{etoolbox}
\makeatletter
\patchcmd\longtable{\par}{\if@noskipsec\mbox{}\fi\par}{}{}
\makeatother
% Allow footnotes in longtable head/foot
\IfFileExists{footnotehyper.sty}{\usepackage{footnotehyper}}{\usepackage{footnote}}
\makesavenoteenv{longtable}
\usepackage{graphicx}
\makeatletter
\def\maxwidth{\ifdim\Gin@nat@width>\linewidth\linewidth\else\Gin@nat@width\fi}
\def\maxheight{\ifdim\Gin@nat@height>\textheight\textheight\else\Gin@nat@height\fi}
\makeatother
% Scale images if necessary, so that they will not overflow the page
% margins by default, and it is still possible to overwrite the defaults
% using explicit options in \includegraphics[width, height, ...]{}
\setkeys{Gin}{width=\maxwidth,height=\maxheight,keepaspectratio}
% Set default figure placement to htbp
\makeatletter
\def\fps@figure{htbp}
\makeatother
\setlength{\emergencystretch}{3em} % prevent overfull lines
\providecommand{\tightlist}{%
\setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
\setcounter{secnumdepth}{5}
\usepackage{booktabs}
\usepackage[]{natbib}
\bibliographystyle{apalike}
\title{Writing Frictionless R Package Wrappers}
\author{Bob Rudis}
\date{2020-01-02}
\begin{document}
\frontmatter
\maketitle
{
\setcounter{tocdepth}{1}
\tableofcontents
}
\mainmatter
\hypertarget{preface}{%
\chapter{Preface}\label{preface}}
\hypertarget{intro}{%
\chapter{Introduction}\label{intro}}
The R language and RStudio IDE are a powerful combination for ``getting stuff done'', and one aspect of R itself that makes it especially useful is the ability to use it with other programming languages via a robust \emph{foreign language interface} capability\footnote{``Writing R Extensions''; Chapter 5, ``System and foreign language interfaces''; (\url{https://cran.r-project.org/doc/manuals/r-release/R-exts.html\#System-and-foreign-language-interfaces})}. The term ``foreign language'' refers to another programming language such as C, C++, Fortran, Java, Python, Rust, etc. A common way of referring the this idiom of using functionality written in another programming language from directly within R is ``wrapping'' since we're putting an R ``shell'' around the code from the other language. Another term you may see used is ``extending'' (hence the title of the ``Writing R Extensions'' R manual).
While R supports using this this extension mechanism from any R script leaving tiny trails of R and other language source and binary files all across your filesystem is not exactly the best way to keep these components organized and creates other challenges when you come across the need to use them in other projects or share them with others. Thankfully, the R Core team, along with many individual contributors over the years, has made it pretty straightforward to incorporate this extension capability into R packages which are much easier (honest!) to organize and share.
The goal of this book is to help you get up to speed using R and RStudio to write R packages that wrap code from many different languages to help you ``get stuff done'' with as little friction as possible.
\hypertarget{intro-reqs}{%
\section{Base Requirements}\label{intro-reqs}}
It is assumed that readers are familiar with the R programming language, RStudio IDE, and are comfortable installing and using packages. Since this work is about extending R with other programming languages, you should also have some knowledge of one or more of the target languages being covered.
To follow along with the series you'll need to ensure you have the necessary components installed along the way. Rather than overwhelm you with all of them up front, each new section will introduce requirements specific to the language or situation being covered. However, there are some fundamentals you'll need to ensure are available.
\begin{itemize}
\tightlist
\item
An R\footnote{R Project Home (\url{https://www.r-project.org/})} environment, preferably R 3.6.x which is what was used for this series.
\item
RStudio\footnote{RStudio Home (\url{http://rstudio.com/})}, as we'll be using many of the features provided in it to help reduce development friction
\item
The \{pkgbuild\}\footnote{\{pkgbuild\} CRAN page (\url{https://cran.rstudio.com/web/packages/pkgbuild/})} package installed
\end{itemize}
Once you've gotten through those steps, you should fire up RStudio and run:
\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{pkgbuild}\OperatorTok{::}\KeywordTok{check\_build\_tools}\NormalTok{(}\DataTypeTok{debug =} \OtherTok{TRUE}\NormalTok{)}
\end{Highlighting}
\end{Shaded}
which will help you make sure your particular system is ready to build packages.
After performing the build tool check and/or installation of the necessary core tools, you will then need to install the \{devtools\}\footnote{\{devtools\} Home (\url{https://devtools.r-lib.org/})} package, which will help ensure that the remaining core packages required are installed.
We're also going to use the \texttt{git}\footnote{\texttt{git} Home (\url{https://git-scm.com/})} source code version control system. The \texttt{git} ecosystem is \emph{not} ``GitHub'', which is just a public (or, potentially somewhat private) place to house source code repositories, just like other hosted services such as Bitbucket, GitLab, or SourceHut. You can use the excellent ``Happy Git with R''\footnote{Happy Git with R (\url{https://happygitwithr.com/})} resource to help ensure you're source code control environment is also ready to use.
\hypertarget{intro-refs}{%
\section{Supplemental References}\label{intro-refs}}
It may be helpful to create a browser bookmark folder for supplemental reference material that will be referred to from time-to-time across the sections (we'll be adding to this list in each chapter, too):
\begin{itemize}
\tightlist
\item
Writing R Extensions (\url{https://cran.r-project.org/doc/manuals/r-release/R-exts.html})
\item
Advanced R (\url{http://adv-r.had.co.nz/})
\item
R Packaged (\url{http://r-pkgs.had.co.nz/})
\end{itemize}
\hypertarget{intro-up-next}{%
\section{Up Next}\label{intro-up-next}}
If you've been a user of ``development versions'' of R packages or have authored R packages you likely made quick work of this first installment. Those new to creating packages with R, those who tend to only use fully-baked CRAN versions of R packages, and/or those who have not worked with \texttt{git} before likely had to do quite a bit of work to get down to this point (if this describes you, you definitely deserve both a break and kudos for getting this far!).
In the next installment we'll make sure the package building infrastructure is ready to roll by creating a basic R package that we'll use as a building block for future work.
\hypertarget{basic-r-package}{%
\chapter{Building A Basic R Package}\label{basic-r-package}}
Before we start wrapping foreign language code we need to make sure that basic R packages can be created. If you've followed along from the previous chapter you have everything you need to get started here. \emph{Just to make sure}, you should be able to fire up a new RStudio session and execute the following R code and see similar output. If not, you'll need to go through the steps and resources outlined there before continuing.
\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{pkgbuild}\OperatorTok{::}\KeywordTok{check\_build\_tools}\NormalTok{()}
\CommentTok{\#\# Your system is ready to build packages!}
\end{Highlighting}
\end{Shaded}
\hypertarget{config-devtools}{%
\section{Configuring \{devtools\}}\label{config-devtools}}
We're going to rely on the \{devtools\} package for many operations and the first thing you should do now is execute \texttt{help("create",\ "devtools")} in an RStudio R console to see the package documentation page where you'll see guidance pointing you to \texttt{devtools::use\_description()} that lists some R session \texttt{options()} that you can set to make your package development life much easier and quicker. Specifically, it lets you know that you can setup your \texttt{\textasciitilde{}/.Rprofile} to include the certain options settings which will automatically fill in fields each time you create a new package vs you either specifying these fields manually in the package creation GUI or as parameters to \texttt{devtools::create()}.
A good, minimal setup would be something like:
\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{options}\NormalTok{(}
\DataTypeTok{usethis.description =} \KeywordTok{list}\NormalTok{(}
\StringTok{\textasciigrave{}}\DataTypeTok{Authors@R}\StringTok{\textasciigrave{}}\NormalTok{ =}\StringTok{ \textquotesingle{}person("Some", "One", email = "someone@example.com", role = c("aut", "cre"),}
\StringTok{ comment = c(ORCID = "YOUR{-}ORCID{-}ID"))\textquotesingle{}}\NormalTok{,}
\DataTypeTok{License =} \StringTok{"MIT + file LICENSE"}
\NormalTok{ )}
\NormalTok{)}
\end{Highlighting}
\end{Shaded}
NOTE: If you do not have an ``ORCID'' you really should get one (they're free!) by heading over to
--- \url{https://orcid.org/} --- and filling in some basic information.
Take a moment to edit your \texttt{\textasciitilde{}/.Rprofile}. If you're not sure about how to do that there is an excellent chapter in Efficient R Programming\footnote{Efficient R Programming, ``3.3 R Startup''; (\url{https://csgillespie.github.io/efficientR/3-3-r-startup.html\#r-startup})} which walks you through the process.
Once you've added or verified these new \texttt{options()} settings, restart your R session.
\hypertarget{create-a-package}{%
\section{Creating A Package}\label{create-a-package}}
We're \emph{almost} ready to create and build a basic R package. All R packages live in a package directory and I highly suggest creating a \texttt{packages} directory right off your home directory (e.g.~``\texttt{\textasciitilde{}/packages}'') or someplace where you'll be able to keep them all organized and accessible. The rest of these chapters will assume you're using ``\texttt{\textasciitilde{}/packages}'' as the
With \{devtools\} now pre-configured, use the RStudio R Console pane to execute the following code which should produce similar output and open up a new RStudio session with the new package directory:
\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{devtools}\OperatorTok{::}\KeywordTok{create}\NormalTok{(}\StringTok{"\textasciitilde{}/packages/myfirstpackage"}\NormalTok{) }
\CommentTok{\#\# ✔ Creating \textquotesingle{}/Users/someuser/packages/myfirstpackage/\textquotesingle{}}
\CommentTok{\#\# ✔ Setting active project to \textquotesingle{}/Users/someuser/packages/myfirstpackage\textquotesingle{}}
\CommentTok{\#\# ✔ Creating \textquotesingle{}R/\textquotesingle{}}
\CommentTok{\#\# ✔ Writing \textquotesingle{}DESCRIPTION\textquotesingle{}}
\CommentTok{\#\# Package: myfirstpackage}
\CommentTok{\#\# Title: What the Package Does (One Line, Title Case)}
\CommentTok{\#\# Version: 0.0.0.9000}
\CommentTok{\#\# Authors@R (parsed):}
\CommentTok{\#\# * Bob Rudis <bob@rud.is> [aut, cre] (<https://orcid.org/0000{-}0001{-}5670{-}2640>)}
\CommentTok{\#\# Description: What the package does (one paragraph).}
\CommentTok{\#\# License: MIT + file LICENSE}
\CommentTok{\#\# Encoding: UTF{-}8}
\CommentTok{\#\# LazyData: true}
\CommentTok{\#\# ✔ Writing \textquotesingle{}NAMESPACE\textquotesingle{}}
\CommentTok{\#\# ✔ Writing \textquotesingle{}myfirstpackage.Rproj\textquotesingle{}}
\CommentTok{\#\# ✔ Adding \textquotesingle{}.Rproj.user\textquotesingle{} to \textquotesingle{}.gitignore\textquotesingle{}}
\CommentTok{\#\# ✔ Adding \textquotesingle{}\^{}myfirstpackage\textbackslash{}\textbackslash{}.Rproj$\textquotesingle{}, \textquotesingle{}\^{}\textbackslash{}\textbackslash{}.Rproj\textbackslash{}\textbackslash{}.user$\textquotesingle{} to \textquotesingle{}.Rbuildignore\textquotesingle{}}
\CommentTok{\#\# ✔ Opening \textquotesingle{}/Users/someuser/packages/myfirstpackage/\textquotesingle{} in new RStudio session}
\CommentTok{\#\# ✔ Setting active project to \textquotesingle{}<no active project>\textquotesingle{}}
\end{Highlighting}
\end{Shaded}
The directory structure will look like this:
\begin{verbatim}
.
├── DESCRIPTION
├── NAMESPACE
├── R/
└── myfirstpackage.Rproj
\end{verbatim}
At this point we still do not have a ``perfect'' R package. To prove this, use the R console to run \texttt{devtools::check()} and --- after some rather verbose output --- you'll see the following lines at the end:
\begin{verbatim}
> checking DESCRIPTION meta-information ... WARNING
Invalid license file pointers: LICENSE
0 errors ✓ | 1 warning x | 0 notes ✓
\end{verbatim}
Since we're saying that our package will be using the MIT license, we need to ensure there's an associated \texttt{LICENSE} file which we can do by executing \texttt{usethis::use\_mit\_license()} which will create the necessary files and ensure the \texttt{License} field in the \texttt{DESCRIPTION} file is formatted properly.
If you run \texttt{devtools::check()} again, now, your final line should report:
\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{\#\# 0 errors ✓ | 0 warnings ✓ | 0 notes ✓}
\end{Highlighting}
\end{Shaded}
and the package directory tree should look like this:
\begin{verbatim}
├── DESCRIPTION
├── LICENSE
├── LICENSE.md
├── NAMESPACE
├── R/
└── myfirstpackage.Rproj
\end{verbatim}
\hypertarget{round-out-corners}{%
\section{Rounding Out The Corners}\label{round-out-corners}}
While we have a minimum viable package there are a few other steps we should take during this setup phase. First we'll setup our package to use \texttt{\{roxygen2\}}\footnote{\{roxygen2\} Home; (\url{https://roxygen2.r-lib.org/})} for documenting functions, declaring \texttt{NAMESPACE} imports, and other helper-features that will be introduced in later chapters. We can do this via \texttt{usethis::use\_roxygen\_md()}:
\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{usethis}\OperatorTok{::}\KeywordTok{use\_roxygen\_md}\NormalTok{()}
\CommentTok{\#\# ✔ Setting Roxygen field in DESCRIPTION to \textquotesingle{}list(markdown = TRUE)\textquotesingle{}}
\CommentTok{\#\# ✔ Setting RoxygenNote field in DESCRIPTION to \textquotesingle{}7.0.2\textquotesingle{}}
\CommentTok{\#\# ● Run \textasciigrave{}devtools::document()\textasciigrave{}}
\end{Highlighting}
\end{Shaded}
We won't run \texttt{devtools::document()} \emph{just yet}, though. Before we do that we'll also create an R file where we can store top-level package introduction/meta-information:
\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{usethis}\OperatorTok{::}\KeywordTok{use\_package\_doc}\NormalTok{()}
\CommentTok{\#\# ✔ Writing \textquotesingle{}R/myfirstpackage{-}package.R\textquotesingle{}}
\end{Highlighting}
\end{Shaded}
Now, our directory tree should look like:
\begin{verbatim}
.
├── DESCRIPTION
├── LICENSE
├── LICENSE.md
├── NAMESPACE
├── R
│ └── myfirstpackage-package.R
└── myfirstpackage.Rproj
\end{verbatim}
Now, run \texttt{devtools::document()} which will translate the \{roxygen2\} comments into a properly-formatted R documentation file and regenerate the \texttt{NAMESPACE} file (as we'll be managing package imports and exports via \{roxygen2\} comments). The directory tree will now look like:
\begin{verbatim}
.
├── DESCRIPTION
├── LICENSE
├── LICENSE.md
├── NAMESPACE
├── R
│ └── myfirstpackage-package.R
├── man
│ └── myfirstpackage-package.Rd
└── myfirstpackage.Rproj
\end{verbatim}
and, we can now re-run \texttt{devtools::check()} to make sure we have the three ``0's'' we're aiming for each time we check our package for errors.
\hypertarget{pass-the-test}{%
\section{Passing The Test}\label{pass-the-test}}
We're going to want to write and use tests to ensure our package works properly. There are many R package testing frameworks available. To ease the introduction into this process, we'll use one of the frameworks that came along for the ride when you installed the various packages outlined in the previous chapter: \{testthat\}\footnote{\{testthat\} Home; (\url{https://testthat.r-lib.org/})}. Setting up \{testthat\} is also pretty painless thanks to the \{usethis\} package we've been taking advantage of quite a bit so far. We'll create the \{testthat\} overall infrastructure then add a placeholder test script since \texttt{devtools::check()} will complain about no tests being available if we do not have at least a single script it can execute during the test phase of the package checking process.
\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{usethis}\OperatorTok{::}\KeywordTok{use\_testthat}\NormalTok{()}
\CommentTok{\#\# ✔ Adding \textquotesingle{}testthat\textquotesingle{} to Suggests field in DESCRIPTION}
\CommentTok{\#\# ✔ Creating \textquotesingle{}tests/testthat/\textquotesingle{}}
\CommentTok{\#\# ✔ Writing \textquotesingle{}tests/testthat.R\textquotesingle{}}
\CommentTok{\#\# ● Call \textasciigrave{}use\_test()\textasciigrave{} to initialize a basic test file and open it for editing.}
\NormalTok{usethis}\OperatorTok{::}\KeywordTok{use\_test}\NormalTok{(}\StringTok{"placeholder"}\NormalTok{)}
\CommentTok{\#\# ✔ Increasing \textquotesingle{}testthat\textquotesingle{} version to \textquotesingle{}>= 2.1.0\textquotesingle{} in DESCRIPTION}
\CommentTok{\#\# ✔ Writing \textquotesingle{}tests/testthat/test{-}placeholder.R\textquotesingle{}}
\CommentTok{\#\# ● Modify \textquotesingle{}tests/testthat/test{-}placeholder.R\textquotesingle{}}
\end{Highlighting}
\end{Shaded}
The directory tree will now look like this:
\begin{verbatim}
.
├── DESCRIPTION
├── LICENSE
├── LICENSE.md
├── NAMESPACE
├── R
│ └── myfirstpackage-package.R
├── man
│ └── myfirstpackage-package.Rd
├── myfirstpackage.Rproj
└── tests
├── testthat
│ └── test-placeholder.R
└── testthat.R
\end{verbatim}
Run \texttt{devtools::check()} one more time to make sure we've got those precious 3 ``0's'' one last time.
\hypertarget{get-under-control}{%
\section{Getting Things Under Control}\label{get-under-control}}
We're \emph{almost} done! One final step is to turn this directory into a git-managed directory so we can work a bit more safely and eventually share our development work with a broader audience. Provided you followed the outline in the previous chapter, setting up git is as straightforward as one \{usethis\} function call:
\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{usethis}\OperatorTok{::}\KeywordTok{use\_git}\NormalTok{()}
\CommentTok{\#\# ✔ Setting active project to \textquotesingle{}/Users/someuser/packages/myfirstpackage\textquotesingle{}}
\CommentTok{\#\# ✔ Initialising Git repo}
\CommentTok{\#\# ✔ Adding \textquotesingle{}.Rhistory\textquotesingle{}, \textquotesingle{}.RData\textquotesingle{} to \textquotesingle{}.gitignore\textquotesingle{}}
\CommentTok{\#\# There are 10 uncommitted files:}
\CommentTok{\#\# * \textquotesingle{}.gitignore\textquotesingle{}}
\CommentTok{\#\# * \textquotesingle{}.Rbuildignore\textquotesingle{}}
\CommentTok{\#\# * \textquotesingle{}DESCRIPTION\textquotesingle{}}
\CommentTok{\#\# * \textquotesingle{}LICENSE\textquotesingle{}}
\CommentTok{\#\# * \textquotesingle{}LICENSE.md\textquotesingle{}}
\CommentTok{\#\# * \textquotesingle{}man/\textquotesingle{}}
\CommentTok{\#\# * \textquotesingle{}myfirstpackage.Rproj\textquotesingle{}}
\CommentTok{\#\# * \textquotesingle{}NAMESPACE\textquotesingle{}}
\CommentTok{\#\# * \textquotesingle{}R/\textquotesingle{}}
\CommentTok{\#\# * \textquotesingle{}tests/\textquotesingle{}}
\CommentTok{\#\# Is it ok to commit them?}
\CommentTok{\#\# }
\CommentTok{\#\# 1: For sure}
\CommentTok{\#\# 2: Negative}
\CommentTok{\#\# 3: Not now}
\CommentTok{\#\# }
\CommentTok{\#\# Selection: 1}
\CommentTok{\#\# ✔ Adding files}
\CommentTok{\#\# ✔ Commit with message \textquotesingle{}Initial commit\textquotesingle{}}
\CommentTok{\#\# ● A restart of RStudio is required to activate the Git pane}
\CommentTok{\#\# Restart now?}
\CommentTok{\#\# }
\CommentTok{\#\# 1: Negative}
\CommentTok{\#\# 2: Not now}
\CommentTok{\#\# 3: Yup}
\CommentTok{\#\# }
\CommentTok{\#\# Selection: 3}
\end{Highlighting}
\end{Shaded}
RStudio should have been restarted (so it can add a ``Git'' pane in case you want to use the GUI to manage git) and the directory tree will now have a \texttt{.git/} subdirectory that you should (almost) never touch by hand.
The last thing to do is to ``vaccinate'' your git setup so you don't leak sensitive or unnecessary files when you (eventually) share your creation with the world:
\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{usethis}\OperatorTok{::}\KeywordTok{git\_vaccinate}\NormalTok{()}
\CommentTok{\#\# ✔ Adding \textquotesingle{}.Rproj.user\textquotesingle{}, \textquotesingle{}.Rhistory\textquotesingle{}, \textquotesingle{}.Rdata\textquotesingle{} to \textquotesingle{}/Users/someuser/.gitignore\textquotesingle{}}
\end{Highlighting}
\end{Shaded}
We now have a basic, working R package that is devoid of any real functionality other than that of getting us familiar with the package setup and validation processes. We'll be building upon this experience in most of the coming chapters.
\hypertarget{quick-reference}{%
\section{Quick Reference}\label{quick-reference}}
After ensuring you've got the recommended \texttt{options()} in place, here are the steps to setup a new package:
\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{\# in any RStudio R Console session}
\NormalTok{devtools}\OperatorTok{::}\KeywordTok{create}\NormalTok{(}\StringTok{"\textasciitilde{}/packages/THE{-}PACKAGE{-}NAME"}\NormalTok{)}
\CommentTok{\# in the newly created package RStudio R Console session:}
\NormalTok{usethis}\OperatorTok{::}\KeywordTok{use\_mit\_license}\NormalTok{() }\CommentTok{\# need a LICENSE file}
\NormalTok{usethis}\OperatorTok{::}\KeywordTok{use\_roxygen\_md}\NormalTok{() }\CommentTok{\# use \{roxygen2\} for documentation and configuration}
\NormalTok{usethis}\OperatorTok{::}\KeywordTok{use\_package\_doc}\NormalTok{() }\CommentTok{\# setup a package{-}level manual page}
\NormalTok{usethis}\OperatorTok{::}\KeywordTok{use\_testthat}\NormalTok{() }\CommentTok{\# setup testing infrastructure}
\NormalTok{usethis}\OperatorTok{::}\KeywordTok{use\_test}\NormalTok{(}\StringTok{"placeholder"}\NormalTok{) }\CommentTok{\# setup a placeholder test file}
\NormalTok{devtools}\OperatorTok{::}\KeywordTok{document}\NormalTok{() }\CommentTok{\# Let \{roxygen2\} create NAMESPACE entries, build manual pages (and, more later on)}
\NormalTok{devtools}\OperatorTok{::}\KeywordTok{check}\NormalTok{() }\CommentTok{\# looking for the three "0\textquotesingle{}s" that tell us we\textquotesingle{}re ready to roll!}
\NormalTok{usethis}\OperatorTok{::}\KeywordTok{use\_git}\NormalTok{() }\CommentTok{\# put the directory under git version control}
\NormalTok{usethis}\OperatorTok{::}\KeywordTok{git\_vaccinate}\NormalTok{() }\CommentTok{\# Prevent leaking credentials and other unnecessary filesystem cruft}
\end{Highlighting}
\end{Shaded}
Rather than re-type \texttt{devtools::document()} (et al) whenever you need to run \{roxygen2\} or build/check a package you can use RStudio keyboard shortcuts that are designed to seamlessly integrate with the \{devtools\} ecosystem:
\begin{longtable}[]{@{}llll@{}}
\toprule
Operation & Windows \& Linux & Mac & \{devtools\} equivalent\tabularnewline
\midrule
\endhead
Install and Restart & Ctrl+Shift+B & Cmd+Shift+B & devtools::install()\tabularnewline
Load All (devtools) & Ctrl+Shift+L & Cmd+Shift+L & devtools::load\_all()\tabularnewline
Test Package (Desktop) & Ctrl+Shift+T & Cmd+Shift+T & devtools::test()\tabularnewline
Test Package (Web) & Ctrl+Alt+F7 & Cmd+Alt+F7 & devtools::test()\tabularnewline
Check Package & Ctrl+Shift+E & Cmd+Shift+E & devtools::check()\tabularnewline
Document Package & Ctrl+Shift+D & Cmd+Shift+D & devtools::document()\tabularnewline
\bottomrule
\end{longtable}
We'll refer to these operations as ``install'' (or ``build''), ``load all'', ``test'', ``check'', and ``document'' from now on so you can choose to use the console or the shortcuts as you prefer.
\hypertarget{exercises}{%
\section{Exercises}\label{exercises}}
Our package may be kinda, well, \emph{useless} for the moment but that doesn't mean you can't show it some love and get some practice in at the same time while things are still relatively straightforward.
\begin{itemize}
\tightlist
\item
Modify the \texttt{Title}, \texttt{Version}, and \texttt{Description} fields of the \texttt{DESCRIPTION} file and refine them as needed until package checks pass.
\item
Deliberately mangle parts of the \texttt{DESCRIPTION} file to see what errors or warnings you receive during the package check process.
\item
Read up on \{roxygen2\} and add some \texttt{Section}s to it formatted with markdown and/or LaTeX. Re-``document'' the package and see how your changes look.
\item
Edit the \texttt{test-placeholder.R} file and change the placeholder test it created so it fails and then re-check the package to see what warnings or errors show up.
\item
After you've made (valid, working) modifications to any/all of the above \emph{and package checks pass}, use either the git command line tools or the RStudio Git pane to add your updates to the git tree. Use the resources linked to in the previous chapter if you need a refresher on how to do that.
\item
Re-run through all the steps with a brand new package name just to make sure you're comfortable with the package creation process.
\end{itemize}
\hypertarget{basic-up-next}{%
\section{Up Next}\label{basic-up-next}}
In the next installment in the series we will start wrapping by creating a basic wrapper that just calls out to the operating system shell to run commands.
\backmatter
\bibliography{book.bib}
\end{document}

5
_bookdown.yml

@ -0,0 +1,5 @@
book_filename: "writing-frictionless-r-package-wrappers"
delete_merged_file: true
language:
ui:
chapter_name: "Chapter "

16
_output.yml

@ -0,0 +1,16 @@
bookdown::gitbook:
css: style.css
config:
toc:
before: |
<li><a href="./">Writing Frictionless R Package Wrappers</a></li>
after: |
<li><a href="https://github.com/rstudio/bookdown" target="blank">Published with bookdown</a></li>
download: ["pdf", "epub"]
bookdown::pdf_book:
includes:
in_header: preamble.tex
latex_engine: xelatex
citation_package: natbib
keep_tex: yes
bookdown::epub_book: default

10
book.bib

@ -0,0 +1,10 @@
@Book{xie2015,
title = {Dynamic Documents with {R} and knitr},
author = {Yihui Xie},
publisher = {Chapman and Hall/CRC},
address = {Boca Raton, Florida},
year = {2015},
edition = {2nd},
note = {ISBN 978-1498716963},
url = {http://yihui.org/knitr/},
}

16
index.Rmd

@ -0,0 +1,16 @@
---
title: "Writing Frictionless R Package Wrappers"
author: "Bob Rudis"
date: "`r Sys.Date()`"
site: bookdown::bookdown_site
documentclass: book
bibliography: [book.bib]
biblio-style: apalike
link-citations: yes
url: 'https\://rud.is/books/writing-frictionless-r-package-wrappers/'
description: "Extending the functionality of R via R's foreign language interfaces."
---
# Preface {#preface}

1
preamble.tex

@ -0,0 +1 @@
\usepackage{booktabs}

1
publish.sh

@ -0,0 +1 @@
rsync -avp ~/books/writing-frictionless-r-package-wrappers/_book/* bob@rud.is:/var/sites/rud.is/books/writing-frictionless-r-package-wrappers/

14
style.css

@ -0,0 +1,14 @@
p.caption {
color: #777;
margin-top: 10px;
}
p code {
white-space: inherit;
}
pre {
word-break: normal;
word-wrap: normal;
}
pre code {
white-space: inherit;
}

17
writing-frictionless-r-package-wrappers.Rproj

@ -0,0 +1,17 @@
Version: 1.0
RestoreWorkspace: Default
SaveWorkspace: Default
AlwaysSaveHistory: Default
EnableCodeIndexing: Yes
UseSpacesForTab: Yes
NumSpacesForTab: 2
Encoding: UTF-8
RnwWeave: Sweave
LaTeX: pdfLaTeX
AutoAppendNewline: Yes
BuildType: Website
Loading…
Cancel
Save