小标题:Vignettes的普及
对于日常使用R语言的用户,以下几点需要注意:
- 在CRAN软件包页面上可以找到vignettes(如果作者有这个功能,则说明软件包质量很高!)
- 添加到软件包二进制文件中,并通过
browseVignettes(package = "pkgname")
在vignette帮助部分中显示出来 [正如你所指出的]
- 嵌入到R软件包源代码中
- 可以将vignette中的嵌入式代码作为单独的脚本演示在
/demos
中使用demo()
- 最重要的一点:用户根本不知道vignettes是什么。
因此,如果您在软件包文档上花费了相当多的时间,那么您可能至少应该在启动时指出存在这样一个功能。
利用.onAttach()
中的packageStartupMessage()
使用户受益。
在软件包加载时,控制台相对清晰,用户一定会看到红色文本,因为通常情况下普通的蓝色R文本与它形成了较高的对比度(假设没有使用crayon)。但是,在某些情况下,向用户提醒vignettes的存在并没有意义。
- 如果会话是非交互式的(例如bash脚本)。
- 如果用户是R专家
- 如果用户已经长时间使用您的软件包,导致用户忽略消息。
因此,不良实现的packageStartupMessage()
会产生负面影响。
因此,我建议在以下四种不同情况下引入启动消息。
- (所有情况) 通过查询
interactive()
来查看是否有人类参与。如果有,则继续:
- (标准情况) 准备至少3个不同的启动消息列表,并每次随机选择一个进行显示;
- (正常情况) 随机生成一个数字以确定是否应该显示启动消息;
- (专家情况) 统计软件包加载次数,在
x
次软件包加载后,停止启动消息,直到用户重新安装该软件包。
接下来,我将介绍两种解决方案,它们遵循(1)-(3)的原则,以及仅使用(1)和(4)的简单解决方案。
随机选择软件包提示
在此版本中,我们仅寻求检查人类是否存在,提供一个跳过添加软件包加载消息的方法,并随机选择一个提示来显示。除了base
作用域之外,只需要一个依赖项,即stats::runif
命令,以生成介于[0,1]之间的概率。
.onAttach <- function(...) {
if (!interactive() || stats::runif(1) > 0.5){
return()
}
pkg_hints = c(
"Check for updates and report bugs at https://cran.r-project.org/web/packages/pkgname/.",
"Use `suppressPackageStartupMessages()` to remove package startup messages.",
"To see the user guides use `browseVignettes('pkgname')`"
)
startup_hint = sample(pkg_hints, 1)
packageStartupMessage(paste(strwrap(startup_hint), collapse = "\n"))
}
计算包的加载次数
为了使用一个计数器,我们利用保存到包的安装目录而不是"工作"目录/用户空间的能力。这样有一些与之相关的问题,我会简要提一下:
- 用户可能只有查看而不是修改
system
库的权限(用户库可以)。
- 因此,他们将始终根据此方法收到软件包提示,因为他们无法增加计数器。
- 如果软件包在
system
库中,则可能共享计数器。
- 错误日志可能会增加。
当然,您可以通过R_USER
或 HOME
环境变量在用户空间内创建自己的文件夹来消除这些问题。(此处留给读者做练习,提示:使用Sys.getenv()
和dir.create()
。)
无论如何,这个函数的好处之一是,在以后的时间里,您可能会在包内包含一个"发送软件包使用统计信息"的函数。这将实际上给出一个相当准确的“电话回家”统计信息,而不是当前的RStudio CRAN镜像软件包下载信息。但我跑题了。
为了使此方法起作用,我们需要在最初提供给CRAN的软件包上做更多的准备工作。具体来说,我们可能应该通过以下方式预安装计数器:
setwd("package_dir")
if(!dir.exists("inst")){
dir.create("inst")
}
pkg_count = 0
save(pkg_count, file="inst/counter.rda")
现在,开始介绍.onAttach()
计数器的实现!
.onAttach <- function(...){
if (!interactive()) return()
path_count = system.file("counter.rda", package = "pkgname")
displayMsg = FALSE
a = tryCatch(load(path_count), error = function(e){"error"}, warning = function(e){"warning"})
count_error = a %in% c("error","warning")
if(!count_error){
if(pkg_count < 10){
pkg_count = pkg_count + 1
try(save(pkg_count, file = path_count), silent=TRUE)
displayMsg = T
}
}
if(displayMsg){
packageStartupMessage("use `browseVignettes('packagename')` to see vignettes")
}
}
最后一点想法
请记住,如果您有任何软件包依赖关系(例如DESCRIPTION
中的Depend:
),它们可能会有自己的启动消息,在您的软件包中编写的消息之前显示。
library(packagename)
加载时打印一些内容? - Anthony Damicodata.table
使用的包启动策略,详情请见https://github.com/Rdatatable/data.table/blob/d9cf539b0fda2197b3a1d3bd5a0b5180b036200f/R/onAttach.R - Anthony Damico