【问题标题】:Downloading new data from internet when package is loaded every time每次加载包时从互联网下载新数据
【发布时间】:2019-02-07 19:03:18
【问题描述】:

我有一个包,它从互联网上抓取数据并根据函数调用显示其内容。但最近我从 CRAN 收到一条消息,当安装二进制构建时数据变得陈旧(因为该功能在 utils.R 中提到并且它在构建时已下载)。

在过去的几天里,我尝试了以下但没有成功:

  • 使用<<- 的全局变量,但它会生成一个 CRAN 注释,我还查看了一些建议不要使用该方法的答案 注:no visible binding for global variable
  • 创建一个新环境,然后在其中添加这个下载的对象,但由于我无法在其他功能中访问该对象,因此它从未成功。参考:Where to create package environment variables?

这是当前的包文件:https://github.com/amrrs/tiobeindexr/tree/master/R

尝试过的解决方案:

zzz.r文件:

.onLoad <- function (libname, pkgname)
{

  assign("newEnv", new.env(hash = TRUE, parent = parent.frame()))

  newEnv$.all_tablesx789  <- rvest::html_table(xml2::read_html('https://www.tiobe.com/tiobe-index/'))


}

核心代码中的功能之一。

hall_of_fame <- function() {

  #check_data()

  #.GlobalEnv$.all_tablesx789 <- check_data()

  newEnv$.all_tablesx789[[4]]

}

包构建良好,但找不到对象。以下错误:

Error in hall_of_fame() : object 'newEnv' not found

我只有几天的时间将我的包保存在 CRAN 上,我希望我已经提供了足够的数据来保存这个正在下载的问题。

谢谢!

【问题讨论】:

  • 在你的包中创建一个环境。具有下载数据并将其写入该环境的功能。然后在 .onLoad 中调用该函数。
  • @Thomas 感谢您的评论。它帮助我使用 hrbrmstr 的逻辑来解决问题。
  • 请不要这样做。加载包的能力不应依赖于互联网连接和特定站点的启动。它应该只在用户请求时才更新。我会推荐一个 update_mypkg_data() 函数,其中可能包含一个包启动消息,建议用户运行它。
  • @Hugh 但是包本身只有在连接到互联网时才能运行,否则在早期的情况下,用户获得的数据不是正确的/新的

标签: r r-package


【解决方案1】:

考虑将memoise 添加为依赖项,这样您就可以使用最少的依赖项链免费获得会话缓存,然后使用包环境和(只是为了好玩)活动绑定。

创建新的 ? 环境(你可以将其粘贴在,例如,aaa.R):

.pkgenv <- new.env(parent=emptyenv())

现在,(比如说,在zzz.R)设置一个抓取表格的函数:

.get_tiboe_tables <- function(url) {
  message("Delete this since it's just to show caching works") # delete this
  content <- xml2::read_html(url)
  rvest::html_table(content)
}

然后“记忆”它(再次,在zzz.R):

get_tiboe_tables <- memoise::memoise(.get_tiboe_tables)

现在,创建一个活动绑定,它可以让我们像访问变量一样访问表(即没有())。它比必要的更“有趣”(再次,在zzz.R):

makeActiveBinding(
  sym = "all_tables",
  fun = function() get_tiboe_tables('https://www.tiobe.com/tiobe-index/'),
  env = .pkgenv
)

现在,获取这样的值(请注意,当它“启动”缓存时,我们会收到“加载”消息:

str(.pkgenv$all_tables, 1)
## Delete this since it's just to show caching works ** the loading msg
## List of 4
##  $ :'data.frame':    20 obs. of  6 variables:
##  $ :'data.frame':    30 obs. of  3 variables:
##  $ :'data.frame':    15 obs. of  8 variables:
##  $ :'data.frame':    15 obs. of  2 variables:

在后续调用中没有加载消息,因为它正在检索缓存值:

str(.pkgenv$all_tables, 1)
## List of 4
##  $ :'data.frame':    20 obs. of  6 variables:
##  $ :'data.frame':    30 obs. of  3 variables:
##  $ :'data.frame':    15 obs. of  8 variables:
##  $ :'data.frame':    15 obs. of  2 variables:

在下一个 R 会话中,它将刷新表格。这样,在不滥用网站的情况下就有新数据。您也可以使用文件排序而不是排序名称黑客。

请注意,您也可以导出活动绑定,然后您的 ? 用户可以像变量一样使用它,而不是像函数一样调用它。

【讨论】:

  • 感谢先生的精彩回复。虽然我仍在尝试理解代码,但您能否告诉我如何在每个会话中刷新表格?因为当我在新会话中加载函数时message("Delete this since it's just to show caching works") 没有被打印出来
  • 您将什么定义为新会话? rud.is/dl/tiboe-so-ss.png
  • 我尝试在 Rstudio 中重新启动我的 R 会话并重新加载了包。
【解决方案2】:

其实我采取了与上面answer略有不同的方法。这参考了 Thomas 的 comment,原因是我不想将 memoise 添加为依赖项并尝试了替代方法。

aaa.R中创建一个新包:

.pkgenv &lt;- new.env(parent=emptyenv())

zzz.R中使用.onAttach()将数据加载到环境中的表中

.onAttach <- function(libname, pkgname) {

  packageStartupMessage("Downloading TIOBE Index Data using your Internet...")

  tryCatch({
    .pkgenv$.get_tiboe_tables <- rvest::html_table(xml2::read_html("https://www.tiobe.com/tiobe-index/"))
  },
  error = function(e){
    packageStartupMessage("Downloading TIOBE Index data failed!")
    packageStartupMessage("Error Message:")
    packageStartupMessage(e)
    return(NA)
  })

}

我之前的错误似乎是我试图在.onLoad() 内部创建新环境。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-07
    相关资源
    最近更新 更多