From c9dee264b33ac4954d0dec6a99f1d4d862766116 Mon Sep 17 00:00:00 2001 From: Thomas Lin Pedersen Date: Fri, 17 Mar 2023 09:57:07 +0100 Subject: [PATCH] 2023 upkeeeeep (#91) --- .github/CODE_OF_CONDUCT.md | 126 +++++ .github/workflows/R-CMD-check.yaml | 44 +- .github/workflows/pkgdown.yaml | 37 +- .github/workflows/pr-commands.yaml | 36 +- .github/workflows/test-coverage.yaml | 32 +- DESCRIPTION | 43 +- LICENSE | 2 +- LICENSE.md | 2 +- NAMESPACE | 3 + R/{add-grob.r => add-grob.R} | 8 +- R/{add-rows-cols.r => add-rows-cols.R} | 8 +- R/{add-space.r => add-space.R} | 12 +- R/{align.r => align.R} | 14 +- R/{grid.r => grid.R} | 4 +- R/{gtable-layouts.r => gtable-layouts.R} | 20 +- R/gtable-package.R | 12 +- R/{gtable.r => gtable.R} | 22 +- R/import-standalone-obj-type.R | 348 +++++++++++++ R/import-standalone-types-check.R | 493 ++++++++++++++++++ R/{new-data-frame.r => new-data-frame.R} | 8 +- R/{rbind-cbind.r => rbind-cbind.R} | 8 +- R/{trim.r => trim.R} | 2 +- R/{utils.r => utils.R} | 56 +- R/{z.r => z.R} | 2 +- R/zzz.R | 5 + README.Rmd | 13 +- README.md | 14 +- _pkgdown.yml | 11 + cran-comments.md | 6 - man/bind.Rd | 2 +- man/figures/lifecycle-archived.svg | 21 + man/figures/lifecycle-defunct.svg | 21 + man/figures/lifecycle-deprecated.svg | 21 + man/figures/lifecycle-experimental.svg | 21 + man/figures/lifecycle-maturing.svg | 21 + man/figures/lifecycle-questioning.svg | 21 + man/figures/lifecycle-soft-deprecated.svg | 21 + man/figures/lifecycle-stable.svg | 29 ++ man/figures/lifecycle-superseded.svg | 21 + man/figures/logo.png | Bin 18816 -> 49245 bytes man/gtable-package.Rd | 14 +- man/gtable.Rd | 2 +- man/gtable_add_cols.Rd | 2 +- man/gtable_add_grob.Rd | 2 +- man/gtable_add_padding.Rd | 2 +- man/gtable_add_rows.Rd | 2 +- man/gtable_add_space.Rd | 2 +- man/gtable_col.Rd | 2 +- man/gtable_filter.Rd | 2 +- man/gtable_height.Rd | 2 +- man/gtable_matrix.Rd | 2 +- man/gtable_row.Rd | 2 +- man/gtable_show_layout.Rd | 2 +- man/gtable_spacer.Rd | 2 +- man/gtable_trim.Rd | 2 +- man/gtable_width.Rd | 2 +- man/is.gtable.Rd | 2 +- man/print.gtable.Rd | 2 +- tests/testthat.R | 8 + tests/testthat/{test-bind.r => test-bind.R} | 10 +- tests/testthat/test-filter.R | 2 - .../testthat/{test-layout.r => test-layout.R} | 54 +- tests/testthat/test-new-data-frame.R | 4 +- .../{test-subsetting.r => test-subsetting.R} | 2 - tests/testthat/test-trim.R | 2 - .../{test-z-order.r => test-z-order.R} | 2 - 66 files changed, 1500 insertions(+), 222 deletions(-) create mode 100644 .github/CODE_OF_CONDUCT.md rename R/{add-grob.r => add-grob.R} (93%) rename R/{add-rows-cols.r => add-rows-cols.R} (92%) rename R/{add-space.r => add-space.R} (80%) rename R/{align.r => align.R} (90%) rename R/{grid.r => grid.R} (94%) rename R/{gtable-layouts.r => gtable-layouts.R} (87%) rename R/{gtable.r => gtable.R} (93%) create mode 100644 R/import-standalone-obj-type.R create mode 100644 R/import-standalone-types-check.R rename R/{new-data-frame.r => new-data-frame.R} (61%) rename R/{rbind-cbind.r => rbind-cbind.R} (94%) rename R/{trim.r => trim.R} (95%) rename R/{utils.r => utils.R} (58%) rename R/{z.r => z.R} (94%) create mode 100644 R/zzz.R create mode 100644 man/figures/lifecycle-archived.svg create mode 100644 man/figures/lifecycle-defunct.svg create mode 100644 man/figures/lifecycle-deprecated.svg create mode 100644 man/figures/lifecycle-experimental.svg create mode 100644 man/figures/lifecycle-maturing.svg create mode 100644 man/figures/lifecycle-questioning.svg create mode 100644 man/figures/lifecycle-soft-deprecated.svg create mode 100644 man/figures/lifecycle-stable.svg create mode 100644 man/figures/lifecycle-superseded.svg rename tests/testthat/{test-bind.r => test-bind.R} (81%) rename tests/testthat/{test-layout.r => test-layout.R} (76%) rename tests/testthat/{test-subsetting.r => test-subsetting.R} (99%) rename tests/testthat/{test-z-order.r => test-z-order.R} (99%) diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..3ac34c8 --- /dev/null +++ b/.github/CODE_OF_CONDUCT.md @@ -0,0 +1,126 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall + community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of + any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, + without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at codeofconduct@posit.co. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][https://github.com/mozilla/inclusion]. + +For answers to common questions about this code of conduct, see the FAQ at +. Translations are available at . + +[homepage]: https://www.contributor-covenant.org diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml index 6ab6888..ee65ccb 100644 --- a/.github/workflows/R-CMD-check.yaml +++ b/.github/workflows/R-CMD-check.yaml @@ -1,4 +1,4 @@ -# Workflow derived from https://github.com/r-lib/actions/tree/master/examples +# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help # # NOTE: This workflow is overkill for most R packages and @@ -22,49 +22,41 @@ jobs: fail-fast: false matrix: config: - - {os: macOS-latest, r: 'release'} + - {os: macos-latest, r: 'release'} - {os: windows-latest, r: 'release'} # Use 3.6 to trigger usage of RTools35 - {os: windows-latest, r: '3.6'} + # use 4.1 to check with rtools40's older compiler + - {os: windows-latest, r: '4.1'} - # Use older ubuntu to maximise backward compatibility - - {os: ubuntu-18.04, r: 'devel', http-user-agent: 'release'} - - {os: ubuntu-18.04, r: 'release'} - - {os: ubuntu-18.04, r: 'oldrel-1'} - - {os: ubuntu-18.04, r: 'oldrel-2'} - - {os: ubuntu-18.04, r: 'oldrel-3'} - - {os: ubuntu-18.04, r: 'oldrel-4'} + - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} + - {os: ubuntu-latest, r: 'release'} + - {os: ubuntu-latest, r: 'oldrel-1'} + - {os: ubuntu-latest, r: 'oldrel-2'} + - {os: ubuntu-latest, r: 'oldrel-3'} + - {os: ubuntu-latest, r: 'oldrel-4'} env: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} R_KEEP_PKG_SOURCE: yes steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - - uses: r-lib/actions/setup-pandoc@v1 + - uses: r-lib/actions/setup-pandoc@v2 - - uses: r-lib/actions/setup-r@v1 + - uses: r-lib/actions/setup-r@v2 with: r-version: ${{ matrix.config.r }} http-user-agent: ${{ matrix.config.http-user-agent }} use-public-rspm: true - - uses: r-lib/actions/setup-r-dependencies@v1 + - uses: r-lib/actions/setup-r-dependencies@v2 with: - extra-packages: rcmdcheck + extra-packages: any::rcmdcheck + needs: check - - uses: r-lib/actions/check-r-package@v1 - - - name: Show testthat output - if: always() - run: find check -name 'testthat.Rout*' -exec cat '{}' \; || true - shell: bash - - - name: Upload check results - if: failure() - uses: actions/upload-artifact@main + - uses: r-lib/actions/check-r-package@v2 with: - name: ${{ runner.os }}-r${{ matrix.config.r }}-results - path: check + upload-snapshots: true diff --git a/.github/workflows/pkgdown.yaml b/.github/workflows/pkgdown.yaml index 59ae308..087f0b0 100644 --- a/.github/workflows/pkgdown.yaml +++ b/.github/workflows/pkgdown.yaml @@ -1,33 +1,46 @@ -# Workflow derived from https://github.com/r-lib/actions/tree/master/examples +# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help on: push: branches: [main, master] - tags: ['*'] + pull_request: + branches: [main, master] + release: + types: [published] + workflow_dispatch: name: pkgdown jobs: pkgdown: runs-on: ubuntu-latest + # Only restrict concurrency for non-PR jobs + concurrency: + group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }} env: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - - uses: r-lib/actions/setup-pandoc@v1 + - uses: r-lib/actions/setup-pandoc@v2 - - uses: r-lib/actions/setup-r@v1 + - uses: r-lib/actions/setup-r@v2 with: use-public-rspm: true - - uses: r-lib/actions/setup-r-dependencies@v1 + - uses: r-lib/actions/setup-r-dependencies@v2 with: - extra-packages: pkgdown + extra-packages: any::pkgdown, local::. needs: website - - name: Deploy package - run: | - git config --local user.name "$GITHUB_ACTOR" - git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com" - Rscript -e 'pkgdown::deploy_to_branch(new_process = FALSE)' + - name: Build site + run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE) + shell: Rscript {0} + + - name: Deploy to GitHub pages 🚀 + if: github.event_name != 'pull_request' + uses: JamesIves/github-pages-deploy-action@v4.4.1 + with: + clean: false + branch: gh-pages + folder: docs diff --git a/.github/workflows/pr-commands.yaml b/.github/workflows/pr-commands.yaml index 1cdafbf..71f335b 100644 --- a/.github/workflows/pr-commands.yaml +++ b/.github/workflows/pr-commands.yaml @@ -1,4 +1,4 @@ -# Workflow derived from https://github.com/r-lib/actions/tree/master/examples +# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help on: issue_comment: @@ -8,28 +8,30 @@ name: Commands jobs: document: - if: startsWith(github.event.comment.body, '/document') + if: ${{ github.event.issue.pull_request && (github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER') && startsWith(github.event.comment.body, '/document') }} name: document runs-on: ubuntu-latest env: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - - uses: r-lib/actions/pr-fetch@v1 + - uses: r-lib/actions/pr-fetch@v2 with: repo-token: ${{ secrets.GITHUB_TOKEN }} - - uses: r-lib/actions/setup-r@v1 + - uses: r-lib/actions/setup-r@v2 with: use-public-rspm: true - - uses: r-lib/actions/setup-r-dependencies@v1 + - uses: r-lib/actions/setup-r-dependencies@v2 with: - extra-packages: roxygen2 + extra-packages: any::roxygen2 + needs: pr-document - name: Document - run: Rscript -e 'roxygen2::roxygenise()' + run: roxygen2::roxygenise() + shell: Rscript {0} - name: commit run: | @@ -38,30 +40,32 @@ jobs: git add man/\* NAMESPACE git commit -m 'Document' - - uses: r-lib/actions/pr-push@v1 + - uses: r-lib/actions/pr-push@v2 with: repo-token: ${{ secrets.GITHUB_TOKEN }} style: - if: startsWith(github.event.comment.body, '/style') + if: ${{ github.event.issue.pull_request && (github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER') && startsWith(github.event.comment.body, '/style') }} name: style runs-on: ubuntu-latest env: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - - uses: r-lib/actions/pr-fetch@v1 + - uses: r-lib/actions/pr-fetch@v2 with: repo-token: ${{ secrets.GITHUB_TOKEN }} - - uses: r-lib/actions/setup-r@v1 + - uses: r-lib/actions/setup-r@v2 - name: Install dependencies - run: Rscript -e 'install.packages("styler")' + run: install.packages("styler") + shell: Rscript {0} - name: Style - run: Rscript -e 'styler::style_pkg()' + run: styler::style_pkg() + shell: Rscript {0} - name: commit run: | @@ -70,6 +74,6 @@ jobs: git add \*.R git commit -m 'Style' - - uses: r-lib/actions/pr-push@v1 + - uses: r-lib/actions/pr-push@v2 with: repo-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/test-coverage.yaml b/.github/workflows/test-coverage.yaml index 3c0da1c..2c5bb50 100644 --- a/.github/workflows/test-coverage.yaml +++ b/.github/workflows/test-coverage.yaml @@ -1,4 +1,4 @@ -# Workflow derived from https://github.com/r-lib/actions/tree/master/examples +# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help on: push: @@ -15,16 +15,36 @@ jobs: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - - uses: r-lib/actions/setup-r@v1 + - uses: r-lib/actions/setup-r@v2 with: use-public-rspm: true - - uses: r-lib/actions/setup-r-dependencies@v1 + - uses: r-lib/actions/setup-r-dependencies@v2 with: - extra-packages: covr + extra-packages: any::covr + needs: coverage - name: Test coverage - run: covr::codecov() + run: | + covr::codecov( + quiet = FALSE, + clean = FALSE, + install_path = file.path(Sys.getenv("RUNNER_TEMP"), "package") + ) shell: Rscript {0} + + - name: Show testthat output + if: always() + run: | + ## -------------------------------------------------------------------- + find ${{ runner.temp }}/package -name 'testthat.Rout*' -exec cat '{}' \; || true + shell: bash + + - name: Upload test results + if: failure() + uses: actions/upload-artifact@v3 + with: + name: coverage-test-failures + path: ${{ runner.temp }}/package diff --git a/DESCRIPTION b/DESCRIPTION index 431ed50..0956750 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -5,12 +5,12 @@ Authors@R: c(person(given = "Hadley", family = "Wickham", role = c("aut", "cre"), - email = "hadley@rstudio.com"), + email = "hadley@posit.co"), person(given = "Thomas Lin", family = "Pedersen", role = "aut", - email = "thomas.pedersen@rstudio.com"), - person(given = "RStudio", + email = "thomas.pedersen@posit.co"), + person(given = "Posit Software, PBC", role = "cph")) Description: Tools to make it easier to work with "tables" of 'grobs'. The 'gtable' package defines a 'gtable' grob class that specifies a @@ -19,35 +19,26 @@ Description: Tools to make it easier to work with "tables" of complex compositions can be built up sequentially. License: MIT + file LICENSE Depends: - R (>= 3.0) + R (>= 3.5) Imports: - grid + cli, + glue, + grid, + lifecycle, + rlang Suggests: covr, - testthat, + ggplot2, knitr, + profvis, rmarkdown, - ggplot2, - profvis + testthat (>= 3.0.0) +VignetteBuilder: + knitr Encoding: UTF-8 Roxygen: list(markdown = TRUE) -RoxygenNote: 7.2.1 -Collate: - 'new-data-frame.r' - 'add-grob.r' - 'add-rows-cols.r' - 'add-space.r' - 'grid.r' - 'gtable-layouts.r' - 'gtable-package.R' - 'gtable.r' - 'rbind-cbind.r' - 'utils.r' - 'trim.r' - 'filter.r' - 'align.r' - 'padding.r' - 'z.r' +RoxygenNote: 7.2.3 URL: https://gtable.r-lib.org, https://github.com/r-lib/gtable BugReports: https://github.com/r-lib/gtable/issues -VignetteBuilder: knitr +Config/testthat/edition: 3 +Config/Needs/website: tidyverse/tidytemplate diff --git a/LICENSE b/LICENSE index 64faed7..1ef022b 100644 --- a/LICENSE +++ b/LICENSE @@ -1,2 +1,2 @@ -YEAR: 2020 +YEAR: 2023 COPYRIGHT HOLDER: gtable authors diff --git a/LICENSE.md b/LICENSE.md index cdd9576..d4de78b 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ # MIT License -Copyright (c) 2020 gtable authors +Copyright (c) 2023 gtable authors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/NAMESPACE b/NAMESPACE index 5af29f1..fa44789 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -34,3 +34,6 @@ export(gtable_trim) export(gtable_width) export(is.gtable) import(grid) +import(rlang) +importFrom(glue,glue) +importFrom(lifecycle,deprecated) diff --git a/R/add-grob.r b/R/add-grob.R similarity index 93% rename from R/add-grob.r rename to R/add-grob.R index 8589f8a..7c9134d 100644 --- a/R/add-grob.r +++ b/R/add-grob.R @@ -43,9 +43,11 @@ #' plot(gt) #' gtable_add_grob <- function(x, grobs, t, l, b = t, r = l, z = Inf, clip = "on", name = x$name) { - if (!is.gtable(x)) stop("x must be a gtable", call. = FALSE) + check_gtable(x) if (is.grob(grobs)) grobs <- list(grobs) - if (!is.list(grobs)) stop("grobs must either be a single grob or a list of grobs", call. = FALSE) + if (!is.list(grobs)) { + stop_input_type(grobs, "a single grob or a list of grobs") + } n_grobs <- length(grobs) if (is.logical(clip)) { @@ -59,7 +61,7 @@ gtable_add_grob <- function(x, grobs, t, l, b = t, r = l, z = Inf, clip = "on", list(t, r, b, l, z, clip, name), len_same_or_1, logical(1), n_grobs ))) { - stop("Not all inputs have either length 1 or same length same as 'grobs'") + cli::cli_abort("Not all inputs have either length 1 or same length same as {.arg grobs}") } # If z is just one value, replicate to same length as grobs diff --git a/R/add-rows-cols.r b/R/add-rows-cols.R similarity index 92% rename from R/add-rows-cols.r rename to R/add-rows-cols.R index e7ef156..c14c026 100644 --- a/R/add-rows-cols.r +++ b/R/add-rows-cols.R @@ -38,8 +38,8 @@ #' plot(tab3) #' gtable_add_rows <- function(x, heights, pos = -1) { - if (!is.gtable(x)) stop("x must be a gtable", call. = FALSE) - if (length(pos) != 1) stop("pos must be a scalar unit", call. = FALSE) + check_gtable(x) + check_number_whole(pos) n <- length(heights) pos <- neg_to_pos(pos, length(x$heights)) @@ -94,8 +94,8 @@ gtable_add_rows <- function(x, heights, pos = -1) { #' plot(tab3) #' gtable_add_cols <- function(x, widths, pos = -1) { - if (!is.gtable(x)) stop("x must be a gtable", call. = FALSE) - if (length(pos) != 1) stop("pos must be a scalar unit", call. = FALSE) + check_gtable(x) + check_number_whole(pos) n <- length(widths) pos <- neg_to_pos(pos, length(x$widths)) diff --git a/R/add-space.r b/R/add-space.R similarity index 80% rename from R/add-space.r rename to R/add-space.R index 9f740ee..097131b 100644 --- a/R/add-space.r +++ b/R/add-space.R @@ -35,11 +35,13 @@ NULL #' @export #' @rdname gtable_add_space gtable_add_col_space <- function(x, width) { - if (!is.gtable(x)) stop("x must be a gtable", call. = FALSE) + check_gtable(x) n <- length(x$widths) - 1 if (n == 0) return(x) - if (!(length(width) == 1 || length(width) == n)) stop("width must be of length 1 or ncol - 1", call. = FALSE) + if (!(length(width) == 1 || length(width) == n)) { + cli::cli_abort("{.arg width} must be of length 1 or ncol - 1") + } width <- rep(width, length.out = n) for (i in rev(seq_len(n))) { @@ -53,11 +55,13 @@ gtable_add_col_space <- function(x, width) { #' @export #' @rdname gtable_add_space gtable_add_row_space <- function(x, height) { - if (!is.gtable(x)) stop("x must be a gtable", call. = FALSE) + check_gtable(x) n <- length(x$heights) - 1 if (n == 0) return(x) - if (!(length(height) == 1 || length(height) == n)) stop("height must be of length 1 or nrow - 1", call. = FALSE) + if (!(length(height) == 1 || length(height) == n)) { + cli::cli_abort("{.arg height} must be of length 1 or nrow - 1") + } height <- rep(height, length.out = n) for (i in rev(seq_len(n))) { diff --git a/R/align.r b/R/align.R similarity index 90% rename from R/align.r rename to R/align.R index ac842a2..f38df20 100644 --- a/R/align.r +++ b/R/align.R @@ -23,7 +23,7 @@ gtable_join <- function(x, y, along = 1L, join = "left") { switch(along, cbind(aligned$x, aligned$y), rbind(aligned$x, aligned$y), - stop("along > 2 no implemented") + cli::cli_abort("{.arg along} > 2 no implemented") ) } @@ -41,13 +41,13 @@ gtable_join <- function(x, y, along = 1L, join = "left") { # @return a list with elements \code{x} and \code{y} corresponding to the # input gtables with extra rows/columns so that they now align. gtable_align <- function(x, y, along = 1L, join = "left") { - join <- match.arg(join, c("left", "right", "inner", "outer")) + join <- arg_match0(join, c("left", "right", "inner", "outer")) names_x <- dimnames(x)[[along]] names_y <- dimnames(y)[[along]] if (is.null(names_x) || is.null(names_y)) { - stop("Both gtables must have names along dimension to be aligned") + cli::cli_abort("Both gtables must have names along dimension to be aligned") } idx <- switch(join, @@ -73,12 +73,14 @@ gtable_align <- function(x, y, along = 1L, join = "left") { # rownames(gtable:::gtable_reindex(gt, c("a"))) # rownames(gtable:::gtable_reindex(gt, c("a", "d", "e"))) gtable_reindex <- function(x, index, along = 1) { - if (!is.character(index)) stop("index must be a character", call. = FALSE) + check_character(index) if (length(dim(x)) > 2L || along > 2L) { - stop("reindex only supports 2d objects") + cli::cli_abort("only 2d objects can be reindexed") } old_index <- switch(along, rownames(x), colnames(x)) - if (is.null(old_index)) stop("index is NULL in the given dimension", call. = FALSE) + if (is.null(old_index)) { + cli::cli_abort("{.arg index} is NULL in the given dimension") + } if (identical(index, old_index)) { return(x) diff --git a/R/grid.r b/R/grid.R similarity index 94% rename from R/grid.r rename to R/grid.R index 244ffdb..0bfc68f 100644 --- a/R/grid.r +++ b/R/grid.R @@ -14,13 +14,13 @@ #' gtable_show_layout(gt) #' gtable_show_layout <- function(x, ...) { - if (!is.gtable(x)) stop("x must be a gtable", call. = FALSE) + check_gtable(x) grid.show.layout(gtable_layout(x), ...) } gtable_layout <- function(x) { - if (!is.gtable(x)) stop("x must be a gtable", call. = FALSE) + check_gtable(x) grid.layout( nrow = length(x$heights), heights = x$heights, diff --git a/R/gtable-layouts.r b/R/gtable-layouts.R similarity index 87% rename from R/gtable-layouts.r rename to R/gtable-layouts.R index 414bdb1..0029702 100644 --- a/R/gtable-layouts.r +++ b/R/gtable-layouts.R @@ -30,7 +30,9 @@ gtable_col <- function(name, grobs, width = NULL, heights = NULL, heights <- heights %||% rep(unit(1, "null"), length(grobs)) # z is either NULL, or a vector of the same length as grobs - if (!(is.null(z) || length(z) == length(grobs))) stop("z must be either NULL or the same length as grobs", call. = FALSE) + if (!(is.null(z) || length(z) == length(grobs))) { + cli::cli_abort("{.arg z} must be either NULL or the same length as {.arg grobs}") + } if (is.null(z)) { z <- Inf } @@ -77,7 +79,9 @@ gtable_row <- function(name, grobs, height = NULL, widths = NULL, widths <- widths %||% rep(unit(1, "null"), length(grobs)) # z is either NULL, or a vector of the same length as grobs - if (!(is.null(z) || length(z) == length(grobs))) stop("z must be either NULL or the same length as grobs", call. = FALSE) + if (!(is.null(z) || length(z) == length(grobs))) { + cli::cli_abort("{.arg z} must be either NULL or the same length as {.arg grobs}") + } if (is.null(z)) { z <- Inf } @@ -129,10 +133,16 @@ gtable_row <- function(name, grobs, height = NULL, widths = NULL, #' gtable_matrix("demo", mat, unit(c(1, 1), "null"), unit(c(1, 1), "null"), z = z) gtable_matrix <- function(name, grobs, widths = NULL, heights = NULL, z = NULL, respect = FALSE, clip = "on", vp = NULL) { - if (length(widths) != ncol(grobs)) stop("width must be the same as the number of columns in grob", call. = FALSE) - if (length(heights) != nrow(grobs)) stop("height must be the same as the number of rows in grob", call. = FALSE) + if (length(widths) != ncol(grobs)) { + cli::cli_abort("{.arg widths} must be the same as the number of columns in {.arg grobs}") + } + if (length(heights) != nrow(grobs)) { + cli::cli_abort("{.arg heights} must be the same as the number of rows in {.arg grobs}") + } # z is either NULL or a matrix of the same dimensions as grobs - if (!(is.null(z) || identical(dim(grobs), dim(z)))) stop("z must be either NULL or have the same dimensions as grobs", call. = FALSE) + if (!(is.null(z) || identical(dim(grobs), dim(z)))) { + cli::cli_abort("{.arg z} must be either NULL or have the same dimensions as {.arg grobs}") + } if (is.null(z)) { z <- Inf } diff --git a/R/gtable-package.R b/R/gtable-package.R index 568ad66..ab98311 100644 --- a/R/gtable-package.R +++ b/R/gtable-package.R @@ -1,7 +1,11 @@ #' @keywords internal -#' @import grid #' @aliases NULL -#' -#' @seealso [gtable()] for an overview of the class and construction -#' "_PACKAGE" + +## usethis namespace: start +#' @import grid +#' @import rlang +#' @importFrom glue glue +#' @importFrom lifecycle deprecated +## usethis namespace: end +NULL diff --git a/R/gtable.r b/R/gtable.R similarity index 93% rename from R/gtable.r rename to R/gtable.R index ea2a63a..97cd576 100644 --- a/R/gtable.r +++ b/R/gtable.R @@ -95,12 +95,16 @@ gtable <- function(widths = list(), heights = list(), respect = FALSE, name = "layout", rownames = NULL, colnames = NULL, vp = NULL) { if (length(widths) > 0) { - if (!is.unit(widths)) stop("widths must be a unit object", call. = FALSE) - if (!(is.null(colnames) || length(colnames == length(widths)))) stop("colnames must either be NULL or have the same length as widths", call. = FALSE) + check_unit(widths) + if (!(is.null(colnames) || length(colnames == length(widths)))) { + cli::cli_abort("{.arg colnames} must either be NULL or have the same length as {.arg widths}") + } } if (length(heights) > 0) { - if (!is.unit(heights)) stop("heights must be a unit object", call. = FALSE) - if (!(is.null(rownames) || length(rownames == length(heights)))) stop("rownames must either be NULL or have the same length as heights", call. = FALSE) + check_unit(heights) + if (!(is.null(rownames) || length(rownames == length(heights)))) { + cli::cli_abort("{.arg rownames} must either be NULL or have the same length as {.arg heights}") + } } layout <- new_data_frame(list( @@ -168,14 +172,10 @@ dimnames.gtable <- function(x, ...) list(x$rownames, x$colnames) x$colnames <- value[[2]] if (anyDuplicated(x$rownames)) { - stop("rownames must be distinct", - call. = FALSE - ) + cli::cli_abort("rownames must be distinct") } if (anyDuplicated(x$colnames)) { - stop("colnames must be distinct", - call. = FALSE - ) + cli::cli_abort("colnames must be distinct") } x @@ -224,7 +224,7 @@ t.gtable <- function(x) { if ((length(rows) > 1 && any(diff(rows) < 1)) || (length(cols) > 1 && any(diff(cols) < 1))) { - stop("i and j must be increasing sequences of numbers", call. = FALSE) + cli::cli_abort("{.arg i} and {.arg j} must be increasing sequences of numbers") } i <- seq_along(x$heights) %in% seq_along(x$heights)[rows] diff --git a/R/import-standalone-obj-type.R b/R/import-standalone-obj-type.R new file mode 100644 index 0000000..7cd62fc --- /dev/null +++ b/R/import-standalone-obj-type.R @@ -0,0 +1,348 @@ +# Standalone file: do not edit by hand +# Source: +# ---------------------------------------------------------------------- +# +# --- +# repo: r-lib/rlang +# file: standalone-obj-type.R +# last-updated: 2022-10-04 +# license: https://unlicense.org +# --- +# +# ## Changelog +# +# 2022-10-04: +# - `obj_type_friendly(value = TRUE)` now shows numeric scalars +# literally. +# - `stop_friendly_type()` now takes `show_value`, passed to +# `obj_type_friendly()` as the `value` argument. +# +# 2022-10-03: +# - Added `allow_na` and `allow_null` arguments. +# - `NULL` is now backticked. +# - Better friendly type for infinities and `NaN`. +# +# 2022-09-16: +# - Unprefixed usage of rlang functions with `rlang::` to +# avoid onLoad issues when called from rlang (#1482). +# +# 2022-08-11: +# - Prefixed usage of rlang functions with `rlang::`. +# +# 2022-06-22: +# - `friendly_type_of()` is now `obj_type_friendly()`. +# - Added `obj_type_oo()`. +# +# 2021-12-20: +# - Added support for scalar values and empty vectors. +# - Added `stop_input_type()` +# +# 2021-06-30: +# - Added support for missing arguments. +# +# 2021-04-19: +# - Added support for matrices and arrays (#141). +# - Added documentation. +# - Added changelog. +# +# nocov start + +#' Return English-friendly type +#' @param x Any R object. +#' @param value Whether to describe the value of `x`. Special values +#' like `NA` or `""` are always described. +#' @param length Whether to mention the length of vectors and lists. +#' @return A string describing the type. Starts with an indefinite +#' article, e.g. "an integer vector". +#' @noRd +obj_type_friendly <- function(x, value = TRUE) { + if (is_missing(x)) { + return("absent") + } + + if (is.object(x)) { + if (inherits(x, "quosure")) { + type <- "quosure" + } else { + type <- paste(class(x), collapse = "/") + } + return(sprintf("a <%s> object", type)) + } + + if (!is_vector(x)) { + return(.rlang_as_friendly_type(typeof(x))) + } + + n_dim <- length(dim(x)) + + if (!n_dim) { + if (!is_list(x) && length(x) == 1) { + if (is_na(x)) { + return(switch( + typeof(x), + logical = "`NA`", + integer = "an integer `NA`", + double = + if (is.nan(x)) { + "`NaN`" + } else { + "a numeric `NA`" + }, + complex = "a complex `NA`", + character = "a character `NA`", + .rlang_stop_unexpected_typeof(x) + )) + } + + show_infinites <- function(x) { + if (x > 0) { + "`Inf`" + } else { + "`-Inf`" + } + } + str_encode <- function(x, width = 30, ...) { + if (nchar(x) > width) { + x <- substr(x, 1, width - 3) + x <- paste0(x, "...") + } + encodeString(x, ...) + } + + if (value) { + if (is.numeric(x) && is.infinite(x)) { + return(show_infinites(x)) + } + + if (is.numeric(x) || is.complex(x)) { + number <- as.character(round(x, 2)) + what <- if (is.complex(x)) "the complex number" else "the number" + return(paste(what, number)) + } + + return(switch( + typeof(x), + logical = if (x) "`TRUE`" else "`FALSE`", + character = { + what <- if (nzchar(x)) "the string" else "the empty string" + paste(what, str_encode(x, quote = "\"")) + }, + raw = paste("the raw value", as.character(x)), + .rlang_stop_unexpected_typeof(x) + )) + } + + return(switch( + typeof(x), + logical = "a logical value", + integer = "an integer", + double = if (is.infinite(x)) show_infinites(x) else "a number", + complex = "a complex number", + character = if (nzchar(x)) "a string" else "\"\"", + raw = "a raw value", + .rlang_stop_unexpected_typeof(x) + )) + } + + if (length(x) == 0) { + return(switch( + typeof(x), + logical = "an empty logical vector", + integer = "an empty integer vector", + double = "an empty numeric vector", + complex = "an empty complex vector", + character = "an empty character vector", + raw = "an empty raw vector", + list = "an empty list", + .rlang_stop_unexpected_typeof(x) + )) + } + } + + vec_type_friendly(x) +} + +vec_type_friendly <- function(x, length = FALSE) { + if (!is_vector(x)) { + abort("`x` must be a vector.") + } + type <- typeof(x) + n_dim <- length(dim(x)) + + add_length <- function(type) { + if (length && !n_dim) { + paste0(type, sprintf(" of length %s", length(x))) + } else { + type + } + } + + if (type == "list") { + if (n_dim < 2) { + return(add_length("a list")) + } else if (is.data.frame(x)) { + return("a data frame") + } else if (n_dim == 2) { + return("a list matrix") + } else { + return("a list array") + } + } + + type <- switch( + type, + logical = "a logical %s", + integer = "an integer %s", + numeric = , + double = "a double %s", + complex = "a complex %s", + character = "a character %s", + raw = "a raw %s", + type = paste0("a ", type, " %s") + ) + + if (n_dim < 2) { + kind <- "vector" + } else if (n_dim == 2) { + kind <- "matrix" + } else { + kind <- "array" + } + out <- sprintf(type, kind) + + if (n_dim >= 2) { + out + } else { + add_length(out) + } +} + +.rlang_as_friendly_type <- function(type) { + switch( + type, + + list = "a list", + + NULL = "`NULL`", + environment = "an environment", + externalptr = "a pointer", + weakref = "a weak reference", + S4 = "an S4 object", + + name = , + symbol = "a symbol", + language = "a call", + pairlist = "a pairlist node", + expression = "an expression vector", + + char = "an internal string", + promise = "an internal promise", + ... = "an internal dots object", + any = "an internal `any` object", + bytecode = "an internal bytecode object", + + primitive = , + builtin = , + special = "a primitive function", + closure = "a function", + + type + ) +} + +.rlang_stop_unexpected_typeof <- function(x, call = caller_env()) { + abort( + sprintf("Unexpected type <%s>.", typeof(x)), + call = call + ) +} + +#' Return OO type +#' @param x Any R object. +#' @return One of `"bare"` (for non-OO objects), `"S3"`, `"S4"`, +#' `"R6"`, or `"R7"`. +#' @noRd +obj_type_oo <- function(x) { + if (!is.object(x)) { + return("bare") + } + + class <- inherits(x, c("R6", "R7_object"), which = TRUE) + + if (class[[1]]) { + "R6" + } else if (class[[2]]) { + "R7" + } else if (isS4(x)) { + "S4" + } else { + "S3" + } +} + +#' @param x The object type which does not conform to `what`. Its +#' `obj_type_friendly()` is taken and mentioned in the error message. +#' @param what The friendly expected type as a string. Can be a +#' character vector of expected types, in which case the error +#' message mentions all of them in an "or" enumeration. +#' @param show_value Passed to `value` argument of `obj_type_friendly()`. +#' @param ... Arguments passed to [abort()]. +#' @inheritParams args_error_context +#' @noRd +stop_input_type <- function(x, + what, + ..., + allow_na = FALSE, + allow_null = FALSE, + show_value = TRUE, + arg = caller_arg(x), + call = caller_env()) { + # From standalone-cli.R + cli <- env_get_list( + nms = c("format_arg", "format_code"), + last = topenv(), + default = function(x) sprintf("`%s`", x), + inherit = TRUE + ) + + if (allow_na) { + what <- c(what, cli$format_code("NA")) + } + if (allow_null) { + what <- c(what, cli$format_code("NULL")) + } + if (length(what)) { + what <- oxford_comma(what) + } + + message <- sprintf( + "%s must be %s, not %s.", + cli$format_arg(arg), + what, + obj_type_friendly(x, value = show_value) + ) + + abort(message, ..., call = call, arg = arg) +} + +oxford_comma <- function(chr, sep = ", ", final = "or") { + n <- length(chr) + + if (n < 2) { + return(chr) + } + + head <- chr[seq_len(n - 1)] + last <- chr[n] + + head <- paste(head, collapse = sep) + + # Write a or b. But a, b, or c. + if (n > 2) { + paste0(head, sep, final, " ", last) + } else { + paste0(head, " ", final, " ", last) + } +} + +# nocov end diff --git a/R/import-standalone-types-check.R b/R/import-standalone-types-check.R new file mode 100644 index 0000000..4c4ca85 --- /dev/null +++ b/R/import-standalone-types-check.R @@ -0,0 +1,493 @@ +# Standalone file: do not edit by hand +# Source: +# ---------------------------------------------------------------------- +# +# --- +# repo: r-lib/rlang +# file: standalone-types-check.R +# last-updated: 2023-02-15 +# license: https://unlicense.org +# dependencies: standalone-obj-type.R +# --- +# +# ## Changelog +# +# 2023-02-15: +# - Added `check_logical()`. +# +# - `check_bool()`, `check_number_whole()`, and +# `check_number_decimal()` are now implemented in C. +# +# - For efficiency, `check_number_whole()` and +# `check_number_decimal()` now take a `NULL` default for `min` and +# `max`. This makes it possible to bypass unnecessary type-checking +# and comparisons in the default case of no bounds checks. +# +# 2022-10-07: +# - `check_number_whole()` and `_decimal()` no longer treat +# non-numeric types such as factors or dates as numbers. Numeric +# types are detected with `is.numeric()`. +# +# 2022-10-04: +# - Added `check_name()` that forbids the empty string. +# `check_string()` allows the empty string by default. +# +# 2022-09-28: +# - Removed `what` arguments. +# - Added `allow_na` and `allow_null` arguments. +# - Added `allow_decimal` and `allow_infinite` arguments. +# - Improved errors with absent arguments. +# +# +# 2022-09-16: +# - Unprefixed usage of rlang functions with `rlang::` to +# avoid onLoad issues when called from rlang (#1482). +# +# 2022-08-11: +# - Added changelog. +# +# nocov start + +# Scalars ----------------------------------------------------------------- + +.standalone_types_check_dot_call <- .Call + +check_bool <- function(x, + ..., + allow_na = FALSE, + allow_null = FALSE, + arg = caller_arg(x), + call = caller_env()) { + if (!missing(x) && .standalone_types_check_dot_call(ffi_standalone_is_bool_1.0.7, x, allow_na, allow_null)) { + return(invisible(NULL)) + } + + stop_input_type( + x, + c("`TRUE`", "`FALSE`"), + ..., + allow_na = allow_na, + allow_null = allow_null, + arg = arg, + call = call + ) +} + +check_string <- function(x, + ..., + allow_empty = TRUE, + allow_na = FALSE, + allow_null = FALSE, + arg = caller_arg(x), + call = caller_env()) { + if (!missing(x)) { + is_string <- .rlang_check_is_string( + x, + allow_empty = allow_empty, + allow_na = allow_na, + allow_null = allow_null + ) + if (is_string) { + return(invisible(NULL)) + } + } + + stop_input_type( + x, + "a single string", + ..., + allow_na = allow_na, + allow_null = allow_null, + arg = arg, + call = call + ) +} + +.rlang_check_is_string <- function(x, + allow_empty, + allow_na, + allow_null) { + if (is_string(x)) { + if (allow_empty || !is_string(x, "")) { + return(TRUE) + } + } + + if (allow_null && is_null(x)) { + return(TRUE) + } + + if (allow_na && (identical(x, NA) || identical(x, na_chr))) { + return(TRUE) + } + + FALSE +} + +check_name <- function(x, + ..., + allow_null = FALSE, + arg = caller_arg(x), + call = caller_env()) { + if (!missing(x)) { + is_string <- .rlang_check_is_string( + x, + allow_empty = FALSE, + allow_na = FALSE, + allow_null = allow_null + ) + if (is_string) { + return(invisible(NULL)) + } + } + + stop_input_type( + x, + "a valid name", + ..., + allow_na = FALSE, + allow_null = allow_null, + arg = arg, + call = call + ) +} + +IS_NUMBER_true <- 0 +IS_NUMBER_false <- 1 +IS_NUMBER_oob <- 2 + +check_number_decimal <- function(x, + ..., + min = NULL, + max = NULL, + allow_infinite = TRUE, + allow_na = FALSE, + allow_null = FALSE, + arg = caller_arg(x), + call = caller_env()) { + if (missing(x)) { + exit_code <- IS_NUMBER_false + } else if (0 == (exit_code <- .standalone_types_check_dot_call( + ffi_standalone_check_number_1.0.7, + x, + allow_decimal = TRUE, + min, + max, + allow_infinite, + allow_na, + allow_null + ))) { + return(invisible(NULL)) + } + + .stop_not_number( + x, + ..., + exit_code = exit_code, + allow_decimal = TRUE, + min = min, + max = max, + allow_na = allow_na, + allow_null = allow_null, + arg = arg, + call = call + ) +} + +check_number_whole <- function(x, + ..., + min = NULL, + max = NULL, + allow_na = FALSE, + allow_null = FALSE, + arg = caller_arg(x), + call = caller_env()) { + if (missing(x)) { + exit_code <- IS_NUMBER_false + } else if (0 == (exit_code <- .standalone_types_check_dot_call( + ffi_standalone_check_number_1.0.7, + x, + allow_decimal = FALSE, + min, + max, + allow_infinite = FALSE, + allow_na, + allow_null + ))) { + return(invisible(NULL)) + } + + .stop_not_number( + x, + ..., + exit_code = exit_code, + allow_decimal = FALSE, + min = min, + max = max, + allow_na = allow_na, + allow_null = allow_null, + arg = arg, + call = call + ) +} + +.stop_not_number <- function(x, + ..., + exit_code, + allow_decimal, + min, + max, + allow_na, + allow_null, + arg, + call) { + if (exit_code == IS_NUMBER_oob) { + min <- min %||% -Inf + max <- max %||% Inf + + if (min > -Inf && max < Inf) { + what <- sprintf("a number between %s and %s", min, max) + } else if (x < min) { + what <- sprintf("a number larger than %s", min) + } else if (x > max) { + what <- sprintf("a number smaller than %s", max) + } else { + abort("Unexpected state in OOB check", .internal = TRUE) + } + } else if (allow_decimal) { + what <- "a number" + } else { + what <- "a whole number" + } + + stop_input_type( + x, + what, + ..., + allow_na = allow_na, + allow_null = allow_null, + arg = arg, + call = call + ) +} + +check_symbol <- function(x, + ..., + allow_null = FALSE, + arg = caller_arg(x), + call = caller_env()) { + if (!missing(x)) { + if (is_symbol(x)) { + return(invisible(NULL)) + } + if (allow_null && is_null(x)) { + return(invisible(NULL)) + } + } + + stop_input_type( + x, + "a symbol", + ..., + allow_null = allow_null, + arg = arg, + call = call + ) +} + +check_arg <- function(x, + ..., + allow_null = FALSE, + arg = caller_arg(x), + call = caller_env()) { + if (!missing(x)) { + if (is_symbol(x)) { + return(invisible(NULL)) + } + if (allow_null && is_null(x)) { + return(invisible(NULL)) + } + } + + stop_input_type( + x, + "an argument name", + ..., + allow_null = allow_null, + arg = arg, + call = call + ) +} + +check_call <- function(x, + ..., + allow_null = FALSE, + arg = caller_arg(x), + call = caller_env()) { + if (!missing(x)) { + if (is_call(x)) { + return(invisible(NULL)) + } + if (allow_null && is_null(x)) { + return(invisible(NULL)) + } + } + + stop_input_type( + x, + "a defused call", + ..., + allow_null = allow_null, + arg = arg, + call = call + ) +} + +check_environment <- function(x, + ..., + allow_null = FALSE, + arg = caller_arg(x), + call = caller_env()) { + if (!missing(x)) { + if (is_environment(x)) { + return(invisible(NULL)) + } + if (allow_null && is_null(x)) { + return(invisible(NULL)) + } + } + + stop_input_type( + x, + "an environment", + ..., + allow_null = allow_null, + arg = arg, + call = call + ) +} + +check_function <- function(x, + ..., + allow_null = FALSE, + arg = caller_arg(x), + call = caller_env()) { + if (!missing(x)) { + if (is_function(x)) { + return(invisible(NULL)) + } + if (allow_null && is_null(x)) { + return(invisible(NULL)) + } + } + + stop_input_type( + x, + "a function", + ..., + allow_null = allow_null, + arg = arg, + call = call + ) +} + +check_closure <- function(x, + ..., + allow_null = FALSE, + arg = caller_arg(x), + call = caller_env()) { + if (!missing(x)) { + if (is_closure(x)) { + return(invisible(NULL)) + } + if (allow_null && is_null(x)) { + return(invisible(NULL)) + } + } + + stop_input_type( + x, + "an R function", + ..., + allow_null = allow_null, + arg = arg, + call = call + ) +} + +check_formula <- function(x, + ..., + allow_null = FALSE, + arg = caller_arg(x), + call = caller_env()) { + if (!missing(x)) { + if (is_formula(x)) { + return(invisible(NULL)) + } + if (allow_null && is_null(x)) { + return(invisible(NULL)) + } + } + + stop_input_type( + x, + "a formula", + ..., + allow_null = allow_null, + arg = arg, + call = call + ) +} + + +# Vectors ----------------------------------------------------------------- + +check_character <- function(x, + ..., + allow_null = FALSE, + arg = caller_arg(x), + call = caller_env()) { + if (!missing(x)) { + if (is_character(x)) { + return(invisible(NULL)) + } + if (allow_null && is_null(x)) { + return(invisible(NULL)) + } + } + + stop_input_type( + x, + "a character vector", + ..., + allow_null = allow_null, + arg = arg, + call = call + ) +} + +check_logical <- function(x, + ..., + allow_null = FALSE, + arg = caller_arg(x), + call = caller_env()) { + if (!missing(x)) { + if (is_logical(x)) { + return(invisible(NULL)) + } + if (allow_null && is_null(x)) { + return(invisible(NULL)) + } + } + + stop_input_type( + x, + "a logical vector", + ..., + allow_null = allow_null, + arg = arg, + call = call + ) +} + +# nocov end diff --git a/R/new-data-frame.r b/R/new-data-frame.R similarity index 61% rename from R/new-data-frame.r rename to R/new-data-frame.R index 7a5af0e..8e35795 100644 --- a/R/new-data-frame.r +++ b/R/new-data-frame.R @@ -12,6 +12,10 @@ new_data_frame <- function(x, n = NULL) { } validate_data_frame <- function(x) { - if (length(unique(lengths(x))) != 1) stop('All elements in a data.frame must be of equal length', call. = FALSE) - if (is.null(names(x))) stop('Columns must be named', call. = FALSE) + if (length(unique(lengths(x))) != 1) { + cli::cli_abort('All elements in a data.frame must be of equal length') + } + if (is.null(names(x))) { + cli::cli_abort('columns must be named') + } } diff --git a/R/rbind-cbind.r b/R/rbind-cbind.R similarity index 94% rename from R/rbind-cbind.r rename to R/rbind-cbind.R index 50f318b..1834994 100644 --- a/R/rbind-cbind.r +++ b/R/rbind-cbind.R @@ -62,7 +62,9 @@ rbind.gtable <- function(..., size = "max", z = NULL) { } rbind_gtable <- function(x, y, size = "max") { - if (length(x$widths) != length(y$widths)) stop("x and y must have the same number of columns", call. = FALSE) + if (length(x$widths) != length(y$widths)) { + cli::cli_abort("{.arg x} and {.arg y} must have the same number of columns") + } x_row <- length(x$heights) y_row <- length(y$heights) if (x_row == 0) return(y) @@ -109,7 +111,9 @@ cbind.gtable <- function(..., size = "max", z = NULL) { } cbind_gtable <- function(x, y, size = "max") { - if (length(x$heights) != length(y$heights)) stop("x and y must have the same number of rows", call. = FALSE) + if (length(x$heights) != length(y$heights)) { + cli::cli_abort("{.arg x} and {.arg y} must have the same number of rows") + } x_col <- length(x$widths) y_col <- length(y$widths) if (x_col == 0) return(y) diff --git a/R/trim.r b/R/trim.R similarity index 95% rename from R/trim.r rename to R/trim.R index 431930b..25b5c0e 100644 --- a/R/trim.r +++ b/R/trim.R @@ -29,7 +29,7 @@ #' plot(row) #' plot(gtable_trim(row)) gtable_trim <- function(x) { - if (!is.gtable(x)) stop("x must be a gtable", call. = FALSE) + check_gtable(x) if (length(x) == 0) { return(gtable(respect = x$respect, name = x$name, vp = x$vp)) } diff --git a/R/utils.r b/R/utils.R similarity index 58% rename from R/utils.r rename to R/utils.R index 405558d..09082f8 100644 --- a/R/utils.r +++ b/R/utils.R @@ -1,3 +1,51 @@ +check_gtable <- function(x, + ..., + allow_null = FALSE, + arg = caller_arg(x), + call = caller_env()) { + if (!missing(x)) { + if (is.gtable(x)) { + return(invisible(NULL)) + } + if (allow_null && is_null(x)) { + return(invisible(NULL)) + } + } + + stop_input_type( + x, + "a gtable object", + ..., + allow_null = allow_null, + arg = arg, + call = call + ) +} + +check_unit <- function(x, + ..., + allow_null = FALSE, + arg = caller_arg(x), + call = caller_env()) { + if (!missing(x)) { + if (is.unit(x)) { + return(invisible(NULL)) + } + if (allow_null && is_null(x)) { + return(invisible(NULL)) + } + } + + stop_input_type( + x, + "a unit vector", + ..., + allow_null = allow_null, + arg = arg, + call = call + ) +} + neg_to_pos <- function(x, max) { ifelse(x >= 0, x, max + 1 + x) } @@ -12,7 +60,7 @@ compare_unit <- function(x, y, comp = `=`) { if (identical(comp, pmax)) { return(unit.pmax(x, y)) } - stop('Comparison not supported', call. = FALSE) + cli::cli_abort('comparison not supported') } # Below should be removed once the old grid unit implementation has been deprecated x_attr <- attributes(x) @@ -23,7 +71,7 @@ compare_unit <- function(x, y, comp = `=`) { y_unit <- attr(x, "unit") if (!all(x_unit == y_unit)) { - stop("Comparison of units with different types currently not supported") + cli::cli_abort("comparison of units with different types currently not supported") } `attributes<-`(comp(x_val, y_val), x_attr) @@ -56,7 +104,7 @@ width_cm <- function(x) { } else if (is.unit(x)) { convertWidth(x, "cm", TRUE) } else { - stop("Unknown input") + cli::cli_abort("Unknown input") } } height_cm <- function(x) { @@ -67,7 +115,7 @@ height_cm <- function(x) { } else if (is.unit(x)) { convertHeight(x, "cm", TRUE) } else { - stop("Unknown input") + cli::cli_abort("Unknown input") } } diff --git a/R/z.r b/R/z.R similarity index 94% rename from R/z.r rename to R/z.R index f9cb66f..e9a7338 100644 --- a/R/z.r +++ b/R/z.R @@ -33,7 +33,7 @@ z_normalise <- function(x, i = 1) { #' @noRd z_arrange_gtables <- function(gtables, z) { if (length(gtables) != length(z)) { - stop("'gtables' and 'z' must be the same length") + cli::cli_abort("{.arg gtables} and {.arg z} must be the same length") } # Keep track of largest z value encountered so far diff --git a/R/zzz.R b/R/zzz.R new file mode 100644 index 0000000..03bab3c --- /dev/null +++ b/R/zzz.R @@ -0,0 +1,5 @@ +release_extra_revdeps <- function() { + c( + "ggplot2" + ) +} diff --git a/README.Rmd b/README.Rmd index 2cda891..77610aa 100644 --- a/README.Rmd +++ b/README.Rmd @@ -14,13 +14,14 @@ knitr::opts_chunk$set( set.seed(42L) options(width = 90) ``` -# gtable + +# gtable -[![R-CMD-check](https://github.com/r-lib/gtable/workflows/R-CMD-check/badge.svg)](https://github.com/r-lib/gtable/actions) -[![CRAN_Status_Badge](http://www.r-pkg.org/badges/version/gtable)](https://cran.r-project.org/package=gtable) +[![R-CMD-check](https://github.com/r-lib/gtable/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/r-lib/gtable/actions/workflows/R-CMD-check.yaml) +[![CRAN status](https://www.r-pkg.org/badges/version/gtable)](https://CRAN.R-project.org/package=gtable) [![Codecov test coverage](https://codecov.io/gh/r-lib/gtable/branch/main/graph/badge.svg)](https://app.codecov.io/gh/r-lib/gtable?branch=main) -[![lifecycle](https://img.shields.io/badge/lifecycle-stable-brightgreen.svg)](https://lifecycle.r-lib.org/articles/stages.html#stable) +[![Lifecycle: stable](https://img.shields.io/badge/lifecycle-stable-brightgreen.svg)](https://lifecycle.r-lib.org/articles/stages.html#stable) gtable is a layout engine built on top of the grid package. It is used to abstract away the creation of (potentially nested) grids of viewports into which graphic objects can be placed. gtable makes it easy to ensure alignment of graphic elements and piecemeal compositions of complex graphics. gtable is the layout engine powering [ggplot2](https://ggplot2.tidyverse.org) and is thus used extensively by many plotting functions in R without being called directly. @@ -36,8 +37,8 @@ install.packages("gtable") or use the remotes package to install the development version from [GitHub](https://github.com/r-lib/gtable) ```r -# install.packages("remotes") -remotes::install_github("r-lib/gtable") +# install.packages("pak") +pak::pak("r-lib/gtable") ``` ## Example diff --git a/README.md b/README.md index be3ea7f..102f395 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,17 @@ -# gtable +# gtable -[![R-CMD-check](https://github.com/r-lib/gtable/workflows/R-CMD-check/badge.svg)](https://github.com/r-lib/gtable/actions) -[![CRAN_Status_Badge](http://www.r-pkg.org/badges/version/gtable)](https://cran.r-project.org/package=gtable) +[![R-CMD-check](https://github.com/r-lib/gtable/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/r-lib/gtable/actions/workflows/R-CMD-check.yaml) +[![CRAN +status](https://www.r-pkg.org/badges/version/gtable)](https://CRAN.R-project.org/package=gtable) [![Codecov test coverage](https://codecov.io/gh/r-lib/gtable/branch/main/graph/badge.svg)](https://app.codecov.io/gh/r-lib/gtable?branch=main) -[![lifecycle](https://img.shields.io/badge/lifecycle-stable-brightgreen.svg)](https://lifecycle.r-lib.org/articles/stages.html#stable) +[![Lifecycle: +stable](https://img.shields.io/badge/lifecycle-stable-brightgreen.svg)](https://lifecycle.r-lib.org/articles/stages.html#stable) gtable is a layout engine built on top of the grid package. It is used @@ -33,8 +35,8 @@ or use the remotes package to install the development version from [GitHub](https://github.com/r-lib/gtable) ``` r -# install.packages("remotes") -remotes::install_github("r-lib/gtable") +# install.packages("pak") +pak::pak("r-lib/gtable") ``` ## Example diff --git a/_pkgdown.yml b/_pkgdown.yml index 8a1df7b..e2b7da3 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -1,5 +1,16 @@ url: https://gtable.r-lib.org +template: + package: tidytemplate + bootstrap: 5 + + includes: + in_header: | + + +development: + mode: auto + reference: - title: Construction contents: diff --git a/cran-comments.md b/cran-comments.md index 00ba37c..6178675 100644 --- a/cran-comments.md +++ b/cran-comments.md @@ -1,7 +1 @@ -## R CMD check results - -0 errors | 0 warnings | 0 notes - -## revdepcheck results - This was a patch to fix the HTML in .Rd problems; we did not re-check revdeps. diff --git a/man/bind.Rd b/man/bind.Rd index 80a43a7..62afd4e 100644 --- a/man/bind.Rd +++ b/man/bind.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/rbind-cbind.r +% Please edit documentation in R/rbind-cbind.R \name{bind} \alias{bind} \alias{rbind.gtable} diff --git a/man/figures/lifecycle-archived.svg b/man/figures/lifecycle-archived.svg new file mode 100644 index 0000000..745ab0c --- /dev/null +++ b/man/figures/lifecycle-archived.svg @@ -0,0 +1,21 @@ + + lifecycle: archived + + + + + + + + + + + + + + + lifecycle + + archived + + diff --git a/man/figures/lifecycle-defunct.svg b/man/figures/lifecycle-defunct.svg new file mode 100644 index 0000000..d5c9559 --- /dev/null +++ b/man/figures/lifecycle-defunct.svg @@ -0,0 +1,21 @@ + + lifecycle: defunct + + + + + + + + + + + + + + + lifecycle + + defunct + + diff --git a/man/figures/lifecycle-deprecated.svg b/man/figures/lifecycle-deprecated.svg new file mode 100644 index 0000000..b61c57c --- /dev/null +++ b/man/figures/lifecycle-deprecated.svg @@ -0,0 +1,21 @@ + + lifecycle: deprecated + + + + + + + + + + + + + + + lifecycle + + deprecated + + diff --git a/man/figures/lifecycle-experimental.svg b/man/figures/lifecycle-experimental.svg new file mode 100644 index 0000000..5d88fc2 --- /dev/null +++ b/man/figures/lifecycle-experimental.svg @@ -0,0 +1,21 @@ + + lifecycle: experimental + + + + + + + + + + + + + + + lifecycle + + experimental + + diff --git a/man/figures/lifecycle-maturing.svg b/man/figures/lifecycle-maturing.svg new file mode 100644 index 0000000..897370e --- /dev/null +++ b/man/figures/lifecycle-maturing.svg @@ -0,0 +1,21 @@ + + lifecycle: maturing + + + + + + + + + + + + + + + lifecycle + + maturing + + diff --git a/man/figures/lifecycle-questioning.svg b/man/figures/lifecycle-questioning.svg new file mode 100644 index 0000000..7c1721d --- /dev/null +++ b/man/figures/lifecycle-questioning.svg @@ -0,0 +1,21 @@ + + lifecycle: questioning + + + + + + + + + + + + + + + lifecycle + + questioning + + diff --git a/man/figures/lifecycle-soft-deprecated.svg b/man/figures/lifecycle-soft-deprecated.svg new file mode 100644 index 0000000..9c166ff --- /dev/null +++ b/man/figures/lifecycle-soft-deprecated.svg @@ -0,0 +1,21 @@ + + lifecycle: soft-deprecated + + + + + + + + + + + + + + + lifecycle + + soft-deprecated + + diff --git a/man/figures/lifecycle-stable.svg b/man/figures/lifecycle-stable.svg new file mode 100644 index 0000000..9bf21e7 --- /dev/null +++ b/man/figures/lifecycle-stable.svg @@ -0,0 +1,29 @@ + + lifecycle: stable + + + + + + + + + + + + + + + + lifecycle + + + + stable + + + diff --git a/man/figures/lifecycle-superseded.svg b/man/figures/lifecycle-superseded.svg new file mode 100644 index 0000000..25211d1 --- /dev/null +++ b/man/figures/lifecycle-superseded.svg @@ -0,0 +1,21 @@ + + lifecycle: superseded + + + + + + + + + + + + + + + lifecycle + + superseded + + diff --git a/man/figures/logo.png b/man/figures/logo.png index 57a8f4f34e13e2ad87cbbc64c69c8e9186453e9e..02546a44fee46ea8f7a0910f20e54a1b67096446 100644 GIT binary patch literal 49245 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 literal 18816 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 diff --git a/man/gtable-package.Rd b/man/gtable-package.Rd index 5009dfa..ec958c5 100644 --- a/man/gtable-package.Rd +++ b/man/gtable-package.Rd @@ -9,19 +9,25 @@ Tools to make it easier to work with "tables" of 'grobs'. The 'gtable' package defines a 'gtable' grob class that specifies a grid along with a list of grobs and their placement in the grid. Further the package makes it easy to manipulate and combine 'gtable' objects so that complex compositions can be built up sequentially. } \seealso{ -\code{\link[=gtable]{gtable()}} for an overview of the class and construction +Useful links: +\itemize{ + \item \url{https://gtable.r-lib.org} + \item \url{https://github.com/r-lib/gtable} + \item Report bugs at \url{https://github.com/r-lib/gtable/issues} +} + } \author{ -\strong{Maintainer}: Hadley Wickham \email{hadley@rstudio.com} +\strong{Maintainer}: Hadley Wickham \email{hadley@posit.co} Authors: \itemize{ - \item Thomas Lin Pedersen \email{thomas.pedersen@rstudio.com} + \item Thomas Lin Pedersen \email{thomas.pedersen@posit.co} } Other contributors: \itemize{ - \item RStudio [copyright holder] + \item Posit Software, PBC [copyright holder] } } diff --git a/man/gtable.Rd b/man/gtable.Rd index fe17ad3..4693f96 100644 --- a/man/gtable.Rd +++ b/man/gtable.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/gtable.r +% Please edit documentation in R/gtable.R \name{gtable} \alias{gtable} \title{Create a new grob table.} diff --git a/man/gtable_add_cols.Rd b/man/gtable_add_cols.Rd index 28dc0ab..5fe75ab 100644 --- a/man/gtable_add_cols.Rd +++ b/man/gtable_add_cols.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/add-rows-cols.r +% Please edit documentation in R/add-rows-cols.R \name{gtable_add_cols} \alias{gtable_add_cols} \title{Add new columns in specified position.} diff --git a/man/gtable_add_grob.Rd b/man/gtable_add_grob.Rd index 12667ab..6fcfc51 100644 --- a/man/gtable_add_grob.Rd +++ b/man/gtable_add_grob.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/add-grob.r +% Please edit documentation in R/add-grob.R \name{gtable_add_grob} \alias{gtable_add_grob} \title{Add a single grob, possibly spanning multiple rows or columns.} diff --git a/man/gtable_add_padding.Rd b/man/gtable_add_padding.Rd index eaf466a..8486a22 100644 --- a/man/gtable_add_padding.Rd +++ b/man/gtable_add_padding.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/padding.r +% Please edit documentation in R/padding.R \name{gtable_add_padding} \alias{gtable_add_padding} \title{Add padding around edges of table.} diff --git a/man/gtable_add_rows.Rd b/man/gtable_add_rows.Rd index 266b21f..61a2f26 100644 --- a/man/gtable_add_rows.Rd +++ b/man/gtable_add_rows.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/add-rows-cols.r +% Please edit documentation in R/add-rows-cols.R \name{gtable_add_rows} \alias{gtable_add_rows} \title{Add new rows in specified position.} diff --git a/man/gtable_add_space.Rd b/man/gtable_add_space.Rd index 91c8968..436cdf6 100644 --- a/man/gtable_add_space.Rd +++ b/man/gtable_add_space.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/add-space.r +% Please edit documentation in R/add-space.R \name{gtable_add_space} \alias{gtable_add_space} \alias{gtable_add_col_space} diff --git a/man/gtable_col.Rd b/man/gtable_col.Rd index 28304e4..7ef7c36 100644 --- a/man/gtable_col.Rd +++ b/man/gtable_col.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/gtable-layouts.r +% Please edit documentation in R/gtable-layouts.R \name{gtable_col} \alias{gtable_col} \title{Create a single column gtable} diff --git a/man/gtable_filter.Rd b/man/gtable_filter.Rd index ba69e98..8697254 100644 --- a/man/gtable_filter.Rd +++ b/man/gtable_filter.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/filter.r +% Please edit documentation in R/filter.R \name{gtable_filter} \alias{gtable_filter} \title{Filter cells by name} diff --git a/man/gtable_height.Rd b/man/gtable_height.Rd index 27a622c..e4c0d70 100644 --- a/man/gtable_height.Rd +++ b/man/gtable_height.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/gtable.r +% Please edit documentation in R/gtable.R \name{gtable_height} \alias{gtable_height} \title{Returns the height of a gtable, in the gtable's units} diff --git a/man/gtable_matrix.Rd b/man/gtable_matrix.Rd index 90b163f..a5c0c40 100644 --- a/man/gtable_matrix.Rd +++ b/man/gtable_matrix.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/gtable-layouts.r +% Please edit documentation in R/gtable-layouts.R \name{gtable_matrix} \alias{gtable_matrix} \title{Create a gtable from a matrix of grobs.} diff --git a/man/gtable_row.Rd b/man/gtable_row.Rd index b44b5ef..1ba9ef3 100644 --- a/man/gtable_row.Rd +++ b/man/gtable_row.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/gtable-layouts.r +% Please edit documentation in R/gtable-layouts.R \name{gtable_row} \alias{gtable_row} \title{Create a single row gtable.} diff --git a/man/gtable_show_layout.Rd b/man/gtable_show_layout.Rd index bb5b82c..9422e6c 100644 --- a/man/gtable_show_layout.Rd +++ b/man/gtable_show_layout.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/grid.r +% Please edit documentation in R/grid.R \name{gtable_show_layout} \alias{gtable_show_layout} \title{Visualise the layout of a gtable.} diff --git a/man/gtable_spacer.Rd b/man/gtable_spacer.Rd index 4d51da8..e51bda5 100644 --- a/man/gtable_spacer.Rd +++ b/man/gtable_spacer.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/gtable-layouts.r +% Please edit documentation in R/gtable-layouts.R \name{gtable_spacer} \alias{gtable_spacer} \alias{gtable_row_spacer} diff --git a/man/gtable_trim.Rd b/man/gtable_trim.Rd index 9c7cfda..0372038 100644 --- a/man/gtable_trim.Rd +++ b/man/gtable_trim.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/trim.r +% Please edit documentation in R/trim.R \name{gtable_trim} \alias{gtable_trim} \title{Trim off empty cells.} diff --git a/man/gtable_width.Rd b/man/gtable_width.Rd index c1fc199..b5b5a8b 100644 --- a/man/gtable_width.Rd +++ b/man/gtable_width.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/gtable.r +% Please edit documentation in R/gtable.R \name{gtable_width} \alias{gtable_width} \title{Returns the width of a gtable, in the gtable's units} diff --git a/man/is.gtable.Rd b/man/is.gtable.Rd index 83a27e7..8ad02da 100644 --- a/man/is.gtable.Rd +++ b/man/is.gtable.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/gtable.r +% Please edit documentation in R/gtable.R \name{is.gtable} \alias{is.gtable} \title{Is this a gtable?} diff --git a/man/print.gtable.Rd b/man/print.gtable.Rd index 5f76d50..5ee9959 100644 --- a/man/print.gtable.Rd +++ b/man/print.gtable.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/gtable.r +% Please edit documentation in R/gtable.R \name{print.gtable} \alias{print.gtable} \title{Print a gtable object} diff --git a/tests/testthat.R b/tests/testthat.R index 807b29d..143d5d7 100644 --- a/tests/testthat.R +++ b/tests/testthat.R @@ -1,3 +1,11 @@ +# This file is part of the standard setup for testthat. +# It is recommended that you do not modify it. +# +# Where should you do additional test configuration? +# Learn more about the roles of various files in: +# * https://r-pkgs.org/tests.html +# * https://testthat.r-lib.org/reference/test_package.html#special-files + library(testthat) library(gtable) diff --git a/tests/testthat/test-bind.r b/tests/testthat/test-bind.R similarity index 81% rename from tests/testthat/test-bind.r rename to tests/testthat/test-bind.R index 59597f1..34f00ec 100644 --- a/tests/testthat/test-bind.r +++ b/tests/testthat/test-bind.R @@ -1,19 +1,17 @@ -context("Bind") - test_that("Number of rows grow with rbind", { lay1 <- gtable_add_rows(gtable(), cm) lay2 <- gtable_add_rows(gtable(), rep(cm, 2)) - expect_that(nrow(rbind(lay1, lay2)), equals(3)) - expect_that(nrow(rbind(lay2, lay1)), equals(3)) + expect_equal(nrow(rbind(lay1, lay2)), 3) + expect_equal(nrow(rbind(lay2, lay1)), 3) }) test_that("Number of cols grow with cbind", { lay1 <- gtable_add_cols(gtable(), cm) lay2 <- gtable_add_cols(gtable(), rep(cm, 2)) - expect_that(ncol(cbind(lay1, lay2)), equals(3)) - expect_that(ncol(cbind(lay2, lay1)), equals(3)) + expect_equal(ncol(cbind(lay1, lay2)), 3) + expect_equal(ncol(cbind(lay2, lay1)), 3) }) test_that("Heights and widths vary with size parameter", { diff --git a/tests/testthat/test-filter.R b/tests/testthat/test-filter.R index c36a26a..11e7930 100644 --- a/tests/testthat/test-filter.R +++ b/tests/testthat/test-filter.R @@ -1,5 +1,3 @@ -context("filter") - gt <- gtable(widths = unit(1, "null"), heights = unit(rep(1, 4), "null")) gt <- gtable_add_grob( gt, diff --git a/tests/testthat/test-layout.r b/tests/testthat/test-layout.R similarity index 76% rename from tests/testthat/test-layout.r rename to tests/testthat/test-layout.R index e9e30b4..4466270 100644 --- a/tests/testthat/test-layout.r +++ b/tests/testthat/test-layout.R @@ -13,36 +13,34 @@ loc_df <- function(t, l, b, r) { ) } -context("gtable") - test_that("Number of rows grows with add_rows", { layout <- gtable() - expect_that(nrow(layout), equals(0)) + expect_equal(nrow(layout), 0) layout <- gtable_add_rows(layout, unit(1, "cm")) - expect_that(nrow(layout), equals(1)) + expect_equal(nrow(layout), 1) layout <- gtable_add_rows(layout, unit(1, "cm")) layout <- gtable_add_rows(layout, unit(1, "cm")) - expect_that(nrow(layout), equals(3)) + expect_equal(nrow(layout), 3) layout <- gtable_add_rows(layout, unit(1:2, "cm")) - expect_that(nrow(layout), equals(5)) + expect_equal(nrow(layout), 5) }) test_that("Number of columns grows with add_cols", { layout <- gtable() - expect_that(ncol(layout), equals(0)) + expect_equal(ncol(layout), 0) layout <- gtable_add_cols(layout, unit(1, "cm")) - expect_that(ncol(layout), equals(1)) + expect_equal(ncol(layout), 1) layout <- gtable_add_cols(layout, unit(c(1, 1), "cm")) - expect_that(ncol(layout), equals(3)) + expect_equal(ncol(layout), 3) layout <- gtable_add_cols(layout, unit(1:2, "cm")) - expect_that(ncol(layout), equals(5)) + expect_equal(ncol(layout), 5) }) @@ -52,11 +50,11 @@ test_that("Setting and getting works", { layout <- gtable_add_grob(layout, grob1, 1, 1) loc <- gtable_find(layout, grob1) - expect_that(nrow(loc), equals(1)) - expect_that(loc$t, equals(1)) - expect_that(loc$r, equals(1)) - expect_that(loc$b, equals(1)) - expect_that(loc$l, equals(1)) + expect_equal(nrow(loc), 1) + expect_equal(loc$t, 1) + expect_equal(loc$r, 1) + expect_equal(loc$b, 1) + expect_equal(loc$l, 1) }) test_that("Spanning grobs continue to span after row insertion", { @@ -66,21 +64,21 @@ test_that("Spanning grobs continue to span after row insertion", { within <- gtable_add_rows(gtable_add_cols(layout, cm, pos = 2), cm, pos = 2) loc <- gtable_find(within, grob1) - expect_that(loc, equals(loc_df(t = 1, l = 1, b = 4, r = 4))) + expect_equal(loc, loc_df(t = 1, l = 1, b = 4, r = 4)) top_left <- layout top_left <- gtable_add_cols(top_left, cm, pos = 0) top_left <- gtable_add_rows(top_left, cm, pos = 0) loc <- gtable_find(top_left, grob1) - expect_that(loc, equals(loc_df(t = 2, l = 2, b = 4, r = 4))) + expect_equal(loc, loc_df(t = 2, l = 2, b = 4, r = 4)) bottom_right <- layout bottom_right <- gtable_add_cols(bottom_right, cm) bottom_right <- gtable_add_rows(bottom_right, cm) loc <- gtable_find(bottom_right, grob1) - expect_that(loc, equals(loc_df(t = 1, l = 1, b = 3, r = 3))) + expect_equal(loc, loc_df(t = 1, l = 1, b = 3, r = 3)) }) @@ -90,10 +88,10 @@ test_that("n + 1 new rows/cols after spacing", { layout <- gtable_add_cols(layout, rep(cm, 3)) layout <- gtable_add_col_space(layout, cm) - expect_that(ncol(layout), equals(5)) + expect_equal(ncol(layout), 5) layout <- gtable_add_row_space(layout, cm) - expect_that(ncol(layout), equals(5)) + expect_equal(ncol(layout), 5) }) test_that("Spacing adds rows/cols in correct place", { @@ -104,11 +102,11 @@ test_that("Spacing adds rows/cols in correct place", { layout <- gtable_add_col_space(layout, null) layout <- gtable_add_row_space(layout, null) - expect_that(as.vector(layout$heights), equals(rep(1, 3))) - expect_that(sub('1', '', as.character(layout$heights)), equals(c("cm", "null", "cm"))) + expect_equal(as.vector(layout$heights), rep(1, 3)) + expect_equal(sub('1', '', as.character(layout$heights)), c("cm", "null", "cm")) - expect_that(as.vector(layout$widths), equals(rep(1, 3))) - expect_that(sub('1', '', as.character(layout$widths)), equals(c("cm", "null", "cm"))) + expect_equal(as.vector(layout$widths), rep(1, 3)) + expect_equal(sub('1', '', as.character(layout$widths)), c("cm", "null", "cm")) }) test_that("Negative positions place from end", { @@ -117,15 +115,15 @@ test_that("Negative positions place from end", { layout <- gtable_add_cols(layout, rep(cm, 3)) col_span <- gtable_add_grob(layout, grob1, t = 1, l = 1, r = -1) - expect_that( + expect_equal( gtable_find(col_span, grob1), - equals(loc_df(t = 1, l = 1, b = 1, r = 3)) + loc_df(t = 1, l = 1, b = 1, r = 3) ) row_span <- gtable_add_grob(layout, grob1, t = 1, l = 1, b = -1) - expect_that( + expect_equal( gtable_find(row_span, grob1), - equals(loc_df(t = 1, l = 1, b = 3, r = 1)) + loc_df(t = 1, l = 1, b = 3, r = 1) ) }) diff --git a/tests/testthat/test-new-data-frame.R b/tests/testthat/test-new-data-frame.R index 2b26271..4d4b884 100644 --- a/tests/testthat/test-new-data-frame.R +++ b/tests/testthat/test-new-data-frame.R @@ -1,9 +1,7 @@ -context("data.frame constructor") - test_that("new_data_frame returns a data.frame of expected dimensions", { df <- new_data_frame(list(x = 1:3, y = c("a", "b", "c"))) - expect_is(df, "data.frame") + expect_s3_class(df, "data.frame") expect_equal(nrow(df), 3) expect_equal(ncol(df), 2) expect_named(df, c("x", "y")) diff --git a/tests/testthat/test-subsetting.r b/tests/testthat/test-subsetting.R similarity index 99% rename from tests/testthat/test-subsetting.r rename to tests/testthat/test-subsetting.R index 012b6c8..da3f640 100644 --- a/tests/testthat/test-subsetting.r +++ b/tests/testthat/test-subsetting.R @@ -1,5 +1,3 @@ -context("Subsetting") - base <- gtable(unit(rep(1, 3), "null"), unit(rep(1, 3), "null")) rownames(base) <- LETTERS[1:3] colnames(base) <- letters[1:3] diff --git a/tests/testthat/test-trim.R b/tests/testthat/test-trim.R index 2fa5150..1e925bc 100644 --- a/tests/testthat/test-trim.R +++ b/tests/testthat/test-trim.R @@ -1,5 +1,3 @@ -context("trim") - gt_empty <- gtable( widths = unit(rep(1, 4), 'null'), heights = unit(rep(1, 4), 'null') diff --git a/tests/testthat/test-z-order.r b/tests/testthat/test-z-order.R similarity index 99% rename from tests/testthat/test-z-order.r rename to tests/testthat/test-z-order.R index 6476b10..aa246a1 100644 --- a/tests/testthat/test-z-order.r +++ b/tests/testthat/test-z-order.R @@ -1,5 +1,3 @@ -context("z-order") - # z tests for gtable_add_grob are in test-layout.r, mixed with other tests