我有同一个包的多个版本foo(全部具有一个函数bar),我都想在同一个脚本中使用它们。
在这个问题之后,我可以v1使用 加载包library("foo", lib.loc = "pkgs/v1")。但这会加载包中的所有函数。
现在我想foo::bar从版本 v1 分配到版本v2bar_v1到foo::bar版本 v2 来bar_v2独立调用它们。但我没有看到在给定 lib 位置的情况下仅加载库的一个函数的选项(例如,解决方案是lib.loc在函数调用中指定 a bar_v1 <- foo::bar)。
这在 R 中可能吗?
我在这里创建了一个测试包github.com/DavZim/testPkgfoo ,它有一个打印包版本(硬编码)的函数。该软件包有两个版本,每个版本一个。
要获取包的 tar.gz 文件,您可以使用此
# Download Files from https://github.com/DavZim/testPkg
download.file("https://github.com/DavZim/testPkg/releases/download/v0.1.0/testPkg_0.1.0.tar.gz", "testPkg_0.1.0.tar.gz")
download.file("https://github.com/DavZim/testPkg/releases/download/v0.2.0/testPkg_0.2.0.tar.gz", "testPkg_0.2.0.tar.gz")
Run Code Online (Sandbox Code Playgroud)
然后以以下形式设置文件夹结构
pkgs/
0.1.0/
testPkg/
0.2.0/
testPkg/
Run Code Online (Sandbox Code Playgroud)
我用
if (dir.exists("pkgs")) unlink("pkgs", recursive = TRUE)
dir.create("pkgs")
dir.create("pkgs/0.1.0")
dir.create("pkgs/0.2.0")
# install the packages locally
install.packages("testPkg_0.1.0.tar.gz", lib = "pkgs/0.1.0", repos = NULL)
install.packages("testPkg_0.2.0.tar.gz", lib = "pkgs/0.2.0", repos = NULL)
Run Code Online (Sandbox Code Playgroud)
现在的问题是我该写什么myscript.R?
理想情况下我会有这样的东西
bar_v1 <- some_function(package = "testPkg", function = "foo", lib.loc = "pkgs/0.1.0")
bar_v2 <- some_function(package = "testPkg", function = "foo", lib.loc = "pkgs/0.2.0")
bar_v1() # calling testPkg::foo from lib.loc pkgs/0.1.0
#> [1] "Hello World from Version 0.1.0"
bar_v2() # calling testPkg::foo from lib.loc pkgs/0.2.0
#> [1] "Hello World from Version 0.2.0"
Run Code Online (Sandbox Code Playgroud)
玩弄它,我想这样的东西可能会起作用。但它并不...
lb <- .libPaths()
.libPaths("pkgs/0.1.0")
v1 <- testPkg::foo
v1()
#> [1] "Hello from 0.1.0"
.libPaths("pkgs/0.2.0")
v2 <- testPkg::foo
v2()
#> [1] "Hello from 0.1.0"
.libPaths(lb)
v1()
#> [1] "Hello from 0.1.0"
v2()
#> [1] "Hello from 0.1.0" #! This should be 0.2.0!
Run Code Online (Sandbox Code Playgroud)
有趣的是,如果我交换版本以先加载 0.2.0,然后加载 0.1.0,我会得到这个
lb <- .libPaths()
.libPaths("pkgs/0.2.0")
v1 <- testPkg::foo
v1()
#> [1] "Hello from 0.2.0"
.libPaths("pkgs/0.1.0")
v2 <- testPkg::foo
v2()
#> [1] "Hello from 0.2.0"
.libPaths(lb)
v1()
#> [1] "Hello from 0.2.0"
v2()
#> [1] "Hello from 0.2.0"
Run Code Online (Sandbox Code Playgroud)
1)连续加载假设当前目录下有testPkg的源码包,分别命名为testPkg_0.1.0.tar.gz和testPkg_0.2.0.tar.gz。现在创建 pkgs、pkgs/0.1.0 和 pkgs/0.2.0 目录作为发布库,然后将这些源包安装到这些库中。
foo现在假设每个包都有一个不依赖于包中其他对象的函数,依次加载每个包,重命名foo,并分离/卸载包。现在,两者都可以用新名称进行访问。
dir.create("pkgs")
dir.create("pkgs/0.1.0")
dir.create("pkgs/0.2.0")
install.packages("testPkg_0.1.0.tar.gz", "pkgs/0.1.0", NULL)
install.packages("testPkg_0.2.0.tar.gz", "pkgs/0.2.0", NULL)
library("testPkg", lib.loc = "pkgs/0.1.0")
fooA <- foo
detach(unload = TRUE)
library("testPkg", lib.loc = "pkgs/0.2.0")
fooB <- foo
detach(unload = TRUE)
fooA
fooB
Run Code Online (Sandbox Code Playgroud)
2) 更改包名称另一种方法是正常安装一个版本,然后为另一个版本下载其源代码,在描述文件中更改其名称,然后以新名称安装。那么两者都可以使用。
假设 testPkg_0.1.0.tar.gz 和 testPkg_0.2.0.tar.gz源码包都具有功能foo,并且这两个 tar.gz 文件位于当前目录中,我们可以按如下方式完成此操作。请注意,更改器会将描述文件更改为使用名称 testPkgTest 并将源包的目录名称更改为相同。
library(changer)
install.packages("testPkg_0.1.0.tar.gz", repos = NULL)
untar("testPkg_0.2.0.tar.gz")
changer("testPkg", "testPkgTest")
install.packages("testPkgTest", type = "source", repos = NULL)
testPkg::foo()
## [1] "Hello World from Version 0.1.0"
testPkgTest::foo()
## [1] "Hello World from Version 0.2.0"
Run Code Online (Sandbox Code Playgroud)
3) import下面我们建议导入包,但不幸的是,正如评论中指出的那样,下面使用这个包的代码实际上不起作用,并且导入了同一个包两次。我在 import github 站点上创建了一个问题。 https://github.com/rticulate/import/issues/74
假设当前目录中有源包 mypkg_0.2.4.tar.gz 和 mypkg_0.2.5.tar.gz,并且每个源包都有一个函数myfun。然后这将为每个库创建一个库,将它们安装到各自的库中并myfun从每个库中导入。它们将位于搜索路径上的 A 和 B 中。
注意导入包应该安装但不加载,即不library(import)
应该使用任何语句。您可能希望阅读导入包的文档,因为可能存在变化。
# use development version of import -- the CRAN version (1.3.0) has
# a bug in the .library= argument
devtools::install_github("rticulate/import")
dir.create("mypkglib")
dir.create("mypkglib/v0.2.4")
dir.create("mypkglib/v0.2.5")
install.packages("mypkg_0.2.4.tar.gz", "mypkglib/v0.2.4", NULL)
install.packages("mypkg_0.2.5.tar.gz", "mypkglib/v0.2.5", NULL)
import::from("mypkg", .library = "mypkglib/v0.2.4", .into = "A", myfun)
import::from("mypkg", .library = "mypkglib/v0.2.5", .into = "B", myfun)
search()
ls("A")
ls("B")
get("myfun", "A")
get("myfun", "B")
Run Code Online (Sandbox Code Playgroud)
另一种可能性是将它们都放入具有不同名称的导入(默认使用)中
import::from("mypkg", .library = "mypkglib/v0.2.4", myfunA = myfun)
import::from("mypkg", .library = "mypkglib/v0.2.5", myfunB = myfun)
search()
ls("imports")
myfunA
myfunB
Run Code Online (Sandbox Code Playgroud)