Урок 8 Написание документации к функциям пакета
Этим уроком мы начинаем обширную тему документации вашего пакета. В этом видео мы разберёмся с тем, как добавить документацию к функциям пакета с помощью специальных комментариев и пакета roxygen2
.
Данный урок основан на главе "Function documentation" книги "R Packages (2e)", под авторством Хедли Викхема и Дженни Брайан.
8.1 Видео
8.1.1 Тайм коды
00:00 Вступление
00:43 Какие компоненты пакета отвечают за документацию функций
01:31 Рабочий процесс
04:47 Структура roxygen комментариев
05:34 Особенности разметки roxygen комментариев
07:10 Из каких разделов состоит документация к функциям пакета
09:06 Title, Description и Details
12:07 Документирование аргументов функции
14:55 Возвращаемое функцией значение
16:42 Примеры использования функции
20:12 Повторное использование документации
22:23 Документация уровня пакета
23:50 Заключение
8.3 Конспект
8.3.1 Рабочий процесс
Рабочий процесс по добавлению документации к функциям состоит из следующих этапов:
- Добавляете
roxygen2
комментарии над объектами, к которым хотите сгенерировать документацию (Ctrl+Shift+Alt+R когда курсор находится внутри кода функции или кода генерирующего объект) - Запускаете
devtools::document()
(Ctrl/Cmd + Shift + D), чтобы преобразовать комментарииroxygen2
в.Rd
файлы. - Запускаете предварительный просмотрт сгенерированной документации с помощью
?function_name
. - Исправляете ошибки, повторяете процесс до тех пор, пока не получите нужный результат.
8.3.2 Структура roxygen комментариев
Например, для нашего оператора %+%
, который мы с вами добавили в пакет ещё в первом уроке, можно добавить следующие roxygen комментарии для генерации документации:
#' Concatenate Strings
#'
#' Operator for concatenate two strings.
#'
#' Use `%+%` operator for join two or more strings
#' @section Main:
#' The main ......
#' @param x Character, first string
#' @param y Character, second string
#'
#' @returns A character vector with lenght 1
#' @export
#'
#' @examples
#' # two values
#' "first" %+% "second"
#'
#' # three values
#' "first" %+% "second" %+% "three"
roxygen комментарии имеют следующие структуру:
- Комментарии
roxygen2
начинаются с#'
- Все комментарии
roxygen2
, предшествующие функции называются блоком - Блоки разбиваются на теги , которые выглядят как
@tagName
tagValue
- По умолчанию каждый блок генерирует один топик документации , т.е. один
.Rd
файл вman/
каталоге.
8.3.3 Особенности разметки .Rd файлов
- Используйте апострофы для выделения блока текста как кода:
#' I like \
thisfunction()`, because it's great`. - Для добавление ссылки на документацию к другой функции вашего или стороннего пакета используйте квадратные скобки:
#' It's obvious that `thisfunction()` is better than [otherpkg::otherfunction()]
#' or even our own [olderfunction()].
- Ссылайтесь на виньетки с помощью кода:
vignette("rd-formatting", package = "roxygen2")
- Маркированные списки прописываются так же, как и в обычном markdown:
#' Best features of `thisfunction()`:
#' * Smells nice
#' * Has good vibes
8.3.4 Разделы документации
- Заголовок (
@title
) – Обычно задаётся позиционно в первой строке roxygen комментария - Описание (
@description
) – Более подробное описание, что делает ваша функция, можно задать позиционно, второй строкой roxygen комментария - Детали (
@details
) – Тут описывают важные детали использования вашей функций, можно задать позиционно третей строкой комментария - Аргументы функции (
@param
) – Описание каждого аргумента функции - Возвращаемое значение (
@return
) – Какой объект возвращает ваша функция - Примеры (
@examples
) – Примеры использования вашей функции
8.3.4.1 Title, description и details
Первые 3 тега roxygen можно использовать позиционно, без указания их названий:
-
Title
– заголовок должен быть написан в регистре заголовков, не заканчиваться точкой и после него должна идти пустая строка. -
Description
– более подробное описание того, что делает функция, как правило занимает один абзац. Если ваше описание требует более чем один абзац вам придётся явно использовать тег.1 -
Details
– описание деталей работы вашей функции, в осном этот блок не используется в документации. Хорошей практикой является создание пользовательских разделов подробностей с помощью тега@section
.
8.3.4.2 Аргументы
- Для документирования аргументов функции используйте тег
@param
- Если использование нескольких аргументов тесно связано между собой можете объединить их через запятую, без указания пробела:
#' @param x,y A pair of character vectors
. - Тег
@inheritParams
позволяет наследовать описание аргументов из других функций вашего или даже стороннего пакета. При этом будут унаследованы только те аргументы, которые присутвуют в новой функции, и которые в ней отдельно не были задокументированы.
8.3.4.3 Возвращаемое значение
За возвращаемое значение отвечает тег @returns
. Для возвращаемого значения вам необходимо описать класс, тип и размер возвращаемого функцией значения.
8.3.4.4 Примеры
- Примеры описываются с использованием тега
@examples
- Все прописанные примеры должны выполняться без ошибок, поскольку они регулярно проверяются:
- В интерактивном режиме с помощью команды example()
- Во время работы R CMD check на вашем компьютере
- Во время проверки R CMD check на CRAN.
- Когда генерируется веб-сайт вашего пакета с помощью
pkgdown
- При использовании нестабильных ресурсов в ваших примерах, например веб-сайтах используйте тег
@examplesIf
, который позволяет пропускать такие примеры, так же можно завернуть ваши примеры в\dontrun{}
, для избегания запуска примеров, которые заведомо заканчиваются ошибками.
Примеры использования \dontrun{}
и @examplesIf
можно подсмотреть в коде пакета googledrive
:
Пример \dontrun{}
используется в функции drive_find:
#' @examples
#' \dontrun{
#' # list "My Drive" w/o regard for folder hierarchy
#' drive_find()
#'
#' # filter for folders, the easy way and the hard way
#' drive_find(type = "folder")
#' drive_find(q = "mimeType = 'application/vnd.google-apps.folder'")
#'
#' # filter for Google Sheets, the easy way and the hard way
#' drive_find(type = "spreadsheet")
#' drive_find(q = "mimeType='application/vnd.google-apps.spreadsheet'")
#'
#' }
#'
@examplesIf
используется в функции drive_publish:
#' @examplesIf drive_has_token()
#' # Create a file to publish
#' file <- drive_example_remote("chicken_sheet") %>%
#' drive_cp()
#'
#' # Publish file
#' file <- drive_publish(file)
#' file$published
#'
#' # Unpublish file
#' file <- drive_unpublish(file)
#' file$published
#'
#' # Clean up
#' drive_rm(file)
В данном случае с помощью функции drive_has_token()
мы проверяем есть ли кеш авторизационных данных, для доступа к данным, если учётные данные доступны то примеры выполняются, если не доступны то нет.
8.3.5 Объединить документацию к нескольким функциям в один файл
Документацию к нескольким близким по функционалу функциям имеет смысл объединить в один файл документации, сделать это можно с помощью тега @rdname
. Например в пакете stringr
в один файл объеденена документация к функциям str_length()
и str_width()
:
Изначально общее описание документации обеих функций мы привязываем к функции str_length()
:
#' The length/width of a string
#'
#' @description
#' `str_length()` returns the number of codepoints in a string. These are
#' the individual elements (which are often, but not always letters) that
#' can be extracted with [str_sub()].
#'
#' `str_width()` returns how much space the string will occupy when printed
#' in a fixed width font (i.e. when printed in the console).
#'
#' ...
str_length <- function(string) {
...
}
Далее используем в функции str_width()
тег @rdname
для её объединения с str_length()
:
#' @rdname str_length
str_width <- function(string) {
...
}
8.3.6 Повторное использование документации
При необходимости объединить документацию нескольких функций в один файл документации используйте тег @rdname
, и передайте в него название функции, в которой подробно описана документация всех функций.
Теги отвечающие за наследование частей документации:
-
@inherit source_function
- унаследует все поддерживаемые компоненты от source_function(). -
@inheritSection source_function Section title
- унаследует один раздел с заголовком «Section title» от source_function(). -
@inheritDotParams
- автоматически генерирует документацию по параметрам для ... общего случая, когда вы переходите ... к другой функции.
Пример из пакета stringr
, в котором практически в каждой функции доступны оноимённые аргументы string
и pattern
. Прописывать их отдельно для каждой функции не удобно, поскльку при необходимости внести в описание этих аргументов изменения, нам бы пришлось их руками вносить практически во все фукции пакета, поэтому в одной функции, в нашем случае str_length()
мы прописали описание этих аргументов, а в других функциях мы их можем переиспользовать:
Описание аргументов в функции str_length():
#' @param string Input vector. Either a character vector, or something
#' coercible to one.
#' @param pattern Pattern to look for.
#'
#' The default interpretation is a regular expression, as described in
#' `vignette("regular-expressions")`. Use [regex()] for finer control of the
#' matching behaviour.
#'
#' Match a fixed string (i.e. by comparing only bytes), using
#' [fixed()]. This is fast, but approximate. Generally,
#' for matching human text, you'll want [coll()] which
#' respects character matching rules for the specified locale.
#'
#' Match character, word, line and sentence boundaries with
#' [boundary()]. An empty pattern, "", is equivalent to
#' `boundary("character")`.
Далее с помощью тега @inheritParams
в других функциях, например str_match()
#' @inheritParams str_detect
#' @param pattern Unlike other stringr functions, `str_match()` only supports
#' regular expressions, as described `vignette("regular-expressions")`.
#' The pattern should contain at least one capturing group.
При этом унаследованы будут только те аргументы, которые присутвуют в новой функции, и не задокументированы в ней. В примере выше мы унаследуем описание аргумента string
, но переопределяем описание аргумента pattern
.
8.3.7 Раздел справки по пакету
Используйте функцию usethis::use_package_doc()
для генерации файла R/{pkgname}-package.R
, который содердит документацию уровня пакета. Так же это хорошее место для хранения импорта, т.е. тегов @import
и @importFrom
. Данный файл по умолчанию будет иметь следующий вид:
#' @keywords internal
"_PACKAGE"
# The following block is used by usethis to automatically manage
# roxygen namespace tags. Modify with care!
## usethis namespace: start
#' @importFrom glue glue_collapse
## usethis namespace: end
NULL