简体   繁体   中英

Grouping functions from an R package

Context

I am developing an R package which contains over a hundred page-long functions grouped into 10 different themes.

Desired behavior

I would like the user to be able to take such themes into consideration when calling functions.

For example, instead of calling foo() , the user would have to do either

load(theme1) # or whatever would be used to load a subgroup of functions
foo()

or something like

theme1$foo()

What I want to prevent the user from doing is directly loading the package and calling the function without taking the theme into consideration, ie library(package); foo() library(package); foo() .

What I have tried

I have used the modules package to accomplish the latter solution in a previous package , but this time around the published version of that package doesn't work very well due to how my functions are interdependent (I've opened a GitHub issue on the topic).

I also thought about coding my own solution, maybe something simple involving the creationg of a sublibrary() function that exports only a few functions at a time, but I didn't get anywhere with that.

Of course, I guess publishing 10 different packages would also technically work, but I think that's too clumsy a solution to consider.

Question

Apart from using modules, is there a way to implement either of the functionalities above?

Object oriented programming could be used here where theme1 is a class or an object instantiated from the class and the functions associated with it are the methods. There are a number of alternatives here including R reference classes (more info via ?ReferenceClasses ), R6 package , proto package , the R.oo package and function scoping (more info via demo("scoping") .

For example using the proto package:

library(proto)

theme1 <- proto(
  foo = function(.) print("foo"),
  bar = function(.) print("bar")
)

theme1$foo()
## [1] "foo"
theme1$bar()
## [1] "bar"

If it is just a matter of grouping and if you don't need local storage or inheritance then we could even use a list:

theme1 <- list(foo = function() print("foo"),
               bar = function() print("bar"))

theme1$foo()
## [1] "foo"
theme1$bar()
## [1] "bar"

A number of other OO approaches could be used but they involve creating a class which is then used to create a single object (which is an extra step); however, they do support the $ syntax of the question.

Using R6 we have:

library(R6)

Theme1 = R6Class("theme1",
  public = list(
    foo = function() print("foo"),
    bar = function() print("bar")
  )
)

theme1 <- Theme1$new() # generate a Theme1 object

theme1$foo()
## [1] "foo"
theme1$bar()
## [1] "bar"

or using Reference Classes (no packages needed):

setRefClass(
  "Theme1",
  methods = list(
    foo = function() print("foo"),
    bar = function() print("bar")
  )
)

theme1 <- Theme1()  # generate Theme1 object

theme1$foo()
## [1] "foo"
theme1$bar()
## [1] "bar"

or using function scoping (no packages needed):

Theme1 <- function() list(
  foo = function() print("foo"),
  bar = function() print("bar")
)

theme1 <- Theme1()

theme1$foo()
## [1] "foo"
theme1$bar()
## [1] "bar"

Here's an idea of how you could achieve the sublibrary function. In this case we will use it to load a small subsection of ggplot2

sublibrary <- function(theme) {
  subgroups <- 
    list(basic   = list(ggplot = ggplot2::ggplot,
                        aes = ggplot2::aes,
                        geom_line = ggplot2::geom_line,
                        geom_point = ggplot2::geom_point),
        advanced = list(scale_color_manual = ggplot2::scale_color_manual,
                        theme = ggplot2::theme))
  
  attach(list2env(subgroups[[theme]]))
}

This means that without loading an entire package I could do:

sublibrary("basic")

ggplot(iris, aes(Sepal.Length, Petal.Length, color = Species)) +
  geom_point()

In reality, the subgroup object would be stored outside the function, in a list or environment within the package namespace.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM