|
781 | 781 | "href": "slides/02-documentation/index.html#you-might-get-tired-of-using-all-the-time", |
782 | 782 | "title": "Function documentation and dependencies", |
783 | 783 | "section": "You might get tired of using :: all the time", |
784 | | - "text": "You might get tired of using :: all the time\nOr you might want to use an infix function\n\n`%>%` <- magittr::`%>%`\n\ncol_summary <- function(df, fun) {\n stopifnot(is.data.frame(df))\n\n df %>%\n purrr::keep(is.numeric) %>%\n purrr::modify(fun)\n}" |
| 784 | + "text": "You might get tired of using :: all the time\nOr you might want to use an infix function\n\n`%+%` <- roperators::`%+%`\n\nwelcome <- function(name, place){\n message(\"Welcome \" %+% name %+% \" from \" %+% place %+% \"!\")\n}" |
| 785 | + }, |
| 786 | + { |
| 787 | + "objectID": "slides/02-documentation/index.html#aside-vs", |
| 788 | + "href": "slides/02-documentation/index.html#aside-vs", |
| 789 | + "title": "Function documentation and dependencies", |
| 790 | + "section": "Aside: %>% vs |>", |
| 791 | + "text": "Aside: %>% vs |>\nThe native pipe, |>, has been available in R since 4.1.0, and we now prefer this to importing the %>% pipe from magrittr.\nThere are then two options:\n\nDepend on R >= 4.1.0, with this in DESCRIPTION:\n\nDepends:\n R (>= 4.1.0)\n\nUse the methods outlined in this tidyverse blog post to ensure the package can still work with older versions of R." |
785 | 792 | }, |
786 | 793 | { |
787 | 794 | "objectID": "slides/02-documentation/index.html#you-can-import-functions-into-the-package", |
788 | 795 | "href": "slides/02-documentation/index.html#you-can-import-functions-into-the-package", |
789 | 796 | "title": "Function documentation and dependencies", |
790 | 797 | "section": "You can import functions into the package", |
791 | | - "text": "You can import functions into the package\n\n#' @importFrom purrr keep modify\n#' @importFrom magrittr %>%\ncol_summary <- function(df, fun) {\n stopifnot(is.data.frame(df))\n\n df %>%\n keep(is.numeric) %>%\n modify(fun)\n}\n\ndevtools::document() will add corresponding import() statements to the NAMESPACE, e.g. import(purr, keep, modify).\nAdding formal imports is slightly more efficient than using ::.\nHere, the @importFrom tag is placed above the function in which the imported function is used." |
| 798 | + "text": "You can import functions into the package\n\n#' @importFrom purrr keep modify\n\ncol_summary <- function(df, fun) {\n stopifnot(is.data.frame(df))\n\n df |>\n keep(is.numeric) |>\n modify(fun)\n}\n\ndevtools::document() will add corresponding import() statements to the NAMESPACE, e.g. import(purr, keep, modify).\nAdding formal imports is slightly more efficient than using ::.\nHere, the @importFrom tag is placed above the function in which the imported function is used." |
792 | 799 | }, |
793 | 800 | { |
794 | 801 | "objectID": "slides/02-documentation/index.html#package-level-import-file", |
795 | 802 | "href": "slides/02-documentation/index.html#package-level-import-file", |
796 | 803 | "title": "Function documentation and dependencies", |
797 | 804 | "section": "Package-level import file", |
798 | | - "text": "Package-level import file\nImports belong to the package, not to individual functions, so alternatively you can recognise this by storing them in a central location, e.g. R/animalsounds-package.R\n#' @importFrom purrr keep modify\n#' @importFrom magrittr %>%\nNULL\n\nThis removes the possibility of multiple (redundant) imports of the same function. But harder to remember to remove import if function changes! It’s a matter of personal taste." |
| 805 | + "text": "Package-level import file\nImports belong to the package, not to individual functions, so alternatively you can recognise this by storing them in a central location, e.g. R/animalsounds-package.R\n#' @importFrom purrr keep modify\n#' @importFrom roperators %+%\nNULL\n\nThis removes the possibility of multiple (redundant) imports of the same function. But harder to remember to remove import if function changes! It’s a matter of personal taste." |
799 | 806 | }, |
800 | 807 | { |
801 | 808 | "objectID": "slides/02-documentation/index.html#usethisuse_import_from", |
|
809 | 816 | "href": "slides/02-documentation/index.html#it-may-be-tempting-to-import-a-whole-package", |
810 | 817 | "title": "Function documentation and dependencies", |
811 | 818 | "section": "It may be tempting to import a whole package…", |
812 | | - "text": "It may be tempting to import a whole package…\n#' @import purrr\ncol_summary <- function(df, fun) {\n stopifnot(is.data.frame(df))\n\n df %>%\n keep(is.numeric) %>%\n map_dfc(fun)\n}" |
| 819 | + "text": "It may be tempting to import a whole package…\n#' @import purrr\ncol_summary <- function(df, fun) {\n stopifnot(is.data.frame(df))\n\n df |>\n keep(is.numeric) |>\n map_dfc(fun)\n}" |
813 | 820 | }, |
814 | 821 | { |
815 | 822 | "objectID": "slides/02-documentation/index.html#but-it-is-dangerous", |
|
853 | 860 | "section": "Your turn", |
854 | 861 | "text": "Your turn\n\nUse use_package() to add rlang and cli to Imports.\nUpdate animal_sounds() to use is_character() to check the arguments and cli_abort to throw an informative error if necessary, using :: to fully qualify the function calls.\nLoad all and try giving animal_sounds() invalid inputs for animal and/or sound.\nCommit your changes to git.\nPush your commits for this session." |
855 | 862 | }, |
| 863 | + { |
| 864 | + "objectID": "slides/02-documentation/index.html#you-might-get-tired-of-using-all-the-time-1", |
| 865 | + "href": "slides/02-documentation/index.html#you-might-get-tired-of-using-all-the-time-1", |
| 866 | + "title": "Function documentation and dependencies", |
| 867 | + "section": "You might get tired of using :: all the time", |
| 868 | + "text": "You might get tired of using :: all the time\nOr you might want to use an infix function\n\n`%>%` <- magittr::`%>%`\n\ncol_summary <- function(df, fun) {\n stopifnot(is.data.frame(df))\n\n df %>%\n purrr::keep(is.numeric) %>%\n purrr::modify(fun)\n}" |
| 869 | + }, |
| 870 | + { |
| 871 | + "objectID": "slides/02-documentation/index.html#you-can-import-functions-into-the-package-1", |
| 872 | + "href": "slides/02-documentation/index.html#you-can-import-functions-into-the-package-1", |
| 873 | + "title": "Function documentation and dependencies", |
| 874 | + "section": "You can import functions into the package", |
| 875 | + "text": "You can import functions into the package\n\n#' @importFrom purrr keep modify\n#' @importFrom magrittr %>%\ncol_summary <- function(df, fun) {\n stopifnot(is.data.frame(df))\n\n df %>%\n keep(is.numeric) %>%\n modify(fun)\n}\n\ndevtools::document() will add corresponding import() statements to the NAMESPACE, e.g. import(purr, keep, modify).\nAdding formal imports is slightly more efficient than using ::.\nHere, the @importFrom tag is placed above the function in which the imported function is used." |
| 876 | + }, |
| 877 | + { |
| 878 | + "objectID": "slides/02-documentation/index.html#package-level-import-file-1", |
| 879 | + "href": "slides/02-documentation/index.html#package-level-import-file-1", |
| 880 | + "title": "Function documentation and dependencies", |
| 881 | + "section": "Package-level import file", |
| 882 | + "text": "Package-level import file\nImports belong to the package, not to individual functions, so alternatively you can recognise this by storing them in a central location, e.g. R/animalsounds-package.R\n#' @importFrom purrr keep modify\n#' @importFrom magrittr %>%\nNULL\n\nThis removes the possibility of multiple (redundant) imports of the same function. But harder to remember to remove import if function changes! It’s a matter of personal taste." |
| 883 | + }, |
| 884 | + { |
| 885 | + "objectID": "slides/02-documentation/index.html#usethisuse_import_from-1", |
| 886 | + "href": "slides/02-documentation/index.html#usethisuse_import_from-1", |
| 887 | + "title": "Function documentation and dependencies", |
| 888 | + "section": "usethis::use_import_from()", |
| 889 | + "text": "usethis::use_import_from()\nThere can be several steps to importing a function. usethis::use_import_from() takes care of all of them.\nIt will first create the package documentation file R/animalsounds-package.R (if it doesn’t already exist – you will also need to agree to this).\n\nusethis::use_import_from(\"purrr\", c(\"keep\", \"modify\"))\n\n✔ Adding 'purrr' to Imports field in DESCRIPTION\n✔ Adding '@importFrom purrr keep', '@importFrom purrr modify' to 'R/animalsounds-package.R'\n✔ Writing 'NAMESPACE'\n✔ Loading animalsounds\n\nuse_import_from() is opinionated in implementing package-level import (rather than above the function in which they are used).\nMay need to close and reopen R/animalsounds-package.R to see the changes." |
| 890 | + }, |
| 891 | + { |
| 892 | + "objectID": "slides/02-documentation/index.html#it-may-be-tempting-to-import-a-whole-package-1", |
| 893 | + "href": "slides/02-documentation/index.html#it-may-be-tempting-to-import-a-whole-package-1", |
| 894 | + "title": "Function documentation and dependencies", |
| 895 | + "section": "It may be tempting to import a whole package…", |
| 896 | + "text": "It may be tempting to import a whole package…\n#' @import purrr\ncol_summary <- function(df, fun) {\n stopifnot(is.data.frame(df))\n\n df %>%\n keep(is.numeric) %>%\n map_dfc(fun)\n}" |
| 897 | + }, |
| 898 | + { |
| 899 | + "objectID": "slides/02-documentation/index.html#but-it-is-dangerous-1", |
| 900 | + "href": "slides/02-documentation/index.html#but-it-is-dangerous-1", |
| 901 | + "title": "Function documentation and dependencies", |
| 902 | + "section": "…but it is dangerous", |
| 903 | + "text": "…but it is dangerous\n#' @import pkg1\n#' @import pkg2\nfun <- function(x) {\n fun1(x) + fun2(x)\n}\nWorks today…\n… but next year, what if pkg2 adds a fun1 function?" |
| 904 | + }, |
| 905 | + { |
| 906 | + "objectID": "slides/02-documentation/index.html#metapackages-1", |
| 907 | + "href": "slides/02-documentation/index.html#metapackages-1", |
| 908 | + "title": "Function documentation and dependencies", |
| 909 | + "section": "Metapackages", |
| 910 | + "text": "Metapackages\nIt is bad practice to import “metapackages” (i.e. packages that are collections of packages), such as tidyverse.\nSee the blog post https://www.tidyverse.org/blog/2018/06/tidyverse-not-for-packages/ for more details." |
| 911 | + }, |
| 912 | + { |
| 913 | + "objectID": "slides/02-documentation/index.html#documenting-dependencies-1", |
| 914 | + "href": "slides/02-documentation/index.html#documenting-dependencies-1", |
| 915 | + "title": "Function documentation and dependencies", |
| 916 | + "section": "Documenting dependencies", |
| 917 | + "text": "Documenting dependencies\n\n\n\n\nDESCRIPTION\nNAMESPACE\n\n\n\n\nMakes package available\nMakes function available\n\n\nMandatory\nOptional (can use :: instead)\n\n\nuse_package()\nuse_import_from()" |
| 918 | + }, |
| 919 | + { |
| 920 | + "objectID": "slides/02-documentation/index.html#example-rlang-and-cli-1", |
| 921 | + "href": "slides/02-documentation/index.html#example-rlang-and-cli-1", |
| 922 | + "title": "Function documentation and dependencies", |
| 923 | + "section": "Example: rlang and cli", |
| 924 | + "text": "Example: rlang and cli\nCurrently we are using stopifnot() for argument validation\n\nstopifnot(is.character(animal) & length(animal) == 1)\nstopifnot(is.character(sound) & length(sound) == 1)\n\nWe might instead use rlang::is_character() with cli::cli_abort()\n\nsound <- c(\"woof\", \"bark\")\n\nif (!rlang::is_character(sound, n = 1)) {\n cli::cli_abort(\"`sound` must be a single string!\")\n}\n\nError:\n! `sound` must be a single string!\n\n\n\nin is_character, n tests for length of the vector.\ncli::cli_abort() has some really nice capability - glue interpolation (next slide) - inline classes (next slide) - features that make it easier to write tests (covered later in this course)\nhttps://cli.r-lib.org/reference/inline-markup.html" |
| 925 | + }, |
| 926 | + { |
| 927 | + "objectID": "slides/02-documentation/index.html#aside-informative-messages-with-cli-1", |
| 928 | + "href": "slides/02-documentation/index.html#aside-informative-messages-with-cli-1", |
| 929 | + "title": "Function documentation and dependencies", |
| 930 | + "section": "Aside: informative messages with cli", |
| 931 | + "text": "Aside: informative messages with cli\ncli functions can combine glue interpolation and inline classes to produce informative, nicely-formatted error messages.\nIn animal_sounds() we can use\n\ncli::cli_abort(\n c(\"{.var animal} must be a single string!\",\n \"i\" = \"It was {.type {animal}} of length {length(animal)} instead.\")\n)\n\nThis gives the error message\n\nanimal_sounds(c(\"dog\", \"cat\"), c(\"woof\", \"miaow\"))\n\nError in `animal_sounds()`:\n! `animal` must be a single string!\nℹ It was a character vector of length 2 instead.\n\n\n\nInformative error messages will make using your package a much nicer experience for you and others." |
| 932 | + }, |
| 933 | + { |
| 934 | + "objectID": "slides/02-documentation/index.html#your-turn-3", |
| 935 | + "href": "slides/02-documentation/index.html#your-turn-3", |
| 936 | + "title": "Function documentation and dependencies", |
| 937 | + "section": "Your turn", |
| 938 | + "text": "Your turn\n\nUse use_package() to add rlang and cli to Imports.\nUpdate animal_sounds() to use is_character() to check the arguments and cli_abort to throw an informative error if necessary, using :: to fully qualify the function calls.\nLoad all and try giving animal_sounds() invalid inputs for animal and/or sound.\nCommit your changes to git.\nPush your commits for this session." |
| 939 | + }, |
856 | 940 | { |
857 | 941 | "objectID": "slides/02-documentation/index.html#references", |
858 | 942 | "href": "slides/02-documentation/index.html#references", |
|
0 commit comments