第一部分是入门内容
第1章 简介
其实是些环境准备和说明
# 安装所需包
install.packages(c('devtools','roxygen2','testthat','knitr'))
rstudioapi::isAvailable()
library(devtools)
install.packages("rlang")
remove.packages('rlang')
has_devel()
第2章 包的结构
一些包的内容和约定,主要是创建一个项目的步骤。一个好名字,尽量不要大小写同时用。
文件|新项目--新的目录--R Package--填写包名。
Rstudio是个好工具,F2跳转到函数的定义, Ctrl+.通过名字来查找函数。Alt+Shift+K查看所有快捷键。
什么是包
- 源码包(开发版本的包,只包含R/、DESCRIPTION等组件的一个目录)
- 压缩包:相比源码包,解压的包使用指南被创建,不存在临时文件src/等,.Rbuildignore中列出的文件也不会出现
- 二进制包:R/中没有.R文件;Meta/中包含大量Rds文件(readRDS()可以确切知道包含了什么内容);html/包含帮助文件;如果之前有src/,将会有一个libs/,包含已编译的代码;inst/目录下的内容移到了顶级目录。
- 已安装的包:解压到一个库的二进制包
- 内存中的包:
库
一个包含已安装包的目录
library()和require()的区别是,找不到包时前者报错,后者打印一个消息并返回FALSE
packrat可以自动化管理特定项目库
第二部分是包的组件
第3章 R代码
所有的R代码都要放在R/目录中
R代码的工作流程
# 重新加载代码
devtools::load_all() # 或者Rstudio下Ctrl/(mac下Cmd)+Shift+L
组织函数
文件名尽量不要有大小写区分
代码风格
谢益辉的formatR包可以快速使你乱的代码变漂亮。lintr包可以检查代码是否符合风格,只警告不修改。
- 对象名称简洁有意义
- 空格 除:(包含多个)外中缀运算符(=、+、-、<-等)前后加空格;左括号空格,圆或方括号前后不要空格,有逗号除外;左花括号不另起一行,总跟换行,右花括号总独占一行,除非有else,非常短可以不换行
- 行长度 80字符内,方便印刷
- 缩进 两个空格控制,跨越多行函数例外
- 赋值 <-
- 注释 #+空格,-和=把文件分成易于阅读的部分
顶层代码
- 不应该在包的顶层运行代码,包的代码只能创建对象,一般是函数。
- R运行环境:永远不要用修改全局设置的函数library/require/source;如果修改options()或par(),使用on.exit()
- .onLoad()应该总是使用,为包设置自定义选项;.onAttach()在包加载时显示一些信息
第4章 包的元数据
DESCRIPTION描述文件作用是储存包中的重要元数据,使用Debian控制格式,中间用:分开,跨越多行需要缩进。
# 自动添加一个描述文件框架
devtools::create('mypackage')
依赖:包需要什么
- Imports(必须安装)
- Suggests(建议,如果包不可用,有备用方法)
版本
- 总指定一个依赖包的最小版本
- .或-分隔的至少有两个整数的序列,发布版格式(主版本号.次版本号.补丁版本。开发版,添加开发版本号,如9000
标题和描述:包是做什么的
Title, Description, Author@R
许可证:谁能使用包
- MIT 简单的,类似BDS-2/3-clause,许可证必须始终和代码一起分发,自由分发。
- GPL-2/3 许可证保留,发布修改版本必须公开源码
- CC0 放弃对代码和数据的所有权利
其他域
- Collate控制R文件加载顺序
- LazyData使得访问包中的数据更容易
第5章 对象文档
man/目录下提供一些.Rd文件,语法大致基于LaTeX,会被编译为html、纯文本和PDF。roxygen2包将特殊格式转注释为.Rd,还可以管理NAMESPACE和DESCRIPTION。
文档工作流程
- roxygen注释到.R。以#开始
devtools::document() # 或者Rstudio中Ctrl+Shift+D将roxygen注释转为.Rd
- ?预览
- 修改,重复以上
另一个工作流
想看到链接
build--Build & Reload 或者Ctrl+Shift+B
设置好像已经和书中的描述不太一样
roxygen注释
- 块可以分解成标签@tag
- @seealso 其他有用资源
- @aliases 别名
函数文档
- @para 参数
- @examples 例子
- @return 返回值描述
不要重复自己
DRY Donnot repeat yourself
@rdname或@describeIn在一个文件中为多个函数提供文档
第6章 使用指南:长篇文档
browserVignettes() # 查看已经安装的使用指南
browserVignettes(‘ggplot2’) # 查看ggplot2的使用指南
editor(vignetter(x)) # 查看代码
knitr提供的R markdown使用指南引擎,rmarkdown包进一步简化,协调Markdown和nitr, pandoc提供很多有用的模板将Markdown转化成HTML。Rstudio是最简单的方法。
使用指南工作流程
devtools::use_vignette('my-vignette')
# 创建vignette/目录;DESCRIPTION添加必要的依赖;生成使用指南的模板vignettes/my-vignette.Rmd
Ctrl+Shift+K(或者单击Knit)来生成使用指南和预览输出。
元数据
YAML格式,像DESCRIPTION文件,一个特殊的YAML特征是>。
- 标题、作者和日期
- 输出
- 使用指南
Markdown(略)
knitr
混合代码、结果和文本。栅栏代码块:
# add two numbers
add <- function(a.b) a+b
add(10,20)
- eval = FALSE 防止代码运行
- echo = FALSE 关闭代码输入的打印
- results = 'hide' 关闭代码输出的打印
- warning = FALSE 和 message = FALSE
- collapse = TRUE 和 comment = "#>"
- error = TRUE 捕捉块内任何错误
- results = "asis" 认为R代码已经是Markdown格式
- fig.show = "hold" 保存所有的图
- fig.width = 5 和 fig.height = 5
开发周期
Ctrl + Alt + C一次运行一个代码块。重新运行整个文档Ctrl+Shift+K,devtools::build_vignettes()
编译所有使用指南,很少用。通常用devtools::build()
。
第7章 测试
自动化测试,又名单元测试,可以有更少的错误,更好的代码结构,容易重新启动,可靠的代码。R语言更像一个函数式编程语言。
测试工作流程
devtools::use_test_that()
将要创建一个tests/testthat目录,在DESCRIPTION的Suggests域中增加testthat,创建一个tests/testthat.R。Ctrl+Shift+T或者devtools::test()
测试你的包。
测试结构
测试文件放在tests/testthat/,名字必须以test开始。分层组织,期望组成文件,测试组成文件。context()
给文件赋予可读的名称。
期望
- 以expect_开始
- 两个参数,一个实际结果,一个期望值
- 如果两个不一致,抛出错误
测试相等,expect_equal()
和expect_identical()
,前者常用,使用all.equal()判断在误差范围内是否相等,后者是精确相等。expect_match()
检查一个字符串向量是否和一个正则表达式匹配。expect_output(),expect_message(),expect_warning(),expect_error(),expect_true(), expect_false()
。expect_equal_to_reference()
比较结果是否与上次结果相同。
编写测试
- 重点放在外部接口
- 仅有一个测试来测试每个行为
- 避免测试有信心的代码
- 发现错误时,写一个测试
跳过测试
skip()
建立自己的测试工具
测试文件
第8章 命名空间
搜索路径
R首先地全局环境中找,如果找不到,就在搜索路径中你已经附加的所有包中寻找。如果要根据一个建议的包是否被安装来执行一个特定的动作,请在包内使用requireNamespace(x, quietly = TRUE)。永远不要用require()或者loadNamespace()(只是在R内部代码中需要)。不要在包内使用前者或library(),如果需要在包内DESCRIPTION里的Depends或Imports域,Depends只是加载包,Imports附加包,除非有很好理由,否则使用Imports。因为一个好的包是独立的,最大限度减少对全局环境的改变。唯一例外是包被设计成与另一个包一起使用。
全名空间
roxygen2可以生成NAMESPACE文件,相比手写的优势是:命名空间定义在其关联函数的旁边;抽象了NAMESPACE的一些细节,使其更整洁。可以选择只生成 NAMESPACE或man/*.Rd ,也可以同时生成两者。
导出
要使一个函数可在包外用,必需导出它。
导入
控制哪些外部函数可以被包调用而无需使用::。通常在DESCRIPTION中列出需要的包,这样会被安装,然后总是pkg::fun显式调用。
第9章 外部数据
- 二进制数据,并提供用户data/目录,利用save()创建的RData文件(LazyData:true延迟加载)
- 解析过的数据,不提供用户R/sysdata.rda,不需要文档,包内使用
- 原始数据, inst/extdata
数据的文档
- @format:数据集概述
- @source:数据来源
永远不要@export数据集
第10章 编译过的代码
涉及内存管理等,一般用不到,这里略过
- rJava:将一个对象从R对象传递到Java函数涉及一个复制操作,会对性能有严重影响
第11章 安装文件
主要讲的是包引用,inst/CITATION文件,citEntry()函数可实现。
第12章 其他组成部分
- demo:包的演示目录,指南出现前使用的,现在不推荐使用。一个.R文件demo()可查看
- exec:可执行脚本
- po:翻译信息
第13章 Git和Github
这部分有不少详细教程,这里只摘最重要的。
理想状况下,每个提交是最小却完整的。提交信息简洁但具有提示性,描述为什么而不是是什么。
revert撤销(恢复),SHA(唯一标识),拉请求(Pull Request)
第14章 自动检查
R CMD check,返回ERROR,WARNING和NOTE
检查元数据,如包的结构,描述(强烈推荐UTF-8编码),命名空间,代码,数据,文档,演示,编译过的代码,测试和使用指南。
强烈建议使用Travis,一个连续的集成服务,开源项目,每次推送50分钟的Ubuntu服务器免费计算。
第15章 发布包
- 选择一个版本号,补丁加patch,次要minor,主要增加major,向后兼容
- 运行和记录R CMD check
- 检查是否符合CRAN标准
- 更新README.md和NEWS.md
- 提交到CRAN
- 更新版本号务下一版本准备
- 宣传
- tools: 辅助文件和脚本源码
网友评论