如何创建命名空间并将函数导出到其中?

时间:2017-12-22 12:18:17

标签: r

有没有办法声明命名空间并将函数导出到其中,以便可以使用::访问它,而无需创建整个包?

以下适用于:::但不适用::

ns <- namespace::makeNamespace("my_namespace")
assign("test",7, env=ns)
my_namespace:::test # Triple colon - works.
# [1] 7
my_namespace::test # Double colon - doesn't work.
# Error: 'test' is not an exported object from 'namespace:my_namespace'

是否有替代assign会使最后一行有效? (目标是能够在开发包时模拟包,因此其他文件可以使用它,就好像它是一个完整的包,但可以使用source而不是devtools::install快速重新加载。)< / p>

3 个答案:

答案 0 :(得分:3)

base::namespaceExport(ns, ls(ns))似乎有用(当然你也可以使用子集作为第二个参数中要导出的对象列表)。一旦定义了要导出的命名空间中的所有对象,就使用它:

ns <- namespace::makeNamespace("my_namespace")
assign("test", 7, env = ns)
base::namespaceExport(ns, ls(ns))

my_namespace::test

输出:

7

答案 1 :(得分:1)

您可能会发现以下内容对于加快软件包开发的预期用例非常有用:

http://stat.ethz.ch/R-manual/R-patched/library/utils/html/getFromNamespace.html

  

说明

     

实用程序用于访问和替换命名空间中的非导出函数,以用于开发具有命名空间的包。

答案 2 :(得分:1)

我有相同的用例,并设计了这个:

#' simulate a package
#'
#' simulate loading a namespace or attaching a package. designed to make reprexes easy. The input function's closer env is set to
#' the namespace and no fancy feature such as registering S3 methods is supported
#'
#' @param name string, name of fake package
#' @param exported named list of exported functions
#' @param unexported named list of unexported functions
#' @param attach whether to attach the fake package
#'
#' @noRd
fake_package <- function(name, exported = NULL, unexported = NULL, attach = TRUE) {
  # fetch and eval call to create `makeNamespace`
  eval(body(loadNamespace)[[c(8, 4, 4)]])
  # create an empty namespace
  ns <- makeNamespace(name)
  # makethis namespace the closure env of our input functions
  exported <- lapply(exported, `environment<-`, ns)
  unexported <- lapply(unexported, `environment<-`, ns)
  # place these in the namespace
  list2env(exported, ns)
  list2env(unexported, ns)
  # export relevant functions
  namespaceExport(ns, names(exported))
  if(attach) {
    # copy exported funs to "package:pkg" envir of the search path
    attach(exported, name = paste0("package:", name))
  }
  invisible()
}

以下是它的使用方法(这里我们将 attach 保留为默认的 TRUE,因此我们在搜索路径上创建了一个 "package:fake" 环境):

fake_package(
  "fake",
  exported = list(add_2 = function(x) add_1(x) + 1),
  unexported = list(add_1 = function(x) x + 1))

# the search path looks as it would after a library call
search()
#>  [1] ".GlobalEnv"        "package:fake"      "package:stats"    
#>  [4] "package:graphics"  "package:grDevices" "package:utils"    
#>  [7] "package:datasets"  "package:methods"   "Autoloads"        
#> [10] "tools:callr"       "package:base"

# add_2 was exported
add_2
#> function(x) add_1(x) + 1
#> <environment: namespace:fake>

fake::add_2
#> function(x) add_1(x) + 1
#> <environment: namespace:fake>

fake:::add_2
#> function(x) add_1(x) + 1
#> <environment: namespace:fake>

# add_1 was not, so as expected can't be found
add_1
#> Error: object 'add_1' not found

fake::add_1
#> Error: 'add_1' is not an exported object from 'namespace:fake'

fake:::add_1
#> function(x) x + 1
#> <environment: namespace:fake>

# let's try it
add_2(3)
#> [1] 5

解决方案是 100% 基础 R,eval(body(loadNamespace)[[c(8, 4, 4)]]) 调用不是很优雅,如果代码更改可能会中断,您可以将其删除并用 ns <- namespace::makeNamespace(name) 替换下一行(如果取决于 { namespace} 包没问题。