Skip to contents

Besides helping to detect a built-in list of bad patterns in R code, flir can also be used to refactor code, for instance by replacing the use of deprecated or superseded functions. If you work on a project that uses dplyr, you could for instance write your own rules to replace the use of sample_n() by slice_sample() (as described in this blog post).

However, that puts the burden of writing such rules on the end user, who is not necessarily familiar with all the changes in the package they use. Therefore, flir provides a way for package developers to define their own rules in the package so that anyone who uses it will also have access to the same set of rules.

Let’s take an example with one of my packages: tidypolars.

State of the package

At the time of writing, tidypolars (0.13.0) contains several deprecated functions, such as describe() and describe_plan(). Those functions should be replaced by summary() and explain(optimized = FALSE) respectively.

For package developers

On the side of package developers (in this example, this is only me), we can define some rules for tidypolars and store them in inst/flir/rules1.

First, I define a rule to detect the use of describe() and replace it with summary():

id: deprecated-describe
language: r
severity: warning
rule:
  pattern: describe($$$ARGS)
fix: summary(~~ARGS~~)
message: In tidypolars, `describe()` is deprecated. Use `summary()` instead.

Keep in mind that flir works mainly by using code patterns, it doesn’t have information on the R environment. Therefore, the rule above doesn’t know which package provides the function and it would also replace describe() calls coming from other packages.

I do the same with describe_plan():

id: deprecated-describe_plan
language: r
severity: warning
rule:
  pattern: describe_plan($ARG)
fix: explain(~~ARG~~, optimized = FALSE)
message: In tidypolars, `describe_plan()` is deprecated. Use `explain(optimized = FALSE)` instead.

This is all that is needed from package developers. When users will install the package, they will have access to those rules.

Note: it is good practice to have a single name for a family of rules and to use this name as filename. For instance, the first rule has id: deprecated-describe, so I should name the file deprecated-describe.yml. If you want to store several rules related to this deprecation, you could name the other rules deprecated-describe_2, deprecated-describe_3, etc. and store them in the same file, separated by ---.

Overall, the only changes I had to do in tidypolars are:

inst
└── flir
    └── rules
        ├── deprecated-describe.yml
        └── deprecated-describe_plan.yml

For users

To use rules defined in other packages, you need to set up a flir folder with setup_flir(). This will create the file flir/config.yml that we will modify to get rules from other packages.

Once this is done, you can add a field from-package and list the packages from which you want to import the rules. For instance, to benefit from the rules defined above, we can do:

from-package:
  - tidypolars

and that’s it! From now on, all calls to lint_*() or fix_*() on the project will also use the rules stored in tidypolars. Note that those rules are bundled with the package, meaning that if the package developers change or remove some rules and you update the package, the rules you will have access to will be different.

As before, you can also list rules to exclude in the exclude field of flir/config.yml but you will need to prefix them with from-<pkgname>-. For instance, to ignore the rule about the deprecation of describe(), you can set:

exclude:
  - from-tidypolars-deprecated-describe