R 教程#
关于添加 lubridate 绑定的 R 教程#
在本教程中,我们将记录向 Arrow R 包添加绑定的贡献,遵循指南快速参考部分指定的步骤以及更详细的提交你的第一个 PR 的步骤部分。如果此处缺少某些信息,请导航至那里。
该绑定将添加到 R 包中的 `expression.R` 文件中。但如果您添加的绑定位于其他位置,也可以按照这些步骤操作。
本教程与提交你的第一个 PR 的步骤不同,因为我们将处理一个特定案例。本教程并非分步指南。
让我们开始吧!
设置#
让我们设置 Arrow 仓库。我们假设 Git 已经安装。否则,请参阅设置部分。
一旦Apache Arrow 仓库被 fork(参见Fork 仓库),我们将克隆它并将主仓库的链接添加到我们的上游。
$ git clone https://github.com/<your username>/arrow.git
$ cd arrow
$ git remote add upstream https://github.com/apache/arrow
构建 R 包#
构建 R 包的步骤因您使用的操作系统而异。因此,在本教程中,我们仅参考构建过程的说明。
问题#
在本教程中,我们将解决一个问题,即为 `mday()` 函数实现一个简单的绑定,该函数将与 `lubridate` 中现有的 R 函数匹配。
注意
如果您没有问题并且需要帮助找到一个问题,请参阅指南的寻找合适的入门问题 🔎部分。
选择一个问题并将其分配给自己后,您可以继续下一步。
在新分支上开始工作#
在我们开始添加绑定之前,我们应该从更新的主分支创建一个新分支。
$ git checkout main
$ git fetch upstream
$ git pull --ff-only upstream main
$ git checkout -b ARROW-14816
现在我们可以开始研究 R 函数和我们要公开或连接的 C++ Arrow 计算函数。
检查 lubridate mday() 函数
通过lubridate 文档,我们可以看到 `mday()` 接受一个日期对象并返回月份中的日期作为数字对象。
我们可以在 R 控制台中运行一些示例来帮助我们更好地理解该函数
> library(lubridate)
> mday(as.Date("2000-12-31"))
[1] 31
> mday(ymd(080306))
[1] 6
检查 Arrow C++ day() 函数
从计算函数文档中,我们可以看到 `day` 是一个一元函数,这意味着它接受单个数据输入。数据输入必须是 `Temporal class`,返回值是 `Integer/numeric` 类型。
`Temporal class` 指定为:日期类型(Date32、Date64)、时间类型(Time32、Time64)、时间戳、持续时间、间隔。
我们可以使用 `call_function` 从 R 控制台调用 Arrow C++ 函数,以了解其工作原理
> call_function("day", Scalar$create(lubridate::ymd("2000-12-31")))
Scalar
31
我们可以看到 lubridate 和 Arrow 函数对等效数据类型进行操作并返回等效数据类型。lubridate 的 `mday()` 函数没有额外的参数,并且也没有与 Arrow C++ 函数 `day()` 关联的选项类。
查看 `expressions.R` 中的代码,我们可以看到 day 函数已在 R 包端指定/映射:apache/arrow
我们只需要将 `mday()` 添加到表达式列表中,将其连接到 C++ `day` 函数即可。
# second is defined in dplyr-functions.R
# wday is defined in dplyr-functions.R
"mday" = "day",
"yday" = "day_of_year",
"year" = "year",
添加测试#
现在我们需要添加一个测试来检查一切是否正常。如果有其他选项或边缘情况,我们必须添加更多。查看类似函数(例如 `yday()` 或 `day()`)的测试,我们可以看到添加我们拥有的两个测试的好地方是 `test-dplyr-funcs-datetime.R`
test_that("extract mday from timestamp", {
compare_dplyr_binding(
.input %>%
mutate(x = mday(datetime)) %>%
collect(),
test_df
)
})
和
test_that("extract mday from date", {
compare_dplyr_binding(
.input %>%
mutate(x = mday(date)) %>%
collect(),
test_df
)
})
现在我们需要看看测试是否通过,或者我们需要做更多的研究和代码更正。 运行测试的最简单方法是在 shell 中运行以下命令
devtools::test(filter="datetime")
> devtools::test(filter="datetime")
ℹ Loading arrow
See arrow_info() for available features
ℹ Testing arrow
See arrow_info() for available features
✔ | F W S OK | Context
✖ | 1 230 | dplyr-funcs-datetime [1.4s]
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Failure (test-dplyr-funcs-datetime.R:187:3): strftime
``%>%`(...)` did not throw the expected error.
Backtrace:
1. testthat::expect_error(...) test-dplyr-funcs-datetime.R:187:2
2. testthat:::expect_condition_matching(...)
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
══ Results ═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
Duration: 1.4 s
[ FAIL 1 | WARN 0 | SKIP 0 | PASS 230 ]
我们看到 `strftime` 函数失败,但查看代码,我们发现它与我们的工作无关。我们可以继续前进,也许问问其他人他们在运行测试时是否也遇到了类似的失败。可能我们只需要重建库即可。
检查代码风格#
我们还应该运行 linters 以检查代码的样式是否遵循tidyverse style。为此,我们在 shell 中运行以下命令
$ make style
R -s -e 'setwd(".."); if (requireNamespace("styler")) styler::style_file(setdiff(system("git diff --name-only | grep r/.*R$", intern = TRUE), file.path("r", source("r/.styler_excludes.R")$value)))'
Loading required namespace: styler
Styling 2 files:
r/R/expression.R ✔
r/tests/testthat/test-dplyr-funcs-datetime.R ℹ
────────────────────────────────────────────
Status Count Legend
✔ 1 File unchanged.
ℹ 1 File changed.
✖ 0 Styling threw an error.
────────────────────────────────────────────
Please review the changes carefully!
创建拉取请求#
首先,让我们使用 `git status` 在 shell 中查看我们的更改,以查看哪些文件已更改,并仅提交我们正在处理的文件。
$ git status
On branch ARROW-14816
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: R/expression.R
modified: tests/testthat/test-dplyr-funcs-datetime.R
和 `git diff` 以查看文件中的更改,以便发现我们可能犯的任何错误。
$ git diff
diff --git a/r/R/expression.R b/r/R/expression.R
index 37fc21c25..0e71803ec 100644
--- a/r/R/expression.R
+++ b/r/R/expression.R
@@ -70,6 +70,7 @@
"quarter" = "quarter",
# second is defined in dplyr-functions.R
# wday is defined in dplyr-functions.R
+ "mday" = "day",
"yday" = "day_of_year",
"year" = "year",
diff --git a/r/tests/testthat/test-dplyr-funcs-datetime.R b/r/tests/testthat/test-dplyr-funcs-datetime.R
index 359a5403a..228eca56a 100644
--- a/r/tests/testthat/test-dplyr-funcs-datetime.R
+++ b/r/tests/testthat/test-dplyr-funcs-datetime.R
@@ -444,6 +444,15 @@ test_that("extract wday from timestamp", {
)
})
+test_that("extract mday from timestamp", {
+ compare_dplyr_binding(
+ .input %>%
+ mutate(x = mday(datetime)) %>%
+ collect(),
+ test_df
+ )
+})
+
test_that("extract yday from timestamp", {
compare_dplyr_binding(
.input %>%
@@ -626,6 +635,15 @@ test_that("extract wday from date", {
)
})
+test_that("extract mday from date", {
+ compare_dplyr_binding(
+ .input %>%
+ mutate(x = mday(date)) %>%
+ collect(),
+ test_df
+ )
+})
+
test_that("extract yday from date", {
compare_dplyr_binding(
.input %>%
一切看起来都OK。现在我们可以进行提交(将我们的更改保存到分支历史记录)
$ git commit -am "Adding a binding and a test for mday() lubridate"
[ARROW-14816 ed37d3a3b] Adding a binding and a test for mday() lubridate
2 files changed, 19 insertions(+)
我们可以使用 `git log` 来检查提交历史
$ git log
commit ed37d3a3b3eef76b696532f10562fea85f809fab (HEAD -> ARROW-14816)
Author: Alenka Frim <[email protected]>
Date: Fri Jan 21 09:15:31 2022 +0100
Adding a binding and a test for mday() lubridate
commit c5358787ee8f7b80f067292f49e5f032854041b9 (upstream/main, upstream/HEAD, main, ARROW-15346, ARROW-10643)
Author: Krisztián Szűcs <[email protected]>
Date: Thu Jan 20 09:45:59 2022 +0900
ARROW-15372: [C++][Gandiva] Gandiva now depends on boost/crc.hpp which is missing from the trimmed boost archive
See build error https://github.com/ursacomputing/crossbow/runs/4871392838?check_suite_focus=true#step:5:11762
Closes #12190 from kszucs/ARROW-15372
Authored-by: Krisztián Szűcs <[email protected]>
Signed-off-by: Sutou Kouhei <[email protected]>
如果我们前段时间启动了分支,我们可能需要变基到上游主分支,以确保没有合并冲突
$ git pull upstream main --rebase
现在我们可以将我们的工作推送到 GitHub 上名为 origin 的 forked Arrow 仓库。
$ git push origin ARROW-14816
Enumerating objects: 233, done.
Counting objects: 100% (233/233), done.
Delta compression using up to 8 threads
Compressing objects: 100% (130/130), done.
Writing objects: 100% (151/151), 35.78 KiB | 8.95 MiB/s, done.
Total 151 (delta 129), reused 33 (delta 20), pack-reused 0
remote: Resolving deltas: 100% (129/129), completed with 80 local objects.
remote:
remote: Create a pull request for 'ARROW-14816' on GitHub by visiting:
remote: https://github.com/AlenkaF/arrow/pull/new/ARROW-14816
remote:
To https://github.com/AlenkaF/arrow.git
* [new branch] ARROW-14816 -> ARROW-14816
现在我们必须转到GitHub 上的 Arrow 仓库来创建一个拉取请求。在 GitHub Arrow 页面(主页面或 forked 页面)上,我们将看到一个黄色通知栏,其中包含一条注释,说明我们最近对 ARROW-14816 分支进行了推送。太好了,现在我们可以通过单击 **Compare & pull request** 来创建拉取请求。

Apache Arrow 仓库上的通知栏。#
首先,我们需要将标题更改为 **ARROW-14816: [R] Implement bindings for lubridate::mday()**,以便使其与问题匹配。注意添加了一个标点符号!
补充说明:创建本教程时,我们一直在使用 Jira 问题跟踪器。由于我们目前正在使用 GitHub issues,因此标题将以 GH-14816: [R] Implement bindings for lubridate::mday() 开头.
我们还将添加一个描述,以便其他人清楚地了解我们正在尝试做什么。

编辑拉取请求的标题和描述。#
一旦我们点击 **创建拉取请求**,我们的代码就可以作为拉取请求在 Apache Arrow 存储库中进行审查。

这就是我们的拉取请求!#
拉取请求会连接到问题,并且 CI 正在运行。一段时间过后,我们收到审查意见,就可以更正代码、添加评论、解决对话等等。
另请参阅
有关拉取请求工作流程的更多信息,请参阅 拉取请求的生命周期。
我们创建的拉取请求可以 在此处 查看。