knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)

Introduction

install.packages(c("devtools", "roxygen2", "testthat", "knitr"))
install.packages("digest")
install.packages("rcmdcheck")
devtools::install_github("hadley/devtools")
library("devtools")

x <-  has_devel()
x

*In the book it says has_devel() will return a bunch of diagnostics and then TRUE, but it now seems to return the value silently---invisibly. *

Package structure

Says it doesn't matter if you start a package from Rstudio or using devtools::create() even though Robert Flight says a rstudio created project won't pass the CRAn tests - although he did say that in 2014.

At this point I start a package as a new project, from Rstudio, also initialising a git repo and a packrat file. Best see how this works in practice.

After I do the initial commit I realise I obviously don't have a github repo yet, so I start a new one and then use:

git remote add origin git@github.com:majazaloznik/pkgs.had.git

to add the repository.

Then I also start this journal as a vingette, because what else am I gonna write it as?

devtools::use_vignette("journal")

This is in the vignettes chapter although it is deprecated. You're supposed to use usethis::use_vignette(). Note that the default output is html, which I have for the time being changed to pff_document, but not sure how this works when you build your package.

Package states

Source package

A source package is the development version of a package that lived on my conmputer: the directory with all the components e.g. R/, DESCRIPTION etc.

Bundled package

Is compressed to a single file---by linux convention tar.gz. If you decompress a bundle it will look almost like a source package. You create a bundle using devtools::build(), which will bundle everyhting but what is in the Rbuildignore file and temporary files like compilation files in src/. Bundles also have the vignettes built to html and pdf.

Rbuildignore lets you have additional files and folders in the source package that are not included in the bundle e.g. data you generated: you want the data in the source package but doens't need to be distributed.

Use Perl-compatible regular expresions to exclude files. (e.g. notes will also exclude end.notes.R, so you have to say ^notes$ to be clear that the name begins ^ and ends $ with notes.

You can use devtools::use_build_ignore() to have it do the regexing for you.

Binary package

To distribute to someone without development tools, you need a binary. This is also a single file, but when uncompressed it is slightly different to the source package:

Binary packages are platform specific.

Use devtools::build(binary = TRUE) to build a binary---although it doesnt' say how you bild one specific to each platform? Oh, seems like it's current platform only?

Installed package

Is a binary that has been decompressed into a package library. This can be done in several ways. e/g/:

In memory packages

To use a package you must load it into memory. There is an important disticntion between loading and loading and attaching an installed package.:

This will apparently be explained later, but for now, library is not useful when you're developing the package, because you have to install it first.

What is a library

A library is simply a directory containing packages. Use .libPaths() to see what you've got active

Rcode

All code goes into R\.

R code workflow

(Re)load your code with Ctrl+Shift+L. Then 'explore the code in the console' I don't get this, what is that supposed to mean?. OK, so this is the same as devtools::load_all(), whic builds the package from source and installs it and loads it/attaches. so explore the code means you can access the updated functions, in the console. Use Ctrl+Shift+L, because it also saves the files.

Organising your functions

Putting them all in one file or each in their own are both bad!? Hmm, I'm def in the latter camp, unless there is a good reason to merge more together. OK, rule of thumb: it must be easy to remember where each function lives. You can't use subdirectories inside R\.

Looking for functions within a file:

Then get back to where you were with Ctrl+F9

Code style

formatR and lintr are an automatic and static approach to keeping clean code approx in line with the Rstudio guidelines.

Object names

Functions and variiables, all lower case, with underscore, not fullstop---reserved for S3 methods. Variable names should be nouns and funcion names should be verbs.

Spacing

Around operators except :, before ( except in funciton call, after , not before

Curyl braces

Open { never on own line, always followed by newline; closed } always on new line ugh except before else

commenting

Explain the why, not the what!

Top-level code

Code in packages---as opposed to scripts---is run when it is built, so it should only build objects, mainly functions. Not a clear sentence, really Aha, he's trying to say not to write top-level code, because it won't get executed when you load it (see more below).

Anticipate unimagined applications of your code by other people.

Loading code

So in a package the code is executed when you build it, but not when you load it. So top-level code (e.g. library(ggplot) won't execute when you install a package, installing a package will only load the objects into the environment. So this sort of top level code has to be moved into the functions themselves if you want it available---but don't do that with libraries, do that in the DESCRIPTION file as we'll see later.

The R landscape

Don't change the landscape---it will not be the same for other people and will make things more difficult to understand. library(), source(), setwd(), options() are all landscape changing functions and you probably don't want to use them. Although I'm again not particulalry happy with the explanation here, so you should avoid things that change the behaviour of other functions after you're done, so you should always revert them back to the way they were using on.exit().

Also, be careful not to make assumptions about the user's landscape¬

When you do need side-effects

Sometimes you do ened some initial setup (what would be equivalent to top-level code in a script file) in a package. Use onLoad() and onAttach() for this (mainly the first one unless directed otherwise). Uses:

.onAttach <- function(libname, pkgname) {
  packageStartupMessage("Welcome to my package")
}
.onLoad <- function(libname, pkgname) {
  op <- options()
  op.devtools <- list(
    devtools.path = "~/R-dev",
    devtools.install.args = "",
    devtools.name = "Your name goes here",
    devtools.desc.author = "First Last <first.last@example.com> [aut, cre]",
    devtools.desc.license = "What license is it under?",
    devtools.desc.suggests = NULL,
    devtools.desc = list()
  )
  toset <- !(names(op.devtools) %in% names(op))
  if(any(toset)) options(op.devtools[toset])

  invisible()
}

This is again not clearly explained at all. To avoid conflicts with other packages you prefix the options with the package name, in this case devtools, and also you test if the user has already set the options themself before you override them. After you do this you can use getOption("devtools.name") for example, to access the value. Oh, invisible() is used instead of return to mean that you can assign the value, but it won't be printed if you don't. But not sure why it is necessary here?

These last two bullet points are not clear at all tbh. The last one must be based on this section in the manual which unfotunately isn't massively more helpful.

Hopefully there will be more info on .onLoad(), but yeah, you should consider using onUnload() to clean up as well, and these files are by convention saved in a file called zzz.R

Also---apart from the mention in 'Object names' that fullstops should be reserved for S3 objets---there is no explanaiton for the periods in names, especially names starting with them. Which is odd, since they are useful in package building.

S4 classes

Another side-effect that you do want to ensure S4 clases are defined in the right order, with methods and generics, so the R\ folder needs to be sourced in a specific order, which you do through the DESCRIPTION file as well, we'll see later.

Package metadata

The DESCRIPTION file is the defining feature of a package, if it's in the folder, R considers it a package. Minimal bare-bones is provided when you create it using devtools or Rstudio.

Dependencies

Imports:
    dplyr
Suggests:
    ggvis
    vcd

Comma separated lists of packages. Imports means the packages are necessary for your package to work. If not present, then devtools_load_all() will install them, however they will not be attached along with your package! Best practice is to use :: to refer to external fucntions, also makes it more readable.

Suggests means the packages are not required, they might be useful for example datasets to run tests, build vignettes etc.They will not be automatically installed, so if you want to use stuff from there you need to use requireNamespace(x, quetly - TRUE) to check if it is available before you try to use it:

# Option 1: exit if the package isn't available
my_fun <- function(a, b) {
  if (!requireNamespace("pkg", quietly = TRUE)) {
    stop("Package \"pkg\" needed for this function to work. Please install it.",
      call. = FALSE)
  }
}

# Use alternative if package isn't available
my_fun <- function(a, b) {
  if (requireNamespace("pkg", quietly = TRUE)) {
    pkg::f()
  } else {
    g()
  }
}

usethis::use_package("dplyr") to add a package dependency automatically the devtools:: version is deprecated. [^1]

[^1]: this issue here explains that the deprecation is a temp warning as the devtools package is on it's way to becoming a wrapper package, like tidyveres, so while these funcitons will live in usethis, they will automatically be loaded with devtools, so it won't change anything from the user's perspective.

Versioning

You should specify the version of the package required:

Imports:
    dplyr (>= 0.2),
    ggbis(>= 0.3.1.1)

Usually minimum rather than exact. "unless you know otherwise always require a version greater than or equal to the version you're currenlty using" Well, you could also try an older one, to be nice? But I guess that's not encouraging people to update their packages..

Other dependencies

Before namespaces were rolled out in R 2.14.0 you used Depends instead of Imports, which you should now use almost in all cases except when not---which will be covered in namespaces.

You can use Depends: R (>= 3.0.1) but not at all clear what he means by devtools::create() will do this for you. This seems to no longer be true.

Title and description: what does your package do?

Short and long versions of what your package does. But also add a README.md for a longer description

Author

Use:

person("Maja", "Zaloznik", email = "maja.zaloznik@gmail.com", 
  role = c("aut", "cre"))

Also might be useful to add URL: and BugReports: e.g. the github repo's issues.

Licence

Either the acronym, or write file LICENCE and then write sth in that file.

Open source licences to conside:

Version

Standard versioning major.minor.patch, while in development use 0.0.0.9000 to make that clear before it's released. if that's so, then why doesn't create() do that instead of 0.1.0.?

Object documentation

Is only helpful if you know what you're looking for.

Instead of manually writing .Rd files for each function, roxygen2 lets you write literate code with comments alongside the functions, which are then automatically converted to .Rd files. (also you use it for the collate field and the namespace, but more on that later)

the documentation workflow

So write roxygen comments in your source file, run devtools::document() to generate the .Rd files, preview the documentation with ?. But the previews created this way will not show any links between pages.For that use:

alternative documentation workflow

Add roxygen comments, click the build and reload button in the build pane or pres Ctrl+shift+B. This is a lot more thorough: it completley rebuilds the package, which also updates the documentation, and then installs it in your regular library, restarts R and reloads the package. This is now called install and restart

Roxygen comments

Are placed before the function they refer to, the blocks of text are broken up into @tags, The first three sections are implicit, so you don't need to add the tags:

You can use formatting e.g. \code{} and \link{}

Vignettes

What's the deal with the default outputs? OK, html_vingette as opposed to html_document is explained here to be due to its smaller size i.e. great for CRAN.



majazaloznik/pkgs.had documentation built on May 31, 2019, 2:26 p.m.