【问题标题】:Automatically generate R source code to build a package自动生成R源码构建包
【发布时间】:2015-11-25 22:44:04
【问题描述】:

我编写了与 API 的绑定并将所有内容放入 R 包中,包括测试、插图等,但 API 不断变化。这带来了一些问题

  • 更新我的包很容易出错,也许我错过了一个新功能或忘记将旧功能标记为已弃用
  • 将包提交给 CRAN 不是一个好主意,因为它经常更改并且包是人工审核的
  • 我很难让这个软件保持更新,因为 API 机会不定期,因此我可能会错过它们

我想出了自动生成绑定的想法。 API 本身通过在线 JSON 文档提供了所需的一切。这些文档不断反映 API 的当前定义。

编写一些将 JSON 文档转换为 R 函数的代码不是问题。但如果我这样做,我仍然需要更新 CRAN 上的包。最好的解决方案是创建一个包(在加载时)查找 API 定义并创建所需的函数。理想情况下,这些函数应该进行单元测试。

感谢您对此的任何提示。

最好的

编辑:API 是 firebrowse APIan example 的输入。

【问题讨论】:

  • 如果不知道您正在谈论的 API,可能很难给出有用的答案。
  • 我发现了一些有用的提示:stackoverflow.com/questions/16985417/…
  • 我从 Swagger 规范生成一个 R 包的包的粗略开始。拥有一个充满活力的一代并不难(一旦完成)。我暂时没有时间投入到 pkg 上。

标签: json r cran


【解决方案1】:

这确实具有挑战性,因此没有明显的方法可以做到这一点。 wsdl 背后的整个想法是能够使用标准化的 XML 描述轻松地做到这一点。这从未在 R 中真正实现过,也从未真正得到更广泛的应用(因为 RESTful 服务和 JSON 的出现)。

您绝对可以通过创建所谓的“函数工厂”来动态生成函数(Hadley 讨论了一些here)。简而言之,您编写一个以 JSON 作为输入的函数,并返回一个执行 JSON 中描述的任何操作的函数。 (创建这样一个在加载包时动态执行此操作的工厂似乎有风险,但我认为这是可能的。我可能只是将工厂留给自己并使用它来创建和更新包。)

我不会尝试专门处理您的 API,而是看看它是如何工作的:

# create factory with arguments to control returned function
factory <- function(action, endpoint, content = TRUE, parsed = FALSE) {
    if (content) {
        if(parsed) {
            out <- function() httr::content(httr::VERB(action, endpoint))
        } else {
            out <- function() httr::content(httr::VERB(action, endpoint), "text")
        } 
    } else {
            out <- function() httr::VERB(action, endpoint)
    }
    return(out)
}

# use factory to create different functions
(a <- factory("GET", "http://example.com", content = TRUE, parsed = FALSE))
## function() httr::content(httr::VERB(action, endpoint), "text")

(b <- factory("GET", "http://example.com", content = TRUE, parsed = TRUE))
## function() httr::content(httr::VERB(action, endpoint))

(c <- factory("GET", "http://example.com", content = FALSE))
function() httr::VERB(action, endpoint)

# evaluate each function
a() # returns a character string
b() # returns parsed HTML
c() # returns an httr response object

【讨论】:

  • 您好 Thomas,非常感谢您分享您的想法。我以前不知道 httr 包,它可能会派上用场。但这并不能解决我的问题。你真的把它钉在了“我可能只是把工厂留给自己,并用它来创建和更新包”。这是我要避免的部分。 API 经常变化,包应该独立于 hat 工作。
  • @mariodeng 我并不是说这是不可能的,所以您绝对可以将工厂放入一个包中,在onLoad 期间调用它并将生成的函数分配到包命名空间中。这似乎应该是可能的,但我认为这将具有挑战性(部分原因是用户需要互联网访问,无法导出尚不存在的功能等)。
  • 没错,我也是这么想的。另外我想使用单元测试并生成适当的文档。嗯,我想我会坚持自己生成包。不完美,但仍有改进:) 谢谢
【解决方案2】:

最好的解决方案是创建一个包(在加载时)查找 API 定义并创建所需的函数。理想情况下,这些函数应该进行单元测试。

这是一个众所周知的问题。在不中断客户端的情况下对服务器更改做出反应不仅是您的情况,而且对于移动应用程序(每次 API 更改时都需要重新提交)也是一种痛苦。

虽然您的方法可能奏效(动态生成客户端),但如果服务器可以协作以达成成就,则可以达到最佳结果。

您必须将客户端与 API 实现分离。如何?使用 REST(实际上),引入了状态和转换的概念。

这里不适合解释它是如何工作的,但是可以在这个great presentation by Glenn Block 中找到一个很好的介绍,然后继续阅读。

这不会解决您的特定问题,但在我看来,这是解决问题的正确方法。

您可能想看看this video as well,15:24 部分。

【讨论】:

    猜你喜欢
    • 2017-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-17
    • 2016-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多