Professional Documents
Culture Documents
Subsequent chapters of the book go into more details about each package component.
They’re roughly organised in order of importance:
R code, chapter 6: the most important directory is R/, where your R code lives. A
package with just this directory is still a useful package. (And indeed, if you stop reading
the book after this chapter, you’ll have still learned some useful new skills.)
External data, chapter 12: the data/ directory allows you to include data with your
package. You might do this to bundle data in a way that’s easy for R users to access, or
just to provide compelling examples in your documentation.
Git and GitHub, chapter 16: mastering a version control system is vital to easily
collaborate with others, and is useful even for solo work because it allows you to easily
undo mistakes. In this chapter, you’ll learn how to use the popular Git and GitHub
combo with RStudio.
Automated checking, chapter 17: R provides very useful automated quality
checks in the form of R CMD check . Running them regularly is a great way to avoid many
common mistakes. The results can sometimes be a bit cryptic, so we provide a
comprehensive cheatsheet to help you convert warnings to actionable insight.
.Rbuildignore lists files that we need to have around but that should not be included
when building the R package from source. More in 4.3.1.
.Rproj.user , if you have it, is a directory used internally by RStudio.
.gitignore anticipates Git usage and ignores some standard, behind-the-scenes files
created by R and RStudio. Even if you do not plan to use Git, this is harmless.
DESCRIPTION provides metadata about your package . We edit this shortly.
NAMESPACE declares the functions your package exports for external use and the
external functions your package imports from other packages. At the moment, it holds
temporary-yet-functional placeholder content.
The R/ directory is the “business end” of your package . It will soon
contain .R files with function definitions.
foofactors.Rproj is the file that makes this directory an RStudio Project. Even if you
don’t use RStudio, this file is harmless. Or you can suppress its creation
with create_package(..., rstudio = FALSE) . More in 5.2.
CAPÍTULO 02 - “The whole game”
Use Ctrl + . in RStudio and start typing “DESCRIPTION” to activate a helper that makes it easy to open a
file for editing. In addition to a filename, your hint can be a function name. This is very handy once a
package has lots of functions and files below R/.
use_mit_license("Jane Doe")
#> ✔ Setting License field in DESCRIPTION to 'MIT + file LICENSE'
#> ✔ Writing 'LICENSE.md'
#> ✔ Adding '^LICENSE\\.md$' to '.Rbuildignore'
#> ✔ Writing 'LICENSE'
Like other license helpers, use_mit_license() also puts a copy of the full license
in LICENSE.md and adds this file to .Rbuildignore. It’s considered a best practice to include a full
license in your package’s source, such as on GitHub, but CRAN disallows the inclusion of this
file in a package tarball.
If you use RStudio, open R/fbind.R in the source editor and put the cursor somewhere in
the fbind() function definition. Now do Code > Insert roxygen skeleton.
document()
#> Updating foofactors documentation
#> Updating roxygen version in /tmp/RtmpsJ87ir/foofactors/DESCRIPTION
#> Writing NAMESPACE
#> Loading foofactors
#> Writing NAMESPACE
#> Writing fbind.Rd
Since we have a minimum viable product now, let’s install the foofactors package into
your library via install():
install()
The helper use_test() opens and/or creates a test file. You can provide the file’s basename
or, if you are editing the relevant source file in RStudio, it will be automatically
generated. Since this book is built non-interactively, we must provide the basename
explicitly:
use_test("fbind")
#> ✔ Increasing 'testthat' version to '>= 2.1.0' in DESCRIPTION
#> ✔ Writing 'tests/testthat/test-fbind.R'
This creates the file tests/testthat/test-fbind.R . Put this content in it:
test_that("fbind() binds factor (or character)", {
x <- c("a", "b")
x_fact <- factor(x)
y <- c("c", "d")
z <- factor(c("a", "b", "c", "d"))
RStudio exposes test() in the Build menu, in the Build pane via More > Test package, and in
keyboard shortcuts Ctrl + Shift + T (Windows & Linux) or Cmd + Shift + T (macOS).
expect_identical(fbind(x, y), z)
expect_identical(fbind(x_fact, y), z)
})
It is a good idea to use the covr package to track what proportion of your package’s source
code is exercised by the tests. More details can be found in chapter 10.
You will inevitably want to use a function from another package in your own package. Just as
we needed to export fbind(), we need to import functions from the namespace of other
packages. If you plan to submit a package to CRAN, note that this even applies to functions in
packages that you think of as “always available”, such as stats::median() or utils::head() .
We’re going to add another function to foofactors that produces a sorted frequency table
for a factor. We’ll borrow some smarts from the forcats package, specifically the
function forcats::fct_count() .
First, declare your general intent to use some functions from the forcats namespace
with use_package() :
use_package("forcats")
#> ✔ Adding 'forcats' to Imports field in DESCRIPTION
#> ● Refer to functions with `forcats::fun()`
This adds the forcats package to the “Imports” section of DESCRIPTION.
How would you connect your local foofactors package and Git repository to a companion
repository on GitHub?
Además de crear README.Rmd, esto agrega algunas líneas a .Rbuildignore y crea un enlace
de precompromiso de Git para ayudarlo a mantener README.Rmd y README.md
sincronizados.
Nos gusta escribir el archivo README en R Markdown, por lo que puede incluir el uso real.
Cargará la versión actualmente instalada de su paquete, por lo que este es un buen momento
para "Instalar y reiniciar" en RStudio. O haga esto en R Console:
install()
Ejemplo: The README.Rmd we use is here: README.Rmd and these are the contents:
Don’t forget to render it to make README.md! The pre-commit hook should remind you
if you try to commit README.Rmd but not README.md and also
when README.md appears to be out-of-date.
rmarkdown::render("README.Rmd") ## or use "Knit HTML" in RStudio
check()
install()
To get started, make sure you have the latest version of R (at
least 3.6.1, which is the version being used to render this book),
then run the following code to get the packages you’ll need:
install.packages(c("devtools", "roxygen2", "testthat", "knitr"))
If you choose to specify the namespace, such as when working in a more programmatic style,
then access usethis functions directly: do usethis::use_testthat() instead of
devtools::use_testthat().
Do not select the box for “Edit the system PATH”. devtools and
RStudio should put Rtools on the PATH automatically when it is needed.
Do select the box for “Save version information to registry”. It
should be selected by default.
You can check that you have everything installed and
working by running the following code:
# TODO: replace with whatever results from https://github.com/r-
lib/devtools/issues/1970
library(devtools)
has_devel()
#> [1] TRUE
If everything is ok, it returns TRUE. Otherwise, it will reveal
some diagnostic info about the problem.
CAPÍTULO 04 - “Package structure and state”
Aprenderá sobre los diversos estados en los que puede estar un paquete y la diferencia entre un
paquete y una biblioteca (y por qué debería importarle).
Los flujos de trabajo de desarrollo de paquetes tienen mucho más sentido si comprende los cinco
estados en los que puede estar un paquete R:
1. Source (Fuente)
2. Bundled (Incluido)
3. Binary (Binario)
4. Installed (Instalado)
5. in-memory (En - memoria)
Ya conoce algunas de las funciones que colocan paquetes en estos estados. Por ejemplo,
install.packages() y devtools::install_github() mueven un paquete desde los estados
fuente, empaquetado o binario al estado instalado. La función library() carga un paquete
instalado en la memoria, lo que lo hace disponible para uso inmediato y directo.
Source Package
Un paquete fuente es solo un directorio de archivos con una estructura específica. Incluye
componentes particulares, como un archivo DESCRIPTION, un directorio R/ que contiene archivos
.R , etc.
Muchos paquetes R se desarrollan al aire libre en GitHub (o GitLab o similar). El mejor de los casos
es que visite la página de inicio de CRAN del paquete, por ejemplo:
forcats: https://cran.r-project.org/package=forcats
readxl: https://cran.r-project.org/package=readxl
y una de sus URL enlaza con un repositorio en un servicio de alojamiento público, por ejemplo:
forcats: https://github.com/tidyverse/forcats
readxl: https://github.com/tidyverse/readxl
Bundled Package
En el raro caso de que necesite hacer un paquete a partir de un paquete que está desarrollando
localmente, use devtools::build() . Bajo el capó, esto llama a pkgbuild::build() y, en última
instancia, R CMD build, que se describe más adelante en la sección de construcción de paquetes
de tarballs de Writing R Extensions.
Cada paquete CRAN está disponible en forma de paquete, a través del campo "Fuente del
paquete" de las páginas de destino individuales. Continuando con nuestros ejemplos anteriores,
puede descargar los paquetes forcats_0.4.0.tar.gz y readxl_1.3.1.tar.gz (o cualesquiera
que sean las versiones actuales). Podría desempaquetar dicho paquete en el shell (no en la
consola R) de esta manera:
Controla qué archivos del paquete fuente llegan a los formularios posteriores.
Cada línea de .Rbuildignore es una expresión regular compatible con Perl que
coincide, sin importar el caso, con la ruta a cada archivo en el paquete
fuente.
Si la expresión regular coincide, ese archivo o directorio se excluye. Tenga
en cuenta que hay algunas exclusiones predeterminadas implementadas por R,
relacionadas principalmente con los sistemas y editores de control de
versiones clásicos, como SVN, Git y Emacs.
Para excluir un archivo o directorio específico (el caso de uso más común),
DEBE anclar la expresión regular. Por ejemplo, para excluir un directorio
llamado "notas", use ^notes$. Las notas de expresión regular coincidirán con
cualquier nombre de archivo que contenga notas, p. R/notes.R man/important-
notes.R, data/endnotes.Rdata, etc. La forma más segura de excluir un archivo o
directorio específico es usar usethis::use_build_ignore("notes"), que hace el
escape para tú.
.Rbuildignore es una forma de resolver algunas de las tensiones entre las
prácticas que respaldan su proceso de desarrollo y los requisitos de CRAN para
el envío y la distribución. Incluso si no planea lanzar CRAN, seguir estas
convenciones le permitirá hacer el mejor uso de las herramientas integradas de
R para la verificación e instalación de paquetes. Los archivos afectados se
dividen en dos clases amplias, semi-superpuestas:
Los paquetes binarios para macOS se almacenan como .tgz, mientras que los
paquetes binarios de Windows terminan en .zip. Si necesita hacer un paquete
binario, use devtools::build(binary = TRUE) en el sistema operativo relevante.
Bajo el capó, esto llama a pkgbuild::build(binary = TRUE) y, en última
instancia, R CMD INSTALL --build, que se describe con más detalle en la
sección Building binary packages de Writing R Extensions.
Esto es, de hecho, parte de lo que generalmente sucede detrás de escena cuando
llamas a install.packages() .
library(remotes)
In - memory Package
library(usethis)
Suponiendo que usethis está instalado, esta llamada hace que sus funciones estén
disponibles para su uso, es decir, ahora podemos hacer:
create_package("/path/to/my/coolpackage")
Packages libraries
# on Windows
.libPaths()
#> [1] "C:/Users/jenny/Documents/R/win-library/3.6"
#> [2] "C:/Program Files/R/R-3.6.0/library"
Las rutas de archivo para estas bibliotecas también dejan en claro que están
asociadas con una versión específica de R (3.6.x en el momento de la escritura),
que también es típica. Esto refleja y refuerza el hecho de que necesita
reinstalar sus paquetes de complementos cuando actualiza R de, digamos, 3.5 a
3.6, lo cual es un cambio en la versión menor. Por lo general, no necesita
volver a instalar paquetes de complementos para una versión de parche, por
ejemplo, pasar de R 3.6.0 a 3.6.1.
Estas son las principales palancas que controlan qué bibliotecas están activas,
en orden de alcance y persistencia:
Antes de poder crear su paquete, debe encontrar un nombre para él. ¡Esta puede
ser la parte más difícil de crear un paquete! Hay tres requisitos formales:
Es imposible cumplir con todas las sugerencias para nombrar un paquete, por lo
que obviamente deberá hacer algunas compensaciones (trade-offs). El available
package tiene una función llamada available() que le ayuda a evaluar un nombre
de paquete potencial desde muchos ángulos:
library(available)
available("doofus")
#> Urban Dictionary can contain potentially offensive results,
#> should they be included? [Y]es / [N]o:
#> 1: 1
#> ── doofus
──────────────────────────────────────────────────────────────────
#> Name valid: ✔
#> Available on CRAN: ✔
#> Available on Bioconductor: ✔
#> Available on GitHub: ✔
#> Abbreviations: http://www.abbreviations.com/doofus
#> Wikipedia: https://en.wikipedia.org/wiki/doofus
#> Wiktionary: https://en.wiktionary.org/wiki/doofus
#> Sentiment:???
Una vez que haya encontrado un nombre, hay dos formas de crear el paquete.
Llamar usethis::create_package().
En rstudio, hacer File > New Project > New Directory > R Package. Esto
finalmente llama usethis::create_package(), así que realmente solo hay
una manera.
No use package.skeleton() para crear un paquete. Debido a que esta función
viene con R, es posible que tenga la tentación de usarla, pero crea un paquete
que arroja errores de inmediato con la compilación R CMD. Anticipa un proceso de
desarrollo diferente al que usamos aquí, por lo que reparar este estado inicial
roto simplemente hace un trabajo innecesario para las personas que usan devtools
(y, especialmente, roxygen2).
create_package("path/to/package/pkgname")
devtools trabaja de la mano con RStudio, que creemos que es el mejor entorno de
desarrollo para la mayoría de los usuarios de R.
Version: 1.0
RestoreWorkspace: No
SaveWorkspace: No
AlwaysSaveHistory: Default
EnableCodeIndexing: Yes
Encoding: UTF-8
AutoAppendNewline: Yes
StripTrailingWhitespace: Yes
BuildType: Package
PackageUseDevtools: Yes
PackageInstallArgs: --no-multiarch --with-keep.source
PackageRoxygenize: rd,collate,namespace
load_all() es
el paso clave en este ciclo de "espuma, enjuague,
repetición" del desarrollo del paquete:
devtools::load_all() es
una envoltura delgada pkgload::load_all() que
agrega un poco de facilidad de uso. Es poco probable que lo
use load_all()programáticamente o dentro de otro paquete, pero si lo
hace, probablemente debería usarlo pkgload::load_all() directamente.
CAPÍTULO 06 - “R code”
El primer principio de usar un paquete es que todo el código R va en R/.
Si bien es libre de organizar las funciones en archivos como desee, los dos
extremos son malos: no coloque todas las funciones en un archivo y no ponga cada
función en su propio archivo separado. (Está bien si algunos archivos solo
contienen una función, particularmente si la función es grande o tiene mucha
documentación). Los nombres de los archivos deben ser significativos y terminar
en .R.
# Good
fit_models.R
utility_functions.R
# Bad
foo.r
stuff.r
Evite problemas al nunca usar nombres de archivo que difieran solo en
mayúsculas.
Mi regla general es que si no puedo recordar el nombre del archivo donde vive
una función, necesito separar las funciones en más archivos o darle un mejor
nombre al archivo. (Desafortunadamente no puedes usar subdirectorios dentro de R
/. Lo mejor que puedes hacer es usar un prefijo común, por ejemplo, abc - *.
R.).
Code style
Nombres de objeto
Los nombres de las variables y funciones deben estar en minúsculas. Use un guión
bajo (_) para separar las palabras dentro de un nombre (reserve “.” para métodos
S3). En general, los nombres de las variables deben ser sustantivos y los
nombres de las funciones deben ser verbos. Esfuércese por nombres concisos y
significativos (¡esto no es fácil!).
# Good
day_one
day_1
# Bad
first_day_of_the_month
DayOne
dayone
djm1
Espaciado
Coloque espacios alrededor de todos los operadores infijos (=, +, -, <-, etc.).
La misma regla se aplica cuando se utiliza = en llamadas a funciones. Siempre
ponga un espacio después de una coma, y nunca antes (como en el inglés normal).
# Good
average <- mean(feet / 12 + inches, na.rm = TRUE)
# Bad
average<-mean(feet/12+inches,na.rm=TRUE)
# Bad
if(debug)do(x)
plot (x, y)
El espacio adicional (es decir, más de un espacio en una fila) está bien si
mejora la alineación de signos o asignaciones iguales (<-).
list(
total = a + b + c,
mean = (a + b + c) / n
)
# Bad
if ( debug ) do(x) # No spaces around debug
x[1,] # Needs a space after the comma
x[1 ,] # Space goes after comma not before
Llaves
Una llave de apertura nunca debe ir en su propia línea y siempre debe ir seguida
de una nueva línea. Una llave de cierre debe ir siempre en su propia línea, a
menos que le siga otra cosa.
if (y == 0) {
log(x)
} else {
y ^ x
}
# Bad
if (y == 0) {
log(x)
}
else {
y ^ x
}
Está bien dejar declaraciones muy cortas en la misma línea:
Sangría
Al sangrar su código, use dos espacios. Nunca use pestañas ni mezcle pestañas y
espacios. Cambie estas opciones en el panel de preferencias de código:
knitr::include_graphics("images/style-options.png")
Asignación
TOP-LEVEL Code
Loading code
Cuando carga un script con source(), cada línea de código se ejecuta y los
resultados están disponibles de inmediato. Las cosas son diferentes en un
paquete, porque se carga en dos pasos. Cuando se construye el paquete (por
ejemplo, CRAN), se ejecuta todo el código en R/ y se guardan los resultados.
Cuando carga un paquete, con library() o require() los resultados almacenados
en caché están disponibles para usted. Si cargó scripts de la misma manera que
los paquetes, su código se vería así:
( https://r-pkgs.org/description.html#dependencies )