Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

In reorganising my code base I’d like to clean up my code sharing mechanism. So far I’m using source for lots of small, largely self-contained modules of functionality.

However, this approach suffers from a number of problems, among them

  • the lack of tests for circularity (accidental circular source chains),
  • complex syntax required to properly specify include paths (chdir=TRUE argument, hard-coded paths),
  • potential of name clashes (when redefining objects).

Ideally I’d like to get something alike to the Python module mechanism. The R package mechanism would be overkill here:?I do not want to generate nested path hierarchies, multiple files with tons of metadata and manually build the package just to get a small, self-contained, reusable code module.

For now I’m using a code snippet which allows me to solve the first two problems mentioned above. The syntax for inclusion is like this:

import(functional)
import(io)
import(strings)

… and a module is defined as a simple source file which resides in the local path. The definition of import is straightforward but I cannot solve the third point: I want to import the module into a separate namespace but from what I see the namespace lookup mechanism is pretty hard-wired to packages. True, I could override `::` or getExportedValue and maybe asNamespace and isNamespace but that feels very dirty and has the potential of breaking other packages.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
329 views
Welcome To Ask or Share your Answers For Others

1 Answer

Here's a function that completely automates package creation, compilation, and reloading. As others have noted, the utility functions package.skeleton() and devtools::load_all() already get you almost all the way there. This just combines their functionality, using package.skeleton() to create the source directory in a temp directory that gets cleaned up when load_all() is done processing it.

All you need to do is point to the source files from which you want to read in functions, and give the package a name: import() does the rest for you.

import <- function(srcFiles, pkgName) {
    require(devtools)
    dd <- tempdir()
    on.exit(unlink(file.path(dd, pkgName), recursive=TRUE))
    package.skeleton(name=pkgName, path = dd, code_files=srcFiles)
    load_all(file.path(dd, pkgName))
}

## Create a couple of example source files
cat("bar <- function() {print('Hello World')}", file="bar.R")
cat("baz <- function() {print('Goodbye, cruel world.')}", file="baz.R")

## Try it out
import(srcFiles=c("bar.R", "baz.R"), pkgName="foo")

## Check that it worked
head(search())
# [1] ".GlobalEnv"        "package:foo"       "package:devtools"
# [4] "package:stats"     "package:graphics"  "package:grDevices"
bar()
# [1] "Hello World"
foo::baz()
# [1] "Goodbye, cruel world."

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...