By default, the goodpractice() function and its alias gp() run all the checks available in the package (use all_checks() to show all checks implemented). In addition, users can provide their own custom checks.

What’s happening inside of gp()?

The gp() function essentially carries out two types of steps:

  • First, it runs preparation steps for the checks, such as calculating test coverage or cyclomatic complexity.
  • Then it carrys out the checks, e.g., if cyclomatic complexity exceeds a threshold.

The results of the preparation steps and the checks are added to the return object, also referred to as the state. The print method accesses the check results and prints the advice for the failed checks - or praise if none fail.

Writing custom checks

Checks without corresponding preparation steps

Custom checks can be created with the make_check() function. As inputs it takes a short description of the check, the check itself, and the gp advice to be given in case the check fails. To illustrate this, let’s use a simplified version of the check on T and F instead of TRUE and FALSE.

The check argument is a function which takes the state as the input and carries out the check, returning TRUE if the check was successful. The state includes the path to the source code of the package and the checkTnF() function of the tools package can be used to check if T or F was used.

Additional checks can be used in gp() via the extra_checks argument. This should be a named list of check objects as returned by the make_check() function. All checks to be carried out, readless of whether they are provided by the goodpractice package or custom checks, must be named in the checks argument to gp().

The check on T/F implemented in the package gives more helpful advice than this simpified version and returns which files contain T and F so let’s do a quick comparison and run both versions:

Including a preparation step

Including a preparation step is optional but can be helpful if several checks require the same prepartions upfront. In the following example we check for two different fields to be present in the DESCRIPTION file, the URL field and the BugReports field. Both checks can be carried out easily building on a preparation step with the desc package for handling DESCRIPTION files.

The checks are linked to the preparation via the prep name: it appears as the name argument to make_prep(), as the preps argument to make_check() and finally as the name in the list for the extra_preps argument to gp().

More examples for using custom checks can be found in the rOpenSci unconf 2017 project checkers for automated checking of best practices for research compendia.