没有包的命名空间 [英] Namespaces without packages
问题描述
在重新组织代码库时,我想清理代码共享机制.到目前为止,我将source
用于许多小型的,功能齐全的功能模块.
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
- 缺乏圆度测试(偶然的圆形
source
链),
正确指定包含路径( - 复杂语法,
- 潜在的名称冲突(重新定义对象时).
chdir=TRUE
参数,硬编码路径)所需的- 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).
理想情况下,我想对Python模块机制有所帮助. R包机制在这里可能会过大:我不是想要生成嵌套的路径层次结构,包含大量元数据的多个文件并手动构建包只是为了获得一个小的,独立的可重用代码模块.
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)
…,并且将模块定义为驻留在本地路径中的简单源文件. import
的定义很简单,但我无法解决第三点:我想导入模块进入一个单独的命名空间,但从我的观察来看,命名空间查找机制非常牢固地连接到包.没错,我可以覆盖`::`
或getExportedValue
以及asNamespace
和isNamespace
,但这听起来很脏,并且有可能破坏其他软件包.
… 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.
推荐答案
这是一个完全自动化程序包创建,编译和重新加载的功能.正如其他人指出的那样,实用程序功能package.skeleton()
和devtools::load_all()
已经使您几乎一直存在.这只是结合了它们的功能,使用package.skeleton()
在临时目录中创建源目录,当load_all()
处理完该目录时,该目录将被清除.
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.
您需要做的只是指向要从中读取函数的源文件,并为程序包命名:import()
为您完成其余的工作.
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."
这篇关于没有包的命名空间的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!