R包文件结构
为了提高代码复用性,开发人员可以将R代码和相应支撑文件按特定的文件组织结构存放并压缩成包,并提供给他人使用。下图展示R包最为常见的7个部分
其中R/
文件夹为提供功能的R代码存放的位置,其他语言编写的代码(例如使用Rcpp
编写的C++扩展)则需要存放在文件夹src/
中。data/
文件夹为R原生数据文件(.Rda
,.Rdata
)的存放位置,其中的文件会随R包载入,或者通过R函数data()
载入至当前环境。其它格式的数据文件(比如表格、图片)则需要存放在inst/extdata
文件夹中,R包安装后,可以通过R函数system.file("file_path_relate_to_package_root",package="package_name")
获取该文件的绝对路径,并可随后自行读取至当前环境。man/
用于存放帮助文档,帮助文档以.Rd
的格式给出,可以通过R包roxygen2
和devtools::document()
生成帮助文档,vignettes/
可以理解为更详尽更长的帮助文档,一般用于介绍R包的使用方法(而不是想man/
里面的函数帮助)。test/
用以存放用于测试R包提供的功能的R代码。DESCRIPTION
和NAMESPACE
是R包的配置文件,其中DECRIPTION
用于描述该包的信息,包括功能介绍、作者、依赖哪些包等等,NAMESPACE
用于定义R包与其它R包或者其他语言提供的模块(比如使用Rcpp生成的动态链接库)之间的交互。
这里补充博主对NAMESPACE
的理解,将R看成一个黑箱子的话,NAMESPACE
就是在这个黑箱子上打开两个洞,一个洞(A)连接其它的包,一个洞(B)连接到R包使用者,A的作用就是把其它包里的功能导入到这个黑箱子里面来,这种导入是在黑箱子里的功能定义运行之前进行的,所以之后定义的所有功能都可以使用已经导入的其它包的功能(而不需要用户在自己的环境里导入这些功能,因为黑箱子里面是有的),B的左右就是决定给用户提供哪些功能(有些功能是底层的,而不是面向用户的,是面向用户的功能的依赖,不需要提供给用户)。
开发环境及开发工具
原则上来说,开发者可以自行部署R代码及帮助文档至指定文件夹,并编写相应的R包配置文件。但这显然比较繁琐且枯燥。R
强大的社区中诞生了几个有些的开发者工具用于人性化R包开发流程,包括用于解析R/
中代码的注释生成文档到man/
的roxygen2
,以及广为人知且功能强大的devtools
。本博文基于以下环境:
R4.0.1
devtools2.3.1
roxygen27.1.1
usethis1.6.1
Rstudio==1.3.1056
项目初始化
所谓项目初始化就是新建一个按照R包文件结构组织文件的文件夹。usethis
提供函数用于R包项目初始化如下:
usethis::create_package("./mypkg")
稍等片刻即可在当前文件夹得到初始化完成的R包项目,默认为一个Rstudio项目。
R代码编写或部署
如果R文件已经提前编写完成,则需要复制到项目文件夹中R/
文件夹中,注意R代码中不应有library()
之类与环境交互的函数,因为每个R包都有自己单独的一个环境,且与其它环境的交互需要在NAMESPACE
中完成。作为例子在R/
文件夹添加文件myfun.R
,并在其中编写函数如下:
#' This is function for demo
#'
#' @description The description of function
#' @usage myfun(a,b)
#' @param a a
#' @param b b
#' @return The sum of a and b
#' @examples
#'
#' myfun(1,2)
#' @export
mufun <- function(a,b){
return(a+b)
}
其中注释部分由roxygen2
可解析的特殊格式写成,主要分为函数文档及NAMESPACE
定义(@import,@export等)两类,详细说明于roxygen2文档
文档生成
在生成文档之前,在R/
中添加文件用以生成R包文档(非函数文档)如下:
usethis::use_package_doc()
随后调用函数在man/
文件夹中生成文档文件如下:
devtools::document()
数据部署
上文已经有数据文件部署的相关介绍,这里不做赘述
构建
通过devtools提供的函数构建R包如下,构建目标有两种选择(源文件压缩包、二进制文件包),区别在于可编译代码是否编译。build函数默认构建目标为源文件压缩包
devtools::build()
稍等片刻,如果没有错误即可得到构建完成的R包(.tar.gz)。并可以通过以下方式安装到R
install.packages("path_of_tar_gz",repos=NULL,type="source")
上传到CRAN
构建好的R包可以通过在线表单CRAN提交至CRAN。CRAN会进行可用性审核,对代码进行check(周期较长),因此为了节省时间,开发者最好在本地进行check如下:
devtools:check()
当check结果不再有error或warning时即可提交,方便起见,可以使用devtools提供的函数进行提交
devtools:submit_cran()
总结
这篇博文仅介绍了R包的一般文档结构以及开发工具辅助下的R包开发流程。实际开发过程中必定会遇到更多的需求(比如使用Rcpp编写C++扩展、编写测试并执行项目测试、编译文档为静态站点、管理NAMESPACE及DESCRIPTION)。博主建议读者在开发之前或开发时查阅roxygen2
,usethis
,testhat
等包的帮助,以及R官方文档Writing R Extensions了解更多信息。