├── .Rbuildignore ├── .github ├── .gitignore ├── CODEOWNERS ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE │ └── issue_template.md ├── SUPPORT.md ├── move.yml └── workflows │ ├── R-CMD-check.yaml │ ├── pkgdown.yaml │ ├── pr-commands.yaml │ ├── rhub.yaml │ └── test-coverage.yaml ├── .gitignore ├── DESCRIPTION ├── LICENSE ├── LICENSE.md ├── NAMESPACE ├── NEWS.md ├── R ├── adverb-auto-browse.R ├── adverb-compose.R ├── adverb-insistently.R ├── adverb-negate.R ├── adverb-partial.R ├── adverb-possibly.R ├── adverb-quietly.R ├── adverb-safely.R ├── adverb-slowly.R ├── arrays.R ├── cleancall.R ├── coerce.R ├── compat-obj-type.R ├── compat-types-check.R ├── conditions.R ├── deprec-along.R ├── deprec-cross.R ├── deprec-invoke.R ├── deprec-lift.R ├── deprec-map.R ├── deprec-prepend.R ├── deprec-rerun.R ├── deprec-splice.R ├── deprec-utils.R ├── deprec-when.R ├── detect.R ├── every-some-none.R ├── faq.R ├── head-tail.R ├── imap.R ├── keep.R ├── list-combine.R ├── list-flatten.R ├── list-modify.R ├── list-simplify.R ├── list-transpose.R ├── lmap.R ├── map-depth.R ├── map-if-at.R ├── map-mapper.R ├── map-raw.R ├── map.R ├── map2.R ├── modify-tree.R ├── modify.R ├── package-purrr.R ├── parallelization.R ├── pluck-assign.R ├── pluck-depth.R ├── pluck.R ├── pmap.R ├── progress-bars.R ├── rate.R ├── reduce.R ├── reexport-pipe.R ├── reexport-rlang.R ├── superseded-flatten.R ├── superseded-map-df.R ├── superseded-simplify.R ├── superseded-transpose.R └── utils.R ├── README.Rmd ├── README.md ├── _pkgdown.yml ├── cleanup ├── codecov.yml ├── configure ├── configure.win ├── cran-comments.md ├── man ├── accumulate.Rd ├── along.Rd ├── array-coercion.Rd ├── as_mapper.Rd ├── as_vector.Rd ├── at_depth.Rd ├── attr_getter.Rd ├── auto_browse.Rd ├── chuck.Rd ├── compose.Rd ├── cross.Rd ├── detect.Rd ├── every.Rd ├── faq-adverbs-export.Rd ├── figures │ ├── lifecycle-archived.svg │ ├── lifecycle-defunct.svg │ ├── lifecycle-deprecated.svg │ ├── lifecycle-experimental.svg │ ├── lifecycle-maturing.svg │ ├── lifecycle-questioning.svg │ ├── lifecycle-soft-deprecated.svg │ ├── lifecycle-stable.svg │ ├── lifecycle-superseded.svg │ └── logo.png ├── flatten.Rd ├── get-attr.Rd ├── has_element.Rd ├── head_while.Rd ├── imap.Rd ├── insistently.Rd ├── invoke.Rd ├── keep.Rd ├── keep_at.Rd ├── lift.Rd ├── list_assign.Rd ├── list_c.Rd ├── list_flatten.Rd ├── list_simplify.Rd ├── list_transpose.Rd ├── lmap.Rd ├── macros │ └── .gitignore ├── map.Rd ├── map2.Rd ├── map_depth.Rd ├── map_dfr.Rd ├── map_if.Rd ├── map_raw.Rd ├── modify.Rd ├── modify_in.Rd ├── modify_tree.Rd ├── negate.Rd ├── parallelization.Rd ├── partial.Rd ├── pipe.Rd ├── pluck.Rd ├── pluck_depth.Rd ├── pmap.Rd ├── possibly.Rd ├── prepend.Rd ├── progress_bars.Rd ├── purrr-package.Rd ├── purrr_error_indexed.Rd ├── quietly.Rd ├── rate-helpers.Rd ├── rate_sleep.Rd ├── rbernoulli.Rd ├── rdunif.Rd ├── reduce.Rd ├── reduce_right.Rd ├── reexports.Rd ├── rerun.Rd ├── rmd │ └── indexed-error.Rmd ├── safely.Rd ├── slowly.Rd ├── splice.Rd ├── transpose.Rd ├── update_list.Rd └── when.Rd ├── pkgdown └── favicon │ ├── apple-touch-icon-120x120.png │ ├── apple-touch-icon-152x152.png │ ├── apple-touch-icon-180x180.png │ ├── apple-touch-icon-60x60.png │ ├── apple-touch-icon-76x76.png │ ├── apple-touch-icon.png │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ └── favicon.ico ├── purrr.Rproj ├── revdep ├── .gitignore ├── README.md ├── cran.md ├── email.yml ├── failures.md └── problems.md ├── src ├── .gitignore ├── Makevars ├── backports.c ├── backports.h ├── cleancall.c ├── cleancall.h ├── coerce.c ├── coerce.h ├── conditions.c ├── conditions.h ├── flatten.c ├── init.c ├── map.c ├── map.h ├── pluck.c ├── transpose.c ├── utils.c └── utils.h ├── tests ├── testthat.R └── testthat │ ├── _snaps │ ├── adverb-auto-browse.md │ ├── adverb-compose.md │ ├── adverb-insistently.md │ ├── adverb-partial.md │ ├── adverb-slowly.md │ ├── arrays.md │ ├── coerce.md │ ├── conditions.md │ ├── deprec-along.md │ ├── deprec-cross.md │ ├── deprec-invoke.md │ ├── deprec-lift.md │ ├── deprec-map.md │ ├── deprec-prepend.md │ ├── deprec-rerun.md │ ├── deprec-splice.md │ ├── deprec-utils.md │ ├── deprec-when.md │ ├── detect.md │ ├── every-some-none.md │ ├── head-tail.md │ ├── keep.md │ ├── list-combine.md │ ├── list-flatten.md │ ├── list-modify.md │ ├── list-simplify.md │ ├── list-transpose.md │ ├── lmap.md │ ├── map-depth.md │ ├── map-if-at.md │ ├── map-raw.md │ ├── map.md │ ├── map2.md │ ├── modify-tree.md │ ├── modify.md │ ├── parallel.md │ ├── pluck-assign.md │ ├── pluck-depth.md │ ├── pluck.md │ ├── pmap.md │ ├── rate.md │ ├── reduce.md │ ├── superseded-flatten.md │ ├── superseded-transpose.md │ └── utils.md │ ├── helper-map.R │ ├── helper.R │ ├── setup.R │ ├── test-adverb-auto-browse.R │ ├── test-adverb-compose.R │ ├── test-adverb-insistently.R │ ├── test-adverb-negate.R │ ├── test-adverb-partial.R │ ├── test-adverb-possibly.R │ ├── test-adverb-quietly.R │ ├── test-adverb-safely.R │ ├── test-adverb-slowly.R │ ├── test-arrays.R │ ├── test-coerce.R │ ├── test-conditions.R │ ├── test-deprec-along.R │ ├── test-deprec-cross.R │ ├── test-deprec-invoke.R │ ├── test-deprec-lift.R │ ├── test-deprec-map.R │ ├── test-deprec-prepend.R │ ├── test-deprec-rerun.R │ ├── test-deprec-splice.R │ ├── test-deprec-utils.R │ ├── test-deprec-when.R │ ├── test-detect.R │ ├── test-every-some-none.R │ ├── test-head-tail.R │ ├── test-imap.R │ ├── test-keep.R │ ├── test-list-combine.R │ ├── test-list-flatten.R │ ├── test-list-modify.R │ ├── test-list-simplify.R │ ├── test-list-transpose.R │ ├── test-lmap.R │ ├── test-map-depth.R │ ├── test-map-if-at.R │ ├── test-map-mapper.R │ ├── test-map-raw.R │ ├── test-map.R │ ├── test-map2.R │ ├── test-modify-tree.R │ ├── test-modify.R │ ├── test-parallel.R │ ├── test-pluck-assign.R │ ├── test-pluck-depth.R │ ├── test-pluck.R │ ├── test-pmap.R │ ├── test-rate.R │ ├── test-reduce.R │ ├── test-superseded-flatten.R │ ├── test-superseded-map-df.R │ ├── test-superseded-simplify.R │ ├── test-superseded-transpose.R │ └── test-utils.R ├── tools └── examples.R └── vignettes ├── .gitignore ├── base.Rmd └── other-langs.Rmd /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^CRAN-RELEASE$ 2 | ^pkgdown$ 3 | ^appveyor\.yml$ 4 | ^.*\.Rproj$ 5 | ^\.Rproj\.user$ 6 | ^\.travis\.yml$ 7 | ^cran-comments\.md$ 8 | ^revdep$ 9 | ^codecov\.yml$ 10 | ^README\.Rmd$ 11 | ^README-.*\.png$ 12 | ^logo\.png$ 13 | ^_pkgdown\.yml$ 14 | ^docs$ 15 | ^\.dir-locals.el 16 | ^src/\.dir-locals.el 17 | ^CODE_OF_CONDUCT\.md$ 18 | ^\.github$ 19 | ^TAGS$ 20 | ^\.httr-oauth$ 21 | ^LICENSE\.md$ 22 | ^\.github/workflows/R-CMD-check\.yaml$ 23 | ^\.github/workflows/pkgdown\.yaml$ 24 | ^\.github/workflows/pr-commands\.yaml$ 25 | ^CRAN-SUBMISSION$ 26 | ^compile_commands\.json$ 27 | ^\.cache$ 28 | -------------------------------------------------------------------------------- /.github/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # CODEOWNERS for purrr 2 | # https://www.tidyverse.org/development/understudies 3 | .github/CODEOWNERS @hadley @lionel- 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/issue_template.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report or feature request 3 | about: Describe a bug you've seen or make a case for a new feature 4 | --- 5 | 6 | Please briefly describe your problem and what output you expect. If you have a question, please don't use this form. Instead, ask on or . 7 | 8 | Please include a minimal reproducible example (AKA a reprex). If you've never heard of a [reprex](http://reprex.tidyverse.org/) before, start by reading . 9 | 10 | Brief description of the problem 11 | 12 | ```r 13 | # insert reprex here 14 | ``` 15 | -------------------------------------------------------------------------------- /.github/move.yml: -------------------------------------------------------------------------------- 1 | # Configuration for move-issues bot - https://github.com/dessant/move-issues 2 | 3 | # Delete the command comment when it contains no other content 4 | deleteCommand: true 5 | 6 | # Close the source issue after moving 7 | closeSourceIssue: true 8 | 9 | # Lock the source issue after moving 10 | lockSourceIssue: false 11 | 12 | # Mention issue and comment authors 13 | mentionAuthors: true 14 | 15 | # Preserve mentions in the issue content 16 | keepContentMentions: true 17 | 18 | # Set custom aliases for targets 19 | # aliases: 20 | # r: repo 21 | # or: owner/repo 22 | -------------------------------------------------------------------------------- /.github/workflows/R-CMD-check.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | # 4 | # NOTE: This workflow is overkill for most R packages and 5 | # check-standard.yaml is likely a better choice. 6 | # usethis::use_github_action("check-standard") will install it. 7 | on: 8 | push: 9 | branches: [main, master] 10 | pull_request: 11 | branches: [main, master] 12 | 13 | name: R-CMD-check.yaml 14 | 15 | permissions: read-all 16 | 17 | jobs: 18 | R-CMD-check: 19 | runs-on: ${{ matrix.config.os }} 20 | 21 | name: ${{ matrix.config.os }} (${{ matrix.config.r }}) 22 | 23 | strategy: 24 | fail-fast: false 25 | matrix: 26 | config: 27 | - {os: macos-latest, r: 'release'} 28 | 29 | - {os: windows-latest, r: 'release'} 30 | # use 4.0 or 4.1 to check with rtools40's older compiler 31 | - {os: windows-latest, r: 'oldrel-4'} 32 | 33 | - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} 34 | - {os: ubuntu-latest, r: 'release'} 35 | - {os: ubuntu-latest, r: 'oldrel-1'} 36 | - {os: ubuntu-latest, r: 'oldrel-2'} 37 | - {os: ubuntu-latest, r: 'oldrel-3'} 38 | - {os: ubuntu-latest, r: 'oldrel-4'} 39 | 40 | env: 41 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 42 | R_KEEP_PKG_SOURCE: yes 43 | 44 | steps: 45 | - uses: actions/checkout@v4 46 | 47 | - uses: r-lib/actions/setup-pandoc@v2 48 | 49 | - uses: r-lib/actions/setup-r@v2 50 | with: 51 | r-version: ${{ matrix.config.r }} 52 | http-user-agent: ${{ matrix.config.http-user-agent }} 53 | use-public-rspm: true 54 | 55 | - uses: r-lib/actions/setup-r-dependencies@v2 56 | with: 57 | extra-packages: any::rcmdcheck 58 | needs: check 59 | 60 | - uses: r-lib/actions/check-r-package@v2 61 | with: 62 | upload-snapshots: true 63 | build_args: 'c("--no-manual","--compact-vignettes=gs+qpdf")' 64 | -------------------------------------------------------------------------------- /.github/workflows/pkgdown.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | branches: [main, master] 8 | release: 9 | types: [published] 10 | workflow_dispatch: 11 | 12 | name: pkgdown.yaml 13 | 14 | permissions: read-all 15 | 16 | jobs: 17 | pkgdown: 18 | runs-on: ubuntu-latest 19 | # Only restrict concurrency for non-PR jobs 20 | concurrency: 21 | group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }} 22 | env: 23 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 24 | permissions: 25 | contents: write 26 | steps: 27 | - uses: actions/checkout@v4 28 | 29 | - uses: r-lib/actions/setup-pandoc@v2 30 | 31 | - uses: r-lib/actions/setup-r@v2 32 | with: 33 | use-public-rspm: true 34 | 35 | - uses: r-lib/actions/setup-r-dependencies@v2 36 | with: 37 | extra-packages: any::pkgdown, local::. 38 | needs: website 39 | 40 | - name: Build site 41 | run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE) 42 | shell: Rscript {0} 43 | 44 | - name: Deploy to GitHub pages 🚀 45 | if: github.event_name != 'pull_request' 46 | uses: JamesIves/github-pages-deploy-action@v4.5.0 47 | with: 48 | clean: false 49 | branch: gh-pages 50 | folder: docs 51 | -------------------------------------------------------------------------------- /.github/workflows/test-coverage.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | branches: [main, master] 8 | 9 | name: test-coverage.yaml 10 | 11 | permissions: read-all 12 | 13 | jobs: 14 | test-coverage: 15 | runs-on: ubuntu-latest 16 | env: 17 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 18 | 19 | steps: 20 | - uses: actions/checkout@v4 21 | 22 | - uses: r-lib/actions/setup-r@v2 23 | with: 24 | use-public-rspm: true 25 | 26 | - uses: r-lib/actions/setup-r-dependencies@v2 27 | with: 28 | extra-packages: any::covr, any::xml2 29 | needs: coverage 30 | 31 | - name: Test coverage 32 | run: | 33 | cov <- covr::package_coverage( 34 | quiet = FALSE, 35 | clean = FALSE, 36 | install_path = file.path(normalizePath(Sys.getenv("RUNNER_TEMP"), winslash = "/"), "package") 37 | ) 38 | covr::to_cobertura(cov) 39 | shell: Rscript {0} 40 | 41 | - uses: codecov/codecov-action@v4 42 | with: 43 | fail_ci_if_error: ${{ github.event_name != 'pull_request' && true || false }} 44 | file: ./cobertura.xml 45 | plugin: noop 46 | disable_search: true 47 | token: ${{ secrets.CODECOV_TOKEN }} 48 | 49 | - name: Show testthat output 50 | if: always() 51 | run: | 52 | ## -------------------------------------------------------------------- 53 | find '${{ runner.temp }}/package' -name 'testthat.Rout*' -exec cat '{}' \; || true 54 | shell: bash 55 | 56 | - name: Upload test results 57 | if: failure() 58 | uses: actions/upload-artifact@v4 59 | with: 60 | name: coverage-test-failures 61 | path: ${{ runner.temp }}/package 62 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | inst/doc 5 | revdep/checks 6 | revdep/library 7 | TAGS 8 | .httr-oauth 9 | docs 10 | compile_commands.json 11 | .cache 12 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: purrr 2 | Title: Functional Programming Tools 3 | Version: 1.0.4.9000 4 | Authors@R: c( 5 | person("Hadley", "Wickham", , "hadley@posit.co", role = c("aut", "cre"), 6 | comment = c(ORCID = "0000-0003-4757-117X")), 7 | person("Lionel", "Henry", , "lionel@posit.co", role = "aut"), 8 | person("Posit Software, PBC", role = c("cph", "fnd"), 9 | comment = c(ROR = "https://ror.org/03wc8by49")) 10 | ) 11 | Description: A complete and consistent functional programming toolkit for 12 | R. 13 | License: MIT + file LICENSE 14 | URL: https://purrr.tidyverse.org/, https://github.com/tidyverse/purrr 15 | BugReports: https://github.com/tidyverse/purrr/issues 16 | Depends: 17 | R (>= 4.0) 18 | Imports: 19 | cli (>= 3.6.1), 20 | lifecycle (>= 1.0.3), 21 | magrittr (>= 1.5.0), 22 | rlang (>= 1.1.1), 23 | vctrs (>= 0.6.3) 24 | Suggests: 25 | carrier (>= 0.1.1), 26 | covr, 27 | dplyr (>= 0.7.8), 28 | httr, 29 | knitr, 30 | lubridate, 31 | mirai (>= 2.3.0), 32 | rmarkdown, 33 | testthat (>= 3.0.0), 34 | tibble, 35 | tidyselect 36 | LinkingTo: 37 | cli 38 | VignetteBuilder: 39 | knitr 40 | Biarch: true 41 | Config/build/compilation-database: true 42 | Config/Needs/website: tidyverse/tidytemplate, tidyr 43 | Config/testthat/edition: 3 44 | Config/testthat/parallel: TRUE 45 | Encoding: UTF-8 46 | Roxygen: list(markdown = TRUE) 47 | RoxygenNote: 7.3.2 48 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2023 2 | COPYRIGHT HOLDER: purrr authors 3 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright (c) 2023 purrr authors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /R/adverb-auto-browse.R: -------------------------------------------------------------------------------- 1 | #' Wrap a function so it will automatically `browse()` on error 2 | #' 3 | #' A function wrapped with `auto_browse()` will automatically enter an 4 | #' interactive debugger using [browser()] when ever it encounters an error. 5 | #' 6 | #' @inheritParams safely 7 | #' @inheritSection safely Adverbs 8 | #' @inherit safely return 9 | #' @family adverbs 10 | #' @export 11 | #' @examples 12 | #' # For interactive usage, auto_browse() is useful because it automatically 13 | #' # starts a browser() in the right place. 14 | #' f <- function(x) { 15 | #' y <- 20 16 | #' if (x > 5) { 17 | #' stop("!") 18 | #' } else { 19 | #' x 20 | #' } 21 | #' } 22 | #' if (interactive()) { 23 | #' map(1:6, auto_browse(f)) 24 | #' } 25 | #' 26 | auto_browse <- function(.f) { 27 | if (is_primitive(.f)) { 28 | cli::cli_abort( 29 | "{.arg .f} must not be a primitive function.", 30 | arg = ".f" 31 | ) 32 | } 33 | 34 | function(...) { 35 | withCallingHandlers( 36 | .f(...), 37 | error = function(e) { 38 | # 1: h(simpleError(msg, call)) 39 | # 2: .handleSimpleError(function (e) <...> 40 | # 3: stop(...) 41 | frame <- sys.frame(4) 42 | browse_in_frame(frame) 43 | }, 44 | warning = function(e) { 45 | if (getOption("warn") >= 2) { 46 | frame <- sys.frame(7) 47 | browse_in_frame(frame) 48 | } 49 | } 50 | ) 51 | } 52 | } 53 | 54 | browse_in_frame <- function(frame) { 55 | # ESS should problably set `.Platform$GUI == "ESS"` 56 | # In the meantime, check that ESSR is attached 57 | if (is_attached("ESSR")) { 58 | # Workaround ESS issue 59 | with_env(frame, on.exit({ 60 | browser() 61 | NULL 62 | })) 63 | return_from(frame) 64 | } else { 65 | eval_bare(quote(browser()), env = frame) 66 | } 67 | } 68 | 69 | -------------------------------------------------------------------------------- /R/adverb-negate.R: -------------------------------------------------------------------------------- 1 | #' Negate a predicate function so it selects what it previously rejected 2 | #' 3 | #' Negating a function changes `TRUE` to `FALSE` and `FALSE` to `TRUE`. 4 | #' 5 | #' @inheritParams keep 6 | #' @inheritSection safely Adverbs 7 | #' @family adverbs 8 | #' @return A new predicate function. 9 | #' @export 10 | #' @examples 11 | #' x <- list(x = 1:10, y = rbernoulli(10), z = letters) 12 | #' x |> keep(is.numeric) |> names() 13 | #' x |> keep(negate(is.numeric)) |> names() 14 | #' # Same as 15 | #' x |> discard(is.numeric) 16 | negate <- function(.p) { 17 | compose(`!`, as_mapper(.p)) 18 | } 19 | -------------------------------------------------------------------------------- /R/adverb-possibly.R: -------------------------------------------------------------------------------- 1 | #' Wrap a function to return a value instead of an error 2 | #' 3 | #' Create a modified version of `.f` that return a default value (`otherwise`) 4 | #' whenever an error occurs. 5 | #' 6 | #' @inheritParams safely 7 | #' @inheritSection safely Adverbs 8 | #' @inherit safely return 9 | #' @family adverbs 10 | #' @export 11 | #' @examples 12 | #' # To replace errors with a default value, use possibly(). 13 | #' list("a", 10, 100) |> 14 | #' map_dbl(possibly(log, NA_real_)) 15 | #' 16 | #' # The default, NULL, will be discarded with `list_c()` 17 | #' list("a", 10, 100) |> 18 | #' map(possibly(log)) |> 19 | #' list_c() 20 | possibly <- function(.f, otherwise = NULL, quiet = TRUE) { 21 | .f <- as_mapper(.f) 22 | force(otherwise) 23 | check_bool(quiet) 24 | 25 | function(...) { 26 | tryCatch(.f(...), 27 | error = function(e) { 28 | if (!quiet) 29 | message("Error: ", conditionMessage(e)) 30 | otherwise 31 | } 32 | ) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /R/adverb-quietly.R: -------------------------------------------------------------------------------- 1 | #' Wrap a function to capture side-effects 2 | #' 3 | #' Create a modified version of `.f` that captures side-effects along with 4 | #' the return value of the function and returns a list containing 5 | #' the `result`, `output`, `messages` and `warnings`. 6 | #' 7 | #' @inheritParams safely 8 | #' @inheritSection safely Adverbs 9 | #' @inherit safely return 10 | #' @family adverbs 11 | #' @export 12 | #' @examples 13 | #' f <- function() { 14 | #' print("Hi!") 15 | #' message("Hello") 16 | #' warning("How are ya?") 17 | #' "Gidday" 18 | #' } 19 | #' f() 20 | #' 21 | #' f_quiet <- quietly(f) 22 | #' str(f_quiet()) 23 | quietly <- function(.f) { 24 | .f <- as_mapper(.f) 25 | function(...) capture_output(.f(...)) 26 | } 27 | 28 | capture_output <- function(code) { 29 | warnings <- character() 30 | wHandler <- function(w) { 31 | warnings <<- c(warnings, conditionMessage(w)) 32 | invokeRestart("muffleWarning") 33 | } 34 | 35 | messages <- character() 36 | mHandler <- function(m) { 37 | messages <<- c(messages, conditionMessage(m)) 38 | invokeRestart("muffleMessage") 39 | } 40 | 41 | temp <- file() 42 | sink(temp) 43 | on.exit({ 44 | sink() 45 | close(temp) 46 | }) 47 | 48 | result <- withCallingHandlers( 49 | code, 50 | warning = wHandler, 51 | message = mHandler 52 | ) 53 | 54 | output <- paste0(readLines(temp, warn = FALSE), collapse = "\n") 55 | 56 | list( 57 | result = result, 58 | output = output, 59 | warnings = warnings, 60 | messages = messages 61 | ) 62 | } 63 | -------------------------------------------------------------------------------- /R/adverb-safely.R: -------------------------------------------------------------------------------- 1 | #' Wrap a function to capture errors 2 | #' 3 | #' Creates a modified version of `.f` that always succeeds. It returns a list 4 | #' with components `result` and `error`. If the function succeeds, `result` 5 | #' contains the returned value and `error` is `NULL`. If an error occurred, 6 | #' `error` is an `error` object and `result` is either `NULL` or `otherwise`. 7 | #' 8 | #' # Adverbs 9 | #' This function is called an adverb because it modifies the effect of a 10 | #' function (a verb). If you'd like to include a function created an adverb 11 | #' in a package, be sure to read [faq-adverbs-export]. 12 | #' 13 | #' @param .f A function to modify, specified in one of the following ways: 14 | #' * A named function, e.g. `mean`. 15 | #' * An anonymous function, e.g. `\(x) x + 1` or `function(x) x + 1`. 16 | #' * A formula, e.g. `~ .x + 1`. Only recommended if you require backward 17 | #' compatibility with older versions of R. 18 | #' @param otherwise Default value to use when an error occurs. 19 | #' @param quiet Hide errors (`TRUE`, the default), or display them 20 | #' as they occur? 21 | #' @returns A function that takes the same arguments as `.f`, but returns 22 | #' a different value, as described above. 23 | #' @family adverbs 24 | #' @export 25 | #' @examples 26 | #' safe_log <- safely(log) 27 | #' safe_log(10) 28 | #' safe_log("a") 29 | #' 30 | #' list("a", 10, 100) |> 31 | #' map(safe_log) |> 32 | #' transpose() 33 | #' 34 | #' # This is a bit easier to work with if you supply a default value 35 | #' # of the same type and use the simplify argument to transpose(): 36 | #' safe_log <- safely(log, otherwise = NA_real_) 37 | #' list("a", 10, 100) |> 38 | #' map(safe_log) |> 39 | #' transpose() |> 40 | #' simplify_all() 41 | safely <- function(.f, otherwise = NULL, quiet = TRUE) { 42 | .f <- as_mapper(.f) 43 | force(otherwise) 44 | check_bool(quiet) 45 | 46 | function(...) capture_error(.f(...), otherwise, quiet) 47 | } 48 | 49 | capture_error <- function(code, otherwise = NULL, quiet = TRUE) { 50 | tryCatch( 51 | list(result = code, error = NULL), 52 | error = function(e) { 53 | if (!quiet) 54 | message("Error: ", conditionMessage(e)) 55 | 56 | list(result = otherwise, error = e) 57 | } 58 | ) 59 | } 60 | -------------------------------------------------------------------------------- /R/adverb-slowly.R: -------------------------------------------------------------------------------- 1 | #' Wrap a function to wait between executions 2 | #' 3 | #' `slowly()` takes a function and modifies it to wait a given 4 | #' amount of time between each call. 5 | #' 6 | #' @inheritParams insistently 7 | #' @param rate A [rate][rate-helpers] object. Defaults to a constant delay. 8 | #' @inheritSection safely Adverbs 9 | #' @inherit safely return 10 | #' @family adverbs 11 | #' @export 12 | #' @examples 13 | #' # For these example, we first create a custom rate 14 | #' # with a low waiting time between attempts: 15 | #' rate <- rate_delay(0.1) 16 | #' 17 | #' # slowly() causes a function to sleep for a given time between calls: 18 | #' slow_runif <- slowly(\(x) runif(1), rate = rate, quiet = FALSE) 19 | #' out <- map(1:5, slow_runif) 20 | slowly <- function(f, rate = rate_delay(), quiet = TRUE) { 21 | f <- as_mapper(f) 22 | check_rate(rate) 23 | check_bool(quiet) 24 | 25 | function(...) { 26 | rate_sleep(rate, quiet = quiet) 27 | f(...) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /R/cleancall.R: -------------------------------------------------------------------------------- 1 | call_with_cleanup <- function(ptr, ...) { 2 | .Call(cleancall_call, pairlist(ptr, ...), parent.frame()) 3 | } 4 | -------------------------------------------------------------------------------- /R/coerce.R: -------------------------------------------------------------------------------- 1 | # Used internally by map and flatten. 2 | # Exposed here for testing 3 | coerce <- function(x, type) { 4 | .Call(coerce_impl, x, type) 5 | } 6 | 7 | coerce_lgl <- function(x) coerce(x, "logical") 8 | coerce_int <- function(x) coerce(x, "integer") 9 | coerce_dbl <- function(x) coerce(x, "double") 10 | coerce_chr <- function(x) { 11 | local_deprecation_user_env() 12 | coerce(x, "character") 13 | } 14 | 15 | 16 | deprecate_to_char <- function(type) { 17 | lifecycle::deprecate_warn( 18 | "1.0.0", 19 | I(paste0("Automatic coercion from ", type, " to character")), 20 | I("an explicit call to `as.character()` within `map_chr()`"), 21 | always = TRUE, 22 | user_env = the$deprecation_user_env 23 | ) 24 | } 25 | 26 | 27 | # Can rewrite after https://github.com/r-lib/rlang/issues/1643 28 | local_deprecation_user_env <- function(user_env = caller_env(2), frame = caller_env()) { 29 | 30 | old <- the$deprecation_user_env 31 | the$deprecation_user_env <- user_env 32 | defer(the$deprecation_user_env <- old, frame) 33 | } 34 | 35 | # Lightweight equivalent of withr::defer() 36 | defer <- function(expr, env = caller_env(), after = FALSE) { 37 | thunk <- as.call(list(function() expr)) 38 | do.call(on.exit, list(thunk, TRUE, after), envir = env) 39 | } 40 | 41 | -------------------------------------------------------------------------------- /R/deprec-along.R: -------------------------------------------------------------------------------- 1 | #' Create a list of given length 2 | #' 3 | #' @description 4 | #' `r lifecycle::badge("deprecated")` 5 | #' 6 | #' This function was deprecated in purrr 1.0.0 since it's not related to the 7 | #' core purpose of purrr. 8 | #' 9 | #' It can be useful to create an empty list that you plan to fill later. This is 10 | #' similar to the idea of [seq_along()], which creates a vector of the same 11 | #' length as its input. 12 | #' 13 | #' @param x A vector. 14 | #' @return A list of the same length as `x`. 15 | #' @keywords internal 16 | #' @examples 17 | #' x <- 1:5 18 | #' seq_along(x) 19 | #' list_along(x) 20 | #' @name along 21 | #' @rdname along 22 | #' @export 23 | list_along <- function(x) { 24 | lifecycle::deprecate_soft("1.0.0", "list_along()", I("rep_along(x, list())")) 25 | 26 | vector("list", length(x)) 27 | } 28 | -------------------------------------------------------------------------------- /R/deprec-map.R: -------------------------------------------------------------------------------- 1 | #' Map at depth 2 | #' 3 | #' This function is defunct and has been replaced by [map_depth()]. 4 | #' See also [modify_depth()] for a version that preserves the types of 5 | #' the elements of the tree. 6 | #' 7 | #' @export 8 | #' @keywords internal 9 | at_depth <- function(.x, .depth, .f, ...) { 10 | lifecycle::deprecate_stop("0.3.0", "at_depth()", "map_depth()") 11 | } 12 | -------------------------------------------------------------------------------- /R/deprec-prepend.R: -------------------------------------------------------------------------------- 1 | #' Prepend a vector 2 | #' 3 | #' @description 4 | #' `r lifecycle::badge("deprecated")` 5 | #' 6 | #' This function was deprecated in purrr 1.0.0 because it's not related to the 7 | #' core purpose of purrr. 8 | #' 9 | #' This is a companion to [append()] to help merging two 10 | #' lists or atomic vectors. `prepend()` is a clearer semantic 11 | #' signal than `c()` that a vector is to be merged at the beginning of 12 | #' another, especially in a pipe chain. 13 | #' 14 | #' @param x the vector to be modified. 15 | #' @param values to be included in the modified vector. 16 | #' @param before a subscript, before which the values are to be appended. If 17 | #' `NULL`, values will be appended at the beginning even for `x` of length 0. 18 | #' @return A merged vector. 19 | #' @keywords internal 20 | #' @export 21 | #' @examples 22 | #' x <- as.list(1:3) 23 | #' 24 | #' x |> append("a") 25 | #' x |> prepend("a") 26 | #' x |> prepend(list("a", "b"), before = 3) 27 | #' prepend(list(), x) 28 | prepend <- function(x, values, before = NULL) { 29 | lifecycle::deprecate_soft("1.0.0", "prepend()", I("append(after = 0)")) 30 | 31 | n <- length(x) 32 | stopifnot(is.null(before) || (before > 0 && before <= n)) 33 | 34 | if (is.null(before) || before == 1) { 35 | c(values, x) 36 | } else { 37 | c(x[1:(before - 1)], values, x[before:n]) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /R/deprec-rerun.R: -------------------------------------------------------------------------------- 1 | #' Re-run expressions multiple times 2 | #' 3 | #' @description 4 | #' `r lifecycle::badge("deprecated")` 5 | #' 6 | #' This function was deprecated in purrr 1.0.0 because we believe that NSE 7 | #' functions are not a good fit for purrr. Also, `rerun(n, x)` can just as 8 | #' easily be expressed as `map(1:n, \(i) x)` 9 | #' 10 | #' `rerun()` is a convenient way of generating sample data. It works similarly to 11 | #' \code{\link{replicate}(..., simplify = FALSE)}. 12 | #' 13 | #' @param .n Number of times to run expressions 14 | #' @param ... Expressions to re-run. 15 | #' @return A list of length `.n`. Each element of `...` will be 16 | #' re-run once for each `.n`. 17 | #' 18 | #' There is one special case: if there's a single unnamed input, the second 19 | #' level list will be dropped. In this case, `rerun(n, x)` behaves like 20 | #' `replicate(n, x, simplify = FALSE)`. 21 | #' @export 22 | #' @keywords internal 23 | #' @examples 24 | #' # old 25 | #' 5 |> rerun(rnorm(5)) |> str() 26 | #' # new 27 | #' 1:5 |> map(\(i) rnorm(5)) |> str() 28 | #' 29 | #' # old 30 | #' 5 |> 31 | #' rerun(x = rnorm(5), y = rnorm(5)) |> 32 | #' map_dbl(\(l) cor(l$x, l$y)) 33 | #' # new 34 | #' 1:5 |> 35 | #' map(\(i) list(x = rnorm(5), y = rnorm(5))) |> 36 | #' map_dbl(\(l) cor(l$x, l$y)) 37 | rerun <- function(.n, ...) { 38 | deprec_rerun(.n, ..., .purrr_user_env = caller_env()) 39 | 40 | dots <- quos(...) 41 | 42 | # Special case: if single unnamed argument, insert directly into the output 43 | # rather than wrapping in a list. 44 | if (length(dots) == 1 && !is_named(dots)) { 45 | dots <- dots[[1]] 46 | eval_dots <- eval_tidy 47 | } else { 48 | eval_dots <- function(x) lapply(x, eval_tidy) 49 | } 50 | 51 | out <- vector("list", .n) 52 | for (i in seq_len(.n)) { 53 | out[[i]] <- eval_dots(dots) 54 | } 55 | out 56 | } 57 | 58 | deprec_rerun <- function(.n, ..., .purrr_user_env) { 59 | n <- .n 60 | old <- substitute(rerun(n, ...)) 61 | if (dots_n(...) == 1) { 62 | new <- substitute(map(1:n, ~ ...)) 63 | } else { 64 | new <- substitute(map(1:n, ~ list(...))) 65 | } 66 | 67 | lifecycle::deprecate_soft( 68 | when = "1.0.0", 69 | what = "rerun()", 70 | with = "map()", 71 | details = c( 72 | " " = "# Previously", 73 | " " = expr_deparse(old), 74 | "", 75 | " " = "# Now", 76 | " " = expr_deparse(new) 77 | ), 78 | user_env = .purrr_user_env 79 | ) 80 | } 81 | -------------------------------------------------------------------------------- /R/deprec-splice.R: -------------------------------------------------------------------------------- 1 | #' Splice objects and lists of objects into a list 2 | #' 3 | #' @description 4 | #' `r lifecycle::badge("deprecated")` 5 | #' 6 | #' This function was deprecated in purrr 1.0.0 because we no longer believe that 7 | #' this style of implicit/automatic splicing is a good idea; instead use 8 | #' `rlang::list2()` + `!!!` or [list_flatten()]. 9 | #' 10 | #' `splice()` splices all arguments into a list. Non-list objects and lists 11 | #' with a S3 class are encapsulated in a list before concatenation. 12 | #' 13 | #' @param ... Objects to concatenate. 14 | #' @return A list. 15 | #' @keywords internal 16 | #' @examples 17 | #' inputs <- list(arg1 = "a", arg2 = "b") 18 | #' 19 | #' # splice() concatenates the elements of inputs with arg3 20 | #' splice(inputs, arg3 = c("c1", "c2")) |> str() 21 | #' list(inputs, arg3 = c("c1", "c2")) |> str() 22 | #' c(inputs, arg3 = c("c1", "c2")) |> str() 23 | #' @export 24 | splice <- function(...) { 25 | lifecycle::deprecate_soft("1.0.0", "splice()", "list_flatten()") 26 | 27 | splice_if(list(...), is_bare_list) 28 | } 29 | 30 | splice_if <- function(.x, .p) { 31 | unspliced <- !where_if(.x, .p) 32 | out <- modify_if(.x, unspliced, list) 33 | list_flatten(out, name_spec = "{inner}") 34 | } 35 | -------------------------------------------------------------------------------- /R/deprec-utils.R: -------------------------------------------------------------------------------- 1 | #' Infix attribute accessor 2 | #' 3 | #' @description 4 | #' `r lifecycle::badge("deprecated")` 5 | #' 6 | #' This function was deprecated in purrr 0.3.0. Instead, lease use the `%@%` 7 | #' operator exported in rlang. It has an interface more consistent with `@`: 8 | #' uses NSE, supports S4 fields, and has an assignment variant. 9 | #' 10 | #' @param x Object 11 | #' @param name Attribute name 12 | #' @export 13 | #' @name get-attr 14 | #' @keywords internal 15 | `%@%` <- function(x, name) { 16 | lifecycle::deprecate_warn("0.3.0", I("%@%"), I("rlang::%@%"), always = TRUE) 17 | attr(x, name, exact = TRUE) 18 | } 19 | 20 | #' Generate random sample from a Bernoulli distribution 21 | #' 22 | #' @description 23 | #' `r lifecycle::badge("deprecated")` 24 | #' 25 | #' This function was deprecated in purrr 1.0.0 because it's not related to the 26 | #' core purpose of purrr. 27 | #' 28 | #' @param n Number of samples 29 | #' @param p Probability of getting `TRUE` 30 | #' @return A logical vector 31 | #' @keywords internal 32 | #' @export 33 | #' @examples 34 | #' rbernoulli(10) 35 | #' rbernoulli(100, 0.1) 36 | rbernoulli <- function(n, p = 0.5) { 37 | lifecycle::deprecate_soft("1.0.0", "rbernoulli()") 38 | stats::runif(n) > (1 - p) 39 | } 40 | 41 | #' Generate random sample from a discrete uniform distribution 42 | #' 43 | #' @description 44 | #' `r lifecycle::badge("deprecated")` 45 | #' 46 | #' This function was deprecated in purrr 1.0.0 because it's not related to the 47 | #' core purpose of purrr. 48 | #' 49 | #' @param n Number of samples to draw. 50 | #' @param a,b Range of the distribution (inclusive). 51 | #' @keywords internal 52 | #' @export 53 | #' @examples 54 | #' table(rdunif(1e3, 10)) 55 | #' table(rdunif(1e3, 10, -5)) 56 | rdunif <- function(n, b, a = 1) { 57 | lifecycle::deprecate_soft("1.0.0", "rdunif()") 58 | 59 | stopifnot(is.numeric(a), length(a) == 1) 60 | stopifnot(is.numeric(b), length(b) == 1) 61 | 62 | a1 <- min(a, b) 63 | b1 <- max(a, b) 64 | 65 | sample(b1 - a1 + 1, n, replace = TRUE) + a1 - 1 66 | } 67 | -------------------------------------------------------------------------------- /R/every-some-none.R: -------------------------------------------------------------------------------- 1 | #' Do every, some, or none of the elements of a list satisfy a predicate? 2 | #' 3 | #' * `some()` returns `TRUE` when `.p` is `TRUE` for at least one element. 4 | #' * `every()` returns `TRUE` when `.p` is `TRUE` for all elements. 5 | #' * `none()` returns `TRUE` when `.p` is `FALSE` for all elements. 6 | #' 7 | #' @inheritParams keep 8 | #' @param ... Additional arguments passed on to `.p`. 9 | #' @return A logical vector of length 1. 10 | #' @export 11 | #' @examples 12 | #' x <- list(0:10, 5.5) 13 | #' x |> every(is.numeric) 14 | #' x |> every(is.integer) 15 | #' x |> some(is.integer) 16 | #' x |> none(is.character) 17 | #' 18 | #' # Missing values are propagated: 19 | #' some(list(NA, FALSE), identity) 20 | #' 21 | #' # If you need to use these functions in a context where missing values are 22 | #' # unsafe (e.g. in `if ()` conditions), make sure to use safe predicates: 23 | #' if (some(list(NA, FALSE), rlang::is_true)) "foo" else "bar" 24 | every <- function(.x, .p, ...) { 25 | .p <- as_predicate(.p, ..., .mapper = TRUE, .allow_na = TRUE) 26 | 27 | val <- TRUE 28 | for (i in seq_along(.x)) { 29 | val <- val && .p(.x[[i]], ...) 30 | 31 | if (is_false(val)) { 32 | return(FALSE) 33 | } 34 | } 35 | 36 | val 37 | } 38 | 39 | #' @export 40 | #' @rdname every 41 | some <- function(.x, .p, ...) { 42 | .p <- as_predicate(.p, ..., .mapper = TRUE, .allow_na = TRUE) 43 | 44 | val <- FALSE 45 | for (i in seq_along(.x)) { 46 | val <- val || .p(.x[[i]], ...) 47 | 48 | if (is_true(val)) { 49 | return(TRUE) 50 | } 51 | } 52 | 53 | val 54 | } 55 | 56 | #' @export 57 | #' @rdname every 58 | none <- function(.x, .p, ...) { 59 | every(.x, negate(.p), ...) 60 | } 61 | -------------------------------------------------------------------------------- /R/faq.R: -------------------------------------------------------------------------------- 1 | #' Best practices for exporting adverb-wrapped functions 2 | #' 3 | #' @description 4 | #' Exporting functions created with purrr adverbs in your package 5 | #' requires some precautions because the functions will contain internal 6 | #' purrr code. This means that creating them once and for all when 7 | #' the package is built may cause problems when purrr is updated, because 8 | #' a function that the adverb uses might no longer exist. 9 | #' 10 | #' Instead, either create the modified function once per session on package 11 | #' load or wrap the call within another function every time you use it: 12 | #' 13 | #' * Using the \code{\link[=.onLoad]{.onLoad()}} hook: 14 | #' ``` 15 | #' #' My function 16 | #' #' @export 17 | #' insist_my_function <- function(...) "dummy" 18 | #' 19 | #' my_function <- function(...) { 20 | #' # Implementation 21 | #' } 22 | #' 23 | #' .onLoad <- function(lib, pkg) { 24 | #' insist_my_function <<- purrr::insistently(my_function) 25 | #' } 26 | #' ``` 27 | #' 28 | #' * Using a wrapper function: 29 | #' ``` 30 | #' my_function <- function(...) { 31 | #' # Implementation 32 | #' } 33 | #' 34 | #' #' My function 35 | #' #' @export 36 | #' insist_my_function <- function(...) { 37 | #' purrr::insistently(my_function)(...) 38 | #' } 39 | #' ``` 40 | #' @keywords internal 41 | #' @name faq-adverbs-export 42 | NULL 43 | -------------------------------------------------------------------------------- /R/head-tail.R: -------------------------------------------------------------------------------- 1 | #' Find head/tail that all satisfies a predicate. 2 | #' 3 | #' @inheritParams map_if 4 | #' @inheritParams map 5 | #' @return A vector the same type as `.x`. 6 | #' @export 7 | #' @examples 8 | #' pos <- function(x) x >= 0 9 | #' head_while(5:-5, pos) 10 | #' tail_while(5:-5, negate(pos)) 11 | #' 12 | #' big <- function(x) x > 100 13 | #' head_while(0:10, big) 14 | #' tail_while(0:10, big) 15 | head_while <- function(.x, .p, ...) { 16 | # Find location of first FALSE 17 | .p <- as_predicate(.p, ..., .mapper = TRUE) 18 | loc <- detect_index(.x, negate(.p), ...) 19 | if (loc == 0) return(.x) 20 | 21 | .x[seq_len(loc - 1)] 22 | } 23 | 24 | #' @export 25 | #' @rdname head_while 26 | tail_while <- function(.x, .p, ...) { 27 | .p <- as_predicate(.p, ..., .mapper = TRUE) 28 | # Find location of last FALSE 29 | loc <- detect_index(.x, negate(.p), ..., .dir = "backward") 30 | if (loc == 0) return(.x) 31 | 32 | .x[-seq_len(loc)] 33 | } 34 | -------------------------------------------------------------------------------- /R/imap.R: -------------------------------------------------------------------------------- 1 | #' Apply a function to each element of a vector, and its index 2 | #' 3 | #' `imap(x, ...)`, an indexed map, is short hand for 4 | #' `map2(x, names(x), ...)` if `x` has names, or `map2(x, seq_along(x), ...)` 5 | #' if it does not. This is useful if you need to compute on both the value 6 | #' and the position of an element. 7 | #' 8 | #' @param .f A function, specified in one of the following ways: 9 | #' 10 | #' * A named function, e.g. `paste`. 11 | #' * An anonymous function, e.g. `\(x, idx) x + idx` or 12 | #' `function(x, idx) x + idx`. 13 | #' * A formula, e.g. `~ .x + .y`. You must use `.x` to refer to the 14 | #' current element and `.y` to refer to the current index. Only recommended 15 | #' if you require backward compatibility with older versions of R. 16 | #' @inheritParams map 17 | #' @return A vector the same length as `.x`. 18 | #' @export 19 | #' @family map variants 20 | #' @examples 21 | #' imap_chr(sample(10), paste) 22 | #' 23 | #' imap_chr(sample(10), \(x, idx) paste0(idx, ": ", x)) 24 | #' 25 | #' iwalk(mtcars, \(x, idx) cat(idx, ": ", median(x), "\n", sep = "")) 26 | imap <- function(.x, .f, ...) { 27 | .f <- as_mapper(.f, ...) 28 | map2(.x, vec_index(.x), .f, ...) 29 | } 30 | 31 | #' @rdname imap 32 | #' @export 33 | imap_lgl <- function(.x, .f, ...) { 34 | .f <- as_mapper(.f, ...) 35 | map2_lgl(.x, vec_index(.x), .f, ...) 36 | } 37 | 38 | #' @rdname imap 39 | #' @export 40 | imap_chr <- function(.x, .f, ...) { 41 | .f <- as_mapper(.f, ...) 42 | map2_chr(.x, vec_index(.x), .f, ...) 43 | } 44 | 45 | #' @rdname imap 46 | #' @export 47 | imap_int <- function(.x, .f, ...) { 48 | .f <- as_mapper(.f, ...) 49 | map2_int(.x, vec_index(.x), .f, ...) 50 | } 51 | 52 | #' @rdname imap 53 | #' @export 54 | imap_dbl <- function(.x, .f, ...) { 55 | .f <- as_mapper(.f, ...) 56 | map2_dbl(.x, vec_index(.x), .f, ...) 57 | } 58 | 59 | #' @rdname imap 60 | #' @export 61 | imap_vec <- function(.x, .f, ...) { 62 | .f <- as_mapper(.f, ...) 63 | map2_vec(.x, vec_index(.x), .f, ...) 64 | } 65 | 66 | 67 | #' @export 68 | #' @rdname imap 69 | iwalk <- function(.x, .f, ...) { 70 | .f <- as_mapper(.f, ...) 71 | walk2(.x, vec_index(.x), .f, ...) 72 | } 73 | 74 | 75 | vec_index <- function(x) { 76 | names(x) %||% seq_along(x) 77 | } 78 | -------------------------------------------------------------------------------- /R/map-raw.R: -------------------------------------------------------------------------------- 1 | #' Functions that return raw vectors 2 | #' 3 | #' @description 4 | #' `r lifecycle::badge("deprecated")` 5 | #' 6 | #' These functions were deprecated in purrr 1.0.0 because they are of limited 7 | #' use and you can now use `map_vec()` instead. They are variants of [map()], 8 | #' [map2()], [imap()], [pmap()], and [flatten()] that return raw vectors. 9 | #' 10 | #' @keywords internal 11 | #' @export 12 | map_raw <- function(.x, .f, ...) { 13 | lifecycle::deprecate_soft("1.0.0", "map_raw()", "map_vec()") 14 | map_("raw", .x, .f, ...) 15 | } 16 | 17 | #' @export 18 | #' @rdname map_raw 19 | map2_raw <- function(.x, .y, .f, ...) { 20 | lifecycle::deprecate_soft("1.0.0", "map2_raw()", "map2_vec()") 21 | map2_("raw", .x, .y, .f, ...) 22 | } 23 | 24 | #' @rdname map_raw 25 | #' @export 26 | imap_raw <- function(.x, .f, ...) { 27 | lifecycle::deprecate_soft("1.0.0", "imap_raw()", "imap_vec()") 28 | map2_("raw", .x, vec_index(.x), .f, ...) 29 | } 30 | 31 | #' @export 32 | #' @rdname map_raw 33 | pmap_raw <- function(.l, .f, ...) { 34 | lifecycle::deprecate_soft("1.0.0", "pmap_raw()", "pmap_vec()") 35 | pmap_("raw", .l, .f, ...) 36 | } 37 | 38 | #' @export 39 | #' @rdname map_raw 40 | flatten_raw <- function(.x) { 41 | lifecycle::deprecate_soft("1.0.0", "flatten_raw()") 42 | .Call(vflatten_impl, .x, "raw") 43 | } 44 | -------------------------------------------------------------------------------- /R/package-purrr.R: -------------------------------------------------------------------------------- 1 | #' @keywords internal 2 | #' @import rlang 3 | #' @import vctrs 4 | #' @importFrom cli cli_progress_bar 5 | #' @importFrom lifecycle deprecated 6 | #' @useDynLib purrr, .registration = TRUE 7 | "_PACKAGE" 8 | 9 | the <- new_environment() 10 | -------------------------------------------------------------------------------- /R/pluck-depth.R: -------------------------------------------------------------------------------- 1 | #' Compute the depth of a vector 2 | #' 3 | #' The depth of a vector is how many levels that you can index/pluck into it. 4 | #' `pluck_depth()` was previously called `vec_depth()`. 5 | #' 6 | #' @param x A vector 7 | #' @param is_node Optionally override the default criteria for determine an 8 | #' element can be recursed within. The default matches the behaviour of 9 | #' `pluck()` which can recurse into lists and expressions. 10 | #' @return An integer. 11 | #' @export 12 | #' @examples 13 | #' x <- list( 14 | #' list(), 15 | #' list(list()), 16 | #' list(list(list(1))) 17 | #' ) 18 | #' pluck_depth(x) 19 | #' x |> map_int(pluck_depth) 20 | pluck_depth <- function(x, is_node = NULL) { 21 | if (is.null(is_node)) { 22 | is_node <- function(x) is.expression(x) || is.list(x) 23 | } 24 | is_node <- as_is_node(is_node) 25 | 26 | if (is_node(x)) { 27 | depths <- map_int(x, pluck_depth, is_node = is_node) 28 | 1L + max(depths, 0L) 29 | } else if (is_atomic(x)) { 30 | 1L 31 | } else { 32 | 0L 33 | } 34 | } 35 | 36 | #' @export 37 | #' @rdname pluck_depth 38 | #' @usage NULL 39 | vec_depth <- function(x) { 40 | lifecycle::deprecate_soft("1.0.0", "vec_depth()", "pluck_depth()") 41 | pluck_depth(x) 42 | } 43 | -------------------------------------------------------------------------------- /R/reexport-pipe.R: -------------------------------------------------------------------------------- 1 | #' Pipe operator 2 | #' 3 | #' @name %>% 4 | #' @rdname pipe 5 | #' @keywords internal 6 | #' @export 7 | #' @importFrom magrittr %>% 8 | #' @usage lhs \%>\% rhs 9 | NULL 10 | 11 | -------------------------------------------------------------------------------- /R/reexport-rlang.R: -------------------------------------------------------------------------------- 1 | #' @export 2 | rlang::set_names 3 | 4 | #' @export 5 | rlang::exec 6 | 7 | #' @export 8 | rlang::zap 9 | 10 | #' @export 11 | rlang::`%||%` 12 | 13 | #' @export 14 | rlang::done 15 | 16 | #' @export 17 | rlang::rep_along 18 | 19 | # Predicates --------------------------------------------------- 20 | 21 | #' @export 22 | rlang::is_bare_list 23 | 24 | #' @export 25 | rlang::is_bare_atomic 26 | 27 | #' @export 28 | rlang::is_bare_vector 29 | 30 | #' @export 31 | rlang::is_bare_double 32 | 33 | #' @export 34 | rlang::is_bare_integer 35 | 36 | #' @export 37 | rlang::is_bare_numeric 38 | 39 | #' @export 40 | rlang::is_bare_character 41 | 42 | #' @export 43 | rlang::is_bare_logical 44 | 45 | #' @export 46 | rlang::is_list 47 | 48 | #' @export 49 | rlang::is_atomic 50 | 51 | #' @export 52 | rlang::is_vector 53 | 54 | #' @export 55 | rlang::is_integer 56 | 57 | #' @export 58 | rlang::is_double 59 | 60 | #' @export 61 | rlang::is_character 62 | 63 | #' @export 64 | rlang::is_logical 65 | 66 | #' @export 67 | rlang::is_null 68 | 69 | #' @export 70 | rlang::is_function 71 | 72 | #' @export 73 | rlang::is_scalar_list 74 | 75 | #' @export 76 | rlang::is_scalar_atomic 77 | 78 | #' @export 79 | rlang::is_scalar_vector 80 | 81 | #' @export 82 | rlang::is_scalar_double 83 | 84 | #' @export 85 | rlang::is_scalar_character 86 | 87 | #' @export 88 | rlang::is_scalar_logical 89 | 90 | #' @export 91 | rlang::is_scalar_integer 92 | 93 | #' @export 94 | rlang::is_empty 95 | 96 | #' @export 97 | rlang::is_formula 98 | -------------------------------------------------------------------------------- /cleanup: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env sh 2 | 3 | rm -f man/macros/examples.Rd 4 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | comment: false 2 | 3 | coverage: 4 | status: 5 | project: 6 | default: 7 | target: auto 8 | threshold: 1% 9 | informational: true 10 | patch: 11 | default: 12 | target: auto 13 | threshold: 1% 14 | informational: true 15 | -------------------------------------------------------------------------------- /configure: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env sh 2 | 3 | # Check that this is not just ./configure. We need to run this 4 | # from R CMD INSTALL, to have the R env vars set. 5 | 6 | if [ -z "$R_HOME" ]; then 7 | echo >&2 R_HOME is not set, are you running R CMD INSTALL? 8 | exit 1 9 | fi 10 | 11 | # Find the R binary we need to use. This is a bit trickier on 12 | # Windows, because it has two architectures. On windows R_ARCH_BIN 13 | # is set, so this should work everywhere. 14 | RBIN="${R_HOME}/bin${R_ARCH_BIN}/R" 15 | 16 | "$RBIN" --vanilla --slave -f tools/examples.R 17 | -------------------------------------------------------------------------------- /configure.win: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env sh 2 | 3 | sh ./configure 4 | -------------------------------------------------------------------------------- /cran-comments.md: -------------------------------------------------------------------------------- 1 | ## R CMD check results 2 | 3 | 0 errors | 0 warnings | 0 notes 4 | 5 | ## revdepcheck results 6 | 7 | This was a patch release to fix R CMD check issues. I saw 2 false positives in my revdepchecks (meta and waywiser) and failed to check a further 45 packages. 8 | -------------------------------------------------------------------------------- /man/along.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/deprec-along.R 3 | \name{along} 4 | \alias{along} 5 | \alias{list_along} 6 | \title{Create a list of given length} 7 | \usage{ 8 | list_along(x) 9 | } 10 | \arguments{ 11 | \item{x}{A vector.} 12 | } 13 | \value{ 14 | A list of the same length as \code{x}. 15 | } 16 | \description{ 17 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} 18 | 19 | This function was deprecated in purrr 1.0.0 since it's not related to the 20 | core purpose of purrr. 21 | 22 | It can be useful to create an empty list that you plan to fill later. This is 23 | similar to the idea of \code{\link[=seq_along]{seq_along()}}, which creates a vector of the same 24 | length as its input. 25 | } 26 | \examples{ 27 | x <- 1:5 28 | seq_along(x) 29 | list_along(x) 30 | } 31 | \keyword{internal} 32 | -------------------------------------------------------------------------------- /man/array-coercion.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/arrays.R 3 | \name{array-coercion} 4 | \alias{array-coercion} 5 | \alias{array_branch} 6 | \alias{array_tree} 7 | \title{Coerce array to list} 8 | \usage{ 9 | array_branch(array, margin = NULL) 10 | 11 | array_tree(array, margin = NULL) 12 | } 13 | \arguments{ 14 | \item{array}{An array to coerce into a list.} 15 | 16 | \item{margin}{A numeric vector indicating the positions of the 17 | indices to be to be enlisted. If \code{NULL}, a full margin is 18 | used. If \code{numeric(0)}, the array as a whole is wrapped in a 19 | list.} 20 | } 21 | \description{ 22 | \code{array_branch()} and \code{array_tree()} enable arrays to be 23 | used with purrr's functionals by turning them into lists. The 24 | details of the coercion are controlled by the \code{margin} 25 | argument. \code{array_tree()} creates an hierarchical list (a tree) 26 | that has as many levels as dimensions specified in \code{margin}, 27 | while \code{array_branch()} creates a flat list (by analogy, a 28 | branch) along all mentioned dimensions. 29 | } 30 | \details{ 31 | When no margin is specified, all dimensions are used by 32 | default. When \code{margin} is a numeric vector of length zero, the 33 | whole array is wrapped in a list. 34 | } 35 | \examples{ 36 | # We create an array with 3 dimensions 37 | x <- array(1:12, c(2, 2, 3)) 38 | 39 | # A full margin for such an array would be the vector 1:3. This is 40 | # the default if you don't specify a margin 41 | 42 | # Creating a branch along the full margin is equivalent to 43 | # as.list(array) and produces a list of size length(x): 44 | array_branch(x) |> str() 45 | 46 | # A branch along the first dimension yields a list of length 2 47 | # with each element containing a 2x3 array: 48 | array_branch(x, 1) |> str() 49 | 50 | # A branch along the first and third dimensions yields a list of 51 | # length 2x3 whose elements contain a vector of length 2: 52 | array_branch(x, c(1, 3)) |> str() 53 | 54 | # Creating a tree from the full margin creates a list of lists of 55 | # lists: 56 | array_tree(x) |> str() 57 | 58 | # The ordering and the depth of the tree are controlled by the 59 | # margin argument: 60 | array_tree(x, c(3, 1)) |> str() 61 | } 62 | -------------------------------------------------------------------------------- /man/as_vector.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/superseded-simplify.R 3 | \name{as_vector} 4 | \alias{as_vector} 5 | \alias{simplify} 6 | \alias{simplify_all} 7 | \title{Coerce a list to a vector} 8 | \usage{ 9 | as_vector(.x, .type = NULL) 10 | 11 | simplify(.x, .type = NULL) 12 | 13 | simplify_all(.x, .type = NULL) 14 | } 15 | \arguments{ 16 | \item{.x}{A list of vectors} 17 | 18 | \item{.type}{Can be a vector mold specifying both the type and the 19 | length of the vectors to be concatenated, such as \code{numeric(1)} 20 | or \code{integer(4)}. Alternatively, it can be a string describing 21 | the type, one of: "logical", "integer", "double", "complex", 22 | "character" or "raw".} 23 | } 24 | \description{ 25 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#superseded}{\figure{lifecycle-superseded.svg}{options: alt='[Superseded]'}}}{\strong{[Superseded]}} 26 | 27 | These functions were superseded in purrr 1.0.0 in favour of 28 | \code{list_simplify()} which has more consistent semantics based on vctrs 29 | principles: 30 | \itemize{ 31 | \item \code{as_vector(x)} is now \code{list_simplify(x)} 32 | \item \code{simplify(x)} is now \code{list_simplify(x, strict = FALSE)} 33 | \item \code{simplify_all(x)} is \code{map(x, list_simplify, strict = FALSE)} 34 | } 35 | 36 | Superseded functions will not go away, but will only receive critical 37 | bug fixes. 38 | } 39 | \examples{ 40 | # was 41 | as.list(letters) |> as_vector("character") 42 | # now 43 | as.list(letters) |> list_simplify(ptype = character()) 44 | 45 | # was: 46 | list(1:2, 3:4, 5:6) |> as_vector(integer(2)) 47 | # now: 48 | list(1:2, 3:4, 5:6) |> list_c(ptype = integer()) 49 | } 50 | \keyword{internal} 51 | -------------------------------------------------------------------------------- /man/at_depth.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/deprec-map.R 3 | \name{at_depth} 4 | \alias{at_depth} 5 | \title{Map at depth} 6 | \usage{ 7 | at_depth(.x, .depth, .f, ...) 8 | } 9 | \description{ 10 | This function is defunct and has been replaced by \code{\link[=map_depth]{map_depth()}}. 11 | See also \code{\link[=modify_depth]{modify_depth()}} for a version that preserves the types of 12 | the elements of the tree. 13 | } 14 | \keyword{internal} 15 | -------------------------------------------------------------------------------- /man/attr_getter.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/pluck.R 3 | \name{attr_getter} 4 | \alias{attr_getter} 5 | \title{Create an attribute getter function} 6 | \usage{ 7 | attr_getter(attr) 8 | } 9 | \arguments{ 10 | \item{attr}{An attribute name as string.} 11 | } 12 | \description{ 13 | \code{attr_getter()} generates an attribute accessor function; i.e., it 14 | generates a function for extracting an attribute with a given 15 | name. Unlike the base R \code{attr()} function with default options, it 16 | doesn't use partial matching. 17 | } 18 | \examples{ 19 | # attr_getter() takes an attribute name and returns a function to 20 | # access the attribute: 21 | get_rownames <- attr_getter("row.names") 22 | get_rownames(mtcars) 23 | 24 | # These getter functions are handy in conjunction with pluck() for 25 | # extracting deeply into a data structure. Here we'll first 26 | # extract by position, then by attribute: 27 | obj1 <- structure("obj", obj_attr = "foo") 28 | obj2 <- structure("obj", obj_attr = "bar") 29 | x <- list(obj1, obj2) 30 | 31 | pluck(x, 1, attr_getter("obj_attr")) # From first object 32 | pluck(x, 2, attr_getter("obj_attr")) # From second object 33 | } 34 | \seealso{ 35 | \code{\link[=pluck]{pluck()}} 36 | } 37 | -------------------------------------------------------------------------------- /man/auto_browse.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/adverb-auto-browse.R 3 | \name{auto_browse} 4 | \alias{auto_browse} 5 | \title{Wrap a function so it will automatically \code{browse()} on error} 6 | \usage{ 7 | auto_browse(.f) 8 | } 9 | \arguments{ 10 | \item{.f}{A function to modify, specified in one of the following ways: 11 | \itemize{ 12 | \item A named function, e.g. \code{mean}. 13 | \item An anonymous function, e.g. \verb{\\(x) x + 1} or \code{function(x) x + 1}. 14 | \item A formula, e.g. \code{~ .x + 1}. Only recommended if you require backward 15 | compatibility with older versions of R. 16 | }} 17 | } 18 | \value{ 19 | A function that takes the same arguments as \code{.f}, but returns 20 | a different value, as described above. 21 | } 22 | \description{ 23 | A function wrapped with \code{auto_browse()} will automatically enter an 24 | interactive debugger using \code{\link[=browser]{browser()}} when ever it encounters an error. 25 | } 26 | \section{Adverbs}{ 27 | This function is called an adverb because it modifies the effect of a 28 | function (a verb). If you'd like to include a function created an adverb 29 | in a package, be sure to read \link{faq-adverbs-export}. 30 | } 31 | 32 | \examples{ 33 | # For interactive usage, auto_browse() is useful because it automatically 34 | # starts a browser() in the right place. 35 | f <- function(x) { 36 | y <- 20 37 | if (x > 5) { 38 | stop("!") 39 | } else { 40 | x 41 | } 42 | } 43 | if (interactive()) { 44 | map(1:6, auto_browse(f)) 45 | } 46 | 47 | } 48 | \seealso{ 49 | Other adverbs: 50 | \code{\link{compose}()}, 51 | \code{\link{insistently}()}, 52 | \code{\link{negate}()}, 53 | \code{\link{partial}()}, 54 | \code{\link{possibly}()}, 55 | \code{\link{quietly}()}, 56 | \code{\link{safely}()}, 57 | \code{\link{slowly}()} 58 | } 59 | \concept{adverbs} 60 | -------------------------------------------------------------------------------- /man/chuck.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/pluck.R 3 | \name{chuck} 4 | \alias{chuck} 5 | \title{Get an element deep within a nested data structure, failing if it doesn't 6 | exist} 7 | \usage{ 8 | chuck(.x, ...) 9 | } 10 | \arguments{ 11 | \item{.x}{A vector or environment} 12 | 13 | \item{...}{A list of accessors for indexing into the object. Can be 14 | an positive integer, a negative integer (to index from the right), 15 | a string (to index into names), or an accessor function 16 | (except for the assignment variants which only support names and 17 | positions). If the object being indexed is an S4 object, 18 | accessing it by name will return the corresponding slot. 19 | 20 | \link[rlang:dyn-dots]{Dynamic dots} are supported. In particular, if 21 | your accessors are stored in a list, you can splice that in with 22 | \verb{!!!}.} 23 | } 24 | \description{ 25 | \code{chuck()} implements a generalised form of \code{[[} that allow you to index 26 | deeply and flexibly into data structures. If the index you are trying to 27 | access does not exist (or is \code{NULL}), it will throw (i.e. chuck) an error. 28 | } 29 | \examples{ 30 | x <- list(a = 1, b = 2) 31 | 32 | # When indexing an element that doesn't exist `[[` sometimes returns NULL: 33 | x[["y"]] 34 | # and sometimes errors: 35 | try(x[[3]]) 36 | 37 | # chuck() consistently errors: 38 | try(chuck(x, "y")) 39 | try(chuck(x, 3)) 40 | } 41 | \seealso{ 42 | \code{\link[=pluck]{pluck()}} for a quiet equivalent. 43 | } 44 | -------------------------------------------------------------------------------- /man/compose.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/adverb-compose.R 3 | \name{compose} 4 | \alias{compose} 5 | \title{Compose multiple functions together to create a new function} 6 | \usage{ 7 | compose(..., .dir = c("backward", "forward")) 8 | } 9 | \arguments{ 10 | \item{...}{Functions to apply in order (from right to left by 11 | default). Formulas are converted to functions in the usual way. 12 | 13 | \link[rlang:dyn-dots]{Dynamic dots} are supported. In particular, if 14 | your functions are stored in a list, you can splice that in with 15 | \verb{!!!}.} 16 | 17 | \item{.dir}{If \code{"backward"} (the default), the functions are called 18 | in the reverse order, from right to left, as is conventional in 19 | mathematics. If \code{"forward"}, they are called from left to right.} 20 | } 21 | \value{ 22 | A function 23 | } 24 | \description{ 25 | Create a new function that is the composition of multiple functions, 26 | i.e. \code{compose(f, g)} is equivalent to \code{function(...) f(g(...))}. 27 | } 28 | \section{Adverbs}{ 29 | This function is called an adverb because it modifies the effect of a 30 | function (a verb). If you'd like to include a function created an adverb 31 | in a package, be sure to read \link{faq-adverbs-export}. 32 | } 33 | 34 | \examples{ 35 | not_null <- compose(`!`, is.null) 36 | not_null(4) 37 | not_null(NULL) 38 | 39 | add1 <- function(x) x + 1 40 | compose(add1, add1)(8) 41 | 42 | fn <- compose(\(x) paste(x, "foo"), \(x) paste(x, "bar")) 43 | fn("input") 44 | 45 | # Lists of functions can be spliced with !!! 46 | fns <- list( 47 | function(x) paste(x, "foo"), 48 | \(x) paste(x, "bar") 49 | ) 50 | fn <- compose(!!!fns) 51 | fn("input") 52 | } 53 | \seealso{ 54 | Other adverbs: 55 | \code{\link{auto_browse}()}, 56 | \code{\link{insistently}()}, 57 | \code{\link{negate}()}, 58 | \code{\link{partial}()}, 59 | \code{\link{possibly}()}, 60 | \code{\link{quietly}()}, 61 | \code{\link{safely}()}, 62 | \code{\link{slowly}()} 63 | } 64 | \concept{adverbs} 65 | -------------------------------------------------------------------------------- /man/every.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/every-some-none.R 3 | \name{every} 4 | \alias{every} 5 | \alias{some} 6 | \alias{none} 7 | \title{Do every, some, or none of the elements of a list satisfy a predicate?} 8 | \usage{ 9 | every(.x, .p, ...) 10 | 11 | some(.x, .p, ...) 12 | 13 | none(.x, .p, ...) 14 | } 15 | \arguments{ 16 | \item{.x}{A list or vector.} 17 | 18 | \item{.p}{A predicate function (i.e. a function that returns either \code{TRUE} 19 | or \code{FALSE}) specified in one of the following ways: 20 | \itemize{ 21 | \item A named function, e.g. \code{is.character}. 22 | \item An anonymous function, e.g. \verb{\\(x) all(x < 0)} or \code{function(x) all(x < 0)}. 23 | \item A formula, e.g. \code{~ all(.x < 0)}. You must use \code{.x} to refer to the first 24 | argument). Only recommended if you require backward compatibility with 25 | older versions of R. 26 | }} 27 | 28 | \item{...}{Additional arguments passed on to \code{.p}.} 29 | } 30 | \value{ 31 | A logical vector of length 1. 32 | } 33 | \description{ 34 | \itemize{ 35 | \item \code{some()} returns \code{TRUE} when \code{.p} is \code{TRUE} for at least one element. 36 | \item \code{every()} returns \code{TRUE} when \code{.p} is \code{TRUE} for all elements. 37 | \item \code{none()} returns \code{TRUE} when \code{.p} is \code{FALSE} for all elements. 38 | } 39 | } 40 | \examples{ 41 | x <- list(0:10, 5.5) 42 | x |> every(is.numeric) 43 | x |> every(is.integer) 44 | x |> some(is.integer) 45 | x |> none(is.character) 46 | 47 | # Missing values are propagated: 48 | some(list(NA, FALSE), identity) 49 | 50 | # If you need to use these functions in a context where missing values are 51 | # unsafe (e.g. in `if ()` conditions), make sure to use safe predicates: 52 | if (some(list(NA, FALSE), rlang::is_true)) "foo" else "bar" 53 | } 54 | -------------------------------------------------------------------------------- /man/faq-adverbs-export.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/faq.R 3 | \name{faq-adverbs-export} 4 | \alias{faq-adverbs-export} 5 | \title{Best practices for exporting adverb-wrapped functions} 6 | \description{ 7 | Exporting functions created with purrr adverbs in your package 8 | requires some precautions because the functions will contain internal 9 | purrr code. This means that creating them once and for all when 10 | the package is built may cause problems when purrr is updated, because 11 | a function that the adverb uses might no longer exist. 12 | 13 | Instead, either create the modified function once per session on package 14 | load or wrap the call within another function every time you use it: 15 | \itemize{ 16 | \item Using the \code{\link[=.onLoad]{.onLoad()}} hook: 17 | 18 | \if{html}{\out{
}}\preformatted{#' My function 19 | #' @export 20 | insist_my_function <- function(...) "dummy" 21 | 22 | my_function <- function(...) \{ 23 | # Implementation 24 | \} 25 | 26 | .onLoad <- function(lib, pkg) \{ 27 | insist_my_function <<- purrr::insistently(my_function) 28 | \} 29 | }\if{html}{\out{
}} 30 | \item Using a wrapper function: 31 | 32 | \if{html}{\out{
}}\preformatted{my_function <- function(...) \{ 33 | # Implementation 34 | \} 35 | 36 | #' My function 37 | #' @export 38 | insist_my_function <- function(...) \{ 39 | purrr::insistently(my_function)(...) 40 | \} 41 | }\if{html}{\out{
}} 42 | } 43 | } 44 | \keyword{internal} 45 | -------------------------------------------------------------------------------- /man/figures/lifecycle-archived.svg: -------------------------------------------------------------------------------- 1 | lifecyclelifecyclearchivedarchived -------------------------------------------------------------------------------- /man/figures/lifecycle-defunct.svg: -------------------------------------------------------------------------------- 1 | lifecyclelifecycledefunctdefunct -------------------------------------------------------------------------------- /man/figures/lifecycle-deprecated.svg: -------------------------------------------------------------------------------- 1 | lifecyclelifecycledeprecateddeprecated -------------------------------------------------------------------------------- /man/figures/lifecycle-experimental.svg: -------------------------------------------------------------------------------- 1 | lifecyclelifecycleexperimentalexperimental -------------------------------------------------------------------------------- /man/figures/lifecycle-maturing.svg: -------------------------------------------------------------------------------- 1 | lifecyclelifecyclematuringmaturing -------------------------------------------------------------------------------- /man/figures/lifecycle-questioning.svg: -------------------------------------------------------------------------------- 1 | lifecyclelifecyclequestioningquestioning -------------------------------------------------------------------------------- /man/figures/lifecycle-soft-deprecated.svg: -------------------------------------------------------------------------------- 1 | lifecyclelifecyclesoft-deprecatedsoft-deprecated -------------------------------------------------------------------------------- /man/figures/lifecycle-stable.svg: -------------------------------------------------------------------------------- 1 | lifecyclelifecyclestablestable -------------------------------------------------------------------------------- /man/figures/lifecycle-superseded.svg: -------------------------------------------------------------------------------- 1 | lifecyclelifecyclesupersededsuperseded -------------------------------------------------------------------------------- /man/figures/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/purrr/175307f88e110a6d2e1f029df65cd6821625678f/man/figures/logo.png -------------------------------------------------------------------------------- /man/flatten.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/superseded-flatten.R 3 | \name{flatten} 4 | \alias{flatten} 5 | \alias{flatten_lgl} 6 | \alias{flatten_int} 7 | \alias{flatten_dbl} 8 | \alias{flatten_chr} 9 | \alias{flatten_dfr} 10 | \alias{flatten_dfc} 11 | \alias{flatten_df} 12 | \title{Flatten a list of lists into a simple vector} 13 | \usage{ 14 | flatten(.x) 15 | 16 | flatten_lgl(.x) 17 | 18 | flatten_int(.x) 19 | 20 | flatten_dbl(.x) 21 | 22 | flatten_chr(.x) 23 | 24 | flatten_dfr(.x, .id = NULL) 25 | 26 | flatten_dfc(.x) 27 | } 28 | \arguments{ 29 | \item{.x}{A list to flatten. The contents of the list can be anything for 30 | \code{flatten()} (as a list is returned), but the contents must match the 31 | type for the other functions.} 32 | } 33 | \value{ 34 | \code{flatten()} returns a list, \code{flatten_lgl()} a logical 35 | vector, \code{flatten_int()} an integer vector, \code{flatten_dbl()} a 36 | double vector, and \code{flatten_chr()} a character vector. 37 | 38 | \code{flatten_dfr()} and \code{flatten_dfc()} return data frames created by 39 | row-binding and column-binding respectively. They require dplyr to 40 | be installed. 41 | } 42 | \description{ 43 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#superseded}{\figure{lifecycle-superseded.svg}{options: alt='[Superseded]'}}}{\strong{[Superseded]}} 44 | 45 | These functions were superseded in purrr 1.0.0 because their behaviour was 46 | inconsistent. Superseded functions will not go away, but will only receive 47 | critical bug fixes. 48 | \itemize{ 49 | \item \code{flatten()} has been superseded by \code{\link[=list_flatten]{list_flatten()}}. 50 | \item \code{flatten_lgl()}, \code{flatten_int()}, \code{flatten_dbl()}, and \code{flatten_chr()} 51 | have been superseded by \code{\link[=list_c]{list_c()}}. 52 | \item \code{flatten_dfr()} and \code{flatten_dfc()} have been superseded by \code{\link[=list_rbind]{list_rbind()}} 53 | and \code{\link[=list_cbind]{list_cbind()}} respectively. 54 | } 55 | } 56 | \examples{ 57 | x <- map(1:3, \(i) sample(4)) 58 | x 59 | 60 | # was 61 | x |> flatten_int() |> str() 62 | # now 63 | x |> list_c() |> str() 64 | 65 | x <- list(list(1, 2), list(3, 4)) 66 | # was 67 | x |> flatten() |> str() 68 | # now 69 | x |> list_flatten() |> str() 70 | } 71 | \keyword{internal} 72 | -------------------------------------------------------------------------------- /man/get-attr.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/deprec-utils.R 3 | \name{get-attr} 4 | \alias{get-attr} 5 | \alias{\%@\%} 6 | \title{Infix attribute accessor} 7 | \usage{ 8 | x \%@\% name 9 | } 10 | \arguments{ 11 | \item{x}{Object} 12 | 13 | \item{name}{Attribute name} 14 | } 15 | \description{ 16 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} 17 | 18 | This function was deprecated in purrr 0.3.0. Instead, lease use the \verb{\%@\%} 19 | operator exported in rlang. It has an interface more consistent with \code{@}: 20 | uses NSE, supports S4 fields, and has an assignment variant. 21 | } 22 | \keyword{internal} 23 | -------------------------------------------------------------------------------- /man/has_element.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/detect.R 3 | \name{has_element} 4 | \alias{has_element} 5 | \title{Does a list contain an object?} 6 | \usage{ 7 | has_element(.x, .y) 8 | } 9 | \arguments{ 10 | \item{.x}{A list or atomic vector.} 11 | 12 | \item{.y}{Object to test for} 13 | } 14 | \description{ 15 | Does a list contain an object? 16 | } 17 | \examples{ 18 | x <- list(1:10, 5, 9.9) 19 | x |> has_element(1:10) 20 | x |> has_element(3) 21 | } 22 | -------------------------------------------------------------------------------- /man/head_while.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/head-tail.R 3 | \name{head_while} 4 | \alias{head_while} 5 | \alias{tail_while} 6 | \title{Find head/tail that all satisfies a predicate.} 7 | \usage{ 8 | head_while(.x, .p, ...) 9 | 10 | tail_while(.x, .p, ...) 11 | } 12 | \arguments{ 13 | \item{.x}{A list or atomic vector.} 14 | 15 | \item{.p}{A single predicate function, a formula describing such a 16 | predicate function, or a logical vector of the same length as \code{.x}. 17 | Alternatively, if the elements of \code{.x} are themselves lists of 18 | objects, a string indicating the name of a logical element in the 19 | inner lists. Only those elements where \code{.p} evaluates to 20 | \code{TRUE} will be modified.} 21 | 22 | \item{...}{Additional arguments passed on to the mapped function. 23 | 24 | We now generally recommend against using \code{...} to pass additional 25 | (constant) arguments to \code{.f}. Instead use a shorthand anonymous function: 26 | 27 | \if{html}{\out{
}}\preformatted{# Instead of 28 | x |> map(f, 1, 2, collapse = ",") 29 | # do: 30 | x |> map(\\(x) f(x, 1, 2, collapse = ",")) 31 | }\if{html}{\out{
}} 32 | 33 | This makes it easier to understand which arguments belong to which 34 | function and will tend to yield better error messages.} 35 | } 36 | \value{ 37 | A vector the same type as \code{.x}. 38 | } 39 | \description{ 40 | Find head/tail that all satisfies a predicate. 41 | } 42 | \examples{ 43 | pos <- function(x) x >= 0 44 | head_while(5:-5, pos) 45 | tail_while(5:-5, negate(pos)) 46 | 47 | big <- function(x) x > 100 48 | head_while(0:10, big) 49 | tail_while(0:10, big) 50 | } 51 | -------------------------------------------------------------------------------- /man/imap.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/imap.R 3 | \name{imap} 4 | \alias{imap} 5 | \alias{imap_lgl} 6 | \alias{imap_chr} 7 | \alias{imap_int} 8 | \alias{imap_dbl} 9 | \alias{imap_vec} 10 | \alias{iwalk} 11 | \title{Apply a function to each element of a vector, and its index} 12 | \usage{ 13 | imap(.x, .f, ...) 14 | 15 | imap_lgl(.x, .f, ...) 16 | 17 | imap_chr(.x, .f, ...) 18 | 19 | imap_int(.x, .f, ...) 20 | 21 | imap_dbl(.x, .f, ...) 22 | 23 | imap_vec(.x, .f, ...) 24 | 25 | iwalk(.x, .f, ...) 26 | } 27 | \arguments{ 28 | \item{.x}{A list or atomic vector.} 29 | 30 | \item{.f}{A function, specified in one of the following ways: 31 | \itemize{ 32 | \item A named function, e.g. \code{paste}. 33 | \item An anonymous function, e.g. \verb{\\(x, idx) x + idx} or 34 | \code{function(x, idx) x + idx}. 35 | \item A formula, e.g. \code{~ .x + .y}. You must use \code{.x} to refer to the 36 | current element and \code{.y} to refer to the current index. Only recommended 37 | if you require backward compatibility with older versions of R. 38 | }} 39 | 40 | \item{...}{Additional arguments passed on to the mapped function. 41 | 42 | We now generally recommend against using \code{...} to pass additional 43 | (constant) arguments to \code{.f}. Instead use a shorthand anonymous function: 44 | 45 | \if{html}{\out{
}}\preformatted{# Instead of 46 | x |> map(f, 1, 2, collapse = ",") 47 | # do: 48 | x |> map(\\(x) f(x, 1, 2, collapse = ",")) 49 | }\if{html}{\out{
}} 50 | 51 | This makes it easier to understand which arguments belong to which 52 | function and will tend to yield better error messages.} 53 | } 54 | \value{ 55 | A vector the same length as \code{.x}. 56 | } 57 | \description{ 58 | \code{imap(x, ...)}, an indexed map, is short hand for 59 | \code{map2(x, names(x), ...)} if \code{x} has names, or \code{map2(x, seq_along(x), ...)} 60 | if it does not. This is useful if you need to compute on both the value 61 | and the position of an element. 62 | } 63 | \examples{ 64 | imap_chr(sample(10), paste) 65 | 66 | imap_chr(sample(10), \(x, idx) paste0(idx, ": ", x)) 67 | 68 | iwalk(mtcars, \(x, idx) cat(idx, ": ", median(x), "\n", sep = "")) 69 | } 70 | \seealso{ 71 | Other map variants: 72 | \code{\link{lmap}()}, 73 | \code{\link{map}()}, 74 | \code{\link{map2}()}, 75 | \code{\link{map_depth}()}, 76 | \code{\link{map_if}()}, 77 | \code{\link{modify}()}, 78 | \code{\link{pmap}()} 79 | } 80 | \concept{map variants} 81 | -------------------------------------------------------------------------------- /man/keep.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/keep.R 3 | \name{keep} 4 | \alias{keep} 5 | \alias{discard} 6 | \alias{compact} 7 | \title{Keep/discard elements based on their values} 8 | \usage{ 9 | keep(.x, .p, ...) 10 | 11 | discard(.x, .p, ...) 12 | 13 | compact(.x, .p = identity) 14 | } 15 | \arguments{ 16 | \item{.x}{A list or vector.} 17 | 18 | \item{.p}{A predicate function (i.e. a function that returns either \code{TRUE} 19 | or \code{FALSE}) specified in one of the following ways: 20 | \itemize{ 21 | \item A named function, e.g. \code{is.character}. 22 | \item An anonymous function, e.g. \verb{\\(x) all(x < 0)} or \code{function(x) all(x < 0)}. 23 | \item A formula, e.g. \code{~ all(.x < 0)}. You must use \code{.x} to refer to the first 24 | argument). Only recommended if you require backward compatibility with 25 | older versions of R. 26 | }} 27 | 28 | \item{...}{Additional arguments passed on to \code{.p}.} 29 | } 30 | \description{ 31 | \code{keep()} selects all elements where \code{.p} evaluates to \code{TRUE}; 32 | \code{discard()} selects all elements where \code{.p} evaluates to \code{FALSE}. 33 | \code{compact()} discards elements where \code{.p} evaluates to an empty vector. 34 | } 35 | \details{ 36 | In other languages, \code{keep()} and \code{discard()} are often called \code{select()}/ 37 | \code{filter()} and \code{reject()}/ \code{drop()}, but those names are already taken 38 | in R. \code{keep()} is similar to \code{\link[=Filter]{Filter()}}, but the argument order is more 39 | convenient, and the evaluation of the predicate function \code{.p} is stricter. 40 | } 41 | \examples{ 42 | rep(10, 10) |> 43 | map(sample, 5) |> 44 | keep(function(x) mean(x) > 6) 45 | 46 | # Or use a formula 47 | rep(10, 10) |> 48 | map(sample, 5) |> 49 | keep(\(x) mean(x) > 6) 50 | 51 | # Using a string instead of a function will select all list elements 52 | # where that subelement is TRUE 53 | x <- rerun(5, a = rbernoulli(1), b = sample(10)) 54 | x 55 | x |> keep("a") 56 | x |> discard("a") 57 | 58 | # compact() discards elements that are NULL or that have length zero 59 | list(a = "a", b = NULL, c = integer(0), d = NA, e = list()) |> 60 | compact() 61 | } 62 | \seealso{ 63 | \code{\link[=keep_at]{keep_at()}}/\code{\link[=discard_at]{discard_at()}} to keep/discard elements by name. 64 | } 65 | -------------------------------------------------------------------------------- /man/keep_at.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/keep.R 3 | \name{keep_at} 4 | \alias{keep_at} 5 | \alias{discard_at} 6 | \title{Keep/discard elements based on their name/position} 7 | \usage{ 8 | keep_at(x, at) 9 | 10 | discard_at(x, at) 11 | } 12 | \arguments{ 13 | \item{x}{A list or atomic vector.} 14 | 15 | \item{at}{A logical, integer, or character vector giving the elements 16 | to select. Alternatively, a function that takes a vector of names, 17 | and returns a logical, integer, or character vector of elements to select. 18 | 19 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}}: if the tidyselect package is 20 | installed, you can use \code{vars()} and tidyselect helpers to select 21 | elements.} 22 | } 23 | \description{ 24 | Keep/discard elements based on their name/position 25 | } 26 | \examples{ 27 | x <- c(a = 1, b = 2, cat = 10, dog = 15, elephant = 5, e = 10) 28 | x |> keep_at(letters) 29 | x |> discard_at(letters) 30 | 31 | # Can also use a function 32 | x |> keep_at(~ nchar(.x) == 3) 33 | x |> discard_at(~ nchar(.x) == 3) 34 | } 35 | \seealso{ 36 | \code{\link[=keep]{keep()}}/\code{\link[=discard]{discard()}} to keep/discard elements by value. 37 | } 38 | -------------------------------------------------------------------------------- /man/list_assign.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/list-modify.R 3 | \name{list_assign} 4 | \alias{list_assign} 5 | \alias{list_modify} 6 | \alias{list_merge} 7 | \title{Modify a list} 8 | \usage{ 9 | list_assign(.x, ..., .is_node = NULL) 10 | 11 | list_modify(.x, ..., .is_node = NULL) 12 | 13 | list_merge(.x, ..., .is_node = NULL) 14 | } 15 | \arguments{ 16 | \item{.x}{List to modify.} 17 | 18 | \item{...}{New values of a list. Use \code{zap()} to remove values. 19 | 20 | These values should be either all named or all unnamed. When 21 | inputs are all named, they are matched to \code{.x} by name. When they 22 | are all unnamed, they are matched by position. 23 | 24 | \link[rlang:dyn-dots]{Dynamic dots} are supported. In particular, if your 25 | replacement values are stored in a list, you can splice that in with 26 | \verb{!!!}.} 27 | 28 | \item{.is_node}{A predicate function that determines whether an element is 29 | a node (by returning \code{TRUE}) or a leaf (by returning \code{FALSE}). The 30 | default value, \code{NULL}, treats simple lists as nodes and everything else 31 | (including richer objects like data frames and linear models) as leaves, 32 | using \code{\link[vctrs:obj_is_list]{vctrs::obj_is_list()}}. To recurse into all objects built on lists 33 | use \code{\link[=is.list]{is.list()}}.} 34 | } 35 | \description{ 36 | \itemize{ 37 | \item \code{list_assign()} modifies the elements of a list by name or position. 38 | \item \code{list_modify()} modifies the elements of a list recursively. 39 | \item \code{list_merge()} merges the elements of a list recursively. 40 | } 41 | 42 | \code{list_modify()} is inspired by \code{\link[utils:modifyList]{utils::modifyList()}}. 43 | } 44 | \examples{ 45 | x <- list(x = 1:10, y = 4, z = list(a = 1, b = 2)) 46 | str(x) 47 | 48 | # Update values 49 | str(list_assign(x, a = 1)) 50 | 51 | # Replace values 52 | str(list_assign(x, z = 5)) 53 | str(list_assign(x, z = NULL)) 54 | str(list_assign(x, z = list(a = 1:5))) 55 | 56 | # Replace recursively with list_modify(), leaving the other elements of z alone 57 | str(list_modify(x, z = list(a = 1:5))) 58 | 59 | # Remove values 60 | str(list_assign(x, z = zap())) 61 | 62 | # Combine values with list_merge() 63 | str(list_merge(x, x = 11, z = list(a = 2:5, c = 3))) 64 | 65 | # All these functions support dynamic dots features. Use !!! to splice 66 | # a list of arguments: 67 | l <- list(new = 1, y = zap(), z = 5) 68 | str(list_assign(x, !!!l)) 69 | } 70 | -------------------------------------------------------------------------------- /man/list_c.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/list-combine.R 3 | \name{list_c} 4 | \alias{list_c} 5 | \alias{list_cbind} 6 | \alias{list_rbind} 7 | \title{Combine list elements into a single data structure} 8 | \usage{ 9 | list_c(x, ..., ptype = NULL) 10 | 11 | list_cbind( 12 | x, 13 | ..., 14 | name_repair = c("unique", "universal", "check_unique"), 15 | size = NULL 16 | ) 17 | 18 | list_rbind(x, ..., names_to = rlang::zap(), ptype = NULL) 19 | } 20 | \arguments{ 21 | \item{x}{A list. For \code{list_rbind()} and \code{list_cbind()} the list must 22 | only contain only data frames or \code{NULL}.} 23 | 24 | \item{...}{These dots are for future extensions and must be empty.} 25 | 26 | \item{ptype}{An optional prototype to ensure that the output type is always 27 | the same.} 28 | 29 | \item{name_repair}{One of \code{"unique"}, \code{"universal"}, or \code{"check_unique"}. 30 | See \code{\link[vctrs:vec_as_names]{vctrs::vec_as_names()}} for the meaning of these options.} 31 | 32 | \item{size}{An optional integer size to ensure that every input has the 33 | same size (i.e. number of rows).} 34 | 35 | \item{names_to}{By default, \code{names(x)} are lost. To keep them, supply a 36 | string to \code{names_to} and the names will be saved into a column with that 37 | name. If \code{names_to} is supplied and \code{x} is not named, the position of 38 | the elements will be used instead of the names.} 39 | } 40 | \description{ 41 | \itemize{ 42 | \item \code{list_c()} combines elements into a vector by concatenating them together 43 | with \code{\link[vctrs:vec_c]{vctrs::vec_c()}}. 44 | \item \code{list_rbind()} combines elements into a data frame by row-binding them 45 | together with \code{\link[vctrs:vec_bind]{vctrs::vec_rbind()}}. 46 | \item \code{list_cbind()} combines elements into a data frame by column-binding them 47 | together with \code{\link[vctrs:vec_bind]{vctrs::vec_cbind()}}. 48 | } 49 | } 50 | \examples{ 51 | x1 <- list(a = 1, b = 2, c = 3) 52 | list_c(x1) 53 | 54 | x2 <- list( 55 | a = data.frame(x = 1:2), 56 | b = data.frame(y = "a") 57 | ) 58 | list_rbind(x2) 59 | list_rbind(x2, names_to = "id") 60 | list_rbind(unname(x2), names_to = "id") 61 | 62 | list_cbind(x2) 63 | } 64 | -------------------------------------------------------------------------------- /man/list_flatten.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/list-flatten.R 3 | \name{list_flatten} 4 | \alias{list_flatten} 5 | \title{Flatten a list} 6 | \usage{ 7 | list_flatten( 8 | x, 9 | ..., 10 | name_spec = "{outer}_{inner}", 11 | name_repair = c("minimal", "unique", "check_unique", "universal") 12 | ) 13 | } 14 | \arguments{ 15 | \item{x}{A list.} 16 | 17 | \item{...}{These dots are for future extensions and must be empty.} 18 | 19 | \item{name_spec}{If both inner and outer names are present, control 20 | how they are combined. Should be a glue specification that uses 21 | variables \code{inner} and \code{outer}.} 22 | 23 | \item{name_repair}{One of \code{"minimal"}, \code{"unique"}, \code{"universal"}, or 24 | \code{"check_unique"}. See \code{\link[vctrs:vec_as_names]{vctrs::vec_as_names()}} for the meaning of these 25 | options.} 26 | } 27 | \value{ 28 | A list of the same type as \code{x}. The list might be shorter 29 | if \code{x} contains empty lists, the same length if it contains lists 30 | of length 1 or no sub-lists, or longer if it contains lists of 31 | length > 1. 32 | } 33 | \description{ 34 | Flattening a list removes a single layer of internal hierarchy, 35 | i.e. it inlines elements that are lists leaving non-lists alone. 36 | } 37 | \examples{ 38 | x <- list(1, list(2, 3), list(4, list(5))) 39 | x |> list_flatten() |> str() 40 | x |> list_flatten() |> list_flatten() |> str() 41 | 42 | # Flat lists are left as is 43 | list(1, 2, 3, 4, 5) |> list_flatten() |> str() 44 | 45 | # Empty lists will disappear 46 | list(1, list(), 2, list(3)) |> list_flatten() |> str() 47 | 48 | # Another way to see this is that it reduces the depth of the list 49 | x <- list( 50 | list(), 51 | list(list()) 52 | ) 53 | x |> pluck_depth() 54 | x |> list_flatten() |> pluck_depth() 55 | 56 | # Use name_spec to control how inner and outer names are combined 57 | x <- list(x = list(a = 1, b = 2), y = list(c = 1, d = 2)) 58 | x |> list_flatten() |> names() 59 | x |> list_flatten(name_spec = "{outer}") |> names() 60 | x |> list_flatten(name_spec = "{inner}") |> names() 61 | } 62 | -------------------------------------------------------------------------------- /man/list_simplify.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/list-simplify.R 3 | \name{list_simplify} 4 | \alias{list_simplify} 5 | \title{Simplify a list to an atomic or S3 vector} 6 | \usage{ 7 | list_simplify(x, ..., strict = TRUE, ptype = NULL) 8 | } 9 | \arguments{ 10 | \item{x}{A list.} 11 | 12 | \item{...}{These dots are for future extensions and must be empty.} 13 | 14 | \item{strict}{What should happen if simplification fails? If \code{TRUE} 15 | (the default) it will error. If \code{FALSE} and \code{ptype} is not supplied, 16 | it will return \code{x} unchanged.} 17 | 18 | \item{ptype}{An optional prototype to ensure that the output type is always 19 | the same.} 20 | } 21 | \value{ 22 | A vector the same length as \code{x}. 23 | } 24 | \description{ 25 | Simplification maintains a one-to-one correspondence between the input 26 | and output, implying that each element of \code{x} must contain a one element 27 | vector or a one-row data frame. If you don't want to maintain this 28 | correspondence, then you probably want either \code{\link[=list_c]{list_c()}}/\code{\link[=list_rbind]{list_rbind()}} or 29 | \code{\link[=list_flatten]{list_flatten()}}. 30 | } 31 | \examples{ 32 | list_simplify(list(1, 2, 3)) 33 | 34 | # Only works when vectors are length one and have compatible types: 35 | try(list_simplify(list(1, 2, 1:3))) 36 | try(list_simplify(list(1, 2, "x"))) 37 | 38 | # Unless you strict = FALSE, in which case you get the input back: 39 | list_simplify(list(1, 2, 1:3), strict = FALSE) 40 | list_simplify(list(1, 2, "x"), strict = FALSE) 41 | } 42 | -------------------------------------------------------------------------------- /man/macros/.gitignore: -------------------------------------------------------------------------------- 1 | examples.Rd 2 | -------------------------------------------------------------------------------- /man/map_raw.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/map-raw.R 3 | \name{map_raw} 4 | \alias{map_raw} 5 | \alias{map2_raw} 6 | \alias{imap_raw} 7 | \alias{pmap_raw} 8 | \alias{flatten_raw} 9 | \title{Functions that return raw vectors} 10 | \usage{ 11 | map_raw(.x, .f, ...) 12 | 13 | map2_raw(.x, .y, .f, ...) 14 | 15 | imap_raw(.x, .f, ...) 16 | 17 | pmap_raw(.l, .f, ...) 18 | 19 | flatten_raw(.x) 20 | } 21 | \description{ 22 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} 23 | 24 | These functions were deprecated in purrr 1.0.0 because they are of limited 25 | use and you can now use \code{map_vec()} instead. They are variants of \code{\link[=map]{map()}}, 26 | \code{\link[=map2]{map2()}}, \code{\link[=imap]{imap()}}, \code{\link[=pmap]{pmap()}}, and \code{\link[=flatten]{flatten()}} that return raw vectors. 27 | } 28 | \keyword{internal} 29 | -------------------------------------------------------------------------------- /man/modify_in.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/pluck-assign.R 3 | \name{modify_in} 4 | \alias{modify_in} 5 | \alias{assign_in} 6 | \title{Modify a pluck location} 7 | \usage{ 8 | modify_in(.x, .where, .f, ...) 9 | 10 | assign_in(x, where, value) 11 | } 12 | \arguments{ 13 | \item{.x, x}{A vector or environment} 14 | 15 | \item{.where, where}{A pluck location, as a numeric vector of 16 | positions, a character vector of names, or a list combining both. 17 | The location must exist in the data structure.} 18 | 19 | \item{.f}{A function to apply at the pluck location given by \code{.where}.} 20 | 21 | \item{...}{Arguments passed to \code{.f}.} 22 | 23 | \item{value}{A value to replace in \code{.x} at the pluck location. 24 | Use \code{zap()} to instead remove the element.} 25 | } 26 | \description{ 27 | \itemize{ 28 | \item \code{assign_in()} takes a data structure and a \link{pluck} location, 29 | assigns a value there, and returns the modified data structure. 30 | \item \code{modify_in()} applies a function to a pluck location, assigns the 31 | result back to that location with \code{\link[=assign_in]{assign_in()}}, and returns the 32 | modified data structure. 33 | } 34 | } 35 | \examples{ 36 | # Recall that pluck() returns a component of a data structure that 37 | # might be arbitrarily deep 38 | x <- list(list(bar = 1, foo = 2)) 39 | pluck(x, 1, "foo") 40 | 41 | # Use assign_in() to modify the pluck location: 42 | str(assign_in(x, list(1, "foo"), 100)) 43 | # Or zap to remove it 44 | str(assign_in(x, list(1, "foo"), zap())) 45 | 46 | # Like pluck(), this works even when the element (or its parents) don't exist 47 | pluck(x, 1, "baz") 48 | str(assign_in(x, list(2, "baz"), 100)) 49 | 50 | # modify_in() applies a function to that location and update the 51 | # element in place: 52 | modify_in(x, list(1, "foo"), \(x) x * 200) 53 | 54 | # Additional arguments are passed to the function in the ordinary way: 55 | modify_in(x, list(1, "foo"), `+`, 100) 56 | } 57 | \seealso{ 58 | \code{\link[=pluck]{pluck()}} 59 | } 60 | -------------------------------------------------------------------------------- /man/modify_tree.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/modify-tree.R 3 | \name{modify_tree} 4 | \alias{modify_tree} 5 | \title{Recursively modify a list} 6 | \usage{ 7 | modify_tree( 8 | x, 9 | ..., 10 | leaf = identity, 11 | is_node = NULL, 12 | pre = identity, 13 | post = identity 14 | ) 15 | } 16 | \arguments{ 17 | \item{x}{A list.} 18 | 19 | \item{...}{Reserved for future use. Must be empty} 20 | 21 | \item{leaf}{A function applied to each leaf.} 22 | 23 | \item{is_node}{A predicate function that determines whether an element is 24 | a node (by returning \code{TRUE}) or a leaf (by returning \code{FALSE}). The 25 | default value, \code{NULL}, treats simple lists as nodes and everything else 26 | (including richer objects like data frames and linear models) as leaves, 27 | using \code{\link[vctrs:obj_is_list]{vctrs::obj_is_list()}}. To recurse into all objects built on lists 28 | use \code{\link[=is.list]{is.list()}}.} 29 | 30 | \item{pre, post}{Functions applied to each node. \code{pre} is applied on the 31 | way "down", i.e. before the leaves are transformed with \code{leaf}, while 32 | \code{post} is applied on the way "up", i.e. after the leaves are transformed.} 33 | } 34 | \description{ 35 | \code{modify_tree()} allows you to recursively modify a list, supplying functions 36 | that either modify each leaf or each node (or both). 37 | } 38 | \examples{ 39 | x <- list(list(a = 2:1, c = list(b1 = 2), b = list(c2 = 3, c1 = 4))) 40 | x |> str() 41 | 42 | # Transform each leaf 43 | x |> modify_tree(leaf = \(x) x + 100) |> str() 44 | 45 | # Recursively sort the nodes 46 | sort_named <- function(x) { 47 | nms <- names(x) 48 | if (!is.null(nms)) { 49 | x[order(nms)] 50 | } else { 51 | x 52 | } 53 | } 54 | x |> modify_tree(post = sort_named) |> str() 55 | } 56 | \seealso{ 57 | Other modify variants: 58 | \code{\link{map_depth}()}, 59 | \code{\link{modify}()} 60 | } 61 | \concept{modify variants} 62 | -------------------------------------------------------------------------------- /man/negate.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/adverb-negate.R 3 | \name{negate} 4 | \alias{negate} 5 | \title{Negate a predicate function so it selects what it previously rejected} 6 | \usage{ 7 | negate(.p) 8 | } 9 | \arguments{ 10 | \item{.p}{A predicate function (i.e. a function that returns either \code{TRUE} 11 | or \code{FALSE}) specified in one of the following ways: 12 | \itemize{ 13 | \item A named function, e.g. \code{is.character}. 14 | \item An anonymous function, e.g. \verb{\\(x) all(x < 0)} or \code{function(x) all(x < 0)}. 15 | \item A formula, e.g. \code{~ all(.x < 0)}. You must use \code{.x} to refer to the first 16 | argument). Only recommended if you require backward compatibility with 17 | older versions of R. 18 | }} 19 | } 20 | \value{ 21 | A new predicate function. 22 | } 23 | \description{ 24 | Negating a function changes \code{TRUE} to \code{FALSE} and \code{FALSE} to \code{TRUE}. 25 | } 26 | \section{Adverbs}{ 27 | This function is called an adverb because it modifies the effect of a 28 | function (a verb). If you'd like to include a function created an adverb 29 | in a package, be sure to read \link{faq-adverbs-export}. 30 | } 31 | 32 | \examples{ 33 | x <- list(x = 1:10, y = rbernoulli(10), z = letters) 34 | x |> keep(is.numeric) |> names() 35 | x |> keep(negate(is.numeric)) |> names() 36 | # Same as 37 | x |> discard(is.numeric) 38 | } 39 | \seealso{ 40 | Other adverbs: 41 | \code{\link{auto_browse}()}, 42 | \code{\link{compose}()}, 43 | \code{\link{insistently}()}, 44 | \code{\link{partial}()}, 45 | \code{\link{possibly}()}, 46 | \code{\link{quietly}()}, 47 | \code{\link{safely}()}, 48 | \code{\link{slowly}()} 49 | } 50 | \concept{adverbs} 51 | -------------------------------------------------------------------------------- /man/pipe.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/reexport-pipe.R 3 | \name{\%>\%} 4 | \alias{\%>\%} 5 | \title{Pipe operator} 6 | \usage{ 7 | lhs \%>\% rhs 8 | } 9 | \description{ 10 | Pipe operator 11 | } 12 | \keyword{internal} 13 | -------------------------------------------------------------------------------- /man/pluck_depth.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/pluck-depth.R 3 | \name{pluck_depth} 4 | \alias{pluck_depth} 5 | \alias{vec_depth} 6 | \title{Compute the depth of a vector} 7 | \usage{ 8 | pluck_depth(x, is_node = NULL) 9 | } 10 | \arguments{ 11 | \item{x}{A vector} 12 | 13 | \item{is_node}{Optionally override the default criteria for determine an 14 | element can be recursed within. The default matches the behaviour of 15 | \code{pluck()} which can recurse into lists and expressions.} 16 | } 17 | \value{ 18 | An integer. 19 | } 20 | \description{ 21 | The depth of a vector is how many levels that you can index/pluck into it. 22 | \code{pluck_depth()} was previously called \code{vec_depth()}. 23 | } 24 | \examples{ 25 | x <- list( 26 | list(), 27 | list(list()), 28 | list(list(list(1))) 29 | ) 30 | pluck_depth(x) 31 | x |> map_int(pluck_depth) 32 | } 33 | -------------------------------------------------------------------------------- /man/possibly.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/adverb-possibly.R 3 | \name{possibly} 4 | \alias{possibly} 5 | \title{Wrap a function to return a value instead of an error} 6 | \usage{ 7 | possibly(.f, otherwise = NULL, quiet = TRUE) 8 | } 9 | \arguments{ 10 | \item{.f}{A function to modify, specified in one of the following ways: 11 | \itemize{ 12 | \item A named function, e.g. \code{mean}. 13 | \item An anonymous function, e.g. \verb{\\(x) x + 1} or \code{function(x) x + 1}. 14 | \item A formula, e.g. \code{~ .x + 1}. Only recommended if you require backward 15 | compatibility with older versions of R. 16 | }} 17 | 18 | \item{otherwise}{Default value to use when an error occurs.} 19 | 20 | \item{quiet}{Hide errors (\code{TRUE}, the default), or display them 21 | as they occur?} 22 | } 23 | \value{ 24 | A function that takes the same arguments as \code{.f}, but returns 25 | a different value, as described above. 26 | } 27 | \description{ 28 | Create a modified version of \code{.f} that return a default value (\code{otherwise}) 29 | whenever an error occurs. 30 | } 31 | \section{Adverbs}{ 32 | This function is called an adverb because it modifies the effect of a 33 | function (a verb). If you'd like to include a function created an adverb 34 | in a package, be sure to read \link{faq-adverbs-export}. 35 | } 36 | 37 | \examples{ 38 | # To replace errors with a default value, use possibly(). 39 | list("a", 10, 100) |> 40 | map_dbl(possibly(log, NA_real_)) 41 | 42 | # The default, NULL, will be discarded with `list_c()` 43 | list("a", 10, 100) |> 44 | map(possibly(log)) |> 45 | list_c() 46 | } 47 | \seealso{ 48 | Other adverbs: 49 | \code{\link{auto_browse}()}, 50 | \code{\link{compose}()}, 51 | \code{\link{insistently}()}, 52 | \code{\link{negate}()}, 53 | \code{\link{partial}()}, 54 | \code{\link{quietly}()}, 55 | \code{\link{safely}()}, 56 | \code{\link{slowly}()} 57 | } 58 | \concept{adverbs} 59 | -------------------------------------------------------------------------------- /man/prepend.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/deprec-prepend.R 3 | \name{prepend} 4 | \alias{prepend} 5 | \title{Prepend a vector} 6 | \usage{ 7 | prepend(x, values, before = NULL) 8 | } 9 | \arguments{ 10 | \item{x}{the vector to be modified.} 11 | 12 | \item{values}{to be included in the modified vector.} 13 | 14 | \item{before}{a subscript, before which the values are to be appended. If 15 | \code{NULL}, values will be appended at the beginning even for \code{x} of length 0.} 16 | } 17 | \value{ 18 | A merged vector. 19 | } 20 | \description{ 21 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} 22 | 23 | This function was deprecated in purrr 1.0.0 because it's not related to the 24 | core purpose of purrr. 25 | 26 | This is a companion to \code{\link[=append]{append()}} to help merging two 27 | lists or atomic vectors. \code{prepend()} is a clearer semantic 28 | signal than \code{c()} that a vector is to be merged at the beginning of 29 | another, especially in a pipe chain. 30 | } 31 | \examples{ 32 | x <- as.list(1:3) 33 | 34 | x |> append("a") 35 | x |> prepend("a") 36 | x |> prepend(list("a", "b"), before = 3) 37 | prepend(list(), x) 38 | } 39 | \keyword{internal} 40 | -------------------------------------------------------------------------------- /man/purrr-package.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/package-purrr.R 3 | \docType{package} 4 | \name{purrr-package} 5 | \alias{purrr} 6 | \alias{purrr-package} 7 | \title{purrr: Functional Programming Tools} 8 | \description{ 9 | \if{html}{\figure{logo.png}{options: style='float: right' alt='logo' width='120'}} 10 | 11 | A complete and consistent functional programming toolkit for R. 12 | } 13 | \seealso{ 14 | Useful links: 15 | \itemize{ 16 | \item \url{https://purrr.tidyverse.org/} 17 | \item \url{https://github.com/tidyverse/purrr} 18 | \item Report bugs at \url{https://github.com/tidyverse/purrr/issues} 19 | } 20 | 21 | } 22 | \author{ 23 | \strong{Maintainer}: Hadley Wickham \email{hadley@posit.co} (\href{https://orcid.org/0000-0003-4757-117X}{ORCID}) 24 | 25 | Authors: 26 | \itemize{ 27 | \item Lionel Henry \email{lionel@posit.co} 28 | } 29 | 30 | Other contributors: 31 | \itemize{ 32 | \item Posit Software, PBC (https://ror.org/03wc8by49) [copyright holder, funder] 33 | } 34 | 35 | } 36 | \keyword{internal} 37 | -------------------------------------------------------------------------------- /man/quietly.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/adverb-quietly.R 3 | \name{quietly} 4 | \alias{quietly} 5 | \title{Wrap a function to capture side-effects} 6 | \usage{ 7 | quietly(.f) 8 | } 9 | \arguments{ 10 | \item{.f}{A function to modify, specified in one of the following ways: 11 | \itemize{ 12 | \item A named function, e.g. \code{mean}. 13 | \item An anonymous function, e.g. \verb{\\(x) x + 1} or \code{function(x) x + 1}. 14 | \item A formula, e.g. \code{~ .x + 1}. Only recommended if you require backward 15 | compatibility with older versions of R. 16 | }} 17 | } 18 | \value{ 19 | A function that takes the same arguments as \code{.f}, but returns 20 | a different value, as described above. 21 | } 22 | \description{ 23 | Create a modified version of \code{.f} that captures side-effects along with 24 | the return value of the function and returns a list containing 25 | the \code{result}, \code{output}, \code{messages} and \code{warnings}. 26 | } 27 | \section{Adverbs}{ 28 | This function is called an adverb because it modifies the effect of a 29 | function (a verb). If you'd like to include a function created an adverb 30 | in a package, be sure to read \link{faq-adverbs-export}. 31 | } 32 | 33 | \examples{ 34 | f <- function() { 35 | print("Hi!") 36 | message("Hello") 37 | warning("How are ya?") 38 | "Gidday" 39 | } 40 | f() 41 | 42 | f_quiet <- quietly(f) 43 | str(f_quiet()) 44 | } 45 | \seealso{ 46 | Other adverbs: 47 | \code{\link{auto_browse}()}, 48 | \code{\link{compose}()}, 49 | \code{\link{insistently}()}, 50 | \code{\link{negate}()}, 51 | \code{\link{partial}()}, 52 | \code{\link{possibly}()}, 53 | \code{\link{safely}()}, 54 | \code{\link{slowly}()} 55 | } 56 | \concept{adverbs} 57 | -------------------------------------------------------------------------------- /man/rate-helpers.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/rate.R 3 | \name{rate-helpers} 4 | \alias{rate-helpers} 5 | \alias{rate_delay} 6 | \alias{rate_backoff} 7 | \alias{is_rate} 8 | \title{Create delaying rate settings} 9 | \usage{ 10 | rate_delay(pause = 1, max_times = Inf) 11 | 12 | rate_backoff( 13 | pause_base = 1, 14 | pause_cap = 60, 15 | pause_min = 1, 16 | max_times = 3, 17 | jitter = TRUE 18 | ) 19 | 20 | is_rate(x) 21 | } 22 | \arguments{ 23 | \item{pause}{Delay between attempts in seconds.} 24 | 25 | \item{max_times}{Maximum number of requests to attempt.} 26 | 27 | \item{pause_base, pause_cap}{\code{rate_backoff()} uses an exponential 28 | back-off so that each request waits \code{pause_base * 2^i} seconds, 29 | up to a maximum of \code{pause_cap} seconds.} 30 | 31 | \item{pause_min}{Minimum time to wait in the backoff; generally 32 | only necessary if you need pauses less than one second (which may 33 | not be kind to the server, use with caution!).} 34 | 35 | \item{jitter}{Whether to introduce a random jitter in the waiting time.} 36 | 37 | \item{x}{An object to test.} 38 | } 39 | \description{ 40 | These helpers create rate settings that you can pass to \code{\link[=insistently]{insistently()}} and 41 | \code{\link[=slowly]{slowly()}}. You can also use them in your own functions with \code{\link[=rate_sleep]{rate_sleep()}}. 42 | } 43 | \examples{ 44 | # A delay rate waits the same amount of time: 45 | rate <- rate_delay(0.02) 46 | for (i in 1:3) rate_sleep(rate, quiet = FALSE) 47 | 48 | # A backoff rate waits exponentially longer each time, with random 49 | # jitter by default: 50 | rate <- rate_backoff(pause_base = 0.2, pause_min = 0.005) 51 | for (i in 1:3) rate_sleep(rate, quiet = FALSE) 52 | } 53 | -------------------------------------------------------------------------------- /man/rate_sleep.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/rate.R 3 | \name{rate_sleep} 4 | \alias{rate_sleep} 5 | \alias{rate_reset} 6 | \title{Wait for a given time} 7 | \usage{ 8 | rate_sleep(rate, quiet = TRUE) 9 | 10 | rate_reset(rate) 11 | } 12 | \arguments{ 13 | \item{rate}{A \link[=rate_backoff]{rate} object determining the waiting time.} 14 | 15 | \item{quiet}{If \code{FALSE}, prints a message displaying how long until 16 | the next request.} 17 | } 18 | \description{ 19 | If the rate's internal counter exceeds the maximum number of times 20 | it is allowed to sleep, \code{rate_sleep()} throws an error of class 21 | \code{purrr_error_rate_excess}. 22 | } 23 | \details{ 24 | Call \code{rate_reset()} to reset the internal rate counter to 0. 25 | } 26 | \seealso{ 27 | \code{\link[=rate_backoff]{rate_backoff()}}, \code{\link[=insistently]{insistently()}} 28 | } 29 | \keyword{internal} 30 | -------------------------------------------------------------------------------- /man/rbernoulli.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/deprec-utils.R 3 | \name{rbernoulli} 4 | \alias{rbernoulli} 5 | \title{Generate random sample from a Bernoulli distribution} 6 | \usage{ 7 | rbernoulli(n, p = 0.5) 8 | } 9 | \arguments{ 10 | \item{n}{Number of samples} 11 | 12 | \item{p}{Probability of getting \code{TRUE}} 13 | } 14 | \value{ 15 | A logical vector 16 | } 17 | \description{ 18 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} 19 | 20 | This function was deprecated in purrr 1.0.0 because it's not related to the 21 | core purpose of purrr. 22 | } 23 | \examples{ 24 | rbernoulli(10) 25 | rbernoulli(100, 0.1) 26 | } 27 | \keyword{internal} 28 | -------------------------------------------------------------------------------- /man/rdunif.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/deprec-utils.R 3 | \name{rdunif} 4 | \alias{rdunif} 5 | \title{Generate random sample from a discrete uniform distribution} 6 | \usage{ 7 | rdunif(n, b, a = 1) 8 | } 9 | \arguments{ 10 | \item{n}{Number of samples to draw.} 11 | 12 | \item{a, b}{Range of the distribution (inclusive).} 13 | } 14 | \description{ 15 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} 16 | 17 | This function was deprecated in purrr 1.0.0 because it's not related to the 18 | core purpose of purrr. 19 | } 20 | \examples{ 21 | table(rdunif(1e3, 10)) 22 | table(rdunif(1e3, 10, -5)) 23 | } 24 | \keyword{internal} 25 | -------------------------------------------------------------------------------- /man/rerun.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/deprec-rerun.R 3 | \name{rerun} 4 | \alias{rerun} 5 | \title{Re-run expressions multiple times} 6 | \usage{ 7 | rerun(.n, ...) 8 | } 9 | \arguments{ 10 | \item{.n}{Number of times to run expressions} 11 | 12 | \item{...}{Expressions to re-run.} 13 | } 14 | \value{ 15 | A list of length \code{.n}. Each element of \code{...} will be 16 | re-run once for each \code{.n}. 17 | 18 | There is one special case: if there's a single unnamed input, the second 19 | level list will be dropped. In this case, \code{rerun(n, x)} behaves like 20 | \code{replicate(n, x, simplify = FALSE)}. 21 | } 22 | \description{ 23 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} 24 | 25 | This function was deprecated in purrr 1.0.0 because we believe that NSE 26 | functions are not a good fit for purrr. Also, \code{rerun(n, x)} can just as 27 | easily be expressed as \verb{map(1:n, \\(i) x)} 28 | 29 | \code{rerun()} is a convenient way of generating sample data. It works similarly to 30 | \code{\link{replicate}(..., simplify = FALSE)}. 31 | } 32 | \examples{ 33 | # old 34 | 5 |> rerun(rnorm(5)) |> str() 35 | # new 36 | 1:5 |> map(\(i) rnorm(5)) |> str() 37 | 38 | # old 39 | 5 |> 40 | rerun(x = rnorm(5), y = rnorm(5)) |> 41 | map_dbl(\(l) cor(l$x, l$y)) 42 | # new 43 | 1:5 |> 44 | map(\(i) list(x = rnorm(5), y = rnorm(5))) |> 45 | map_dbl(\(l) cor(l$x, l$y)) 46 | } 47 | \keyword{internal} 48 | -------------------------------------------------------------------------------- /man/safely.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/adverb-safely.R 3 | \name{safely} 4 | \alias{safely} 5 | \title{Wrap a function to capture errors} 6 | \usage{ 7 | safely(.f, otherwise = NULL, quiet = TRUE) 8 | } 9 | \arguments{ 10 | \item{.f}{A function to modify, specified in one of the following ways: 11 | \itemize{ 12 | \item A named function, e.g. \code{mean}. 13 | \item An anonymous function, e.g. \verb{\\(x) x + 1} or \code{function(x) x + 1}. 14 | \item A formula, e.g. \code{~ .x + 1}. Only recommended if you require backward 15 | compatibility with older versions of R. 16 | }} 17 | 18 | \item{otherwise}{Default value to use when an error occurs.} 19 | 20 | \item{quiet}{Hide errors (\code{TRUE}, the default), or display them 21 | as they occur?} 22 | } 23 | \value{ 24 | A function that takes the same arguments as \code{.f}, but returns 25 | a different value, as described above. 26 | } 27 | \description{ 28 | Creates a modified version of \code{.f} that always succeeds. It returns a list 29 | with components \code{result} and \code{error}. If the function succeeds, \code{result} 30 | contains the returned value and \code{error} is \code{NULL}. If an error occurred, 31 | \code{error} is an \code{error} object and \code{result} is either \code{NULL} or \code{otherwise}. 32 | } 33 | \section{Adverbs}{ 34 | This function is called an adverb because it modifies the effect of a 35 | function (a verb). If you'd like to include a function created an adverb 36 | in a package, be sure to read \link{faq-adverbs-export}. 37 | } 38 | 39 | \examples{ 40 | safe_log <- safely(log) 41 | safe_log(10) 42 | safe_log("a") 43 | 44 | list("a", 10, 100) |> 45 | map(safe_log) |> 46 | transpose() 47 | 48 | # This is a bit easier to work with if you supply a default value 49 | # of the same type and use the simplify argument to transpose(): 50 | safe_log <- safely(log, otherwise = NA_real_) 51 | list("a", 10, 100) |> 52 | map(safe_log) |> 53 | transpose() |> 54 | simplify_all() 55 | } 56 | \seealso{ 57 | Other adverbs: 58 | \code{\link{auto_browse}()}, 59 | \code{\link{compose}()}, 60 | \code{\link{insistently}()}, 61 | \code{\link{negate}()}, 62 | \code{\link{partial}()}, 63 | \code{\link{possibly}()}, 64 | \code{\link{quietly}()}, 65 | \code{\link{slowly}()} 66 | } 67 | \concept{adverbs} 68 | -------------------------------------------------------------------------------- /man/slowly.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/adverb-slowly.R 3 | \name{slowly} 4 | \alias{slowly} 5 | \title{Wrap a function to wait between executions} 6 | \usage{ 7 | slowly(f, rate = rate_delay(), quiet = TRUE) 8 | } 9 | \arguments{ 10 | \item{f}{A function to modify, specified in one of the following ways: 11 | \itemize{ 12 | \item A named function, e.g. \code{mean}. 13 | \item An anonymous function, e.g. \verb{\\(x) x + 1} or \code{function(x) x + 1}. 14 | \item A formula, e.g. \code{~ .x + 1}. Only recommended if you require backward 15 | compatibility with older versions of R. 16 | }} 17 | 18 | \item{rate}{A \link[=rate-helpers]{rate} object. Defaults to a constant delay.} 19 | 20 | \item{quiet}{Hide errors (\code{TRUE}, the default), or display them 21 | as they occur?} 22 | } 23 | \value{ 24 | A function that takes the same arguments as \code{.f}, but returns 25 | a different value, as described above. 26 | } 27 | \description{ 28 | \code{slowly()} takes a function and modifies it to wait a given 29 | amount of time between each call. 30 | } 31 | \section{Adverbs}{ 32 | This function is called an adverb because it modifies the effect of a 33 | function (a verb). If you'd like to include a function created an adverb 34 | in a package, be sure to read \link{faq-adverbs-export}. 35 | } 36 | 37 | \examples{ 38 | # For these example, we first create a custom rate 39 | # with a low waiting time between attempts: 40 | rate <- rate_delay(0.1) 41 | 42 | # slowly() causes a function to sleep for a given time between calls: 43 | slow_runif <- slowly(\(x) runif(1), rate = rate, quiet = FALSE) 44 | out <- map(1:5, slow_runif) 45 | } 46 | \seealso{ 47 | Other adverbs: 48 | \code{\link{auto_browse}()}, 49 | \code{\link{compose}()}, 50 | \code{\link{insistently}()}, 51 | \code{\link{negate}()}, 52 | \code{\link{partial}()}, 53 | \code{\link{possibly}()}, 54 | \code{\link{quietly}()}, 55 | \code{\link{safely}()} 56 | } 57 | \concept{adverbs} 58 | -------------------------------------------------------------------------------- /man/splice.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/deprec-splice.R 3 | \name{splice} 4 | \alias{splice} 5 | \title{Splice objects and lists of objects into a list} 6 | \usage{ 7 | splice(...) 8 | } 9 | \arguments{ 10 | \item{...}{Objects to concatenate.} 11 | } 12 | \value{ 13 | A list. 14 | } 15 | \description{ 16 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} 17 | 18 | This function was deprecated in purrr 1.0.0 because we no longer believe that 19 | this style of implicit/automatic splicing is a good idea; instead use 20 | \code{rlang::list2()} + \verb{!!!} or \code{\link[=list_flatten]{list_flatten()}}. 21 | 22 | \code{splice()} splices all arguments into a list. Non-list objects and lists 23 | with a S3 class are encapsulated in a list before concatenation. 24 | } 25 | \examples{ 26 | inputs <- list(arg1 = "a", arg2 = "b") 27 | 28 | # splice() concatenates the elements of inputs with arg3 29 | splice(inputs, arg3 = c("c1", "c2")) |> str() 30 | list(inputs, arg3 = c("c1", "c2")) |> str() 31 | c(inputs, arg3 = c("c1", "c2")) |> str() 32 | } 33 | \keyword{internal} 34 | -------------------------------------------------------------------------------- /man/update_list.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/list-modify.R 3 | \name{update_list} 4 | \alias{update_list} 5 | \title{Update a list with formulas} 6 | \usage{ 7 | update_list(.x, ...) 8 | } 9 | \arguments{ 10 | \item{.x}{List to modify.} 11 | 12 | \item{...}{New values of a list. Use \code{zap()} to remove values. 13 | 14 | These values should be either all named or all unnamed. When 15 | inputs are all named, they are matched to \code{.x} by name. When they 16 | are all unnamed, they are matched by position. 17 | 18 | \link[rlang:dyn-dots]{Dynamic dots} are supported. In particular, if your 19 | replacement values are stored in a list, you can splice that in with 20 | \verb{!!!}.} 21 | } 22 | \description{ 23 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} 24 | 25 | \code{update_list()} was deprecated in purrr 1.0.0, because we no longer believe 26 | that functions that use NSE are a good fit for purrr. 27 | 28 | \code{update_list()} handles formulas and quosures that can refer to 29 | values existing within the input list. This function is deprecated 30 | because we no longer believe that functions that use tidy evaluation are 31 | a good fit for purrr. 32 | } 33 | \keyword{internal} 34 | -------------------------------------------------------------------------------- /man/when.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/deprec-when.R 3 | \name{when} 4 | \alias{when} 5 | \title{Match/validate a set of conditions for an object and continue with the action 6 | associated with the first valid match.} 7 | \usage{ 8 | when(., ...) 9 | } 10 | \arguments{ 11 | \item{.}{the value to match against} 12 | 13 | \item{...}{formulas; each containing a condition as LHS and an action as RHS. 14 | named arguments will define additional values.} 15 | } 16 | \value{ 17 | The value resulting from the action of the first valid 18 | match/condition is returned. If no matches are found, and no default is 19 | given, NULL will be returned. 20 | 21 | Validity of the conditions are tested with \code{isTRUE}, or equivalently 22 | with \code{identical(condition, TRUE)}. 23 | In other words conditions resulting in more than one logical will never 24 | be valid. Note that the input value is always treated as a single object, 25 | as opposed to the \code{ifelse} function. 26 | } 27 | \description{ 28 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} 29 | 30 | This function was deprecated in purrr 1.0.0 because it's not related to the 31 | core purpose of purrr. You can pull your code out of a pipe and use regular 32 | \code{if}/\verb{else} statements instead. 33 | 34 | \code{when()} is a flavour of pattern matching (or an if-else abstraction) in 35 | which a value is matched against a sequence of condition-action sets. When a 36 | valid match/condition is found the action is executed and the result of the 37 | action is returned. 38 | } 39 | \examples{ 40 | 1:10 |> 41 | when( 42 | sum(.) <= 50 ~ sum(.), 43 | sum(.) <= 100 ~ sum(.)/2, 44 | ~ 0 45 | ) 46 | 47 | # now 48 | x <- 1:10 49 | if (sum(x) < 10) { 50 | sum(x) 51 | } else if (sum(x) < 100) { 52 | sum(x) / 2 53 | } else { 54 | 0 55 | } 56 | } 57 | \keyword{internal} 58 | -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/purrr/175307f88e110a6d2e1f029df65cd6821625678f/pkgdown/favicon/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/purrr/175307f88e110a6d2e1f029df65cd6821625678f/pkgdown/favicon/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/purrr/175307f88e110a6d2e1f029df65cd6821625678f/pkgdown/favicon/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/purrr/175307f88e110a6d2e1f029df65cd6821625678f/pkgdown/favicon/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/purrr/175307f88e110a6d2e1f029df65cd6821625678f/pkgdown/favicon/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/purrr/175307f88e110a6d2e1f029df65cd6821625678f/pkgdown/favicon/apple-touch-icon.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/purrr/175307f88e110a6d2e1f029df65cd6821625678f/pkgdown/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/purrr/175307f88e110a6d2e1f029df65cd6821625678f/pkgdown/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/purrr/175307f88e110a6d2e1f029df65cd6821625678f/pkgdown/favicon/favicon.ico -------------------------------------------------------------------------------- /purrr.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | ProjectId: 7599ac37-3c41-46be-af39-1e11a14300d2 3 | 4 | RestoreWorkspace: No 5 | SaveWorkspace: No 6 | AlwaysSaveHistory: Default 7 | 8 | EnableCodeIndexing: Yes 9 | UseSpacesForTab: Yes 10 | NumSpacesForTab: 2 11 | Encoding: UTF-8 12 | 13 | RnwWeave: Sweave 14 | LaTeX: pdfLaTeX 15 | 16 | AutoAppendNewline: Yes 17 | StripTrailingWhitespace: Yes 18 | 19 | BuildType: Package 20 | PackageUseDevtools: Yes 21 | PackageInstallArgs: --no-multiarch --with-keep.source 22 | PackageRoxygenize: rd,collate,namespace 23 | -------------------------------------------------------------------------------- /revdep/.gitignore: -------------------------------------------------------------------------------- 1 | checks/ 2 | logs/ 3 | data.sqlite 4 | checks 5 | library 6 | checks.noindex 7 | library.noindex 8 | cloud.noindex 9 | *.html 10 | -------------------------------------------------------------------------------- /revdep/cran.md: -------------------------------------------------------------------------------- 1 | ## revdepcheck results 2 | 3 | We checked 1943 reverse dependencies (1937 from CRAN + 6 from Bioconductor), comparing R CMD check results across CRAN and dev versions of this package. 4 | 5 | * We saw 2 new problems 6 | * We failed to check 45 packages 7 | 8 | Issues with CRAN packages are summarised below. 9 | 10 | ### New problems 11 | (This reports the first line of each new failure) 12 | 13 | * meta 14 | checking installed package size ... NOTE 15 | 16 | * waywiser 17 | checking running R code from vignettes ... ERROR 18 | 19 | ### Failed to check 20 | 21 | * AovBay (NA) 22 | * arealDB (NA) 23 | * autoReg (NA) 24 | * bayesCT (NA) 25 | * bspcov (NA) 26 | * censored (NA) 27 | * CGPfunctions (NA) 28 | * CSCNet (NA) 29 | * dartR.base (NA) 30 | * dartR.popgen (NA) 31 | * deeptrafo (NA) 32 | * DR.SC (NA) 33 | * epizootic (NA) 34 | * GseaVis (NA) 35 | * hettx (NA) 36 | * immcp (NA) 37 | * invivoPKfit (NA) 38 | * jsmodule (NA) 39 | * lnmixsurv (NA) 40 | * lsirm12pl (NA) 41 | * metajam (NA) 42 | * miWQS (NA) 43 | * multinma (NA) 44 | * nesRdata (NA) 45 | * obliqueRSF (NA) 46 | * ontologics (NA) 47 | * OVtool (NA) 48 | * pammtools (NA) 49 | * pathwayTMB (NA) 50 | * pencal (NA) 51 | * quid (NA) 52 | * rdflib (NA) 53 | * robber (NA) 54 | * RVA (NA) 55 | * scCustomize (NA) 56 | * scpi (NA) 57 | * SCpubr (NA) 58 | * SEERaBomb (NA) 59 | * SimplyAgree (NA) 60 | * ssdGSA (NA) 61 | * SSHAARP (NA) 62 | * stabiliser (NA) 63 | * tidyseurat (NA) 64 | * TriDimRegression (NA) 65 | * WRTDStidal (NA) 66 | -------------------------------------------------------------------------------- /revdep/email.yml: -------------------------------------------------------------------------------- 1 | release_date: ??? 2 | rel_release_date: ??? 3 | my_news_url: ??? 4 | release_version: ??? 5 | release_details: ??? 6 | -------------------------------------------------------------------------------- /revdep/problems.md: -------------------------------------------------------------------------------- 1 | # meta 2 | 3 |
4 | 5 | * Version: 8.0-2 6 | * GitHub: https://github.com/guido-s/meta 7 | * Source code: https://github.com/cran/meta 8 | * Date/Publication: 2025-01-21 19:20:02 UTC 9 | * Number of recursive dependencies: 96 10 | 11 | Run `revdepcheck::cloud_details(, "meta")` for more info 12 | 13 |
14 | 15 | ## Newly broken 16 | 17 | * checking installed package size ... NOTE 18 | ``` 19 | installed size is 5.6Mb 20 | sub-directories of 1Mb or more: 21 | R 3.5Mb 22 | help 1.5Mb 23 | ``` 24 | 25 | ## In both 26 | 27 | * checking Rd cross-references ... NOTE 28 | ``` 29 | Packages unavailable to check Rd xrefs: ‘metasens’, ‘robumeta’ 30 | ``` 31 | 32 | # waywiser 33 | 34 |
35 | 36 | * Version: 0.6.0 37 | * GitHub: https://github.com/ropensci/waywiser 38 | * Source code: https://github.com/cran/waywiser 39 | * Date/Publication: 2024-06-27 19:10:03 UTC 40 | * Number of recursive dependencies: 172 41 | 42 | Run `revdepcheck::cloud_details(, "waywiser")` for more info 43 | 44 |
45 | 46 | ## Newly broken 47 | 48 | * checking running R code from vignettes ... ERROR 49 | ``` 50 | Errors in running code in vignettes: 51 | when running code in ‘multi-scale-assessment.Rmd’ 52 | ... 53 | | 54 | |================= | 25% 55 | | 56 | |================== | 25%Warning in unzip(file_loc, exdir = tmp) : 57 | error 1 in extracting from zip file 58 | Cannot open layer tl_2022_us_county 59 | 60 | When sourcing ‘multi-scale-assessment.R’: 61 | Error: Opening layer failed. 62 | Execution halted 63 | 64 | ‘multi-scale-assessment.Rmd’ using ‘UTF-8’... failed 65 | ‘residual-autocorrelation.Rmd’ using ‘UTF-8’... OK 66 | ‘waywiser.Rmd’ using ‘UTF-8’... OK 67 | ``` 68 | 69 | ## In both 70 | 71 | * checking data for non-ASCII characters ... NOTE 72 | ``` 73 | Note: found 1 marked UTF-8 string 74 | ``` 75 | 76 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.so 3 | *.dll 4 | -------------------------------------------------------------------------------- /src/Makevars: -------------------------------------------------------------------------------- 1 | PKG_CFLAGS = $(C_VISIBILITY) 2 | -------------------------------------------------------------------------------- /src/backports.c: -------------------------------------------------------------------------------- 1 | #define R_NO_REMAP 2 | #include 3 | #include 4 | #include 5 | 6 | #if defined(R_VERSION) && R_VERSION < R_Version(3, 2, 0) 7 | SEXP Rf_installChar(SEXP x) { 8 | return Rf_install(CHAR(x)); 9 | } 10 | #endif 11 | 12 | #if defined(R_VERSION) && R_VERSION < R_Version(4, 5, 0) 13 | SEXP R_mkClosure(SEXP formals, SEXP body, SEXP env) { 14 | SEXP fun = Rf_allocSExp(CLOSXP); 15 | SET_FORMALS(fun, formals); 16 | SET_BODY(fun, body); 17 | SET_CLOENV(fun, env); 18 | return fun; 19 | } 20 | #endif 21 | -------------------------------------------------------------------------------- /src/backports.h: -------------------------------------------------------------------------------- 1 | #ifndef BACKPORTS_H 2 | #define BACKPORTS_H 3 | 4 | #include 5 | 6 | #if defined(R_VERSION) && R_VERSION < R_Version(3, 2, 0) 7 | SEXP Rf_installChar(SEXP); 8 | #endif 9 | 10 | #if defined(R_VERSION) && R_VERSION < R_Version(4, 5, 0) 11 | SEXP R_mkClosure(SEXP, SEXP, SEXP); 12 | #endif 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /src/cleancall.h: -------------------------------------------------------------------------------- 1 | #ifndef CLEANCALL_H 2 | #define CLEANCALL_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | // -------------------------------------------------------------------- 13 | // Internals 14 | // -------------------------------------------------------------------- 15 | 16 | typedef union {void* p; DL_FUNC fn;} fn_ptr; 17 | 18 | #if (defined(R_VERSION) && R_VERSION < R_Version(3, 4, 0)) 19 | SEXP R_MakeExternalPtrFn(DL_FUNC p, SEXP tag, SEXP prot); 20 | DL_FUNC R_ExternalPtrAddrFn(SEXP s); 21 | #endif 22 | 23 | // -------------------------------------------------------------------- 24 | // API for packages that embed cleancall 25 | // -------------------------------------------------------------------- 26 | 27 | // The R API does not have a setter for external function pointers 28 | SEXP cleancall_MakeExternalPtrFn(DL_FUNC p, SEXP tag, SEXP prot); 29 | void cleancall_SetExternalPtrAddrFn(SEXP s, DL_FUNC p); 30 | 31 | #define CLEANCALL_METHOD_RECORD \ 32 | {"cleancall_call", (DL_FUNC) &cleancall_call, 2} 33 | 34 | SEXP cleancall_call(SEXP args, SEXP env); 35 | void cleancall_init(void); 36 | 37 | // -------------------------------------------------------------------- 38 | // Public API 39 | // -------------------------------------------------------------------- 40 | 41 | #define R_CLEANCALL_SUPPORT 1 42 | 43 | SEXP r_with_cleanup_context(SEXP (*fn)(void* data), void* data); 44 | void r_call_on_exit(void (*fn)(void* data), void* data); 45 | void r_call_on_early_exit(void (*fn)(void* data), void* data); 46 | 47 | #ifdef __cplusplus 48 | } 49 | #endif 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /src/coerce.h: -------------------------------------------------------------------------------- 1 | #ifndef COERCE_H 2 | #define COERCE_H 3 | 4 | // Set value of to[i] to from[j], coercing vectors using usual rules. 5 | void set_vector_value(SEXP to, int i, SEXP from, int j); 6 | 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/conditions.h: -------------------------------------------------------------------------------- 1 | #ifndef CONDITIONS_H 2 | #define CONDITIONS_H 3 | 4 | #include 5 | 6 | void __attribute__ ((noreturn)) stop_bad_type(SEXP x, const char* expected, const char* what, const char* arg) __attribute__((noreturn)); 7 | void __attribute__ ((noreturn)) stop_bad_element_type(SEXP x, R_xlen_t index, const char* expected, const char* what, const char* arg) __attribute__((noreturn)); 8 | void __attribute__ ((noreturn)) stop_bad_element_length(SEXP x, R_xlen_t index, R_xlen_t expected_length, const char* what, const char* arg, bool recycle) __attribute__((noreturn)); 9 | SEXP current_env(void); 10 | void __attribute__ ((noreturn)) r_abort(const char* fmt, ...); 11 | void __attribute__ ((noreturn)) r_abort_call(SEXP env, const char* fmt, ...); 12 | 13 | const char* rlang_obj_type_friendly_full(SEXP x, bool value, bool length); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /src/init.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include // for NULL 4 | #include 5 | 6 | // Compile with `-fvisibility=hidden -DHAVE_VISIBILITY_ATTRIBUTE` if you link to this library 7 | #include 8 | #define export attribute_visible extern 9 | 10 | #include "cleancall.h" 11 | 12 | /* .Call calls */ 13 | extern SEXP coerce_impl(SEXP, SEXP); 14 | extern SEXP pluck_impl(SEXP, SEXP, SEXP, SEXP); 15 | extern SEXP flatten_impl(SEXP); 16 | extern SEXP map_impl(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); 17 | extern SEXP map2_impl(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); 18 | extern SEXP pmap_impl(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); 19 | extern SEXP transpose_impl(SEXP, SEXP); 20 | extern SEXP vflatten_impl(SEXP, SEXP); 21 | 22 | static const R_CallMethodDef CallEntries[] = { 23 | CLEANCALL_METHOD_RECORD, 24 | {"coerce_impl", (DL_FUNC) &coerce_impl, 2}, 25 | {"pluck_impl", (DL_FUNC) &pluck_impl, 4}, 26 | {"flatten_impl", (DL_FUNC) &flatten_impl, 1}, 27 | {"map_impl", (DL_FUNC) &map_impl, 6}, 28 | {"map2_impl", (DL_FUNC) &map2_impl, 6}, 29 | {"pmap_impl", (DL_FUNC) &pmap_impl, 8}, 30 | {"transpose_impl", (DL_FUNC) &transpose_impl, 2}, 31 | {"vflatten_impl", (DL_FUNC) &vflatten_impl, 2}, 32 | {"purrr_eval", (DL_FUNC) &Rf_eval, 2}, 33 | {NULL, NULL, 0} 34 | }; 35 | 36 | export void R_init_purrr(DllInfo *dll) 37 | { 38 | R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); 39 | R_useDynamicSymbols(dll, FALSE); 40 | cleancall_init(); 41 | } 42 | -------------------------------------------------------------------------------- /src/map.h: -------------------------------------------------------------------------------- 1 | #ifndef MAP_H 2 | #define MAP_H 3 | 4 | extern "C" { 5 | SEXP map_impl(SEXP env, 6 | SEXP ffi_type, 7 | SEXP progress, 8 | SEXP ffi_n, 9 | SEXP names, 10 | SEXP i); 11 | 12 | SEXP pmap_impl(SEXP env, 13 | SEXP ffi_type, 14 | SEXP progress, 15 | SEXP ffi_n, 16 | SEXP names, 17 | SEXP i, 18 | SEXP call_names, 19 | SEXP ffi_call_n); 20 | } 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /src/utils.c: -------------------------------------------------------------------------------- 1 | #define R_NO_REMAP 2 | #include 3 | #include 4 | 5 | SEXP sym_protect(SEXP x) { 6 | if (TYPEOF(x) == LANGSXP || TYPEOF(x) == SYMSXP) { 7 | SEXP quote_prim = Rf_eval(Rf_install("quote"), R_BaseEnv); 8 | return(Rf_lang2(quote_prim, x)); 9 | } else { 10 | return x; 11 | } 12 | } 13 | 14 | bool is_vector(SEXP x) { 15 | switch (TYPEOF(x)) { 16 | case LGLSXP: 17 | case INTSXP: 18 | case REALSXP: 19 | case CPLXSXP: 20 | case STRSXP: 21 | case RAWSXP: 22 | case VECSXP: 23 | return true; 24 | default: 25 | return false; 26 | } 27 | } 28 | 29 | SEXP list6(SEXP s, SEXP t, SEXP u, SEXP v, SEXP w, SEXP x) { 30 | PROTECT(s); 31 | s = Rf_cons(s, Rf_list5(t, u, v, w, x)); 32 | UNPROTECT(1); 33 | return s; 34 | } 35 | 36 | SEXP lang7(SEXP s, SEXP t, SEXP u, SEXP v, SEXP w, SEXP x, SEXP y) { 37 | PROTECT(s); 38 | s = Rf_lcons(s, list6(t, u, v, w, x, y)); 39 | UNPROTECT(1); 40 | return s; 41 | } 42 | SEXP list7(SEXP s, SEXP t, SEXP u, SEXP v, SEXP w, SEXP x, SEXP y) { 43 | PROTECT(s); 44 | s = Rf_cons(s, list6(t, u, v, w, x, y)); 45 | UNPROTECT(1); 46 | return s; 47 | } 48 | SEXP lang8(SEXP s, SEXP t, SEXP u, SEXP v, SEXP w, SEXP x, SEXP y, SEXP z) { 49 | PROTECT(s); 50 | s = Rf_lcons(s, list7(t, u, v, w, x, y, z)); 51 | UNPROTECT(1); 52 | return s; 53 | } 54 | -------------------------------------------------------------------------------- /src/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef UTILS_H 2 | #define UTILS_H 3 | 4 | #include 5 | 6 | 7 | SEXP sym_protect(SEXP x); 8 | 9 | bool is_vector(SEXP x); 10 | 11 | SEXP lang7(SEXP s, SEXP t, SEXP u, SEXP v, SEXP w, SEXP x, SEXP y); 12 | SEXP lang8(SEXP s, SEXP t, SEXP u, SEXP v, SEXP w, SEXP x, SEXP y, SEXP z); 13 | 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library(purrr) 3 | 4 | test_check("purrr") 5 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/adverb-auto-browse.md: -------------------------------------------------------------------------------- 1 | # auto_browse() not intended for primitive functions 2 | 3 | Code 4 | auto_browse(log)(NULL) 5 | Condition 6 | Error in `auto_browse()`: 7 | ! `.f` must not be a primitive function. 8 | 9 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/adverb-compose.md: -------------------------------------------------------------------------------- 1 | # composed function prints informatively 2 | 3 | Code 4 | # Single input 5 | compose(fn1) 6 | Output 7 | 8 | 1. function(x) x + 1 9 | Code 10 | # Multiple inputs 11 | compose(fn1, fn2) 12 | Output 13 | 14 | 1. function(x) x / 1 15 | 16 | 2. function(x) x + 1 17 | 18 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/adverb-insistently.md: -------------------------------------------------------------------------------- 1 | # insistently() resets rate state 2 | 3 | Request failed after 0 attempts. 4 | 5 | --- 6 | 7 | Request failed after 0 attempts. 8 | 9 | # validates inputs 10 | 11 | Code 12 | insistently(mean, 10) 13 | Condition 14 | Error in `insistently()`: 15 | ! `rate` must be a rate object, not a number. 16 | 17 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/adverb-partial.md: -------------------------------------------------------------------------------- 1 | # partial() squashes quosures before printing 2 | 3 | Code 4 | foo 5 | Output 6 | 7 | function (...) 8 | foo(y = 3, ...) 9 | 10 | # `.lazy`, `.env`, and `.first` are soft-deprecated 11 | 12 | Code 13 | . <- partial(list, "foo", .lazy = TRUE) 14 | Condition 15 | Warning: 16 | The `.lazy` argument of `partial()` is deprecated as of purrr 0.3.0. 17 | Code 18 | . <- partial(list, "foo", .env = env()) 19 | Condition 20 | Warning: 21 | The `.env` argument of `partial()` is deprecated as of purrr 0.3.0. 22 | Code 23 | . <- partial(list, "foo", .first = TRUE) 24 | Condition 25 | Warning: 26 | The `.first` argument of `partial()` is deprecated as of purrr 0.3.0. 27 | 28 | # checks inputs 29 | 30 | Code 31 | partial(1) 32 | Condition 33 | Error in `partial()`: 34 | ! `.f` must be a function, not a number. 35 | 36 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/adverb-slowly.md: -------------------------------------------------------------------------------- 1 | # validates inputs 2 | 3 | Code 4 | slowly(mean, 10) 5 | Condition 6 | Error in `slowly()`: 7 | ! `rate` must be a rate object, not a number. 8 | 9 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/arrays.md: -------------------------------------------------------------------------------- 1 | # array_branch throws an error for wrong margins on a vector 2 | 3 | Code 4 | array_branch(1:3, 2) 5 | Condition 6 | Error in `array_branch()`: 7 | ! `margin` must be `NULL` or `1` with 1D arrays, not "2". 8 | 9 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/conditions.md: -------------------------------------------------------------------------------- 1 | # stop_bad_type() constructs default `what` 2 | 3 | Code 4 | stop_bad_type(NA, "`NULL`") 5 | Condition 6 | Error: 7 | ! Object must be `NULL`, not `NA`. 8 | 9 | --- 10 | 11 | Code 12 | stop_bad_type(NA, "`NULL`", arg = ".foo") 13 | Condition 14 | Error: 15 | ! `.foo` must be `NULL`, not `NA`. 16 | 17 | --- 18 | 19 | Code 20 | stop_bad_type(NA, "`NULL`", arg = quote(.foo)) 21 | Condition 22 | Error in `what_bad_object()`: 23 | ! `arg` must be `NULL` or a string, not a symbol. 24 | 25 | # stop_bad_element_type() constructs type errors 26 | 27 | Code 28 | stop_bad_element_type(1:3, 3, "a foobaz") 29 | Condition 30 | Error: 31 | ! Element 3 must be a foobaz, not an integer vector. 32 | 33 | --- 34 | 35 | Code 36 | stop_bad_element_type(1:3, 3, "a foobaz", actual = "a quux") 37 | Condition 38 | Error: 39 | ! Element 3 must be a foobaz, not an integer vector. 40 | 41 | --- 42 | 43 | Code 44 | stop_bad_element_type(1:3, 3, "a foobaz", arg = "..arg") 45 | Condition 46 | Error: 47 | ! `..arg[[3]]` must be a foobaz, not an integer vector. 48 | 49 | # stop_bad_element_type() accepts `what` 50 | 51 | Code 52 | stop_bad_element_type(1:3, 3, "a foobaz", what = "Result") 53 | Condition 54 | Error: 55 | ! Result 3 must be a foobaz, not an integer vector. 56 | 57 | # stop_bad_element_length() constructs error message 58 | 59 | Code 60 | stop_bad_element_length(1:3, 8, 10) 61 | Condition 62 | Error: 63 | ! Element 8 must have length 10, not 3. 64 | 65 | --- 66 | 67 | Code 68 | stop_bad_element_length(1:3, 8, 10, arg = ".foo") 69 | Condition 70 | Error: 71 | ! `.foo[[8]]` must have length 10, not 3. 72 | 73 | --- 74 | 75 | Code 76 | stop_bad_element_length(1:3, 8, 10, arg = ".foo", what = "Result") 77 | Condition 78 | Error: 79 | ! `.foo[[8]]` must have length 10, not 3. 80 | 81 | --- 82 | 83 | Code 84 | stop_bad_element_length(1:3, 8, 10, arg = ".foo", what = "Result", recycle = TRUE) 85 | Condition 86 | Error: 87 | ! `.foo[[8]]` must have length 1 or 10, not 3. 88 | 89 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/deprec-along.md: -------------------------------------------------------------------------------- 1 | # list-along is deprecated 2 | 3 | Code 4 | . <- list_along(1:4) 5 | Condition 6 | Warning: 7 | `list_along()` was deprecated in purrr 1.0.0. 8 | i Please use rep_along(x, list()) instead. 9 | 10 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/deprec-cross.md: -------------------------------------------------------------------------------- 1 | # filtering requires a predicate function 2 | 3 | Code 4 | cross2(1:3, 1:3, .filter = ~ c(TRUE, TRUE)) 5 | Condition 6 | Error in `cross()`: 7 | ! The filter function must return a single `TRUE` or `FALSE`, not a logical vector. 8 | 9 | # filtering fails when filter function doesn't return a logical 10 | 11 | Code 12 | cross3(1:3, 1:3, 1:3, .filter = filter) 13 | Condition 14 | Error in `cross()`: 15 | ! The filter function must return a single `TRUE` or `FALSE`, not an integer. 16 | 17 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/deprec-invoke.md: -------------------------------------------------------------------------------- 1 | # invoke_* is deprecated 2 | 3 | Code 4 | . <- invoke(identity, 1) 5 | Condition 6 | Warning: 7 | `invoke()` was deprecated in purrr 1.0.0. 8 | i Please use `exec()` instead. 9 | Code 10 | . <- invoke_map(identity, list()) 11 | Condition 12 | Warning: 13 | `invoke_map()` was deprecated in purrr 1.0.0. 14 | i Please use map() + exec() instead. 15 | Code 16 | . <- invoke_map_lgl(identity, list()) 17 | Condition 18 | Warning: 19 | `invoke_lgl()` was deprecated in purrr 1.0.0. 20 | i Please use map_lgl() + exec() instead. 21 | Code 22 | . <- invoke_map_int(identity, list()) 23 | Condition 24 | Warning: 25 | `invoke_int()` was deprecated in purrr 1.0.0. 26 | i Please use map_int() + exec() instead. 27 | Code 28 | . <- invoke_map_dbl(identity, list()) 29 | Condition 30 | Warning: 31 | `invoke_dbl()` was deprecated in purrr 1.0.0. 32 | i Please use map_dbl() + exec() instead. 33 | Code 34 | . <- invoke_map_chr(identity, list()) 35 | Condition 36 | Warning: 37 | `invoke_chr()` was deprecated in purrr 1.0.0. 38 | i Please use map_chr() + exec() instead. 39 | Code 40 | . <- invoke_map_raw(identity, list()) 41 | Condition 42 | Warning: 43 | `invoke_raw()` was deprecated in purrr 1.0.0. 44 | i Please use map_raw() + exec() instead. 45 | 46 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/deprec-lift.md: -------------------------------------------------------------------------------- 1 | # lift functions are deprecated 2 | 3 | Code 4 | . <- lift_dl(function() { }) 5 | Condition 6 | Warning: 7 | `lift()` was deprecated in purrr 1.0.0. 8 | Code 9 | . <- lift_dv(function() { }) 10 | Condition 11 | Warning: 12 | `lift_dv()` was deprecated in purrr 1.0.0. 13 | Code 14 | . <- lift_vl(function() { }) 15 | Condition 16 | Warning: 17 | `lift_vl()` was deprecated in purrr 1.0.0. 18 | Code 19 | . <- lift_vd(function() { }) 20 | Condition 21 | Warning: 22 | `lift_vd()` was deprecated in purrr 1.0.0. 23 | Code 24 | . <- lift_ld(function() { }) 25 | Condition 26 | Warning: 27 | `lift_ld()` was deprecated in purrr 1.0.0. 28 | Code 29 | . <- lift_lv(function() { }) 30 | Condition 31 | Warning: 32 | `lift_lv()` was deprecated in purrr 1.0.0. 33 | 34 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/deprec-map.md: -------------------------------------------------------------------------------- 1 | # at_depth is defunct 2 | 3 | Code 4 | at_depth() 5 | Condition 6 | Error: 7 | ! `at_depth()` was deprecated in purrr 0.3.0 and is now defunct. 8 | i Please use `map_depth()` instead. 9 | 10 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/deprec-prepend.md: -------------------------------------------------------------------------------- 1 | # prepend is deprecated 2 | 3 | Code 4 | . <- prepend(1, 2) 5 | Condition 6 | Warning: 7 | `prepend()` was deprecated in purrr 1.0.0. 8 | i Please use append(after = 0) instead. 9 | 10 | # prepend throws error if before param is neither NULL nor between 1 and length(x) 11 | 12 | Code 13 | prepend(list(), 1, before = 1) 14 | Condition 15 | Error in `prepend()`: 16 | ! is.null(before) || (before > 0 && before <= n) is not TRUE 17 | 18 | --- 19 | 20 | Code 21 | x %>% prepend(4, before = 0) 22 | Condition 23 | Error in `prepend()`: 24 | ! is.null(before) || (before > 0 && before <= n) is not TRUE 25 | 26 | --- 27 | 28 | Code 29 | x %>% prepend(4, before = 4) 30 | Condition 31 | Error in `prepend()`: 32 | ! is.null(before) || (before > 0 && before <= n) is not TRUE 33 | 34 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/deprec-rerun.md: -------------------------------------------------------------------------------- 1 | # is deprecated 2 | 3 | Code 4 | . <- rerun(5, rnorm(1)) 5 | Condition 6 | Warning: 7 | `rerun()` was deprecated in purrr 1.0.0. 8 | i Please use `map()` instead. 9 | # Previously 10 | rerun(5, rnorm(1)) 11 | 12 | # Now 13 | map(1:5, ~ rnorm(1)) 14 | Code 15 | . <- rerun(5, rnorm(1), rnorm(2)) 16 | Condition 17 | Warning: 18 | `rerun()` was deprecated in purrr 1.0.0. 19 | i Please use `map()` instead. 20 | # Previously 21 | rerun(5, rnorm(1), rnorm(2)) 22 | 23 | # Now 24 | map(1:5, ~ list(rnorm(1), rnorm(2))) 25 | 26 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/deprec-splice.md: -------------------------------------------------------------------------------- 1 | # splice is deprecated 2 | 3 | Code 4 | . <- splice() 5 | Condition 6 | Warning: 7 | `splice()` was deprecated in purrr 1.0.0. 8 | i Please use `list_flatten()` instead. 9 | 10 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/deprec-utils.md: -------------------------------------------------------------------------------- 1 | # rdunif and rbernoulli are deprecated 2 | 3 | Code 4 | . <- rdunif(10, 1) 5 | Condition 6 | Warning: 7 | `rdunif()` was deprecated in purrr 1.0.0. 8 | Code 9 | . <- rbernoulli(10) 10 | Condition 11 | Warning: 12 | `rbernoulli()` was deprecated in purrr 1.0.0. 13 | 14 | # rdunif fails if a and b are not unit length numbers 15 | 16 | Code 17 | rdunif(1000, 1, "a") 18 | Condition 19 | Error in `rdunif()`: 20 | ! is.numeric(a) is not TRUE 21 | 22 | --- 23 | 24 | Code 25 | rdunif(1000, 1, c(0.5, 0.2)) 26 | Condition 27 | Error in `rdunif()`: 28 | ! length(a) == 1 is not TRUE 29 | 30 | --- 31 | 32 | Code 33 | rdunif(1000, FALSE, 2) 34 | Condition 35 | Error in `rdunif()`: 36 | ! is.numeric(b) is not TRUE 37 | 38 | --- 39 | 40 | Code 41 | rdunif(1000, c(2, 3), 2) 42 | Condition 43 | Error in `rdunif()`: 44 | ! length(b) == 1 is not TRUE 45 | 46 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/deprec-when.md: -------------------------------------------------------------------------------- 1 | # when is deprecated 2 | 3 | Code 4 | . <- when(1:5 < 3 ~ 1, ~0) 5 | Condition 6 | Warning: 7 | `when()` was deprecated in purrr 1.0.0. 8 | i Please use `if` instead. 9 | 10 | # error when named arguments have no matching conditions 11 | 12 | Code 13 | 1:5 %>% when(a = sum(.) < 5 ~ 3) 14 | Condition 15 | Error in `when()`: 16 | ! At least one matching condition is needed. 17 | 18 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/detect.md: -------------------------------------------------------------------------------- 1 | # `detect()` requires a predicate function 2 | 3 | Code 4 | detect(list(1:2, 2), is.na) 5 | Condition 6 | Error in `detect()`: 7 | ! `.f()` must return a single `TRUE` or `FALSE`, not a logical vector. 8 | 9 | --- 10 | 11 | Code 12 | detect_index(list(1:2, 2), is.na) 13 | Condition 14 | Error in `detect_index()`: 15 | ! `.f()` must return a single `TRUE` or `FALSE`, not a logical vector. 16 | 17 | # `.right` argument is retired 18 | 19 | Code 20 | . <- detect(1:2, ~TRUE, .right = TRUE) 21 | Condition 22 | Warning: 23 | The `.right` argument of `detect()` is deprecated as of purrr 0.3.0. 24 | i Please use the `.dir` argument instead. 25 | Code 26 | . <- detect_index(1:2, ~TRUE, .right = TRUE) 27 | Condition 28 | Warning: 29 | The `.right` argument of `detect_index()` is deprecated as of purrr 0.3.0. 30 | i Please use the `.dir` argument instead. 31 | 32 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/every-some-none.md: -------------------------------------------------------------------------------- 1 | # every() requires logical value 2 | 3 | Code 4 | every(list(1:3), identity) 5 | Condition 6 | Error in `every()`: 7 | ! `.p()` must return a single `TRUE` or `FALSE`, not an integer vector. 8 | 9 | --- 10 | 11 | Code 12 | every(list(function() NULL), identity) 13 | Condition 14 | Error in `every()`: 15 | ! `.p()` must return a single `TRUE` or `FALSE`, not a function. 16 | 17 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/head-tail.md: -------------------------------------------------------------------------------- 1 | # head_while and tail_while require predicate function 2 | 3 | Code 4 | head_while(1:3, ~NA) 5 | Condition 6 | Error in `head_while()`: 7 | ! `.p()` must return a single `TRUE` or `FALSE`, not `NA`. 8 | 9 | --- 10 | 11 | Code 12 | tail_while(1:3, ~ c(TRUE, FALSE)) 13 | Condition 14 | Error in `tail_while()`: 15 | ! `.p()` must return a single `TRUE` or `FALSE`, not a logical vector. 16 | 17 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/keep.md: -------------------------------------------------------------------------------- 1 | # keep() and discard() require predicate functions 2 | 3 | Code 4 | keep(1:3, ~NA) 5 | Condition 6 | Error in `keep()`: 7 | i In index: 1. 8 | Caused by error: 9 | ! `.p()` must return a single `TRUE` or `FALSE`, not `NA`. 10 | Code 11 | discard(1:3, ~NA) 12 | Condition 13 | Error in `discard()`: 14 | i In index: 1. 15 | Caused by error: 16 | ! `.p()` must return a single `TRUE` or `FALSE`, not `NA`. 17 | 18 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/list-flatten.md: -------------------------------------------------------------------------------- 1 | # requires a list 2 | 3 | Code 4 | list_flatten(1:2) 5 | Condition 6 | Error in `list_flatten()`: 7 | ! `x` must be a list, not an integer vector. 8 | 9 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/list-modify.md: -------------------------------------------------------------------------------- 1 | # list_modify() validates inputs 2 | 3 | Code 4 | list_modify(1:3) 5 | Condition 6 | Error in `list_modify()`: 7 | ! `.x` must be a list, not an integer vector. 8 | 9 | --- 10 | 11 | Code 12 | list_modify(list(a = 1), 2, a = 2) 13 | Condition 14 | Error in `list_modify()`: 15 | ! `...` arguments must be either all named or all unnamed. 16 | 17 | --- 18 | 19 | Code 20 | list_modify(list(x = 1), x = 2, x = 3) 21 | Condition 22 | Error in `list_modify()`: 23 | ! Arguments in `...` must have unique names. 24 | x Multiple arguments named `x` at positions 1 and 2. 25 | 26 | # merge() validates inputs 27 | 28 | Code 29 | list_merge(1:3) 30 | Condition 31 | Error in `list_merge()`: 32 | ! `.x` must be a list, not an integer vector. 33 | 34 | --- 35 | 36 | Code 37 | list_merge(list(x = 1), x = 2, x = 3) 38 | Condition 39 | Error in `list_merge()`: 40 | ! Arguments in `...` must have unique names. 41 | x Multiple arguments named `x` at positions 1 and 2. 42 | 43 | # update_list() is deprecated 44 | 45 | Code 46 | . <- update_list(list()) 47 | Condition 48 | Warning: 49 | `update_list()` was deprecated in purrr 1.0.0. 50 | 51 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/list-simplify.md: -------------------------------------------------------------------------------- 1 | # ptype is enforced 2 | 3 | Code 4 | list_simplify(list(1, 2), ptype = character()) 5 | Condition 6 | Error in `list_simplify()`: 7 | ! Can't convert `[[1]]` to . 8 | 9 | --- 10 | 11 | Code 12 | list_simplify(list(1, 2), ptype = character(), strict = FALSE) 13 | Condition 14 | Error in `list_simplify()`: 15 | ! Can't convert `[[1]]` to . 16 | 17 | # strict simplification will error 18 | 19 | Code 20 | list_simplify(list(mean)) 21 | Condition 22 | Error in `list_simplify()`: 23 | ! `x[[1]]` must be a vector, not a function. 24 | Code 25 | list_simplify(list(1, "a")) 26 | Condition 27 | Error in `list_simplify()`: 28 | ! Can't combine `[[1]]` and `[[2]]` . 29 | Code 30 | list_simplify(list(1, 1:2)) 31 | Condition 32 | Error in `list_simplify()`: 33 | ! `x[[2]]` must have size 1, not size 2. 34 | Code 35 | list_simplify(list(data.frame(x = 1), data.frame(x = 1:2))) 36 | Condition 37 | Error in `list_simplify()`: 38 | ! `x[[2]]` must have size 1, not size 2. 39 | Code 40 | list_simplify(list(1, 2), ptype = character()) 41 | Condition 42 | Error in `list_simplify()`: 43 | ! Can't convert `[[1]]` to . 44 | 45 | # list_simplify() validates inputs 46 | 47 | Code 48 | list_simplify(1:5) 49 | Condition 50 | Error in `list_simplify()`: 51 | ! `x` must be a list, not an integer vector. 52 | 53 | --- 54 | 55 | Code 56 | list_simplify(list(), strict = NA) 57 | Condition 58 | Error in `list_simplify()`: 59 | ! `strict` must be `TRUE` or `FALSE`, not `NA`. 60 | 61 | # list_simplify_internal() validates inputs 62 | 63 | Code 64 | list_simplify_internal(list(), simplify = 1) 65 | Condition 66 | Error: 67 | ! `simplify` must be `TRUE`, `FALSE`, or `NA`, not the number 1. 68 | 69 | --- 70 | 71 | Code 72 | list_simplify_internal(list(), simplify = FALSE, ptype = integer()) 73 | Condition 74 | Error: 75 | ! Can't specify `ptype` when `simplify = FALSE`. 76 | 77 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/lmap.md: -------------------------------------------------------------------------------- 1 | # validates inputs 2 | 3 | Code 4 | lmap(list(1), ~1) 5 | Condition 6 | Error in `lmap()`: 7 | ! `.f(.x[[1]])` must return a list, not a number. 8 | Code 9 | lmap(list(1), environment()) 10 | Condition 11 | Error in `lmap()`: 12 | ! Can't convert `.f`, an environment, to a function. 13 | Code 14 | lmap(list(1), ~1, .else = environment()) 15 | Condition 16 | Error in `lmap()`: 17 | ! Can't convert `.else`, an environment, to a function. 18 | 19 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/map-depth.md: -------------------------------------------------------------------------------- 1 | # map_depth modifies values at specified depth 2 | 3 | Code 4 | map_depth(x1, 6, length) 5 | Condition 6 | Error in `.fmap()`: 7 | i In index: 1. 8 | Caused by error in `.fmap()`: 9 | i In index: 1. 10 | Caused by error in `.fmap()`: 11 | i In index: 1. 12 | Caused by error in `map_depth()`: 13 | ! List not deep enough 14 | 15 | --- 16 | 17 | Code 18 | map_depth(x1, -5, length) 19 | Condition 20 | Error in `map_depth()`: 21 | ! Negative `.depth` (-5) must be greater than -4. 22 | 23 | # default doesn't recurse into data frames, but can customise 24 | 25 | Code 26 | map_depth(x, 2, class) 27 | Condition 28 | Error in `.fmap()`: 29 | i In index: 1. 30 | Caused by error in `map_depth()`: 31 | ! List not deep enough 32 | 33 | # modify_depth modifies values at specified depth 34 | 35 | Code 36 | modify_depth(x1, 5, length) 37 | Condition 38 | Error in `map()`: 39 | i In index: 1. 40 | Caused by error in `map()`: 41 | i In index: 1. 42 | Caused by error in `map()`: 43 | i In index: 1. 44 | Caused by error in `modify_depth()`: 45 | ! List not deep enough 46 | 47 | --- 48 | 49 | Code 50 | modify_depth(x1, -5, length) 51 | Condition 52 | Error in `modify_depth()`: 53 | ! Negative `.depth` (-5) must be greater than -4. 54 | 55 | # vectorised operations on the recursive and atomic levels yield same results 56 | 57 | Code 58 | modify_depth(x, 5, `+`, 10L) 59 | Condition 60 | Error in `map()`: 61 | i In index: 1. 62 | Caused by error in `map()`: 63 | i In index: 1. 64 | Caused by error in `map()`: 65 | i In index: 1. 66 | Caused by error in `modify_depth()`: 67 | ! List not deep enough 68 | 69 | # validates depth 70 | 71 | Code 72 | check_depth(mean) 73 | Condition 74 | Error: 75 | ! `depth` must be a whole number, not a function. 76 | 77 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/map-if-at.md: -------------------------------------------------------------------------------- 1 | # map_if requires predicate functions 2 | 3 | Code 4 | map_if(1:3, ~NA, ~"foo") 5 | Condition 6 | Error in `map_if()`: 7 | i In index: 1. 8 | Caused by error: 9 | ! `.p()` must return a single `TRUE` or `FALSE`, not `NA`. 10 | 11 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/map-raw.md: -------------------------------------------------------------------------------- 1 | # _raw funtions are deprecated 2 | 3 | Code 4 | . <- map_raw(list(), ~.x) 5 | Condition 6 | Warning: 7 | `map_raw()` was deprecated in purrr 1.0.0. 8 | i Please use `map_vec()` instead. 9 | Code 10 | . <- map2_raw(list(), list(), ~.x) 11 | Condition 12 | Warning: 13 | `map2_raw()` was deprecated in purrr 1.0.0. 14 | i Please use `map2_vec()` instead. 15 | Code 16 | . <- imap_raw(list(), ~.x) 17 | Condition 18 | Warning: 19 | `imap_raw()` was deprecated in purrr 1.0.0. 20 | i Please use `imap_vec()` instead. 21 | Code 22 | . <- pmap_raw(list(), ~.x) 23 | Condition 24 | Warning: 25 | `pmap_raw()` was deprecated in purrr 1.0.0. 26 | i Please use `pmap_vec()` instead. 27 | Code 28 | . <- flatten_raw(list()) 29 | Condition 30 | Warning: 31 | `flatten_raw()` was deprecated in purrr 1.0.0. 32 | 33 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/map.md: -------------------------------------------------------------------------------- 1 | # fails on non-vectors 2 | 3 | Code 4 | map(environment(), identity) 5 | Condition 6 | Error in `map()`: 7 | ! `.x` must be a vector, not an environment. 8 | 9 | --- 10 | 11 | Code 12 | map(quote(a), identity) 13 | Condition 14 | Error in `map()`: 15 | ! `.x` must be a vector, not a symbol. 16 | 17 | # all inform about location of problem 18 | 19 | Code 20 | map_int(1:3, ~ fail_at_3(.x, 2:1)) 21 | Condition 22 | Error in `map_int()`: 23 | i In index: 3. 24 | Caused by error: 25 | ! Result must be length 1, not 2. 26 | Code 27 | map_int(1:3, ~ fail_at_3(.x, "x")) 28 | Condition 29 | Error in `map_int()`: 30 | i In index: 3. 31 | Caused by error: 32 | ! Can't coerce from a string to an integer. 33 | Code 34 | map(1:3, ~ fail_at_3(.x, stop("Doesn't work"))) 35 | Condition 36 | Error in `map()`: 37 | i In index: 3. 38 | Caused by error in `fail_at_3()`: 39 | ! Doesn't work 40 | 41 | # error location uses name if present 42 | 43 | Code 44 | map_int(c(a = 1, b = 2, c = 3), ~ fail_at_3(.x, stop("Error"))) 45 | Condition 46 | Error in `map_int()`: 47 | i In index: 3. 48 | i With name: c. 49 | Caused by error in `fail_at_3()`: 50 | ! Error 51 | Code 52 | map_int(c(a = 1, b = 2, 3), ~ fail_at_3(.x, stop("Error"))) 53 | Condition 54 | Error in `map_int()`: 55 | i In index: 3. 56 | Caused by error in `fail_at_3()`: 57 | ! Error 58 | 59 | # requires output be length 1 and have common type 60 | 61 | Code 62 | map_vec(1:2, ~ rep(1, .x)) 63 | Condition 64 | Error in `map_vec()`: 65 | ! `out[[2]]` must have size 1, not size 2. 66 | Code 67 | map_vec(1:2, ~ if (.x == 1) factor("x") else 1) 68 | Condition 69 | Error in `map_vec()`: 70 | ! Can't combine `[[1]]` > and `[[2]]` . 71 | 72 | # can enforce .ptype 73 | 74 | Code 75 | map_vec(1:2, ~ factor("x"), .ptype = integer()) 76 | Condition 77 | Error in `map_vec()`: 78 | ! Can't convert `[[1]]` > to . 79 | 80 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/map2.md: -------------------------------------------------------------------------------- 1 | # verifies result types and length 2 | 3 | Code 4 | map2_int(1, 1, ~"x") 5 | Condition 6 | Error in `map2_int()`: 7 | i In index: 1. 8 | Caused by error: 9 | ! Can't coerce from a string to an integer. 10 | Code 11 | map2_int(1, 1, ~ 1:2) 12 | Condition 13 | Error in `map2_int()`: 14 | i In index: 1. 15 | Caused by error: 16 | ! Result must be length 1, not 2. 17 | Code 18 | map2_vec(1, 1, ~1, .ptype = character()) 19 | Condition 20 | Error in `map2_vec()`: 21 | ! Can't convert `[[1]]` to . 22 | 23 | # requires vector inputs 24 | 25 | Code 26 | map2(environment(), "a", identity) 27 | Condition 28 | Error in `map2()`: 29 | ! `.x` must be a vector, not an environment. 30 | Code 31 | map2("a", environment(), "a", identity) 32 | Condition 33 | Error in `map2()`: 34 | ! `.y` must be a vector, not an environment. 35 | 36 | # recycles inputs 37 | 38 | Code 39 | map2(1:2, 1:3, `+`) 40 | Condition 41 | Error in `map2()`: 42 | ! Can't recycle `.x` (size 2) to match `.y` (size 3). 43 | Code 44 | map2(1:2, integer(), `+`) 45 | Condition 46 | Error in `map2()`: 47 | ! Can't recycle `.x` (size 2) to match `.y` (size 0). 48 | 49 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/modify-tree.md: -------------------------------------------------------------------------------- 1 | # validates inputs 2 | 3 | Code 4 | modify_tree(list(), is_node = ~1) 5 | Condition 6 | Error in `modify_tree()`: 7 | ! `is_node()` must return a single `TRUE` or `FALSE`, not a number. 8 | Code 9 | modify_tree(list(), is_node = 1) 10 | Condition 11 | Error in `modify_tree()`: 12 | ! Can't convert `is_node`, a double vector, to a function. 13 | 14 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/pluck-assign.md: -------------------------------------------------------------------------------- 1 | # assign_in() requires at least one location 2 | 3 | Code 4 | assign_in(x, NULL, value = "foo") 5 | Condition 6 | Error in `assign_in()`: 7 | ! `where` must contain at least one element. 8 | 9 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/pluck-depth.md: -------------------------------------------------------------------------------- 1 | # vec_depth() is deprecated 2 | 3 | Code 4 | . <- vec_depth(list()) 5 | Condition 6 | Warning: 7 | `vec_depth()` was deprecated in purrr 1.0.0. 8 | i Please use `pluck_depth()` instead. 9 | 10 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/pmap.md: -------------------------------------------------------------------------------- 1 | # verifies result types and length 2 | 3 | Code 4 | pmap_int(list(1), ~"x") 5 | Condition 6 | Error in `pmap_int()`: 7 | i In index: 1. 8 | Caused by error: 9 | ! Can't coerce from a string to an integer. 10 | Code 11 | pmap_int(list(1), ~ 1:2) 12 | Condition 13 | Error in `pmap_int()`: 14 | i In index: 1. 15 | Caused by error: 16 | ! Result must be length 1, not 2. 17 | Code 18 | pmap_vec(list(1), ~1, .ptype = character()) 19 | Condition 20 | Error in `pmap_vec()`: 21 | ! Can't convert `[[1]]` to . 22 | 23 | # requires list of vectors 24 | 25 | Code 26 | pmap(environment(), identity) 27 | Condition 28 | Error in `pmap()`: 29 | ! `.l` must be a list, not an environment. 30 | Code 31 | pmap(list(environment()), identity) 32 | Condition 33 | Error in `pmap()`: 34 | ! `.l[[1]]` must be a vector, not an environment. 35 | 36 | # recycles inputs 37 | 38 | Code 39 | pmap(list(1:2, 1:3), `+`) 40 | Condition 41 | Error in `pmap()`: 42 | ! Can't recycle `.l[[1]]` (size 2) to match `.l[[2]]` (size 3). 43 | Code 44 | pmap(list(1:2, integer()), `+`) 45 | Condition 46 | Error in `pmap()`: 47 | ! Can't recycle `.l[[1]]` (size 2) to match `.l[[2]]` (size 0). 48 | 49 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/rate.md: -------------------------------------------------------------------------------- 1 | # rates have print methods 2 | 3 | Code 4 | rate_delay(20, max_times = Inf) 5 | Message 6 | 7 | Attempts: 0/Inf 8 | pause: 20 9 | Code 10 | rate_backoff() 11 | Message 12 | 13 | Attempts: 0/3 14 | pause_base: 1 15 | pause_cap: 60 16 | pause_min: 1 17 | 18 | # rate_delay() delays 19 | 20 | Code 21 | rate_sleep(rate) 22 | Condition 23 | Error in `rate_sleep()`: 24 | ! Request failed after 3 attempts. 25 | 26 | --- 27 | 28 | Code 29 | rate_sleep(rate) 30 | Condition 31 | Error in `rate_sleep()`: 32 | ! This `rate` object has already be run more than `max_times` allows. 33 | i Do you need to reset it with `rate_reset()`? 34 | 35 | # rate_backoff() backs off 36 | 37 | Code 38 | rate_sleep(rate) 39 | Condition 40 | Error in `rate_sleep()`: 41 | ! Request failed after 3 attempts. 42 | 43 | --- 44 | 45 | Code 46 | rate_sleep(rate) 47 | Condition 48 | Error in `rate_sleep()`: 49 | ! This `rate` object has already be run more than `max_times` allows. 50 | i Do you need to reset it with `rate_reset()`? 51 | 52 | # rate_sleep() checks that rate is still valid 53 | 54 | Code 55 | rate_sleep(rate) 56 | Condition 57 | Error in `rate_sleep()`: 58 | ! Request failed after 0 attempts. 59 | 60 | --- 61 | 62 | Code 63 | rate_sleep(rate) 64 | Condition 65 | Error in `rate_sleep()`: 66 | ! This `rate` object has already be run more than `max_times` allows. 67 | i Do you need to reset it with `rate_reset()`? 68 | 69 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/reduce.md: -------------------------------------------------------------------------------- 1 | # empty input returns init or error 2 | 3 | Code 4 | reduce(list()) 5 | Condition 6 | Error in `reduce()`: 7 | ! Must supply `.init` when `.x` is empty. 8 | 9 | # accumulate() does fail when simpification is required 10 | 11 | Code 12 | accumulate(list(1, "a"), ~.y, .simplify = TRUE) 13 | Condition 14 | Error in `accumulate()`: 15 | ! Can't combine `res[[1]]` and `res[[2]]` . 16 | 17 | # requires equal length vectors 18 | 19 | Code 20 | reduce2(1:3, 1, `+`) 21 | Condition 22 | Error in `reduce2()`: 23 | ! `.y` must have length 2, not 1. 24 | 25 | # requires init if `.x` is empty 26 | 27 | Code 28 | reduce2(list()) 29 | Condition 30 | Error in `reduce2()`: 31 | ! Must supply `.init` when `.x` is empty. 32 | 33 | # right variants are retired 34 | 35 | Code 36 | . <- reduce_right(1:3, c) 37 | Condition 38 | Warning: 39 | `reduce_right()` was deprecated in purrr 0.3.0. 40 | i Please use the `.dir` argument of `reduce()` instead. 41 | Code 42 | . <- reduce2_right(1:3, 1:2, c) 43 | Condition 44 | Warning: 45 | `reduce2_right()` was deprecated in purrr 0.3.0. 46 | i Please use reverse your vectors and use `reduce2()` instead. 47 | Code 48 | . <- accumulate_right(1:3, c) 49 | Condition 50 | Warning: 51 | `accumulate_right()` was deprecated in purrr 0.3.0. 52 | i Please use the `.dir` argument of `accumulate()` instead. 53 | 54 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/superseded-flatten.md: -------------------------------------------------------------------------------- 1 | # input must be a list 2 | 3 | Code 4 | flatten(1) 5 | Condition 6 | Error in `flatten()`: 7 | ! `.x` must be a list, not a number. 8 | 9 | --- 10 | 11 | Code 12 | flatten_dbl(1) 13 | Condition 14 | Error in `flatten_dbl()`: 15 | ! `.x` must be a list, not a number. 16 | 17 | # contents of list must be supported types 18 | 19 | Code 20 | flatten(list(quote(a))) 21 | Condition 22 | Error in `flatten()`: 23 | ! `.x[[1]]` must be a vector, not a symbol. 24 | 25 | --- 26 | 27 | Code 28 | flatten(list(expression(a))) 29 | Condition 30 | Error in `flatten()`: 31 | ! `.x[[1]]` must be a vector, not an expression vector. 32 | 33 | # must be a list 34 | 35 | Code 36 | flatten_lgl(1) 37 | Condition 38 | Error in `flatten_lgl()`: 39 | ! `.x` must be a list, not a number. 40 | 41 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/superseded-transpose.md: -------------------------------------------------------------------------------- 1 | # input must be a list 2 | 3 | Code 4 | transpose(1:3) 5 | Condition 6 | Error in `transpose()`: 7 | ! `.l` must be a list, not an integer vector. 8 | 9 | # elements of input must be atomic vectors 10 | 11 | Code 12 | transpose(list(environment())) 13 | Condition 14 | Error in `transpose()`: 15 | ! Element 1 must be a vector, not an environment. 16 | 17 | --- 18 | 19 | Code 20 | transpose(list(list(), environment())) 21 | Condition 22 | Error in `transpose()`: 23 | ! Element 2 must be a vector, not an environment. 24 | 25 | # can't transpose expressions 26 | 27 | Code 28 | transpose(list(expression(a))) 29 | Condition 30 | Error in `transpose()`: 31 | ! Transposed element must be a vector, not an expression vector. 32 | 33 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/utils.md: -------------------------------------------------------------------------------- 1 | # errors on invalid subsetting vectors 2 | 3 | Code 4 | where_at(x, c(FALSE, TRUE)) 5 | Condition 6 | Error: 7 | ! Can't subset elements with `at`. 8 | x Logical subscript `at` must be size 1 or 3, not 2. 9 | Code 10 | where_at(x, NA_real_) 11 | Condition 12 | Error: 13 | ! Can't subset elements. 14 | x Subscript can't contain missing values. 15 | x It has a missing value at location 1. 16 | Code 17 | where_at(x, 4) 18 | Condition 19 | Error: 20 | ! Can't subset elements past the end. 21 | i Location 4 doesn't exist. 22 | i There are only 3 elements. 23 | 24 | # validates its inputs 25 | 26 | Code 27 | where_at(x, list()) 28 | Condition 29 | Error: 30 | ! `list()` must be a numeric vector, character vector, or function, not an empty list. 31 | 32 | # tidyselect `at` is deprecated 33 | 34 | Code 35 | . <- where_at(data.frame(x = 1), vars("x"), user_env = globalenv()) 36 | Condition 37 | Warning: 38 | Using `vars()` in .at was deprecated in purrr 1.0.0. 39 | 40 | # pairlists, expressions, and calls are deprecated 41 | 42 | Code 43 | x <- vctrs_vec_compat(expression(1, 2), globalenv()) 44 | Condition 45 | Warning: 46 | Use of calls and pairlists in map functions was deprecated in purrr 1.0.0. 47 | i Please coerce explicitly with `as.list()` 48 | 49 | --- 50 | 51 | Code 52 | x <- vctrs_vec_compat(pairlist(1, 2), globalenv()) 53 | Condition 54 | Warning: 55 | Use of pairlists in map functions was deprecated in purrr 1.0.0. 56 | i Please coerce explicitly with `as.list()` 57 | 58 | --- 59 | 60 | Code 61 | x <- vctrs_vec_compat(quote(f(a, b = 1)), globalenv()) 62 | Condition 63 | Warning: 64 | Use of calls and pairlists in map functions was deprecated in purrr 1.0.0. 65 | i Please coerce explicitly with `as.list()` 66 | 67 | # can't work with regular S4 objects 68 | 69 | Code 70 | map(foo(), identity) 71 | Condition 72 | Error in `x[[i]]`: 73 | ! this S4 class is not subsettable 74 | 75 | -------------------------------------------------------------------------------- /tests/testthat/helper-map.R: -------------------------------------------------------------------------------- 1 | named <- function(x) set_names(x, chr()) 2 | 3 | # Until we can reexport from rlang 4 | vars <- function(...) rlang::quos(...) 5 | -------------------------------------------------------------------------------- /tests/testthat/helper.R: -------------------------------------------------------------------------------- 1 | expect_bare <- function(x, type) { 2 | predicate <- switch( 3 | type, 4 | logical = is_bare_logical, 5 | integer = is_bare_integer, 6 | double = is_bare_double, 7 | complex = is_bare_complex, 8 | character = is_bare_character, 9 | raw = is_bare_raw, 10 | list = is_bare_list, 11 | ) 12 | 13 | expect_true(predicate(x)) 14 | } 15 | 16 | local_name_repair_quiet <- function(frame = caller_env()) { 17 | local_options(rlib_name_repair_verbosity = "quiet", .frame = frame) 18 | } 19 | local_name_repair_verbose <- function(frame = caller_env()) { 20 | local_options(rlib_name_repair_verbosity = "verbose", .frame = frame) 21 | } 22 | 23 | local_methods <- function(..., .frame = caller_env()) { 24 | local_bindings(..., .env = global_env(), .frame = .frame) 25 | } 26 | -------------------------------------------------------------------------------- /tests/testthat/setup.R: -------------------------------------------------------------------------------- 1 | Sys.setlocale("LC_MESSAGES", "C") 2 | -------------------------------------------------------------------------------- /tests/testthat/test-adverb-auto-browse.R: -------------------------------------------------------------------------------- 1 | test_that("auto_browse() not intended for primitive functions", { 2 | expect_snapshot(auto_browse(log)(NULL), error = TRUE) 3 | expect_no_error(auto_browse(identity)(NULL)) 4 | }) 5 | -------------------------------------------------------------------------------- /tests/testthat/test-adverb-insistently.R: -------------------------------------------------------------------------------- 1 | test_that("insistently() resets rate state", { 2 | fn <- insistently(compose(), rate_delay(1, max_times = 0)) 3 | expect_snapshot_error(fn(), class = "purrr_error_rate_excess") 4 | expect_snapshot_error(fn(), class = "purrr_error_rate_excess") 5 | }) 6 | 7 | test_that("validates inputs", { 8 | expect_snapshot(error = TRUE, { 9 | insistently(mean, 10) 10 | }) 11 | }) 12 | -------------------------------------------------------------------------------- /tests/testthat/test-adverb-negate.R: -------------------------------------------------------------------------------- 1 | test_that("negate works with both functions and vectors", { 2 | true <- function(...) TRUE 3 | expect_equal(negate(true)(), FALSE) 4 | expect_equal(negate("x")(list(x = TRUE)), FALSE) 5 | 6 | expect_equal(negate(is.null)(TRUE), TRUE) 7 | expect_equal(negate(is.null)(NULL), FALSE) 8 | }) 9 | 10 | test_that("negate() works with early returns", { 11 | expect_false(negate(~ return(TRUE))()) 12 | }) 13 | 14 | test_that("negate() works with generic functions and local methods", { 15 | is_foobar <- function(x) UseMethod("is_foobar") 16 | local({ 17 | is_foobar.default <- function(x) TRUE 18 | expect_false(negate(is_foobar)()) 19 | }) 20 | }) 21 | -------------------------------------------------------------------------------- /tests/testthat/test-adverb-possibly.R: -------------------------------------------------------------------------------- 1 | test_that("possibly returns default value on failure", { 2 | expect_identical(possibly(log, NA_real_)("a"), NA_real_) 3 | }) 4 | 5 | test_that("possibly emits a message on failure if quiet = FALSE", { 6 | f <- function(...) stop("tilt") 7 | expect_message({ 8 | possibly(f, NA_real_, quiet = FALSE)() 9 | }, regexp = "tilt") 10 | }) 11 | 12 | -------------------------------------------------------------------------------- /tests/testthat/test-adverb-quietly.R: -------------------------------------------------------------------------------- 1 | test_that("quietly captures output", { 2 | f <- function() { 3 | cat(1) 4 | message(2, appendLF = FALSE) 5 | warning(3) 6 | 4 7 | } 8 | expect_output(quietly(f)(), NA) 9 | expect_message(quietly(f)(), NA) 10 | expect_warning(quietly(f)(), NA) 11 | 12 | out <- quietly(f)() 13 | expect_equal(out, list( 14 | result = 4, 15 | output = "1", 16 | warnings = "3", 17 | messages = "2" 18 | )) 19 | }) 20 | -------------------------------------------------------------------------------- /tests/testthat/test-adverb-safely.R: -------------------------------------------------------------------------------- 1 | test_that("safely has NULL error when successful", { 2 | out <- safely(log10)(10) 3 | expect_equal(out, list(result = 1, error = NULL)) 4 | }) 5 | 6 | test_that("safely has NULL result on failure", { 7 | out <- safely(log10)("a") 8 | expect_equal(out$result, NULL) 9 | expect_equal(out$error$message, 10 | "non-numeric argument to mathematical function") 11 | }) 12 | 13 | -------------------------------------------------------------------------------- /tests/testthat/test-adverb-slowly.R: -------------------------------------------------------------------------------- 1 | test_that("validates inputs", { 2 | expect_snapshot(error = TRUE, { 3 | slowly(mean, 10) 4 | }) 5 | }) 6 | -------------------------------------------------------------------------------- /tests/testthat/test-arrays.R: -------------------------------------------------------------------------------- 1 | x <- array(1:12, c(2, 2, 3), dimnames = list(letters[1:2], LETTERS[1:2], NULL)) 2 | 3 | test_that("array_branch creates a flat list when no margin specified", { 4 | expect_length(array_branch(x), 12) 5 | }) 6 | 7 | test_that("array_branch wraps array in list when margin has length 0", { 8 | expect_identical(array_branch(x, numeric(0)), list(x)) 9 | }) 10 | 11 | test_that("array_branch works on vectors", { 12 | expect_identical(array_branch(1:3), list(1L, 2L, 3L)) 13 | expect_identical(array_branch(1:3, 1), list(1L, 2L, 3L)) 14 | }) 15 | 16 | test_that("array_branch throws an error for wrong margins on a vector", { 17 | expect_snapshot(array_branch(1:3, 2), error = TRUE) 18 | }) 19 | 20 | test_that("length depends on whether list is flattened or not", { 21 | m1 <- c(3, 1) 22 | m2 <- 3 23 | expect_length(array_branch(x, m1), prod(dim(x)[m1])) 24 | expect_length(array_tree(x, m1), prod(dim(x)[m2])) 25 | }) 26 | 27 | test_that("array_branch retains dimnames when going over one dimension", { 28 | expect_identical(names(array_branch(x, 1)), letters[1:2]) 29 | expect_identical(names(array_branch(x, 2)), LETTERS[1:2]) 30 | expect_identical(names(array_branch(x, 2:3)[[1]]), letters[1:2]) 31 | }) 32 | -------------------------------------------------------------------------------- /tests/testthat/test-coerce.R: -------------------------------------------------------------------------------- 1 | test_that("can coerce to logical vectors",{ 2 | expect_equal(coerce_lgl(c(TRUE, FALSE, NA)), c(TRUE, FALSE, NA)) 3 | 4 | expect_equal(coerce_lgl(c(1L, 0L, NA)), c(TRUE, FALSE, NA)) 5 | expect_snapshot(coerce_lgl(2L), error = TRUE) 6 | 7 | expect_equal(coerce_lgl(c(1, 0, NA)), c(TRUE, FALSE, NA)) 8 | expect_snapshot(coerce_lgl(1.5), error = TRUE) 9 | 10 | expect_snapshot(coerce_lgl("true"), error = TRUE) 11 | }) 12 | 13 | test_that("can coerce to integer vectors", { 14 | expect_identical(coerce_int(c(TRUE, FALSE, NA)), c(1L, 0L, NA)) 15 | 16 | expect_identical(coerce_int(c(NA, 1L, 10L)), c(NA, 1L, 10L)) 17 | 18 | expect_identical(coerce_int(c(NA, 1, 10)), c(NA, 1L, 10L)) 19 | expect_snapshot(coerce_int(1.5), error = TRUE) 20 | 21 | expect_snapshot(coerce_int("1"), error = TRUE) 22 | }) 23 | 24 | test_that("can coerce to double vctrs", { 25 | expect_identical(coerce_dbl(c(TRUE, FALSE, NA)), c(1, 0, NA)) 26 | 27 | expect_identical(coerce_dbl(c(NA, 1L, 10L)), c(NA, 1, 10)) 28 | 29 | expect_identical(coerce_dbl(c(NA, 1.5)), c(NA, 1.5)) 30 | 31 | expect_snapshot(coerce_dbl("1.5"), error = TRUE) 32 | }) 33 | 34 | test_that("can coerce to character vectors", { 35 | expect_equal(coerce_chr(NA), NA_character_) 36 | 37 | expect_snapshot({ 38 | expect_equal(coerce_chr(TRUE), "TRUE") 39 | expect_equal(coerce_chr(1L), "1") 40 | expect_equal(coerce_chr(1.5), "1.500000") 41 | }) 42 | 43 | expect_equal(coerce_chr("x"), "x") 44 | }) 45 | 46 | test_that("error captures correct env", { 47 | indirect <- function() { 48 | purrr::map_chr(1:4, identity) 49 | } 50 | environment(indirect) <- ns_env("rlang") 51 | 52 | expect_snapshot({ 53 | map_chr(1:4, identity) 54 | indirect() 55 | }) 56 | 57 | }) 58 | 59 | test_that("warns once per vector", { 60 | expect_warning(expect_warning(coerce_chr(1:5)), NA) 61 | }) 62 | 63 | test_that("can't coerce to expressions", { 64 | expect_snapshot(coerce(list(1), "expression"), error = TRUE) 65 | }) 66 | -------------------------------------------------------------------------------- /tests/testthat/test-conditions.R: -------------------------------------------------------------------------------- 1 | test_that("stop_bad_type() constructs default `what`", { 2 | expect_snapshot(stop_bad_type(NA, "`NULL`"), error = TRUE) 3 | expect_snapshot(stop_bad_type(NA, "`NULL`", arg = ".foo"), error = TRUE) 4 | expect_snapshot(stop_bad_type(NA, "`NULL`", arg = quote(.foo)), error = TRUE) 5 | }) 6 | 7 | test_that("stop_bad_element_type() constructs type errors", { 8 | expect_snapshot(stop_bad_element_type(1:3, 3, "a foobaz"), error = TRUE) 9 | expect_snapshot(stop_bad_element_type(1:3, 3, "a foobaz", actual = "a quux"), error = TRUE) 10 | expect_snapshot(stop_bad_element_type(1:3, 3, "a foobaz", arg = "..arg"), error = TRUE) 11 | }) 12 | 13 | test_that("stop_bad_element_type() accepts `what`", { 14 | expect_snapshot(stop_bad_element_type(1:3, 3, "a foobaz", what = "Result"), error = TRUE) 15 | }) 16 | 17 | test_that("stop_bad_element_length() constructs error message", { 18 | expect_snapshot(stop_bad_element_length(1:3, 8, 10), error = TRUE) 19 | expect_snapshot(stop_bad_element_length(1:3, 8, 10, arg = ".foo"), error = TRUE) 20 | expect_snapshot(stop_bad_element_length(1:3, 8, 10, arg = ".foo", what = "Result"), error = TRUE) 21 | expect_snapshot(stop_bad_element_length(1:3, 8, 10, arg = ".foo", what = "Result", recycle = TRUE), error = TRUE) 22 | }) 23 | -------------------------------------------------------------------------------- /tests/testthat/test-deprec-along.R: -------------------------------------------------------------------------------- 1 | test_that("list-along is deprecated", { 2 | expect_snapshot({ 3 | . <- list_along(1:4) 4 | }) 5 | }) 6 | 7 | test_that("list_along works", { 8 | local_options(lifecycle_verbosity = "quiet") 9 | 10 | x <- 1:5 11 | expect_identical(list_along(x), vector("list", 5)) 12 | }) 13 | 14 | test_that("rep_along works", { 15 | local_options(lifecycle_verbosity = "quiet") 16 | 17 | expect_equal( 18 | rep_along(c("c", "b", "a"), 1:3), 19 | rep_along(c("d", "f", "e"), 1:3) 20 | ) 21 | }) 22 | -------------------------------------------------------------------------------- /tests/testthat/test-deprec-cross.R: -------------------------------------------------------------------------------- 1 | test_that("long format corresponds to expand.grid output", { 2 | skip_if_not_installed("tibble") 3 | local_options(lifecycle_verbosity = "quiet") 4 | 5 | x <- list(a = 1:3, b = 4:9) 6 | 7 | out1 <- cross_df(x) 8 | out2 <- expand.grid(x, KEEP.OUT.ATTRS = FALSE) %>% tibble::as_tibble() 9 | 10 | expect_equal(out1, out2) 11 | }) 12 | 13 | test_that("filtering works", { 14 | local_options(lifecycle_verbosity = "quiet") 15 | filter <- function(x, y) x >= y 16 | out <- cross2(1:3, 1:3, .filter = filter) 17 | expect_equal(out, list(list(1, 2), list(1, 3), list(2, 3))) 18 | }) 19 | 20 | test_that("filtering requires a predicate function", { 21 | local_options(lifecycle_verbosity = "quiet") 22 | expect_snapshot(cross2(1:3, 1:3, .filter = ~ c(TRUE, TRUE)), error = TRUE) 23 | }) 24 | 25 | test_that("filtering fails when filter function doesn't return a logical", { 26 | local_options(lifecycle_verbosity = "quiet") 27 | filter <- function(x, y, z) x + y + z 28 | expect_snapshot(cross3(1:3, 1:3, 1:3, .filter = filter), error = TRUE) 29 | }) 30 | 31 | test_that("works with empty input", { 32 | local_options(lifecycle_verbosity = "quiet") 33 | expect_equal(cross(list()), list()) 34 | expect_equal(cross(NULL), NULL) 35 | }) 36 | -------------------------------------------------------------------------------- /tests/testthat/test-deprec-lift.R: -------------------------------------------------------------------------------- 1 | test_that("lift_dl and lift_ld are inverses of each other", { 2 | options(lifecycle_verbosity = "quiet") 3 | 4 | expect_identical( 5 | sum %>% 6 | lift_dl(.unnamed = TRUE) %>% 7 | do.call(list(3, NA, 4, na.rm = TRUE)), 8 | sum %>% 9 | lift_dl() %>% 10 | lift_ld() %>% 11 | exec(3, NA, 4, na.rm = TRUE) 12 | ) 13 | }) 14 | 15 | test_that("lift_dv is from ... to c(...)", { 16 | options(lifecycle_verbosity = "quiet") 17 | 18 | expect_equal(lift_dv(range, .unnamed = TRUE)(1:10), c(1, 10)) 19 | }) 20 | 21 | test_that("lift_vd is from c(...) to ...", { 22 | options(lifecycle_verbosity = "quiet") 23 | 24 | expect_equal(lift_vd(mean)(1, 2), 1.5) 25 | }) 26 | 27 | test_that("lift_vl is from c(...) to list(...)", { 28 | options(lifecycle_verbosity = "quiet") 29 | 30 | expect_equal(lift_vl(mean)(list(1, 2)), 1.5) 31 | }) 32 | 33 | test_that("lift_lv is from list(...) to c(...)", { 34 | options(lifecycle_verbosity = "quiet") 35 | 36 | glue <- function(l) { 37 | if (!is.list(l)) stop("not a list") 38 | l %>% do.call(paste, .) 39 | } 40 | expect_identical(lift_lv(glue)(letters), paste(letters, collapse = " ")) 41 | }) 42 | 43 | 44 | test_that("lift functions are deprecated", { 45 | expect_snapshot({ 46 | . <- lift_dl(function() {}) 47 | . <- lift_dv(function() {}) 48 | . <- lift_vl(function() {}) 49 | . <- lift_vd(function() {}) 50 | . <- lift_ld(function() {}) 51 | . <- lift_lv(function() {}) 52 | }) 53 | 54 | }) 55 | -------------------------------------------------------------------------------- /tests/testthat/test-deprec-map.R: -------------------------------------------------------------------------------- 1 | test_that("at_depth is defunct", { 2 | expect_snapshot(at_depth(), error = TRUE) 3 | }) 4 | -------------------------------------------------------------------------------- /tests/testthat/test-deprec-prepend.R: -------------------------------------------------------------------------------- 1 | test_that("prepend is deprecated", { 2 | expect_snapshot({ 3 | . <- prepend(1, 2) 4 | }) 5 | }) 6 | 7 | test_that("prepend is clearer version of merging with c()", { 8 | local_options(lifecycle_verbosity = "quiet") 9 | 10 | x <- 1:3 11 | expect_identical( 12 | x %>% prepend(4), 13 | x %>% c(4, .) 14 | ) 15 | expect_identical( 16 | x %>% prepend(4, before = 3), 17 | x %>% { 18 | c(.[1:2], 4, .[3]) 19 | } 20 | ) 21 | }) 22 | 23 | test_that("prepend appends at the beginning for empty list by default", { 24 | local_options(lifecycle_verbosity = "quiet") 25 | 26 | x <- list() 27 | expect_identical( 28 | x %>% prepend(1), 29 | x %>% c(1, .) 30 | ) 31 | }) 32 | 33 | test_that("prepend throws error if before param is neither NULL nor between 1 and length(x)", { 34 | local_options(lifecycle_verbosity = "quiet") 35 | 36 | expect_snapshot(prepend(list(), 1, before = 1), error = TRUE) 37 | x <- as.list(1:3) 38 | expect_snapshot(x %>% prepend(4, before = 0), error = TRUE) 39 | expect_snapshot(x %>% prepend(4, before = 4), error = TRUE) 40 | }) 41 | -------------------------------------------------------------------------------- /tests/testthat/test-deprec-rerun.R: -------------------------------------------------------------------------------- 1 | test_that("is deprecated", { 2 | expect_snapshot({ 3 | . <- rerun(5, rnorm(1)) 4 | . <- rerun(5, rnorm(1), rnorm(2)) 5 | }) 6 | 7 | }) 8 | 9 | test_that("single unnamed arg doesn't get extra list", { 10 | local_options(lifecycle_verbosity = "quiet") 11 | expect_equal(rerun(2, 1), list(1, 1)) 12 | }) 13 | 14 | test_that("single named arg gets extra list", { 15 | local_options(lifecycle_verbosity = "quiet") 16 | expect_equal(rerun(2, a = 1), list(list(a = 1), list(a = 1))) 17 | }) 18 | 19 | test_that("every run is different", { 20 | local_options(lifecycle_verbosity = "quiet") 21 | x <- rerun(2, runif(1)) 22 | expect_true(x[[1]] != x[[2]]) 23 | }) 24 | 25 | test_that("rerun uses scope of expression", { 26 | local_options(lifecycle_verbosity = "quiet") 27 | f <- function(n) { 28 | rerun(1, x = seq_len(n)) 29 | } 30 | 31 | expect_equal(f(10)[[1]]$x, 1:10) 32 | }) 33 | -------------------------------------------------------------------------------- /tests/testthat/test-deprec-splice.R: -------------------------------------------------------------------------------- 1 | test_that("predicate controls which elements get spliced", { 2 | x <- list(1, 2, list(3, 4)) 3 | 4 | expect_equal(splice_if(x, ~ FALSE), x) 5 | expect_equal(splice_if(x, is.list), list(1, 2, 3, 4)) 6 | }) 7 | 8 | test_that("splice() produces correctly named lists", { 9 | local_options(lifecycle_verbosity = "quiet") 10 | inputs <- list(arg1 = "a", arg2 = "b") 11 | 12 | out1 <- splice(inputs, arg3 = c("c1", "c2")) 13 | expect_named(out1, c("arg1", "arg2", "arg3")) 14 | 15 | out2 <- splice(inputs, arg = list(arg3 = 1, arg4 = 2)) 16 | expect_named(out2, c("arg1", "arg2", "arg3", "arg4")) 17 | }) 18 | 19 | test_that("splice is deprecated", { 20 | expect_snapshot({ 21 | . <- splice() 22 | }) 23 | 24 | }) 25 | -------------------------------------------------------------------------------- /tests/testthat/test-deprec-utils.R: -------------------------------------------------------------------------------- 1 | test_that("rdunif and rbernoulli are deprecated", { 2 | expect_snapshot({ 3 | . <- rdunif(10, 1) 4 | . <- rbernoulli(10) 5 | }) 6 | }) 7 | 8 | test_that("rbernoulli is a special case of rbinom", { 9 | local_options(lifecycle_verbosity = "quiet") 10 | 11 | set.seed(1) 12 | x <- rbernoulli(10) 13 | 14 | set.seed(1) 15 | y <- ifelse(rbinom(10, 1, 0.5) == 1, TRUE, FALSE) 16 | 17 | expect_equal(x, y) 18 | }) 19 | 20 | test_that("rdunif works", { 21 | local_options(lifecycle_verbosity = "quiet") 22 | 23 | expect_length(rdunif(100, 10), 100) 24 | }) 25 | 26 | test_that("rdunif fails if a and b are not unit length numbers", { 27 | local_options(lifecycle_verbosity = "quiet") 28 | 29 | expect_snapshot(rdunif(1000, 1, "a"), error = TRUE) 30 | expect_snapshot(rdunif(1000, 1, c(0.5, 0.2)), error = TRUE) 31 | expect_snapshot(rdunif(1000, FALSE, 2), error = TRUE) 32 | expect_snapshot(rdunif(1000, c(2, 3), 2), error = TRUE) 33 | }) 34 | 35 | 36 | # Lifecycle --------------------------------------------------------------- 37 | 38 | test_that("%@% is an infix attribute accessor", { 39 | local_options(lifecycle_verbosity = "quiet") 40 | expect_identical(mtcars %@% "names", attr(mtcars, "names")) 41 | }) 42 | 43 | -------------------------------------------------------------------------------- /tests/testthat/test-deprec-when.R: -------------------------------------------------------------------------------- 1 | test_that("when is deprecated", { 2 | expect_snapshot({ 3 | . <- when(1:5 < 3 ~ 1, ~ 0) 4 | }) 5 | }) 6 | 7 | test_that("when chooses the correct action", { 8 | local_options(lifecycle_verbosity = "quiet") 9 | 10 | x <- 11 | 1:5 %>% 12 | when( 13 | sum(.) <= 50 ~ sum(.), 14 | sum(.) <= 100 ~ sum(.) / 2, 15 | ~ 0 16 | ) 17 | 18 | expect_equal(x, 15) 19 | 20 | y <- 21 | 1:10 %>% 22 | when( 23 | sum(.) <= 50 ~ sum(.), 24 | sum(.) <= 100 ~ sum(.) / 2, 25 | ~ 0 26 | ) 27 | 28 | expect_equal(y, sum(1:10) / 2) 29 | 30 | z <- 31 | 1:100 %>% 32 | when( 33 | sum(.) <= 50 ~ sum(.), 34 | sum(.) <= 100 ~ sum(.) / 2, 35 | ~ 0 36 | ) 37 | 38 | expect_equal(z, 0) 39 | }) 40 | 41 | test_that("named arguments work with when", { 42 | local_options(lifecycle_verbosity = "quiet") 43 | 44 | x <- 45 | 1:10 %>% 46 | when( 47 | sum(.) <= x ~ sum(.) * x, 48 | sum(.) <= 2 * x ~ sum(.) * x / 2, 49 | ~ 0, 50 | x = 60 51 | ) 52 | 53 | expect_equal(x, sum(1:10) * 60) 54 | }) 55 | 56 | test_that("default values work without a formula", { 57 | local_options(lifecycle_verbosity = "quiet") 58 | 59 | x <- iris %>% 60 | subset(Sepal.Length > 10) %>% 61 | when( 62 | nrow(.) > 0 ~ ., 63 | head(iris, 10) 64 | ) 65 | 66 | expect_equal(x, head(iris, 10)) 67 | }) 68 | 69 | test_that("error when named arguments have no matching conditions", { 70 | local_options(lifecycle_verbosity = "quiet") 71 | 72 | expect_snapshot(1:5 %>% when(a = sum(.) < 5 ~ 3), error = TRUE) 73 | }) 74 | -------------------------------------------------------------------------------- /tests/testthat/test-detect.R: -------------------------------------------------------------------------------- 1 | y <- 4:10 2 | 3 | test_that("detect functions work", { 4 | is_odd <- function(x) x %% 2 == 1 5 | expect_equal(detect(y, is_odd), 5) 6 | expect_equal(detect_index(y, is_odd), 2) 7 | expect_equal(detect(y, is_odd, .dir = "backward"), 9) 8 | expect_equal(detect_index(y, is_odd, .dir = "backward"), 6) 9 | }) 10 | 11 | test_that("detect returns NULL when match not found", { 12 | expect_null(detect(y, function(x) x > 11)) 13 | }) 14 | 15 | test_that("detect_index returns 0 when match not found", { 16 | expect_equal(detect_index(y, function(x) x > 11), 0) 17 | }) 18 | 19 | test_that("has_element checks whether a list contains an object", { 20 | expect_true(has_element(list(1, 2), 1)) 21 | expect_false(has_element(list(1, 2), 3)) 22 | }) 23 | 24 | test_that("`detect()` requires a predicate function", { 25 | expect_snapshot(detect(list(1:2, 2), is.na), error = TRUE) 26 | expect_snapshot(detect_index(list(1:2, 2), is.na), error = TRUE) 27 | }) 28 | 29 | 30 | # Lifecycle --------------------------------------------------------------- 31 | 32 | test_that("`.right` argument is retired", { 33 | 34 | expect_snapshot({ 35 | . <- detect(1:2, ~ TRUE, .right = TRUE) 36 | . <- detect_index(1:2, ~ TRUE, .right = TRUE) 37 | }) 38 | }) 39 | 40 | test_that("`.right` argument still works", { 41 | local_options(lifecycle_verbosity = "quiet") 42 | is_odd <- function(x) x %% 2 == 1 43 | expect_equal(detect(y, is_odd, .right = TRUE), 9) 44 | expect_equal(detect_index(y, is_odd, .right = TRUE), 6) 45 | }) 46 | -------------------------------------------------------------------------------- /tests/testthat/test-every-some-none.R: -------------------------------------------------------------------------------- 1 | test_that("every returns TRUE if all elements are TRUE", { 2 | x <- list(0, 1, TRUE) 3 | expect_false(every(x, isTRUE)) 4 | expect_true(every(x[3], isTRUE)) 5 | }) 6 | 7 | test_that("some returns FALSE if all elements are FALSE", { 8 | x <- list(1, 0, FALSE) 9 | expect_false(some(x, isTRUE)) 10 | expect_true(some(x[1], negate(isTRUE))) 11 | }) 12 | 13 | test_that("none returns TRUE if all elements are FALSE", { 14 | x <- list(1, 0, TRUE) 15 | expect_false(none(x, isTRUE)) 16 | expect_true(none(x[1], isTRUE)) 17 | }) 18 | 19 | test_that("every() requires logical value", { 20 | expect_snapshot(every(list(1:3), identity), error = TRUE) 21 | expect_snapshot(every(list(function() NULL), identity), error = TRUE) 22 | }) 23 | 24 | test_that("every() has the same behaviour as `&&` (#751)", { 25 | expect_false(every(list(NA, FALSE), identity)) 26 | expect_false(every(list(FALSE, NA), identity)) 27 | 28 | expect_identical(every(list(NA, TRUE), identity), NA) 29 | expect_identical(every(list(TRUE, NA), identity), NA) 30 | expect_identical(every(list(NA, NA), identity), NA) 31 | }) 32 | 33 | test_that("some() has the same behaviour as `||`", { 34 | expect_true(some(list(TRUE, NA), identity)) 35 | expect_true(some(list(NA, TRUE), identity)) 36 | 37 | expect_identical(some(list(NA, FALSE), identity), NA) 38 | expect_identical(some(list(FALSE, NA), identity), NA) 39 | expect_identical(some(list(NA, NA), identity), NA) 40 | }) 41 | -------------------------------------------------------------------------------- /tests/testthat/test-head-tail.R: -------------------------------------------------------------------------------- 1 | y <- 1:100 2 | 3 | test_that("head_while works", { 4 | expect_length(head_while(y, function(x) x <= 15), 15) 5 | }) 6 | 7 | test_that("tail_while works", { 8 | expect_length(tail_while(y, function(x) x >= 86), 15) 9 | }) 10 | 11 | test_that("original vector returned if predicate satisfied by all elements", { 12 | expect_identical(head_while(y, function(x) x <= 100), y) 13 | expect_identical(tail_while(y, function(x) x >= 0), y) 14 | }) 15 | 16 | test_that("head_while and tail_while require predicate function", { 17 | expect_snapshot(head_while(1:3, ~ NA), error = TRUE) 18 | expect_snapshot(tail_while(1:3, ~ c(TRUE, FALSE)), error = TRUE) 19 | }) 20 | -------------------------------------------------------------------------------- /tests/testthat/test-imap.R: -------------------------------------------------------------------------------- 1 | x <- 1:3 %>% set_names() 2 | 3 | test_that("imap is special case of map2", { 4 | expect_identical(imap(x, paste), map2(x, names(x), paste)) 5 | }) 6 | 7 | test_that("imap always returns a list", { 8 | expect_bare(imap(x, paste), "list") 9 | }) 10 | 11 | test_that("atomic vector imap works", { 12 | expect_true(all(imap_lgl(x, `==`))) 13 | expect_length(imap_chr(x, paste), 3) 14 | expect_equal(imap_int(x, ~ .x + as.integer(.y)), x * 2) 15 | expect_equal(imap_dbl(x, ~ .x + as.numeric(.y)), x * 2) 16 | expect_equal(imap_vec(x, ~ .x + as.numeric(.y)), x * 2) 17 | }) 18 | 19 | test_that("iwalk returns invisibly", { 20 | expect_output(iwalk(mtcars, ~ cat(.y, ": ", median(.x), "\n", sep = ""))) 21 | }) 22 | -------------------------------------------------------------------------------- /tests/testthat/test-keep.R: -------------------------------------------------------------------------------- 1 | test_that("can keep/discard with logical vector", { 2 | expect_equal(keep(1:3, c(TRUE, FALSE, TRUE)), c(1, 3)) 3 | expect_equal(discard(1:3, c(TRUE, FALSE, TRUE)), 2) 4 | }) 5 | 6 | test_that("can keep/discard with predicate", { 7 | expect_equal(keep(1:3, ~ .x != 2), c(1, 3)) 8 | expect_equal(discard(1:3, ~ .x != 2), c(2)) 9 | }) 10 | 11 | test_that("keep() and discard() require predicate functions", { 12 | expect_snapshot(error = TRUE, { 13 | keep(1:3, ~ NA) 14 | discard(1:3, ~ NA) 15 | }) 16 | }) 17 | 18 | # keep_at / discard_at ---------------------------------------------------- 19 | 20 | test_that("can keep_at/discard_at with character vector", { 21 | x <- list(a = 1, b = 1, c = 1) 22 | expect_equal(keep_at(x, "b"), list(b = 1)) 23 | expect_equal(discard_at(x, "b"), list(a = 1, c = 1)) 24 | }) 25 | 26 | test_that("can keep_at/discard_at with function", { 27 | x <- list(a = 1, b = 1, c = 1) 28 | expect_equal(keep_at(x, ~ . == "b"), list(b = 1)) 29 | expect_equal(discard_at(x, ~ . == "b"), list(a = 1, c = 1)) 30 | }) 31 | 32 | test_that("discard_at works when nothing discarded", { 33 | x <- list(a = 1, b = 1, c = 1) 34 | expect_equal(discard_at(x, "d"), x) 35 | }) 36 | -------------------------------------------------------------------------------- /tests/testthat/test-list-flatten.R: -------------------------------------------------------------------------------- 1 | test_that("flattening removes single layer of nesting", { 2 | expect_equal(list_flatten(list(list(1), list(2))), list(1, 2)) 3 | expect_equal(list_flatten(list(list(1), list(list(2)))), list(1, list(2))) 4 | expect_equal(list_flatten(list(list(1), list(), list(2))), list(1, 2)) 5 | }) 6 | 7 | test_that("flattening a flat list is idempotent", { 8 | expect_equal(list_flatten(list(1, 2)), list(1, 2)) 9 | }) 10 | 11 | test_that("uses either inner or outer names if only one present", { 12 | expect_equal(list_flatten(list(x = list(1), list(y = 2))), list(x = 1, y = 2)) 13 | }) 14 | 15 | test_that("can control names if both present", { 16 | x <- list(a = list(x = 1)) 17 | expect_equal(list_flatten(x), list(a_x = 1)) 18 | expect_equal(list_flatten(x, name_spec = "{inner}"), list(x = 1)) 19 | expect_equal(list_flatten(x, name_spec = "{outer}"), list(a = 1)) 20 | }) 21 | 22 | test_that("requires a list", { 23 | expect_snapshot(list_flatten(1:2), error = TRUE) 24 | }) 25 | 26 | test_that("list_flatten() restores", { 27 | # This simulates a recursive list-of type 28 | my_num_list <- function(...) { 29 | new_my_num_list(list2(...)) 30 | } 31 | new_my_num_list <- function(xs) { 32 | stopifnot( 33 | every(xs, function(x) { 34 | is_null(x) || is.numeric(x) || inherits(x, "my_num_list") 35 | }) 36 | ) 37 | new_vctr(xs, class = "my_num_list") 38 | } 39 | 40 | local_methods( 41 | vec_restore.my_num_list = function(x, to, ...) { 42 | new_my_num_list(x) 43 | } 44 | ) 45 | 46 | xs <- my_num_list(1, 2, my_num_list(3:4)) 47 | expect_equal( 48 | list_flatten(xs), 49 | my_num_list(1, 2, 3:4) 50 | ) 51 | }) 52 | 53 | test_that("list_flatten() supports strict types", { 54 | local_methods( 55 | vec_cast.list.my_strict_list = function(x, to, ...) { 56 | abort("Can't coerce to list.") 57 | } 58 | ) 59 | 60 | x <- structure(list(1), class = c("my_strict_list", "list")) 61 | 62 | expect_equal( 63 | list_flatten(list(x)), 64 | list(1) 65 | ) 66 | }) 67 | 68 | test_that("list_flatten() works with vctrs::list_of()", { 69 | # Currently only with flat lists because list_of can't be recursive 70 | expect_equal( 71 | list_flatten(list_of(1, 2, 3)), 72 | list_of(1, 2, 3) 73 | ) 74 | }) 75 | -------------------------------------------------------------------------------- /tests/testthat/test-list-simplify.R: -------------------------------------------------------------------------------- 1 | test_that("simplifies using vctrs principles", { 2 | expect_identical(list_simplify(list(1, 2L)), c(1, 2)) 3 | expect_equal(list_simplify(list("x", factor("y"))), c("x", "y")) 4 | 5 | x <- list(data.frame(x = 1), data.frame(y = 2)) 6 | expect_equal(list_simplify(x), data.frame(x = c(1, NA), y = c(NA, 2))) 7 | }) 8 | 9 | test_that("only uses outer names", { 10 | out <- list_simplify(list(a = 1, c(b = 1), c = c(d = 1))) 11 | expect_named(out, c("a", "", "c")) 12 | }) 13 | 14 | test_that("ptype is enforced", { 15 | expect_equal(list_simplify(list(1, 2), ptype = double()), c(1, 2)) 16 | expect_snapshot(list_simplify(list(1, 2), ptype = character()), error = TRUE) 17 | # even if `strict = FALSE` 18 | expect_snapshot(list_simplify(list(1, 2), ptype = character(), strict = FALSE), error = TRUE) 19 | }) 20 | 21 | test_that("strict simplification will error", { 22 | expect_snapshot(error = TRUE, { 23 | list_simplify(list(mean)) 24 | list_simplify(list(1, "a")) 25 | list_simplify(list(1, 1:2)) 26 | list_simplify(list(data.frame(x = 1), data.frame(x = 1:2))) 27 | list_simplify(list(1, 2), ptype = character()) 28 | }) 29 | }) 30 | 31 | test_that("simplification requires length-1 vectors with common type", { 32 | expect_equal(list_simplify(list(mean), strict = FALSE), list(mean)) 33 | expect_equal(list_simplify(list(1, 2:3), strict = FALSE), list(1, 2:3)) 34 | expect_equal(list_simplify(list(1, "a"), strict = FALSE), list(1, "a")) 35 | }) 36 | 37 | # argument checking ------------------------------------------------------- 38 | 39 | test_that("list_simplify() validates inputs", { 40 | expect_snapshot(list_simplify(1:5), error = TRUE) 41 | expect_snapshot(list_simplify(list(), strict = NA), error = TRUE) 42 | }) 43 | 44 | test_that("list_simplify_internal() validates inputs", { 45 | expect_snapshot(list_simplify_internal(list(), simplify = 1), error = TRUE) 46 | expect_snapshot(list_simplify_internal(list(), simplify = FALSE, ptype = integer()), error = TRUE) 47 | }) 48 | -------------------------------------------------------------------------------- /tests/testthat/test-lmap.R: -------------------------------------------------------------------------------- 1 | test_that("lmap output is list if input is list", { 2 | x <- list(a = 1:4, b = letters[5:7], c = 8:9, d = letters[10]) 3 | maybe_rep <- function(x) { 4 | n <- rpois(1, 2) 5 | out <- rep_len(x, n) 6 | if (length(out) > 0) { 7 | names(out) <- paste0(names(x), seq_len(n)) 8 | } 9 | out 10 | } 11 | expect_bare(lmap_at(x, "a", maybe_rep), "list") 12 | }) 13 | 14 | test_that("lmap() returns a data frame if input is a data frame", { 15 | df <- data.frame(x = 1, y = 2) 16 | 17 | # as.data.frame() handles repeated names 18 | out <- lmap(df, function(x) as.data.frame(rep(x, 2))) 19 | expect_equal(out, data.frame(x = 1, x.1 = 1, y = 2, y.1 = 2)) 20 | 21 | # even if we return bare lists 22 | out <- lmap(df, function(x) as.list(rep(x, 2))) 23 | expect_equal(out, data.frame(x = 1, x.1 = 1, y = 2, y.1 = 2)) 24 | }) 25 | 26 | test_that("lmap() can increase and decrease elements", { 27 | out <- lmap(list(0, 1, 2), ~ as.list(rep(.x, .x))) 28 | expect_equal(out, list(1, 2, 2)) 29 | }) 30 | 31 | test_that("lmap_at() only affects selected elements", { 32 | out <- lmap_at(list(0, 1, 2), c(1, 3), ~ as.list(rep(.x, .x))) 33 | expect_equal(out, list(1, 2, 2)) 34 | 35 | out <- lmap_at(list(0, 1, 2), c(2, 3), ~ as.list(rep(.x, .x))) 36 | expect_equal(out, list(0, 1, 2, 2)) 37 | }) 38 | 39 | test_that("lmap_at can use tidyselect", { 40 | skip_if_not_installed("tidyselect") 41 | local_options(lifecycle_verbosity = "quiet") 42 | 43 | x <- lmap_at(mtcars, vars(tidyselect::contains("vs")), ~ .x + 10) 44 | expect_equal(x$vs[1], 10) 45 | }) 46 | 47 | test_that("`.else` preserves false elements", { 48 | x <- list("a", 99) 49 | out <- lmap_if(x, is.character, ~ list(1, 2), .else = ~ list(3, 4)) 50 | expect_equal(out, list(1, 2, 3, 4)) 51 | }) 52 | 53 | test_that("validates inputs", { 54 | expect_snapshot(error = TRUE, { 55 | lmap(list(1), ~ 1) 56 | lmap(list(1), environment()) 57 | lmap(list(1), ~ 1, .else = environment()) 58 | }) 59 | }) 60 | -------------------------------------------------------------------------------- /tests/testthat/test-map-if-at.R: -------------------------------------------------------------------------------- 1 | test_that("map_if() and map_at() always return a list", { 2 | skip_if_not_installed("tibble") 3 | df <- tibble::tibble(x = 1, y = "a") 4 | expect_identical(map_if(df, is.character, ~"out"), list(x = 1, y = "out")) 5 | expect_identical(map_at(df, 1, ~"out"), list(x = "out", y = "a")) 6 | }) 7 | 8 | test_that("map_at() works with tidyselect", { 9 | skip_if_not_installed("tidyselect") 10 | local_options(lifecycle_verbosity = "quiet") 11 | 12 | x <- list(a = "b", b = "c", aa = "bb") 13 | one <- map_at(x, vars(a), toupper) 14 | expect_identical(one$a, "B") 15 | expect_identical(one$aa, "bb") 16 | two <- map_at(x, vars(tidyselect::contains("a")), toupper) 17 | expect_identical(two$a, "B") 18 | expect_identical(two$aa, "BB") 19 | }) 20 | 21 | test_that("negative .at omits locations", { 22 | x <- c(1, 2, 3) 23 | out <- map_at(x, -1, ~ .x * 2) 24 | expect_equal(out, list(1, 4, 6)) 25 | }) 26 | 27 | test_that("map_if requires predicate functions", { 28 | expect_snapshot(map_if(1:3, ~ NA, ~ "foo"), error = TRUE) 29 | }) 30 | 31 | test_that("`.else` maps false elements", { 32 | expect_identical(map_if(-1:1, ~ .x > 0, paste, .else = ~ "bar", "suffix"), list("bar", "bar", "1 suffix")) 33 | }) 34 | -------------------------------------------------------------------------------- /tests/testthat/test-map-mapper.R: -------------------------------------------------------------------------------- 1 | # formulas ---------------------------------------------------------------- 2 | 3 | test_that("can refer to first argument in three ways", { 4 | expect_equal(map_dbl(1, ~ . + 1), 2) 5 | expect_equal(map_dbl(1, ~ .x + 1), 2) 6 | expect_equal(map_dbl(1, ~ ..1 + 1), 2) 7 | }) 8 | 9 | test_that("can refer to second arg in two ways", { 10 | expect_equal(map2_dbl(1, 2, ~ .x + .y + 1), 4) 11 | expect_equal(map2_dbl(1, 2, ~ ..1 + ..2 + 1), 4) 12 | }) 13 | 14 | # vectors -------------------------------------------------------------- 15 | 16 | # test_that(".null generates warning", { 17 | # expect_warning(map(1, 2, .null = NA), "`.null` is deprecated") 18 | # }) 19 | 20 | test_that(".default replaces absent values", { 21 | x <- list( 22 | list(a = 1, b = 2, c = 3), 23 | list(a = 1, c = 2), 24 | NULL 25 | ) 26 | 27 | expect_equal(map_dbl(x, 3, .default = NA), c(3, NA, NA)) 28 | expect_equal(map_dbl(x, "b", .default = NA), c(2, NA, NA)) 29 | }) 30 | 31 | test_that(".default only replaces NULL elements", { 32 | x <- list( 33 | list(a = 1), 34 | list(a = numeric()), 35 | list(a = NULL), 36 | list() 37 | ) 38 | expect_equal(map(x, "a", .default = NA), list(1, numeric(), NA, NA)) 39 | }) 40 | 41 | test_that("Additional arguments are ignored", { 42 | expect_equal(as_mapper(function() NULL, foo = "bar", foobar), function() NULL) 43 | }) 44 | 45 | test_that("can supply length > 1 vectors", { 46 | expect_identical(as_mapper(1:2)(list(list("a", "b"))), "b") 47 | expect_identical(as_mapper(c("a", "b"))(list(a = list("a", b = "b"))), "b") 48 | }) 49 | 50 | 51 | # primitive functions -------------------------------------------------- 52 | 53 | test_that("primitive functions are wrapped", { 54 | expect_identical(as_mapper(`-`)(.y = 10, .x = 5), -5) 55 | expect_identical(as_mapper(`c`)(1, 3, 5), c(1, 3, 5)) 56 | }) 57 | 58 | test_that("syntactic primitives are wrapped", { 59 | expect_identical(as_mapper(`[[`)(mtcars, "cyl"), mtcars$cyl) 60 | expect_identical(as_mapper(`$`)(mtcars, cyl), mtcars$cyl) 61 | }) 62 | 63 | 64 | # lists ------------------------------------------------------------------ 65 | 66 | test_that("lists are wrapped", { 67 | mapper_list <- as_mapper(list("mpg", 5))(mtcars) 68 | base_list <- mtcars[["mpg"]][[5]] 69 | expect_identical(mapper_list, base_list) 70 | }) 71 | -------------------------------------------------------------------------------- /tests/testthat/test-map-raw.R: -------------------------------------------------------------------------------- 1 | test_that("_raw funtions are deprecated", { 2 | expect_snapshot({ 3 | . <- map_raw(list(), ~ .x) 4 | . <- map2_raw(list(), list(), ~ .x) 5 | . <- imap_raw(list(), ~ .x) 6 | . <- pmap_raw(list(), ~ .x) 7 | . <- flatten_raw(list()) 8 | }) 9 | }) 10 | 11 | test_that("_raw functions still work", { 12 | local_options(lifecycle_verbosity = "quiet") 13 | expect_equal(map_raw("a", charToRaw), charToRaw("a")) 14 | expect_identical(map_raw(set_names(list()), identity), named(raw())) 15 | 16 | expect_identical(map2_raw(set_names(list()), list(), identity), named(raw())) 17 | expect_equal(imap_raw(as.raw(12), rawShift), rawShift(as.raw(12), 1) ) 18 | 19 | expect_bare(pmap_raw(list(1:3), as.raw), "raw") 20 | expect_identical(pmap_raw(list(named(list())), identity), named(raw())) 21 | 22 | expect_equal(flatten_raw(list(as.raw(1))), as.raw(1)) 23 | }) 24 | -------------------------------------------------------------------------------- /tests/testthat/test-modify-tree.R: -------------------------------------------------------------------------------- 1 | test_that("can modify leaves", { 2 | expect_equal( 3 | modify_tree(c(1, 1, 1), leaf = ~ .x + 9), 4 | c(10, 10, 10) 5 | ) 6 | 7 | expect_equal( 8 | modify_tree(list(1, list(1, list(1))), leaf = ~ .x + 9), 9 | list(10, list(10, list(10))) 10 | ) 11 | }) 12 | 13 | test_that("can modify nodes", { 14 | expect_equal( 15 | modify_tree(list(1, list(2, list(3))), post = list_flatten), 16 | list(1, 2, 3) 17 | ) 18 | }) 19 | 20 | test_that("default doesn't recurse into data frames, but can customise", { 21 | local_options(stringsAsFactors = FALSE) 22 | 23 | x <- list(data.frame(x = 1), data.frame(y = 2)) 24 | expect_equal( 25 | modify_tree(x, leaf = class), 26 | list("data.frame", "data.frame") 27 | ) 28 | expect_equal( 29 | modify_tree(x, leaf = class, is_node = is.list), 30 | list(data.frame(x = "numeric"), data.frame(y = "numeric")) 31 | ) 32 | }) 33 | 34 | test_that("leaf() is applied to non-node input", { 35 | expect_equal(modify_tree(1:3, leaf = identity), 1:3) 36 | }) 37 | 38 | test_that("validates inputs", { 39 | expect_snapshot(error = TRUE, { 40 | modify_tree(list(), is_node = ~ 1) 41 | modify_tree(list(), is_node = 1) 42 | }) 43 | }) 44 | -------------------------------------------------------------------------------- /tests/testthat/test-pluck-depth.R: -------------------------------------------------------------------------------- 1 | test_that("depth of non-vectors is 0", { 2 | expect_equal(pluck_depth(NULL), 0L) 3 | expect_equal(pluck_depth(mean), 0L) 4 | }) 5 | 6 | test_that("depth of atomic vector is 1", { 7 | expect_equal(pluck_depth(1:10), 1) 8 | expect_equal(pluck_depth(letters), 1) 9 | expect_equal(pluck_depth(c(TRUE, FALSE)), 1) 10 | }) 11 | 12 | test_that("depth of nested is depth of deepest element + 1", { 13 | x <- list( 14 | NULL, 15 | list(), 16 | list(list()) 17 | ) 18 | 19 | depths <- map_int(x, pluck_depth) 20 | expect_equal(depths, c(0, 1, 2)) 21 | expect_equal(pluck_depth(x), 3) 22 | }) 23 | 24 | test_that("vec_depth() is deprecated", { 25 | expect_snapshot({ 26 | . <- vec_depth(list()) 27 | }) 28 | }) 29 | -------------------------------------------------------------------------------- /tests/testthat/test-rate.R: -------------------------------------------------------------------------------- 1 | test_that("new_rate() creates rate objects", { 2 | rate <- new_rate("foo", jitter = FALSE, max_times = 10) 3 | expect_identical(rate$state$i, 0L) 4 | expect_identical(rate$max_times, 10) 5 | expect_false(rate$jitter) 6 | }) 7 | 8 | test_that("can bump and reset count", { 9 | rate <- new_rate("foo") 10 | 11 | rate_bump_count(rate) 12 | rate_bump_count(rate) 13 | expect_identical(rate_count(rate), 2L) 14 | 15 | rate_reset(rate) 16 | expect_identical(rate_count(rate), 0L) 17 | }) 18 | 19 | test_that("rates have print methods", { 20 | expect_snapshot({ 21 | # Also checks infinite `max_times` prints properly 22 | rate_delay(20, max_times = Inf) 23 | 24 | rate_backoff() 25 | }) 26 | }) 27 | 28 | test_that("rate_delay() delays", { 29 | rate <- rate_delay( 30 | pause = 0.02, 31 | max_times = 3 32 | ) 33 | 34 | rate_sleep(rate, quiet = FALSE) 35 | 36 | rate_reset(rate) 37 | 38 | msg <- catch_cnd(rate_sleep(rate)) 39 | expect_true(inherits_all(msg, c("purrr_condition_rate_init", "condition"))) 40 | 41 | msg <- catch_cnd(rate_sleep(rate, quiet = FALSE)) 42 | expect_true(inherits_all(msg, c("purrr_message_rate_retry", "message"))) 43 | expect_identical(msg$length, 0.02) 44 | 45 | msg <- catch_cnd(rate_sleep(rate, quiet = FALSE)) 46 | expect_identical(msg$length, 0.02) 47 | 48 | expect_snapshot(rate_sleep(rate), error = TRUE) 49 | expect_snapshot(rate_sleep(rate), error = TRUE) 50 | }) 51 | 52 | test_that("rate_backoff() backs off", { 53 | rate <- rate_backoff( 54 | pause_base = 0.02, 55 | pause_min = 0, 56 | jitter = FALSE 57 | ) 58 | 59 | msg <- catch_cnd(rate_sleep(rate)) 60 | expect_true(inherits_all(msg, c("purrr_condition_rate_init", "condition"))) 61 | 62 | msg <- catch_cnd(rate_sleep(rate, quiet = FALSE)) 63 | expect_true(inherits_all(msg, c("purrr_message_rate_retry", "message"))) 64 | expect_identical(msg$length, 0.04) 65 | 66 | msg <- catch_cnd(rate_sleep(rate, quiet = FALSE)) 67 | expect_identical(msg$length, 0.08) 68 | 69 | expect_snapshot(rate_sleep(rate), error = TRUE) 70 | expect_snapshot(rate_sleep(rate), error = TRUE) 71 | }) 72 | 73 | test_that("rate_sleep() checks that rate is still valid", { 74 | rate <- rate_delay(1, max_times = 0) 75 | expect_snapshot(rate_sleep(rate), error = TRUE) 76 | expect_snapshot(rate_sleep(rate), error = TRUE) 77 | }) 78 | 79 | -------------------------------------------------------------------------------- /tests/testthat/test-superseded-map-df.R: -------------------------------------------------------------------------------- 1 | test_that("row and column binding work", { 2 | skip_if_not_installed("dplyr") 3 | local_name_repair_quiet() 4 | 5 | mtcar_mod <- mtcars %>% 6 | split(.$cyl) %>% 7 | map(~ lm(mpg ~ wt, data = .x)) 8 | 9 | f_coef <- function(x) as.data.frame(t(as.matrix(coef(x)))) 10 | expect_length(mtcar_mod %>% map_dfr(f_coef), 2) 11 | expect_length(mtcar_mod %>% map_dfc(f_coef), 6) 12 | }) 13 | 14 | test_that("data frame imap works", { 15 | skip_if_not_installed("dplyr") 16 | x <- set_names(1:3) 17 | expect_identical(imap_dfc(x, paste), imap_dfr(x, paste)) 18 | }) 19 | 20 | test_that("outputs are suffixes have correct type for data frames", { 21 | skip_if_not_installed("dplyr") 22 | local_name_repair_quiet() 23 | 24 | local_options(rlang_message_verbosity = "quiet") 25 | x <- 1:3 26 | expect_s3_class(pmap_dfr(list(x), as.data.frame), "data.frame") 27 | expect_s3_class(pmap_dfc(list(x), as.data.frame), "data.frame") 28 | }) 29 | -------------------------------------------------------------------------------- /tests/testthat/test-superseded-simplify.R: -------------------------------------------------------------------------------- 1 | test_that("can_simplify() understands vector molds", { 2 | x <- as.list(1:3) 3 | x2 <- c(x, list(1:3)) 4 | expect_true(can_simplify(x, integer(1))) 5 | expect_false(can_simplify(x, character(1))) 6 | expect_false(can_simplify(x2, integer(1))) 7 | 8 | x3 <- list(1:2, 3:4, 5:6) 9 | expect_true(can_simplify(x3, integer(2))) 10 | expect_false(can_simplify(x, integer(2))) 11 | }) 12 | 13 | test_that("can_simplify() understands types as strings", { 14 | x <- as.list(1:3) 15 | expect_true(can_simplify(x, "integer")) 16 | expect_false(can_simplify(x, "character")) 17 | }) 18 | 19 | test_that("integer is coercible to double", { 20 | x <- list(1L, 2L) 21 | expect_true(can_simplify(x, "numeric")) 22 | expect_true(can_simplify(x, numeric(1))) 23 | expect_true(can_simplify(x, "double")) 24 | expect_true(can_simplify(x, double(1))) 25 | }) 26 | 27 | test_that("numeric is an alias for double", { 28 | expect_true(can_simplify(list(1, 2), "numeric")) 29 | }) 30 | 31 | test_that("double is not coercible to integer", { 32 | expect_false(can_simplify(list(1, 2), "integer")) 33 | }) 34 | -------------------------------------------------------------------------------- /tools/examples.R: -------------------------------------------------------------------------------- 1 | if (getRversion() < "4.1") { 2 | dir.create("man/macros", showWarnings = FALSE, recursive = TRUE) 3 | cat( 4 | paste( 5 | "\\renewcommand{\\examples}{\\section{Examples}{", 6 | "These examples are designed to work in R >= 4.1 so that we can take", 7 | "advantage of modern syntax like the base pipe (\\verb{|>}) and the ", 8 | "function shorthand (\\verb{\\(x) x + 1}). They might not work on the ", 9 | "version of R that you're using.", 10 | "\\preformatted{#1}}}", 11 | collapse = "" 12 | ), 13 | file = "man/macros/examples.Rd" 14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /vignettes/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | *.R 3 | -------------------------------------------------------------------------------- /vignettes/other-langs.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Functional programming in other languages" 3 | output: rmarkdown::html_vignette 4 | vignette: > 5 | %\VignetteIndexEntry{Functional programming in other languages} 6 | %\VignetteEngine{knitr::rmarkdown} 7 | %\VignetteEncoding{UTF-8} 8 | --- 9 | 10 | purrr draws inspiration from many related tools: 11 | 12 | * List operations defined in the Haskell [prelude][haskell] 13 | 14 | * Scala's [list methods][scala]. 15 | 16 | * Functional programming libraries for javascript: 17 | [underscore.js](http://underscorejs.org), 18 | [lodash](https://lodash.com) and 19 | [lazy.js](http://danieltao.com/lazy.js/). 20 | 21 | * [rlist](https://renkun-ken.github.io/rlist/), another R package to support working 22 | with lists. Similar goals but somewhat different philosophy. 23 | 24 | However, the goal of purrr is not to try and simulate a purer functional programming language in R; we don't want to implement a second-class version of Haskell in R. The goal is to give you similar expressiveness to an FP language, while allowing you to write code that looks and works like R: 25 | 26 | * Instead of point free (tacit) style, we use the pipe, `|>`, to write code 27 | that can be read from left to right. 28 | 29 | * Instead of currying, we use `...` to pass in extra arguments. 30 | 31 | * Before R 4.1, anonymous functions were verbose, so we provide two convenient shorthands. 32 | For unary functions, `~ .x + 1` is equivalent to `function(.x) .x + 1`. 33 | 34 | * R is weakly typed, so we need `map` variants that describe the output type 35 | (like `map_int()`, `map_dbl()`, etc) because we don't know the return type of `.f`. 36 | 37 | * R has named arguments, so instead of providing different functions for 38 | minor variations (e.g. `detect()` and `detectLast()`) we use a named 39 | argument, `.right`. Type-stable functions are easy to reason about so 40 | additional arguments will never change the type of the output. 41 | 42 | [scala]:https://www.scala-lang.org/api/current/index.html 43 | [haskell]:http://hackage.haskell.org/package/base-4.7.0.1/docs/Prelude.html#g:11 44 | --------------------------------------------------------------------------------