From 595cd948153f0d8320a1adc560df25a3acbdca96 Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Tue, 29 Aug 2023 01:02:35 +0200 Subject: [PATCH 01/44] Fix #306 (#308) * Remove icons, note about SAS * Clean the test * Remove the templates * Fix #305 * Update GHA * Upgrade GHA The previous one was too tamed. * Update docs [no ci] * Bump version, update NEWS [no ci] * Update GH handle --- .Rbuildignore | 1 + .editorconfig | 16 +++++ .github/ISSUE_TEMPLATE.md | 25 -------- .github/PULL_REQUEST_TEMPLATE.md | 9 --- .github/workflows/R-CMD-check.yaml | 50 ++++++++++++++++ .github/workflows/check-standard.yaml | 86 --------------------------- .github/workflows/test-coverage.yaml | 60 ++++++++++--------- DESCRIPTION | 15 +++-- NEWS.md | 6 ++ R/rio.R | 3 +- README.Rmd | 6 +- README.md | 85 +++++++++++++------------- man/rio.Rd | 27 +++++++++ tests/testthat/test_format_sas.R | 2 +- 14 files changed, 184 insertions(+), 207 deletions(-) create mode 100644 .editorconfig delete mode 100644 .github/ISSUE_TEMPLATE.md delete mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/workflows/R-CMD-check.yaml delete mode 100644 .github/workflows/check-standard.yaml diff --git a/.Rbuildignore b/.Rbuildignore index c75babd..00d508b 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -37,3 +37,4 @@ ^.*\.Rproj$ ^\.Rproj\.user$ ^\.github$ +^\.editorconfig$ diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..c741847 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,16 @@ +root = true + + +[*] +charset = utf8 +end_of_line = lf +insert_final_newline = true +indent_style = space + + +[*.{r,R,rmd,Rmd,cpp}] +indent_size = 4 +trim_trailing_whitespace = true + +[Makefile] +indent_style = tab diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index f1f7d6f..0000000 --- a/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,25 +0,0 @@ -Please specify whether your issue is about: - - - [ ] a possible bug - - [ ] a question about package functionality - - [ ] a suggested code or documentation change, improvement to the code, or feature request - -If you are reporting (1) a bug or (2) a question about code, please supply: - - - [a fully reproducible example](http://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example) using a publicly available dataset (or provide your data) - - if an error is occurring, include the output of `traceback()` run immediately after the error occurs - - the output of `sessionInfo()` - -Put your code here: - -```R -## load package -library("rio") - -## code goes here - - -## session info for your system -sessionInfo() -``` - diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 1410b3e..0000000 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,9 +0,0 @@ -Please ensure the following before submitting a PR: - - - [ ] if suggesting code changes or improvements, [open an issue](https://github.com/leeper/rio/issues/new) first - - [ ] for all but trivial changes (e.g., typo fixes), add your name to [DESCRIPTION](https://github.com/leeper/rio/blob/master/DESCRIPTION) - - [ ] for all but trivial changes (e.g., typo fixes), documentation your change in [NEWS.md](https://github.com/leeper/rio/blob/master/NEWS.md) with a parenthetical reference to the issue number being addressed - - [ ] if changing documentation, edit files in `/R` not `/man` and run `devtools::document()` to update documentation - - [ ] add code or new test files to [`/tests`](https://github.com/leeper/rio/tree/master/tests/testthat) for any new functionality or bug fix - - [ ] make sure `R CMD check` runs without error before submitting the PR - diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml new file mode 100644 index 0000000..5f57071 --- /dev/null +++ b/.github/workflows/R-CMD-check.yaml @@ -0,0 +1,50 @@ +# 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] + pull_request: + branches: [main, master] + +name: R-CMD-check + +jobs: + R-CMD-check: + runs-on: ${{ matrix.config.os }} + + name: ${{ matrix.config.os }} (${{ matrix.config.r }}) + + strategy: + fail-fast: false + matrix: + config: + - {os: macos-latest, r: 'release'} + - {os: windows-latest, r: 'release'} + - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} + - {os: ubuntu-latest, r: 'release'} + - {os: ubuntu-latest, r: 'oldrel-1'} + - {os: windows-latest, r: '3.6'} + + env: + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + R_KEEP_PKG_SOURCE: yes + + steps: + - uses: actions/checkout@v3 + + - uses: r-lib/actions/setup-pandoc@v2 + + - 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@v2 + with: + extra-packages: any::rcmdcheck + needs: check + + - uses: r-lib/actions/check-r-package@v2 + with: + upload-snapshots: true diff --git a/.github/workflows/check-standard.yaml b/.github/workflows/check-standard.yaml deleted file mode 100644 index 243c87b..0000000 --- a/.github/workflows/check-standard.yaml +++ /dev/null @@ -1,86 +0,0 @@ -# For help debugging build failures open an issue on the RStudio community with the 'github-actions' tag. -# https://community.rstudio.com/new-topic?category=Package%20development&tags=github-actions -on: - push: - branches: - - main - - master - pull_request: - branches: - - main - - master - -name: R-CMD-check - -jobs: - R-CMD-check: - runs-on: ${{ matrix.config.os }} - - name: ${{ matrix.config.os }} (${{ matrix.config.r }}) - - strategy: - fail-fast: false - matrix: - config: - - {os: windows-latest, r: 'release'} - - {os: macOS-latest, r: 'release'} - - {os: ubuntu-20.04, r: 'release', rspm: "https://packagemanager.rstudio.com/cran/__linux__/focal/latest"} - - {os: ubuntu-20.04, r: 'devel', rspm: "https://packagemanager.rstudio.com/cran/__linux__/focal/latest"} - - env: - R_REMOTES_NO_ERRORS_FROM_WARNINGS: true - RSPM: ${{ matrix.config.rspm }} - GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} - - steps: - - uses: actions/checkout@v2 - - - uses: r-lib/actions/setup-r@v1 - with: - r-version: ${{ matrix.config.r }} - - - uses: r-lib/actions/setup-pandoc@v1 - - - name: Query dependencies - run: | - install.packages('remotes') - saveRDS(remotes::dev_package_deps(dependencies = TRUE), ".github/depends.Rds", version = 2) - writeLines(sprintf("R-%i.%i", getRversion()$major, getRversion()$minor), ".github/R-version") - shell: Rscript {0} - - - name: Cache R packages - if: runner.os != 'Windows' - uses: actions/cache@v2 - with: - path: ${{ env.R_LIBS_USER }} - key: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1-${{ hashFiles('.github/depends.Rds') }} - restore-keys: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1- - - - name: Install system dependencies - if: runner.os == 'Linux' - run: | - while read -r cmd - do - eval sudo $cmd - done < <(Rscript -e 'writeLines(remotes::system_requirements("ubuntu", "20.04"))') - - - name: Install dependencies - run: | - remotes::install_deps(dependencies = TRUE) - remotes::install_cran("rcmdcheck") - shell: Rscript {0} - - - name: Check - env: - _R_CHECK_CRAN_INCOMING_REMOTE_: false - run: | - options(crayon.enabled = TRUE) - rcmdcheck::rcmdcheck(args = c("--no-manual", "--as-cran"), error_on = "warning", check_dir = "check") - shell: Rscript {0} - - - name: Upload check results - if: failure() - uses: actions/upload-artifact@main - with: - name: ${{ runner.os }}-r${{ matrix.config.r }}-results - path: check diff --git a/.github/workflows/test-coverage.yaml b/.github/workflows/test-coverage.yaml index 5910c1a..2c5bb50 100644 --- a/.github/workflows/test-coverage.yaml +++ b/.github/workflows/test-coverage.yaml @@ -1,48 +1,50 @@ +# 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 + branches: [main, master] pull_request: - branches: - - main - - master + branches: [main, master] name: test-coverage jobs: test-coverage: - runs-on: macOS-latest + runs-on: ubuntu-latest env: 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-pandoc@v1 + - uses: r-lib/actions/setup-r-dependencies@v2 + with: + extra-packages: any::covr + needs: coverage - - name: Query dependencies + - name: Test coverage run: | - install.packages('remotes') - saveRDS(remotes::dev_package_deps(dependencies = TRUE), ".github/depends.Rds", version = 2) - writeLines(sprintf("R-%i.%i", getRversion()$major, getRversion()$minor), ".github/R-version") + covr::codecov( + quiet = FALSE, + clean = FALSE, + install_path = file.path(Sys.getenv("RUNNER_TEMP"), "package") + ) shell: Rscript {0} - - name: Cache R packages - uses: actions/cache@v2 - with: - path: ${{ env.R_LIBS_USER }} - key: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1-${{ hashFiles('.github/depends.Rds') }} - restore-keys: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1- - - - name: Install dependencies + - name: Show testthat output + if: always() run: | - install.packages(c("remotes")) - remotes::install_deps(dependencies = TRUE) - remotes::install_cran("covr") - shell: Rscript {0} + ## -------------------------------------------------------------------- + find ${{ runner.temp }}/package -name 'testthat.Rout*' -exec cat '{}' \; || true + shell: bash - - name: Test coverage - run: covr::codecov() - shell: Rscript {0} + - 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 fb9b8ca..6257b22 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,14 +1,13 @@ Package: rio Type: Package Title: A Swiss-Army Knife for Data I/O -Version: 0.5.28 -Date: 2021-10-26 +Version: 0.5.29 Authors@R: c(person("Jason", "Becker", role = "ctb", email = "jason@jbecker.co"), - person("Chung-hong", "Chan", role = "aut", email = "chainsawtiney@gmail.com", + person("Chung-hong", "Chan", role = c("aut", "cre"), email = "chainsawtiney@gmail.com", comment = c(ORCID = "0000-0002-6232-7530")), person("Geoffrey CH", "Chan", role = "ctb", email = "gefchchan@gmail.com"), person("Thomas J.", "Leeper", - role = c("aut", "cre"), + role = "aut", email = "thosjleeper@gmail.com", comment = c(ORCID = "0000-0003-4097-6326")), person("Christopher", "Gandrud", role = "ctb"), @@ -35,10 +34,10 @@ Description: Streamlined data import and export by making assumptions that directly without explicit decompression, and fast import packages are used where appropriate. An additional convenience function, 'convert()', provides a simple method for converting between file types. -URL: https://github.com/leeper/rio -BugReports: https://github.com/leeper/rio/issues +URL: https://github.com/chainsawriot/rio +BugReports: https://github.com/chainsawriot/rio/issues Depends: - R (>= 2.15.0) + R (>= 3.6) Imports: tools, stats, @@ -72,4 +71,4 @@ Suggests: License: GPL-2 VignetteBuilder: knitr Encoding: UTF-8 -RoxygenNote: 7.1.1 +RoxygenNote: 7.2.3 diff --git a/NEWS.md b/NEWS.md index b0a543d..d5b7b71 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,9 @@ +# rio 0.5.29 + +* Maintenance release: new maintainer +* Mark `.sas7bdat` as deprecated +* Change the minimum R version to 3.6 + # rio 0.5.28 * Various fixes to tests, examples, and documentation for CRAN. diff --git a/R/rio.R b/R/rio.R index 6ab7e2f..4321f73 100644 --- a/R/rio.R +++ b/R/rio.R @@ -26,4 +26,5 @@ #' @references #' \href{https://github.com/Stan125/GREA}{GREA} provides an RStudio add-in to import data using rio. #' @seealso \code{\link{import}}, \code{\link{import_list}}, \code{\link{export}}, \code{\link{export_list}}, \code{\link{convert}}, \code{\link{install_formats}} -NULL +"_PACKAGE" + diff --git a/README.Rmd b/README.Rmd index 86632a5..27c3448 100644 --- a/README.Rmd +++ b/README.Rmd @@ -7,9 +7,7 @@ output: github_document [![CRAN Version](https://www.r-pkg.org/badges/version/rio)](https://cran.r-project.org/package=rio) ![Downloads](https://cranlogs.r-pkg.org/badges/rio) -[![Travis-CI Build Status](https://travis-ci.org/leeper/rio.png?branch=master)](https://travis-ci.org/leeper/rio) -[![Appveyor Build status](https://ci.appveyor.com/api/projects/status/40ua5l06jw0gjyjb?svg=true)](https://ci.appveyor.com/project/leeper/rio) -[![codecov.io](https://codecov.io/github/leeper/rio/coverage.svg?branch=master)](https://codecov.io/github/leeper/rio?branch=master) +[![codecov.io](https://codecov.io/github/chainsawriot/rio/coverage.svg?branch=main)](https://codecov.io/github/chainsawriot/rio/coverage.svg?branch=main) ## Overview @@ -138,7 +136,7 @@ The full list of supported formats is below: | Pipe-separated data | .psv | [**data.table**](https://cran.r-project.org/package=data.table) | [**data.table**](https://cran.r-project.org/package=data.table) | Yes | | Tab-separated data | .tsv | [**data.table**](https://cran.r-project.org/package=data.table) | [**data.table**](https://cran.r-project.org/package=data.table) | Yes | | CSVY (CSV + YAML metadata header) | .csvy | [**data.table**](https://cran.r-project.org/package=data.table) | [**data.table**](https://cran.r-project.org/package=data.table) | Yes | -| SAS | .sas7bdat | [**haven**](https://cran.r-project.org/package=haven) | [**haven**](https://cran.r-project.org/package=haven) | Yes | +| SAS | .sas7bdat | [**haven**](https://cran.r-project.org/package=haven) | [**haven**](https://cran.r-project.org/package=haven) | Yes (but [deprecated](https://github.com/tidyverse/haven/issues/224)) | | SPSS | .sav | [**haven**](https://cran.r-project.org/package=haven) | [**haven**](https://cran.r-project.org/package=haven) | Yes | | SPSS (compressed) | .zsav | [**haven**](https://cran.r-project.org/package=haven) | [**haven**](https://cran.r-project.org/package=haven) | Yes | | Stata | .dta | [**haven**](https://cran.r-project.org/package=haven) | [**haven**](https://cran.r-project.org/package=haven) | Yes | diff --git a/README.md b/README.md index 48d7084..e177f57 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,8 @@ [![CRAN Version](https://www.r-pkg.org/badges/version/rio)](https://cran.r-project.org/package=rio) -![Downloads](https://cranlogs.r-pkg.org/badges/rio) [![Travis-CI Build -Status](https://travis-ci.org/leeper/rio.png?branch=master)](https://travis-ci.org/leeper/rio) -[![Appveyor Build -status](https://ci.appveyor.com/api/projects/status/40ua5l06jw0gjyjb?svg=true)](https://ci.appveyor.com/project/leeper/rio) -[![codecov.io](https://codecov.io/github/leeper/rio/coverage.svg?branch=master)](https://codecov.io/github/leeper/rio?branch=master) +![Downloads](https://cranlogs.r-pkg.org/badges/rio) + ## Overview @@ -184,45 +181,45 @@ install_formats() The full list of supported formats is below: -| Format | Typical Extension | Import Package | Export Package | Installed by Default | -| ----------------------------------------------------- | ----------------------- | --------------------------------------------------------------- | --------------------------------------------------------------- | -------------------- | -| Comma-separated data | .csv | [**data.table**](https://cran.r-project.org/package=data.table) | [**data.table**](https://cran.r-project.org/package=data.table) | Yes | -| Pipe-separated data | .psv | [**data.table**](https://cran.r-project.org/package=data.table) | [**data.table**](https://cran.r-project.org/package=data.table) | Yes | -| Tab-separated data | .tsv | [**data.table**](https://cran.r-project.org/package=data.table) | [**data.table**](https://cran.r-project.org/package=data.table) | Yes | -| CSVY (CSV + YAML metadata header) | .csvy | [**data.table**](https://cran.r-project.org/package=data.table) | [**data.table**](https://cran.r-project.org/package=data.table) | Yes | -| SAS | .sas7bdat | [**haven**](https://cran.r-project.org/package=haven) | [**haven**](https://cran.r-project.org/package=haven) | Yes | -| SPSS | .sav | [**haven**](https://cran.r-project.org/package=haven) | [**haven**](https://cran.r-project.org/package=haven) | Yes | -| SPSS (compressed) | .zsav | [**haven**](https://cran.r-project.org/package=haven) | [**haven**](https://cran.r-project.org/package=haven) | Yes | -| Stata | .dta | [**haven**](https://cran.r-project.org/package=haven) | [**haven**](https://cran.r-project.org/package=haven) | Yes | -| SAS XPORT | .xpt | [**haven**](https://cran.r-project.org/package=haven) | [**haven**](https://cran.r-project.org/package=haven) | Yes | -| SPSS Portable | .por | [**haven**](https://cran.r-project.org/package=haven) | | Yes | -| Excel | .xls | [**readxl**](https://cran.r-project.org/package=readxl) | | Yes | -| Excel | .xlsx | [**readxl**](https://cran.r-project.org/package=readxl) | [**openxlsx**](https://cran.r-project.org/package=openxlsx) | Yes | -| R syntax | .R | **base** | **base** | Yes | -| Saved R objects | .RData, .rda | **base** | **base** | Yes | -| Serialized R objects | .rds | **base** | **base** | Yes | -| Epiinfo | .rec | [**foreign**](https://cran.r-project.org/package=foreign) | | Yes | -| Minitab | .mtp | [**foreign**](https://cran.r-project.org/package=foreign) | | Yes | -| Systat | .syd | [**foreign**](https://cran.r-project.org/package=foreign) | | Yes | -| “XBASE” database files | .dbf | [**foreign**](https://cran.r-project.org/package=foreign) | [**foreign**](https://cran.r-project.org/package=foreign) | Yes | -| Weka Attribute-Relation File Format | .arff | [**foreign**](https://cran.r-project.org/package=foreign) | [**foreign**](https://cran.r-project.org/package=foreign) | Yes | -| Data Interchange Format | .dif | **utils** | | Yes | -| Fortran data | no recognized extension | **utils** | | Yes | -| Fixed-width format data | .fwf | **utils** | **utils** | Yes | -| gzip comma-separated data | .csv.gz | **utils** | **utils** | Yes | -| Apache Arrow (Parquet) | .parquet | [**arrow**](https://cran.r-project.org/package=arrow) | [**arrow**](https://cran.r-project.org/package=arrow) | No | -| EViews | .wf1 | [**hexView**](https://cran.r-project.org/package=hexView) | | No | -| Feather R/Python interchange format | .feather | [**feather**](https://cran.r-project.org/package=feather) | [**feather**](https://cran.r-project.org/package=feather) | No | -| Fast Storage | .fst | [**fst**](https://cran.r-project.org/package=fst) | [**fst**](https://cran.r-project.org/package=fst) | No | -| JSON | .json | [**jsonlite**](https://cran.r-project.org/package=jsonlite) | [**jsonlite**](https://cran.r-project.org/package=jsonlite) | No | -| Matlab | .mat | [**rmatio**](https://cran.r-project.org/package=rmatio) | [**rmatio**](https://cran.r-project.org/package=rmatio) | No | -| OpenDocument Spreadsheet | .ods | [**readODS**](https://cran.r-project.org/package=readODS) | [**readODS**](https://cran.r-project.org/package=readODS) | No | -| HTML Tables | .html | [**xml2**](https://cran.r-project.org/package=xml2) | [**xml2**](https://cran.r-project.org/package=xml2) | No | -| Shallow XML documents | .xml | [**xml2**](https://cran.r-project.org/package=xml2) | [**xml2**](https://cran.r-project.org/package=xml2) | No | -| YAML | .yml | [**yaml**](https://cran.r-project.org/package=yaml) | [**yaml**](https://cran.r-project.org/package=yaml) | No | -| Clipboard | default is tsv | [**clipr**](https://cran.r-project.org/package=clipr) | [**clipr**](https://cran.r-project.org/package=clipr) | No | -| [Google Sheets](https://www.google.com/sheets/about/) | as Comma-separated data | | | | -| Graphpad Prism | .pzfx | [**pzfx**](https://cran.r-project.org/package=pzfx) | [**pzfx**](https://cran.r-project.org/package=pzfx) | No | +| Format | Typical Extension | Import Package | Export Package | Installed by Default | +| ----------------------------------------------------- | ----------------------- | --------------------------------------------------------------- | --------------------------------------------------------------- | --------------------------------------------------------------------- | +| Comma-separated data | .csv | [**data.table**](https://cran.r-project.org/package=data.table) | [**data.table**](https://cran.r-project.org/package=data.table) | Yes | +| Pipe-separated data | .psv | [**data.table**](https://cran.r-project.org/package=data.table) | [**data.table**](https://cran.r-project.org/package=data.table) | Yes | +| Tab-separated data | .tsv | [**data.table**](https://cran.r-project.org/package=data.table) | [**data.table**](https://cran.r-project.org/package=data.table) | Yes | +| CSVY (CSV + YAML metadata header) | .csvy | [**data.table**](https://cran.r-project.org/package=data.table) | [**data.table**](https://cran.r-project.org/package=data.table) | Yes | +| SAS | .sas7bdat | [**haven**](https://cran.r-project.org/package=haven) | [**haven**](https://cran.r-project.org/package=haven) | Yes (but [deprecated](https://github.com/tidyverse/haven/issues/224)) | +| SPSS | .sav | [**haven**](https://cran.r-project.org/package=haven) | [**haven**](https://cran.r-project.org/package=haven) | Yes | +| SPSS (compressed) | .zsav | [**haven**](https://cran.r-project.org/package=haven) | [**haven**](https://cran.r-project.org/package=haven) | Yes | +| Stata | .dta | [**haven**](https://cran.r-project.org/package=haven) | [**haven**](https://cran.r-project.org/package=haven) | Yes | +| SAS XPORT | .xpt | [**haven**](https://cran.r-project.org/package=haven) | [**haven**](https://cran.r-project.org/package=haven) | Yes | +| SPSS Portable | .por | [**haven**](https://cran.r-project.org/package=haven) | | Yes | +| Excel | .xls | [**readxl**](https://cran.r-project.org/package=readxl) | | Yes | +| Excel | .xlsx | [**readxl**](https://cran.r-project.org/package=readxl) | [**openxlsx**](https://cran.r-project.org/package=openxlsx) | Yes | +| R syntax | .R | **base** | **base** | Yes | +| Saved R objects | .RData, .rda | **base** | **base** | Yes | +| Serialized R objects | .rds | **base** | **base** | Yes | +| Epiinfo | .rec | [**foreign**](https://cran.r-project.org/package=foreign) | | Yes | +| Minitab | .mtp | [**foreign**](https://cran.r-project.org/package=foreign) | | Yes | +| Systat | .syd | [**foreign**](https://cran.r-project.org/package=foreign) | | Yes | +| “XBASE” database files | .dbf | [**foreign**](https://cran.r-project.org/package=foreign) | [**foreign**](https://cran.r-project.org/package=foreign) | Yes | +| Weka Attribute-Relation File Format | .arff | [**foreign**](https://cran.r-project.org/package=foreign) | [**foreign**](https://cran.r-project.org/package=foreign) | Yes | +| Data Interchange Format | .dif | **utils** | | Yes | +| Fortran data | no recognized extension | **utils** | | Yes | +| Fixed-width format data | .fwf | **utils** | **utils** | Yes | +| gzip comma-separated data | .csv.gz | **utils** | **utils** | Yes | +| Apache Arrow (Parquet) | .parquet | [**arrow**](https://cran.r-project.org/package=arrow) | [**arrow**](https://cran.r-project.org/package=arrow) | No | +| EViews | .wf1 | [**hexView**](https://cran.r-project.org/package=hexView) | | No | +| Feather R/Python interchange format | .feather | [**feather**](https://cran.r-project.org/package=feather) | [**feather**](https://cran.r-project.org/package=feather) | No | +| Fast Storage | .fst | [**fst**](https://cran.r-project.org/package=fst) | [**fst**](https://cran.r-project.org/package=fst) | No | +| JSON | .json | [**jsonlite**](https://cran.r-project.org/package=jsonlite) | [**jsonlite**](https://cran.r-project.org/package=jsonlite) | No | +| Matlab | .mat | [**rmatio**](https://cran.r-project.org/package=rmatio) | [**rmatio**](https://cran.r-project.org/package=rmatio) | No | +| OpenDocument Spreadsheet | .ods | [**readODS**](https://cran.r-project.org/package=readODS) | [**readODS**](https://cran.r-project.org/package=readODS) | No | +| HTML Tables | .html | [**xml2**](https://cran.r-project.org/package=xml2) | [**xml2**](https://cran.r-project.org/package=xml2) | No | +| Shallow XML documents | .xml | [**xml2**](https://cran.r-project.org/package=xml2) | [**xml2**](https://cran.r-project.org/package=xml2) | No | +| YAML | .yml | [**yaml**](https://cran.r-project.org/package=yaml) | [**yaml**](https://cran.r-project.org/package=yaml) | No | +| Clipboard | default is tsv | [**clipr**](https://cran.r-project.org/package=clipr) | [**clipr**](https://cran.r-project.org/package=clipr) | No | +| [Google Sheets](https://www.google.com/sheets/about/) | as Comma-separated data | | | | +| Graphpad Prism | .pzfx | [**pzfx**](https://cran.r-project.org/package=pzfx) | [**pzfx**](https://cran.r-project.org/package=pzfx) | No | Additionally, any format that is not supported by **rio** but that has a known R implementation will produce an informative error message diff --git a/man/rio.Rd b/man/rio.Rd index fd211a7..58c3175 100644 --- a/man/rio.Rd +++ b/man/rio.Rd @@ -3,6 +3,7 @@ \docType{package} \name{rio} \alias{rio} +\alias{rio-package} \title{A Swiss-Army Knife for Data I/O} \description{ The aim of rio is to make data file input and output as easy as possible. \code{\link{export}} and \code{\link{import}} serve as a Swiss-army knife for painless data I/O for data from almost any file format by inferring the data structure from the file extension, natively reading web-based data sources, setting reasonable defaults for import and export, and relying on efficient data import and export packages. An additional convenience function, \code{\link{convert}}, provides a simple method for converting between file types. @@ -34,3 +35,29 @@ unlink(c(csv_file, rds_file, sav_file, dta_file)) \seealso{ \code{\link{import}}, \code{\link{import_list}}, \code{\link{export}}, \code{\link{export_list}}, \code{\link{convert}}, \code{\link{install_formats}} } +\author{ +\strong{Maintainer}: Chung-hong Chan \email{chainsawtiney@gmail.com} (\href{https://orcid.org/0000-0002-6232-7530}{ORCID}) + +Authors: +\itemize{ + \item Thomas J. Leeper \email{thosjleeper@gmail.com} (\href{https://orcid.org/0000-0003-4097-6326}{ORCID}) +} + +Other contributors: +\itemize{ + \item Jason Becker \email{jason@jbecker.co} [contributor] + \item Geoffrey CH Chan \email{gefchchan@gmail.com} [contributor] + \item Christopher Gandrud [contributor] + \item Andrew MacDonald [contributor] + \item Ista Zahn [contributor] + \item Stanislaus Stadlmann [contributor] + \item Ruaridh Williamson \email{ruaridh.williamson@gmail.com} [contributor] + \item Patrick Kennedy [contributor] + \item Ryan Price \email{ryapric@gmail.com} [contributor] + \item Trevor L Davis \email{trevor.l.davis@gmail.com} [contributor] + \item Nathan Day \email{nathancday@gmail.com} [contributor] + \item Bill Denney \email{wdenney@humanpredictions.com} (\href{https://orcid.org/0000-0002-5759-428X}{ORCID}) [contributor] + \item Alex Bokov \email{alex.bokov@gmail.com} (\href{https://orcid.org/0000-0002-0511-9815}{ORCID}) [contributor] +} + +} diff --git a/tests/testthat/test_format_sas.R b/tests/testthat/test_format_sas.R index e61e200..5068d1a 100644 --- a/tests/testthat/test_format_sas.R +++ b/tests/testthat/test_format_sas.R @@ -11,7 +11,7 @@ test_that("Import from SAS (.xpt)", { }) test_that("Export SAS (.sas7bdat)", { - expect_true(export(mtcars, "mtcars.sas7bdat") %in% dir()) + expect_true(suppressWarnings(export(mtcars, "mtcars.sas7bdat")) %in% dir()) }) unlink("mtcars.sas7bdat") From e37c6422a64ad35f44e5ad98eb8b87f3d1e6dc92 Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Tue, 29 Aug 2023 01:27:43 +0200 Subject: [PATCH 02/44] Fix #282 [no ci] --- R/import.R | 12 ++++++------ man/import.Rd | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/R/import.R b/R/import.R index 67d209f..9a7c04a 100644 --- a/R/import.R +++ b/R/import.R @@ -45,13 +45,13 @@ #' \item Single-table HTML documents (.html), using \code{\link[xml2]{read_html}}. The data structure will only be read correctly if the HTML file can be converted to a list via \code{\link[xml2]{as_list}}. #' \item Shallow XML documents (.xml), using \code{\link[xml2]{read_xml}}. The data structure will only be read correctly if the XML file can be converted to a list via \code{\link[xml2]{as_list}}. #' \item YAML (.yml), using \code{\link[yaml]{yaml.load}} -#' \item Clipboard import (on Windows and Mac OS), using \code{\link[utils]{read.table}} with \code{row.names = FALSE} +#' \item Clipboard import, using \code{\link[utils]{read.table}} with \code{row.names = FALSE} #' \item Google Sheets, as Comma-separated data (.csv) #' \item GraphPad Prism (.pzfx) using \code{\link[pzfx]{read_pzfx}} #' } #' #' \code{import} attempts to standardize the return value from the various import functions to the extent possible, thus providing a uniform data structure regardless of what import package or function is used. It achieves this by storing any optional variable-related attributes at the variable level (i.e., an attribute for \code{mtcars$mpg} is stored in \code{attributes(mtcars$mpg)} rather than \code{attributes(mtcars)}). If you would prefer these attributes to be stored at the data.frame-level (i.e., in \code{attributes(mtcars)}), see \code{\link{gather_attrs}}. -#' +#' #' After importing metadata-rich file formats (e.g., from Stata or SPSS), it may be helpful to recode labelled variables to character or factor using \code{\link{characterize}} or \code{\link{factorize}} respectively. #' #' @note For csv and txt files with row names exported from \code{\link{export}}, it may be helpful to specify \code{row.names} as the column of the table which contain row names. See example below. @@ -76,7 +76,7 @@ #' #' # set class for the response data.frame as "tbl_df" (from dplyr) #' stopifnot(inherits(import(csv_file, setclass = "tbl_df"), "tbl_df")) -#' +#' #' # non-data frame formats supported for RDS, Rdata, and JSON #' export(list(mtcars, iris), rds_file <- tempfile(fileext = ".rds")) #' li <- import(rds_file) @@ -126,16 +126,16 @@ import <- function(file, format, setclass, which, ...) { } else { fmt <- get_type(format) } - + args_list <- list(...) - + class(file) <- c(paste0("rio_", fmt), class(file)) if (missing(which)) { x <- .import(file = file, ...) } else { x <- .import(file = file, which = which, ...) } - + # if R serialized object, just return it without setting object class if (inherits(file, c("rio_rdata", "rio_rds", "rio_json"))) { return(x) diff --git a/man/import.Rd b/man/import.Rd index 51fbdc2..368f897 100644 --- a/man/import.Rd +++ b/man/import.Rd @@ -62,7 +62,7 @@ This function imports a data frame or matrix from a data file with the file form \item Single-table HTML documents (.html), using \code{\link[xml2]{read_html}}. The data structure will only be read correctly if the HTML file can be converted to a list via \code{\link[xml2]{as_list}}. \item Shallow XML documents (.xml), using \code{\link[xml2]{read_xml}}. The data structure will only be read correctly if the XML file can be converted to a list via \code{\link[xml2]{as_list}}. \item YAML (.yml), using \code{\link[yaml]{yaml.load}} - \item Clipboard import (on Windows and Mac OS), using \code{\link[utils]{read.table}} with \code{row.names = FALSE} + \item Clipboard import, using \code{\link[utils]{read.table}} with \code{row.names = FALSE} \item Google Sheets, as Comma-separated data (.csv) \item GraphPad Prism (.pzfx) using \code{\link[pzfx]{read_pzfx}} } From 327a722d1d5e80951f5d0e46af78c9f52e330a81 Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Tue, 29 Aug 2023 09:50:32 +0200 Subject: [PATCH 03/44] Rearrange README [no ci] --- README.Rmd | 163 ++++++++++++++++---------------- README.md | 267 ++++++++++++++++++++++++++++------------------------- 2 files changed, 227 insertions(+), 203 deletions(-) diff --git a/README.Rmd b/README.Rmd index 27c3448..21b5205 100644 --- a/README.Rmd +++ b/README.Rmd @@ -7,7 +7,6 @@ output: github_document [![CRAN Version](https://www.r-pkg.org/badges/version/rio)](https://cran.r-project.org/package=rio) ![Downloads](https://cranlogs.r-pkg.org/badges/rio) -[![codecov.io](https://codecov.io/github/chainsawriot/rio/coverage.svg?branch=main)](https://codecov.io/github/chainsawriot/rio/coverage.svg?branch=main) ## Overview @@ -17,7 +16,7 @@ The aim of **rio** is to make data file I/O in R as easy as possible by implemen - `import()` provides a painless data import experience by automatically choosing the appropriate import/read function based on file extension (or a specified `format` argument) - `import_list()` imports a list of data frames from a multi-object file (Excel workbook, .Rdata files, zip directory, or HTML file) - `export()` provides the same painless file recognition for data export/write functionality - - `convert()` wraps `import()` and `export()` to allow the user to easily convert between file formats (thus providing a FOSS replacement for programs like [Stat/Transfer](https://stattransfer.com/) or [Sledgehammer](https://www.mtna.us/#/products/sledgehammer)). Relatedly, [Luca Braglia](https://lbraglia.github.io/) has created a Shiny app called [rioweb](https://github.com/lbraglia/rioweb) that provides access to the file conversion features of rio. [GREA](https://github.com/Stan125/GREA/) is an RStudio add-in that provides an interactive interface for reading in data using rio. + - `convert()` wraps `import()` and `export()` to allow the user to easily convert between file formats (thus providing a FOSS replacement for programs like [Stat/Transfer](https://stattransfer.com/) or [Sledgehammer](https://www.mtna.us/#/products/sledgehammer)). ## Installation @@ -41,13 +40,26 @@ remotes::install_github("leeper/rio") Because **rio** is meant to streamline data I/O, the package is extremely easy to use. Here are some examples of reading, writing, and converting data files. +### Import + +Importing data is handled with one function, `import()`: + +```{r import1} +library("rio") +import("starwars.xlsx") +``` + +```{r import2} +import("starwars.csv") +``` + +Note: Because of inconsistencies across underlying packages, the data.frame returned by `import` might vary slightly (in variable classes and attributes) depending on file type. + ### Export Exporting data is handled with one function, `export()`: ```{r exports} -library("rio") - export(mtcars, "mtcars.csv") # comma-separated values export(mtcars, "mtcars.rds") # R serialized export(mtcars, "mtcars.sav") # SPSS @@ -59,67 +71,12 @@ A particularly useful feature of rio is the ability to import from and export to export(mtcars, "mtcars.tsv.zip") ``` -As of rio v0.5.0, `export()` can also write multiple data frames to respective sheets of an Excel workbook or an HTML file: +`export()` can also write multiple data frames to respective sheets of an Excel workbook or an HTML file: ```{r export_a_list} export(list(mtcars = mtcars, iris = iris), file = "mtcars.xlsx") ``` -### Import - -Importing data is handled with one function, `import()`: - -```{r import} -x <- import("mtcars.csv") -y <- import("mtcars.rds") -z <- import("mtcars.sav") - -# confirm data match -all.equal(x, y, check.attributes = FALSE) -all.equal(x, z, check.attributes = FALSE) -``` - -Note: Because of inconsistencies across underlying packages, the data.frame returned by `import` might vary slightly (in variable classes and attributes) depending on file type. - -In rio v0.5.0, a new list-based import function was added. This allows users to import a list of data frames from a multi-object file (such as an Excel workbook, .Rdata file, zip directory, or HTML file): - -```{r import_list} -str(m <- import_list("mtcars.xlsx")) -``` - -And for rio v0.6.0, a new list-based export function was added. This makes it easy to export a list of (possibly named) data frames to multiple files: - -```{r export_list} -export_list(m, "%s.tsv") -c("mtcars.tsv", "iris.tsv") %in% dir() -``` - - -### Convert - -The `convert()` function links `import()` and `export()` by constructing a dataframe from the imported file and immediately writing it back to disk. `convert()` invisibly returns the file name of the exported file, so that it can be used to programmatically access the new file. - -```{r convert} -convert("mtcars.sav", "mtcars.dta") -``` - -It is also possible to use **rio** on the command-line by calling `Rscript` with the `-e` (expression) argument. For example, to convert a file from Stata (.dta) to comma-separated values (.csv), simply do the following: - -``` -Rscript -e "rio::convert('iris.dta', 'iris.csv')" -``` - -```{r cleanup, echo=FALSE, results="hide"} -unlink("mtcars.csv") -unlink("mtcars.dta") -unlink("mtcars.sav") -unlink("mtcars.rds") -unlink("mtcars.xlsx") -unlink("mtcars.tsv.zip") -unlink("mtcars.tsv") -unlink("iris.tsv") -``` - ## Supported file formats **rio** supports a wide range of file formats. To keep the package slim, all non-essential formats are supported via "Suggests" packages, which are not installed (or loaded) by default. To ensure rio is fully functional, install these packages the first time you use **rio** via: @@ -136,7 +93,7 @@ The full list of supported formats is below: | Pipe-separated data | .psv | [**data.table**](https://cran.r-project.org/package=data.table) | [**data.table**](https://cran.r-project.org/package=data.table) | Yes | | Tab-separated data | .tsv | [**data.table**](https://cran.r-project.org/package=data.table) | [**data.table**](https://cran.r-project.org/package=data.table) | Yes | | CSVY (CSV + YAML metadata header) | .csvy | [**data.table**](https://cran.r-project.org/package=data.table) | [**data.table**](https://cran.r-project.org/package=data.table) | Yes | -| SAS | .sas7bdat | [**haven**](https://cran.r-project.org/package=haven) | [**haven**](https://cran.r-project.org/package=haven) | Yes (but [deprecated](https://github.com/tidyverse/haven/issues/224)) | +| SAS | .sas7bdat | [**haven**](https://cran.r-project.org/package=haven) | [**haven**](https://cran.r-project.org/package=haven) (but [deprecated](https://github.com/tidyverse/haven/issues/224)) | Yes | | SPSS | .sav | [**haven**](https://cran.r-project.org/package=haven) | [**haven**](https://cran.r-project.org/package=haven) | Yes | | SPSS (compressed) | .zsav | [**haven**](https://cran.r-project.org/package=haven) | [**haven**](https://cran.r-project.org/package=haven) | Yes | | Stata | .dta | [**haven**](https://cran.r-project.org/package=haven) | [**haven**](https://cran.r-project.org/package=haven) | Yes | @@ -172,35 +129,72 @@ The full list of supported formats is below: Additionally, any format that is not supported by **rio** but that has a known R implementation will produce an informative error message pointing to a package and import or export function. Unrecognized formats will yield a simple "Unrecognized file format" error. +## Other functions + +### Convert + +The `convert()` function links `import()` and `export()` by constructing a dataframe from the imported file and immediately writing it back to disk. `convert()` invisibly returns the file name of the exported file, so that it can be used to programmatically access the new file. + +```{r convert} +convert("mtcars.sav", "mtcars.dta") +``` + +It is also possible to use **rio** on the command-line by calling `Rscript` with the `-e` (expression) argument. For example, to convert a file from Stata (.dta) to comma-separated values (.csv), simply do the following: + +``` +Rscript -e "rio::convert('iris.dta', 'iris.csv')" +``` + +### *_list + +`import_list()` allows users to import a list of data frames from a multi-object file (such as an Excel workbook, .Rdata file, zip directory, or HTML file): + +```{r import_list} +str(m <- import_list("mtcars.xlsx")) +``` + +`export_list()` makes it easy to export a list of (possibly named) data frames to multiple files: + +```{r export_list} +export_list(m, "%s.tsv") +c("mtcars.tsv", "iris.tsv") %in% dir() +``` + +```{r cleanup, echo=FALSE, results="hide"} +unlink("mtcars.csv") +unlink("mtcars.dta") +unlink("mtcars.sav") +unlink("mtcars.rds") +unlink("mtcars.xlsx") +unlink("mtcars.tsv.zip") +unlink("mtcars.tsv") +unlink("iris.tsv") +``` + ## Package Philosophy The core advantage of **rio** is that it makes assumptions that the user is probably willing to make. Eight of these are important: - 1. **rio** uses the file extension of a file name to determine what kind of file it is. This is the same logic used by Windows OS, for example, in determining what application is associated with a given file type. By removing the need to manually match a file type (which a beginner may not recognize) to a particular import or export function, **rio** allows almost all common data formats to be read with the same function. And if a file extension is incorrect, users can force a particular import method by specifying the `format` argument. Other packages do this as well, but **rio** aims to be more complete and more consistent than each: - - - [**reader**](https://cran.r-project.org/package=reader) handles certain text formats and R binary files - - [**io**](https://cran.r-project.org/package=io) offers a set of custom formats - - [**ImportExport**](https://cran.r-project.org/package=ImportExport) focuses on select binary formats (Excel, SPSS, and Access files) and provides a Shiny interface. - - [**SchemaOnRead**](https://cran.r-project.org/package=SchemaOnRead) iterates through a large number of possible import methods until one works successfully - + 1. **rio** uses the file extension of a file name to determine what kind of file it is. This is the same logic used by Windows OS, for example, in determining what application is associated with a given file type. By removing the need to manually match a file type (which a beginner may not recognize) to a particular import or export function, **rio** allows almost all common data formats to be read with the same function. And if a file extension is incorrect, users can force a particular import method by specifying the `format` argument. + 2. **rio** uses `data.table::fread()` for text-delimited files to automatically determine the file format regardless of the extension. So, a CSV that is actually tab-separated will still be correctly imported. It's also crazy fast. - + 3. **rio**, wherever possible, does not import character strings as factors. - + 4. **rio** supports web-based imports natively, including from SSL (HTTPS) URLs, from shortened URLs, from URLs that lack proper extensions, and from (public) Google Documents Spreadsheets. - + 5. **rio** imports from from single-file .zip and .tar archives automatically, without the need to explicitly decompress them. Export to compressed directories is also supported. - + 6. **rio** wraps a variety of faster, more stream-lined I/O packages than those provided by base R or the **foreign** package. It uses [**data.table**](https://cran.r-project.org/package=data.table) for delimited formats, [**haven**](https://cran.r-project.org/package=haven) for SAS, Stata, and SPSS files, smarter and faster fixed-width file import and export routines, and [**readxl**](https://cran.r-project.org/package=readxl) and [**openxlsx**](https://cran.r-project.org/package=openxlsx) for reading and writing Excel workbooks. - + 7. **rio** stores metadata from rich file formats (SPSS, Stata, etc.) in variable-level attributes in a consistent form regardless of file type or underlying import function. These attributes are identified as: - + - `label`: a description of variable - `labels`: a vector mapping numeric values to character strings those values represent - `format`: a character string describing the variable storage type in the original file - + The `gather_attrs()` function makes it easy to move variable-level attributes to the data frame level (and `spread_attrs()` reverses that gathering process). These can be useful, especially, during file conversion to more easily modify attributes that are handled differently across file formats. As an example, the following idiom can be used to trim SPSS value labels to the 32-character maximum allowed by Stata: - + ```R dat <- gather_attrs(rio::import("data.sav")) attr(dat, "labels") <- lapply(attributes(dat)$labels, function(x) { @@ -211,8 +205,21 @@ The core advantage of **rio** is that it makes assumptions that the user is prob }) export(spread_attrs(dat), "data.dta") ``` - + In addition, two functions (added in v0.5.5) provide easy ways to create character and factor variables from these "labels" attributes. `characterize()` converts a single variable or all variables in a data frame that have "labels" attributes into character vectors based on the mapping of values to value labels. `factorize()` does the same but returns factor variables. This can be especially helpful for converting these rich file formats into open formats (e.g., `export(characterize(import("file.dta")), "file.csv")`. - + 8. **rio** imports and exports files based on an internal S3 class infrastructure. This means that other packages can contain extensions to **rio** by registering S3 methods. These methods should take the form `.import.rio_X()` and `.export.rio_X()`, where `X` is the file extension of a file type. An example is provided in the [rio.db package](https://github.com/leeper/rio.db). +## Other projects + +### GUIs + +* [**rioweb**](https://github.com/lbraglia/rioweb) that provides access to the file conversion features of rio. +* [**GREA**](https://github.com/Stan125/GREA/) is an RStudio add-in that provides an interactive interface for reading in data using rio. + +### Similar packages + +* [**reader**](https://cran.r-project.org/package=reader) handles certain text formats and R binary files +* [**io**](https://cran.r-project.org/package=io) offers a set of custom formats +* [**ImportExport**](https://cran.r-project.org/package=ImportExport) focuses on select binary formats (Excel, SPSS, and Access files) and provides a Shiny interface. +* [**SchemaOnRead**](https://cran.r-project.org/package=SchemaOnRead) iterates through a large number of possible import methods until one works successfully diff --git a/README.md b/README.md index e177f57..69a7295 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,7 @@ [![CRAN Version](https://www.r-pkg.org/badges/version/rio)](https://cran.r-project.org/package=rio) -![Downloads](https://cranlogs.r-pkg.org/badges/rio) - - +![Downloads](https://cranlogs.r-pkg.org/badges/rio) ## Overview @@ -26,11 +24,6 @@ implementing four simple functions in Swiss-army knife style: replacement for programs like [Stat/Transfer](https://stattransfer.com/) or [Sledgehammer](https://www.mtna.us/#/products/sledgehammer)). - Relatedly, [Luca Braglia](https://lbraglia.github.io/) has created a - Shiny app called [rioweb](https://github.com/lbraglia/rioweb) that - provides access to the file conversion features of rio. - [GREA](https://github.com/Stan125/GREA/) is an RStudio add-in that - provides an interactive interface for reading in data using rio. ## Installation @@ -59,13 +52,52 @@ Because **rio** is meant to streamline data I/O, the package is extremely easy to use. Here are some examples of reading, writing, and converting data files. -### Export +### Import -Exporting data is handled with one function, `export()`: +Importing data is handled with one function, `import()`: ``` r library("rio") +import("starwars.xlsx") +``` + + ## Name homeworld species + ## 1 Luke Skywalker Tatooine Human + ## 2 C-3PO Tatooine Human + ## 3 R2-D2 Alderaan Human + ## 4 Darth Vader Tatooine Human + ## 5 Leia Organa Tatooine Human + ## 6 Owen Lars Tatooine Human + ## 7 Beru Whitesun lars Stewjon Human + ## 8 R5-D4 Tatooine Human + ## 9 Biggs Darklighter Kashyyyk Wookiee + ## 10 Obi-Wan Kenobi Corellia Human + +``` r +import("starwars.csv") +``` + + ## Name homeworld species + ## 1 Luke Skywalker Tatooine Human + ## 2 C-3PO Tatooine Human + ## 3 R2-D2 Alderaan Human + ## 4 Darth Vader Tatooine Human + ## 5 Leia Organa Tatooine Human + ## 6 Owen Lars Tatooine Human + ## 7 Beru Whitesun lars Stewjon Human + ## 8 R5-D4 Tatooine Human + ## 9 Biggs Darklighter Kashyyyk Wookiee + ## 10 Obi-Wan Kenobi Corellia Human + +Note: Because of inconsistencies across underlying packages, the +data.frame returned by `import` might vary slightly (in variable classes +and attributes) depending on file type. + +### Export + +Exporting data is handled with one function, `export()`: +``` r export(mtcars, "mtcars.csv") # comma-separated values export(mtcars, "mtcars.rds") # R serialized export(mtcars, "mtcars.sav") # SPSS @@ -79,41 +111,96 @@ step of compressing a large exported file, e.g.: export(mtcars, "mtcars.tsv.zip") ``` -As of rio v0.5.0, `export()` can also write multiple data frames to -respective sheets of an Excel workbook or an HTML file: +`export()` can also write multiple data frames to respective sheets of +an Excel workbook or an HTML file: ``` r export(list(mtcars = mtcars, iris = iris), file = "mtcars.xlsx") ``` -### Import +## Supported file formats -Importing data is handled with one function, `import()`: +**rio** supports a wide range of file formats. To keep the package slim, +all non-essential formats are supported via “Suggests” packages, which +are not installed (or loaded) by default. To ensure rio is fully +functional, install these packages the first time you use **rio** via: ``` r -x <- import("mtcars.csv") -y <- import("mtcars.rds") -z <- import("mtcars.sav") - -# confirm data match -all.equal(x, y, check.attributes = FALSE) +install_formats() ``` - ## [1] TRUE +The full list of supported formats is below: + +| Format | Typical Extension | Import Package | Export Package | Installed by Default | +| ----------------------------------------------------- | ----------------------- | --------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | -------------------- | +| Comma-separated data | .csv | [**data.table**](https://cran.r-project.org/package=data.table) | [**data.table**](https://cran.r-project.org/package=data.table) | Yes | +| Pipe-separated data | .psv | [**data.table**](https://cran.r-project.org/package=data.table) | [**data.table**](https://cran.r-project.org/package=data.table) | Yes | +| Tab-separated data | .tsv | [**data.table**](https://cran.r-project.org/package=data.table) | [**data.table**](https://cran.r-project.org/package=data.table) | Yes | +| CSVY (CSV + YAML metadata header) | .csvy | [**data.table**](https://cran.r-project.org/package=data.table) | [**data.table**](https://cran.r-project.org/package=data.table) | Yes | +| SAS | .sas7bdat | [**haven**](https://cran.r-project.org/package=haven) | [**haven**](https://cran.r-project.org/package=haven) (but [deprecated](https://github.com/tidyverse/haven/issues/224)) | Yes | +| SPSS | .sav | [**haven**](https://cran.r-project.org/package=haven) | [**haven**](https://cran.r-project.org/package=haven) | Yes | +| SPSS (compressed) | .zsav | [**haven**](https://cran.r-project.org/package=haven) | [**haven**](https://cran.r-project.org/package=haven) | Yes | +| Stata | .dta | [**haven**](https://cran.r-project.org/package=haven) | [**haven**](https://cran.r-project.org/package=haven) | Yes | +| SAS XPORT | .xpt | [**haven**](https://cran.r-project.org/package=haven) | [**haven**](https://cran.r-project.org/package=haven) | Yes | +| SPSS Portable | .por | [**haven**](https://cran.r-project.org/package=haven) | | Yes | +| Excel | .xls | [**readxl**](https://cran.r-project.org/package=readxl) | | Yes | +| Excel | .xlsx | [**readxl**](https://cran.r-project.org/package=readxl) | [**openxlsx**](https://cran.r-project.org/package=openxlsx) | Yes | +| R syntax | .R | **base** | **base** | Yes | +| Saved R objects | .RData, .rda | **base** | **base** | Yes | +| Serialized R objects | .rds | **base** | **base** | Yes | +| Epiinfo | .rec | [**foreign**](https://cran.r-project.org/package=foreign) | | Yes | +| Minitab | .mtp | [**foreign**](https://cran.r-project.org/package=foreign) | | Yes | +| Systat | .syd | [**foreign**](https://cran.r-project.org/package=foreign) | | Yes | +| “XBASE” database files | .dbf | [**foreign**](https://cran.r-project.org/package=foreign) | [**foreign**](https://cran.r-project.org/package=foreign) | Yes | +| Weka Attribute-Relation File Format | .arff | [**foreign**](https://cran.r-project.org/package=foreign) | [**foreign**](https://cran.r-project.org/package=foreign) | Yes | +| Data Interchange Format | .dif | **utils** | | Yes | +| Fortran data | no recognized extension | **utils** | | Yes | +| Fixed-width format data | .fwf | **utils** | **utils** | Yes | +| gzip comma-separated data | .csv.gz | **utils** | **utils** | Yes | +| Apache Arrow (Parquet) | .parquet | [**arrow**](https://cran.r-project.org/package=arrow) | [**arrow**](https://cran.r-project.org/package=arrow) | No | +| EViews | .wf1 | [**hexView**](https://cran.r-project.org/package=hexView) | | No | +| Feather R/Python interchange format | .feather | [**feather**](https://cran.r-project.org/package=feather) | [**feather**](https://cran.r-project.org/package=feather) | No | +| Fast Storage | .fst | [**fst**](https://cran.r-project.org/package=fst) | [**fst**](https://cran.r-project.org/package=fst) | No | +| JSON | .json | [**jsonlite**](https://cran.r-project.org/package=jsonlite) | [**jsonlite**](https://cran.r-project.org/package=jsonlite) | No | +| Matlab | .mat | [**rmatio**](https://cran.r-project.org/package=rmatio) | [**rmatio**](https://cran.r-project.org/package=rmatio) | No | +| OpenDocument Spreadsheet | .ods | [**readODS**](https://cran.r-project.org/package=readODS) | [**readODS**](https://cran.r-project.org/package=readODS) | No | +| HTML Tables | .html | [**xml2**](https://cran.r-project.org/package=xml2) | [**xml2**](https://cran.r-project.org/package=xml2) | No | +| Shallow XML documents | .xml | [**xml2**](https://cran.r-project.org/package=xml2) | [**xml2**](https://cran.r-project.org/package=xml2) | No | +| YAML | .yml | [**yaml**](https://cran.r-project.org/package=yaml) | [**yaml**](https://cran.r-project.org/package=yaml) | No | +| Clipboard | default is tsv | [**clipr**](https://cran.r-project.org/package=clipr) | [**clipr**](https://cran.r-project.org/package=clipr) | No | +| [Google Sheets](https://www.google.com/sheets/about/) | as Comma-separated data | | | | +| Graphpad Prism | .pzfx | [**pzfx**](https://cran.r-project.org/package=pzfx) | [**pzfx**](https://cran.r-project.org/package=pzfx) | No | + +Additionally, any format that is not supported by **rio** but that has a +known R implementation will produce an informative error message +pointing to a package and import or export function. Unrecognized +formats will yield a simple “Unrecognized file format” error. + +## Other functions + +### Convert + +The `convert()` function links `import()` and `export()` by constructing +a dataframe from the imported file and immediately writing it back to +disk. `convert()` invisibly returns the file name of the exported file, +so that it can be used to programmatically access the new file. ``` r -all.equal(x, z, check.attributes = FALSE) +convert("mtcars.sav", "mtcars.dta") ``` - ## [1] TRUE +It is also possible to use **rio** on the command-line by calling +`Rscript` with the `-e` (expression) argument. For example, to convert a +file from Stata (.dta) to comma-separated values (.csv), simply do the +following: -Note: Because of inconsistencies across underlying packages, the -data.frame returned by `import` might vary slightly (in variable classes -and attributes) depending on file type. + Rscript -e "rio::convert('iris.dta', 'iris.csv')" -In rio v0.5.0, a new list-based import function was added. This allows -users to import a list of data frames from a multi-object file (such as -an Excel workbook, .Rdata file, zip directory, or HTML file): +### \*\_list + +`import_list()` allows users to import a list of data frames from a +multi-object file (such as an Excel workbook, .Rdata file, zip +directory, or HTML file): ``` r str(m <- import_list("mtcars.xlsx")) @@ -139,9 +226,8 @@ str(m <- import_list("mtcars.xlsx")) ## ..$ Petal.Width : num [1:150] 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ... ## ..$ Species : chr [1:150] "setosa" "setosa" "setosa" "setosa" ... -And for rio v0.6.0, a new list-based export function was added. This -makes it easy to export a list of (possibly named) data frames to -multiple files: +`export_list()` makes it easy to export a list of (possibly named) data +frames to multiple files: ``` r export_list(m, "%s.tsv") @@ -150,82 +236,6 @@ c("mtcars.tsv", "iris.tsv") %in% dir() ## [1] TRUE TRUE -### Convert - -The `convert()` function links `import()` and `export()` by constructing -a dataframe from the imported file and immediately writing it back to -disk. `convert()` invisibly returns the file name of the exported file, -so that it can be used to programmatically access the new file. - -``` r -convert("mtcars.sav", "mtcars.dta") -``` - -It is also possible to use **rio** on the command-line by calling -`Rscript` with the `-e` (expression) argument. For example, to convert a -file from Stata (.dta) to comma-separated values (.csv), simply do the -following: - - Rscript -e "rio::convert('iris.dta', 'iris.csv')" - -## Supported file formats - -**rio** supports a wide range of file formats. To keep the package slim, -all non-essential formats are supported via “Suggests” packages, which -are not installed (or loaded) by default. To ensure rio is fully -functional, install these packages the first time you use **rio** via: - -``` r -install_formats() -``` - -The full list of supported formats is below: - -| Format | Typical Extension | Import Package | Export Package | Installed by Default | -| ----------------------------------------------------- | ----------------------- | --------------------------------------------------------------- | --------------------------------------------------------------- | --------------------------------------------------------------------- | -| Comma-separated data | .csv | [**data.table**](https://cran.r-project.org/package=data.table) | [**data.table**](https://cran.r-project.org/package=data.table) | Yes | -| Pipe-separated data | .psv | [**data.table**](https://cran.r-project.org/package=data.table) | [**data.table**](https://cran.r-project.org/package=data.table) | Yes | -| Tab-separated data | .tsv | [**data.table**](https://cran.r-project.org/package=data.table) | [**data.table**](https://cran.r-project.org/package=data.table) | Yes | -| CSVY (CSV + YAML metadata header) | .csvy | [**data.table**](https://cran.r-project.org/package=data.table) | [**data.table**](https://cran.r-project.org/package=data.table) | Yes | -| SAS | .sas7bdat | [**haven**](https://cran.r-project.org/package=haven) | [**haven**](https://cran.r-project.org/package=haven) | Yes (but [deprecated](https://github.com/tidyverse/haven/issues/224)) | -| SPSS | .sav | [**haven**](https://cran.r-project.org/package=haven) | [**haven**](https://cran.r-project.org/package=haven) | Yes | -| SPSS (compressed) | .zsav | [**haven**](https://cran.r-project.org/package=haven) | [**haven**](https://cran.r-project.org/package=haven) | Yes | -| Stata | .dta | [**haven**](https://cran.r-project.org/package=haven) | [**haven**](https://cran.r-project.org/package=haven) | Yes | -| SAS XPORT | .xpt | [**haven**](https://cran.r-project.org/package=haven) | [**haven**](https://cran.r-project.org/package=haven) | Yes | -| SPSS Portable | .por | [**haven**](https://cran.r-project.org/package=haven) | | Yes | -| Excel | .xls | [**readxl**](https://cran.r-project.org/package=readxl) | | Yes | -| Excel | .xlsx | [**readxl**](https://cran.r-project.org/package=readxl) | [**openxlsx**](https://cran.r-project.org/package=openxlsx) | Yes | -| R syntax | .R | **base** | **base** | Yes | -| Saved R objects | .RData, .rda | **base** | **base** | Yes | -| Serialized R objects | .rds | **base** | **base** | Yes | -| Epiinfo | .rec | [**foreign**](https://cran.r-project.org/package=foreign) | | Yes | -| Minitab | .mtp | [**foreign**](https://cran.r-project.org/package=foreign) | | Yes | -| Systat | .syd | [**foreign**](https://cran.r-project.org/package=foreign) | | Yes | -| “XBASE” database files | .dbf | [**foreign**](https://cran.r-project.org/package=foreign) | [**foreign**](https://cran.r-project.org/package=foreign) | Yes | -| Weka Attribute-Relation File Format | .arff | [**foreign**](https://cran.r-project.org/package=foreign) | [**foreign**](https://cran.r-project.org/package=foreign) | Yes | -| Data Interchange Format | .dif | **utils** | | Yes | -| Fortran data | no recognized extension | **utils** | | Yes | -| Fixed-width format data | .fwf | **utils** | **utils** | Yes | -| gzip comma-separated data | .csv.gz | **utils** | **utils** | Yes | -| Apache Arrow (Parquet) | .parquet | [**arrow**](https://cran.r-project.org/package=arrow) | [**arrow**](https://cran.r-project.org/package=arrow) | No | -| EViews | .wf1 | [**hexView**](https://cran.r-project.org/package=hexView) | | No | -| Feather R/Python interchange format | .feather | [**feather**](https://cran.r-project.org/package=feather) | [**feather**](https://cran.r-project.org/package=feather) | No | -| Fast Storage | .fst | [**fst**](https://cran.r-project.org/package=fst) | [**fst**](https://cran.r-project.org/package=fst) | No | -| JSON | .json | [**jsonlite**](https://cran.r-project.org/package=jsonlite) | [**jsonlite**](https://cran.r-project.org/package=jsonlite) | No | -| Matlab | .mat | [**rmatio**](https://cran.r-project.org/package=rmatio) | [**rmatio**](https://cran.r-project.org/package=rmatio) | No | -| OpenDocument Spreadsheet | .ods | [**readODS**](https://cran.r-project.org/package=readODS) | [**readODS**](https://cran.r-project.org/package=readODS) | No | -| HTML Tables | .html | [**xml2**](https://cran.r-project.org/package=xml2) | [**xml2**](https://cran.r-project.org/package=xml2) | No | -| Shallow XML documents | .xml | [**xml2**](https://cran.r-project.org/package=xml2) | [**xml2**](https://cran.r-project.org/package=xml2) | No | -| YAML | .yml | [**yaml**](https://cran.r-project.org/package=yaml) | [**yaml**](https://cran.r-project.org/package=yaml) | No | -| Clipboard | default is tsv | [**clipr**](https://cran.r-project.org/package=clipr) | [**clipr**](https://cran.r-project.org/package=clipr) | No | -| [Google Sheets](https://www.google.com/sheets/about/) | as Comma-separated data | | | | -| Graphpad Prism | .pzfx | [**pzfx**](https://cran.r-project.org/package=pzfx) | [**pzfx**](https://cran.r-project.org/package=pzfx) | No | - -Additionally, any format that is not supported by **rio** but that has a -known R implementation will produce an informative error message -pointing to a package and import or export function. Unrecognized -formats will yield a simple “Unrecognized file format” error. - ## Package Philosophy The core advantage of **rio** is that it makes assumptions that the user @@ -239,23 +249,7 @@ is probably willing to make. Eight of these are important: function, **rio** allows almost all common data formats to be read with the same function. And if a file extension is incorrect, users can force a particular import method by specifying the `format` - argument. Other packages do this as well, but **rio** aims to be - more complete and more consistent than each: - - - - - [**reader**](https://cran.r-project.org/package=reader) handles - certain text formats and R binary files - - [**io**](https://cran.r-project.org/package=io) offers a set of - custom formats - - [**ImportExport**](https://cran.r-project.org/package=ImportExport) - focuses on select binary formats (Excel, SPSS, and Access files) and - provides a Shiny interface. - - [**SchemaOnRead**](https://cran.r-project.org/package=SchemaOnRead) - iterates through a large number of possible import methods until one - works successfully - - + argument. 2. **rio** uses `data.table::fread()` for text-delimited files to automatically determine the file format regardless of the extension. @@ -330,3 +324,26 @@ is probably willing to make. Eight of these are important: should take the form `.import.rio_X()` and `.export.rio_X()`, where `X` is the file extension of a file type. An example is provided in the [rio.db package](https://github.com/leeper/rio.db). + +## Other projects + +### GUIs + + - [**rioweb**](https://github.com/lbraglia/rioweb) that provides + access to the file conversion features of rio. + - [**GREA**](https://github.com/Stan125/GREA/) is an RStudio add-in + that provides an interactive interface for reading in data using + rio. + +### Similar packages + + - [**reader**](https://cran.r-project.org/package=reader) handles + certain text formats and R binary files + - [**io**](https://cran.r-project.org/package=io) offers a set of + custom formats + - [**ImportExport**](https://cran.r-project.org/package=ImportExport) + focuses on select binary formats (Excel, SPSS, and Access files) and + provides a Shiny interface. + - [**SchemaOnRead**](https://cran.r-project.org/package=SchemaOnRead) + iterates through a large number of possible import methods until one + works successfully From 7d1623e5d9c311f94de66bed03117db17b0eaf48 Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Tue, 29 Aug 2023 10:01:46 +0200 Subject: [PATCH 04/44] Further update README [no ci] * Update handle * Stop calling other formats as "non-essential" * Add the starwars datasets --- .Rbuildignore | 2 ++ README.Rmd | 16 ++++++++++------ README.md | 27 +++++++++++++-------------- starwars.csv | 11 +++++++++++ starwars.xlsx | Bin 0 -> 6899 bytes 5 files changed, 36 insertions(+), 20 deletions(-) create mode 100644 starwars.csv create mode 100644 starwars.xlsx diff --git a/.Rbuildignore b/.Rbuildignore index 00d508b..99e5739 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -38,3 +38,5 @@ ^\.Rproj\.user$ ^\.github$ ^\.editorconfig$ +^starwars.xlsx$ +^starwars.csv$ diff --git a/README.Rmd b/README.Rmd index 21b5205..3db9dd8 100644 --- a/README.Rmd +++ b/README.Rmd @@ -14,17 +14,14 @@ output: github_document The aim of **rio** is to make data file I/O in R as easy as possible by implementing four simple functions in Swiss-army knife style: - `import()` provides a painless data import experience by automatically choosing the appropriate import/read function based on file extension (or a specified `format` argument) - - `import_list()` imports a list of data frames from a multi-object file (Excel workbook, .Rdata files, zip directory, or HTML file) - `export()` provides the same painless file recognition for data export/write functionality - - `convert()` wraps `import()` and `export()` to allow the user to easily convert between file formats (thus providing a FOSS replacement for programs like [Stat/Transfer](https://stattransfer.com/) or [Sledgehammer](https://www.mtna.us/#/products/sledgehammer)). ## Installation -The package is available on [CRAN](https://cran.r-project.org/package=rio) and can be installed directly in R using `install.packages()`. You may want to run `install_formats()` after the first installation. +The package is available on [CRAN](https://cran.r-project.org/package=rio) and can be installed directly in R using `install.packages()`. ```R install.packages("rio") -install_formats() ``` The latest development version on GitHub can be installed using: @@ -33,7 +30,14 @@ The latest development version on GitHub can be installed using: if (!require("remotes")){ install.packages("remotes") } -remotes::install_github("leeper/rio") +remotes::install_github("chainsawriot/rio") +``` + +Optional: Installation of additional formats (see below: **Supported file formats**) + +```R +library(rio) +install_formats() ``` ## Usage @@ -79,7 +83,7 @@ export(list(mtcars = mtcars, iris = iris), file = "mtcars.xlsx") ## Supported file formats -**rio** supports a wide range of file formats. To keep the package slim, all non-essential formats are supported via "Suggests" packages, which are not installed (or loaded) by default. To ensure rio is fully functional, install these packages the first time you use **rio** via: +**rio** supports a wide range of file formats. To keep the package slim, several formats are supported via "Suggests" packages, which are not installed (or loaded) by default. To ensure rio is fully functional, install these packages the first time you use **rio** via: ```R install_formats() diff --git a/README.md b/README.md index 69a7295..d761f89 100644 --- a/README.md +++ b/README.md @@ -15,26 +15,17 @@ implementing four simple functions in Swiss-army knife style: - `import()` provides a painless data import experience by automatically choosing the appropriate import/read function based on file extension (or a specified `format` argument) - - `import_list()` imports a list of data frames from a multi-object - file (Excel workbook, .Rdata files, zip directory, or HTML file) - `export()` provides the same painless file recognition for data export/write functionality - - `convert()` wraps `import()` and `export()` to allow the user to - easily convert between file formats (thus providing a FOSS - replacement for programs like - [Stat/Transfer](https://stattransfer.com/) or - [Sledgehammer](https://www.mtna.us/#/products/sledgehammer)). ## Installation The package is available on [CRAN](https://cran.r-project.org/package=rio) and can be installed -directly in R using `install.packages()`. You may want to run -`install_formats()` after the first installation. +directly in R using `install.packages()`. ``` r install.packages("rio") -install_formats() ``` The latest development version on GitHub can be installed using: @@ -43,7 +34,15 @@ The latest development version on GitHub can be installed using: if (!require("remotes")){ install.packages("remotes") } -remotes::install_github("leeper/rio") +remotes::install_github("chainsawriot/rio") +``` + +Optional: Installation of additional formats (see below: **Supported +file formats**) + +``` r +library(rio) +install_formats() ``` ## Usage @@ -121,9 +120,9 @@ export(list(mtcars = mtcars, iris = iris), file = "mtcars.xlsx") ## Supported file formats **rio** supports a wide range of file formats. To keep the package slim, -all non-essential formats are supported via “Suggests” packages, which -are not installed (or loaded) by default. To ensure rio is fully -functional, install these packages the first time you use **rio** via: +several formats are supported via “Suggests” packages, which are not +installed (or loaded) by default. To ensure rio is fully functional, +install these packages the first time you use **rio** via: ``` r install_formats() diff --git a/starwars.csv b/starwars.csv new file mode 100644 index 0000000..9e5f9e0 --- /dev/null +++ b/starwars.csv @@ -0,0 +1,11 @@ +Name,homeworld,species +Luke Skywalker,Tatooine,Human +C-3PO,Tatooine,Human +R2-D2,Alderaan,Human +Darth Vader,Tatooine,Human +Leia Organa,Tatooine,Human +Owen Lars,Tatooine,Human +Beru Whitesun lars,Stewjon,Human +R5-D4,Tatooine,Human +Biggs Darklighter,Kashyyyk,Wookiee +Obi-Wan Kenobi,Corellia,Human diff --git a/starwars.xlsx b/starwars.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..b817be6a787e8bff5a63b42dbcd983f3a5f53e2a GIT binary patch literal 6899 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 a{;wggs(^fND>yi``zP!^)$0B-!T$qXbi{7} literal 0 HcmV?d00001 From 57d3a20b38ccd46afb42249e1c00bf7dbe860639 Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Tue, 29 Aug 2023 10:58:27 +0200 Subject: [PATCH 05/44] Massive declutter [no ci] (#309) --- R/import.R | 2 +- R/import_list.R | 34 +- docs/404.html | 159 --- docs/CONTRIBUTING.html | 185 ---- docs/ISSUE_TEMPLATE.html | 189 ---- docs/PULL_REQUEST_TEMPLATE.html | 182 ---- docs/apple-touch-icon-120x120.png | Bin 10213 -> 0 bytes docs/apple-touch-icon-152x152.png | Bin 13109 -> 0 bytes docs/apple-touch-icon-180x180.png | Bin 15374 -> 0 bytes docs/apple-touch-icon-60x60.png | Bin 4920 -> 0 bytes docs/apple-touch-icon-76x76.png | Bin 6318 -> 0 bytes docs/apple-touch-icon.png | Bin 15374 -> 0 bytes docs/articles/index.html | 158 --- docs/articles/rio.html | 531 ---------- .../empty-anchor.js | 15 - docs/authors.html | 227 ----- docs/bootstrap-toc.css | 60 -- docs/bootstrap-toc.js | 159 --- docs/docsearch.css | 148 --- docs/docsearch.js | 85 -- docs/favicon-16x16.png | Bin 1306 -> 0 bytes docs/favicon-32x32.png | Bin 2507 -> 0 bytes docs/favicon.ico | Bin 15086 -> 0 bytes docs/index.html | 572 ----------- docs/jquery.sticky-kit.min.js | 9 - docs/link.svg | 12 - docs/logo.png | Bin 11768 -> 0 bytes docs/logo.svg | 147 --- docs/news/index.html | 924 ------------------ docs/pkgdown.css | 367 ------- docs/pkgdown.js | 108 -- docs/pkgdown.yml | 7 - docs/reference/arg_reconcile.html | 256 ----- docs/reference/characterize.html | 226 ----- docs/reference/convert.html | 193 ---- docs/reference/export.html | 293 ------ docs/reference/export_list.html | 210 ---- docs/reference/extensions.html | 200 ---- docs/reference/figures/logo.png | Bin 11768 -> 0 bytes docs/reference/figures/logo.svg | 147 --- docs/reference/figures/logo.xcf | Bin 78942 -> 0 bytes docs/reference/gather_attrs.html | 289 ------ docs/reference/get_ext.html | 176 ---- docs/reference/import.html | 273 ------ docs/reference/import_list.html | 250 ----- docs/reference/index.html | 256 ----- docs/reference/install_formats.html | 176 ---- docs/reference/is_file_text.html | 196 ---- docs/reference/list.rds | Bin 2248 -> 0 bytes docs/reference/mtcars.csv | 33 - docs/reference/rio.html | 189 ---- man-roxygen/setclass.R | 1 - man/import_list.Rd | 2 +- pkgdown/favicon/apple-touch-icon-120x120.png | Bin 10213 -> 0 bytes pkgdown/favicon/apple-touch-icon-152x152.png | Bin 13109 -> 0 bytes pkgdown/favicon/apple-touch-icon-180x180.png | Bin 15374 -> 0 bytes pkgdown/favicon/apple-touch-icon-60x60.png | Bin 4920 -> 0 bytes pkgdown/favicon/apple-touch-icon-76x76.png | Bin 6318 -> 0 bytes pkgdown/favicon/apple-touch-icon.png | Bin 15374 -> 0 bytes pkgdown/favicon/favicon-16x16.png | Bin 1306 -> 0 bytes pkgdown/favicon/favicon-32x32.png | Bin 2507 -> 0 bytes pkgdown/favicon/favicon.ico | Bin 15086 -> 0 bytes 62 files changed, 19 insertions(+), 7627 deletions(-) delete mode 100644 docs/404.html delete mode 100644 docs/CONTRIBUTING.html delete mode 100644 docs/ISSUE_TEMPLATE.html delete mode 100644 docs/PULL_REQUEST_TEMPLATE.html delete mode 100644 docs/apple-touch-icon-120x120.png delete mode 100644 docs/apple-touch-icon-152x152.png delete mode 100644 docs/apple-touch-icon-180x180.png delete mode 100644 docs/apple-touch-icon-60x60.png delete mode 100644 docs/apple-touch-icon-76x76.png delete mode 100644 docs/apple-touch-icon.png delete mode 100644 docs/articles/index.html delete mode 100644 docs/articles/rio.html delete mode 100644 docs/articles/rio_files/accessible-code-block-0.0.1/empty-anchor.js delete mode 100644 docs/authors.html delete mode 100644 docs/bootstrap-toc.css delete mode 100644 docs/bootstrap-toc.js delete mode 100644 docs/docsearch.css delete mode 100644 docs/docsearch.js delete mode 100644 docs/favicon-16x16.png delete mode 100644 docs/favicon-32x32.png delete mode 100644 docs/favicon.ico delete mode 100644 docs/index.html delete mode 100644 docs/jquery.sticky-kit.min.js delete mode 100644 docs/link.svg delete mode 100644 docs/logo.png delete mode 100644 docs/logo.svg delete mode 100644 docs/news/index.html delete mode 100644 docs/pkgdown.css delete mode 100644 docs/pkgdown.js delete mode 100644 docs/pkgdown.yml delete mode 100644 docs/reference/arg_reconcile.html delete mode 100644 docs/reference/characterize.html delete mode 100644 docs/reference/convert.html delete mode 100644 docs/reference/export.html delete mode 100644 docs/reference/export_list.html delete mode 100644 docs/reference/extensions.html delete mode 100644 docs/reference/figures/logo.png delete mode 100644 docs/reference/figures/logo.svg delete mode 100644 docs/reference/figures/logo.xcf delete mode 100644 docs/reference/gather_attrs.html delete mode 100644 docs/reference/get_ext.html delete mode 100644 docs/reference/import.html delete mode 100644 docs/reference/import_list.html delete mode 100644 docs/reference/index.html delete mode 100644 docs/reference/install_formats.html delete mode 100644 docs/reference/is_file_text.html delete mode 100644 docs/reference/list.rds delete mode 100644 docs/reference/mtcars.csv delete mode 100644 docs/reference/rio.html delete mode 100644 man-roxygen/setclass.R delete mode 100644 pkgdown/favicon/apple-touch-icon-120x120.png delete mode 100644 pkgdown/favicon/apple-touch-icon-152x152.png delete mode 100644 pkgdown/favicon/apple-touch-icon-180x180.png delete mode 100644 pkgdown/favicon/apple-touch-icon-60x60.png delete mode 100644 pkgdown/favicon/apple-touch-icon-76x76.png delete mode 100644 pkgdown/favicon/apple-touch-icon.png delete mode 100644 pkgdown/favicon/favicon-16x16.png delete mode 100644 pkgdown/favicon/favicon-32x32.png delete mode 100644 pkgdown/favicon/favicon.ico diff --git a/R/import.R b/R/import.R index 9a7c04a..61552d9 100644 --- a/R/import.R +++ b/R/import.R @@ -3,7 +3,7 @@ #' @description Read in a data.frame from a file. Exceptions to this rule are Rdata, RDS, and JSON input file formats, which return the originally saved object without changing its class. #' @param file A character string naming a file, URL, or single-file .zip or .tar archive. #' @param format An optional character string code of file format, which can be used to override the format inferred from \code{file}. Shortcuts include: \dQuote{,} (for comma-separated values), \dQuote{;} (for semicolon-separated values), and \dQuote{|} (for pipe-separated values). -#' @template setclass +#' @param setclass An optional character vector specifying one or more classes to set on the import. By default, the return object is always a \dQuote{data.frame}. Allowed values include \dQuote{tbl_df}, \dQuote{tbl}, or \dQuote{tibble} (if using dplyr) or \dQuote{data.table} (if using data.table). Other values are ignored, such that a data.frame is returned. #' @param which This argument is used to control import from multi-object files; as a rule \code{import} only ever returns a single data frame (use \code{\link{import_list}} to import multiple data frames from a multi-object file). If \code{file} is a compressed directory, \code{which} can be either a character string specifying a filename or an integer specifying which file (in locale sort order) to extract from the compressed directory. For Excel spreadsheets, this can be used to specify a sheet name or number. For .Rdata files, this can be an object name. For HTML files, it identifies which table to extract (from document order). Ignored otherwise. A character string value will be used as a regular expression, such that the extracted file is the first match of the regular expression against the file names in the archive. #' @param \dots Additional arguments passed to the underlying import functions. For example, this can control column classes for delimited file types, or control the use of haven for Stata and SPSS or readxl for Excel (.xlsx) format. See details below. #' @return A data frame. If \code{setclass} is used, this data frame may have additional class attribute values, such as \dQuote{tibble} or \dQuote{data.table}. diff --git a/R/import_list.R b/R/import_list.R index 4289958..f6b7b9e 100644 --- a/R/import_list.R +++ b/R/import_list.R @@ -1,31 +1,31 @@ #' @title Import list of data frames #' @description Use \code{\link{import}} to import a list of data frames from a vector of file names or from a multi-object file (Excel workbook, .Rdata file, zip directory, or HTML file) #' @param file A character string containing a single file name for a multi-object file (e.g., Excel workbook, zip directory, or HTML file), or a vector of file paths for multiple files to be imported. -#' @template setclass #' @param which If \code{file} is a single file path, this specifies which objects should be extracted (passed to \code{\link{import}}'s \code{which} argument). Ignored otherwise. #' @param rbind A logical indicating whether to pass the import list of data frames through \code{\link[data.table]{rbindlist}}. #' @param rbind_label If \code{rbind = TRUE}, a character string specifying the name of a column to add to the data frame indicating its source file. #' @param rbind_fill If \code{rbind = TRUE}, a logical indicating whether to set the \code{fill = TRUE} (and fill missing columns with \code{NA}). #' @param \dots Additional arguments passed to \code{\link{import}}. Behavior may be unexpected if files are of different formats. +#' @inheritParams import #' @return If \code{rbind=FALSE} (the default), a list of a data frames. Otherwise, that list is passed to \code{\link[data.table]{rbindlist}} with \code{fill = TRUE} and returns a data frame object of class set by the \code{setclass} argument; if this operation fails, the list is returned. #' @examples #' library('datasets') -#' export(list(mtcars1 = mtcars[1:10,], +#' export(list(mtcars1 = mtcars[1:10,], #' mtcars2 = mtcars[11:20,], #' mtcars3 = mtcars[21:32,]), #' xlsx_file <- tempfile(fileext = ".xlsx") #' ) -#' +#' #' # import a single file from multi-object workbook #' str(import(xlsx_file, which = "mtcars1")) -#' +#' #' # import all worksheets #' str(import_list(xlsx_file), 1) -#' +#' #' # import and rbind all worksheets #' mtcars2 <- import_list(xlsx_file, rbind = TRUE) #' all.equal(mtcars2[,-12], mtcars, check.attributes = FALSE) -#' +#' #' # import multiple files #' wd <- getwd() #' setwd(tempdir()) @@ -34,19 +34,19 @@ #' str(import_list(dir(pattern = "csv$")), 1) #' unlink(c("mtcars1.csv", "mtcars2.csv")) #' setwd(wd) -#' +#' #' # cleanup #' unlink(xlsx_file) -#' +#' #' @seealso \code{\link{import}}, \code{\link{export_list}}, \code{\link{export}} #' @export -import_list <- -function(file, - setclass, - which, - rbind = FALSE, - rbind_label = "_file", - rbind_fill = TRUE, +import_list <- +function(file, + setclass, + which, + rbind = FALSE, + rbind_label = "_file", + rbind_fill = TRUE, ...) { if (missing(setclass)) { setclass <- NULL @@ -123,7 +123,7 @@ function(file, names(x) <- whichnames } } - + # optionally rbind if (isTRUE(rbind)) { if (length(x) == 1) { @@ -158,6 +158,6 @@ function(file, } } } - + return(x) } diff --git a/docs/404.html b/docs/404.html deleted file mode 100644 index 99261a5..0000000 --- a/docs/404.html +++ /dev/null @@ -1,159 +0,0 @@ - - - - - - - - -Page not found (404) • rio - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - - - -
- -
-
- - -Content not found. Please use links in the navbar. - -
- - - -
- - - -
- - -
-

Site built with pkgdown 1.5.1.

-
- -
-
- - - - - - - - diff --git a/docs/CONTRIBUTING.html b/docs/CONTRIBUTING.html deleted file mode 100644 index b33c2d6..0000000 --- a/docs/CONTRIBUTING.html +++ /dev/null @@ -1,185 +0,0 @@ - - - - - - - - -NA • rio - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - - - -
- -
-
- - - -

Contributions to rio are welcome from anyone and are best sent as pull requests on the GitHub repository. This page provides some instructions to potential contributors about how to add to the package.

-
    -
  1. Contributions can be submitted as a pull request on GitHub by forking or cloning the repo, making changes and submitting the pull request.

  2. -
  3. Pull requests should involve only one commit per substantive change. This means if you change multiple files (e.g., code and documentation), these changes should be committed together. If you don’t know how to do this (e.g., you are making changes in the GitHub web interface) just submit anyway and the maintainer will clean things up.

  4. -
  5. All contributions must be submitted consistent with the package license (GPL-2).

  6. -
  7. All contributions need to be noted in the Authors@R field in the DESCRIPTION. Just follow the format of the existing entries to add your name (and, optionally, email address). Substantial contributions should also be noted in inst/CITATION.

  8. -
  9. This package uses royxgen code and documentation markup, so changes should be made to roxygen comments in the source code .R files. If changes are made, roxygen needs to be run. The easiest way to do this is a command line call to: Rscript -e devtools::document(). Please resolve any roxygen errors before submitting a pull request.

  10. -
  11. Please run R CMD BUILD rio and R CMD CHECK rio_VERSION.tar.gz before submitting the pull request to check for any errors.

  12. -
-

Some specific types of changes that you might make are:

-
    -
  1. Documentation-only changes (e.g., to Rd files, README, vignettes). This is great! All contributions are welcome.

  2. -
  3. Addition of new file format imports or exports. This is also great! Some advice:

  4. -
-
    -
  • Import is based on S3 dispatch to functions of the form .import.rio_FORMAT(). Export works the same, but with .export.rio_FORMAT(). New import/export methods should take this form. There’s no need to change the body of the import() or export() functions; S3 will take care of dispatch. All .import() methods must accept a file and which argument: file represents the path to the file and which can be used to extract sheets or files from multi-object files (e.g., zip, Excel workbooks, etc.). .export() methods take two arguments: file and x, where file is the path to the file and x is the data frame being exported. Most of the work of import and export methods involves mapping these arguments to their corresponding argument names in the various underlying packages.

  • -
  • The S3 methods should be documented in NAMESPACE using S3method(), which is handled automatically by roxygen markup in the source code.

  • -
  • Any new format support needs to be documented in each of the following places: README.Rmd, the vignette, and the appropriate Rd file in /man.

  • -
  • New formats or new options for handling formats should have a test added in /tests/testthat called test_format_FORMAT.R that completely covers the function’s behavior. This may require adding an example file to inst/examples (e.g., for testing import()).

  • -
-
    -
  1. Changes requiring a new package dependency should be discussed on the GitHub issues page before submitting a pull request.

  2. -
  3. Message translations. These are very appreciated! The format is a pain, but if you’re doing this I’m assuming you’re already familiar with it.

  4. -
-

Any questions you have can be opened as GitHub issues or directed to thosjleeper (at) gmail.com.

- - -
- - - -
- - - -
- - -
-

Site built with pkgdown 1.5.1.

-
- -
-
- - - - - - - - diff --git a/docs/ISSUE_TEMPLATE.html b/docs/ISSUE_TEMPLATE.html deleted file mode 100644 index 282d435..0000000 --- a/docs/ISSUE_TEMPLATE.html +++ /dev/null @@ -1,189 +0,0 @@ - - - - - - - - -NA • rio - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - - - -
- -
-
- - - -

Please specify whether your issue is about:

-
    -
  • - -a possible bug
  • -
  • - -a question about package functionality
  • -
  • - -a suggested code or documentation change, improvement to the code, or feature request
  • -
-

If you are reporting (1) a bug or (2) a question about code, please supply:

- -

Put your code here:

-
## load package
-library("rio")
-
-## code goes here
-
-
-## session info for your system
-sessionInfo()
- - -
- - - -
- - - -
- - -
-

Site built with pkgdown 1.5.1.

-
- -
-
- - - - - - - - diff --git a/docs/PULL_REQUEST_TEMPLATE.html b/docs/PULL_REQUEST_TEMPLATE.html deleted file mode 100644 index 8999632..0000000 --- a/docs/PULL_REQUEST_TEMPLATE.html +++ /dev/null @@ -1,182 +0,0 @@ - - - - - - - - -NA • rio - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - - - -
- -
-
- - - -

Please ensure the following before submitting a PR:

-
    -
  • - -if suggesting code changes or improvements, open an issue first
  • -
  • - -for all but trivial changes (e.g., typo fixes), add your name to DESCRIPTION -
  • -
  • - -for all but trivial changes (e.g., typo fixes), documentation your change in NEWS.md with a parenthetical reference to the issue number being addressed
  • -
  • - -if changing documentation, edit files in /R not /man and run devtools::document() to update documentation
  • -
  • - -add code or new test files to /tests for any new functionality or bug fix
  • -
  • - -make sure R CMD check runs without error before submitting the PR
  • -
- - -
- - - -
- - - -
- - -
-

Site built with pkgdown 1.5.1.

-
- -
-
- - - - - - - - diff --git a/docs/apple-touch-icon-120x120.png b/docs/apple-touch-icon-120x120.png deleted file mode 100644 index a5ffa4720357ef797fbd6b24a229b36d8314838a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10213 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 Y7#r2?T8uLlxCMx;q>@CXm~rs`05ZbH8UO$Q diff --git a/docs/apple-touch-icon-60x60.png b/docs/apple-touch-icon-60x60.png deleted file mode 100644 index 35d4df01ccc54402a3c6b043781942fbd1e3c6fb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4920 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 diff --git a/docs/apple-touch-icon-76x76.png b/docs/apple-touch-icon-76x76.png deleted file mode 100644 index 46db16433cacdbe7f4d3db84f689ef1f66a30ada..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6318 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 P5&)1g_;sbC&Aa~rHK7^$ diff --git a/docs/apple-touch-icon.png b/docs/apple-touch-icon.png deleted file mode 100644 index 7abe275f09d7a1a619291aacdd893e009ecc226c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15374 zcmZ{LWmFwav@GuK?(XjH?!nz1f;)uZ?u1|gf&_O6?ykYz-QD31_xp3-kGBY%#UayY zrn~pvRkf=lRg|O=;qc%>WhB&q*ZR+I7%1SU;5ZZ;@B(2aswfHqQWFpVY61!T zPGTmbrU(M!Lj?j76aoVB47?R|2m<2H0s?Yu3UUb zSkC$>F-(=30x&MOX@AcJf4AJpoAdL!$(B2J2R(g%4G7v`IaF3rz7RSTTev)EF`0{G z*^CU=bzvp62naUz;S}S_N$J_Gl$TZ4@eBQjs1dY%LxRtI|BN%&gGmQ@eq$7gZG{eG{*^p+ z1|GO+viSwVB%;z6o77K}Ow>&3*ZfHWr7W+UN>M8pcYLseFAc93f_%dtyhVsM=qv~d zPhkaVDeAlxD9!|sS7;V-^vw%QHX8<$8LDkUq9}$@lF_DYiU_i#eld#y-s@x!l?-pB zCDV2!KQIPJ$L5!AJ~}?wGaessVMwe9U59FuMG~@ogIkuDiFZ;6)jremqTMN0 zxW@A$DsCgNxB~5yakpc;)@fPm7gPuV*jELVP@$F|)}*HQ8eq}`dDr(Hw9NLQBqT5@ znOZX4_w5)L!oh_j+TavxoK>K}upPNQ^9)UWh+R5Rqm>6thJRQ?9JPgC$zP z>T-{GhS3Cl$)`I3^OoiRBQq+&rFZ?!qD#7q(^FYQT7)`JFB}8`A^=pN==vTBCWct5 z?^MEVdM!0H2l2XRKQodHD>?Gtg|f=!8j}Jqx4HQf$EBw+xys%-?3KA2+VeRKbPlK? zmWCOu5r z*~7Fg@G+??!5#ZW|&SPYxR46l*slnTk`GNXeqyTZFH zJe5<5^OC2=Nx{g2w7x;l`D6=OuhR5bDRvjz{dSSyAA#2+jUb!1y@9 z!lA9m#!O`;&>o;p;4h$ct<=+NhZG!-pvZX=PuqSiQc+uVMJNIu6t+g~FOjd}91LP* z%tn;L-qaR@%H(r%>0r6w7vKkLf)Y(i@vYFCQYGJNXdIg}@B)P|ifD`^76}Xda==6} zYUbxv1GW*KhWY<=_+jcKP2?r`AgUanv$j|mt_p&1=V4#MRjbU}ih*yZ(BvBB=8!}Y zDSl3m+Yw2bR40K6ilKesd(!hz^|+;&UtV@ef!q=PR#(q>I%9HaMp}>cBbbbt%I-VD zDLv0{o%Otjsr>mE&*{0I#r<)=Rg*U6s70)ekZeMn^6*<3j`J}M; z;6408_=^pDhPWDzwugU$iIoqRDHJ&sX*PuecJ5F10TN6@mNBmJJDXD22KtK*c4EbR z84axRXb_lZe2qcw!Wy`>bVQfRW_p)E>ck+o*Qrd873KC!d$dcRAkAmMMg1s?;g;{Z zhAZzRP-bT+N&>byH9`;wfPUyBO;S1a{u; z=JWtswUbK3+LnA5A77sTH)z%JYnI$fRMW>XT8Q}ghcTMma1j(pis;nRv724WvtMjG z1hxH1qvL4R`oNrQS-C!d5QM1MZZdvzLw< z2nO8#@r69OE`=gBe=p<*2aLlhX3&UCN7J*9ufg zYG927k4Ahlu-eij^-w=T(DvkKA)u_qiz!gjegtV*UkaiFt4u>_%$Y*SEBfx)%3?5@ znz+YK({Y06F2cy0I+c)y@n@oar#3iY$WnWIbF|F*kfI>61725bK;X~{ zXUuDZHKIL&ATxm8aESSWv#ad(^Hfb4yD!#9hA7~Lb4~T;`ypzM6%6c_OFJ-t$_q-q zrx|D%{iPxwwfYtaVg$N(PGmNty(Sn0714!~qT3Pvg^#%N*ED%VGc#&#N#zJC5d|}Z z>hH#C99J9O=N#3E3XlhkRb8;g0}#npBo!k~!}uiEH?C@AWE#+$5RVoEmD;U!ERE90 zckpK)Nk+ev2p#n)C`ccSM0|JO{yzw{=@o^>D@3*~H!3g3(@?l5bGDOsPQK!4sz-j8 z7aP!>@9l}l$6wq-C2MNu_^|hU+YnNkT_euxr+hX+Q)o6|E{2>bN77N^2PPMG7=Wbk zgT9Pru_Y6zXEiuZ0|c`jJ_zL7FquDtI<$}{X-eI@{j^VxX@nDtQi2Rdq|$!h085p- zQ-sFiiJ}YHS0M4UU-EV<)D2qzo6Cv|488}WTanQw ztA~>hJ-dSV(-?Ogtwkf85%#wYPVpCLY^RfWrh%vM+!~R#N`RjxeJ}|J>YS$acLbbm zsBQE)L|2=?O@HhCAZi8R3wz$lj9u=@c`~Q)jM+v`4nC|A-VMksDdAM%i71U#gdvcP zBw&L@91KAzq2oyO&YG%$dJ}WNtooG=QT_|(@-LCufDRAzen{lfa@0~qAO#hAe6T9~ z^)3lUu)gK9f5#kQ3#Q3G!HP6_H0F2@nBB*Q(k)Yr?Bc;N@W-TvvdEG>?C5g(CLE=E zmeBQ>cYJ7-Lt?&-qv4Y+js6!km_$WOMPfM53<7NiuN=xBOUJklyt8&-ua36RIzb8~8H zBJyEG?o;U*^cs??lnd2_n~_2N&x}qu(t^GeStX{|e=n`WPN6rgzXPs#v zOaFLgVj7w=o=WMUL#HkxCdU3M)}%p~_vP2bY?S!M_}`6lU!;%|L&`E$G&(ywTkZei@%~WOkoBOt zC2UJ$_zmi1y;+gc7!t8Hh_K(Zyi#gOdEX#qJD97zXGQK1CS^@6kgP;wI>6ue6YPSD zLy_3>2QcQ+!>qY6r^5LwVC1P&qwugH#daF4M68MI`j~M7MeedCMO;h+;fDCf;Nf(^ z)$|cTi~UzsRwKVVN_tO+Vg{a6?^kOIDQh)Jf{Y(zWRDP>?GFm6+Nb7_zpDa#u47IJ zL#_lZ=t>AUrSUzQuE@4hxp>Hq3d5BDKFX<8O#((}#FxuJES@%?kV+ zLiu6WU{uSxokWO37r#Gm%xl!zbBUaLSOEWmWqtUeMM0u%jc+~JkE=$xRI+8 zNHo?B&piAa;*kfUmu4{+1&Wov**B>976e`ISe1165Jpc&9BW`Dw}C%aK~7%I^fR-0 z4WYF8`>k?G83_vy#Nqb#b$`{!QJ}tgDVX)Oxq{w%cOjEm!B?-8 z<(v(U0oDn2CooKvo70=;0$0~N2zaYX@a-PKBrpg#JPA!7uh>MZow>-GRlB=O@Q-ms zVV>G0*9P_X{v1R*LFY}GQ((a_C;Aege-4Ef#hKYWMy4p=vzP{{5Mn^~A0X9WztX3K2 z*JBN-ID+9Krw)^&rpzHkc4HjeaH*=gtrr!n==+`k_%&ztCV(1^GH(wQU3?PIKkxT$ zdc*cb+haPVwM<*WCCs0MQ@A>}H_vlgUj8v=Sfj`SAW&{cJI{}gEIzl^SWNmur%QE_ z5fRQuZ!2&gK_FO+x_!4cGmlD;W`p|40CZt9f~7Y=u%uqwq5`gCXKhdcE*y-Bm?|0*{Q0WYDe- zqE#<4X2H>SF|zvA(UDWOP^qe~65**tgc+`O1ppRN`%oESD0qVaws9)94LCaoLJMhS zwTzrlfB^TPQE#p^r5j|+LZ(Jd{XwVU57@_woOuVbviU?7@8{@`k6wPO%|mwd3RLLO zNCd`b%MJRS0ofVsR@d_@7ngyZ+9v3s`c%BDKkpX9x?<-v#D}}hG_pplOF*-NgytLZ zM0AoakLE*x3eo&NXK8Nt(%_3OnV2K!dp$%R&l33V2Ze|iqI>qM;tE7VL!;XDK&j*P zTE4Wj^asBuQ{eMV?%{F+y-l(5iZv3ZR(bnjbKN|YcBvx91;4`6Fh?O23oEF{3n%HCTLMt!mUkAm~vXX5FVu70)&z+Y%Xoe#cQad|?amFih zS6JquV^2&>JP?E18w?50w<}illrr==DY5w6Nhv8I-Nu_4Ryiimw?~gJFHLS?XV@3@ zQ*qt;sXjvQy2fAxe1R%1ts5s?CDGnMa3eW0oh=tNS3pq&ZN0A3#g1^jqm` z@UeZOu^3IScZVS$AevvM3BxF4_1nA>nLA&T3|c*=+kHI^1K-@K6n+F%rYZ>O(Vofd zE`W-y7zr$?0(na*;2+XRhp?!#m;fpI;P%=cQUxYn%$5Hal zSL2#;NX2MuUlB-Q3$Eah9lTEYQTV%ZFL9FrsxlB;(MtR5$jxfdy2cLQ-qOOSrmn8j z?!##{kwq#bloR;6L)_Qjzx1Sk|2w^94B6jF_s}xI;utP!$RJk&*g?Sj$X`A_V%dS< zb9&yz3fTUen3gWsxfA}#2q*GNAR_e3vtr9wY;qzl)2gE4=g;ixlMs5^MSs3KIe0yA znajVF7CFdFu&{O7O}^=;ib5u!bQ|Fb9*om?J_iLPqAwmucSi?@^wvLZZ^_8W*95P* z^4i+62>Cs#JV)9H8nIN|2s^}x(sO|?-1{s{prFrmof*7 z`cbUV^Y0`u)?kQ^gx?ute^l!Cnx-{7tqbJ%Jzr%~eR90e*&%Y8&*wE!*XyHXS8c z1P{dg+Et+gkWQ8lbGFg~gFCx`z^cRK8c|7E*$x1C%Ju&yp;IfdnD)V}`(6lc@9a$5 zHk=c!pE<|wqO6|mC0KBPz5^vh;cm~q7^4ag0jfwTdjvo${C*P1zgk*;rleqKR_OLW z-5g}_d?k}lXR^55>}Gn1U18vb7_^n(PYH7jVHm{;LnJdE0vSj!7Q-P+hI1{0>)A5re3jAUKrH^WHHW}eANp7(x3W#&A*po|K_isbsl;IYRBZ25 z$>H-N_#^VU@^s~!M%J)fGn-z8COR?kBz3M|&w9J>)8kIOtdf%DR!^wF>t!#I9vG!8 z+QCHjPBe1|2`_KP=B9BPgH8`nsPt}0H=4hGuh45^^ElOhez>>@LtW{%){=x144EXM zXRJf`3VwBhE&pX763+9Y7|PuWn?y6FFMSYYAx&+tH1R}W3#*N zD_}P_*neNL2a+uN=ei5}-cQw8DF@tSZm>8k*RT8>8>$^krPtE#3=p)NFW>rCC|_>W zxvm(}NLX3+e9uBiC6AUb^&O~Cug?!fbT2obdY8 z^pBE4wr6w{KDw1pbl8Id9^cz?u;ZMNzWN`Wxvbc%Eeis1@J5i3hGkZP^FjdK%p~a? zuheN*mx!U)7Ucd!_ULkh-BT~|y9f{zpP!Gz=SD-9YIkqIh8O$$_wUOktK7tljN!+t zozJDf<#pL5^dI8nLjD3{j+qCL}9|!YB!^$tVn#f>1G|es0$|Dwzxj*qvEk8!hj!GYr3fDz?@Yjn%8AKgFz9?e(iwZ;kx3+Fm@JcV)E&8z6> z41*&JbopMiTcsoG6sk37OKvN{JGeg6aL6KwqNJoba&4|F6Q_!%QA#*D1#gD~xQQ50 zDri?5ase7iK-NeCb9=Fo%e~>3oJ_4;>vp7;6Zq~;6!2(5_L5GR%D43?`|^A#q{Ob08F8l2bZ9bU<(<^|)M2gy=)0a5`}e;bJ)F zz(Y)?QX~TkS~kCDt;?PqkXrldCWS_Khm$X~1#G!8dEJjO$}}rXfyi?^TTcCWo%}GL zFV{Is3iqRiN0dX3EiI+H^=X&y-Q+5EagJV@KW^kN4nR9lT=$L$aW92#l2D)5aS zz=vncC9g_Yc$;gU8y3JN3O_j_(~SZ$fJFA!e%&FAe)$NDa7F9`r4}J+wNkGaz$-Vi z>dLG@1Osb6Nc{0A4djDK0Od3Xyzz~uF_JSf#sY{?==D;3AfEW5ejdt`%+17vG&D5y zcTo{nVaomCbT6%$GeTU$jQgg6D{|t}ur-2s;Oo_3NN8w{*Oh6&)2I;|8d}dtD!opJ zAMZ?&qAOm;xFtI#CT0auQ{YEH8l&ER5^qhJR);)=wDiK1qsT&~f%jR%!qE7*1%QPF z9yh-$EmUAd7s_5Q1_MPQMyg;OUMJineb+fM^gM(d1p>6)@S^s*;_hVO=4Im}2bki_ zIA$iM0drelJV)Q{{rstWSAw5QaVhF2wANYd!;qOtmX?;+1NcrVhK7zeyh1`kOvB1G zc7Oh%(AHBER?djEqExa#0JSji<7LC#!eYtYu*$GqzYa6YfPcJ2%!Oxhx(NL~)R|Dy z$A`}-@U3BO=O>3vlKct0gK0t;g)}umcpYpz0Bx_YuTS}kJulYBvUq1WCpR96m6nrw zSj9Z?tiw0$;T>wUd3LzCmy#q5V_J257trBGPXwN!i_dHz+TqJl-}G8&qY9{NfZz+QG9rDJsIs>=`OX%v2qVb~$W4KwMR z+JBc3?b6p(T8f;(nKT$sa}cYz>26Y12K3S?DCkBT=H9qCTz1RLm5ukb&bKos3{1?m zE1t5sW4EUnw9_<#VE?4vZ~AfbZ&Uxv+m+6rooec*=456|ru!vk-u{FGRcu8g-HdZC zp~)NH9dZO4mB$n&%tTy7gL7@gYm03`v!d7Q3U0Ml{L58$!J#@5dc$RnUgeRFb71oj*o8{22?nwy&&k7LgqcO4`fy=7>i!RtC|_%r0^qXmvhgcD~Decl)oAOZg*ll(*$b(m;A4j>%}$;D9hAFEwbQULsAlY=mBp}M5eI(t6dZG7Ob1wD zlTEmmRW~NqbNG~P1EUnknnm8(=pIT6Mc{$1^`O|sxFp$aN_{5%buHKOr0(2*oel|6Q(|=dEnV6NCNrZ4S z+~S}1Zy$JzKgA#=%w=6(?`$n4_jdGCM9$%%n!w;(`Cl`46C9AsIhf$Gj~iV%cx6!_ zBpUD>oJo2ZvBc~1T-!c@@;(RSErcow&=Z<{4;aFtw{6eayee?SY8hdhTjH&7l(;~8 zU4(V$+(kJZX>lDxJ_BKxqf%I?R1Xk9{8O`$MY2hVx_lgDQI`6=ojI?wxAR@OiHTbf zw>Cz30cQ3&GZy1SUM^9vTw`N~p}tr?Za^|mTGKzBh*z}#NP%Ilh-&l*6EDVSW4$6^ zxOOgTFD*?ozX{v6z4Ayv=d(qC(%$|{?ax&8PuoPsc}pj7u|}JQrulV8ri>0@_Vq8V_P*9;DkUrJ=8z4Z!Y+Epw!MQColg5=o_e#i9qtdnGAeSt}z?r^B1_+ET?gD zvhw9!hRsi(=TZ)#;i#(zZq~km3;**+GET7E8V1n=Mf0*)=J)`Sj&&E;B3$?jZti{3??!D zQ|dV1Zd9?r>AL3)reBe#NQLgyeup&}M`(Aqc+vTh0}OtEJkqh)w7uo*Vcd@j5lf`B zVe~=J8PJ|7#BR{4G`Dn9@h&3K0C!QHQ1sC>KT8LiruWSCqt^9j=u&%6u%MD~D;ki0 zJ3rno+TQM0W|yl!6ciN^v6&6sx`)j9lU72C0_{V;f5U{H_-8wHcc`RoDwaH-%BVS_ zTtwQiABzIv#;Q8b;WGSAKD&=e5<%u3+7Czwe$jf$5*zHxd1UfdJ*imFD^8tz6;12; z6LC@(mA<}K|lj;7CU{L5ZB{Cof39q5vPs3 zr)2oc@m@@N?cc}ALLkqXjZCN}rQ&U3Vg);0E zavk!hP|Zk>20oAFd=(T3h*&()3dd3r&;&|c{|g+T-A+=X0b`3fr&XzHq#s2>xAj%D zP;KI`yXr#qpy#ctGMa!8QL3lwM(N?6K8>*D6x-?!Ke>rY|;`pZs0)IA=jSV&Z)1$Do{;;a(uq-CxK)G~N;WEhy_ z+1c8jCgB4xtnK~zgz4<3d2*yCPDLMDmYlU7rCYD1py%rezd}m|u1gcqL7EyF^k&qQ zr?xhZp`jt8egd>s%5duiUZndyXD`EmS!egg zY|SzU^^Fz)C^6|bcU2m+e%||^KYvov(w1Kl81<}QD8o1Pn+%GB9pU++q%Bt(9sDl4 zp$P) z%~aeMe{RHb^!u)4EGdbJ4prT9=!%39bb2#0CkYzdqfLF?J6rk)(d?>{NR2^;c|9PwslZKbzt#qeXLKGQ!S zHx2N2yiaEHOIui2)J-Bl^%8P-G(mQEcPsp0*}6~B@O_)IrM5eq5XsvCDz{;sB_crJ zYhDBb0|VXo2n!1fJ+iS;P`WMLv@VTlZq(W%Vsv z_;$MmrhhXtdV)-(q+48ImR43Pvt9!$E19y%R9Ao+!0xcju@V4rzw1&m2jlVMPznCb zv^i?3mLWMQ>0fC&8692JU)KY!moeLhTH86gsOabmuN=)Xi?JW93_7(TysrD37Z*-5 z&E<%h0!v{7aXJ%?Q`yci6V;zX{QMa;ZEZf1LaUg&FgxqKH)}#wb371uct2(U8m6=mtM2{7Z8+0f-Kufclj zO!sM)qT*JTN}B}Rn@Azx>^c#N>eqhL?VevFr=Kv7K&?ZAB_fVr*1AZ1`RRp5Kw7_K zPen@`Dg3&HoW4uM`}0r$PBN2@ zzn(5lC14nq=68W1RW-=`-MdB-0hZJ+_i2tyYE;h%0L+npK^Y*0KwZu<=%w3$ThZzY zF#dWL8=PKQ`C6){b8JI)pfu=YyrG2a0?lKZ=j!U}4W#C$+Zp9EN0ONceupy;`f^SB zI?Hj>>3m79@HPvbeSJ-=+)7>9>m`ogq;D`;Eb6dfG8MNnHVLSl+;9Md3@x%?)K3uOvsPy2@HDWAF5xeTnzzYP~+w>NOIfkO?$orw=)v6tk z8@S;pHgVt*lR=UZ#jQ~t?!@K0U^gX=lM9z`bphXI0o}ieQsDDQ&HV&yg@MQY2cidS zprO(Ca?v>nP3-5quo=d$qG~wt**Dbr$E}Zi-ye8y9t{5KKviqrsPdIB`E{2N=uJvD z>beHS2U*Za)hb$7b;%)C6Y+qw0q)StWIOr=cV=Zl#lF>}N91GA8_wBCez7D9Bx0d4 ze5bbV^R?EqWsi!Q`-^bL=6f**MaEXoi|qpDg(Rkhyj-57gv*4qm4-JI!1$Ts`aKxv zuJF1cl>Hfiv4?m^${GOmo<>{dSNnndin&OpSJ7E6!~ddkw^!By*gk04egg)~*?5hx z)p4G&NHb8-IUkS!*Bms8Try%sO?i+u2c<6y&H)p!#WlQ(bYD@V7?>ZevpdjP+ z5C&;>@T5{ zSz?!fX*8gZZ8tmw=v4qZ-*vd~>o-Qd#?>@yr%CtD_h&nx&G)#_`7YTR@U|>40e>)g zb5xp2VUab!){GqXm0i__qk{R-IsyC6a%A#%VtO0+&fn-EOv_QLO z22RdYKq^lHdRA}302&|6Wvzri*?KsSapPnhXv>WE4^ z{N|Xw03+;$eBXgIm3V-4p1hpg(D1O$f-eUZHXxiV&Gog_<_C{&1dJAEcJBWa4gc^@ zhGB(RtltFhr&|Cdlq{DYJ%qHgn5o(-^ItAN_(4`YSzJ&mM;epAsdp&{RRP9<1$fVM zeD#c+Lby!Uj0D(%X^s%73yb>Sc|Z#U=p%TXX}VJ%-ua-Rqkk48K(wsQ7;|rEI9+Q^ zkDssHs-FuHGT|Xb&1+_?H%L&C9$&i@@Wj89Z)WNny=!VcY9G)Gd;5tx~ofi}RPJac;=(8+L6s+CUr3s8zt zt*Y%zc4`*nQ^hWv6>PsL5@xwknq}Vzz>{0TOv?^V+qKd~^s8eong{e;;WAzIHJ%wf zvmBU4IL|X;y~LbCq+DPcBhAivamiqM9N>k4es61887Cg%)zwwo?LYa|z>hZwD5zyW zN6`Qwz{G=@d$A^KqX7YmJkh0fV3w}b_%v5@9!J`j#ubbSORso?QuK$Q~UR5I4LbHr=X?H zDBQ3oS=qq<$UujIUi%nhk32LGJCAvvLwKR(i6)ZT zbkTQF*(si#NVX!!l(l^cWXxlrf z^oz-vv9^yS!M;)}`|^%KBvIOSwzT{nQLl{re<cJ_98Q8_+7wSEZ-d#Q_X+668SBohVL&Y8)S0jE;wan*{nwjDdSy zmfsFNsAXyXr`J+}%i=0hRTwv#syL?pgt~tWa|2zaK+D_B8tq3jmk;g63151-5MfOW}s{~+epqnr!$zX(}c^W1L)mnMoWRj4kaNB8q zDWGT-$h*Emg25Bax_l|hk9KTDuqk&f8)^xnIuk%fChUig#zG}TpD7ZpGHAsrm>vQ; zqKic*GD#B4N9=y}E|9I224Vz4D4jXeBOQkxC{OcnC);n~H5zz!L5wul+cZ;K&l)`J zD-%mJV2$9^7SV;#fQQ1j{|G^qEAuK2LHulIhv$!lB++9?IO%N^+1)i{qvIpqpAnf! zB37i)gqRqFWcPX_Mb?0p5#kz`PzELQ0DF% zl5C-Lq-L$Bq&<5vPOL2Q6bf~VKy7j^iX-1C3xbBwgDtF&wjO}4^tGHbUf(A8KiznucAAz}tkW z2G`M?OHb+7%u=|iWMmki=fH_2{pC=}qa#&uBZ`eL{w+OfmvPwKKQQGS6*VL@eC0H9 zXlx8<6%8Q9kNwX76 z;`%kz*x>a`c?oruKEzRiRc`$ZcF8oB!=Qb=eOseNj!W+{4o18J2tJ!2tpreqT%6hw zd70(vZ~sp1ZcnGdKZ54*Q7p~PRSXQqOH>PV1?Tmh_PaXXUeC|Cb-bT(id4U|BH+g? z53W>Np-7-c*Zj;E3~z3{rl(UXl2>bgqPaApN$e z^EJa}?9Yi$N%bi}I5G&JTWe+NgsGY$;rJE?gnO!Hbfq-LfC@POeWA14i&C)v+u?eJ zUi5iWozeXNfmD}Niln!#!~68$~tr1TU= z<6O9j8M?;qDx;ZuBJ3$Xg*mqXDv4?sK|15S^Gw5u>K-+_hMNC(?%x$`5^2+icZWU? z6j~`V&-Z#vgu=2K>6Ia2VO%o{85tRXsfz{R^Oor}jI<_u0Kq-)4g4xn*====<5$p1 z9?{7BxM>NV4j8Y7bpFOg)z@h**$c(gZu%lOPY6;l>-NNdn*xfZJPjMgq^>%;p8LI@ z^Ot!^4L+x~9S_%jq0Rcg#d84DFxcnXrAVtTv zNlD31XZ%hzyv+D$Qm9j%@oQ$PyP=`i>PPx|PneRvNTz>EC#1f1zZs=8>JkywIx@d% z!>mQ3{&yRqgYnfa-7O97X_@n*u z=`_sDR%3_L1c1Ns!~4aFK{(*YaUwV?0Bh^eK~SI!?V7c$ywwhD|!p+x31)_NeI=`;tSkQ;_<(S zG%UoMp5{qlhLS?A)VM4FOUfTMG#-Dlckq{``SJJgbi0yjCgBXFfNP}~Y$k3^?GJqI zPz?{$)I9M=Bi&^iC-ngGQxzYO8>l;FajY{SA(}?FNJ^Dh5yS0q3DzV zC=ilMst;P)zGQr`YXo@4WKjqi`G{=5!4xGD23Al972}s7lTP{o&}!xmva4`j`$2DH`mJk!-ucq@c9Q0FI4c}g?LnRJ6q z%i|O9(~nK`PhZt zoxfq6-JgE00(G8)GzbgvBV_QDGBG+O@NiO_LwO|xmzu9AikS0%5HaVq1Uh?`fx~gu zFVpakw4Z0c#1Y8DP%Xy`DC zSwUJd32HEQ;>3G#hQIY9pXrQE0IVVEm1+$$KnTr>RPmgk3XXywyJ589cj+xx%l5>tRUMO z3tZx{h?~J&!ez7N0LHFMI9MnZx^mCoKt=IoNc}?C(bIx1jPwXT30{l}Aqzb2gWnVG z-$8igVZgIL1QU#Dkvv=sy26+2nU78sBt)Z@uQXd?AzG29s>Ztk?bGb*{6P0EJfaW* z9dV}D4V-4Bbd%I}GdFRw;4^cv0A4`YSXg-(Sw8=1uyXRTaPe_))3dPgv9Q!!YE1t> z7dSYX+gN)4|1apOICTIn(DKpHc2hI)Byo0evb3?cAaV0{wji-_b~6J3@ygn{Mu7RM zNkcQDJUS-3rv?H}4$ou;k4}y*pNs*HP9hP+(Q6J)UZ+7ax;Q)3H`Yhc2R#}j^Gl8i Z - - - - - - - -Articles • rio - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - - - -
- -
-
- - -
-

All vignettes

-

- -
-
Import, Export, and Convert Data Files
-
-
-
-
-
- - -
- - -
-

Site built with pkgdown 1.5.1.

-
- -
-
- - - - - - - - diff --git a/docs/articles/rio.html b/docs/articles/rio.html deleted file mode 100644 index 4c07687..0000000 --- a/docs/articles/rio.html +++ /dev/null @@ -1,531 +0,0 @@ - - - - - - - -Import, Export, and Convert Data Files • rio - - - - - - - - - - - - - - - - - -
-
- - - - -
-
- - - - -
-

-Import, Export, and Convert Data Files

-

The idea behind rio is to simplify the process of importing data into R and exporting data from R. This process is, probably unnecessarily, extremely complex for beginning R users. Indeed, R supplies an entire manual describing the process of data import/export. And, despite all of that text, most of the packages described are (to varying degrees) out-of-date. Faster, simpler, packages with fewer dependencies have been created for many of the file types described in that document. rio aims to unify data I/O (importing and exporting) into two simple functions: import() and export() so that beginners (and experienced R users) never have to think twice (or even once) about the best way to read and write R data.

-

The core advantage of rio is that it makes assumptions that the user is probably willing to make. Specifically, rio uses the file extension of a file name to determine what kind of file it is. This is the same logic used by Windows OS, for example, in determining what application is associated with a given file type. By taking away the need to manually match a file type (which a beginner may not recognize) to a particular import or export function, rio allows almost all common data formats to be read with the same function.

-

By making import and export easy, it’s an obvious next step to also use R as a simple data conversion utility. Transferring data files between various proprietary formats is always a pain and often expensive. The convert function therefore combines import and export to easily convert between file formats (thus providing a FOSS replacement for programs like Stat/Transfer or Sledgehammer).

-
-

-Supported file formats

-

rio supports a variety of different file formats for import and export. To keep the package slim, all non-essential formats are supported via “Suggests” packages, which are not installed (or loaded) by default. To ensure rio is fully functional, install these packages the first time you use rio via:

- -

The full list of supported formats is below:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FormatTypical ExtensionImport PackageExport PackageInstalled by Default
Comma-separated data.csvdata.tabledata.tableYes
Pipe-separated data.psvdata.tabledata.tableYes
Tab-separated data.tsvdata.tabledata.tableYes
CSVY (CSV + YAML metadata header).csvydata.tabledata.tableYes
SAS.sas7bdathavenhavenYes
SPSS.savhavenhavenYes
SPSS (compressed).zsavhavenhavenYes
Stata.dtahavenhavenYes
SAS XPORT.xpthavenhavenYes
SPSS Portable.porhavenYes
Excel.xlsreadxlYes
Excel.xlsxreadxlopenxlsxYes
R syntax.RbasebaseYes
Saved R objects.RData, .rdabasebaseYes
Serialized R objects.rdsbasebaseYes
Epiinfo.recforeignYes
Minitab.mtpforeignYes
Systat.sydforeignYes
“XBASE” database files.dbfforeignforeignYes
Weka Attribute-Relation File Format.arffforeignforeignYes
Data Interchange Format.difutilsYes
Fortran datano recognized extensionutilsYes
Fixed-width format data.fwfutilsutilsYes
gzip comma-separated data.csv.gzutilsutilsYes
Apache Arrow (Parquet).parquetarrowarrowNo
EViews.wf1hexViewNo
Feather R/Python interchange format.featherfeatherfeatherNo
Fast Storage.fstfstfstNo
JSON.jsonjsonlitejsonliteNo
Matlab.matrmatiormatioNo
OpenDocument Spreadsheet.odsreadODSreadODSNo
HTML Tables.htmlxml2xml2No
Shallow XML documents.xmlxml2xml2No
YAML.ymlyamlyamlNo
Clipboarddefault is tsvcliprcliprNo
Google Sheetsas Comma-separated data
-

Additionally, any format that is not supported by rio but that has a known R implementation will produce an informative error message pointing to a package and import or export function. Unrecognized formats will yield a simple “Unrecognized file format” error.

-
-
-

-Data Import

-

rio allows you to import files in almost any format using one, typically single-argument, function. import() infers the file format from the file’s extension and calls the appropriate data import function for you, returning a simple data.frame. This works for any for the formats listed above.

-
library("rio")
-
-x <- import("mtcars.csv")
-y <- import("mtcars.rds")
-z <- import("mtcars.dta")
-
-# confirm identical
-all.equal(x, y, check.attributes = FALSE)
-
## [1] TRUE
-
all.equal(x, z, check.attributes = FALSE)
-
## [1] TRUE
-

If for some reason a file does not have an extension, or has a file extension that does not match its actual type, you can manually specify a file format to override the format inference step. For example, we can read in a CSV file that does not have a file extension by specifying csv:

-
head(import("mtcars_noext", format = "csv"))
-
##    mpg cyl disp  hp drat    wt  qsec vs am gear carb
-## 1 21.0   6  160 110 3.90 2.620 16.46  0  1    4    4
-## 2 21.0   6  160 110 3.90 2.875 17.02  0  1    4    4
-## 3 22.8   4  108  93 3.85 2.320 18.61  1  1    4    1
-## 4 21.4   6  258 110 3.08 3.215 19.44  1  0    3    1
-## 5 18.7   8  360 175 3.15 3.440 17.02  0  0    3    2
-## 6 18.1   6  225 105 2.76 3.460 20.22  1  0    3    1
-
-

-Importing Data Lists

-

Sometimes you may have multiple data files that you want to import. import() only ever returns a single data frame, but import_list() can be used to import a vector of file names into R. This works even if the files are different formats:

- -

Similarly, some single-file formats (e.g. Excel Workbooks, Zip directories, HTML files, etc.) can contain multiple data sets. Because import() is type safe, always returning a data frame, importing from these formats requires specifying a which argument to import() to dictate which data set (worksheet, file, table, etc.) to import (the default being which = 1). But import_list() can be used to import all (or only a specified subset, again via which) of data objects from these types of files.

-
-
-
-

-Data Export

-

The export capabilities of rio are somewhat more limited than the import capabilities, given the availability of different functions in various R packages and because import functions are often written to make use of data from other applications and it never seems to be a development priority to have functions to export to the formats used by other applications. That said, rio currently supports the following formats:

-
library("rio")
-
-export(mtcars, "mtcars.csv")
-export(mtcars, "mtcars.rds")
-export(mtcars, "mtcars.dta")
-

It is also easy to use export() as part of an R pipeline (from magrittr or dplyr). For example, the following code uses export() to save the results of a simple data transformation:

-
library("magrittr")
-mtcars %>% subset(hp > 100) %>%  aggregate(. ~ cyl + am, data = ., FUN = mean) %>% export(file = "mtcars2.dta")
-

Some file formats (e.g., Excel workbooks, Rdata files) can support multiple data objects in a single file. export() natively supports output of multiple objects to these types of files:

-
# export to sheets of an Excel workbook
-export(list(mtcars = mtcars, iris = iris), "multi.xlsx")
-
# export to an .Rdata file
-## as a named list
-export(list(mtcars = mtcars, iris = iris), "multi.rdata")
-
-## as a character vector
-export(c("mtcars", "iris"), "multi.rdata")
-

It is also possible to use the new (as of v0.6.0) function export_list() to write a list of data frames to multiple files using either a vector of file names or a file pattern:

-
export_list(list(mtcars = mtcars, iris = iris), "%s.tsv")
-
-
-

-File Conversion

-

The convert() function links import() and export() by constructing a dataframe from the imported file and immediately writing it back to disk. convert() invisibly returns the file name of the exported file, so that it can be used to programmatically access the new file.

-

Because convert() is just a thin wrapper for import() and export(), it is very easy to use. For example, we can convert

-
# create file to convert
-export(mtcars, "mtcars.dta")
-
-# convert Stata to SPSS
-convert("mtcars.dta", "mtcars.sav")
-

convert() also accepts lists of arguments for controlling import (in_opts) and export (out_opts). This can be useful for passing additional arguments to import or export methods. This could be useful, for example, for reading in a fixed-width format file and converting it to a comma-separated values file:

-
# create an ambiguous file
-fwf <- tempfile(fileext = ".fwf")
-cat(file = fwf, "123456", "987654", sep = "\n")
-
-# see two ways to read in the file
-identical(import(fwf, widths = c(1,2,3)), import(fwf, widths = c(1,-2,3)))
-
## [1] FALSE
-
# convert to CSV
-convert(fwf, "fwf.csv", in_opts = list(widths = c(1,2,3)))
-import("fwf.csv") # check conversion
-
##   V1 V2  V3
-## 1  1 23 456
-## 2  9 87 654
-

With metadata-rich file formats (e.g., Stata, SPSS, SAS), it can also be useful to pass imported data through characterize() or factorize() when converting to an open, text-delimited format: characterize() converts a single variable or all variables in a data frame that have “labels” attributes into character vectors based on the mapping of values to value labels (e.g., export(characterize(import("file.dta")), "file.csv")). An alternative approach is exporting to CSVY format, which records metadata in a YAML-formatted header at the beginning of a CSV file.

-

It is also possible to use rio on the command-line by calling Rscript with the -e (expression) argument. For example, to convert a file from Stata (.dta) to comma-separated values (.csv), simply do the following:

-
Rscript -e "rio::convert('mtcars.dta', 'mtcars.csv')"
-
-
-

-Package Philosophy

-

The core advantage of rio is that it makes assumptions that the user is probably willing to make. Eight of these are important:

-
    -
  1. -rio uses the file extension of a file name to determine what kind of file it is. This is the same logic used by Windows OS, for example, in determining what application is associated with a given file type. By removing the need to manually match a file type (which a beginner may not recognize) to a particular import or export function, rio allows almost all common data formats to be read with the same function. And if a file extension is incorrect, users can force a particular import method by specifying the format argument. Other packages do this as well, but rio aims to be more complete and more consistent than each:
  2. -
-
    -
  • -reader handles certain text formats and R binary files
  • -
  • -io offers a set of custom formats
  • -
  • -ImportExport focuses on select binary formats (Excel, SPSS, and Access files) and provides a Shiny interface.
  • -
  • -SchemaOnRead iterates through a large number of possible import methods until one works successfully
  • -
-
    -
  1. rio uses data.table::fread() for text-delimited files to automatically determine the file format regardless of the extension. So, a CSV that is actually tab-separated will still be correctly imported. It’s also crazy fast.

  2. -
  3. rio, wherever possible, does not import character strings as factors.

  4. -
  5. rio supports web-based imports natively, including from SSL (HTTPS) URLs, from shortened URLs, from URLs that lack proper extensions, and from (public) Google Documents Spreadsheets.

  6. -
  7. rio imports from from single-file .zip and .tar archives automatically, without the need to explicitly decompress them. Export to compressed directories is also supported.

  8. -
  9. rio wraps a variety of faster, more stream-lined I/O packages than those provided by base R or the foreign package. It uses data.table for delimited formats, haven for SAS, Stata, and SPSS files, smarter and faster fixed-width file import and export routines, and readxl and openxlsx for reading and writing Excel workbooks.

  10. -
  11. -

    rio stores metadata from rich file formats (SPSS, Stata, etc.) in variable-level attributes in a consistent form regardless of file type or underlying import function. These attributes are identified as:

    -
      -
    • -label: a description of variable
    • -
    • -labels: a vector mapping numeric values to character strings those values represent
    • -
    • -format: a character string describing the variable storage type in the original file
    • -
    -

    The gather_attrs() function makes it easy to move variable-level attributes to the data frame level (and spread_attrs() reverses that gathering process). These can be useful, especially, during file conversion to more easily modify attributes that are handled differently across file formats. As an example, the following idiom can be used to trim SPSS value labels to the 32-character maximum allowed by Stata:

    -
    dat <- gather_attrs(rio::import("data.sav"))
    -attr(dat, "labels") <- lapply(attributes(dat)$labels, function(x) {
    -    if (!is.null(x)) {
    -        names(x) <- substring(names(x), 1, 32)
    -    }
    -    x
    -})
    -export(spread_attrs(dat), "data.dta")
    -

    In addition, two functions (added in v0.5.5) provide easy ways to create character and factor variables from these “labels” attributes. characterize() converts a single variable or all variables in a data frame that have “labels” attributes into character vectors based on the mapping of values to value labels. factorize() does the same but returns factor variables. This can be especially helpful for converting these rich file formats into open formats (e.g., export(characterize(import("file.dta")), "file.csv").

    -
  12. -
  13. rio imports and exports files based on an internal S3 class infrastructure. This means that other packages can contain extensions to rio by registering S3 methods. These methods should take the form .import.rio_X() and .export.rio_X(), where X is the file extension of a file type. An example is provided in the rio.db package.

  14. -
-
-
-
- - - -
- - - -
- -
-

Site built with pkgdown 1.5.1.

-
- -
-
- - - - - - diff --git a/docs/articles/rio_files/accessible-code-block-0.0.1/empty-anchor.js b/docs/articles/rio_files/accessible-code-block-0.0.1/empty-anchor.js deleted file mode 100644 index ca349fd..0000000 --- a/docs/articles/rio_files/accessible-code-block-0.0.1/empty-anchor.js +++ /dev/null @@ -1,15 +0,0 @@ -// Hide empty tag within highlighted CodeBlock for screen reader accessibility (see https://github.com/jgm/pandoc/issues/6352#issuecomment-626106786) --> -// v0.0.1 -// Written by JooYoung Seo (jooyoung@psu.edu) and Atsushi Yasumoto on June 1st, 2020. - -document.addEventListener('DOMContentLoaded', function() { - const codeList = document.getElementsByClassName("sourceCode"); - for (var i = 0; i < codeList.length; i++) { - var linkList = codeList[i].getElementsByTagName('a'); - for (var j = 0; j < linkList.length; j++) { - if (linkList[j].innerHTML === "") { - linkList[j].setAttribute('aria-hidden', 'true'); - } - } - } -}); diff --git a/docs/authors.html b/docs/authors.html deleted file mode 100644 index 74c7228..0000000 --- a/docs/authors.html +++ /dev/null @@ -1,227 +0,0 @@ - - - - - - - - -Citation and Authors • rio - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - - - -
- -
-
- - -

Chung-hong Chan, Geoffrey CH Chan, Thomas J. Leeper, and Jason Becker (2021). rio: A Swiss-army knife for data file I/O. R package version 0.5.26.

-
@Manual{,
-  title = {rio: A Swiss-army knife for data file I/O},
-  author = {Chung-hong Chan and Geoffrey CH Chan and Thomas J. Leeper and Jason Becker},
-  year = {2021},
-  note = {R package version 0.5.26},
-}
- - - -
    -
  • -

    Jason Becker. Contributor. -

    -
  • -
  • -

    Chung-hong Chan. Author. -

    -
  • -
  • -

    Geoffrey CH Chan. Contributor. -

    -
  • -
  • -

    Thomas J. Leeper. Author, maintainer. -

    -
  • -
  • -

    Christopher Gandrud. Contributor. -

    -
  • -
  • -

    Andrew MacDonald. Contributor. -

    -
  • -
  • -

    Ista Zahn. Contributor. -

    -
  • -
  • -

    Stanislaus Stadlmann. Contributor. -

    -
  • -
  • -

    Ruaridh Williamson. Contributor. -

    -
  • -
  • -

    Patrick Kennedy. Contributor. -

    -
  • -
  • -

    Ryan Price. Contributor. -

    -
  • -
  • -

    Trevor L Davis. Contributor. -

    -
  • -
  • -

    Nathan Day. Contributor. -

    -
  • -
  • -

    Bill Denney. Contributor. -

    -
  • -
  • -

    Alex Bokov. Contributor. -

    -
  • -
- -
- -
- - - -
- - -
-

Site built with pkgdown 1.5.1.

-
- -
-
- - - - - - - - diff --git a/docs/bootstrap-toc.css b/docs/bootstrap-toc.css deleted file mode 100644 index 5a85941..0000000 --- a/docs/bootstrap-toc.css +++ /dev/null @@ -1,60 +0,0 @@ -/*! - * Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/) - * Copyright 2015 Aidan Feldman - * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */ - -/* modified from https://github.com/twbs/bootstrap/blob/94b4076dd2efba9af71f0b18d4ee4b163aa9e0dd/docs/assets/css/src/docs.css#L548-L601 */ - -/* All levels of nav */ -nav[data-toggle='toc'] .nav > li > a { - display: block; - padding: 4px 20px; - font-size: 13px; - font-weight: 500; - color: #767676; -} -nav[data-toggle='toc'] .nav > li > a:hover, -nav[data-toggle='toc'] .nav > li > a:focus { - padding-left: 19px; - color: #563d7c; - text-decoration: none; - background-color: transparent; - border-left: 1px solid #563d7c; -} -nav[data-toggle='toc'] .nav > .active > a, -nav[data-toggle='toc'] .nav > .active:hover > a, -nav[data-toggle='toc'] .nav > .active:focus > a { - padding-left: 18px; - font-weight: bold; - color: #563d7c; - background-color: transparent; - border-left: 2px solid #563d7c; -} - -/* Nav: second level (shown on .active) */ -nav[data-toggle='toc'] .nav .nav { - display: none; /* Hide by default, but at >768px, show it */ - padding-bottom: 10px; -} -nav[data-toggle='toc'] .nav .nav > li > a { - padding-top: 1px; - padding-bottom: 1px; - padding-left: 30px; - font-size: 12px; - font-weight: normal; -} -nav[data-toggle='toc'] .nav .nav > li > a:hover, -nav[data-toggle='toc'] .nav .nav > li > a:focus { - padding-left: 29px; -} -nav[data-toggle='toc'] .nav .nav > .active > a, -nav[data-toggle='toc'] .nav .nav > .active:hover > a, -nav[data-toggle='toc'] .nav .nav > .active:focus > a { - padding-left: 28px; - font-weight: 500; -} - -/* from https://github.com/twbs/bootstrap/blob/e38f066d8c203c3e032da0ff23cd2d6098ee2dd6/docs/assets/css/src/docs.css#L631-L634 */ -nav[data-toggle='toc'] .nav > .active > ul { - display: block; -} diff --git a/docs/bootstrap-toc.js b/docs/bootstrap-toc.js deleted file mode 100644 index 1cdd573..0000000 --- a/docs/bootstrap-toc.js +++ /dev/null @@ -1,159 +0,0 @@ -/*! - * Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/) - * Copyright 2015 Aidan Feldman - * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */ -(function() { - 'use strict'; - - window.Toc = { - helpers: { - // return all matching elements in the set, or their descendants - findOrFilter: function($el, selector) { - // http://danielnouri.org/notes/2011/03/14/a-jquery-find-that-also-finds-the-root-element/ - // http://stackoverflow.com/a/12731439/358804 - var $descendants = $el.find(selector); - return $el.filter(selector).add($descendants).filter(':not([data-toc-skip])'); - }, - - generateUniqueIdBase: function(el) { - var text = $(el).text(); - var anchor = text.trim().toLowerCase().replace(/[^A-Za-z0-9]+/g, '-'); - return anchor || el.tagName.toLowerCase(); - }, - - generateUniqueId: function(el) { - var anchorBase = this.generateUniqueIdBase(el); - for (var i = 0; ; i++) { - var anchor = anchorBase; - if (i > 0) { - // add suffix - anchor += '-' + i; - } - // check if ID already exists - if (!document.getElementById(anchor)) { - return anchor; - } - } - }, - - generateAnchor: function(el) { - if (el.id) { - return el.id; - } else { - var anchor = this.generateUniqueId(el); - el.id = anchor; - return anchor; - } - }, - - createNavList: function() { - return $(''); - }, - - createChildNavList: function($parent) { - var $childList = this.createNavList(); - $parent.append($childList); - return $childList; - }, - - generateNavEl: function(anchor, text) { - var $a = $(''); - $a.attr('href', '#' + anchor); - $a.text(text); - var $li = $('
  • '); - $li.append($a); - return $li; - }, - - generateNavItem: function(headingEl) { - var anchor = this.generateAnchor(headingEl); - var $heading = $(headingEl); - var text = $heading.data('toc-text') || $heading.text(); - return this.generateNavEl(anchor, text); - }, - - // Find the first heading level (`

    `, then `

    `, etc.) that has more than one element. Defaults to 1 (for `

    `). - getTopLevel: function($scope) { - for (var i = 1; i <= 6; i++) { - var $headings = this.findOrFilter($scope, 'h' + i); - if ($headings.length > 1) { - return i; - } - } - - return 1; - }, - - // returns the elements for the top level, and the next below it - getHeadings: function($scope, topLevel) { - var topSelector = 'h' + topLevel; - - var secondaryLevel = topLevel + 1; - var secondarySelector = 'h' + secondaryLevel; - - return this.findOrFilter($scope, topSelector + ',' + secondarySelector); - }, - - getNavLevel: function(el) { - return parseInt(el.tagName.charAt(1), 10); - }, - - populateNav: function($topContext, topLevel, $headings) { - var $context = $topContext; - var $prevNav; - - var helpers = this; - $headings.each(function(i, el) { - var $newNav = helpers.generateNavItem(el); - var navLevel = helpers.getNavLevel(el); - - // determine the proper $context - if (navLevel === topLevel) { - // use top level - $context = $topContext; - } else if ($prevNav && $context === $topContext) { - // create a new level of the tree and switch to it - $context = helpers.createChildNavList($prevNav); - } // else use the current $context - - $context.append($newNav); - - $prevNav = $newNav; - }); - }, - - parseOps: function(arg) { - var opts; - if (arg.jquery) { - opts = { - $nav: arg - }; - } else { - opts = arg; - } - opts.$scope = opts.$scope || $(document.body); - return opts; - } - }, - - // accepts a jQuery object, or an options object - init: function(opts) { - opts = this.helpers.parseOps(opts); - - // ensure that the data attribute is in place for styling - opts.$nav.attr('data-toggle', 'toc'); - - var $topContext = this.helpers.createChildNavList(opts.$nav); - var topLevel = this.helpers.getTopLevel(opts.$scope); - var $headings = this.helpers.getHeadings(opts.$scope, topLevel); - this.helpers.populateNav($topContext, topLevel, $headings); - } - }; - - $(function() { - $('nav[data-toggle="toc"]').each(function(i, el) { - var $nav = $(el); - Toc.init($nav); - }); - }); -})(); diff --git a/docs/docsearch.css b/docs/docsearch.css deleted file mode 100644 index e5f1fe1..0000000 --- a/docs/docsearch.css +++ /dev/null @@ -1,148 +0,0 @@ -/* Docsearch -------------------------------------------------------------- */ -/* - Source: https://github.com/algolia/docsearch/ - License: MIT -*/ - -.algolia-autocomplete { - display: block; - -webkit-box-flex: 1; - -ms-flex: 1; - flex: 1 -} - -.algolia-autocomplete .ds-dropdown-menu { - width: 100%; - min-width: none; - max-width: none; - padding: .75rem 0; - background-color: #fff; - background-clip: padding-box; - border: 1px solid rgba(0, 0, 0, .1); - box-shadow: 0 .5rem 1rem rgba(0, 0, 0, .175); -} - -@media (min-width:768px) { - .algolia-autocomplete .ds-dropdown-menu { - width: 175% - } -} - -.algolia-autocomplete .ds-dropdown-menu::before { - display: none -} - -.algolia-autocomplete .ds-dropdown-menu [class^=ds-dataset-] { - padding: 0; - background-color: rgb(255,255,255); - border: 0; - max-height: 80vh; -} - -.algolia-autocomplete .ds-dropdown-menu .ds-suggestions { - margin-top: 0 -} - -.algolia-autocomplete .algolia-docsearch-suggestion { - padding: 0; - overflow: visible -} - -.algolia-autocomplete .algolia-docsearch-suggestion--category-header { - padding: .125rem 1rem; - margin-top: 0; - font-size: 1.3em; - font-weight: 500; - color: #00008B; - border-bottom: 0 -} - -.algolia-autocomplete .algolia-docsearch-suggestion--wrapper { - float: none; - padding-top: 0 -} - -.algolia-autocomplete .algolia-docsearch-suggestion--subcategory-column { - float: none; - width: auto; - padding: 0; - text-align: left -} - -.algolia-autocomplete .algolia-docsearch-suggestion--content { - float: none; - width: auto; - padding: 0 -} - -.algolia-autocomplete .algolia-docsearch-suggestion--content::before { - display: none -} - -.algolia-autocomplete .ds-suggestion:not(:first-child) .algolia-docsearch-suggestion--category-header { - padding-top: .75rem; - margin-top: .75rem; - border-top: 1px solid rgba(0, 0, 0, .1) -} - -.algolia-autocomplete .ds-suggestion .algolia-docsearch-suggestion--subcategory-column { - display: block; - padding: .1rem 1rem; - margin-bottom: 0.1; - font-size: 1.0em; - font-weight: 400 - /* display: none */ -} - -.algolia-autocomplete .algolia-docsearch-suggestion--title { - display: block; - padding: .25rem 1rem; - margin-bottom: 0; - font-size: 0.9em; - font-weight: 400 -} - -.algolia-autocomplete .algolia-docsearch-suggestion--text { - padding: 0 1rem .5rem; - margin-top: -.25rem; - font-size: 0.8em; - font-weight: 400; - line-height: 1.25 -} - -.algolia-autocomplete .algolia-docsearch-footer { - width: 110px; - height: 20px; - z-index: 3; - margin-top: 10.66667px; - float: right; - font-size: 0; - line-height: 0; -} - -.algolia-autocomplete .algolia-docsearch-footer--logo { - background-image: url("data:image/svg+xml;utf8,"); - background-repeat: no-repeat; - background-position: 50%; - background-size: 100%; - overflow: hidden; - text-indent: -9000px; - width: 100%; - height: 100%; - display: block; - transform: translate(-8px); -} - -.algolia-autocomplete .algolia-docsearch-suggestion--highlight { - color: #FF8C00; - background: rgba(232, 189, 54, 0.1) -} - - -.algolia-autocomplete .algolia-docsearch-suggestion--text .algolia-docsearch-suggestion--highlight { - box-shadow: inset 0 -2px 0 0 rgba(105, 105, 105, .5) -} - -.algolia-autocomplete .ds-suggestion.ds-cursor .algolia-docsearch-suggestion--content { - background-color: rgba(192, 192, 192, .15) -} diff --git a/docs/docsearch.js b/docs/docsearch.js deleted file mode 100644 index b35504c..0000000 --- a/docs/docsearch.js +++ /dev/null @@ -1,85 +0,0 @@ -$(function() { - - // register a handler to move the focus to the search bar - // upon pressing shift + "/" (i.e. "?") - $(document).on('keydown', function(e) { - if (e.shiftKey && e.keyCode == 191) { - e.preventDefault(); - $("#search-input").focus(); - } - }); - - $(document).ready(function() { - // do keyword highlighting - /* modified from https://jsfiddle.net/julmot/bL6bb5oo/ */ - var mark = function() { - - var referrer = document.URL ; - var paramKey = "q" ; - - if (referrer.indexOf("?") !== -1) { - var qs = referrer.substr(referrer.indexOf('?') + 1); - var qs_noanchor = qs.split('#')[0]; - var qsa = qs_noanchor.split('&'); - var keyword = ""; - - for (var i = 0; i < qsa.length; i++) { - var currentParam = qsa[i].split('='); - - if (currentParam.length !== 2) { - continue; - } - - if (currentParam[0] == paramKey) { - keyword = decodeURIComponent(currentParam[1].replace(/\+/g, "%20")); - } - } - - if (keyword !== "") { - $(".contents").unmark({ - done: function() { - $(".contents").mark(keyword); - } - }); - } - } - }; - - mark(); - }); -}); - -/* Search term highlighting ------------------------------*/ - -function matchedWords(hit) { - var words = []; - - var hierarchy = hit._highlightResult.hierarchy; - // loop to fetch from lvl0, lvl1, etc. - for (var idx in hierarchy) { - words = words.concat(hierarchy[idx].matchedWords); - } - - var content = hit._highlightResult.content; - if (content) { - words = words.concat(content.matchedWords); - } - - // return unique words - var words_uniq = [...new Set(words)]; - return words_uniq; -} - -function updateHitURL(hit) { - - var words = matchedWords(hit); - var url = ""; - - if (hit.anchor) { - url = hit.url_without_anchor + '?q=' + escape(words.join(" ")) + '#' + hit.anchor; - } else { - url = hit.url + '?q=' + escape(words.join(" ")); - } - - return url; -} diff --git a/docs/favicon-16x16.png b/docs/favicon-16x16.png deleted file mode 100644 index e5f8719dd5893bd7e8c88035dc69859e2db2bde7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1306 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 - - - - - - -A Swiss-Army Knife for Data I/O • rio - - - - - - - - - - - - - - - - - -
    -
    - - - - -
    -
    - -
    -

    title: ‘rio: A Swiss-Army Knife for Data I/O’ output: github_document —

    -

    -

    The aim of rio is to make data file I/O in R as easy as possible by implementing four simple functions in Swiss-army knife style:

    -
      -
    • -import() provides a painless data import experience by automatically choosing the appropriate import/read function based on file extension (or a specified format argument)
    • -
    • -import_list() imports a list of data frames from a multi-object file (Excel workbook, .Rdata files, zip directory, or HTML file)
    • -
    • -export() provides the same painless file recognition for data export/write functionality
    • -
    • -convert() wraps import() and export() to allow the user to easily convert between file formats (thus providing a FOSS replacement for programs like Stat/Transfer or Sledgehammer). Relatedly, Luca Braglia has created a Shiny app called rioweb that provides access to the file conversion features of rio. GREA is an RStudio add-in that provides an interactive interface for reading in data using rio.
    • -
    -
    -

    -Examples

    -

    Because rio is meant to streamline data I/O, the package is extremely easy to use. Here are some examples of reading, writing, and converting data files.

    -
    -

    -Export

    -

    Exporting data is handled with one function, export():

    -
    library("rio")
    -
    -export(mtcars, "mtcars.csv") # comma-separated values
    -export(mtcars, "mtcars.rds") # R serialized
    -export(mtcars, "mtcars.sav") # SPSS
    -

    A particularly useful feature of rio is the ability to import from and export to compressed (e.g., zip) directories, saving users the extra step of compressing a large exported file, e.g.:

    -
    export(mtcars, "mtcars.tsv.zip")
    -

    As of rio v0.5.0, export() can also write multiple data frames to respective sheets of an Excel workbook or an HTML file:

    -
    export(list(mtcars = mtcars, iris = iris), file = "mtcars.xlsx")
    -
    -
    -

    -Import

    -

    Importing data is handled with one function, import():

    -
    x <- import("mtcars.csv")
    -y <- import("mtcars.rds")
    -z <- import("mtcars.sav")
    -
    -# confirm data match
    -all.equal(x, y, check.attributes = FALSE)
    -
    ## [1] TRUE
    -
    all.equal(x, z, check.attributes = FALSE)
    -
    ## [1] TRUE
    -

    Note: Because of inconsistencies across underlying packages, the data.frame returned by import might vary slightly (in variable classes and attributes) depending on file type.

    -

    In rio v0.5.0, a new list-based import function was added. This allows users to import a list of data frames from a multi-object file (such as an Excel workbook, .Rdata file, zip directory, or HTML file):

    -
    str(m <- import_list("mtcars.xlsx"))
    -
    ## List of 2
    -##  $ mtcars:'data.frame':  32 obs. of  11 variables:
    -##   ..$ mpg : num [1:32] 21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
    -##   ..$ cyl : num [1:32] 6 6 4 6 8 6 8 4 4 6 ...
    -##   ..$ disp: num [1:32] 160 160 108 258 360 ...
    -##   ..$ hp  : num [1:32] 110 110 93 110 175 105 245 62 95 123 ...
    -##   ..$ drat: num [1:32] 3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ...
    -##   ..$ wt  : num [1:32] 2.62 2.88 2.32 3.21 3.44 ...
    -##   ..$ qsec: num [1:32] 16.5 17 18.6 19.4 17 ...
    -##   ..$ vs  : num [1:32] 0 0 1 1 0 1 0 1 1 1 ...
    -##   ..$ am  : num [1:32] 1 1 1 0 0 0 0 0 0 0 ...
    -##   ..$ gear: num [1:32] 4 4 4 3 3 3 3 4 4 4 ...
    -##   ..$ carb: num [1:32] 4 4 1 1 2 1 4 2 2 4 ...
    -##  $ iris  :'data.frame':  150 obs. of  5 variables:
    -##   ..$ Sepal.Length: num [1:150] 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
    -##   ..$ Sepal.Width : num [1:150] 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
    -##   ..$ Petal.Length: num [1:150] 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
    -##   ..$ Petal.Width : num [1:150] 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
    -##   ..$ Species     : chr [1:150] "setosa" "setosa" "setosa" "setosa" ...
    -

    And for rio v0.6.0, a new list-based export function was added. This makes it easy to export a list of (possibly named) data frames to multiple files:

    -
    export_list(m, "%s.tsv")
    -
    ## Error in export_list(m, "%s.tsv"): could not find function "export_list"
    -
    c("mtcars.tsv", "iris.tsv") %in% dir()
    -
    ## [1] FALSE FALSE
    -
    -
    -

    -Convert

    -

    The convert() function links import() and export() by constructing a dataframe from the imported file and immediately writing it back to disk. convert() invisibly returns the file name of the exported file, so that it can be used to programmatically access the new file.

    -
    convert("mtcars.sav", "mtcars.dta")
    -

    It is also possible to use rio on the command-line by calling Rscript with the -e (expression) argument. For example, to convert a file from Stata (.dta) to comma-separated values (.csv), simply do the following:

    -
    Rscript -e "rio::convert('iris.dta', 'iris.csv')"
    -
    -
    -
    -

    -Supported file formats

    -

    rio supports a wide range of file formats. To keep the package slim, all non-essential formats are supported via “Suggests” packages, which are not installed (or loaded) by default. To ensure rio is fully functional, install these packages the first time you use rio via:

    - -

    The full list of supported formats is below:

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    FormatTypical ExtensionImport PackageExport PackageInstalled by Default
    Comma-separated data.csvdata.tabledata.tableYes
    Pipe-separated data.psvdata.tabledata.tableYes
    Tab-separated data.tsvdata.tabledata.tableYes
    CSVY (CSV + YAML metadata header).csvydata.tabledata.tableYes
    SAS.sas7bdathavenhavenYes
    SPSS.savhavenhavenYes
    SPSS (compressed).zsavhavenhavenYes
    Stata.dtahavenhavenYes
    SAS XPORT.xpthavenhavenYes
    SPSS Portable.porhavenYes
    Excel.xlsreadxlYes
    Excel.xlsxreadxlopenxlsxYes
    R syntax.RbasebaseYes
    Saved R objects.RData, .rdabasebaseYes
    Serialized R objects.rdsbasebaseYes
    Epiinfo.recforeignYes
    Minitab.mtpforeignYes
    Systat.sydforeignYes
    “XBASE” database files.dbfforeignforeignYes
    Weka Attribute-Relation File Format.arffforeignforeignYes
    Data Interchange Format.difutilsYes
    Fortran datano recognized extensionutilsYes
    Fixed-width format data.fwfutilsutilsYes
    gzip comma-separated data.csv.gzutilsutilsYes
    Apache Arrow (Parquet).parquetarrowarrowNo
    EViews.wf1hexViewNo
    Feather R/Python interchange format.featherfeatherfeatherNo
    Fast Storage.fstfstfstNo
    JSON.jsonjsonlitejsonliteNo
    Matlab.matrmatiormatioNo
    OpenDocument Spreadsheet.odsreadODSreadODSNo
    HTML Tables.htmlxml2xml2No
    Shallow XML documents.xmlxml2xml2No
    YAML.ymlyamlyamlNo
    Clipboarddefault is tsvcliprcliprNo
    Google Sheetsas Comma-separated data
    Graphpad Prism.pzfxpzfxpzfxNo
    -

    Additionally, any format that is not supported by rio but that has a known R implementation will produce an informative error message pointing to a package and import or export function. Unrecognized formats will yield a simple “Unrecognized file format” error.

    -
    -
    -

    -Package Philosophy

    -

    The core advantage of rio is that it makes assumptions that the user is probably willing to make. Eight of these are important:

    -
      -
    1. -rio uses the file extension of a file name to determine what kind of file it is. This is the same logic used by Windows OS, for example, in determining what application is associated with a given file type. By removing the need to manually match a file type (which a beginner may not recognize) to a particular import or export function, rio allows almost all common data formats to be read with the same function. And if a file extension is incorrect, users can force a particular import method by specifying the format argument. Other packages do this as well, but rio aims to be more complete and more consistent than each:
    2. -
    -
      -
    • -reader handles certain text formats and R binary files
    • -
    • -io offers a set of custom formats
    • -
    • -ImportExport focuses on select binary formats (Excel, SPSS, and Access files) and provides a Shiny interface.
    • -
    • -SchemaOnRead iterates through a large number of possible import methods until one works successfully
    • -
    -
      -
    1. rio uses data.table::fread() for text-delimited files to automatically determine the file format regardless of the extension. So, a CSV that is actually tab-separated will still be correctly imported. It’s also crazy fast.

    2. -
    3. rio, wherever possible, does not import character strings as factors.

    4. -
    5. rio supports web-based imports natively, including from SSL (HTTPS) URLs, from shortened URLs, from URLs that lack proper extensions, and from (public) Google Documents Spreadsheets.

    6. -
    7. rio imports from from single-file .zip and .tar archives automatically, without the need to explicitly decompress them. Export to compressed directories is also supported.

    8. -
    9. rio wraps a variety of faster, more stream-lined I/O packages than those provided by base R or the foreign package. It uses data.table for delimited formats, haven for SAS, Stata, and SPSS files, smarter and faster fixed-width file import and export routines, and readxl and openxlsx for reading and writing Excel workbooks.

    10. -
    11. -

      rio stores metadata from rich file formats (SPSS, Stata, etc.) in variable-level attributes in a consistent form regardless of file type or underlying import function. These attributes are identified as:

      -
        -
      • -label: a description of variable
      • -
      • -labels: a vector mapping numeric values to character strings those values represent
      • -
      • -format: a character string describing the variable storage type in the original file
      • -
      -

      The gather_attrs() function makes it easy to move variable-level attributes to the data frame level (and spread_attrs() reverses that gathering process). These can be useful, especially, during file conversion to more easily modify attributes that are handled differently across file formats. As an example, the following idiom can be used to trim SPSS value labels to the 32-character maximum allowed by Stata:

      -
      dat <- gather_attrs(rio::import("data.sav"))
      -attr(dat, "labels") <- lapply(attributes(dat)$labels, function(x) {
      -    if (!is.null(x)) {
      -        names(x) <- substring(names(x), 1, 32)
      -    }
      -    x
      -})
      -export(spread_attrs(dat), "data.dta")
      -

      In addition, two functions (added in v0.5.5) provide easy ways to create character and factor variables from these “labels” attributes. characterize() converts a single variable or all variables in a data frame that have “labels” attributes into character vectors based on the mapping of values to value labels. factorize() does the same but returns factor variables. This can be especially helpful for converting these rich file formats into open formats (e.g., export(characterize(import("file.dta")), "file.csv").

      -
    12. -
    13. rio imports and exports files based on an internal S3 class infrastructure. This means that other packages can contain extensions to rio by registering S3 methods. These methods should take the form .import.rio_X() and .export.rio_X(), where X is the file extension of a file type. An example is provided in the rio.db package.

    14. -
    -
    -
    -

    -Package Installation

    -

    CRAN Version DownloadsTravis-CI Build Status Appveyor Build status codecov.io

    -

    The package is available on CRAN and can be installed directly in R using install.packages(). You may want to run install_formats() after the first installation.

    - -

    The latest development version on GitHub can be installed using:

    -
    if (!require("remotes")){
    -    install.packages("remotes")
    -}
    -remotes::install_github("leeper/rio")
    -
    - -
    - - -
    - - -
    - -
    -

    Site built with pkgdown 1.5.1.

    -
    - -
    -
    - - - - - - diff --git a/docs/jquery.sticky-kit.min.js b/docs/jquery.sticky-kit.min.js deleted file mode 100644 index e2a3c6d..0000000 --- a/docs/jquery.sticky-kit.min.js +++ /dev/null @@ -1,9 +0,0 @@ -/* - Sticky-kit v1.1.2 | WTFPL | Leaf Corcoran 2015 | http://leafo.net -*/ -(function(){var b,f;b=this.jQuery||window.jQuery;f=b(window);b.fn.stick_in_parent=function(d){var A,w,J,n,B,K,p,q,k,E,t;null==d&&(d={});t=d.sticky_class;B=d.inner_scrolling;E=d.recalc_every;k=d.parent;q=d.offset_top;p=d.spacer;w=d.bottoming;null==q&&(q=0);null==k&&(k=void 0);null==B&&(B=!0);null==t&&(t="is_stuck");A=b(document);null==w&&(w=!0);J=function(a,d,n,C,F,u,r,G){var v,H,m,D,I,c,g,x,y,z,h,l;if(!a.data("sticky_kit")){a.data("sticky_kit",!0);I=A.height();g=a.parent();null!=k&&(g=g.closest(k)); -if(!g.length)throw"failed to find stick parent";v=m=!1;(h=null!=p?p&&a.closest(p):b("
    "))&&h.css("position",a.css("position"));x=function(){var c,f,e;if(!G&&(I=A.height(),c=parseInt(g.css("border-top-width"),10),f=parseInt(g.css("padding-top"),10),d=parseInt(g.css("padding-bottom"),10),n=g.offset().top+c+f,C=g.height(),m&&(v=m=!1,null==p&&(a.insertAfter(h),h.detach()),a.css({position:"",top:"",width:"",bottom:""}).removeClass(t),e=!0),F=a.offset().top-(parseInt(a.css("margin-top"),10)||0)-q, -u=a.outerHeight(!0),r=a.css("float"),h&&h.css({width:a.outerWidth(!0),height:u,display:a.css("display"),"vertical-align":a.css("vertical-align"),"float":r}),e))return l()};x();if(u!==C)return D=void 0,c=q,z=E,l=function(){var b,l,e,k;if(!G&&(e=!1,null!=z&&(--z,0>=z&&(z=E,x(),e=!0)),e||A.height()===I||x(),e=f.scrollTop(),null!=D&&(l=e-D),D=e,m?(w&&(k=e+u+c>C+n,v&&!k&&(v=!1,a.css({position:"fixed",bottom:"",top:c}).trigger("sticky_kit:unbottom"))),eb&&!v&&(c-=l,c=Math.max(b-u,c),c=Math.min(q,c),m&&a.css({top:c+"px"})))):e>F&&(m=!0,b={position:"fixed",top:c},b.width="border-box"===a.css("box-sizing")?a.outerWidth()+"px":a.width()+"px",a.css(b).addClass(t),null==p&&(a.after(h),"left"!==r&&"right"!==r||h.append(a)),a.trigger("sticky_kit:stick")),m&&w&&(null==k&&(k=e+u+c>C+n),!v&&k)))return v=!0,"static"===g.css("position")&&g.css({position:"relative"}), -a.css({position:"absolute",bottom:d,top:"auto"}).trigger("sticky_kit:bottom")},y=function(){x();return l()},H=function(){G=!0;f.off("touchmove",l);f.off("scroll",l);f.off("resize",y);b(document.body).off("sticky_kit:recalc",y);a.off("sticky_kit:detach",H);a.removeData("sticky_kit");a.css({position:"",bottom:"",top:"",width:""});g.position("position","");if(m)return null==p&&("left"!==r&&"right"!==r||a.insertAfter(h),h.remove()),a.removeClass(t)},f.on("touchmove",l),f.on("scroll",l),f.on("resize", -y),b(document.body).on("sticky_kit:recalc",y),a.on("sticky_kit:detach",H),setTimeout(l,0)}};n=0;for(K=this.length;n - - - - - diff --git a/docs/logo.png b/docs/logo.png deleted file mode 100644 index eda1a58bb22355b3211f1d871790027e433bcd47..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11768 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 - - - - - - - image/svg+xml - - - - - - - - - - - - - - RIO - - - - - - diff --git a/docs/news/index.html b/docs/news/index.html deleted file mode 100644 index e4ab72e..0000000 --- a/docs/news/index.html +++ /dev/null @@ -1,924 +0,0 @@ - - - - - - - - -Changelog • rio - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - - -
    - -
    -
    - - -
    -

    -rio 0.5.26 Unreleased -

    -
      -
    • -

      Added support for “zsav” format. (#273)

      -

      rio 0.5.25 Unreleased -

      -
    • -
    • Modified tests per email request from CRAN.

    • -
    • Added coerce_character argument (default FALSE) to factorize() to enable coercing character columns to factor. (#278)

    • -
    -
    -
    -

    -rio 0.5.24 Unreleased -

    -
      -
    • Fix handling of “label” and “labels” attributes when exporting using haven methods (SPSS, Stata, SAS). (#268, h/t Ruben Arslan)
    • -
    • Fix (a different bug?) handling factors by haven::labelled() (#271, Alex Bokov)
    • -
    • HTML import can now handle multiple tbody elements within a single table, a th element in a non-header row, and empty elements in either the header or data. (#260, #263, #264 Bill Denney)
    • -
    -
    -
    -

    -rio 0.5.23 Unreleased -

    - -
    -
    -

    -rio 0.5.22 Unreleased -

    -
      -
    • Added an export_list() function to write a list of data frames to multiple files using a vector of file names or a file pattern. (#207, h/t Bill Denney)
    • -
    • Added an is_file_text() function to determine whether a file is in a plain-text format. Optionally narrower subsets of characters can be specified, e.g. ASCII. (#236 Alex Bokov)
    • -
    -
    -
    -

    -rio 0.5.21 Unreleased -

    -
      -
    • Added support for Apache Arrow (Parquet) files. (#214)
    • -
    • Fix dropping of variable label in characterize() and factorize(). (#204, h/t David Armstrong)
    • -
    • -import_list() now returns a filename attribute for each data frame in the list (when importing from multiple files), in order to distinguish files with the same base name but different extensions (e.g., import_list(c("foo.csv", "foo.tsv"))). (#208, h/t Vimal Rawat)
    • -
    • Import of DBF files now does not convert strings to factors. (#202, h/t @jllipatz)
    • -
    • Implemented import() method for .dump R files. (#240)
    • -
    -
    -
    -

    -rio 0.5.20 Unreleased -

    -
      -
    • Additional pointers were added to indicate how to load .doc, .docx, and .pdf files (#210, h/t Bill Denney)
    • -
    • Ensure that tests only run if the corresponding package is installed. (h/t Bill Denney)
    • -
    • Escape ampersands for html and xml export (#234 Alex Bokov)
    • -
    -
    -
    -

    -rio 0.5.19 Unreleased -

    -
      -
    • Fix behavior of export() to plain text files when append = TRUE (#201, h/t Julián Urbano)
    • -
    • -import_list() now preserve names of Excel sheets, etc. when the ‘which’ argument is specified. (#162, h/t Danny Parsons)
    • -
    • Modify message and errors when working with unrecognized file formats. (#195, h/t Trevor Davis)
    • -
    • Add support for GraphPad Prism .pzfx files (#205, h/t Bill Denney)
    • -
    -
    -
    -

    -rio 0.5.18 Unreleased -

    -
      -
    • Adjust import()/export() for JSON file formats to allow non-data frame objects. Behavior modeled after RDS format. (#199 h/t Nathan Day)
    • -
    -
    -
    -

    -rio 0.5.17 Unreleased -

    -
      -
    • Fix the condition has length > 1 and only the first element will be used warning in gather_attributes(). (#196, h/t Ruben Arslan)
    • -
    -
    -
    -

    -rio 0.5.16 2018-11-26 -

    -
      -
    • Fix the condition has length > 1 and only the first element will be used warning in standardize_attributes().
    • -
    -
    -
    -

    -rio 0.5.15 2018-11-25 -

    -
      -
    • Modified some further code to produce compatibility with haven 2.0.0 release. (#188)
    • -
    • Add some additional function suggestions for the ledger package. (#190, h/t Trevor Davis)
    • -
    -
    -
    -

    -rio 0.5.14 Unreleased -

    -
      -
    • Changes to gather_attrs() for haven 2.0.0 release. (#188)
    • -
    • Fixed a bug that generated a superfluous warning in import().
    • -
    • Some style guide changes to code.
    • -
    -
    -
    -

    -rio 0.5.13 Unreleased -

    -
      -
    • Allow import() of objects other than data frames from R-serialized (.rds and .rdata) files. Also, export of such objects to .rds files is supported, as previously intended. (#183, h/t Nicholas Jhirad)
    • -
    • Added (suggests) support for import of EViews files using hexView::readEViews(). (#163, h/t Boris Demeshev)
    • -
    -

    # rio 0.5.12

    -
      -
    • Add better package specification to install_formats() so that it reads from the Suggests field of the DESCRIPTION file.
    • -
    • Edit header of README.Rmd (and thusly README.md) to stop complaining about a lack of title field.
    • -
    • Fix typo in CONTRIBUTING.md (line said “three arguments”, but only listed two).
    • -
    -
    -
    -

    -rio 0.5.11 Unreleased -

    -
      -
    • Fixed a bug in import() wherein matlab files were ignored unless format was specified, as well as a related bug that made importing appear to fail for matlab files. (#171)
    • -
    • Fixed a bug in export() wherein format was ignored. (#99, h/t Sebastian Sauer)
    • -
    • Fixed a bug in the importing of European-style semicolon-separated CSV files. Added a test to ensure correct behavior. (#159, h/t Kenneth Rose)
    • -
    • Updated documentation to reflect recent changes to the xlsx export() method. (#156)
    • -
    -
    -
    -

    -rio 0.5.10 2018-03-29 -

    -
      -
    • Removed some csvy-related tests, which were failing on CRAN.
    • -
    -
    -
    -

    -rio 0.5.9 2018-02-01 -

    -
      -
    • Removed longstanding warnings from the tests of export() to fixed-width format.
    • -
    -
    -
    -

    -rio 0.5.8 Unreleased -

    -
      -
    • Export the get_ext() function. (#169)
    • -
    • Fix a bug related to an xml2 bug (#168, h/t Jim Hester)
    • -
    • -import_list() gains improved file name handling. (#164, h/t Ruaridh Williamson)
    • -
    • Removed the overwrite argument from export() method for xlsx files. Instead, existing workbooks are always overwritten unless which is specified, in which case only the specified sheet (if it exists) is overwritten. If the file exists but the which sheet does not, the data are added as a new sheet to the existing workbook. (#156)
    • -
    -
    -
    -

    -rio 0.5.7 Unreleased -

    -
      -
    • Import of files with the ambiguous .dat extension, which are typically text-delimited files, are now passed to data.table::fread() with a message. Export to the format remains unsupported. (#98, #155)
    • -
    • Added support for export to SAS XPORT format (via haven::write_xpt()). (#157)
    • -
    • Switched default import package for SAS XPORT format to haven::read_xpt() with a haven = FALSE toggle restoring the previous default behavior using foreign::read.xpt(). (#157)
    • -
    -
    -
    -

    -rio 0.5.6 Unreleased -

    -
      -
    • Fixed a bug in import() from compressed files wherein the which argument did not necessarily return the correct file if >=2 files in the compressed folder.
    • -
    • Tweak handling of export() to xlsx workbooks when which is specified. (#156)
    • -
    -
    -
    -

    -rio 0.5.5 2017-06-18 -

    -
      -
    • Expanded test suite and increased test coverage, fixing a few tests that were failing on certain CRAN builds.
    • -
    -
    -
    -

    -rio 0.5.4 Unreleased -

    -
      -
    • New functions characterize() and factorize() provide methods for converting “labelled” variables (e.g., from Stata or SPSS) into character or factor variables using embedded metadata. This can also be useful for exporting a metadata-rich file format into a plain text file. (#153)
    • -
    -
    -
    -

    -rio 0.5.3 Unreleased -

    -
      -
    • Fixed a bug in writing to .zip and .tar archives related to absolute file paths.
    • -
    • Fixed some small bugs in import_list() and added tests for behavior.
    • -
    • Add .bib as known-unsupported format via bib2df::bib2df().
    • -
    • Expanded test coverage.
    • -
    -
    -
    -

    -rio 0.5.3 Unreleased -

    -
      -
    • Fixed a bug in .import.rio_xlsx() when readxl = FALSE. (#152, h/t Danny Parsons)
    • -
    • Added a new function spread_attrs() that reverses the gather_attrs() operation.
    • -
    • Expanded test coverage.
    • -
    -
    -
    -

    -rio 0.5.1 Unreleased -

    -
      -
    • -export() now sets variables with a “labels” attribute to haven’s “labelled” class.
    • -
    -
    -
    -

    -rio 0.5.0 2017-04-28 -

    -
      -
    • CRAN Release.
    • -
    • Restored import of openxlsx so that writing to xlsx is supported on install. (#150)
    • -
    -
    -
    -

    -rio 0.4.28 Unreleased -

    -
      -
    • Improved documentation of mapping between file format support and the packages used for each format. (#151, h/t Patrick Kennedy)
    • -
    • -import_list() now returns a NULL entry for any failed imports, with a warning. (#149)
    • -
    • -import_list() gains additional arguments rbind_fill and rbind_label to control rbind-ing behavior. (#149)
    • -
    -
    -
    -

    -rio 0.4.27 Unreleased -

    - -
    -
    -

    -rio 0.4.26 Unreleased -

    -
      -
    • Further fixes to .csv.gz import/export. (#146, h/t Trevor Davis)
    • -
    -
    -
    -

    -rio 0.4.25 Unreleased -

    -
      -
    • Remove unecessary urltools dependency.
    • -
    • New function import_list() returns a list of data frames from a multi-object Excel Workbook, .Rdata file, zip directory, or HTML file. (#126, #129)
    • -
    • -export() can now write a list of data frames to an Excel (.xlsx) workbook. (#142, h/t Jeremy Johnson)
    • -
    • -export() can now write a list of data frames to an HTML (.html) file.
    • -
    -
    -
    -

    -rio 0.4.24 Unreleased -

    -
      -
    • Verbosity of export(format = "fwf") now depends on options("verbose").
    • -
    • Fixed various errors, warnings, and messages in fixed-width format tests.
    • -
    • Modified defaults and argument handling in internal function read_delim().
    • -
    • Fixed handling of “data.table”, “tibble”, and “data.frame” classes in set_class(). (#144)
    • -
    -
    -
    -

    -rio 0.4.23 Unreleased -

    -
      -
    • Moved all non-critical format packages to Suggests, rather than Imports. (#143)
    • -
    • Added support for Matlab formats. (#78, #98)
    • -
    • Added support for fst format. (#138)
    • -
    -
    -
    -

    -rio 0.4.22 Unreleased -

    -
      -
    • Rearranged README.
    • -
    • Bumped readxl dependency to >= 0.1.1 (#130, h/t Yongfa Chen)
    • -
    • Pass explicit excel_format arguments when using readxl functions. (#130)
    • -
    • Google Spreadsheets can now be imported using any of the allowed formats (CSV, TSV, XLSX, ODS).
    • -
    • Added support for writing to ODS files via readODS::write_ods(). (#96)
    • -
    -
    -
    -

    -rio 0.4.21 Unreleased -

    -
      -
    • Handle HTML tables with <tbody> elements. (h/t Mohamed Elgoussi)
    • -
    -
    -
    -

    -rio 0.4.20 Unreleased -

    -
      -
    • Fixed a big in the .import.rio_xls() and .import.rio_xlsx() where the sheet argument would return an error.
    • -
    -
    -
    -

    -rio 0.4.19 Unreleased -

    -
      -
    • Fixed a bug in the import of delimited files when fread = FALSE. (#133, h/t Christopher Gandrud)
    • -
    -
    -
    -

    -rio 0.4.18 Unreleased -

    -
      -
    • With new data.table release, export using fwrite() is now the default for text-based file formats.
    • -
    -
    -
    -

    -rio 0.4.17 Unreleased -

    -
      -
    • Fixed a bug in .import.rio_xls() wherein the which argument was ignored. (h/t Mohamed Elgoussi)
    • -
    -
    -
    -

    -rio 0.4.16 2016-09-25 -

    -
      -
    • Added support for importing from multi-table HTML files using the which argument. (#126)
    • -
    -
    -
    -

    -rio 0.4.15 Unreleased -

    -
      -
    • Improved behavior of import() and export() with respect to unrecognized file types. (#124, #125, h/t Jason Becker)
    • -
    • Added explicit tests of the S3 extension mechanism for .import() and .export().
    • -
    • Attempt to recognize compressed but non-archived file formats (e.g., “.csv.gz”). (#123, h/t trevorld)
    • -
    -
    -
    -

    -rio 0.4.14 Unreleased -

    -
      -
    • Update import and export methods to use new xml2 for XML and HTML export. (#86)
    • -
    -
    -
    -

    -rio 0.4.13 Unreleased -

    -
      -
    • Fix failing tests related to stricter variable name handling for Stata files in development version of haven. (#113, h/t Hadley Wickham)
    • -
    • Added support for export of .sas7bdat files via haven (#116)
    • -
    • Restored support for import from SPSS portable via haven (#116)
    • -
    • Updated import methods to reflect changed formal argument names in haven. (#116)
    • -
    • Converted to roxygen2 documentation and made NEWS an explicit markdown file.
    • -
    -
    -
    -

    -rio 0.4.12 2016-08-10 -

    - -
    -
    -

    -rio 0.4.11 2016-08-09 -

    -
      -
    • Note unsupported NumPy i/o via RcppCNPy. (#112)
    • -
    • Fix import of European-style CSV files (sep = “,” and sep2 = “;”). (#106, #107, h/t Stani Stadlmann)
    • -
    -
    -
    -

    -rio 0.4.10 Unreleased -

    -
      -
    • Changed feather Imports to Suggests to make rio installable on older R versions. (#104)
    • -
    • Noted new RStudio add-in, GREA, that uses rio. (#109)
    • -
    • Migrated CSVY-related code to separate package (https://github.com/leeper/csvy/). (#111)
    • -
    -
    -
    -

    -rio 0.4.9 Unreleased -

    -
      -
    • Removed unnecessary error in xlsx imports. (#103, h/t Kevin Wright)
    • -
    -
    -
    -

    -rio 0.4.8 2016-06-14 -

    -
      -
    • Fixed a bug in the handling of “labelled” class variables imported from haven. (#102, h/t Pierre LaFortune)
    • -
    -
    -
    -

    -rio 0.4.7 Unreleased -

    -
      -
    • Improved use of the sep argument for import of delimited files. (#99, h/t Danny Parsons)
    • -
    • Removed support for import of SPSS Portable (.por) files, given deprecation from haven. (#100)
    • -
    -
    -
    -

    -rio 0.4.5 2016-05-20 -

    -
      -
    • Fixed other tests to remove (unimportant) warnings.
    • -
    • Fixed a failing test of file compression that was found in v0.4.3 on some platforms.
    • -
    -
    -
    -

    -rio 0.4.3 2016-05-19 -

    -
      -
    • Improved, generalized, tested, and expanded documentation of which argument in import().
    • -
    • Expanded test suite and made some small fixes.
    • -
    -
    -
    -

    -rio 0.4.2 Unreleased -

    -
      -
    • Added support to import and export to feather data serialization format. (#88, h/t Jason Becker)
    • -
    -
    -
    -

    -rio 0.4.1 Unreleased -

    -
      -
    • Fixed behavior of gather_attrs() on a data.frame with no attributes to gather. (#94)
    • -
    • Removed unrecognized file format error for import from compressed files. (#93)
    • -
    -
    -
    -

    -rio 0.4.0 2016-05-01 -

    -
      -
    • CRAN Release.
    • -
    -
    -
    -

    -rio 0.3.19 Unreleased -

    -
      -
    • Added a gather_attrs() function that moves variable-level attributes to the data.frame level. (#80)
    • -
    • Added preliminary support for import from HTML tables (#86)
    • -
    -
    -
    -

    -rio 0.3.18 Unreleased -

    -
      -
    • Added support for export to HTML tables. (#86)
    • -
    -
    -
    -

    -rio 0.3.17 Unreleased -

    -
      -
    • Fixed a bug in import from remote URLs with incorrect file extensions.
    • -
    -
    -
    -

    -rio 0.3.16 Unreleased -

    -
      -
    • Added support for import from fixed-width format files via readr::read_fwf() with a specified widths argument. This may enable faster import of these types of files and provides a base-like interface for working with readr. (#48)
    • -
    -
    -
    -

    -rio 0.3.15 Unreleased -

    -
      -
    • Added support for import from and export to yaml. (#83)
    • -
    • Fixed a bug when reading from an uncommented CSVY yaml header that contained single-line comments. (#84, h/t Tom Aldenberg)
    • -
    -
    -
    -

    -rio 0.3.14 Unreleased -

    -
      -
    • Diagnostic messages were cleaned up to facilitate translation. (#57)
    • -
    -
    -
    -

    -rio 0.3.12 Unreleased -

    -
      -
    • -.import() and .export() are now exported S3 generics and documentation has been added to describe how to write rio extensions for new file types. An example of this functionality is shown in the new suggested “rio.db” package.
    • -
    -
    -
    -

    -rio 0.3.11 Unreleased -

    -
      -
    • -import() now uses xml2 to read XML structures and export() uses a custom method for writing to XML, thereby negating dependency on the XML package. (#67)
    • -
    • Enhancements were made to import and export of CSVY to store attribute metadata as variable-level attributes (like imports from binary file formats).
    • -
    • -import() gains a which argument that is used to select which file to return from within a compressed tar or zip archive.
    • -
    • Export to tar now tries to correct for bugs in tar() that are being fixed in base R via PR#16716.
    • -
    -
    -
    -

    -rio 0.3.10 Unreleased -

    -
      -
    • Fixed a bug in import() (introduced in #62, 7a7480e5) that prevented import from clipboard. (h/t Kevin Wright)
    • -
    • -export() returns a character string. (#82)
    • -
    -
    -
    -

    -rio 0.3.9 Unreleased -

    -
      -
    • The use of import() for SAS, Stata, and SPSS files has been streamlined. Regardless of whether the haven = TRUE argument is used, the data.frame returned by import() should now be (nearly) identical, with all attributes stored at the variable rather than data.frame level. This is a non-backwards compatible change. (#80)
    • -
    -
    -
    -

    -rio 0.3.8 Unreleased -

    -
      -
    • Fixed error in export to CSVY with a commented yaml header. (#81, h/t Andrew MacDonald)
    • -
    -
    -
    -

    -rio 0.3.7 Unreleased -

    - -
    -
    -

    -rio 0.3.6 Unreleased -

    -
      -
    • Expanded verbosity of export() for fixed-width format files and added a commented header containing column class and width information.
    • -
    • Exporting factors to fixed-width format now saves those values as integer rather than numeric.
    • -
    • Expanded test suite and separated tests into format-specific files. (#51)
    • -
    -
    -
    -

    -rio 0.3.5 Unreleased -

    -
      -
    • Export of CSVY files now includes commenting the yaml header by default. Import of CSVY accommodates this automatically. (#74)
    • -
    -
    -
    -

    -rio 0.3.3 Unreleased -

    -
      -
    • Export of CSVY files and metadata now supported by export(). (#73)
    • -
    • Import of CSVY files now stores dataset-level metadata in attributes of the output data.frame. (#73, h/t Tom Aldenberg)
    • -
    • When rio receives an unrecognized file format, it now issues a message. The new internal .import.default() and .export.default() then produce an error. This enables add-on packages to support additional formats through new s3 methods of the form .import.rio_EXTENSION() and .export.rio_EXTENSION().
    • -
    -
    -
    -

    -rio 0.3.2 Unreleased -

    -
      -
    • Use S3 dispatch internally to call new (unexported) .import() and .export() methods. (#42, h/t Jason Becker)
    • -
    -
    -
    -

    -rio 0.3.0 2016-01-14 -

    -
      -
    • Release to CRAN.
    • -
    • Set a default numerical precision (of 2 decimal places) for export to fixed-width format.
    • -
    -
    -
    -

    -rio 0.2.13 Unreleased -

    - -
    -
    -

    -rio 0.2.11 Unreleased -

    -
      -
    • Added support for direct import from Google Sheets. (#60, #63, h/t Chung-hong Chan)
    • -
    -
    -
    -

    -rio 0.2.7 Unreleased -

    -
      -
    • Refactored remote file retrieval into separate (non-exported) function used by import(). (#62)
    • -
    • Added test sutie to test file conversion.
    • -
    • Expanded test suite to include test of all export formats.
    • -
    -
    -
    -

    -rio 0.2.6 Unreleased -

    -
      -
    • Cleaned up NAMESPACE file.
    • -
    -
    -
    -

    -rio 0.2.5 Unreleased -

    -
      -
    • If file format for a remote file cannot be identified from the supplied URL or the final URL reported by curl::curl_fetch_memory(), the HTTP headers are checked for a filename in the Content-Disposition header. (#36)
    • -
    • Removed longurl dependency. This is no longer needed because we can identify formats using curl’s url argument.
    • -
    • Fixed a bug related to importing European-style (“csv2”) format files. (#44)
    • -
    • Updated CSVY import to embed variable-level metadata. (#52)
    • -
    • Use urltools::url_parse() to extract file extensions from complex URLs (e.g., those with query arguments). (#56)
    • -
    • Fixed NAMESPACE notes for base packages. (#58)
    • -
    -
    -
    -

    -rio 0.2.4 Unreleased -

    -
      -
    • Modified behavior so that files imported using haven now store variable metadata at the data.frame level by default (unlike the default behavior in haven, which can cause problems). (#37, h/t Ista Zahn)
    • -
    • Added support for importing CSVY (http://csvy.org/) formatted files. (#52)
    • -
    • Added import dependency on data.table 1.9.5. (#39)
    • -
    -
    -
    -

    -rio 0.2.2 Unreleased -

    -
      -
    • Uses the longurl package to expand shortened URLs so that their file type can be easily determined.
    • -
    -
    -
    -

    -rio 0.2.1 Unreleased -

    -
      -
    • Improved support for importing from compressed directories, especially web-based compressed directories. (#38)
    • -
    • Add import dependency on curl >= 0.6 to facilitate content type parsing and format inference from URL redirects. (#36)
    • -
    • Add bit64 to Suggests to remove an import warning.
    • -
    -
    -
    -

    -rio 0.2 2015-05-07 -

    -
      -
    • -import always returns a data.frame, unless setclass is specified. (#22)
    • -
    • Added support for import from legacy Excel (.xls) files readxl::read_excel, making its use optional. (#19)
    • -
    • Added support for import from and export to the system clipboard on Windows and Mac OS.
    • -
    • Added support for export to simple XML documents. (#12)
    • -
    • Added support for import from simple XML documents via XML::xmlToDataFrame. (#12)
    • -
    • Added support for import from ODS spreadsheet formats. (#12, h/t Chung-hong Chan)
    • -
    • Use data.table::fread by default for reading delimited files. (#3)
    • -
    • Added support for import and export of dput and dget objects. (#10)
    • -
    • Added support for reading from compressed archives (.zip and .tar). (#7)
    • -
    • Added support for writing to fixed-width format. (#8)
    • -
    • Set stringsAsFactors = FALSE as default for reading tabular data. (#4)
    • -
    • Added support for HTTPS imports. (#1, h/t Christopher Gandrud)
    • -
    • Added support for automatic file naming in export based on object name and file format. (#5)
    • -
    • Exposed convert function.
    • -
    • Added vignette, knitr-generated README.md, and updated documentation. (#2)
    • -
    • Added some non-exported functions to simplify argument passing and streamline package API. (#6)
    • -
    • Separated import, export, convert, and utilities into separate source code files.
    • -
    • Expanded the set of supported file types/extensions, switched SPSS, SAS, and Stata formats to haven, making its use optional.
    • -
    -
    -
    -

    -rio 0.1.2 2013-09-04 -

    -
      -
    • Updated documentation and fixed a bug in csv import without header.
    • -
    -
    -
    -

    -rio 0.1.1 2013-08-28 -

    -
      -
    • Initial release
    • -
    -
    -
    - - - -
    - - -
    - - -
    -

    Site built with pkgdown 1.5.1.

    -
    - -
    -
    - - - - - - - - diff --git a/docs/pkgdown.css b/docs/pkgdown.css deleted file mode 100644 index c01e592..0000000 --- a/docs/pkgdown.css +++ /dev/null @@ -1,367 +0,0 @@ -/* Sticky footer */ - -/** - * Basic idea: https://philipwalton.github.io/solved-by-flexbox/demos/sticky-footer/ - * Details: https://github.com/philipwalton/solved-by-flexbox/blob/master/assets/css/components/site.css - * - * .Site -> body > .container - * .Site-content -> body > .container .row - * .footer -> footer - * - * Key idea seems to be to ensure that .container and __all its parents__ - * have height set to 100% - * - */ - -html, body { - height: 100%; -} - -body { - position: relative; -} - -body > .container { - display: flex; - height: 100%; - flex-direction: column; -} - -body > .container .row { - flex: 1 0 auto; -} - -footer { - margin-top: 45px; - padding: 35px 0 36px; - border-top: 1px solid #e5e5e5; - color: #666; - display: flex; - flex-shrink: 0; -} -footer p { - margin-bottom: 0; -} -footer div { - flex: 1; -} -footer .pkgdown { - text-align: right; -} -footer p { - margin-bottom: 0; -} - -img.icon { - float: right; -} - -img { - max-width: 100%; -} - -/* Fix bug in bootstrap (only seen in firefox) */ -summary { - display: list-item; -} - -/* Typographic tweaking ---------------------------------*/ - -.contents .page-header { - margin-top: calc(-60px + 1em); -} - -dd { - margin-left: 3em; -} - -/* Section anchors ---------------------------------*/ - -a.anchor { - margin-left: -30px; - display:inline-block; - width: 30px; - height: 30px; - visibility: hidden; - - background-image: url(./link.svg); - background-repeat: no-repeat; - background-size: 20px 20px; - background-position: center center; -} - -.hasAnchor:hover a.anchor { - visibility: visible; -} - -@media (max-width: 767px) { - .hasAnchor:hover a.anchor { - visibility: hidden; - } -} - - -/* Fixes for fixed navbar --------------------------*/ - -.contents h1, .contents h2, .contents h3, .contents h4 { - padding-top: 60px; - margin-top: -40px; -} - -/* Navbar submenu --------------------------*/ - -.dropdown-submenu { - position: relative; -} - -.dropdown-submenu>.dropdown-menu { - top: 0; - left: 100%; - margin-top: -6px; - margin-left: -1px; - border-radius: 0 6px 6px 6px; -} - -.dropdown-submenu:hover>.dropdown-menu { - display: block; -} - -.dropdown-submenu>a:after { - display: block; - content: " "; - float: right; - width: 0; - height: 0; - border-color: transparent; - border-style: solid; - border-width: 5px 0 5px 5px; - border-left-color: #cccccc; - margin-top: 5px; - margin-right: -10px; -} - -.dropdown-submenu:hover>a:after { - border-left-color: #ffffff; -} - -.dropdown-submenu.pull-left { - float: none; -} - -.dropdown-submenu.pull-left>.dropdown-menu { - left: -100%; - margin-left: 10px; - border-radius: 6px 0 6px 6px; -} - -/* Sidebar --------------------------*/ - -#pkgdown-sidebar { - margin-top: 30px; - position: -webkit-sticky; - position: sticky; - top: 70px; -} - -#pkgdown-sidebar h2 { - font-size: 1.5em; - margin-top: 1em; -} - -#pkgdown-sidebar h2:first-child { - margin-top: 0; -} - -#pkgdown-sidebar .list-unstyled li { - margin-bottom: 0.5em; -} - -/* bootstrap-toc tweaks ------------------------------------------------------*/ - -/* All levels of nav */ - -nav[data-toggle='toc'] .nav > li > a { - padding: 4px 20px 4px 6px; - font-size: 1.5rem; - font-weight: 400; - color: inherit; -} - -nav[data-toggle='toc'] .nav > li > a:hover, -nav[data-toggle='toc'] .nav > li > a:focus { - padding-left: 5px; - color: inherit; - border-left: 1px solid #878787; -} - -nav[data-toggle='toc'] .nav > .active > a, -nav[data-toggle='toc'] .nav > .active:hover > a, -nav[data-toggle='toc'] .nav > .active:focus > a { - padding-left: 5px; - font-size: 1.5rem; - font-weight: 400; - color: inherit; - border-left: 2px solid #878787; -} - -/* Nav: second level (shown on .active) */ - -nav[data-toggle='toc'] .nav .nav { - display: none; /* Hide by default, but at >768px, show it */ - padding-bottom: 10px; -} - -nav[data-toggle='toc'] .nav .nav > li > a { - padding-left: 16px; - font-size: 1.35rem; -} - -nav[data-toggle='toc'] .nav .nav > li > a:hover, -nav[data-toggle='toc'] .nav .nav > li > a:focus { - padding-left: 15px; -} - -nav[data-toggle='toc'] .nav .nav > .active > a, -nav[data-toggle='toc'] .nav .nav > .active:hover > a, -nav[data-toggle='toc'] .nav .nav > .active:focus > a { - padding-left: 15px; - font-weight: 500; - font-size: 1.35rem; -} - -/* orcid ------------------------------------------------------------------- */ - -.orcid { - font-size: 16px; - color: #A6CE39; - /* margins are required by official ORCID trademark and display guidelines */ - margin-left:4px; - margin-right:4px; - vertical-align: middle; -} - -/* Reference index & topics ----------------------------------------------- */ - -.ref-index th {font-weight: normal;} - -.ref-index td {vertical-align: top;} -.ref-index .icon {width: 40px;} -.ref-index .alias {width: 40%;} -.ref-index-icons .alias {width: calc(40% - 40px);} -.ref-index .title {width: 60%;} - -.ref-arguments th {text-align: right; padding-right: 10px;} -.ref-arguments th, .ref-arguments td {vertical-align: top;} -.ref-arguments .name {width: 20%;} -.ref-arguments .desc {width: 80%;} - -/* Nice scrolling for wide elements --------------------------------------- */ - -table { - display: block; - overflow: auto; -} - -/* Syntax highlighting ---------------------------------------------------- */ - -pre { - word-wrap: normal; - word-break: normal; - border: 1px solid #eee; -} - -pre, code { - background-color: #f8f8f8; - color: #333; -} - -pre code { - overflow: auto; - word-wrap: normal; - white-space: pre; -} - -pre .img { - margin: 5px 0; -} - -pre .img img { - background-color: #fff; - display: block; - height: auto; -} - -code a, pre a { - color: #375f84; -} - -a.sourceLine:hover { - text-decoration: none; -} - -.fl {color: #1514b5;} -.fu {color: #000000;} /* function */ -.ch,.st {color: #036a07;} /* string */ -.kw {color: #264D66;} /* keyword */ -.co {color: #888888;} /* comment */ - -.message { color: black; font-weight: bolder;} -.error { color: orange; font-weight: bolder;} -.warning { color: #6A0366; font-weight: bolder;} - -/* Clipboard --------------------------*/ - -.hasCopyButton { - position: relative; -} - -.btn-copy-ex { - position: absolute; - right: 0; - top: 0; - visibility: hidden; -} - -.hasCopyButton:hover button.btn-copy-ex { - visibility: visible; -} - -/* headroom.js ------------------------ */ - -.headroom { - will-change: transform; - transition: transform 200ms linear; -} -.headroom--pinned { - transform: translateY(0%); -} -.headroom--unpinned { - transform: translateY(-100%); -} - -/* mark.js ----------------------------*/ - -mark { - background-color: rgba(255, 255, 51, 0.5); - border-bottom: 2px solid rgba(255, 153, 51, 0.3); - padding: 1px; -} - -/* vertical spacing after htmlwidgets */ -.html-widget { - margin-bottom: 10px; -} - -/* fontawesome ------------------------ */ - -.fab { - font-family: "Font Awesome 5 Brands" !important; -} - -/* don't display links in code chunks when printing */ -/* source: https://stackoverflow.com/a/10781533 */ -@media print { - code a:link:after, code a:visited:after { - content: ""; - } -} diff --git a/docs/pkgdown.js b/docs/pkgdown.js deleted file mode 100644 index 7e7048f..0000000 --- a/docs/pkgdown.js +++ /dev/null @@ -1,108 +0,0 @@ -/* http://gregfranko.com/blog/jquery-best-practices/ */ -(function($) { - $(function() { - - $('.navbar-fixed-top').headroom(); - - $('body').css('padding-top', $('.navbar').height() + 10); - $(window).resize(function(){ - $('body').css('padding-top', $('.navbar').height() + 10); - }); - - $('[data-toggle="tooltip"]').tooltip(); - - var cur_path = paths(location.pathname); - var links = $("#navbar ul li a"); - var max_length = -1; - var pos = -1; - for (var i = 0; i < links.length; i++) { - if (links[i].getAttribute("href") === "#") - continue; - // Ignore external links - if (links[i].host !== location.host) - continue; - - var nav_path = paths(links[i].pathname); - - var length = prefix_length(nav_path, cur_path); - if (length > max_length) { - max_length = length; - pos = i; - } - } - - // Add class to parent
  • , and enclosing
  • if in dropdown - if (pos >= 0) { - var menu_anchor = $(links[pos]); - menu_anchor.parent().addClass("active"); - menu_anchor.closest("li.dropdown").addClass("active"); - } - }); - - function paths(pathname) { - var pieces = pathname.split("/"); - pieces.shift(); // always starts with / - - var end = pieces[pieces.length - 1]; - if (end === "index.html" || end === "") - pieces.pop(); - return(pieces); - } - - // Returns -1 if not found - function prefix_length(needle, haystack) { - if (needle.length > haystack.length) - return(-1); - - // Special case for length-0 haystack, since for loop won't run - if (haystack.length === 0) { - return(needle.length === 0 ? 0 : -1); - } - - for (var i = 0; i < haystack.length; i++) { - if (needle[i] != haystack[i]) - return(i); - } - - return(haystack.length); - } - - /* Clipboard --------------------------*/ - - function changeTooltipMessage(element, msg) { - var tooltipOriginalTitle=element.getAttribute('data-original-title'); - element.setAttribute('data-original-title', msg); - $(element).tooltip('show'); - element.setAttribute('data-original-title', tooltipOriginalTitle); - } - - if(ClipboardJS.isSupported()) { - $(document).ready(function() { - var copyButton = ""; - - $(".examples, div.sourceCode").addClass("hasCopyButton"); - - // Insert copy buttons: - $(copyButton).prependTo(".hasCopyButton"); - - // Initialize tooltips: - $('.btn-copy-ex').tooltip({container: 'body'}); - - // Initialize clipboard: - var clipboardBtnCopies = new ClipboardJS('[data-clipboard-copy]', { - text: function(trigger) { - return trigger.parentNode.textContent; - } - }); - - clipboardBtnCopies.on('success', function(e) { - changeTooltipMessage(e.trigger, 'Copied!'); - e.clearSelection(); - }); - - clipboardBtnCopies.on('error', function() { - changeTooltipMessage(e.trigger,'Press Ctrl+C or Command+C to copy'); - }); - }); - } -})(window.jQuery || window.$) diff --git a/docs/pkgdown.yml b/docs/pkgdown.yml deleted file mode 100644 index 2a3efac..0000000 --- a/docs/pkgdown.yml +++ /dev/null @@ -1,7 +0,0 @@ -pandoc: 2.7.3 -pkgdown: 1.5.1 -pkgdown_sha: ~ -articles: - rio: rio.html -last_built: 2021-02-22T21:50Z - diff --git a/docs/reference/arg_reconcile.html b/docs/reference/arg_reconcile.html deleted file mode 100644 index 6b894e0..0000000 --- a/docs/reference/arg_reconcile.html +++ /dev/null @@ -1,256 +0,0 @@ - - - - - - - - -Reconcile an argument list to any function signature. — arg_reconcile • rio - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - - -
    - -
    -
    - - -
    -

    Adapt an argument list to a function excluding arguments that - will not be recognized by it, redundant arguments, and un-named - arguments.

    -
    - -
    arg_reconcile(
    -  fun,
    -  ...,
    -  .args = alist(),
    -  .docall = FALSE,
    -  .include = c(),
    -  .exclude = c(),
    -  .remap = list(),
    -  .warn = TRUE,
    -  .error = "default",
    -  .finish = identity
    -)
    - -

    Arguments

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    fun

    A function to which an argument list needs to be adapted. Use -the unquoted name of the function. If it's in a different -package then the fully qualified unquoted name (e.g. -utils::read.table)

    ...

    An arbitrary list of named arguments (unnamed ones will be -ignored). Arguments in .args are overridden by -arguments of the same name (if any) in ...

    .args

    A list or alist of named arguments, to be merged -with .... Arguments in .args are overridden by -arguments of the same name (if any) in ...

    .docall

    If set to TRUE will not only clean up the arguments -but also execute fun with those arguments -(FALSE by default) and return the results

    .include

    Whitelist. If not empty, only arguments named here will be -permitted, and only if they satisfy the conditions implied by -the other arguments. Evaluated before .remap.

    .exclude

    Blacklist. If not empty, arguments named here will be removed -even if they satisfy the conditions implied by the other -arguments. Evaluated before .remap.

    .remap

    An optional named character vector or named list of character -values for standardizing arguments that play the same role -but have different names in different functions. Evaluated -after .exclude and .include.

    .warn

    Whether to issue a warning message (default) when invalid -arguments need to be discarded.

    .error

    If specified, should be the object to return in the event of -error. This object will have the error as its -error attribute. If not specified an ordinary error is -thrown with an added hint on the documentation to read for -troubleshooting. Ignored if .docall is FALSE. -The point of doing this is fault-tolerance-- if this function -is part of a lengthy process where you want to document an -error but keep going, you can set .error to some -object of a compatible type. That object will be returned in -the event of error and will have as its "error" -attribute the error object.

    .finish

    A function to run on the result before returning it. Ignored -if .docall is FALSE.

    - -

    Value

    - -

    Either a named list or the result of calling fun with the - supplied arguments

    - -
    - -
    - - -
    - - -
    -

    Site built with pkgdown 1.5.1.

    -
    - -
    -
    - - - - - - - - diff --git a/docs/reference/characterize.html b/docs/reference/characterize.html deleted file mode 100644 index 4f6bfc1..0000000 --- a/docs/reference/characterize.html +++ /dev/null @@ -1,226 +0,0 @@ - - - - - - - - -Character conversion of labelled data — characterize • rio - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - - -
    - -
    -
    - - -
    -

    Convert labelled variables to character or factor

    -
    - -
    characterize(x, ...)
    -
    -factorize(x, ...)
    -
    -# S3 method for default
    -characterize(x, ...)
    -
    -# S3 method for data.frame
    -characterize(x, ...)
    -
    -# S3 method for default
    -factorize(x, coerce_character = FALSE, ...)
    -
    -# S3 method for data.frame
    -factorize(x, ...)
    - -

    Arguments

    - - - - - - - - - - - - - - -
    x

    A vector or data frame.

    ...

    additional arguments passed to methods

    coerce_character

    A logical indicating whether to additionally coerce character columns to factor (in factorize). Default FALSE.

    - -

    Details

    - -

    characterize converts a vector with a labels attribute of named levels into a character vector. factorize does the same but to factors. This can be useful at two stages of a data workflow: (1) importing labelled data from metadata-rich file formats (e.g., Stata or SPSS), and (2) exporting such data to plain text files (e.g., CSV) in a way that preserves information.

    -

    See also

    - - - -

    Examples

    -
    # vector method -x <- structure(1:4, labels = c("A" = 1, "B" = 2, "C" = 3)) -characterize(x)
    #> [1] "A" "B" "C" NA
    factorize(x)
    #> [1] A B C <NA> -#> Levels: A B C
    -# data frame method -x <- data.frame(v1 = structure(1:4, labels = c("A" = 1, "B" = 2, "C" = 3)), - v2 = structure(c(1,0,0,1), labels = c("foo" = 0, "bar" = 1))) -str(factorize(x))
    #> 'data.frame': 4 obs. of 2 variables: -#> $ v1: Factor w/ 3 levels "A","B","C": 1 2 3 NA -#> $ v2: Factor w/ 2 levels "foo","bar": 2 1 1 2
    str(characterize(x))
    #> 'data.frame': 4 obs. of 2 variables: -#> $ v1: chr "A" "B" "C" NA -#> $ v2: chr "bar" "foo" "foo" "bar"
    -# comparison of exported file contents -import(export(x, "example.csv"))
    #> v1 v2 -#> 1 1 1 -#> 2 2 0 -#> 3 3 0 -#> 4 4 1
    import(export(factorize(x), "example.csv"))
    #> v1 v2 -#> 1 A bar -#> 2 B foo -#> 3 C foo -#> 4 bar
    -# cleanup -unlink("example.csv")
    -
    - -
    - - -
    - - -
    -

    Site built with pkgdown 1.5.1.

    -
    - -
    -
    - - - - - - - - diff --git a/docs/reference/convert.html b/docs/reference/convert.html deleted file mode 100644 index 4a0b5bc..0000000 --- a/docs/reference/convert.html +++ /dev/null @@ -1,193 +0,0 @@ - - - - - - - - -Convert from one file format to another — convert • rio - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - - -
    - -
    -
    - - -
    -

    This function constructs a data frame from a data file using import and uses export to write the data to disk in the format indicated by the file extension.

    -
    - -
    convert(in_file, out_file, in_opts = list(), out_opts = list())
    - -

    Arguments

    - - - - - - - - - - - - - - - - - - -
    in_file

    A character string naming an input file.

    out_file

    A character string naming an output file.

    in_opts

    A named list of options to be passed to import.

    out_opts

    A named list of options to be passed to export.

    - -

    Value

    - -

    A character string containing the name of the output file (invisibly).

    -

    See also

    - -

    Luca Braglia has created a Shiny app called rioweb that provides access to the file conversion features of rio through a web browser. The app is featured in the RStudio Shiny Gallery.

    - -

    Examples

    -
    
    -  
    - -
    - - -
    - - -
    -

    Site built with pkgdown 1.5.1.

    -
    - -
    -
    - - - - - - - - diff --git a/docs/reference/export.html b/docs/reference/export.html deleted file mode 100644 index b64023c..0000000 --- a/docs/reference/export.html +++ /dev/null @@ -1,293 +0,0 @@ - - - - - - - - -Export — export • rio - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - - -
    - -
    -
    - - -
    -

    Write data.frame to a file

    -
    - -
    export(x, file, format, ...)
    - -

    Arguments

    - - - - - - - - - - - - - - - - - - -
    x

    A data frame or matrix to be written into a file. Exceptions to this rule are that x can be a list of data frames if the output file format is an Excel .xlsx workbook, .Rdata file, or HTML file, or a variety of R objects if the output file format is RDS or JSON. See examples.) To export a list of data frames to multiple files, use export_list instead.

    file

    A character string naming a file. Must specify file and/or format.

    format

    An optional character string containing the file format, which can be used to override the format inferred from file or, in lieu of specifying file, a file with the symbol name of x and the specified file extension will be created. Must specify file and/or format. Shortcuts include: “,” (for comma-separated values), “;” (for semicolon-separated values), “|” (for pipe-separated values), and “dump” for dump.

    ...

    Additional arguments for the underlying export functions. This can be used to specify non-standard arguments. See examples.

    - -

    Value

    - -

    The name of the output file as a character string (invisibly).

    -

    Details

    - -

    This function exports a data frame or matrix into a file with file format based on the file extension (or the manually specified format, if format is specified).

    -

    The output file can be to a compressed directory, simply by adding an appropriate additional extensiont to the file argument, such as: “mtcars.csv.tar”, “mtcars.csv.zip”, or “mtcars.csv.gz”.

    -

    export supports many file formats. See the documentation for the underlying export functions for optional arguments that can be passed via ...

    -
      -
    • Comma-separated data (.csv), using fwrite or, if fwrite = TRUE, write.table with row.names = FALSE.

    • -
    • Pipe-separated data (.psv), using fwrite or, if fwrite = TRUE, write.table with sep = '|' and row.names = FALSE.

    • -
    • Tab-separated data (.tsv), using fwrite or, if fwrite = TRUE, write.table with row.names = FALSE.

    • -
    • SAS (.sas7bdat), using write_sas.

    • -
    • SAS XPORT (.xpt), using write_xpt.

    • -
    • SPSS (.sav), using write_sav

    • -
    • SPSS compressed (.zsav), using write_sav

    • -
    • Stata (.dta), using write_dta. Note that variable/column names containing dots (.) are not allowed and will produce an error.

    • -
    • Excel (.xlsx), using write.xlsx. Existing workbooks are overwritten unless which is specified, in which case only the specified sheet (if it exists) is overwritten. If the file exists but the which sheet does not, data are added as a new sheet to the existing workbook. x can also be a list of data frames; the list entry names are used as sheet names.

    • -
    • R syntax object (.R), using dput (by default) or dump (if format = 'dump')

    • -
    • Saved R objects (.RData,.rda), using save. In this case, x can be a data frame, a named list of objects, an R environment, or a character vector containing the names of objects if a corresponding envir argument is specified.

    • -
    • Serialized R objects (.rds), using saveRDS. In this case, x can be any serializable R object.

    • -
    • "XBASE" database files (.dbf), using write.dbf

    • -
    • Weka Attribute-Relation File Format (.arff), using write.arff

    • -
    • Fixed-width format data (.fwf), using write.table with row.names = FALSE, quote = FALSE, and col.names = FALSE

    • -
    • gzip comma-separated data (.csv.gz), using write.table with row.names = FALSE

    • -
    • CSVY (CSV with a YAML metadata header) using fwrite.

    • -
    • Apache Arrow Parquet (.parquet), using write_parquet

    • -
    • Feather R/Python interchange format (.feather), using write_feather

    • -
    • Fast storage (.fst), using write.fst

    • -
    • JSON (.json), using toJSON. In this case, x can be a variety of R objects, based on class mapping conventions in this paper: https://arxiv.org/abs/1403.2805.

    • -
    • Matlab (.mat), using write.mat

    • -
    • OpenDocument Spreadsheet (.ods), using write_ods. (Currently only single-sheet exports are supported.)

    • -
    • HTML (.html), using a custom method based on xml_add_child to create a simple HTML table and write_xml to write to disk.

    • -
    • XML (.xml), using a custom method based on xml_add_child to create a simple XML tree and write_xml to write to disk.

    • -
    • YAML (.yml), using as.yaml

    • -
    • Clipboard export (on Windows and Mac OS), using write.table with row.names = FALSE

    • -
    - -

    When exporting a data set that contains label attributes (e.g., if imported from an SPSS or Stata file) to a plain text file, characterize can be a useful pre-processing step that records value labels into the resulting file (e.g., export(characterize(x), "file.csv")) rather than the numeric values.

    -

    Use export_list to export a list of dataframes to separate files.

    -

    See also

    - - - -

    Examples

    -
    library("datasets") -# specify only `file` argument -export(mtcars, "mtcars.csv") - -if (FALSE) { -# Stata does not recognize variables names with '.' -export(mtcars, "mtcars.dta") -} - -# specify only `format` argument -"mtcars.dta" %in% dir()
    #> [1] FALSE
    export(mtcars, format = "stata") -"mtcars.dta" %in% dir()
    #> [1] TRUE
    -# specify `file` and `format` to override default format -export(mtcars, file = "mtcars.txt", format = "csv") - -# export multiple objects to Rdata -export(list(mtcars = mtcars, iris = iris), "mtcars.rdata") -export(c("mtcars", "iris"), "mtcars.rdata") - -# export to non-data frame R object to RDS or JSON -export(mtcars$cyl, "mtcars_cyl.rds") -export(list(iris, mtcars), "list.json")
    #> Loading required namespace: jsonlite
    -# pass arguments to underlying export function -export(mtcars, "mtcars.csv", col.names = FALSE) - -# write data to .R syntax file and append additional data -export(mtcars, file = "data.R", format = "dump") -export(mtcars, file = "data.R", format = "dump", append = TRUE) -source("data.R", echo = TRUE)
    #> -#> > x <- structure(list(mpg = c(21, 21, 22.8, 21.4, 18.7, -#> + 18.1, 14.3, 24.4, 22.8, 19.2, 17.8, 16.4, 17.3, 15.2, 10.4, -#> + 10.4, 14.7, 32.4, 30 .... [TRUNCATED] -#> -#> > x <- structure(list(mpg = c(21, 21, 22.8, 21.4, 18.7, -#> + 18.1, 14.3, 24.4, 22.8, 19.2, 17.8, 16.4, 17.3, 15.2, 10.4, -#> + 10.4, 14.7, 32.4, 30 .... [TRUNCATED]
    -# write to an Excel workbook -if (FALSE) { - ## export a single data frame - export(mtcars, "mtcars.xlsx") - - ## export NAs to Excel as missing via args passed to `...` - mtcars$drat <- NA_real_ - mtcars %>% export("tst2.xlsx", keepNA = TRUE) - - ## export a list of data frames as worksheets - export(list(a = mtcars, b = iris), "multisheet.xlsx") - - ## export, adding a new sheet to an existing workbook - export(iris, "mtcars.xlsx", which = "iris") -} - -# write data to a zip-compressed CSV -export(mtcars, "mtcars.csv.zip") - -# cleanup -unlink("mtcars.csv") -unlink("mtcars.dta") -unlink("mtcars.txt") -unlink("mtcars_cyl.rds") -unlink("mtcars.rdata") -unlink("data.R") -unlink("mtcars.csv.zip") -unlink("list.json")
    -
    - -
    - - -
    - - -
    -

    Site built with pkgdown 1.5.1.

    -
    - -
    -
    - - - - - - - - diff --git a/docs/reference/export_list.html b/docs/reference/export_list.html deleted file mode 100644 index 5e0ad9a..0000000 --- a/docs/reference/export_list.html +++ /dev/null @@ -1,210 +0,0 @@ - - - - - - - - -Export list of data frames to files — export_list • rio - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - - -
    - -
    -
    - - -
    -

    Use export to export a list of data frames to a vector of file names or a filename pattern.

    -
    - -
    export_list(x, file, ...)
    - -

    Arguments

    - - - - - - - - - - - - - - -
    x

    A list of data frames to be written to files.

    file

    A character vector string containing a single file name with a %s wildcard placeholder, or a vector of file paths for multiple files to be imported. If x elements are named, these will be used in place of %s, otherwise numbers will be used; all elements must be named for names to be used.

    ...

    Additional arguments passed to export.

    - -

    Value

    - -

    The name(s) of the output file(s) as a character vector (invisibly).

    -

    Details

    - -

    export can export a list of data frames to a single multi-dataset file (e.g., an Rdata or Excel .xlsx file). Use export_list to export such a list to multiple files.

    -

    See also

    - - - -

    Examples

    -
    library('datasets') -export(list(mtcars1 = mtcars[1:10,], - mtcars2 = mtcars[11:20,], - mtcars3 = mtcars[21:32,]), "mtcars.xlsx") - -# import all worksheets -mylist <- import_list("mtcars.xlsx") - -# re-export as separate named files -export_list(mylist, file = paste0("mtcars", 1:3, ".csv")) - -# re-export as separate files using a name pattern -export_list(mylist, file = "%s.csv") - -# cleanup -unlink("mtcars.xlsx") -unlink("mtcars1.csv") -unlink("mtcars2.csv") -unlink("mtcars3.csv")
    -
    - -
    - - -
    - - -
    -

    Site built with pkgdown 1.5.1.

    -
    - -
    -
    - - - - - - - - diff --git a/docs/reference/extensions.html b/docs/reference/extensions.html deleted file mode 100644 index 625e1af..0000000 --- a/docs/reference/extensions.html +++ /dev/null @@ -1,200 +0,0 @@ - - - - - - - - -rio Extensions — .import • rio - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - - -
    - -
    -
    - - -
    -

    Writing Import/Export Extensions for rio

    -
    - -
    .import(file, ...)
    -
    -# S3 method for default
    -.import(file, ...)
    -
    -.export(file, x, ...)
    -
    -# S3 method for default
    -.export(file, x, ...)
    - -

    Arguments

    - - - - - - - - - - - - - - -
    file

    A character string naming a file.

    ...

    Additional arguments passed to methods.

    x

    A data frame or matrix to be written into a file.

    - -

    Value

    - -

    For .import, an R data.frame. For .export, file, invisibly.

    -

    Details

    - -

    rio implements format-specific S3 methods for each type of file that can be imported from or exported to. This happens via internal S3 generics, .import and .export. It is possible to write new methods like with any S3 generic (e.g., print).

    -

    As an example, .import.rio_csv imports from a comma-separated values file. If you want to produce a method for a new filetype with extension “myfile”, you simply have to create a function called .import.rio_myfile that implements a format-specific importing routine and returns a data.frame. rio will automatically recognize new S3 methods, so that you can then import your file using: import("file.myfile").

    -

    As general guidance, if an import method creates many attributes, these attributes should be stored --- to the extent possible --- in variable-level attributes fields. These can be “gathered” to the data.frame level by the user via gather_attrs.

    -

    See also

    - - - -
    - -
    - - -
    - - -
    -

    Site built with pkgdown 1.5.1.

    -
    - -
    -
    - - - - - - - - diff --git a/docs/reference/figures/logo.png b/docs/reference/figures/logo.png deleted file mode 100644 index eda1a58bb22355b3211f1d871790027e433bcd47..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11768 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 - - - - - - - image/svg+xml - - - - - - - - - - - - - - RIO - - - - - - diff --git a/docs/reference/figures/logo.xcf b/docs/reference/figures/logo.xcf deleted file mode 100644 index 3c4e16c9a2b2a597da33d0e93798db91d599db24..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 78942 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 - - - - - - - -Gather attributes from data frame variables — gather_attrs • rio - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - - -
    - -
    -
    - - -
    -

    gather_attrs moves variable-level attributes to the data frame level and spread_attrs reverses that operation.

    -
    - -
    gather_attrs(x)
    -
    -spread_attrs(x)
    - -

    Arguments

    - - - - - - -
    x

    A data frame.

    - -

    Value

    - -

    x, with variable-level attributes stored at the data frame level.

    -

    Details

    - -

    import attempts to standardize the return value from the various import functions to the extent possible, thus providing a uniform data structure regardless of what import package or function is used. It achieves this by storing any optional variable-related attributes at the variable level (i.e., an attribute for mtcars$mpg is stored in attributes(mtcars$mpg) rather than attributes(mtcars)). gather_attrs moves these to the data frame level (i.e., in attributes(mtcars)). spread_attrs moves attributes back to the variable level.

    -

    See also

    - - - -

    Examples

    -
    e <- import("http://www.stata-press.com/data/r13/auto.dta") -str(e)
    #> 'data.frame': 74 obs. of 12 variables: -#> $ make : chr "AMC Concord" "AMC Pacer" "AMC Spirit" "Buick Century" ... -#> ..- attr(*, "label")= chr "Make and Model" -#> ..- attr(*, "format.stata")= chr "%-18s" -#> $ price : num 4099 4749 3799 4816 7827 ... -#> ..- attr(*, "label")= chr "Price" -#> ..- attr(*, "format.stata")= chr "%8.0gc" -#> $ mpg : num 22 17 22 20 15 18 26 20 16 19 ... -#> ..- attr(*, "label")= chr "Mileage (mpg)" -#> ..- attr(*, "format.stata")= chr "%8.0g" -#> $ rep78 : num 3 3 NA 3 4 3 NA 3 3 3 ... -#> ..- attr(*, "label")= chr "Repair Record 1978" -#> ..- attr(*, "format.stata")= chr "%8.0g" -#> $ headroom : num 2.5 3 3 4.5 4 4 3 2 3.5 3.5 ... -#> ..- attr(*, "label")= chr "Headroom (in.)" -#> ..- attr(*, "format.stata")= chr "%6.1f" -#> $ trunk : num 11 11 12 16 20 21 10 16 17 13 ... -#> ..- attr(*, "label")= chr "Trunk space (cu. ft.)" -#> ..- attr(*, "format.stata")= chr "%8.0g" -#> $ weight : num 2930 3350 2640 3250 4080 3670 2230 3280 3880 3400 ... -#> ..- attr(*, "label")= chr "Weight (lbs.)" -#> ..- attr(*, "format.stata")= chr "%8.0gc" -#> $ length : num 186 173 168 196 222 218 170 200 207 200 ... -#> ..- attr(*, "label")= chr "Length (in.)" -#> ..- attr(*, "format.stata")= chr "%8.0g" -#> $ turn : num 40 40 35 40 43 43 34 42 43 42 ... -#> ..- attr(*, "label")= chr "Turn Circle (ft.) " -#> ..- attr(*, "format.stata")= chr "%8.0g" -#> $ displacement: num 121 258 121 196 350 231 304 196 231 231 ... -#> ..- attr(*, "label")= chr "Displacement (cu. in.)" -#> ..- attr(*, "format.stata")= chr "%8.0g" -#> $ gear_ratio : num 3.58 2.53 3.08 2.93 2.41 ... -#> ..- attr(*, "label")= chr "Gear Ratio" -#> ..- attr(*, "format.stata")= chr "%6.2f" -#> $ foreign : num 0 0 0 0 0 0 0 0 0 0 ... -#> ..- attr(*, "label")= chr "Car type" -#> ..- attr(*, "format.stata")= chr "%8.0g" -#> ..- attr(*, "labels")= Named num [1:2] 0 1 -#> .. ..- attr(*, "names")= chr [1:2] "Domestic" "Foreign" -#> - attr(*, "label")= chr "1978 Automobile Data" -#> - attr(*, "notes")= chr [1:2] "from Consumer Reports with permission" "1"
    g <- gather_attrs(e) -str(attributes(e))
    #> List of 5 -#> $ label : chr "1978 Automobile Data" -#> $ notes : chr [1:2] "from Consumer Reports with permission" "1" -#> $ names : chr [1:12] "make" "price" "mpg" "rep78" ... -#> $ row.names: int [1:74] 1 2 3 4 5 6 7 8 9 10 ... -#> $ class : chr "data.frame"
    str(g)
    #> 'data.frame': 74 obs. of 12 variables: -#> $ make : chr "AMC Concord" "AMC Pacer" "AMC Spirit" "Buick Century" ... -#> $ price : num 4099 4749 3799 4816 7827 ... -#> $ mpg : num 22 17 22 20 15 18 26 20 16 19 ... -#> $ rep78 : num 3 3 NA 3 4 3 NA 3 3 3 ... -#> $ headroom : num 2.5 3 3 4.5 4 4 3 2 3.5 3.5 ... -#> $ trunk : num 11 11 12 16 20 21 10 16 17 13 ... -#> $ weight : num 2930 3350 2640 3250 4080 3670 2230 3280 3880 3400 ... -#> $ length : num 186 173 168 196 222 218 170 200 207 200 ... -#> $ turn : num 40 40 35 40 43 43 34 42 43 42 ... -#> $ displacement: num 121 258 121 196 350 231 304 196 231 231 ... -#> $ gear_ratio : num 3.58 2.53 3.08 2.93 2.41 ... -#> $ foreign : num 0 0 0 0 0 0 0 0 0 0 ... -#> ..- attr(*, "labels")= Named num [1:2] 0 1 -#> .. ..- attr(*, "names")= chr [1:2] "Domestic" "Foreign" -#> - attr(*, "title")= chr "1978 Automobile Data" -#> - attr(*, "notes")= chr [1:2] "from Consumer Reports with permission" "1" -#> - attr(*, "format.stata")=List of 12 -#> ..$ make : chr "%-18s" -#> ..$ price : chr "%8.0gc" -#> ..$ mpg : chr "%8.0g" -#> ..$ rep78 : chr "%8.0g" -#> ..$ headroom : chr "%6.1f" -#> ..$ trunk : chr "%8.0g" -#> ..$ weight : chr "%8.0gc" -#> ..$ length : chr "%8.0g" -#> ..$ turn : chr "%8.0g" -#> ..$ displacement: chr "%8.0g" -#> ..$ gear_ratio : chr "%6.2f" -#> ..$ foreign : chr "%8.0g" -#> - attr(*, "label")=List of 12 -#> ..$ make : chr "Make and Model" -#> ..$ price : chr "Price" -#> ..$ mpg : chr "Mileage (mpg)" -#> ..$ rep78 : chr "Repair Record 1978" -#> ..$ headroom : chr "Headroom (in.)" -#> ..$ trunk : chr "Trunk space (cu. ft.)" -#> ..$ weight : chr "Weight (lbs.)" -#> ..$ length : chr "Length (in.)" -#> ..$ turn : chr "Turn Circle (ft.) " -#> ..$ displacement: chr "Displacement (cu. in.)" -#> ..$ gear_ratio : chr "Gear Ratio" -#> ..$ foreign : chr "Car type" -#> - attr(*, "labels")=List of 12 -#> ..$ make : NULL -#> ..$ price : NULL -#> ..$ mpg : NULL -#> ..$ rep78 : NULL -#> ..$ headroom : NULL -#> ..$ trunk : NULL -#> ..$ weight : NULL -#> ..$ length : NULL -#> ..$ turn : NULL -#> ..$ displacement: NULL -#> ..$ gear_ratio : NULL -#> ..$ foreign : Named num [1:2] 0 1 -#> .. ..- attr(*, "names")= chr [1:2] "Domestic" "Foreign"
    -
    - -
    - - -
    - - -
    -

    Site built with pkgdown 1.5.1.

    -
    - -
    -
    - - - - - - - - diff --git a/docs/reference/get_ext.html b/docs/reference/get_ext.html deleted file mode 100644 index 3e3ef9e..0000000 --- a/docs/reference/get_ext.html +++ /dev/null @@ -1,176 +0,0 @@ - - - - - - - - -Get File Type from Extension — get_ext • rio - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - - -
    - -
    -
    - - -
    -

    A utility function to retrieve the file type from a file extension (via its filename/path/URL)

    -
    - -
    get_ext(file)
    - -

    Arguments

    - - - - - - -
    file

    A character string containing a filename, file path, or URL.

    - -

    Value

    - -

    A characters string containing a file type recognized by rio.

    - -
    - -
    - - -
    - - -
    -

    Site built with pkgdown 1.5.1.

    -
    - -
    -
    - - - - - - - - diff --git a/docs/reference/import.html b/docs/reference/import.html deleted file mode 100644 index 77c8586..0000000 --- a/docs/reference/import.html +++ /dev/null @@ -1,273 +0,0 @@ - - - - - - - - -Import — import • rio - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - - -
    - -
    -
    - - -
    -

    Read in a data.frame from a file. Exceptions to this rule are Rdata, RDS, and JSON input file formats, which return the originally saved object without changing its class.

    -
    - -
    import(file, format, setclass, which, ...)
    - -

    Arguments

    - - - - - - - - - - - - - - - - - - - - - - -
    file

    A character string naming a file, URL, or single-file .zip or .tar archive.

    format

    An optional character string code of file format, which can be used to override the format inferred from file. Shortcuts include: “,” (for comma-separated values), “;” (for semicolon-separated values), and “|” (for pipe-separated values).

    setclass

    An optional character vector specifying one or more classes to set on the import. By default, the return object is always a “data.frame”. Allowed values include “tbl_df”, “tbl”, or “tibble” (if using dplyr) or “data.table” (if using data.table). Other values are ignored, such that a data.frame is returned.

    which

    This argument is used to control import from multi-object files; as a rule import only ever returns a single data frame (use import_list to import multiple data frames from a multi-object file). If file is a compressed directory, which can be either a character string specifying a filename or an integer specifying which file (in locale sort order) to extract from the compressed directory. For Excel spreadsheets, this can be used to specify a sheet name or number. For .Rdata files, this can be an object name. For HTML files, it identifies which table to extract (from document order). Ignored otherwise. A character string value will be used as a regular expression, such that the extracted file is the first match of the regular expression against the file names in the archive.

    ...

    Additional arguments passed to the underlying import functions. For example, this can control column classes for delimited file types, or control the use of haven for Stata and SPSS or readxl for Excel (.xlsx) format. See details below.

    - -

    Value

    - -

    A data frame. If setclass is used, this data frame may have additional class attribute values, such as “tibble” or “data.table”.

    -

    Details

    - -

    This function imports a data frame or matrix from a data file with the file format based on the file extension (or the manually specified format, if format is specified).

    -

    import supports the following file formats:

    -
      -
    • Comma-separated data (.csv), using fread or, if fread = FALSE, read.table with row.names = FALSE and stringsAsFactors = FALSE

    • -
    • Pipe-separated data (.psv), using fread or, if fread = FALSE, read.table with sep = '|', row.names = FALSE and stringsAsFactors = FALSE

    • -
    • Tab-separated data (.tsv), using fread or, if fread = FALSE, read.table with row.names = FALSE and stringsAsFactors = FALSE

    • -
    • SAS (.sas7bdat), using read_sas.

    • -
    • SAS XPORT (.xpt), using read_xpt or, if haven = FALSE, read.xport.

    • -
    • SPSS (.sav), using read_sav. If haven = FALSE, read.spss can be used.

    • -
    • SPSS compressed (.zsav), using read_sav.

    • -
    • Stata (.dta), using read_dta. If haven = FALSE, read.dta can be used.

    • -
    • SPSS Portable Files (.por), using read_por.

    • -
    • Excel (.xls and .xlsx), using read_excel. Use which to specify a sheet number. For .xlsx files, it is possible to set readxl = FALSE, so that read.xlsx can be used instead of readxl (the default).

    • -
    • R syntax object (.R), using dget

    • -
    • Saved R objects (.RData,.rda), using load for single-object .Rdata files. Use which to specify an object name for multi-object .Rdata files. This can be any R object (not just a data frame).

    • -
    • Serialized R objects (.rds), using readRDS. This can be any R object (not just a data frame).

    • -
    • Epiinfo (.rec), using read.epiinfo

    • -
    • Minitab (.mtp), using read.mtp

    • -
    • Systat (.syd), using read.systat

    • -
    • "XBASE" database files (.dbf), using read.dbf

    • -
    • Weka Attribute-Relation File Format (.arff), using read.arff

    • -
    • Data Interchange Format (.dif), using read.DIF

    • -
    • Fortran data (no recognized extension), using read.fortran

    • -
    • Fixed-width format data (.fwf), using a faster version of read.fwf that requires a widths argument and by default in rio has stringsAsFactors = FALSE. If readr = TRUE, import will be performed using read_fwf, where widths should be: NULL, a vector of column widths, or the output of fwf_empty, fwf_widths, or fwf_positions.

    • -
    • gzip comma-separated data (.csv.gz), using read.table with row.names = FALSE and stringsAsFactors = FALSE

    • -
    • CSVY (CSV with a YAML metadata header) using fread.

    • -
    • Apache Arrow Parquet (.parquet), using read_parquet

    • -
    • Feather R/Python interchange format (.feather), using read_feather

    • -
    • Fast storage (.fst), using read.fst

    • -
    • JSON (.json), using fromJSON

    • -
    • Matlab (.mat), using read.mat

    • -
    • EViews (.wf1), using readEViews

    • -
    • OpenDocument Spreadsheet (.ods), using read_ods. Use which to specify a sheet number.

    • -
    • Single-table HTML documents (.html), using read_html. The data structure will only be read correctly if the HTML file can be converted to a list via as_list.

    • -
    • Shallow XML documents (.xml), using read_xml. The data structure will only be read correctly if the XML file can be converted to a list via as_list.

    • -
    • YAML (.yml), using yaml.load

    • -
    • Clipboard import (on Windows and Mac OS), using read.table with row.names = FALSE

    • -
    • Google Sheets, as Comma-separated data (.csv)

    • -
    • GraphPad Prism (.pzfx) using read_pzfx

    • -
    - -

    import attempts to standardize the return value from the various import functions to the extent possible, thus providing a uniform data structure regardless of what import package or function is used. It achieves this by storing any optional variable-related attributes at the variable level (i.e., an attribute for mtcars$mpg is stored in attributes(mtcars$mpg) rather than attributes(mtcars)). If you would prefer these attributes to be stored at the data.frame-level (i.e., in attributes(mtcars)), see gather_attrs.

    -

    After importing metadata-rich file formats (e.g., from Stata or SPSS), it may be helpful to recode labelled variables to character or factor using characterize or factorize respectively.

    -

    Note

    - -

    For csv and txt files with row names exported from export, it may be helpful to specify row.names as the column of the table which contain row names. See example below.

    -

    See also

    - - - -

    Examples

    -
    # create CSV to import -export(iris, "iris1.csv") - -# specify `format` to override default format -export(iris, "iris.tsv", format = "csv") -stopifnot(identical(import("iris1.csv"), import("iris.tsv", format = "csv"))) - -# import CSV as a `data.table` -stopifnot(inherits(import("iris1.csv", setclass = "data.table"), "data.table")) - -# pass arguments to underlying import function -iris1 <- import("iris1.csv") -identical(names(iris), names(iris1))
    #> [1] TRUE
    -export(iris, "iris2.csv", col.names = FALSE) -iris2 <- import("iris2.csv") -identical(names(iris), names(iris2))
    #> [1] FALSE
    -# set class for the response data.frame as "tbl_df" (from dplyr) -stopifnot(inherits(import("iris1.csv", setclass = "tbl_df"), "tbl_df")) - -# non-data frame formats supported for RDS, Rdata, and JSON -export(list(mtcars, iris), "list.rds") -li <- import("list.rds") -identical(names(mtcars), names(li[[1]]))
    #> [1] TRUE
    -# cleanup -unlink("iris.tsv") -unlink("iris1.csv") -unlink("iris2.csv") -unlist("list.rds")
    #> [1] "list.rds"
    -
    -
    - -
    - - -
    - - -
    -

    Site built with pkgdown 1.5.1.

    -
    - -
    -
    - - - - - - - - diff --git a/docs/reference/import_list.html b/docs/reference/import_list.html deleted file mode 100644 index 5c476be..0000000 --- a/docs/reference/import_list.html +++ /dev/null @@ -1,250 +0,0 @@ - - - - - - - - -Import list of data frames — import_list • rio - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - - -
    - -
    -
    - - -
    -

    Use import to import a list of data frames from a vector of file names or from a multi-object file (Excel workbook, .Rdata file, zip directory, or HTML file)

    -
    - -
    import_list(
    -  file,
    -  setclass,
    -  which,
    -  rbind = FALSE,
    -  rbind_label = "_file",
    -  rbind_fill = TRUE,
    -  ...
    -)
    - -

    Arguments

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    file

    A character string containing a single file name for a multi-object file (e.g., Excel workbook, zip directory, or HTML file), or a vector of file paths for multiple files to be imported.

    setclass

    An optional character vector specifying one or more classes to set on the import. By default, the return object is always a “data.frame”. Allowed values include “tbl_df”, “tbl”, or “tibble” (if using dplyr) or “data.table” (if using data.table). Other values are ignored, such that a data.frame is returned.

    which

    If file is a single file path, this specifies which objects should be extracted (passed to import's which argument). Ignored otherwise.

    rbind

    A logical indicating whether to pass the import list of data frames through rbindlist.

    rbind_label

    If rbind = TRUE, a character string specifying the name of a column to add to the data frame indicating its source file.

    rbind_fill

    If rbind = TRUE, a logical indicating whether to set the fill = TRUE (and fill missing columns with NA).

    ...

    Additional arguments passed to import. Behavior may be unexpected if files are of different formats.

    - -

    Value

    - -

    If rbind=FALSE (the default), a list of a data frames. Otherwise, that list is passed to rbindlist with fill = TRUE and returns a data frame object of class set by the setclass argument; if this operation fails, the list is returned.

    -

    See also

    - - - -

    Examples

    -
    library('datasets') -export(list(mtcars1 = mtcars[1:10,], - mtcars2 = mtcars[11:20,], - mtcars2 = mtcars[21:32,]), "mtcars.xlsx") - -# import a single file from multi-object workbook -str(import("mtcars.xlsx", which = "mtcars1"))
    #> 'data.frame': 10 obs. of 11 variables: -#> $ mpg : num 21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 -#> $ cyl : num 6 6 4 6 8 6 8 4 4 6 -#> $ disp: num 160 160 108 258 360 ... -#> $ hp : num 110 110 93 110 175 105 245 62 95 123 -#> $ drat: num 3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 -#> $ wt : num 2.62 2.88 2.32 3.21 3.44 ... -#> $ qsec: num 16.5 17 18.6 19.4 17 ... -#> $ vs : num 0 0 1 1 0 1 0 1 1 1 -#> $ am : num 1 1 1 0 0 0 0 0 0 0 -#> $ gear: num 4 4 4 3 3 3 3 4 4 4 -#> $ carb: num 4 4 1 1 2 1 4 2 2 4
    -# import all worksheets -str(import_list("mtcars.xlsx"), 1)
    #> List of 3 -#> $ mtcars1 :'data.frame': 10 obs. of 11 variables: -#> $ mtcars2 :'data.frame': 10 obs. of 11 variables: -#> $ mtcars2.1:'data.frame': 12 obs. of 11 variables:
    -# import and rbind all worksheets -mtcars2 <- import_list("mtcars.xlsx", rbind = TRUE) -all.equal(mtcars2, mtcars, check.attributes = FALSE)
    #> [1] "Length mismatch: comparison on first 11 components"
    -# import multiple files -export(mtcars, "mtcars.csv") -export(mtcars, "iris.csv") -str(import_list(dir(pattern = "csv$")), 1)
    #> List of 2 -#> $ iris :'data.frame': 32 obs. of 11 variables: -#> ..- attr(*, "filename")= chr "iris.csv" -#> $ mtcars:'data.frame': 32 obs. of 11 variables: -#> ..- attr(*, "filename")= chr "mtcars.csv"
    -# cleanup -unlink("mtcars.xlsx") -unlink("mtcars.csv") -unlink("iris.csv")
    -
    - -
    - - -
    - - -
    -

    Site built with pkgdown 1.5.1.

    -
    - -
    -
    - - - - - - - - diff --git a/docs/reference/index.html b/docs/reference/index.html deleted file mode 100644 index 4b97779..0000000 --- a/docs/reference/index.html +++ /dev/null @@ -1,256 +0,0 @@ - - - - - - - - -Function reference • rio - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - - -
    - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -

    All functions

    -

    -
    -

    arg_reconcile()

    -

    Reconcile an argument list to any function signature.

    -

    characterize() factorize()

    -

    Character conversion of labelled data

    -

    convert()

    -

    Convert from one file format to another

    -

    export()

    -

    Export

    -

    export_list()

    -

    Export list of data frames to files

    -

    .import() .export()

    -

    rio Extensions

    -

    gather_attrs() spread_attrs()

    -

    Gather attributes from data frame variables

    -

    get_ext()

    -

    Get File Type from Extension

    -

    import()

    -

    Import

    -

    import_list()

    -

    Import list of data frames

    -

    install_formats()

    -

    Install rio's ‘Suggests’ Dependencies

    -

    is_file_text()

    -

    Determine whether a file is “plain-text” or some sort of binary format

    -

    rio

    -

    A Swiss-Army Knife for Data I/O

    -
    - - -
    - - -
    - - -
    -

    Site built with pkgdown 1.5.1.

    -
    - -
    -
    - - - - - - - - diff --git a/docs/reference/install_formats.html b/docs/reference/install_formats.html deleted file mode 100644 index ec0a611..0000000 --- a/docs/reference/install_formats.html +++ /dev/null @@ -1,176 +0,0 @@ - - - - - - - - -Install rio's ‘Suggests’ Dependencies — install_formats • rio - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - - -
    - -
    -
    - - -
    -

    This function installs various ‘Suggests’ dependencies for rio that expand its support to the full range of support import and export formats. These packages are not installed or loaded by default in order to create a slimmer and faster package build, install, and load.

    -
    - -
    install_formats(...)
    - -

    Arguments

    - - - - - - -
    ...

    Additional arguments passed to install.packages.

    - -

    Value

    - -

    NULL

    - -
    - -
    - - -
    - - -
    -

    Site built with pkgdown 1.5.1.

    -
    - -
    -
    - - - - - - - - diff --git a/docs/reference/is_file_text.html b/docs/reference/is_file_text.html deleted file mode 100644 index a3a5f2e..0000000 --- a/docs/reference/is_file_text.html +++ /dev/null @@ -1,196 +0,0 @@ - - - - - - - - -Determine whether a file is “plain-text” or some sort of binary format — is_file_text • rio - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - - -
    - -
    -
    - - -
    -

    Determine whether a file is “plain-text” or some sort of binary format

    -
    - -
    is_file_text(file, maxsize = Inf, text_bytes = as.raw(c(7:16, 18, 19, 32:255)))
    - -

    Arguments

    - - - - - - - - - - - - - - -
    file

    Path to the file

    maxsize

    Maximum number of bytes to read

    text_bytes

    Which characters are used by normal text (though not -necessarily just ASCII). To detect just ASCII, the -following value can be used: -as.raw(c(7:16, 18, 19, 32:127))

    - -

    Value

    - -

    A logical

    - -

    Examples

    -
    library(datasets) -export(iris, "iris.yml") -is_file_text("iris.yml") # TRUE
    #> [1] TRUE
    -export(iris, "iris.sav") -is_file_text("iris.sav") # FALSE
    #> [1] FALSE
    -# cleanup -unlink("iris.yml") -unlink("iris.sav")
    -
    - -
    - - -
    - - -
    -

    Site built with pkgdown 1.5.1.

    -
    - -
    -
    - - - - - - - - diff --git a/docs/reference/list.rds b/docs/reference/list.rds deleted file mode 100644 index 4235677d0ab07714cb3ea76d92fc9156ebc24340..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2248 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 WBm8sc&Yc${sQ&>{T_y`mB>(`=?!6=c diff --git a/docs/reference/mtcars.csv b/docs/reference/mtcars.csv deleted file mode 100644 index d154466..0000000 --- a/docs/reference/mtcars.csv +++ /dev/null @@ -1,33 +0,0 @@ -mpg,cyl,disp,hp,drat,wt,qsec,vs,am,gear,carb -21,6,160,110,3.9,2.62,16.46,0,1,4,4 -21,6,160,110,3.9,2.875,17.02,0,1,4,4 -22.8,4,108,93,3.85,2.32,18.61,1,1,4,1 -21.4,6,258,110,3.08,3.215,19.44,1,0,3,1 -18.7,8,360,175,3.15,3.44,17.02,0,0,3,2 -18.1,6,225,105,2.76,3.46,20.22,1,0,3,1 -14.3,8,360,245,3.21,3.57,15.84,0,0,3,4 -24.4,4,146.7,62,3.69,3.19,20,1,0,4,2 -22.8,4,140.8,95,3.92,3.15,22.9,1,0,4,2 -19.2,6,167.6,123,3.92,3.44,18.3,1,0,4,4 -17.8,6,167.6,123,3.92,3.44,18.9,1,0,4,4 -16.4,8,275.8,180,3.07,4.07,17.4,0,0,3,3 -17.3,8,275.8,180,3.07,3.73,17.6,0,0,3,3 -15.2,8,275.8,180,3.07,3.78,18,0,0,3,3 -10.4,8,472,205,2.93,5.25,17.98,0,0,3,4 -10.4,8,460,215,3,5.424,17.82,0,0,3,4 -14.7,8,440,230,3.23,5.345,17.42,0,0,3,4 -32.4,4,78.7,66,4.08,2.2,19.47,1,1,4,1 -30.4,4,75.7,52,4.93,1.615,18.52,1,1,4,2 -33.9,4,71.1,65,4.22,1.835,19.9,1,1,4,1 -21.5,4,120.1,97,3.7,2.465,20.01,1,0,3,1 -15.5,8,318,150,2.76,3.52,16.87,0,0,3,2 -15.2,8,304,150,3.15,3.435,17.3,0,0,3,2 -13.3,8,350,245,3.73,3.84,15.41,0,0,3,4 -19.2,8,400,175,3.08,3.845,17.05,0,0,3,2 -27.3,4,79,66,4.08,1.935,18.9,1,1,4,1 -26,4,120.3,91,4.43,2.14,16.7,0,1,5,2 -30.4,4,95.1,113,3.77,1.513,16.9,1,1,5,2 -15.8,8,351,264,4.22,3.17,14.5,0,1,5,4 -19.7,6,145,175,3.62,2.77,15.5,0,1,5,6 -15,8,301,335,3.54,3.57,14.6,0,1,5,8 -21.4,4,121,109,4.11,2.78,18.6,1,1,4,2 diff --git a/docs/reference/rio.html b/docs/reference/rio.html deleted file mode 100644 index ddfff4b..0000000 --- a/docs/reference/rio.html +++ /dev/null @@ -1,189 +0,0 @@ - - - - - - - - -A Swiss-Army Knife for Data I/O — rio • rio - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - - -
    - -
    -
    - - -
    -

    The aim of rio is to make data file input and output as easy as possible. export and import serve as a Swiss-army knife for painless data I/O for data from almost any file format by inferring the data structure from the file extension, natively reading web-based data sources, setting reasonable defaults for import and export, and relying on efficient data import and export packages. An additional convenience function, convert, provides a simple method for converting between file types.

    -

    Note that some of rio's functionality is provided by ‘Suggests’ dependendencies, meaning they are not installed by default. Use install_formats to make sure these packages are available for use.

    -
    - - - -

    References

    - -

    GREA provides an RStudio add-in to import data using rio.

    -

    See also

    - - - -

    Examples

    -
    # export -library("datasets") -export(mtcars, "mtcars.csv") # comma-separated values -export(mtcars, "mtcars.rds") # R serialized -export(mtcars, "mtcars.sav") # SPSS - -# import -x <- import("mtcars.csv") -y <- import("mtcars.rds") -z <- import("mtcars.sav") - -# convert -convert("mtcars.sav", "mtcars.dta") - -# cleanup -unlink(c("mtcars.csv", "mtcars.rds", "mtcars.sav", "mtcars.dta"))
    -
    - -
    - - -
    - - -
    -

    Site built with pkgdown 1.5.1.

    -
    - -
    -
    - - - - - - - - diff --git a/man-roxygen/setclass.R b/man-roxygen/setclass.R deleted file mode 100644 index 8e50412..0000000 --- a/man-roxygen/setclass.R +++ /dev/null @@ -1 +0,0 @@ -#' @param setclass An optional character vector specifying one or more classes to set on the import. By default, the return object is always a \dQuote{data.frame}. Allowed values include \dQuote{tbl_df}, \dQuote{tbl}, or \dQuote{tibble} (if using dplyr) or \dQuote{data.table} (if using data.table). Other values are ignored, such that a data.frame is returned. diff --git a/man/import_list.Rd b/man/import_list.Rd index d5c6b2c..0d135f7 100644 --- a/man/import_list.Rd +++ b/man/import_list.Rd @@ -37,7 +37,7 @@ Use \code{\link{import}} to import a list of data frames from a vector of file n } \examples{ library('datasets') -export(list(mtcars1 = mtcars[1:10,], +export(list(mtcars1 = mtcars[1:10,], mtcars2 = mtcars[11:20,], mtcars3 = mtcars[21:32,]), xlsx_file <- tempfile(fileext = ".xlsx") diff --git a/pkgdown/favicon/apple-touch-icon-120x120.png b/pkgdown/favicon/apple-touch-icon-120x120.png deleted file mode 100644 index a5ffa4720357ef797fbd6b24a229b36d8314838a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10213 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 Y7#r2?T8uLlxCMx;q>@CXm~rs`05ZbH8UO$Q diff --git a/pkgdown/favicon/apple-touch-icon-60x60.png b/pkgdown/favicon/apple-touch-icon-60x60.png deleted file mode 100644 index 35d4df01ccc54402a3c6b043781942fbd1e3c6fb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4920 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 diff --git a/pkgdown/favicon/apple-touch-icon-76x76.png b/pkgdown/favicon/apple-touch-icon-76x76.png deleted file mode 100644 index 46db16433cacdbe7f4d3db84f689ef1f66a30ada..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6318 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 P5&)1g_;sbC&Aa~rHK7^$ diff --git a/pkgdown/favicon/apple-touch-icon.png b/pkgdown/favicon/apple-touch-icon.png deleted file mode 100644 index 7abe275f09d7a1a619291aacdd893e009ecc226c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15374 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 Date: Tue, 29 Aug 2023 11:41:55 +0200 Subject: [PATCH 06/44] update CONTRIBUTING.md fix #132 [no ci] --- CONTRIBUTING.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 643d05f..000fbda 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -21,14 +21,17 @@ Some specific types of changes that you might make are: - Import is based on S3 dispatch to functions of the form `.import.rio_FORMAT()`. Export works the same, but with `.export.rio_FORMAT()`. New import/export methods should take this form. There's no need to change the body of the `import()` or `export()` functions; S3 will take care of dispatch. All `.import()` methods must accept a `file` and `which` argument: `file` represents the path to the file and `which` can be used to extract sheets or files from multi-object files (e.g., zip, Excel workbooks, etc.). `.export()` methods take two arguments: `file` and `x`, where `file` is the path to the file and `x` is the data frame being exported. Most of the work of import and export methods involves mapping these arguments to their corresponding argument names in the various underlying packages. - The S3 methods should be documented in [NAMESPACE](https://github.com/leeper/rio/blob/master/NAMESPACE) using `S3method()`, which is handled automatically by roxygen markup in the source code. - + - Use the following `base` convention for these three arguments: + - `file`: A character string naming a file, URL, or single-file .zip or .tar archive. (not `path`) + - `which`: This argument is used to control import from multi-object files. (not `sheet`) + - `header`: This argument is used to control whether the first row in the data file contains the header information. (not `col_names`) - Any new format support needs to be documented in each of the following places: [README.Rmd](https://github.com/leeper/rio/blob/master/README.Rmd), [the vignette](https://github.com/leeper/rio/blob/master/vignettes/rio.Rmd), and the appropriate Rd file in [`/man`](https://github.com/leeper/rio/tree/master/man). - New formats or new options for handling formats should have a test added in [`/tests/testthat`](https://github.com/leeper/rio/tree/master/tests/testthat) called `test_format_FORMAT.R` that completely covers the function's behavior. This may require adding an example file to [`inst/examples`](https://github.com/leeper/rio/tree/master/inst/examples) (e.g., for testing `import()`). - + 3. Changes requiring a new package dependency should be discussed on the GitHub issues page before submitting a pull request. 4. Message translations. These are very appreciated! The format is a pain, but if you're doing this I'm assuming you're already familiar with it. -Any questions you have can be opened as GitHub issues or directed to thosjleeper (at) gmail.com. +Any questions you have can be opened as GitHub issues. From 593e6a87fa97c04958be9136e34b6b3bc883a213 Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Tue, 29 Aug 2023 12:17:19 +0200 Subject: [PATCH 07/44] Switch off codecov commmenting please generate the codecov of the `main` branch --- .Rbuildignore | 1 + codecov.yml | 5 +++++ 2 files changed, 6 insertions(+) create mode 100644 codecov.yml diff --git a/.Rbuildignore b/.Rbuildignore index 99e5739..b4ea04b 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -40,3 +40,4 @@ ^\.editorconfig$ ^starwars.xlsx$ ^starwars.csv$ +^codecov\.yml$ diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 0000000..6d835ab --- /dev/null +++ b/codecov.yml @@ -0,0 +1,5 @@ +comment: false + +coverage: + status: + patch: off From c153f6d20a26ccace42d9ab5400f5b2bf273ba81 Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Tue, 29 Aug 2023 13:34:00 +0200 Subject: [PATCH 08/44] Update citation [no ci] So that winbuilder won't complain --- inst/CITATION | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/inst/CITATION b/inst/CITATION index 220488d..877b6bf 100644 --- a/inst/CITATION +++ b/inst/CITATION @@ -1,18 +1,7 @@ citHeader("To cite package 'rio' in publications use:") - year <- sub(".*(2[[:digit:]]{3})-.*", "\\1", meta$Date, perl = TRUE) - vers <- paste("R package version", meta$Version) - - citEntry(entry="Manual", - title = "rio: A Swiss-army knife for data file I/O", - author = personList(as.person("Chung-hong Chan"), - as.person("Geoffrey CH Chan"), - as.person("Thomas J. Leeper"), - as.person("Jason Becker")), - year = year, - note = vers, - textVersion = - paste("Chung-hong Chan, Geoffrey CH Chan, Thomas J. Leeper, and Jason Becker (", - year, - "). rio: A Swiss-army knife for data file I/O. ", - vers, ".", sep="")) +bibentry(bibtype = "Manual", + title = "rio: A Swiss-army knife for data file I/O", + author = c(person("Chung-hong", "Chan"), person("Thomas J.", "Leeper"), person("Jason", "Becker")), + url = "https://cran.r-project.org/package=rio", + year = 2023) From c29db87aac539e53f1908563d170e5c941c9cad0 Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Tue, 29 Aug 2023 13:36:41 +0200 Subject: [PATCH 09/44] Make test properly clean up [no ci] --- tests/testthat/test_format_dta.R | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/testthat/test_format_dta.R b/tests/testthat/test_format_dta.R index 7eaaee9..6b34071 100644 --- a/tests/testthat/test_format_dta.R +++ b/tests/testthat/test_format_dta.R @@ -31,9 +31,10 @@ test_that("Import from Stata (read.dta)", { expect_true(inherits(test1, "data.frame")) } expect_error( - is.data.frame(import("mtcars.dta", haven = FALSE)), + is.data.frame(import("mtcars.dta", haven = FALSE)), label = "foreign::read.dta cannot read newer Stata files" ) }) unlink("mtcars.dta") +unlink("mtcars3.dta") From 30a23b40d3f2d4ece12436c3aa2411702b904f49 Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Tue, 29 Aug 2023 13:40:01 +0200 Subject: [PATCH 10/44] Bump ver. [no ci] --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 6257b22..4c9d2f7 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: rio Type: Package Title: A Swiss-Army Knife for Data I/O -Version: 0.5.29 +Version: 0.5.30 Authors@R: c(person("Jason", "Becker", role = "ctb", email = "jason@jbecker.co"), person("Chung-hong", "Chan", role = c("aut", "cre"), email = "chainsawtiney@gmail.com", comment = c(ORCID = "0000-0002-6232-7530")), From 3976eeaf170d4d269a23e5c9c304860cc921fd6f Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Tue, 29 Aug 2023 14:23:49 +0200 Subject: [PATCH 11/44] Use usual test file arrangement [no ci] (#314) --- .../{testthat/files => testdata}/br-in-header.html | 0 tests/{testthat/files => testdata}/br-in-td.html | 0 .../examples => tests/testdata}/example-DESCRIPTION | 0 {inst/examples => tests/testdata}/example.csvy | 0 {inst/examples => tests/testdata}/iris.xls | Bin {inst/examples => tests/testdata}/mtcars.ods | Bin {inst/examples => tests/testdata}/noheader.csv | 0 .../files => testdata}/th-as-row-element.html | 0 tests/{testthat/files => testdata}/two-tbody.html | 0 {inst/examples => tests/testdata}/twotables.html | 0 tests/{test-all.R => testthat.R} | 0 tests/testthat/test_format_csv.R | 2 +- tests/testthat/test_format_html.R | 12 ++++++------ tests/testthat/test_format_ods.R | 5 ++--- tests/testthat/test_format_xls.R | 12 ++++-------- tests/testthat/test_import_list.R | 12 ++++++------ tests/testthat/test_install_formats.R | 3 +-- 17 files changed, 20 insertions(+), 26 deletions(-) rename tests/{testthat/files => testdata}/br-in-header.html (100%) rename tests/{testthat/files => testdata}/br-in-td.html (100%) rename {inst/examples => tests/testdata}/example-DESCRIPTION (100%) rename {inst/examples => tests/testdata}/example.csvy (100%) rename {inst/examples => tests/testdata}/iris.xls (100%) rename {inst/examples => tests/testdata}/mtcars.ods (100%) rename {inst/examples => tests/testdata}/noheader.csv (100%) rename tests/{testthat/files => testdata}/th-as-row-element.html (100%) rename tests/{testthat/files => testdata}/two-tbody.html (100%) rename {inst/examples => tests/testdata}/twotables.html (100%) rename tests/{test-all.R => testthat.R} (100%) diff --git a/tests/testthat/files/br-in-header.html b/tests/testdata/br-in-header.html similarity index 100% rename from tests/testthat/files/br-in-header.html rename to tests/testdata/br-in-header.html diff --git a/tests/testthat/files/br-in-td.html b/tests/testdata/br-in-td.html similarity index 100% rename from tests/testthat/files/br-in-td.html rename to tests/testdata/br-in-td.html diff --git a/inst/examples/example-DESCRIPTION b/tests/testdata/example-DESCRIPTION similarity index 100% rename from inst/examples/example-DESCRIPTION rename to tests/testdata/example-DESCRIPTION diff --git a/inst/examples/example.csvy b/tests/testdata/example.csvy similarity index 100% rename from inst/examples/example.csvy rename to tests/testdata/example.csvy diff --git a/inst/examples/iris.xls b/tests/testdata/iris.xls similarity index 100% rename from inst/examples/iris.xls rename to tests/testdata/iris.xls diff --git a/inst/examples/mtcars.ods b/tests/testdata/mtcars.ods similarity index 100% rename from inst/examples/mtcars.ods rename to tests/testdata/mtcars.ods diff --git a/inst/examples/noheader.csv b/tests/testdata/noheader.csv similarity index 100% rename from inst/examples/noheader.csv rename to tests/testdata/noheader.csv diff --git a/tests/testthat/files/th-as-row-element.html b/tests/testdata/th-as-row-element.html similarity index 100% rename from tests/testthat/files/th-as-row-element.html rename to tests/testdata/th-as-row-element.html diff --git a/tests/testthat/files/two-tbody.html b/tests/testdata/two-tbody.html similarity index 100% rename from tests/testthat/files/two-tbody.html rename to tests/testdata/two-tbody.html diff --git a/inst/examples/twotables.html b/tests/testdata/twotables.html similarity index 100% rename from inst/examples/twotables.html rename to tests/testdata/twotables.html diff --git a/tests/test-all.R b/tests/testthat.R similarity index 100% rename from tests/test-all.R rename to tests/testthat.R diff --git a/tests/testthat/test_format_csv.R b/tests/testthat/test_format_csv.R index 62a5947..9b13a74 100644 --- a/tests/testthat/test_format_csv.R +++ b/tests/testthat/test_format_csv.R @@ -17,7 +17,7 @@ test_that("Export (Append) to CSV", { }) test_that("Import from CSV", { - noheadercsv <- import(system.file("examples", "noheader.csv", package = "rio"), header = FALSE) + noheadercsv <- import("../testdata/noheader.csv", header = FALSE) expect_that(colnames(noheadercsv)[1], equals("V1"), label = "Header is correctly specified") }) diff --git a/tests/testthat/test_format_html.R b/tests/testthat/test_format_html.R index ccdff59..4ea9242 100644 --- a/tests/testthat/test_format_html.R +++ b/tests/testthat/test_format_html.R @@ -11,24 +11,24 @@ test_that("Export to HTML with ampersands",{ iris$`R & D` <- paste(sample(letters,nrow(iris),rep=T), '&', sample(LETTERS,nrow(iris),rep=TRUE)) - expect_true(export(iris, "iris2.html") %in% dir(), + expect_true(export(iris, "iris2.html") %in% dir(), label = "export to html with ampersands works") }) test_that("Import from HTML", { skip_if_not_installed("xml2") expect_true(is.data.frame(import("iris.html")), label = "import from single-table html works") - f <- system.file("examples", "twotables.html", package = "rio") + f <- "../testdata/twotables.html" expect_true(all(dim(import(f, which = 1)) == c(32, 11)), label = "import from two-table html works (which = 1)") expect_true(all(dim(import(f, which = 2)) == c(150, 5)), label = "import from two-table html works (which = 2)") }) test_that("Import from HTML with multiple tbody elements", { skip_if_not_installed("xml2") - expect_true(is.data.frame(import("files/two-tbody.html")), label="import with two tbody elements in a single html table works") - expect_true(is.data.frame(import("files/br-in-header.html")), label="import with an empty header cell in an html table works") - expect_true(is.data.frame(import("files/br-in-td.html")), label="import with an empty data cell in a single html table works") - expect_true(is.data.frame(import("files/th-as-row-element.html")), label="import with th instead of td in a non-header row in a single html table works") + expect_true(is.data.frame(import("../testdata/two-tbody.html")), label="import with two tbody elements in a single html table works") + expect_true(is.data.frame(import("../testdata/br-in-header.html")), label="import with an empty header cell in an html table works") + expect_true(is.data.frame(import("../testdata/br-in-td.html")), label="import with an empty data cell in a single html table works") + expect_true(is.data.frame(import("../testdata/th-as-row-element.html")), label="import with th instead of td in a non-header row in a single html table works") }) unlink(c("iris.xml", "iris2.xml", "iris2.html")) diff --git a/tests/testthat/test_format_ods.R b/tests/testthat/test_format_ods.R index b3d4536..ae3f050 100644 --- a/tests/testthat/test_format_ods.R +++ b/tests/testthat/test_format_ods.R @@ -3,9 +3,8 @@ require("datasets") test_that("Import from ODS", { skip_if_not_installed(pkg="readODS") - ods0 <- import(system.file("examples", "mtcars.ods", package = "rio")) - expect_warning(ods <- import(system.file("examples", "mtcars.ods" - , package = "rio"), + ods0 <- import("../testdata/mtcars.ods") + expect_warning(ods <- import("../testdata/mtcars.ods", sheet = 1, col_names = TRUE, path = 'ignored value', invalid_argument = 42), diff --git a/tests/testthat/test_format_xls.R b/tests/testthat/test_format_xls.R index bf96dce..4455a4f 100644 --- a/tests/testthat/test_format_xls.R +++ b/tests/testthat/test_format_xls.R @@ -17,14 +17,10 @@ test_that("Import from Excel (.xlsx)", { }) test_that("Import from Excel (.xls)", { - expect_true(is.data.frame(import(system.file('examples', 'iris.xls', - package='rio')))) - expect_true(is.data.frame(import(system.file('examples', 'iris.xls', - package='rio'), sheet = 1))) - expect_true(is.data.frame(import(system.file('examples', 'iris.xls', - package='rio'), which = 1))) - expect_warning(is.data.frame(import(system.file('examples', 'iris.xls', - package='rio'), which = 1, + expect_true(is.data.frame(import("../testdata/iris.xls"))) + expect_true(is.data.frame(import("../testdata/iris.xls", sheet = 1))) + expect_true(is.data.frame(import("../testdata/iris.xls", which = 1))) + expect_warning(is.data.frame(import("../testdata/iris.xls", which = 1, nrows = 42)), "nrows", label="xls reads the file and ignores unused arguments with warning") }) diff --git a/tests/testthat/test_import_list.R b/tests/testthat/test_import_list.R index 0544aa3..8395b98 100644 --- a/tests/testthat/test_import_list.R +++ b/tests/testthat/test_import_list.R @@ -20,7 +20,7 @@ test_that("Import multi-object .Rdata in import_list()", { }) test_that("Import multiple HTML tables in import_list()", { - dat <- import_list(system.file("examples", "twotables.html", package = "rio")) + dat <- import_list("../testdata/twotables.html") expect_true(identical(dim(dat[[1]]), dim(mtcars))) expect_true(identical(names(dat[[1]]), names(mtcars))) expect_true(identical(dim(dat[[2]]), dim(iris))) @@ -69,10 +69,10 @@ test_that("Object names are preserved by import_list()", { expected_names <- c("mtcars1", "mtcars2", "mtcars3") dat_xls <- import_list("mtcars.xlsx") dat_csv <- import_list(c("mtcars1.csv","mtcars2.tsv","mtcars3.csv")) - + expect_identical(names(dat_xls), expected_names) expect_identical(names(dat_csv), expected_names) - + unlink(c("mtcars.xlsx", "mtcars1.csv","mtcars2.tsv","mtcars3.csv")) }) @@ -82,13 +82,13 @@ test_that("File names are added as attributes by import_list()", { expected_names <- c("mtcars", "mtcars") expected_attrs <- c(mtcars = "mtcars.csv", mtcars = "mtcars.tsv") dat <- import_list(c("mtcars.csv","mtcars.tsv")) - + expect_identical(names(dat), expected_names) expect_identical(unlist(lapply(dat, attr, "filename")), expected_attrs) - + unlink(c("mtcars.csv", "mtcars.tsv")) }) unlink("data.rdata") unlink("mtcars.rds") -unlink("mtcars.csv.zip") \ No newline at end of file +unlink("mtcars.csv.zip") diff --git a/tests/testthat/test_install_formats.R b/tests/testthat/test_install_formats.R index 546e789..0c28503 100644 --- a/tests/testthat/test_install_formats.R +++ b/tests/testthat/test_install_formats.R @@ -11,8 +11,7 @@ test_that("uninstalled_formats()", { }) test_that("install_formats()", { - suggestions <- read.dcf(system.file("examples/example-DESCRIPTION", - package = "rio", mustWork = TRUE), + suggestions <- read.dcf("../testdata/example-DESCRIPTION", fields = "Suggests") suggestions <- parse_suggestions(suggestions) expect_true("NANTUCKET" %in% suggestions) From 2540084d49fcad2d3af1c60cfacf0890e62cf6bb Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Tue, 29 Aug 2023 14:36:26 +0200 Subject: [PATCH 12/44] Correct NEWS; add cran-comment.md to ignore [no ci] Ready for release --- .Rbuildignore | 1 + NEWS.md | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.Rbuildignore b/.Rbuildignore index b4ea04b..7d8ab27 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -41,3 +41,4 @@ ^starwars.xlsx$ ^starwars.csv$ ^codecov\.yml$ +^cran-comments\.md$ diff --git a/NEWS.md b/NEWS.md index d5b7b71..88edc6d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,9 +1,13 @@ -# rio 0.5.29 +# rio 0.5.30 * Maintenance release: new maintainer * Mark `.sas7bdat` as deprecated * Change the minimum R version to 3.6 +# rio 0.5.29 + +* fixes for CRAN + # rio 0.5.28 * Various fixes to tests, examples, and documentation for CRAN. From daf6cd1551d0a5aa6680f0a6b008e3d90215d97e Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Tue, 29 Aug 2023 21:11:12 +0200 Subject: [PATCH 13/44] Update `.Rbuildignore` [no ci] --- .Rbuildignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.Rbuildignore b/.Rbuildignore index 7d8ab27..d53bf53 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -42,3 +42,4 @@ ^starwars.csv$ ^codecov\.yml$ ^cran-comments\.md$ +^CRAN-SUBMISSION$ From 01e55d2fd6dd1ee8c59ea782541d57353621d3c1 Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Wed, 30 Aug 2023 09:53:39 +0200 Subject: [PATCH 14/44] Update README [no ci] --- README.Rmd | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.Rmd b/README.Rmd index 3db9dd8..21eae96 100644 --- a/README.Rmd +++ b/README.Rmd @@ -11,7 +11,7 @@ output: github_document ## Overview -The aim of **rio** is to make data file I/O in R as easy as possible by implementing four simple functions in Swiss-army knife style: +The aim of **rio** is to make data file I/O in R as easy as possible by implementing two main functions in Swiss-army knife style: - `import()` provides a painless data import experience by automatically choosing the appropriate import/read function based on file extension (or a specified `format` argument) - `export()` provides the same painless file recognition for data export/write functionality diff --git a/README.md b/README.md index d761f89..d32c481 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Version](https://www.r-pkg.org/badges/version/rio)](https://cran.r-project.org/p ## Overview The aim of **rio** is to make data file I/O in R as easy as possible by -implementing four simple functions in Swiss-army knife style: +implementing two main functions in Swiss-army knife style: - `import()` provides a painless data import experience by automatically choosing the appropriate import/read function based on From af4824c2d99c6fc900a90f278851f4106b90d995 Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Wed, 30 Aug 2023 11:09:43 +0200 Subject: [PATCH 15/44] Add code meta ref ropensci/software-review#605 --- .Rbuildignore | 1 + codemeta.json | 480 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 481 insertions(+) create mode 100644 codemeta.json diff --git a/.Rbuildignore b/.Rbuildignore index d53bf53..1545912 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -43,3 +43,4 @@ ^codecov\.yml$ ^cran-comments\.md$ ^CRAN-SUBMISSION$ +^codemeta\.json$ diff --git a/codemeta.json b/codemeta.json new file mode 100644 index 0000000..cf29c62 --- /dev/null +++ b/codemeta.json @@ -0,0 +1,480 @@ +{ + "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@type": "SoftwareSourceCode", + "identifier": "rio", + "description": "Streamlined data import and export by making assumptions that the user is probably willing to make: 'import()' and 'export()' determine the data structure from the file extension, reasonable defaults are used for data import and export (e.g., 'stringsAsFactors=FALSE'), web-based import is natively supported (including from SSL/HTTPS), compressed files can be read directly without explicit decompression, and fast import packages are used where appropriate. An additional convenience function, 'convert()', provides a simple method for converting between file types.", + "name": "rio: A Swiss-Army Knife for Data I/O", + "codeRepository": "https://github.com/chainsawriot/rio", + "issueTracker": "https://github.com/chainsawriot/rio/issues", + "license": "https://spdx.org/licenses/GPL-2.0", + "version": "0.5.30", + "programmingLanguage": { + "@type": "ComputerLanguage", + "name": "R", + "url": "https://r-project.org" + }, + "runtimePlatform": "R version 4.3.1 (2023-06-16)", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "author": [ + { + "@type": "Person", + "givenName": "Chung-hong", + "familyName": "Chan", + "email": "chainsawtiney@gmail.com", + "@id": "https://orcid.org/0000-0002-6232-7530" + }, + { + "@type": "Person", + "givenName": "Thomas J.", + "familyName": "Leeper", + "email": "thosjleeper@gmail.com", + "@id": "https://orcid.org/0000-0003-4097-6326" + } + ], + "contributor": [ + { + "@type": "Person", + "givenName": "Jason", + "familyName": "Becker", + "email": "jason@jbecker.co" + }, + { + "@type": "Person", + "givenName": "Geoffrey CH", + "familyName": "Chan", + "email": "gefchchan@gmail.com" + }, + { + "@type": "Person", + "givenName": "Christopher", + "familyName": "Gandrud" + }, + { + "@type": "Person", + "givenName": "Andrew", + "familyName": "MacDonald" + }, + { + "@type": "Person", + "givenName": "Ista", + "familyName": "Zahn" + }, + { + "@type": "Person", + "givenName": "Stanislaus", + "familyName": "Stadlmann" + }, + { + "@type": "Person", + "givenName": "Ruaridh", + "familyName": "Williamson", + "email": "ruaridh.williamson@gmail.com" + }, + { + "@type": "Person", + "givenName": "Patrick", + "familyName": "Kennedy" + }, + { + "@type": "Person", + "givenName": "Ryan", + "familyName": "Price", + "email": "ryapric@gmail.com" + }, + { + "@type": "Person", + "givenName": "Trevor L", + "familyName": "Davis", + "email": "trevor.l.davis@gmail.com" + }, + { + "@type": "Person", + "givenName": "Nathan", + "familyName": "Day", + "email": "nathancday@gmail.com" + }, + { + "@type": "Person", + "givenName": "Bill", + "familyName": "Denney", + "email": "wdenney@humanpredictions.com", + "@id": "https://orcid.org/0000-0002-5759-428X" + }, + { + "@type": "Person", + "givenName": "Alex", + "familyName": "Bokov", + "email": "alex.bokov@gmail.com", + "@id": "https://orcid.org/0000-0002-0511-9815" + } + ], + "maintainer": [ + { + "@type": "Person", + "givenName": "Chung-hong", + "familyName": "Chan", + "email": "chainsawtiney@gmail.com", + "@id": "https://orcid.org/0000-0002-6232-7530" + } + ], + "softwareSuggestions": [ + { + "@type": "SoftwareApplication", + "identifier": "datasets", + "name": "datasets" + }, + { + "@type": "SoftwareApplication", + "identifier": "bit64", + "name": "bit64", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=bit64" + }, + { + "@type": "SoftwareApplication", + "identifier": "testthat", + "name": "testthat", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=testthat" + }, + { + "@type": "SoftwareApplication", + "identifier": "knitr", + "name": "knitr", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=knitr" + }, + { + "@type": "SoftwareApplication", + "identifier": "magrittr", + "name": "magrittr", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=magrittr" + }, + { + "@type": "SoftwareApplication", + "identifier": "arrow", + "name": "arrow", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=arrow" + }, + { + "@type": "SoftwareApplication", + "identifier": "clipr", + "name": "clipr", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=clipr" + }, + { + "@type": "SoftwareApplication", + "identifier": "feather", + "name": "feather", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=feather" + }, + { + "@type": "SoftwareApplication", + "identifier": "fst", + "name": "fst", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=fst" + }, + { + "@type": "SoftwareApplication", + "identifier": "hexView", + "name": "hexView", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=hexView" + }, + { + "@type": "SoftwareApplication", + "identifier": "jsonlite", + "name": "jsonlite", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=jsonlite" + }, + { + "@type": "SoftwareApplication", + "identifier": "pzfx", + "name": "pzfx", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=pzfx" + }, + { + "@type": "SoftwareApplication", + "identifier": "readODS", + "name": "readODS", + "version": ">= 1.6.4", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=readODS" + }, + { + "@type": "SoftwareApplication", + "identifier": "readr", + "name": "readr", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=readr" + }, + { + "@type": "SoftwareApplication", + "identifier": "rmarkdown", + "name": "rmarkdown", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=rmarkdown" + }, + { + "@type": "SoftwareApplication", + "identifier": "rmatio", + "name": "rmatio", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=rmatio" + }, + { + "@type": "SoftwareApplication", + "identifier": "xml2", + "name": "xml2", + "version": ">= 1.2.0", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=xml2" + }, + { + "@type": "SoftwareApplication", + "identifier": "yaml", + "name": "yaml", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=yaml" + } + ], + "softwareRequirements": { + "1": { + "@type": "SoftwareApplication", + "identifier": "R", + "name": "R", + "version": ">= 3.6" + }, + "2": { + "@type": "SoftwareApplication", + "identifier": "tools", + "name": "tools" + }, + "3": { + "@type": "SoftwareApplication", + "identifier": "stats", + "name": "stats" + }, + "4": { + "@type": "SoftwareApplication", + "identifier": "utils", + "name": "utils" + }, + "5": { + "@type": "SoftwareApplication", + "identifier": "foreign", + "name": "foreign", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=foreign" + }, + "6": { + "@type": "SoftwareApplication", + "identifier": "haven", + "name": "haven", + "version": ">= 1.1.2", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=haven" + }, + "7": { + "@type": "SoftwareApplication", + "identifier": "curl", + "name": "curl", + "version": ">= 0.6", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=curl" + }, + "8": { + "@type": "SoftwareApplication", + "identifier": "data.table", + "name": "data.table", + "version": ">= 1.9.8", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=data.table" + }, + "9": { + "@type": "SoftwareApplication", + "identifier": "readxl", + "name": "readxl", + "version": ">= 0.1.1", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=readxl" + }, + "10": { + "@type": "SoftwareApplication", + "identifier": "openxlsx", + "name": "openxlsx", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=openxlsx" + }, + "11": { + "@type": "SoftwareApplication", + "identifier": "tibble", + "name": "tibble", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=tibble" + }, + "SystemRequirements": null + }, + "fileSize": "323.042KB", + "citation": [ + { + "@type": "SoftwareSourceCode", + "datePublished": "2023", + "author": [ + { + "@type": "Person", + "givenName": "Chung-hong", + "familyName": "Chan" + }, + { + "@type": "Person", + "givenName": "Thomas J.", + "familyName": "Leeper" + }, + { + "@type": "Person", + "givenName": "Jason", + "familyName": "Becker" + } + ], + "name": "rio: A Swiss-army knife for data file I/O", + "url": "https://cran.r-project.org/package=rio" + } + ], + "releaseNotes": "https://github.com/chainsawriot/rio/blob/master/NEWS.md", + "readme": "https://github.com/chainsawriot/rio/blob/main/README.md", + "keywords": ["r", "rio", "stata", "spss", "sas", "excel", "io", "data-science", "data", "cran", "csvy", "csv"], + "relatedLink": "https://CRAN.R-project.org/package=rio" +} From 010896257755105e087406cda0b03753f9dcb58e Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Wed, 30 Aug 2023 11:31:21 +0200 Subject: [PATCH 16/44] Remove the doc of `arg_reconcile` [no ci] ref #320 ropensci/software-review#605 --- R/arg_reconcile.R | 121 +++++++++++++++++++++---------------------- man/arg_reconcile.Rd | 77 --------------------------- 2 files changed, 60 insertions(+), 138 deletions(-) delete mode 100644 man/arg_reconcile.Rd diff --git a/R/arg_reconcile.R b/R/arg_reconcile.R index cc44a2a..09a6ab7 100644 --- a/R/arg_reconcile.R +++ b/R/arg_reconcile.R @@ -1,53 +1,53 @@ -#' @title Reconcile an argument list to any function signature. -#' -#' @description Adapt an argument list to a function excluding arguments that -#' will not be recognized by it, redundant arguments, and un-named -#' arguments. -#' -#' @param fun A function to which an argument list needs to be adapted. Use -#' the unquoted name of the function. If it's in a different -#' package then the fully qualified unquoted name (e.g. -#' \code{utils::read.table}) -#' @param ... An arbitrary list of named arguments (unnamed ones will be -#' ignored). Arguments in \code{.args} are overridden by -#' arguments of the same name (if any) in \code{...} -#' @param .args A list or \code{alist} of named arguments, to be merged -#' with \code{...}. Arguments in \code{.args} are overridden by -#' arguments of the same name (if any) in \code{...} -#' @param .docall If set to \code{TRUE} will not only clean up the arguments -#' but also execute \code{fun} with those arguments -#' (\code{FALSE} by default) and return the results -#' @param .include Whitelist. If not empty, only arguments named here will be -#' permitted, and only if they satisfy the conditions implied by -#' the other arguments. Evaluated before \code{.remap}. -#' @param .exclude Blacklist. If not empty, arguments named here will be removed -#' even if they satisfy the conditions implied by the other -#' arguments. Evaluated before \code{.remap}. -#' @param .remap An optional named character vector or named list of character -#' values for standardizing arguments that play the same role -#' but have different names in different functions. Evaluated -#' after \code{.exclude} and \code{.include}. -#' @param .warn Whether to issue a warning message (default) when invalid -#' arguments need to be discarded. -#' @param .error If specified, should be the object to return in the event of -#' error. This object will have the error as its -#' \code{error} attribute. If not specified an ordinary error is -#' thrown with an added hint on the documentation to read for -#' troubleshooting. Ignored if \code{.docall} is \code{FALSE}. -#' The point of doing this is fault-tolerance-- if this function -#' is part of a lengthy process where you want to document an -#' error but keep going, you can set \code{.error} to some -#' object of a compatible type. That object will be returned in -#' the event of error and will have as its \code{"error"} -#' attribute the error object. -#' @param .finish A function to run on the result before returning it. Ignored -#' if \code{.docall} is \code{FALSE}. -#' -#' @return Either a named list or the result of calling \code{fun} with the -#' supplied arguments -#' -arg_reconcile <- function(fun, ..., .args = alist(), .docall = FALSE, - .include = c(), .exclude= c(), .remap = list(), +## @title Reconcile an argument list to any function signature. +## +## @description Adapt an argument list to a function excluding arguments that +## will not be recognized by it, redundant arguments, and un-named +## arguments. +## +## @param fun A function to which an argument list needs to be adapted. Use +## the unquoted name of the function. If it's in a different +## package then the fully qualified unquoted name (e.g. +## \code{utils::read.table}) +## @param ... An arbitrary list of named arguments (unnamed ones will be +## ignored). Arguments in \code{.args} are overridden by +## arguments of the same name (if any) in \code{...} +## @param .args A list or \code{alist} of named arguments, to be merged +## with \code{...}. Arguments in \code{.args} are overridden by +## arguments of the same name (if any) in \code{...} +## @param .docall If set to \code{TRUE} will not only clean up the arguments +## but also execute \code{fun} with those arguments +## (\code{FALSE} by default) and return the results +## @param .include Whitelist. If not empty, only arguments named here will be +## permitted, and only if they satisfy the conditions implied by +## the other arguments. Evaluated before \code{.remap}. +## @param .exclude Blacklist. If not empty, arguments named here will be removed +## even if they satisfy the conditions implied by the other +## arguments. Evaluated before \code{.remap}. +## @param .remap An optional named character vector or named list of character +## values for standardizing arguments that play the same role +## but have different names in different functions. Evaluated +## after \code{.exclude} and \code{.include}. +## @param .warn Whether to issue a warning message (default) when invalid +## arguments need to be discarded. +## @param .error If specified, should be the object to return in the event of +## error. This object will have the error as its +## \code{error} attribute. If not specified an ordinary error is +## thrown with an added hint on the documentation to read for +## troubleshooting. Ignored if \code{.docall} is \code{FALSE}. +## The point of doing this is fault-tolerance-- if this function +## is part of a lengthy process where you want to document an +## error but keep going, you can set \code{.error} to some +## object of a compatible type. That object will be returned in +## the event of error and will have as its \code{"error"} +## attribute the error object. +## @param .finish A function to run on the result before returning it. Ignored +## if \code{.docall} is \code{FALSE}. +## +## @return Either a named list or the result of calling \code{fun} with the +## supplied arguments +## +arg_reconcile <- function(fun, ..., .args = alist(), .docall = FALSE, + .include = c(), .exclude= c(), .remap = list(), .warn = TRUE, .error = "default", .finish = identity) { # capture the formal arguments of the target function frmls <- formals(fun) @@ -58,7 +58,7 @@ arg_reconcile <- function(fun, ..., .args = alist(), .docall = FALSE, try(args[[ii]] <- eval(args[[ii]], parent.frame())) } } - # get rid of duplicate arguments, with freeform arguments + # get rid of duplicate arguments, with freeform arguments dupes <- names(args)[duplicated(names(args))] for (ii in dupes) { args[which(names(args) == ii)[-1]] <- NULL @@ -67,7 +67,7 @@ arg_reconcile <- function(fun, ..., .args = alist(), .docall = FALSE, args <- c(args, .args) # Apply whitelist and blacklist. This step also removes duplicates _between_ # the freeform (...) and pre-specified (.args) arguments, with ... versions - # taking precedence over the .args versions. This is a consequence of the + # taking precedence over the .args versions. This is a consequence of the # intersect() and setdiff() operations and works even if there is no blacklist # nor whitelist if (!missing(.include)) { @@ -88,13 +88,13 @@ arg_reconcile <- function(fun, ..., .args = alist(), .docall = FALSE, unused <- setdiff(names(args), names(frmls)) if (length(unused)>0){ if (isTRUE(.warn)) { - warning("The following arguments were ignored for ", + warning("The following arguments were ignored for ", deparse(substitute(fun)), ":\n", paste(unused, collapse = ", ")) } args <- args[intersect(names(args), names(frmls))] } } - # the final, cleaned-up arguments either get returned as a list or used on the + # the final, cleaned-up arguments either get returned as a list or used on the # function, depending on how .docall is set if (!isTRUE(.docall)) { return(args) @@ -104,13 +104,13 @@ arg_reconcile <- function(fun, ..., .args = alist(), .docall = FALSE, if (!inherits(oo, "try-error")) { return(.finish(oo)) } else { - # construct an informative error... eventually there will be more + # construct an informative error... eventually there will be more # detailed info here - errorhint <- paste('\nThis error was generated by: ', - deparse(match.call()$fun), - '\nWith the following arguments:\n', - gsub('^list\\(|\\)$', '', - paste(deparse(args, control=c('delayPromises')), + errorhint <- paste('\nThis error was generated by: ', + deparse(match.call()$fun), + '\nWith the following arguments:\n', + gsub('^list\\(|\\)$', '', + paste(deparse(args, control=c('delayPromises')), collapse='\n'))) if (missing(.error)) { stop(attr(oo, "condition")$message, errorhint) @@ -121,4 +121,3 @@ arg_reconcile <- function(fun, ..., .args = alist(), .docall = FALSE, } } } - diff --git a/man/arg_reconcile.Rd b/man/arg_reconcile.Rd deleted file mode 100644 index ec36ffc..0000000 --- a/man/arg_reconcile.Rd +++ /dev/null @@ -1,77 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/arg_reconcile.R -\name{arg_reconcile} -\alias{arg_reconcile} -\title{Reconcile an argument list to any function signature.} -\usage{ -arg_reconcile( - fun, - ..., - .args = alist(), - .docall = FALSE, - .include = c(), - .exclude = c(), - .remap = list(), - .warn = TRUE, - .error = "default", - .finish = identity -) -} -\arguments{ -\item{fun}{A function to which an argument list needs to be adapted. Use -the unquoted name of the function. If it's in a different -package then the fully qualified unquoted name (e.g. -\code{utils::read.table})} - -\item{...}{An arbitrary list of named arguments (unnamed ones will be -ignored). Arguments in \code{.args} are overridden by -arguments of the same name (if any) in \code{...}} - -\item{.args}{A list or \code{alist} of named arguments, to be merged -with \code{...}. Arguments in \code{.args} are overridden by -arguments of the same name (if any) in \code{...}} - -\item{.docall}{If set to \code{TRUE} will not only clean up the arguments -but also execute \code{fun} with those arguments -(\code{FALSE} by default) and return the results} - -\item{.include}{Whitelist. If not empty, only arguments named here will be -permitted, and only if they satisfy the conditions implied by -the other arguments. Evaluated before \code{.remap}.} - -\item{.exclude}{Blacklist. If not empty, arguments named here will be removed -even if they satisfy the conditions implied by the other -arguments. Evaluated before \code{.remap}.} - -\item{.remap}{An optional named character vector or named list of character -values for standardizing arguments that play the same role -but have different names in different functions. Evaluated -after \code{.exclude} and \code{.include}.} - -\item{.warn}{Whether to issue a warning message (default) when invalid -arguments need to be discarded.} - -\item{.error}{If specified, should be the object to return in the event of -error. This object will have the error as its -\code{error} attribute. If not specified an ordinary error is -thrown with an added hint on the documentation to read for -troubleshooting. Ignored if \code{.docall} is \code{FALSE}. -The point of doing this is fault-tolerance-- if this function -is part of a lengthy process where you want to document an -error but keep going, you can set \code{.error} to some -object of a compatible type. That object will be returned in -the event of error and will have as its \code{"error"} -attribute the error object.} - -\item{.finish}{A function to run on the result before returning it. Ignored -if \code{.docall} is \code{FALSE}.} -} -\value{ -Either a named list or the result of calling \code{fun} with the - supplied arguments -} -\description{ -Adapt an argument list to a function excluding arguments that - will not be recognized by it, redundant arguments, and un-named - arguments. -} From 277ae22176c1440217b94dcf442f9baa45b701cb Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Wed, 30 Aug 2023 11:36:31 +0200 Subject: [PATCH 17/44] Style --- R/arg_reconcile.R | 132 +++++++++++++++++++++++----------------------- 1 file changed, 66 insertions(+), 66 deletions(-) diff --git a/R/arg_reconcile.R b/R/arg_reconcile.R index 09a6ab7..fcc1692 100644 --- a/R/arg_reconcile.R +++ b/R/arg_reconcile.R @@ -49,75 +49,75 @@ arg_reconcile <- function(fun, ..., .args = alist(), .docall = FALSE, .include = c(), .exclude= c(), .remap = list(), .warn = TRUE, .error = "default", .finish = identity) { - # capture the formal arguments of the target function - frmls <- formals(fun) - # both freeform and an explicit list - args <- match.call(expand.dots = FALSE)[["..."]] - if (isTRUE(.docall)) { - for (ii in names(args)) { - try(args[[ii]] <- eval(args[[ii]], parent.frame())) + ## capture the formal arguments of the target function + frmls <- formals(fun) + ## both freeform and an explicit list + args <- match.call(expand.dots = FALSE)[["..."]] + if (isTRUE(.docall)) { + for (ii in names(args)) { + try(args[[ii]] <- eval(args[[ii]], parent.frame())) + } } - } - # get rid of duplicate arguments, with freeform arguments - dupes <- names(args)[duplicated(names(args))] - for (ii in dupes) { - args[which(names(args) == ii)[-1]] <- NULL - } - # Merge ... with .args - args <- c(args, .args) - # Apply whitelist and blacklist. This step also removes duplicates _between_ - # the freeform (...) and pre-specified (.args) arguments, with ... versions - # taking precedence over the .args versions. This is a consequence of the - # intersect() and setdiff() operations and works even if there is no blacklist - # nor whitelist - if (!missing(.include)) { - args <- args[intersect(names(args), .include)] - } - args <- args[setdiff(names(args), .exclude)] - # if any remappings of one argument to another are specified, perform them - for (ii in names(.remap)) { - if (!.remap[[ii]] %in% names(args) && ii %in% names(args)) { - args[[.remap[[ii]] ]] <- args[[ii]] + ## get rid of duplicate arguments, with freeform arguments + dupes <- names(args)[duplicated(names(args))] + for (ii in dupes) { + args[which(names(args) == ii)[-1]] <- NULL } - } - # remove any unnamed arguments - args[names(args) == ""] <- NULL - # if the target function doesn't have "..." as an argument, check to make sure - # only recognized arguments get passed, optionally with a warning - if (!"..." %in% names(frmls)) { - unused <- setdiff(names(args), names(frmls)) - if (length(unused)>0){ - if (isTRUE(.warn)) { - warning("The following arguments were ignored for ", - deparse(substitute(fun)), ":\n", paste(unused, collapse = ", ")) - } - args <- args[intersect(names(args), names(frmls))] + ## Merge ... with .args + args <- c(args, .args) + ## Apply whitelist and blacklist. This step also removes duplicates _between_ + ## the freeform (...) and pre-specified (.args) arguments, with ... versions + ## taking precedence over the .args versions. This is a consequence of the + ## intersect() and setdiff() operations and works even if there is no blacklist + ## nor whitelist + if (!missing(.include)) { + args <- args[intersect(names(args), .include)] } - } - # the final, cleaned-up arguments either get returned as a list or used on the - # function, depending on how .docall is set - if (!isTRUE(.docall)) { - return(args) - } else { - # run the function and return the result case - oo <- try(do.call(fun, args), silent = TRUE) - if (!inherits(oo, "try-error")) { - return(.finish(oo)) + args <- args[setdiff(names(args), .exclude)] + ## if any remappings of one argument to another are specified, perform them + for (ii in names(.remap)) { + if (!.remap[[ii]] %in% names(args) && ii %in% names(args)) { + args[[.remap[[ii]] ]] <- args[[ii]] + } + } + ## remove any unnamed arguments + args[names(args) == ""] <- NULL + ## if the target function doesn't have "..." as an argument, check to make sure + ## only recognized arguments get passed, optionally with a warning + if (!"..." %in% names(frmls)) { + unused <- setdiff(names(args), names(frmls)) + if (length(unused)>0) { + if (isTRUE(.warn)) { + warning("The following arguments were ignored for ", + deparse(substitute(fun)), ":\n", paste(unused, collapse = ", ")) + } + args <- args[intersect(names(args), names(frmls))] + } + } + ## the final, cleaned-up arguments either get returned as a list or used on the + ## function, depending on how .docall is set + if (!isTRUE(.docall)) { + return(args) } else { - # construct an informative error... eventually there will be more - # detailed info here - errorhint <- paste('\nThis error was generated by: ', - deparse(match.call()$fun), - '\nWith the following arguments:\n', - gsub('^list\\(|\\)$', '', - paste(deparse(args, control=c('delayPromises')), - collapse='\n'))) - if (missing(.error)) { - stop(attr(oo, "condition")$message, errorhint) - } else { - attr(.error, "error") <- oo - return(.error) - } + ## run the function and return the result case + oo <- try(do.call(fun, args), silent = TRUE) + if (!inherits(oo, "try-error")) { + return(.finish(oo)) + } else { + ## construct an informative error... eventually there will be more + ## detailed info here + errorhint <- paste("\nThis error was generated by: ", + deparse(match.call()$fun), + "\nWith the following arguments:\n", + gsub("^list\\(|\\)$", "", + paste(deparse(args, control=c("delayPromises")), + collapse = "\n"))) + if (missing(.error)) { + stop(attr(oo, "condition")$message, errorhint) + } else { + attr(.error, "error") <- oo + return(.error) + } + } } - } } From b6c72ebc224ab68afe23cc344f159deb3d71637d Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Wed, 30 Aug 2023 11:40:29 +0200 Subject: [PATCH 18/44] Add examples to `get_ext` [no ci] ref ropensci/software-review#605 --- R/utils.R | 5 +++++ man/get_ext.Rd | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/R/utils.R b/R/utils.R index 735f452..f6c4028 100644 --- a/R/utils.R +++ b/R/utils.R @@ -2,6 +2,11 @@ #' @description A utility function to retrieve the file type from a file extension (via its filename/path/URL) #' @param file A character string containing a filename, file path, or URL. #' @return A characters string containing a file type recognized by rio. +#' @examples +#' get_ext("starwars.xlsx") +#' get_ext("starwars.ods") +#' get_ext("clipboard") ## "clipboard" +#' get_ext("https://github.com/ropensci/readODS/raw/v2.1/starwars.ods") #' @export get_ext <- function(file) { if (!is.character(file)) { diff --git a/man/get_ext.Rd b/man/get_ext.Rd index e656a9a..5ece047 100644 --- a/man/get_ext.Rd +++ b/man/get_ext.Rd @@ -15,3 +15,9 @@ A characters string containing a file type recognized by rio. \description{ A utility function to retrieve the file type from a file extension (via its filename/path/URL) } +\examples{ +get_ext("starwars.xlsx") +get_ext("starwars.ods") +get_ext("clipboard") ## "clipboard" +get_ext("https://github.com/ropensci/readODS/raw/v2.1/starwars.ods") +} From a1057deb0872008f158f682a5830c78f130681b1 Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Wed, 30 Aug 2023 11:46:05 +0200 Subject: [PATCH 19/44] Add examples to `install_formats()` [no ci] ref ropensci/software-review#605 --- R/suggestions.R | 6 ++++++ man/install_formats.Rd | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/R/suggestions.R b/R/suggestions.R index 7d2ba69..dbc72c5 100644 --- a/R/suggestions.R +++ b/R/suggestions.R @@ -3,6 +3,12 @@ #' @param \dots Additional arguments passed to \code{\link[utils]{install.packages}}. #' @return \code{NULL} #' @importFrom utils install.packages +#' @examples +#' \donttest{ +#' if (interactive()) { +#' install_formats() +#' } +#' } #' @export install_formats <- function(...) { diff --git a/man/install_formats.Rd b/man/install_formats.Rd index 31ae8a3..3c763c7 100644 --- a/man/install_formats.Rd +++ b/man/install_formats.Rd @@ -15,3 +15,10 @@ install_formats(...) \description{ This function installs various \sQuote{Suggests} dependencies for rio that expand its support to the full range of support import and export formats. These packages are not installed or loaded by default in order to create a slimmer and faster package build, install, and load. } +\examples{ +\donttest{ +if (interactive()) { +install_formats() +} +} +} From f58c2c0d1c4837c890d841aa45d77f67bd38fb4e Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Wed, 30 Aug 2023 11:50:43 +0200 Subject: [PATCH 20/44] Document the return value of `characterize` [no ci] ref ropensci/software-review#605 --- R/characterize.R | 9 +++++---- man/characterize.Rd | 3 +++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/R/characterize.R b/R/characterize.R index 24dca6c..0561d8b 100644 --- a/R/characterize.R +++ b/R/characterize.R @@ -5,25 +5,26 @@ #' @param coerce_character A logical indicating whether to additionally coerce character columns to factor (in \code{factorize}). Default \code{FALSE}. #' @param \dots additional arguments passed to methods #' @details \code{characterize} converts a vector with a \code{labels} attribute of named levels into a character vector. \code{factorize} does the same but to factors. This can be useful at two stages of a data workflow: (1) importing labelled data from metadata-rich file formats (e.g., Stata or SPSS), and (2) exporting such data to plain text files (e.g., CSV) in a way that preserves information. +#' @return a character vector (for \code{characterize}) or factor vector (for \code{factorize}) #' @examples #' # vector method #' x <- structure(1:4, labels = c("A" = 1, "B" = 2, "C" = 3)) #' characterize(x) #' factorize(x) -#' +#' #' # data frame method #' x <- data.frame(v1 = structure(1:4, labels = c("A" = 1, "B" = 2, "C" = 3)), #' v2 = structure(c(1,0,0,1), labels = c("foo" = 0, "bar" = 1))) #' str(factorize(x)) #' str(characterize(x)) -#' +#' #' # comparison of exported file contents #' import(export(x, csv_file <- tempfile(fileext = ".csv"))) #' import(export(factorize(x), csv_file)) -#' +#' #' # cleanup #' unlink(csv_file) -#' +#' #' @seealso \code{\link{gather_attrs}} #' @export characterize <- function(x, ...) { diff --git a/man/characterize.Rd b/man/characterize.Rd index cda559f..dda61cb 100644 --- a/man/characterize.Rd +++ b/man/characterize.Rd @@ -28,6 +28,9 @@ factorize(x, ...) \item{coerce_character}{A logical indicating whether to additionally coerce character columns to factor (in \code{factorize}). Default \code{FALSE}.} } +\value{ +a character vector (for \code{characterize}) or factor vector (for \code{factorize}) +} \description{ Convert labelled variables to character or factor } From 325fce320b782ab5e826a00046c4c7d785c3f562 Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Wed, 30 Aug 2023 11:57:45 +0200 Subject: [PATCH 21/44] Unexport .export .import ref #320 ropensci/software-review#605 Pending: write a Vignette instead --- NAMESPACE | 4 ---- R/export.R | 20 ++++++++++---------- R/extensions.R | 42 +++++++++++++++++++----------------------- R/import.R | 2 +- man/export.Rd | 8 ++++---- man/extensions.Rd | 41 ----------------------------------------- man/import.Rd | 2 +- 7 files changed, 35 insertions(+), 84 deletions(-) delete mode 100644 man/extensions.Rd diff --git a/NAMESPACE b/NAMESPACE index 7f41243..c0bc1fa 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,6 +1,5 @@ # Generated by roxygen2: do not edit by hand -S3method(.export,default) S3method(.export,rio_arff) S3method(.export,rio_clipboard) S3method(.export,rio_csv) @@ -32,7 +31,6 @@ S3method(.export,rio_xml) S3method(.export,rio_xpt) S3method(.export,rio_yml) S3method(.export,rio_zsav) -S3method(.import,default) S3method(.import,rio_arff) S3method(.import,rio_clipboard) S3method(.import,rio_csv) @@ -77,8 +75,6 @@ S3method(characterize,data.frame) S3method(characterize,default) S3method(factorize,data.frame) S3method(factorize,default) -export(.export) -export(.import) export(characterize) export(convert) export(export) diff --git a/R/export.R b/R/export.R index 0cf5acb..8c1e4b2 100644 --- a/R/export.R +++ b/R/export.R @@ -7,7 +7,7 @@ #' @param \dots Additional arguments for the underlying export functions. This can be used to specify non-standard arguments. See examples. #' @return The name of the output file as a character string (invisibly). #' @details This function exports a data frame or matrix into a file with file format based on the file extension (or the manually specified format, if \code{format} is specified). -#' +#' #' The output file can be to a compressed directory, simply by adding an appropriate additional extensiont to the \code{file} argument, such as: \dQuote{mtcars.csv.tar}, \dQuote{mtcars.csv.zip}, or \dQuote{mtcars.csv.gz}. #' #' \code{export} supports many file formats. See the documentation for the underlying export functions for optional arguments that can be passed via \code{...} @@ -33,7 +33,7 @@ #' \item Apache Arrow Parquet (.parquet), using \code{\link[arrow]{write_parquet}} #' \item Feather R/Python interchange format (.feather), using \code{\link[feather]{write_feather}} #' \item Fast storage (.fst), using \code{\link[fst]{write.fst}} -#' \item JSON (.json), using \code{\link[jsonlite]{toJSON}}. In this case, \code{x} can be a variety of R objects, based on class mapping conventions in this paper: \href{https://arxiv.org/abs/1403.2805}{https://arxiv.org/abs/1403.2805}. +#' \item JSON (.json), using \code{\link[jsonlite]{toJSON}}. In this case, \code{x} can be a variety of R objects, based on class mapping conventions in this paper: \href{https://arxiv.org/abs/1403.2805}{https://arxiv.org/abs/1403.2805}. #' \item Matlab (.mat), using \code{\link[rmatio]{write.mat}} #' \item OpenDocument Spreadsheet (.ods), using \code{\link[readODS]{write_ods}}. (Currently only single-sheet exports are supported.) #' \item HTML (.html), using a custom method based on \code{\link[xml2]{xml_add_child}} to create a simple HTML table and \code{\link[xml2]{write_xml}} to write to disk. @@ -43,9 +43,9 @@ #' } #' #' When exporting a data set that contains label attributes (e.g., if imported from an SPSS or Stata file) to a plain text file, \code{\link{characterize}} can be a useful pre-processing step that records value labels into the resulting file (e.g., \code{export(characterize(x), "file.csv")}) rather than the numeric values. -#' +#' #' Use \code{\link{export_list}} to export a list of dataframes to separate files. -#' +#' #' @examples #' library("datasets") #' # specify only `file` argument @@ -61,7 +61,7 @@ #' f2 %in% tempdir() #' export(mtcars, format = "stata") #' "mtcars.dta" %in% dir() -#' +#' #' setwd(wd) #' } #' # specify `file` and `format` to override default format @@ -87,14 +87,14 @@ #' \dontrun{ #' ## export a single data frame #' export(mtcars, f9 <- tempfile(fileext = ".xlsx")) -#' +#' #' ## export NAs to Excel as missing via args passed to `...` #' mtcars$drat <- NA_real_ #' mtcars %>% export(f10 <- tempfile(fileext = ".xlsx"), keepNA = TRUE) -#' +#' #' ## export a list of data frames as worksheets #' export(list(a = mtcars, b = iris), f11 <- tempfile(fileext = ".xlsx")) -#' +#' #' ## export, adding a new sheet to an existing workbook #' export(iris, f12 <- tempfile(fileext = ".xlsx"), which = "iris") #' } @@ -116,7 +116,7 @@ #' # unlink(f11) #' # unlink(f12) #' # unlink(f13) -#' @seealso \code{\link{.export}}, \code{\link{characterize}}, \code{\link{import}}, \code{\link{convert}}, \code{\link{export_list}} +#' @seealso \code{\link{characterize}}, \code{\link{import}}, \code{\link{convert}}, \code{\link{export_list}} #' @importFrom haven labelled #' @export export <- function(x, file, format, ...) { @@ -155,7 +155,7 @@ export <- function(x, file, format, ...) { } else if (is.matrix(x)) { x <- as.data.frame(x) } - + class(file) <- c(paste0("rio_", fmt), class(file)) .export(file = file, x = x, ...) diff --git a/R/extensions.R b/R/extensions.R index 4ff8033..c327cfe 100644 --- a/R/extensions.R +++ b/R/extensions.R @@ -1,25 +1,23 @@ -#' @rdname extensions -#' @aliases extensions .import .export -#' @title rio Extensions -#' @description Writing Import/Export Extensions for rio -#' @param file A character string naming a file. -#' @param x A data frame or matrix to be written into a file. -#' @param \dots Additional arguments passed to methods. -#' @return For \code{.import}, an R data.frame. For \code{.export}, \code{file}, invisibly. -#' @details rio implements format-specific S3 methods for each type of file that can be imported from or exported to. This happens via internal S3 generics, \code{.import} and \code{.export}. It is possible to write new methods like with any S3 generic (e.g., \code{print}). -#' -#' As an example, \code{.import.rio_csv} imports from a comma-separated values file. If you want to produce a method for a new filetype with extension \dQuote{myfile}, you simply have to create a function called \code{.import.rio_myfile} that implements a format-specific importing routine and returns a data.frame. rio will automatically recognize new S3 methods, so that you can then import your file using: \code{import("file.myfile")}. -#' -#' As general guidance, if an import method creates many attributes, these attributes should be stored --- to the extent possible --- in variable-level attributes fields. These can be \dQuote{gathered} to the data.frame level by the user via \code{\link{gather_attrs}}. -#' @seealso \code{\link{import}}, \code{\link{export}} -#' @export +## @rdname extensions +## @aliases extensions .import .export +## @title rio Extensions +## @description Writing Import/Export Extensions for rio +## @param file A character string naming a file. +## @param x A data frame or matrix to be written into a file. +## @param \dots Additional arguments passed to methods. +## @return For \code{.import}, an R data.frame. For \code{.export}, \code{file}, invisibly. +## @details rio implements format-specific S3 methods for each type of file that can be imported from or exported to. This happens via internal S3 generics, \code{.import} and \code{.export}. It is possible to write new methods like with any S3 generic (e.g., \code{print}). +## +## As an example, \code{.import.rio_csv} imports from a comma-separated values file. If you want to produce a method for a new filetype with extension \dQuote{myfile}, you simply have to create a function called \code{.import.rio_myfile} that implements a format-specific importing routine and returns a data.frame. rio will automatically recognize new S3 methods, so that you can then import your file using: \code{import("file.myfile")}. +## +## As general guidance, if an import method creates many attributes, these attributes should be stored --- to the extent possible --- in variable-level attributes fields. These can be \dQuote{gathered} to the data.frame level by the user via \code{\link{gather_attrs}}. +## @seealso \code{\link{import}}, \code{\link{export}} .import <- function(file, ...){ UseMethod('.import') } -#' @rdname extensions -#' @importFrom tools file_ext -#' @export +## @rdname extensions +## @importFrom tools file_ext .import.default <- function(file, ...){ x <- gettext("%s format not supported. Consider using the '%s()' function") xA <- gettext("Import support for the %s format is exported by the %s package. Run 'library(%s)' then try again.") @@ -48,15 +46,13 @@ stop(out, call. = FALSE) } -#' @rdname extensions -#' @export +## @rdname extensions .export <- function(file, x, ...){ UseMethod(".export") } -#' @rdname extensions -#' @importFrom tools file_ext -#' @export +## @rdname extensions +## @importFrom tools file_ext .export.default <- function(file, x, ...){ x <- gettext("%s format not supported. Consider using the '%s()' function") fmt <- tools::file_ext(file) diff --git a/R/import.R b/R/import.R index 61552d9..ad6a281 100644 --- a/R/import.R +++ b/R/import.R @@ -88,7 +88,7 @@ #' unlink(tsv_file) #' unlink(rds_file) #' -#' @seealso \code{\link{import_list}}, \code{\link{.import}}, \code{\link{characterize}}, \code{\link{gather_attrs}}, \code{\link{export}}, \code{\link{convert}} +#' @seealso \code{\link{import_list}}, \code{\link{characterize}}, \code{\link{gather_attrs}}, \code{\link{export}}, \code{\link{convert}} #' @importFrom tools file_ext file_path_sans_ext #' @importFrom stats na.omit setNames #' @importFrom utils installed.packages untar unzip tar zip type.convert capture.output diff --git a/man/export.Rd b/man/export.Rd index 310ceaa..5e82d3d 100644 --- a/man/export.Rd +++ b/man/export.Rd @@ -49,7 +49,7 @@ The output file can be to a compressed directory, simply by adding an appropriat \item Apache Arrow Parquet (.parquet), using \code{\link[arrow]{write_parquet}} \item Feather R/Python interchange format (.feather), using \code{\link[feather]{write_feather}} \item Fast storage (.fst), using \code{\link[fst]{write.fst}} - \item JSON (.json), using \code{\link[jsonlite]{toJSON}}. In this case, \code{x} can be a variety of R objects, based on class mapping conventions in this paper: \href{https://arxiv.org/abs/1403.2805}{https://arxiv.org/abs/1403.2805}. + \item JSON (.json), using \code{\link[jsonlite]{toJSON}}. In this case, \code{x} can be a variety of R objects, based on class mapping conventions in this paper: \href{https://arxiv.org/abs/1403.2805}{https://arxiv.org/abs/1403.2805}. \item Matlab (.mat), using \code{\link[rmatio]{write.mat}} \item OpenDocument Spreadsheet (.ods), using \code{\link[readODS]{write_ods}}. (Currently only single-sheet exports are supported.) \item HTML (.html), using a custom method based on \code{\link[xml2]{xml_add_child}} to create a simple HTML table and \code{\link[xml2]{write_xml}} to write to disk. @@ -103,11 +103,11 @@ source(f8, echo = TRUE) \dontrun{ ## export a single data frame export(mtcars, f9 <- tempfile(fileext = ".xlsx")) - + ## export NAs to Excel as missing via args passed to `...` mtcars$drat <- NA_real_ mtcars \%>\% export(f10 <- tempfile(fileext = ".xlsx"), keepNA = TRUE) - + ## export a list of data frames as worksheets export(list(a = mtcars, b = iris), f11 <- tempfile(fileext = ".xlsx")) @@ -134,5 +134,5 @@ unlink(f8) # unlink(f13) } \seealso{ -\code{\link{.export}}, \code{\link{characterize}}, \code{\link{import}}, \code{\link{convert}}, \code{\link{export_list}} +\code{\link{characterize}}, \code{\link{import}}, \code{\link{convert}}, \code{\link{export_list}} } diff --git a/man/extensions.Rd b/man/extensions.Rd deleted file mode 100644 index eb03194..0000000 --- a/man/extensions.Rd +++ /dev/null @@ -1,41 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/extensions.R -\name{.import} -\alias{.import} -\alias{extensions} -\alias{.export} -\alias{.import.default} -\alias{.export.default} -\title{rio Extensions} -\usage{ -.import(file, ...) - -\method{.import}{default}(file, ...) - -.export(file, x, ...) - -\method{.export}{default}(file, x, ...) -} -\arguments{ -\item{file}{A character string naming a file.} - -\item{\dots}{Additional arguments passed to methods.} - -\item{x}{A data frame or matrix to be written into a file.} -} -\value{ -For \code{.import}, an R data.frame. For \code{.export}, \code{file}, invisibly. -} -\description{ -Writing Import/Export Extensions for rio -} -\details{ -rio implements format-specific S3 methods for each type of file that can be imported from or exported to. This happens via internal S3 generics, \code{.import} and \code{.export}. It is possible to write new methods like with any S3 generic (e.g., \code{print}). - -As an example, \code{.import.rio_csv} imports from a comma-separated values file. If you want to produce a method for a new filetype with extension \dQuote{myfile}, you simply have to create a function called \code{.import.rio_myfile} that implements a format-specific importing routine and returns a data.frame. rio will automatically recognize new S3 methods, so that you can then import your file using: \code{import("file.myfile")}. - -As general guidance, if an import method creates many attributes, these attributes should be stored --- to the extent possible --- in variable-level attributes fields. These can be \dQuote{gathered} to the data.frame level by the user via \code{\link{gather_attrs}}. -} -\seealso{ -\code{\link{import}}, \code{\link{export}} -} diff --git a/man/import.Rd b/man/import.Rd index 368f897..29a16da 100644 --- a/man/import.Rd +++ b/man/import.Rd @@ -109,5 +109,5 @@ unlink(rds_file) } \seealso{ -\code{\link{import_list}}, \code{\link{.import}}, \code{\link{characterize}}, \code{\link{gather_attrs}}, \code{\link{export}}, \code{\link{convert}} +\code{\link{import_list}}, \code{\link{characterize}}, \code{\link{gather_attrs}}, \code{\link{export}}, \code{\link{convert}} } From 157ced899b1536d66af841c3bcfbb570e4c9929d Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Wed, 30 Aug 2023 12:07:54 +0200 Subject: [PATCH 22/44] Update codemeta.json [no ci] --- codemeta.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codemeta.json b/codemeta.json index cf29c62..4413620 100644 --- a/codemeta.json +++ b/codemeta.json @@ -447,7 +447,7 @@ }, "SystemRequirements": null }, - "fileSize": "323.042KB", + "fileSize": "319.109KB", "citation": [ { "@type": "SoftwareSourceCode", From bd67fcf8ba828171f21c66f8a20efca8d7ec2c42 Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Wed, 30 Aug 2023 15:40:05 +0200 Subject: [PATCH 23/44] Fix the arrow test error for arrow 7 --- tests/testthat/test_format_parquet.R | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/testthat/test_format_parquet.R b/tests/testthat/test_format_parquet.R index 5f1aae1..334b3b9 100644 --- a/tests/testthat/test_format_parquet.R +++ b/tests/testthat/test_format_parquet.R @@ -3,7 +3,6 @@ require("datasets") test_that("Export to and import from parquet", { skip_if_not_installed("arrow") - skip_if_not(arrow::arrow_available()) expect_true(export(iris, "iris.parquet") %in% dir()) expect_true(is.data.frame(import("iris.parquet"))) unlink("iris.parquet") From 0382450657d05dee4c1bebb1342764bb7541a098 Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Wed, 30 Aug 2023 15:44:51 +0200 Subject: [PATCH 24/44] Disable the shorten URL test --- tests/testthat/test_remote.R | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/testthat/test_remote.R b/tests/testthat/test_remote.R index 19e3d65..6ef4e0d 100644 --- a/tests/testthat/test_remote.R +++ b/tests/testthat/test_remote.R @@ -17,7 +17,7 @@ test_that("Import Remote GitHub File", { if (!inherits(rfile_imported2, "try-error")) { expect_true(inherits(rfile_imported2, "data.frame"), label = "Import remote file (explicit format)") } - + lfile <- remote_to_local(rfile) if (!inherits(lfile, "try-error")) { expect_true(file.exists(lfile), label = "Remote file copied successfully") @@ -25,18 +25,18 @@ test_that("Import Remote GitHub File", { } }) -test_that("Import Remote File from Shortened URL", { - skip_if_not_installed(pkg="data.table") - shorturl <- try(import("https://goo.gl/KPFiaK")) - if (!inherits(shorturl, "try-error")) { - expect_true(inherits(shorturl, "data.frame"), label = "Import remote file") - } -}) +## test_that("Import Remote File from Shortened URL", { +## skip_if_not_installed(pkg = "data.table") +## shorturl <- try(import("https://raw.githubusercontent.com/chainsawriot/rio/main/tests/testdata/example.csvy")) +## if (!inherits(shorturl, "try-error")) { +## expect_true(inherits(shorturl, "data.frame"), label = "Import remote file") +## } +## }) test_that("Import from Google Sheets", { googleurl1 <- "https://docs.google.com/spreadsheets/d/1I9mJsS5QnXF2TNNntTy-HrcdHmIF9wJ8ONYvEJTXSNo/edit#gid=0" expect_true(inherits(import(googleurl1), "data.frame"), label = "Import google sheets (specified sheet)") - + googleurl2 <- "https://docs.google.com/spreadsheets/d/1I9mJsS5QnXF2TNNntTy-HrcdHmIF9wJ8ONYvEJTXSNo/edit" expect_true(inherits(import(googleurl2), "data.frame"), label = "Import google sheets (unspecified sheet)") From 7ec4155715e544f681ddf30355e5a8e650d53aa4 Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Wed, 30 Aug 2023 16:00:50 +0200 Subject: [PATCH 25/44] Fix #301 --- R/import.R | 5 ++++- tests/testthat/test_import.r | 12 ++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 tests/testthat/test_import.r diff --git a/R/import.R b/R/import.R index ad6a281..3a6dd9c 100644 --- a/R/import.R +++ b/R/import.R @@ -97,11 +97,14 @@ #' @importFrom tibble as_tibble is_tibble #' @export import <- function(file, format, setclass, which, ...) { + if (isFALSE(inherits(file, "character")) || isFALSE(length(file) == 1)) { + stop("Invalid `file` argument.", call. = FALSE) + } if (grepl("^http.*://", file)) { file <- remote_to_local(file, format = format) } if ((file != "clipboard") && !file.exists(file)) { - stop("No such file") + stop("No such file: ", file, call. = FALSE) } if (grepl("\\.zip$", file)) { if (missing(which)) { diff --git a/tests/testthat/test_import.r b/tests/testthat/test_import.r new file mode 100644 index 0000000..6cb4eb6 --- /dev/null +++ b/tests/testthat/test_import.r @@ -0,0 +1,12 @@ + +test_that("Invalid file argument, #301", { + data <- data.frame( + x = sample(1:10, 10000, replace = TRUE), + y = sample(1:10, 10000, replace = TRUE) + ) + expect_error(import(data), "Invalid") + expect_error(import(iris), "Invalid") + expect_error(import(1), "Invalid") + expect_error(import(TRUE), "Invalid") + expect_error(import(c("a.csv", "b.csv")), "Invalid") +}) From 2ed27290b6ffdbe40a4bc8fecaa4c44cd2af23ae Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Wed, 30 Aug 2023 16:52:57 +0200 Subject: [PATCH 26/44] Remove the obsolete data.table option change (#323) * Remove the obsolete data.table option change It has been removed since 2018 https://github.com/Rdatatable/data.table/blob/88039186915028ab3c93ccfd8e22c0d1c3534b1a/NEWS.md?plain=1#L1797 * Update NEWS.md [no ci] --- DESCRIPTION | 2 +- NEWS.md | 4 ++++ R/onLoad.R | 4 ---- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 4c9d2f7..f7b9906 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -45,7 +45,7 @@ Imports: foreign, haven (>= 1.1.2), curl (>= 0.6), - data.table (>= 1.9.8), + data.table (>= 1.11.2), readxl (>= 0.1.1), openxlsx, tibble diff --git a/NEWS.md b/NEWS.md index 88edc6d..e486100 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,7 @@ +* Unexport objects: `.import`, `.export`; remove documentation for `arg_reconcile` #321 +* Declutter + - remove the obsolete data.table option #323 + # rio 0.5.30 * Maintenance release: new maintainer diff --git a/R/onLoad.R b/R/onLoad.R index d7978de..d4ad805 100644 --- a/R/onLoad.R +++ b/R/onLoad.R @@ -1,7 +1,3 @@ -.onLoad <- function(libname, pkgname) { - options(datatable.fread.dec.experiment=FALSE) -} - .onAttach <- function(libname, pkgname) { if (interactive()) { w <- uninstalled_formats() From fb8d7d7abbb882e1a770dcbfdd2ea42802fd51c9 Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Wed, 30 Aug 2023 19:26:45 +0200 Subject: [PATCH 27/44] Add `.check_pkg_availability` fix #296 (#324) --- NEWS.md | 1 + R/export_methods.R | 28 +++++++++--------- R/import_list.R | 4 +-- R/import_methods.R | 58 ++++++++++++++++++------------------- R/utils.R | 7 +++++ tests/testthat/test_guess.R | 5 ++++ 6 files changed, 58 insertions(+), 45 deletions(-) diff --git a/NEWS.md b/NEWS.md index e486100..a7dd072 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,4 @@ +* Stop loading the entire namespace of a suggested package when it is available #296 * Unexport objects: `.import`, `.export`; remove documentation for `arg_reconcile` #321 * Declutter - remove the obsolete data.table option #323 diff --git a/R/export_methods.R b/R/export_methods.R index f9c20b4..d85afe2 100644 --- a/R/export_methods.R +++ b/R/export_methods.R @@ -4,7 +4,7 @@ export_delim <- function(file, x, fwrite = TRUE, sep = "\t", row.names = FALSE, col.names = TRUE, append = FALSE, ...) { if (isTRUE(fwrite) & !inherits(file, "connection")) { if (isTRUE(append)) { - data.table::fwrite(x, file = file, sep = sep, row.names = row.names, + data.table::fwrite(x, file = file, sep = sep, row.names = row.names, col.names = FALSE, append = TRUE, ...) } else { data.table::fwrite(x, file = file, sep = sep, row.names = row.names, @@ -145,19 +145,19 @@ export_delim <- function(file, x, fwrite = TRUE, sep = "\t", row.names = FALSE, #' @export .export.rio_feather <- function(file, x, ...) { - requireNamespace("feather") + .check_pkg_availability("feather") feather::write_feather(x = x, path = file) } #' @export .export.rio_fst <- function(file, x, ...) { - requireNamespace("fst") + .check_pkg_availability("fst") fst::write.fst(x = x, path = file, ...) } #' @export .export.rio_matlab <- function(file, x, ...) { - requireNamespace("rmatio") + .check_pkg_availability("rmatio") rmatio::write.mat(object = x, filename = file, ...) } @@ -204,7 +204,7 @@ export_delim <- function(file, x, fwrite = TRUE, sep = "\t", row.names = FALSE, #' @export .export.rio_json <- function(file, x, ...) { - requireNamespace("jsonlite") + .check_pkg_availability("jsonlite") cat(jsonlite::toJSON(x, ...), file = file) } @@ -248,13 +248,13 @@ export_delim <- function(file, x, fwrite = TRUE, sep = "\t", row.names = FALSE, #' @export .export.rio_ods <- function(file, x, ...) { - requireNamespace("readODS") + .check_pkg_availability("readODS") readODS::write_ods(x = x, path = file) } #' @export .export.rio_html <- function(file, x, ...) { - requireNamespace("xml2") + .check_pkg_availability("xml2") html <- xml2::read_html("\nR Exported Data\n\n\n") bod <- xml2::xml_children(html)[[2]] if (is.data.frame(x)) { @@ -277,7 +277,7 @@ export_delim <- function(file, x, fwrite = TRUE, sep = "\t", row.names = FALSE, #' @export .export.rio_xml <- function(file, x, ...) { - requireNamespace("xml2") + .check_pkg_availability("xml2") root <- "" xml <- xml2::read_xml(paste0("<",as.character(substitute(x)),">\n\n")) att <- attributes(x)[!names(attributes(x)) %in% c("names", "row.names", "class")] @@ -302,24 +302,24 @@ export_delim <- function(file, x, fwrite = TRUE, sep = "\t", row.names = FALSE, #' @export .export.rio_yml <- function(file, x, ...) { - requireNamespace("yaml") + .check_pkg_availability("yaml") cat(yaml::as.yaml(x, ...), file = file) } #' @export .export.rio_clipboard <- function(file, x, row.names = FALSE, col.names = TRUE, sep = "\t", ...) { - requireNamespace("clipr") + .check_pkg_availability("clipr") clipr::write_clip(content = x, row.names = row.names, col.names = col.names, sep = sep, ...) } #' @export -.export.rio_pzfx <- function(file, x, ..., row_names=FALSE) { - requireNamespace("pzfx") +.export.rio_pzfx <- function(file, x, ..., row_names = FALSE) { + .check_pkg_availability("pzfx") pzfx::write_pzfx(x=x, path=file, ..., row_names=row_names) } #' @export .export.rio_parquet <- function(file, x, ...) { - requireNamespace("arrow") - arrow::write_parquet(x=x, sink=file, ...) + .check_pkg_availability("arrow") + arrow::write_parquet(x=x, sink = file, ...) } diff --git a/R/import_list.R b/R/import_list.R index f6b7b9e..ae37f0c 100644 --- a/R/import_list.R +++ b/R/import_list.R @@ -74,7 +74,7 @@ function(file, x <- as.list(e) } else { if (get_ext(file) == "html") { - requireNamespace("xml2", quietly = TRUE) + .check_pkg_availability("xml2") tables <- xml2::xml_find_all(xml2::read_html(unclass(file)), ".//table") if (missing(which)) { which <- seq_along(tables) @@ -84,7 +84,7 @@ function(file, ) names(which) <- whichnames } else if (get_ext(file) %in% c("xls","xlsx")) { - requireNamespace("readxl", quietly = TRUE) + .check_pkg_availability("readxl") whichnames <- readxl::excel_sheets(path = file) if (missing(which)) { which <- seq_along(whichnames) diff --git a/R/import_methods.R b/R/import_methods.R index 4209754..1fdf6c6 100644 --- a/R/import_methods.R +++ b/R/import_methods.R @@ -1,10 +1,10 @@ #' @importFrom data.table fread -import_delim <- - function(file, which = 1, fread = TRUE, sep = "auto", +import_delim <- + function(file, which = 1, fread = TRUE, sep = "auto", header = "auto", stringsAsFactors = FALSE, data.table = FALSE, ...) { if (isTRUE(fread) & !inherits(file, "connection")) { arg_reconcile(data.table::fread, input = file, sep = sep, header = header, - stringsAsFactors = stringsAsFactors, + stringsAsFactors = stringsAsFactors, data.table = data.table, ..., .docall = TRUE) } else { if (isTRUE(fread) & inherits(file, "connection")) { @@ -24,7 +24,7 @@ import_delim <- if (missing(header) || is.null(header) || header == "auto") { header <- TRUE } - arg_reconcile(utils::read.table, file=file, sep=sep, header=header, + arg_reconcile(utils::read.table, file=file, sep=sep, header=header, stringsAsFactors = stringsAsFactors, ..., .docall = TRUE) } } @@ -68,22 +68,22 @@ import_delim <- #' @importFrom utils read.fwf #' @export -.import.rio_fwf <- -function(file, - which = 1, - widths, - header = FALSE, - col.names, +.import.rio_fwf <- +function(file, + which = 1, + widths, + header = FALSE, + col.names, comment = "#", - readr = FALSE, - progress = getOption("verbose", FALSE), + readr = FALSE, + progress = getOption("verbose", FALSE), ...) { if (missing(widths)) { stop("Import of fixed-width format data requires a 'widths' argument. See ? read.fwf().") } a <- list(...) if (isTRUE(readr)) { - requireNamespace("readr") + .check_pkg_availability("readr") if (is.null(widths)) { if (!missing(col.names)) { widths <- readr::fwf_empty(file = file, col_names = col.names) @@ -103,8 +103,8 @@ function(file, } else { widths <- readr::fwf_widths(abs(widths)) } - readr::read_fwf(file = file, col_positions = widths, - col_types = col_types, progress = progress, + readr::read_fwf(file = file, col_positions = widths, + col_types = col_types, progress = progress, comment = comment, ...) } else { if (!missing(col.names)) { @@ -189,19 +189,19 @@ function(file, #' @export .import.rio_feather <- function(file, which = 1, ...) { - requireNamespace("feather") + .check_pkg_availability("feather") feather::read_feather(path = file) } #' @export .import.rio_fst <- function(file, which = 1, ...) { - requireNamespace("fst") + .check_pkg_availability("fst") fst::read.fst(path = file, ...) } #' @export .import.rio_matlab <- function(file, which = 1, ...) { - requireNamespace("rmatio") + .check_pkg_availability("rmatio") rmatio::read.mat(filename = file) } @@ -289,7 +289,7 @@ function(file, #' @export .import.rio_json <- function(file, which = 1, ...) { - requireNamespace("jsonlite") + .check_pkg_availability("jsonlite") jsonlite::fromJSON(txt = file, ...) } @@ -308,7 +308,7 @@ function(file, #' @importFrom readxl read_xls #' @export .import.rio_xls <- function(file, which = 1, ...) { - requireNamespace("readxl") + .check_pkg_availability("readxl") arg_reconcile(read_xls, path = file, ..., sheet = which, .docall = TRUE, .remap = c(colNames = 'col_names', na.strings = 'na')) @@ -319,12 +319,12 @@ function(file, #' @export .import.rio_xlsx <- function(file, which = 1, readxl = TRUE, ...) { if (isTRUE(readxl)) { - requireNamespace("readxl") + .check_pkg_availability("readxl") arg_reconcile(read_xlsx, path = file, ..., sheet = which, .docall = TRUE, .remap = c(colNames = 'col_names', na.strings = 'na')) } else { - requireNamespace("openxlsx") + .check_pkg_availability("openxlsx") arg_reconcile(read.xlsx, xlsxFile = file, ..., sheet = which, .docall = TRUE, .remap = c(col_names = 'colNames', na = 'na.strings')) @@ -342,7 +342,7 @@ function(file, #' @export .import.rio_ods <- function(file, which = 1, header = TRUE, ...) { - requireNamespace("readODS") + .check_pkg_availability("readODS") "read_ods" <- readODS::read_ods a <- list(...) if ("sheet" %in% names(a)) { @@ -371,7 +371,7 @@ function(file, #' @importFrom utils type.convert #' @export .import.rio_xml <- function(file, which = 1, stringsAsFactors = FALSE, ...) { - requireNamespace("xml2") + .check_pkg_availability("xml2") x <- xml2::as_list(xml2::read_xml(unclass(file)))[[1L]] d <- do.call("rbind", c(lapply(x, unlist))) row.names(d) <- 1:nrow(d) @@ -448,30 +448,30 @@ extract_html_row <- function(x, empty_value) { #' @export .import.rio_yml <- function(file, which = 1, stringsAsFactors = FALSE, ...) { - requireNamespace("yaml") + .check_pkg_availability("yaml") as.data.frame(yaml::read_yaml(file, ...), stringsAsFactors = stringsAsFactors) } #' @export .import.rio_eviews <- function(file, which = 1, ...) { - requireNamespace("hexView") + .check_pkg_availability("hexView") hexView::readEViews(file, ...) } #' @export .import.rio_clipboard <- function(file = "clipboard", which = 1, header = TRUE, sep = "\t", ...) { - requireNamespace("clipr") + .check_pkg_availability("clipr") clipr::read_clip_tbl(x = clipr::read_clip(), header = header, sep = sep, ...) } #' @export .import.rio_pzfx <- function(file, which=1, ...) { - requireNamespace("pzfx") + .check_pkg_availability("pzfx") pzfx::read_pzfx(path=file, table=which, ...) } #' @export .import.rio_parquet <- function(file, which = 1, as_data_frame = TRUE, ...) { - requireNamespace("arrow") + .check_pkg_availability("arrow") arrow::read_parquet(file = file, as_data_frame = TRUE, ...) } diff --git a/R/utils.R b/R/utils.R index f6c4028..a7dee6b 100644 --- a/R/utils.R +++ b/R/utils.R @@ -118,3 +118,10 @@ get_type <- function(fmt) { twrap <- function(value, tag) { paste0("<", tag, ">", value, "") } + +.check_pkg_availability <- function(pkg, lib.loc = NULL) { + if (identical(find.package(pkg, quiet = TRUE, lib.loc = lib.loc), character(0))) { + stop("Suggested package `", pkg, "` is not available. Please install it individually or use `install_formats()`", call. = FALSE) + } + return(invisible(NULL)) +} diff --git a/tests/testthat/test_guess.R b/tests/testthat/test_guess.R index d8b1f45..0043a3e 100644 --- a/tests/testthat/test_guess.R +++ b/tests/testthat/test_guess.R @@ -24,3 +24,8 @@ test_that("Export without file specified", { expect_true(export(iris, format = "csv") %in% dir()) unlink("iris.csv") }) + +test_that(".check_pkg_availability", { + expect_error(.check_pkg_availability("nonexistingpkg1233222"), "Suggested package `nonexisting") + expect_error(.check_pkg_availability("rio"), NA) +}) From 22593762163496eaf6bd8b40280eea997c38e6db Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Wed, 30 Aug 2023 21:26:59 +0200 Subject: [PATCH 28/44] Unexport `is_file_text` [no ci] --- NAMESPACE | 1 - R/is_file_text.R | 52 ++++++++++++++++++++++----------------------- man/is_file_text.Rd | 37 -------------------------------- 3 files changed, 26 insertions(+), 64 deletions(-) delete mode 100644 man/is_file_text.Rd diff --git a/NAMESPACE b/NAMESPACE index c0bc1fa..7af7280 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -85,7 +85,6 @@ export(get_ext) export(import) export(import_list) export(install_formats) -export(is_file_text) export(spread_attrs) importFrom(curl,curl_fetch_memory) importFrom(curl,parse_headers) diff --git a/R/is_file_text.R b/R/is_file_text.R index 86f9897..1ac59cf 100644 --- a/R/is_file_text.R +++ b/R/is_file_text.R @@ -1,36 +1,36 @@ -#' @title Determine whether a file is \dQuote{plain-text} or some sort of binary format -#' -#' @param file Path to the file -#' @param maxsize Maximum number of bytes to read -#' @param text_bytes Which characters are used by normal text (though not -#' necessarily just ASCII). To detect just ASCII, the -#' following value can be used: -#' \code{as.raw(c(7:16, 18, 19, 32:127))} -#' -#' @return A logical -#' @export -#' @examples -#' library(datasets) -#' export(iris, yml_file <- tempfile(fileext = ".yml")) -#' is_file_text(yml_file) # TRUE -#' -#' export(iris, sav_file <- tempfile(fileext = ".sav")) -#' is_file_text(sav_file) # FALSE -#' -#' # cleanup -#' unlink(yml_file) -#' unlink(sav_file) -#' +## @title Determine whether a file is \dQuote{plain-text} or some sort of binary format +## +## @param file Path to the file +## @param maxsize Maximum number of bytes to read +## @param text_bytes Which characters are used by normal text (though not +## necessarily just ASCII). To detect just ASCII, the +## following value can be used: +## \code{as.raw(c(7:16, 18, 19, 32:127))} +## +## @return A logical +## @export +## @examples +## library(datasets) +## export(iris, yml_file <- tempfile(fileext = ".yml")) +## is_file_text(yml_file) # TRUE +## +## export(iris, sav_file <- tempfile(fileext = ".sav")) +## is_file_text(sav_file) # FALSE +## +## # cleanup +## unlink(yml_file) +## unlink(sav_file) +## is_file_text <- function( file, - maxsize = Inf, + maxsize = Inf, text_bytes = as.raw(c(0x7:0x10, 0x12, 0x13, 0x20:0xFF)) ) { - + ff <- file(file, "rb") bytes <- readBin( ff, - raw(), + raw(), n = min(file.info(file)$size, maxsize) ) close(ff) diff --git a/man/is_file_text.Rd b/man/is_file_text.Rd deleted file mode 100644 index e713f46..0000000 --- a/man/is_file_text.Rd +++ /dev/null @@ -1,37 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/is_file_text.R -\name{is_file_text} -\alias{is_file_text} -\title{Determine whether a file is \dQuote{plain-text} or some sort of binary format} -\usage{ -is_file_text(file, maxsize = Inf, text_bytes = as.raw(c(7:16, 18, 19, 32:255))) -} -\arguments{ -\item{file}{Path to the file} - -\item{maxsize}{Maximum number of bytes to read} - -\item{text_bytes}{Which characters are used by normal text (though not -necessarily just ASCII). To detect just ASCII, the -following value can be used: -\code{as.raw(c(7:16, 18, 19, 32:127))}} -} -\value{ -A logical -} -\description{ -Determine whether a file is \dQuote{plain-text} or some sort of binary format -} -\examples{ -library(datasets) -export(iris, yml_file <- tempfile(fileext = ".yml")) -is_file_text(yml_file) # TRUE - -export(iris, sav_file <- tempfile(fileext = ".sav")) -is_file_text(sav_file) # FALSE - -# cleanup -unlink(yml_file) -unlink(sav_file) - -} From b5099cdf836966208a2ca9441da4d589d83b534b Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Thu, 31 Aug 2023 02:01:01 +0200 Subject: [PATCH 29/44] Update NEWS.md [no ci] --- NEWS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index a7dd072..1d6a9a0 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,5 @@ * Stop loading the entire namespace of a suggested package when it is available #296 -* Unexport objects: `.import`, `.export`; remove documentation for `arg_reconcile` #321 +* Unexport objects: `.import`, `.export`, `is_file_text`; remove documentation for `arg_reconcile` #321 * Declutter - remove the obsolete data.table option #323 From 1108d499149dcf68be07baa8f5aaf9ad38f0f94c Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Thu, 31 Aug 2023 02:07:03 +0200 Subject: [PATCH 30/44] Update caution about HTML tables, fix #265 [no ci] --- R/import.R | 2 +- man/import.Rd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/R/import.R b/R/import.R index 3a6dd9c..14e1f64 100644 --- a/R/import.R +++ b/R/import.R @@ -42,7 +42,7 @@ #' \item Matlab (.mat), using \code{\link[rmatio]{read.mat}} #' \item EViews (.wf1), using \code{\link[hexView]{readEViews}} #' \item OpenDocument Spreadsheet (.ods), using \code{\link[readODS]{read_ods}}. Use \code{which} to specify a sheet number. -#' \item Single-table HTML documents (.html), using \code{\link[xml2]{read_html}}. The data structure will only be read correctly if the HTML file can be converted to a list via \code{\link[xml2]{as_list}}. +#' \item Single-table HTML documents (.html), using \code{\link[xml2]{read_html}}. There is no standard HTML table and we have only tested this with HTML tables exported with this package. HTML tables will only be read correctly if the HTML file can be converted to a list via \code{\link[xml2]{as_list}}. This import feature is not robust, especially for HTML tables in the wild. Please use a proper web scraping framework, e.g. \code{rvest}. #' \item Shallow XML documents (.xml), using \code{\link[xml2]{read_xml}}. The data structure will only be read correctly if the XML file can be converted to a list via \code{\link[xml2]{as_list}}. #' \item YAML (.yml), using \code{\link[yaml]{yaml.load}} #' \item Clipboard import, using \code{\link[utils]{read.table}} with \code{row.names = FALSE} diff --git a/man/import.Rd b/man/import.Rd index 29a16da..06c5cf8 100644 --- a/man/import.Rd +++ b/man/import.Rd @@ -59,7 +59,7 @@ This function imports a data frame or matrix from a data file with the file form \item Matlab (.mat), using \code{\link[rmatio]{read.mat}} \item EViews (.wf1), using \code{\link[hexView]{readEViews}} \item OpenDocument Spreadsheet (.ods), using \code{\link[readODS]{read_ods}}. Use \code{which} to specify a sheet number. - \item Single-table HTML documents (.html), using \code{\link[xml2]{read_html}}. The data structure will only be read correctly if the HTML file can be converted to a list via \code{\link[xml2]{as_list}}. + \item Single-table HTML documents (.html), using \code{\link[xml2]{read_html}}. There is no standard HTML table and we have only tested this with HTML tables exported with this package. HTML tables will only be read correctly if the HTML file can be converted to a list via \code{\link[xml2]{as_list}}. This import feature is not robust, especially for HTML tables in the wild. Please use a proper web scraping framework, e.g. \code{rvest}. \item Shallow XML documents (.xml), using \code{\link[xml2]{read_xml}}. The data structure will only be read correctly if the XML file can be converted to a list via \code{\link[xml2]{as_list}}. \item YAML (.yml), using \code{\link[yaml]{yaml.load}} \item Clipboard import, using \code{\link[utils]{read.table}} with \code{row.names = FALSE} From 8fd8ba734ac58286faca1c3672123bdb3a0d88eb Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Thu, 31 Aug 2023 02:18:11 +0200 Subject: [PATCH 31/44] Solve gp issue on 1: ref #319 --- R/import_methods.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/import_methods.R b/R/import_methods.R index 1fdf6c6..8e80748 100644 --- a/R/import_methods.R +++ b/R/import_methods.R @@ -374,7 +374,7 @@ function(file, .check_pkg_availability("xml2") x <- xml2::as_list(xml2::read_xml(unclass(file)))[[1L]] d <- do.call("rbind", c(lapply(x, unlist))) - row.names(d) <- 1:nrow(d) + row.names(d) <- seq_len(nrow(d)) d <- as.data.frame(d, stringsAsFactors = stringsAsFactors) tc2 <- function(x) { out <- utils::type.convert(x, as.is = FALSE) @@ -440,7 +440,7 @@ extract_html_row <- function(x, empty_value) { } out <- as.data.frame(out, ..., stringsAsFactors = stringsAsFactors) # set row names - rownames(out) <- 1:nrow(out) + rownames(out) <- seq_len(nrow(out)) # type.convert() to numeric, etc. out[] <- lapply(out, utils::type.convert, as.is = TRUE) out From da0a03df2de7490338e5bf77e23d5569a6ecede5 Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Thu, 31 Aug 2023 15:26:14 +0200 Subject: [PATCH 32/44] Rewrite all docs in Markdown fix #311 (#328) * Rewrite all docs in Markdown fix #311 Using `roxygen2md::roxygen2md()` * Update NEWS.md [no ci] --- DESCRIPTION | 1 + NEWS.md | 1 + R/characterize.R | 8 ++-- R/convert.R | 8 ++-- R/export.R | 72 +++++++++++++++++----------------- R/export_list.R | 10 ++--- R/gather_attrs.R | 8 ++-- R/import.R | 88 +++++++++++++++++++++--------------------- R/import_list.R | 16 ++++---- R/rio.R | 8 ++-- R/suggestions.R | 4 +- man/characterize.Rd | 2 +- man/convert.Rd | 6 +-- man/export.Rd | 64 +++++++++++++++--------------- man/export_list.Rd | 10 ++--- man/gather_attrs.Rd | 4 +- man/import.Rd | 82 +++++++++++++++++++-------------------- man/import_list.Rd | 12 +++--- man/install_formats.Rd | 2 +- man/rio.Rd | 6 +-- 20 files changed, 207 insertions(+), 205 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index f7b9906..518e354 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -72,3 +72,4 @@ License: GPL-2 VignetteBuilder: knitr Encoding: UTF-8 RoxygenNote: 7.2.3 +Roxygen: list(markdown = TRUE) diff --git a/NEWS.md b/NEWS.md index 1d6a9a0..ff6e0e7 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,6 +2,7 @@ * Unexport objects: `.import`, `.export`, `is_file_text`; remove documentation for `arg_reconcile` #321 * Declutter - remove the obsolete data.table option #323 + - write all documentation blocks in markdown #311 # rio 0.5.30 diff --git a/R/characterize.R b/R/characterize.R index 0561d8b..25d35a3 100644 --- a/R/characterize.R +++ b/R/characterize.R @@ -2,10 +2,10 @@ #' @title Character conversion of labelled data #' @description Convert labelled variables to character or factor #' @param x A vector or data frame. -#' @param coerce_character A logical indicating whether to additionally coerce character columns to factor (in \code{factorize}). Default \code{FALSE}. +#' @param coerce_character A logical indicating whether to additionally coerce character columns to factor (in `factorize`). Default `FALSE`. #' @param \dots additional arguments passed to methods -#' @details \code{characterize} converts a vector with a \code{labels} attribute of named levels into a character vector. \code{factorize} does the same but to factors. This can be useful at two stages of a data workflow: (1) importing labelled data from metadata-rich file formats (e.g., Stata or SPSS), and (2) exporting such data to plain text files (e.g., CSV) in a way that preserves information. -#' @return a character vector (for \code{characterize}) or factor vector (for \code{factorize}) +#' @details `characterize` converts a vector with a `labels` attribute of named levels into a character vector. `factorize` does the same but to factors. This can be useful at two stages of a data workflow: (1) importing labelled data from metadata-rich file formats (e.g., Stata or SPSS), and (2) exporting such data to plain text files (e.g., CSV) in a way that preserves information. +#' @return a character vector (for `characterize`) or factor vector (for `factorize`) #' @examples #' # vector method #' x <- structure(1:4, labels = c("A" = 1, "B" = 2, "C" = 3)) @@ -25,7 +25,7 @@ #' # cleanup #' unlink(csv_file) #' -#' @seealso \code{\link{gather_attrs}} +#' @seealso [gather_attrs()] #' @export characterize <- function(x, ...) { UseMethod("characterize") diff --git a/R/convert.R b/R/convert.R index d7d1e28..a20aab3 100644 --- a/R/convert.R +++ b/R/convert.R @@ -1,9 +1,9 @@ #' @title Convert from one file format to another -#' @description This function constructs a data frame from a data file using \code{\link{import}} and uses \code{\link{export}} to write the data to disk in the format indicated by the file extension. +#' @description This function constructs a data frame from a data file using [import()] and uses [export()] to write the data to disk in the format indicated by the file extension. #' @param in_file A character string naming an input file. #' @param out_file A character string naming an output file. -#' @param in_opts A named list of options to be passed to \code{\link{import}}. -#' @param out_opts A named list of options to be passed to \code{\link{export}}. +#' @param in_opts A named list of options to be passed to [import()]. +#' @param out_opts A named list of options to be passed to [export()]. #' @return A character string containing the name of the output file (invisibly). #' @examples #' # create a file to convert @@ -33,7 +33,7 @@ #' ## Rscript -e "rio::convert('mtcars.dta', 'mtcars.csv')" #' }} #' -#' @seealso \href{https://lbraglia.github.io/}{Luca Braglia} has created a Shiny app called \href{https://github.com/lbraglia/rioweb}{rioweb} that provides access to the file conversion features of rio through a web browser. +#' @seealso [Luca Braglia](https://lbraglia.github.io/) has created a Shiny app called [rioweb](https://github.com/lbraglia/rioweb) that provides access to the file conversion features of rio through a web browser. #' @export convert <- function(in_file, out_file, in_opts=list(), out_opts=list()) { if (missing(out_file)) { diff --git a/R/export.R b/R/export.R index 8c1e4b2..d40c169 100644 --- a/R/export.R +++ b/R/export.R @@ -1,50 +1,50 @@ #' @rdname export #' @title Export #' @description Write data.frame to a file -#' @param x A data frame or matrix to be written into a file. Exceptions to this rule are that \code{x} can be a list of data frames if the output file format is an Excel .xlsx workbook, .Rdata file, or HTML file, or a variety of R objects if the output file format is RDS or JSON. See examples.) To export a list of data frames to multiple files, use \code{\link{export_list}} instead. -#' @param file A character string naming a file. Must specify \code{file} and/or \code{format}. -#' @param format An optional character string containing the file format, which can be used to override the format inferred from \code{file} or, in lieu of specifying \code{file}, a file with the symbol name of \code{x} and the specified file extension will be created. Must specify \code{file} and/or \code{format}. Shortcuts include: \dQuote{,} (for comma-separated values), \dQuote{;} (for semicolon-separated values), \dQuote{|} (for pipe-separated values), and \dQuote{dump} for \code{\link[base]{dump}}. +#' @param x A data frame or matrix to be written into a file. Exceptions to this rule are that `x` can be a list of data frames if the output file format is an Excel .xlsx workbook, .Rdata file, or HTML file, or a variety of R objects if the output file format is RDS or JSON. See examples.) To export a list of data frames to multiple files, use [export_list()] instead. +#' @param file A character string naming a file. Must specify `file` and/or `format`. +#' @param format An optional character string containing the file format, which can be used to override the format inferred from `file` or, in lieu of specifying `file`, a file with the symbol name of `x` and the specified file extension will be created. Must specify `file` and/or `format`. Shortcuts include: \dQuote{,} (for comma-separated values), \dQuote{;} (for semicolon-separated values), \dQuote{|} (for pipe-separated values), and \dQuote{dump} for [base::dump()]. #' @param \dots Additional arguments for the underlying export functions. This can be used to specify non-standard arguments. See examples. #' @return The name of the output file as a character string (invisibly). -#' @details This function exports a data frame or matrix into a file with file format based on the file extension (or the manually specified format, if \code{format} is specified). +#' @details This function exports a data frame or matrix into a file with file format based on the file extension (or the manually specified format, if `format` is specified). #' -#' The output file can be to a compressed directory, simply by adding an appropriate additional extensiont to the \code{file} argument, such as: \dQuote{mtcars.csv.tar}, \dQuote{mtcars.csv.zip}, or \dQuote{mtcars.csv.gz}. +#' The output file can be to a compressed directory, simply by adding an appropriate additional extensiont to the `file` argument, such as: \dQuote{mtcars.csv.tar}, \dQuote{mtcars.csv.zip}, or \dQuote{mtcars.csv.gz}. #' -#' \code{export} supports many file formats. See the documentation for the underlying export functions for optional arguments that can be passed via \code{...} +#' `export` supports many file formats. See the documentation for the underlying export functions for optional arguments that can be passed via `...` #' #' \itemize{ -#' \item Comma-separated data (.csv), using \code{\link[data.table]{fwrite}} or, if \code{fwrite = TRUE}, \code{\link[utils]{write.table}} with \code{row.names = FALSE}. -#' \item Pipe-separated data (.psv), using \code{\link[data.table]{fwrite}} or, if \code{fwrite = TRUE}, \code{\link[utils]{write.table}} with \code{sep = '|'} and \code{row.names = FALSE}. -#' \item Tab-separated data (.tsv), using \code{\link[data.table]{fwrite}} or, if \code{fwrite = TRUE}, \code{\link[utils]{write.table}} with \code{row.names = FALSE}. -#' \item SAS (.sas7bdat), using \code{\link[haven]{write_sas}}. -#' \item SAS XPORT (.xpt), using \code{\link[haven]{write_xpt}}. -#' \item SPSS (.sav), using \code{\link[haven]{write_sav}} -#' \item SPSS compressed (.zsav), using \code{\link[haven]{write_sav}} -#' \item Stata (.dta), using \code{\link[haven]{write_dta}}. Note that variable/column names containing dots (.) are not allowed and will produce an error. -#' \item Excel (.xlsx), using \code{\link[openxlsx]{write.xlsx}}. Existing workbooks are overwritten unless \code{which} is specified, in which case only the specified sheet (if it exists) is overwritten. If the file exists but the \code{which} sheet does not, data are added as a new sheet to the existing workbook. \code{x} can also be a list of data frames; the list entry names are used as sheet names. -#' \item R syntax object (.R), using \code{\link[base]{dput}} (by default) or \code{\link[base]{dump}} (if \code{format = 'dump'}) -#' \item Saved R objects (.RData,.rda), using \code{\link[base]{save}}. In this case, \code{x} can be a data frame, a named list of objects, an R environment, or a character vector containing the names of objects if a corresponding \code{envir} argument is specified. -#' \item Serialized R objects (.rds), using \code{\link[base]{saveRDS}}. In this case, \code{x} can be any serializable R object. -#' \item "XBASE" database files (.dbf), using \code{\link[foreign]{write.dbf}} -#' \item Weka Attribute-Relation File Format (.arff), using \code{\link[foreign]{write.arff}} -#' \item Fixed-width format data (.fwf), using \code{\link[utils]{write.table}} with \code{row.names = FALSE}, \code{quote = FALSE}, and \code{col.names = FALSE} -#' \item gzip comma-separated data (.csv.gz), using \code{\link[utils]{write.table}} with \code{row.names = FALSE} -#' \item \href{https://github.com/csvy}{CSVY} (CSV with a YAML metadata header) using \code{\link[data.table]{fwrite}}. -#' \item Apache Arrow Parquet (.parquet), using \code{\link[arrow]{write_parquet}} -#' \item Feather R/Python interchange format (.feather), using \code{\link[feather]{write_feather}} -#' \item Fast storage (.fst), using \code{\link[fst]{write.fst}} -#' \item JSON (.json), using \code{\link[jsonlite]{toJSON}}. In this case, \code{x} can be a variety of R objects, based on class mapping conventions in this paper: \href{https://arxiv.org/abs/1403.2805}{https://arxiv.org/abs/1403.2805}. -#' \item Matlab (.mat), using \code{\link[rmatio]{write.mat}} -#' \item OpenDocument Spreadsheet (.ods), using \code{\link[readODS]{write_ods}}. (Currently only single-sheet exports are supported.) -#' \item HTML (.html), using a custom method based on \code{\link[xml2]{xml_add_child}} to create a simple HTML table and \code{\link[xml2]{write_xml}} to write to disk. -#' \item XML (.xml), using a custom method based on \code{\link[xml2]{xml_add_child}} to create a simple XML tree and \code{\link[xml2]{write_xml}} to write to disk. -#' \item YAML (.yml), using \code{\link[yaml]{as.yaml}} -#' \item Clipboard export (on Windows and Mac OS), using \code{\link[utils]{write.table}} with \code{row.names = FALSE} +#' \item Comma-separated data (.csv), using [data.table::fwrite()] or, if `fwrite = TRUE`, [utils::write.table()] with `row.names = FALSE`. +#' \item Pipe-separated data (.psv), using [data.table::fwrite()] or, if `fwrite = TRUE`, [utils::write.table()] with `sep = '|'` and `row.names = FALSE`. +#' \item Tab-separated data (.tsv), using [data.table::fwrite()] or, if `fwrite = TRUE`, [utils::write.table()] with `row.names = FALSE`. +#' \item SAS (.sas7bdat), using [haven::write_sas()]. +#' \item SAS XPORT (.xpt), using [haven::write_xpt()]. +#' \item SPSS (.sav), using [haven::write_sav()] +#' \item SPSS compressed (.zsav), using [haven::write_sav()] +#' \item Stata (.dta), using [haven::write_dta()]. Note that variable/column names containing dots (.) are not allowed and will produce an error. +#' \item Excel (.xlsx), using [openxlsx::write.xlsx()]. Existing workbooks are overwritten unless `which` is specified, in which case only the specified sheet (if it exists) is overwritten. If the file exists but the `which` sheet does not, data are added as a new sheet to the existing workbook. `x` can also be a list of data frames; the list entry names are used as sheet names. +#' \item R syntax object (.R), using [base::dput()] (by default) or [base::dump()] (if `format = 'dump'`) +#' \item Saved R objects (.RData,.rda), using [base::save()]. In this case, `x` can be a data frame, a named list of objects, an R environment, or a character vector containing the names of objects if a corresponding `envir` argument is specified. +#' \item Serialized R objects (.rds), using [base::saveRDS()]. In this case, `x` can be any serializable R object. +#' \item "XBASE" database files (.dbf), using [foreign::write.dbf()] +#' \item Weka Attribute-Relation File Format (.arff), using [foreign::write.arff()] +#' \item Fixed-width format data (.fwf), using [utils::write.table()] with `row.names = FALSE`, `quote = FALSE`, and `col.names = FALSE` +#' \item gzip comma-separated data (.csv.gz), using [utils::write.table()] with `row.names = FALSE` +#' \item [CSVY](https://github.com/csvy) (CSV with a YAML metadata header) using [data.table::fwrite()]. +#' \item Apache Arrow Parquet (.parquet), using [arrow::write_parquet()] +#' \item Feather R/Python interchange format (.feather), using [feather::write_feather()] +#' \item Fast storage (.fst), using [fst::write.fst()] +#' \item JSON (.json), using [jsonlite::toJSON()]. In this case, `x` can be a variety of R objects, based on class mapping conventions in this paper: [https://arxiv.org/abs/1403.2805](https://arxiv.org/abs/1403.2805). +#' \item Matlab (.mat), using [rmatio::write.mat()] +#' \item OpenDocument Spreadsheet (.ods), using [readODS::write_ods()]. (Currently only single-sheet exports are supported.) +#' \item HTML (.html), using a custom method based on [xml2::xml_add_child()] to create a simple HTML table and [xml2::write_xml()] to write to disk. +#' \item XML (.xml), using a custom method based on [xml2::xml_add_child()] to create a simple XML tree and [xml2::write_xml()] to write to disk. +#' \item YAML (.yml), using [yaml::as.yaml()] +#' \item Clipboard export (on Windows and Mac OS), using [utils::write.table()] with `row.names = FALSE` #' } #' -#' When exporting a data set that contains label attributes (e.g., if imported from an SPSS or Stata file) to a plain text file, \code{\link{characterize}} can be a useful pre-processing step that records value labels into the resulting file (e.g., \code{export(characterize(x), "file.csv")}) rather than the numeric values. +#' When exporting a data set that contains label attributes (e.g., if imported from an SPSS or Stata file) to a plain text file, [characterize()] can be a useful pre-processing step that records value labels into the resulting file (e.g., `export(characterize(x), "file.csv")`) rather than the numeric values. #' -#' Use \code{\link{export_list}} to export a list of dataframes to separate files. +#' Use [export_list()] to export a list of dataframes to separate files. #' #' @examples #' library("datasets") @@ -116,7 +116,7 @@ #' # unlink(f11) #' # unlink(f12) #' # unlink(f13) -#' @seealso \code{\link{characterize}}, \code{\link{import}}, \code{\link{convert}}, \code{\link{export_list}} +#' @seealso [characterize()], [import()], [convert()], [export_list()] #' @importFrom haven labelled #' @export export <- function(x, file, format, ...) { diff --git a/R/export_list.R b/R/export_list.R index 2b1e50e..c6cf22e 100644 --- a/R/export_list.R +++ b/R/export_list.R @@ -1,10 +1,10 @@ #' @title Export list of data frames to files -#' @description Use \code{\link{export}} to export a list of data frames to a vector of file names or a filename pattern. +#' @description Use [export()] to export a list of data frames to a vector of file names or a filename pattern. #' @param x A list of data frames to be written to files. -#' @param file A character vector string containing a single file name with a \code{\%s} wildcard placeholder, or a vector of file paths for multiple files to be imported. If \code{x} elements are named, these will be used in place of \code{\%s}, otherwise numbers will be used; all elements must be named for names to be used. -#' @param \dots Additional arguments passed to \code{\link{export}}. +#' @param file A character vector string containing a single file name with a `\%s` wildcard placeholder, or a vector of file paths for multiple files to be imported. If `x` elements are named, these will be used in place of `\%s`, otherwise numbers will be used; all elements must be named for names to be used. +#' @param \dots Additional arguments passed to [export()]. #' @return The name(s) of the output file(s) as a character vector (invisibly). -#' @details \code{\link{export}} can export a list of data frames to a single multi-dataset file (e.g., an Rdata or Excel .xlsx file). Use \code{export_list} to export such a list to \emph{multiple} files. +#' @details [export()] can export a list of data frames to a single multi-dataset file (e.g., an Rdata or Excel .xlsx file). Use `export_list` to export such a list to *multiple* files. #' @examples #' library('datasets') #' export(list(mtcars1 = mtcars[1:10,], @@ -28,7 +28,7 @@ #' unlink(csv_files1) #' unlink(csv_files2) #' -#' @seealso \code{\link{import}}, \code{\link{import_list}}, \code{\link{export}} +#' @seealso [import()], [import_list()], [export()] #' @export export_list <- function( diff --git a/R/gather_attrs.R b/R/gather_attrs.R index b4922a0..53e7c06 100644 --- a/R/gather_attrs.R +++ b/R/gather_attrs.R @@ -1,9 +1,9 @@ #' @rdname gather_attrs #' @title Gather attributes from data frame variables -#' @description \code{gather_attrs} moves variable-level attributes to the data frame level and \code{spread_attrs} reverses that operation. -#' @details \code{\link{import}} attempts to standardize the return value from the various import functions to the extent possible, thus providing a uniform data structure regardless of what import package or function is used. It achieves this by storing any optional variable-related attributes at the variable level (i.e., an attribute for \code{mtcars$mpg} is stored in \code{attributes(mtcars$mpg)} rather than \code{attributes(mtcars)}). \code{gather_attrs} moves these to the data frame level (i.e., in \code{attributes(mtcars)}). \code{spread_attrs} moves attributes back to the variable level. +#' @description `gather_attrs` moves variable-level attributes to the data frame level and `spread_attrs` reverses that operation. +#' @details [import()] attempts to standardize the return value from the various import functions to the extent possible, thus providing a uniform data structure regardless of what import package or function is used. It achieves this by storing any optional variable-related attributes at the variable level (i.e., an attribute for `mtcars$mpg` is stored in `attributes(mtcars$mpg)` rather than `attributes(mtcars)`). `gather_attrs` moves these to the data frame level (i.e., in `attributes(mtcars)`). `spread_attrs` moves attributes back to the variable level. #' @param x A data frame. -#' @return \code{x}, with variable-level attributes stored at the data frame level. +#' @return `x`, with variable-level attributes stored at the data frame level. #' @examples #' e <- try(import("http://www.stata-press.com/data/r13/auto.dta")) #' if (!inherits(e, "try-error")) { @@ -12,7 +12,7 @@ #' str(attributes(e)) #' str(g) #' } -#' @seealso \code{\link{import}}, \code{\link{characterize}} +#' @seealso [import()], [characterize()] #' @importFrom stats setNames #' @export gather_attrs <- function(x) { diff --git a/R/import.R b/R/import.R index 14e1f64..e3c01c5 100644 --- a/R/import.R +++ b/R/import.R @@ -2,59 +2,59 @@ #' @title Import #' @description Read in a data.frame from a file. Exceptions to this rule are Rdata, RDS, and JSON input file formats, which return the originally saved object without changing its class. #' @param file A character string naming a file, URL, or single-file .zip or .tar archive. -#' @param format An optional character string code of file format, which can be used to override the format inferred from \code{file}. Shortcuts include: \dQuote{,} (for comma-separated values), \dQuote{;} (for semicolon-separated values), and \dQuote{|} (for pipe-separated values). +#' @param format An optional character string code of file format, which can be used to override the format inferred from `file`. Shortcuts include: \dQuote{,} (for comma-separated values), \dQuote{;} (for semicolon-separated values), and \dQuote{|} (for pipe-separated values). #' @param setclass An optional character vector specifying one or more classes to set on the import. By default, the return object is always a \dQuote{data.frame}. Allowed values include \dQuote{tbl_df}, \dQuote{tbl}, or \dQuote{tibble} (if using dplyr) or \dQuote{data.table} (if using data.table). Other values are ignored, such that a data.frame is returned. -#' @param which This argument is used to control import from multi-object files; as a rule \code{import} only ever returns a single data frame (use \code{\link{import_list}} to import multiple data frames from a multi-object file). If \code{file} is a compressed directory, \code{which} can be either a character string specifying a filename or an integer specifying which file (in locale sort order) to extract from the compressed directory. For Excel spreadsheets, this can be used to specify a sheet name or number. For .Rdata files, this can be an object name. For HTML files, it identifies which table to extract (from document order). Ignored otherwise. A character string value will be used as a regular expression, such that the extracted file is the first match of the regular expression against the file names in the archive. +#' @param which This argument is used to control import from multi-object files; as a rule `import` only ever returns a single data frame (use [import_list()] to import multiple data frames from a multi-object file). If `file` is a compressed directory, `which` can be either a character string specifying a filename or an integer specifying which file (in locale sort order) to extract from the compressed directory. For Excel spreadsheets, this can be used to specify a sheet name or number. For .Rdata files, this can be an object name. For HTML files, it identifies which table to extract (from document order). Ignored otherwise. A character string value will be used as a regular expression, such that the extracted file is the first match of the regular expression against the file names in the archive. #' @param \dots Additional arguments passed to the underlying import functions. For example, this can control column classes for delimited file types, or control the use of haven for Stata and SPSS or readxl for Excel (.xlsx) format. See details below. -#' @return A data frame. If \code{setclass} is used, this data frame may have additional class attribute values, such as \dQuote{tibble} or \dQuote{data.table}. -#' @details This function imports a data frame or matrix from a data file with the file format based on the file extension (or the manually specified format, if \code{format} is specified). +#' @return A data frame. If `setclass` is used, this data frame may have additional class attribute values, such as \dQuote{tibble} or \dQuote{data.table}. +#' @details This function imports a data frame or matrix from a data file with the file format based on the file extension (or the manually specified format, if `format` is specified). #' -#' \code{import} supports the following file formats: +#' `import` supports the following file formats: #' #' \itemize{ -#' \item Comma-separated data (.csv), using \code{\link[data.table]{fread}} or, if \code{fread = FALSE}, \code{\link[utils]{read.table}} with \code{row.names = FALSE} and \code{stringsAsFactors = FALSE} -#' \item Pipe-separated data (.psv), using \code{\link[data.table]{fread}} or, if \code{fread = FALSE}, \code{\link[utils]{read.table}} with \code{sep = '|'}, \code{row.names = FALSE} and \code{stringsAsFactors = FALSE} -#' \item Tab-separated data (.tsv), using \code{\link[data.table]{fread}} or, if \code{fread = FALSE}, \code{\link[utils]{read.table}} with \code{row.names = FALSE} and \code{stringsAsFactors = FALSE} -#' \item SAS (.sas7bdat), using \code{\link[haven]{read_sas}}. -#' \item SAS XPORT (.xpt), using \code{\link[haven]{read_xpt}} or, if \code{haven = FALSE}, \code{\link[foreign]{read.xport}}. -#' \item SPSS (.sav), using \code{\link[haven]{read_sav}}. If \code{haven = FALSE}, \code{\link[foreign]{read.spss}} can be used. -#' \item SPSS compressed (.zsav), using \code{\link[haven]{read_sav}}. -#' \item Stata (.dta), using \code{\link[haven]{read_dta}}. If \code{haven = FALSE}, \code{\link[foreign]{read.dta}} can be used. -#' \item SPSS Portable Files (.por), using \code{\link[haven]{read_por}}. -#' \item Excel (.xls and .xlsx), using \code{\link[readxl]{read_excel}}. Use \code{which} to specify a sheet number. For .xlsx files, it is possible to set \code{readxl = FALSE}, so that \code{\link[openxlsx]{read.xlsx}} can be used instead of readxl (the default). -#' \item R syntax object (.R), using \code{\link[base]{dget}} -#' \item Saved R objects (.RData,.rda), using \code{\link[base]{load}} for single-object .Rdata files. Use \code{which} to specify an object name for multi-object .Rdata files. This can be any R object (not just a data frame). -#' \item Serialized R objects (.rds), using \code{\link[base]{readRDS}}. This can be any R object (not just a data frame). -#' \item Epiinfo (.rec), using \code{\link[foreign]{read.epiinfo}} -#' \item Minitab (.mtp), using \code{\link[foreign]{read.mtp}} -#' \item Systat (.syd), using \code{\link[foreign]{read.systat}} -#' \item "XBASE" database files (.dbf), using \code{\link[foreign]{read.dbf}} -#' \item Weka Attribute-Relation File Format (.arff), using \code{\link[foreign]{read.arff}} -#' \item Data Interchange Format (.dif), using \code{\link[utils]{read.DIF}} -#' \item Fortran data (no recognized extension), using \code{\link[utils]{read.fortran}} -#' \item Fixed-width format data (.fwf), using a faster version of \code{\link[utils]{read.fwf}} that requires a \code{widths} argument and by default in rio has \code{stringsAsFactors = FALSE}. If \code{readr = TRUE}, import will be performed using \code{\link[readr]{read_fwf}}, where \code{widths} should be: \code{NULL}, a vector of column widths, or the output of \code{\link[readr]{fwf_empty}}, \code{\link[readr]{fwf_widths}}, or \code{\link[readr]{fwf_positions}}. -#' \item gzip comma-separated data (.csv.gz), using \code{\link[utils]{read.table}} with \code{row.names = FALSE} and \code{stringsAsFactors = FALSE} -#' \item \href{https://github.com/csvy}{CSVY} (CSV with a YAML metadata header) using \code{\link[data.table]{fread}}. -#' \item Apache Arrow Parquet (.parquet), using \code{\link[arrow]{read_parquet}} -#' \item Feather R/Python interchange format (.feather), using \code{\link[feather]{read_feather}} -#' \item Fast storage (.fst), using \code{\link[fst]{read.fst}} -#' \item JSON (.json), using \code{\link[jsonlite]{fromJSON}} -#' \item Matlab (.mat), using \code{\link[rmatio]{read.mat}} -#' \item EViews (.wf1), using \code{\link[hexView]{readEViews}} -#' \item OpenDocument Spreadsheet (.ods), using \code{\link[readODS]{read_ods}}. Use \code{which} to specify a sheet number. -#' \item Single-table HTML documents (.html), using \code{\link[xml2]{read_html}}. There is no standard HTML table and we have only tested this with HTML tables exported with this package. HTML tables will only be read correctly if the HTML file can be converted to a list via \code{\link[xml2]{as_list}}. This import feature is not robust, especially for HTML tables in the wild. Please use a proper web scraping framework, e.g. \code{rvest}. -#' \item Shallow XML documents (.xml), using \code{\link[xml2]{read_xml}}. The data structure will only be read correctly if the XML file can be converted to a list via \code{\link[xml2]{as_list}}. -#' \item YAML (.yml), using \code{\link[yaml]{yaml.load}} -#' \item Clipboard import, using \code{\link[utils]{read.table}} with \code{row.names = FALSE} +#' \item Comma-separated data (.csv), using [data.table::fread()] or, if `fread = FALSE`, [utils::read.table()] with `row.names = FALSE` and `stringsAsFactors = FALSE` +#' \item Pipe-separated data (.psv), using [data.table::fread()] or, if `fread = FALSE`, [utils::read.table()] with `sep = '|'`, `row.names = FALSE` and `stringsAsFactors = FALSE` +#' \item Tab-separated data (.tsv), using [data.table::fread()] or, if `fread = FALSE`, [utils::read.table()] with `row.names = FALSE` and `stringsAsFactors = FALSE` +#' \item SAS (.sas7bdat), using [haven::read_sas()]. +#' \item SAS XPORT (.xpt), using [haven::read_xpt()] or, if `haven = FALSE`, [foreign::read.xport()]. +#' \item SPSS (.sav), using [haven::read_sav()]. If `haven = FALSE`, [foreign::read.spss()] can be used. +#' \item SPSS compressed (.zsav), using [haven::read_sav()]. +#' \item Stata (.dta), using [haven::read_dta()]. If `haven = FALSE`, [foreign::read.dta()] can be used. +#' \item SPSS Portable Files (.por), using [haven::read_por()]. +#' \item Excel (.xls and .xlsx), using [readxl::read_excel()]. Use `which` to specify a sheet number. For .xlsx files, it is possible to set `readxl = FALSE`, so that [openxlsx::read.xlsx()] can be used instead of readxl (the default). +#' \item R syntax object (.R), using [base::dget()] +#' \item Saved R objects (.RData,.rda), using [base::load()] for single-object .Rdata files. Use `which` to specify an object name for multi-object .Rdata files. This can be any R object (not just a data frame). +#' \item Serialized R objects (.rds), using [base::readRDS()]. This can be any R object (not just a data frame). +#' \item Epiinfo (.rec), using [foreign::read.epiinfo()] +#' \item Minitab (.mtp), using [foreign::read.mtp()] +#' \item Systat (.syd), using [foreign::read.systat()] +#' \item "XBASE" database files (.dbf), using [foreign::read.dbf()] +#' \item Weka Attribute-Relation File Format (.arff), using [foreign::read.arff()] +#' \item Data Interchange Format (.dif), using [utils::read.DIF()] +#' \item Fortran data (no recognized extension), using [utils::read.fortran()] +#' \item Fixed-width format data (.fwf), using a faster version of [utils::read.fwf()] that requires a `widths` argument and by default in rio has `stringsAsFactors = FALSE`. If `readr = TRUE`, import will be performed using [readr::read_fwf()], where `widths` should be: `NULL`, a vector of column widths, or the output of [readr::fwf_empty()], [readr::fwf_widths()], or [readr::fwf_positions()]. +#' \item gzip comma-separated data (.csv.gz), using [utils::read.table()] with `row.names = FALSE` and `stringsAsFactors = FALSE` +#' \item [CSVY](https://github.com/csvy) (CSV with a YAML metadata header) using [data.table::fread()]. +#' \item Apache Arrow Parquet (.parquet), using [arrow::read_parquet()] +#' \item Feather R/Python interchange format (.feather), using [feather::read_feather()] +#' \item Fast storage (.fst), using [fst::read.fst()] +#' \item JSON (.json), using [jsonlite::fromJSON()] +#' \item Matlab (.mat), using [rmatio::read.mat()] +#' \item EViews (.wf1), using [hexView::readEViews()] +#' \item OpenDocument Spreadsheet (.ods), using [readODS::read_ods()]. Use `which` to specify a sheet number. +#' \item Single-table HTML documents (.html), using [xml2::read_html()]. There is no standard HTML table and we have only tested this with HTML tables exported with this package. HTML tables will only be read correctly if the HTML file can be converted to a list via [xml2::as_list()]. This import feature is not robust, especially for HTML tables in the wild. Please use a proper web scraping framework, e.g. `rvest`. +#' \item Shallow XML documents (.xml), using [xml2::read_xml()]. The data structure will only be read correctly if the XML file can be converted to a list via [xml2::as_list()]. +#' \item YAML (.yml), using [yaml::yaml.load()] +#' \item Clipboard import, using [utils::read.table()] with `row.names = FALSE` #' \item Google Sheets, as Comma-separated data (.csv) -#' \item GraphPad Prism (.pzfx) using \code{\link[pzfx]{read_pzfx}} +#' \item GraphPad Prism (.pzfx) using [pzfx::read_pzfx()] #' } #' -#' \code{import} attempts to standardize the return value from the various import functions to the extent possible, thus providing a uniform data structure regardless of what import package or function is used. It achieves this by storing any optional variable-related attributes at the variable level (i.e., an attribute for \code{mtcars$mpg} is stored in \code{attributes(mtcars$mpg)} rather than \code{attributes(mtcars)}). If you would prefer these attributes to be stored at the data.frame-level (i.e., in \code{attributes(mtcars)}), see \code{\link{gather_attrs}}. +#' `import` attempts to standardize the return value from the various import functions to the extent possible, thus providing a uniform data structure regardless of what import package or function is used. It achieves this by storing any optional variable-related attributes at the variable level (i.e., an attribute for `mtcars$mpg` is stored in `attributes(mtcars$mpg)` rather than `attributes(mtcars)`). If you would prefer these attributes to be stored at the data.frame-level (i.e., in `attributes(mtcars)`), see [gather_attrs()]. #' -#' After importing metadata-rich file formats (e.g., from Stata or SPSS), it may be helpful to recode labelled variables to character or factor using \code{\link{characterize}} or \code{\link{factorize}} respectively. +#' After importing metadata-rich file formats (e.g., from Stata or SPSS), it may be helpful to recode labelled variables to character or factor using [characterize()] or [factorize()] respectively. #' -#' @note For csv and txt files with row names exported from \code{\link{export}}, it may be helpful to specify \code{row.names} as the column of the table which contain row names. See example below. +#' @note For csv and txt files with row names exported from [export()], it may be helpful to specify `row.names` as the column of the table which contain row names. See example below. #' @examples #' # create CSV to import #' export(iris, csv_file <- tempfile(fileext = ".csv")) @@ -88,7 +88,7 @@ #' unlink(tsv_file) #' unlink(rds_file) #' -#' @seealso \code{\link{import_list}}, \code{\link{characterize}}, \code{\link{gather_attrs}}, \code{\link{export}}, \code{\link{convert}} +#' @seealso [import_list()], [characterize()], [gather_attrs()], [export()], [convert()] #' @importFrom tools file_ext file_path_sans_ext #' @importFrom stats na.omit setNames #' @importFrom utils installed.packages untar unzip tar zip type.convert capture.output diff --git a/R/import_list.R b/R/import_list.R index ae37f0c..277c2ea 100644 --- a/R/import_list.R +++ b/R/import_list.R @@ -1,13 +1,13 @@ #' @title Import list of data frames -#' @description Use \code{\link{import}} to import a list of data frames from a vector of file names or from a multi-object file (Excel workbook, .Rdata file, zip directory, or HTML file) +#' @description Use [import()] to import a list of data frames from a vector of file names or from a multi-object file (Excel workbook, .Rdata file, zip directory, or HTML file) #' @param file A character string containing a single file name for a multi-object file (e.g., Excel workbook, zip directory, or HTML file), or a vector of file paths for multiple files to be imported. -#' @param which If \code{file} is a single file path, this specifies which objects should be extracted (passed to \code{\link{import}}'s \code{which} argument). Ignored otherwise. -#' @param rbind A logical indicating whether to pass the import list of data frames through \code{\link[data.table]{rbindlist}}. -#' @param rbind_label If \code{rbind = TRUE}, a character string specifying the name of a column to add to the data frame indicating its source file. -#' @param rbind_fill If \code{rbind = TRUE}, a logical indicating whether to set the \code{fill = TRUE} (and fill missing columns with \code{NA}). -#' @param \dots Additional arguments passed to \code{\link{import}}. Behavior may be unexpected if files are of different formats. +#' @param which If `file` is a single file path, this specifies which objects should be extracted (passed to [import()]'s `which` argument). Ignored otherwise. +#' @param rbind A logical indicating whether to pass the import list of data frames through [data.table::rbindlist()]. +#' @param rbind_label If `rbind = TRUE`, a character string specifying the name of a column to add to the data frame indicating its source file. +#' @param rbind_fill If `rbind = TRUE`, a logical indicating whether to set the `fill = TRUE` (and fill missing columns with `NA`). +#' @param \dots Additional arguments passed to [import()]. Behavior may be unexpected if files are of different formats. #' @inheritParams import -#' @return If \code{rbind=FALSE} (the default), a list of a data frames. Otherwise, that list is passed to \code{\link[data.table]{rbindlist}} with \code{fill = TRUE} and returns a data frame object of class set by the \code{setclass} argument; if this operation fails, the list is returned. +#' @return If `rbind=FALSE` (the default), a list of a data frames. Otherwise, that list is passed to [data.table::rbindlist()] with `fill = TRUE` and returns a data frame object of class set by the `setclass` argument; if this operation fails, the list is returned. #' @examples #' library('datasets') #' export(list(mtcars1 = mtcars[1:10,], @@ -38,7 +38,7 @@ #' # cleanup #' unlink(xlsx_file) #' -#' @seealso \code{\link{import}}, \code{\link{export_list}}, \code{\link{export}} +#' @seealso [import()], [export_list()], [export()] #' @export import_list <- function(file, diff --git a/R/rio.R b/R/rio.R index 4321f73..7897c03 100644 --- a/R/rio.R +++ b/R/rio.R @@ -1,9 +1,9 @@ #' @docType package #' @name rio #' @title A Swiss-Army Knife for Data I/O -#' @description The aim of rio is to make data file input and output as easy as possible. \code{\link{export}} and \code{\link{import}} serve as a Swiss-army knife for painless data I/O for data from almost any file format by inferring the data structure from the file extension, natively reading web-based data sources, setting reasonable defaults for import and export, and relying on efficient data import and export packages. An additional convenience function, \code{\link{convert}}, provides a simple method for converting between file types. +#' @description The aim of rio is to make data file input and output as easy as possible. [export()] and [import()] serve as a Swiss-army knife for painless data I/O for data from almost any file format by inferring the data structure from the file extension, natively reading web-based data sources, setting reasonable defaults for import and export, and relying on efficient data import and export packages. An additional convenience function, [convert()], provides a simple method for converting between file types. #' -#' Note that some of rio's functionality is provided by \sQuote{Suggests} dependendencies, meaning they are not installed by default. Use \code{\link{install_formats}} to make sure these packages are available for use. +#' Note that some of rio's functionality is provided by \sQuote{Suggests} dependendencies, meaning they are not installed by default. Use [install_formats()] to make sure these packages are available for use. #' #' @examples #' # export @@ -24,7 +24,7 @@ #' unlink(c(csv_file, rds_file, sav_file, dta_file)) #' #' @references -#' \href{https://github.com/Stan125/GREA}{GREA} provides an RStudio add-in to import data using rio. -#' @seealso \code{\link{import}}, \code{\link{import_list}}, \code{\link{export}}, \code{\link{export_list}}, \code{\link{convert}}, \code{\link{install_formats}} +#' [GREA](https://github.com/Stan125/GREA) provides an RStudio add-in to import data using rio. +#' @seealso [import()], [import_list()], [export()], [export_list()], [convert()], [install_formats()] "_PACKAGE" diff --git a/R/suggestions.R b/R/suggestions.R index dbc72c5..952860d 100644 --- a/R/suggestions.R +++ b/R/suggestions.R @@ -1,7 +1,7 @@ #' @title Install rio's \sQuote{Suggests} Dependencies #' @description This function installs various \sQuote{Suggests} dependencies for rio that expand its support to the full range of support import and export formats. These packages are not installed or loaded by default in order to create a slimmer and faster package build, install, and load. -#' @param \dots Additional arguments passed to \code{\link[utils]{install.packages}}. -#' @return \code{NULL} +#' @param \dots Additional arguments passed to [utils::install.packages()]. +#' @return `NULL` #' @importFrom utils install.packages #' @examples #' \donttest{ diff --git a/man/characterize.Rd b/man/characterize.Rd index dda61cb..cfe03c8 100644 --- a/man/characterize.Rd +++ b/man/characterize.Rd @@ -58,5 +58,5 @@ unlink(csv_file) } \seealso{ -\code{\link{gather_attrs}} +\code{\link[=gather_attrs]{gather_attrs()}} } diff --git a/man/convert.Rd b/man/convert.Rd index 5d45465..867292a 100644 --- a/man/convert.Rd +++ b/man/convert.Rd @@ -11,15 +11,15 @@ convert(in_file, out_file, in_opts = list(), out_opts = list()) \item{out_file}{A character string naming an output file.} -\item{in_opts}{A named list of options to be passed to \code{\link{import}}.} +\item{in_opts}{A named list of options to be passed to \code{\link[=import]{import()}}.} -\item{out_opts}{A named list of options to be passed to \code{\link{export}}.} +\item{out_opts}{A named list of options to be passed to \code{\link[=export]{export()}}.} } \value{ A character string containing the name of the output file (invisibly). } \description{ -This function constructs a data frame from a data file using \code{\link{import}} and uses \code{\link{export}} to write the data to disk in the format indicated by the file extension. +This function constructs a data frame from a data file using \code{\link[=import]{import()}} and uses \code{\link[=export]{export()}} to write the data to disk in the format indicated by the file extension. } \examples{ # create a file to convert diff --git a/man/export.Rd b/man/export.Rd index 5e82d3d..ac0aff4 100644 --- a/man/export.Rd +++ b/man/export.Rd @@ -7,11 +7,11 @@ export(x, file, format, ...) } \arguments{ -\item{x}{A data frame or matrix to be written into a file. Exceptions to this rule are that \code{x} can be a list of data frames if the output file format is an Excel .xlsx workbook, .Rdata file, or HTML file, or a variety of R objects if the output file format is RDS or JSON. See examples.) To export a list of data frames to multiple files, use \code{\link{export_list}} instead.} +\item{x}{A data frame or matrix to be written into a file. Exceptions to this rule are that \code{x} can be a list of data frames if the output file format is an Excel .xlsx workbook, .Rdata file, or HTML file, or a variety of R objects if the output file format is RDS or JSON. See examples.) To export a list of data frames to multiple files, use \code{\link[=export_list]{export_list()}} instead.} \item{file}{A character string naming a file. Must specify \code{file} and/or \code{format}.} -\item{format}{An optional character string containing the file format, which can be used to override the format inferred from \code{file} or, in lieu of specifying \code{file}, a file with the symbol name of \code{x} and the specified file extension will be created. Must specify \code{file} and/or \code{format}. Shortcuts include: \dQuote{,} (for comma-separated values), \dQuote{;} (for semicolon-separated values), \dQuote{|} (for pipe-separated values), and \dQuote{dump} for \code{\link[base]{dump}}.} +\item{format}{An optional character string containing the file format, which can be used to override the format inferred from \code{file} or, in lieu of specifying \code{file}, a file with the symbol name of \code{x} and the specified file extension will be created. Must specify \code{file} and/or \code{format}. Shortcuts include: \dQuote{,} (for comma-separated values), \dQuote{;} (for semicolon-separated values), \dQuote{|} (for pipe-separated values), and \dQuote{dump} for \code{\link[base:dump]{base::dump()}}.} \item{\dots}{Additional arguments for the underlying export functions. This can be used to specify non-standard arguments. See examples.} } @@ -29,38 +29,38 @@ The output file can be to a compressed directory, simply by adding an appropriat \code{export} supports many file formats. See the documentation for the underlying export functions for optional arguments that can be passed via \code{...} \itemize{ - \item Comma-separated data (.csv), using \code{\link[data.table]{fwrite}} or, if \code{fwrite = TRUE}, \code{\link[utils]{write.table}} with \code{row.names = FALSE}. - \item Pipe-separated data (.psv), using \code{\link[data.table]{fwrite}} or, if \code{fwrite = TRUE}, \code{\link[utils]{write.table}} with \code{sep = '|'} and \code{row.names = FALSE}. - \item Tab-separated data (.tsv), using \code{\link[data.table]{fwrite}} or, if \code{fwrite = TRUE}, \code{\link[utils]{write.table}} with \code{row.names = FALSE}. - \item SAS (.sas7bdat), using \code{\link[haven]{write_sas}}. - \item SAS XPORT (.xpt), using \code{\link[haven]{write_xpt}}. - \item SPSS (.sav), using \code{\link[haven]{write_sav}} - \item SPSS compressed (.zsav), using \code{\link[haven]{write_sav}} - \item Stata (.dta), using \code{\link[haven]{write_dta}}. Note that variable/column names containing dots (.) are not allowed and will produce an error. - \item Excel (.xlsx), using \code{\link[openxlsx]{write.xlsx}}. Existing workbooks are overwritten unless \code{which} is specified, in which case only the specified sheet (if it exists) is overwritten. If the file exists but the \code{which} sheet does not, data are added as a new sheet to the existing workbook. \code{x} can also be a list of data frames; the list entry names are used as sheet names. - \item R syntax object (.R), using \code{\link[base]{dput}} (by default) or \code{\link[base]{dump}} (if \code{format = 'dump'}) - \item Saved R objects (.RData,.rda), using \code{\link[base]{save}}. In this case, \code{x} can be a data frame, a named list of objects, an R environment, or a character vector containing the names of objects if a corresponding \code{envir} argument is specified. - \item Serialized R objects (.rds), using \code{\link[base]{saveRDS}}. In this case, \code{x} can be any serializable R object. - \item "XBASE" database files (.dbf), using \code{\link[foreign]{write.dbf}} - \item Weka Attribute-Relation File Format (.arff), using \code{\link[foreign]{write.arff}} - \item Fixed-width format data (.fwf), using \code{\link[utils]{write.table}} with \code{row.names = FALSE}, \code{quote = FALSE}, and \code{col.names = FALSE} - \item gzip comma-separated data (.csv.gz), using \code{\link[utils]{write.table}} with \code{row.names = FALSE} - \item \href{https://github.com/csvy}{CSVY} (CSV with a YAML metadata header) using \code{\link[data.table]{fwrite}}. - \item Apache Arrow Parquet (.parquet), using \code{\link[arrow]{write_parquet}} - \item Feather R/Python interchange format (.feather), using \code{\link[feather]{write_feather}} - \item Fast storage (.fst), using \code{\link[fst]{write.fst}} - \item JSON (.json), using \code{\link[jsonlite]{toJSON}}. In this case, \code{x} can be a variety of R objects, based on class mapping conventions in this paper: \href{https://arxiv.org/abs/1403.2805}{https://arxiv.org/abs/1403.2805}. - \item Matlab (.mat), using \code{\link[rmatio]{write.mat}} - \item OpenDocument Spreadsheet (.ods), using \code{\link[readODS]{write_ods}}. (Currently only single-sheet exports are supported.) - \item HTML (.html), using a custom method based on \code{\link[xml2]{xml_add_child}} to create a simple HTML table and \code{\link[xml2]{write_xml}} to write to disk. - \item XML (.xml), using a custom method based on \code{\link[xml2]{xml_add_child}} to create a simple XML tree and \code{\link[xml2]{write_xml}} to write to disk. - \item YAML (.yml), using \code{\link[yaml]{as.yaml}} - \item Clipboard export (on Windows and Mac OS), using \code{\link[utils]{write.table}} with \code{row.names = FALSE} +\item Comma-separated data (.csv), using \code{\link[data.table:fwrite]{data.table::fwrite()}} or, if \code{fwrite = TRUE}, \code{\link[utils:write.table]{utils::write.table()}} with \code{row.names = FALSE}. +\item Pipe-separated data (.psv), using \code{\link[data.table:fwrite]{data.table::fwrite()}} or, if \code{fwrite = TRUE}, \code{\link[utils:write.table]{utils::write.table()}} with \code{sep = '|'} and \code{row.names = FALSE}. +\item Tab-separated data (.tsv), using \code{\link[data.table:fwrite]{data.table::fwrite()}} or, if \code{fwrite = TRUE}, \code{\link[utils:write.table]{utils::write.table()}} with \code{row.names = FALSE}. +\item SAS (.sas7bdat), using \code{\link[haven:write_sas]{haven::write_sas()}}. +\item SAS XPORT (.xpt), using \code{\link[haven:read_xpt]{haven::write_xpt()}}. +\item SPSS (.sav), using \code{\link[haven:read_spss]{haven::write_sav()}} +\item SPSS compressed (.zsav), using \code{\link[haven:read_spss]{haven::write_sav()}} +\item Stata (.dta), using \code{\link[haven:read_dta]{haven::write_dta()}}. Note that variable/column names containing dots (.) are not allowed and will produce an error. +\item Excel (.xlsx), using \code{\link[openxlsx:write.xlsx]{openxlsx::write.xlsx()}}. Existing workbooks are overwritten unless \code{which} is specified, in which case only the specified sheet (if it exists) is overwritten. If the file exists but the \code{which} sheet does not, data are added as a new sheet to the existing workbook. \code{x} can also be a list of data frames; the list entry names are used as sheet names. +\item R syntax object (.R), using \code{\link[base:dput]{base::dput()}} (by default) or \code{\link[base:dump]{base::dump()}} (if \code{format = 'dump'}) +\item Saved R objects (.RData,.rda), using \code{\link[base:save]{base::save()}}. In this case, \code{x} can be a data frame, a named list of objects, an R environment, or a character vector containing the names of objects if a corresponding \code{envir} argument is specified. +\item Serialized R objects (.rds), using \code{\link[base:readRDS]{base::saveRDS()}}. In this case, \code{x} can be any serializable R object. +\item "XBASE" database files (.dbf), using \code{\link[foreign:write.dbf]{foreign::write.dbf()}} +\item Weka Attribute-Relation File Format (.arff), using \code{\link[foreign:write.arff]{foreign::write.arff()}} +\item Fixed-width format data (.fwf), using \code{\link[utils:write.table]{utils::write.table()}} with \code{row.names = FALSE}, \code{quote = FALSE}, and \code{col.names = FALSE} +\item gzip comma-separated data (.csv.gz), using \code{\link[utils:write.table]{utils::write.table()}} with \code{row.names = FALSE} +\item \href{https://github.com/csvy}{CSVY} (CSV with a YAML metadata header) using \code{\link[data.table:fwrite]{data.table::fwrite()}}. +\item Apache Arrow Parquet (.parquet), using \code{\link[arrow:write_parquet]{arrow::write_parquet()}} +\item Feather R/Python interchange format (.feather), using \code{\link[feather:read_feather]{feather::write_feather()}} +\item Fast storage (.fst), using \code{\link[fst:write_fst]{fst::write.fst()}} +\item JSON (.json), using \code{\link[jsonlite:fromJSON]{jsonlite::toJSON()}}. In this case, \code{x} can be a variety of R objects, based on class mapping conventions in this paper: \url{https://arxiv.org/abs/1403.2805}. +\item Matlab (.mat), using \code{\link[rmatio:write.mat-methods]{rmatio::write.mat()}} +\item OpenDocument Spreadsheet (.ods), using \code{\link[readODS:write_ods]{readODS::write_ods()}}. (Currently only single-sheet exports are supported.) +\item HTML (.html), using a custom method based on \code{\link[xml2:xml_replace]{xml2::xml_add_child()}} to create a simple HTML table and \code{\link[xml2:write_xml]{xml2::write_xml()}} to write to disk. +\item XML (.xml), using a custom method based on \code{\link[xml2:xml_replace]{xml2::xml_add_child()}} to create a simple XML tree and \code{\link[xml2:write_xml]{xml2::write_xml()}} to write to disk. +\item YAML (.yml), using \code{\link[yaml:as.yaml]{yaml::as.yaml()}} +\item Clipboard export (on Windows and Mac OS), using \code{\link[utils:write.table]{utils::write.table()}} with \code{row.names = FALSE} } -When exporting a data set that contains label attributes (e.g., if imported from an SPSS or Stata file) to a plain text file, \code{\link{characterize}} can be a useful pre-processing step that records value labels into the resulting file (e.g., \code{export(characterize(x), "file.csv")}) rather than the numeric values. +When exporting a data set that contains label attributes (e.g., if imported from an SPSS or Stata file) to a plain text file, \code{\link[=characterize]{characterize()}} can be a useful pre-processing step that records value labels into the resulting file (e.g., \code{export(characterize(x), "file.csv")}) rather than the numeric values. -Use \code{\link{export_list}} to export a list of dataframes to separate files. +Use \code{\link[=export_list]{export_list()}} to export a list of dataframes to separate files. } \examples{ library("datasets") @@ -134,5 +134,5 @@ unlink(f8) # unlink(f13) } \seealso{ -\code{\link{characterize}}, \code{\link{import}}, \code{\link{convert}}, \code{\link{export_list}} +\code{\link[=characterize]{characterize()}}, \code{\link[=import]{import()}}, \code{\link[=convert]{convert()}}, \code{\link[=export_list]{export_list()}} } diff --git a/man/export_list.Rd b/man/export_list.Rd index 1f18eda..297ee88 100644 --- a/man/export_list.Rd +++ b/man/export_list.Rd @@ -9,18 +9,18 @@ export_list(x, file, ...) \arguments{ \item{x}{A list of data frames to be written to files.} -\item{file}{A character vector string containing a single file name with a \code{\%s} wildcard placeholder, or a vector of file paths for multiple files to be imported. If \code{x} elements are named, these will be used in place of \code{\%s}, otherwise numbers will be used; all elements must be named for names to be used.} +\item{file}{A character vector string containing a single file name with a \verb{\\\%s} wildcard placeholder, or a vector of file paths for multiple files to be imported. If \code{x} elements are named, these will be used in place of \verb{\\\%s}, otherwise numbers will be used; all elements must be named for names to be used.} -\item{\dots}{Additional arguments passed to \code{\link{export}}.} +\item{\dots}{Additional arguments passed to \code{\link[=export]{export()}}.} } \value{ The name(s) of the output file(s) as a character vector (invisibly). } \description{ -Use \code{\link{export}} to export a list of data frames to a vector of file names or a filename pattern. +Use \code{\link[=export]{export()}} to export a list of data frames to a vector of file names or a filename pattern. } \details{ -\code{\link{export}} can export a list of data frames to a single multi-dataset file (e.g., an Rdata or Excel .xlsx file). Use \code{export_list} to export such a list to \emph{multiple} files. +\code{\link[=export]{export()}} can export a list of data frames to a single multi-dataset file (e.g., an Rdata or Excel .xlsx file). Use \code{export_list} to export such a list to \emph{multiple} files. } \examples{ library('datasets') @@ -47,5 +47,5 @@ unlink(csv_files2) } \seealso{ -\code{\link{import}}, \code{\link{import_list}}, \code{\link{export}} +\code{\link[=import]{import()}}, \code{\link[=import_list]{import_list()}}, \code{\link[=export]{export()}} } diff --git a/man/gather_attrs.Rd b/man/gather_attrs.Rd index c5f3845..1589e43 100644 --- a/man/gather_attrs.Rd +++ b/man/gather_attrs.Rd @@ -19,7 +19,7 @@ spread_attrs(x) \code{gather_attrs} moves variable-level attributes to the data frame level and \code{spread_attrs} reverses that operation. } \details{ -\code{\link{import}} attempts to standardize the return value from the various import functions to the extent possible, thus providing a uniform data structure regardless of what import package or function is used. It achieves this by storing any optional variable-related attributes at the variable level (i.e., an attribute for \code{mtcars$mpg} is stored in \code{attributes(mtcars$mpg)} rather than \code{attributes(mtcars)}). \code{gather_attrs} moves these to the data frame level (i.e., in \code{attributes(mtcars)}). \code{spread_attrs} moves attributes back to the variable level. +\code{\link[=import]{import()}} attempts to standardize the return value from the various import functions to the extent possible, thus providing a uniform data structure regardless of what import package or function is used. It achieves this by storing any optional variable-related attributes at the variable level (i.e., an attribute for \code{mtcars$mpg} is stored in \code{attributes(mtcars$mpg)} rather than \code{attributes(mtcars)}). \code{gather_attrs} moves these to the data frame level (i.e., in \code{attributes(mtcars)}). \code{spread_attrs} moves attributes back to the variable level. } \examples{ e <- try(import("http://www.stata-press.com/data/r13/auto.dta")) @@ -31,5 +31,5 @@ if (!inherits(e, "try-error")) { } } \seealso{ -\code{\link{import}}, \code{\link{characterize}} +\code{\link[=import]{import()}}, \code{\link[=characterize]{characterize()}} } diff --git a/man/import.Rd b/man/import.Rd index 06c5cf8..09af0c7 100644 --- a/man/import.Rd +++ b/man/import.Rd @@ -13,7 +13,7 @@ import(file, format, setclass, which, ...) \item{setclass}{An optional character vector specifying one or more classes to set on the import. By default, the return object is always a \dQuote{data.frame}. Allowed values include \dQuote{tbl_df}, \dQuote{tbl}, or \dQuote{tibble} (if using dplyr) or \dQuote{data.table} (if using data.table). Other values are ignored, such that a data.frame is returned.} -\item{which}{This argument is used to control import from multi-object files; as a rule \code{import} only ever returns a single data frame (use \code{\link{import_list}} to import multiple data frames from a multi-object file). If \code{file} is a compressed directory, \code{which} can be either a character string specifying a filename or an integer specifying which file (in locale sort order) to extract from the compressed directory. For Excel spreadsheets, this can be used to specify a sheet name or number. For .Rdata files, this can be an object name. For HTML files, it identifies which table to extract (from document order). Ignored otherwise. A character string value will be used as a regular expression, such that the extracted file is the first match of the regular expression against the file names in the archive.} +\item{which}{This argument is used to control import from multi-object files; as a rule \code{import} only ever returns a single data frame (use \code{\link[=import_list]{import_list()}} to import multiple data frames from a multi-object file). If \code{file} is a compressed directory, \code{which} can be either a character string specifying a filename or an integer specifying which file (in locale sort order) to extract from the compressed directory. For Excel spreadsheets, this can be used to specify a sheet name or number. For .Rdata files, this can be an object name. For HTML files, it identifies which table to extract (from document order). Ignored otherwise. A character string value will be used as a regular expression, such that the extracted file is the first match of the regular expression against the file names in the archive.} \item{\dots}{Additional arguments passed to the underlying import functions. For example, this can control column classes for delimited file types, or control the use of haven for Stata and SPSS or readxl for Excel (.xlsx) format. See details below.} } @@ -29,50 +29,50 @@ This function imports a data frame or matrix from a data file with the file form \code{import} supports the following file formats: \itemize{ - \item Comma-separated data (.csv), using \code{\link[data.table]{fread}} or, if \code{fread = FALSE}, \code{\link[utils]{read.table}} with \code{row.names = FALSE} and \code{stringsAsFactors = FALSE} - \item Pipe-separated data (.psv), using \code{\link[data.table]{fread}} or, if \code{fread = FALSE}, \code{\link[utils]{read.table}} with \code{sep = '|'}, \code{row.names = FALSE} and \code{stringsAsFactors = FALSE} - \item Tab-separated data (.tsv), using \code{\link[data.table]{fread}} or, if \code{fread = FALSE}, \code{\link[utils]{read.table}} with \code{row.names = FALSE} and \code{stringsAsFactors = FALSE} - \item SAS (.sas7bdat), using \code{\link[haven]{read_sas}}. - \item SAS XPORT (.xpt), using \code{\link[haven]{read_xpt}} or, if \code{haven = FALSE}, \code{\link[foreign]{read.xport}}. - \item SPSS (.sav), using \code{\link[haven]{read_sav}}. If \code{haven = FALSE}, \code{\link[foreign]{read.spss}} can be used. - \item SPSS compressed (.zsav), using \code{\link[haven]{read_sav}}. - \item Stata (.dta), using \code{\link[haven]{read_dta}}. If \code{haven = FALSE}, \code{\link[foreign]{read.dta}} can be used. - \item SPSS Portable Files (.por), using \code{\link[haven]{read_por}}. - \item Excel (.xls and .xlsx), using \code{\link[readxl]{read_excel}}. Use \code{which} to specify a sheet number. For .xlsx files, it is possible to set \code{readxl = FALSE}, so that \code{\link[openxlsx]{read.xlsx}} can be used instead of readxl (the default). - \item R syntax object (.R), using \code{\link[base]{dget}} - \item Saved R objects (.RData,.rda), using \code{\link[base]{load}} for single-object .Rdata files. Use \code{which} to specify an object name for multi-object .Rdata files. This can be any R object (not just a data frame). - \item Serialized R objects (.rds), using \code{\link[base]{readRDS}}. This can be any R object (not just a data frame). - \item Epiinfo (.rec), using \code{\link[foreign]{read.epiinfo}} - \item Minitab (.mtp), using \code{\link[foreign]{read.mtp}} - \item Systat (.syd), using \code{\link[foreign]{read.systat}} - \item "XBASE" database files (.dbf), using \code{\link[foreign]{read.dbf}} - \item Weka Attribute-Relation File Format (.arff), using \code{\link[foreign]{read.arff}} - \item Data Interchange Format (.dif), using \code{\link[utils]{read.DIF}} - \item Fortran data (no recognized extension), using \code{\link[utils]{read.fortran}} - \item Fixed-width format data (.fwf), using a faster version of \code{\link[utils]{read.fwf}} that requires a \code{widths} argument and by default in rio has \code{stringsAsFactors = FALSE}. If \code{readr = TRUE}, import will be performed using \code{\link[readr]{read_fwf}}, where \code{widths} should be: \code{NULL}, a vector of column widths, or the output of \code{\link[readr]{fwf_empty}}, \code{\link[readr]{fwf_widths}}, or \code{\link[readr]{fwf_positions}}. - \item gzip comma-separated data (.csv.gz), using \code{\link[utils]{read.table}} with \code{row.names = FALSE} and \code{stringsAsFactors = FALSE} - \item \href{https://github.com/csvy}{CSVY} (CSV with a YAML metadata header) using \code{\link[data.table]{fread}}. - \item Apache Arrow Parquet (.parquet), using \code{\link[arrow]{read_parquet}} - \item Feather R/Python interchange format (.feather), using \code{\link[feather]{read_feather}} - \item Fast storage (.fst), using \code{\link[fst]{read.fst}} - \item JSON (.json), using \code{\link[jsonlite]{fromJSON}} - \item Matlab (.mat), using \code{\link[rmatio]{read.mat}} - \item EViews (.wf1), using \code{\link[hexView]{readEViews}} - \item OpenDocument Spreadsheet (.ods), using \code{\link[readODS]{read_ods}}. Use \code{which} to specify a sheet number. - \item Single-table HTML documents (.html), using \code{\link[xml2]{read_html}}. There is no standard HTML table and we have only tested this with HTML tables exported with this package. HTML tables will only be read correctly if the HTML file can be converted to a list via \code{\link[xml2]{as_list}}. This import feature is not robust, especially for HTML tables in the wild. Please use a proper web scraping framework, e.g. \code{rvest}. - \item Shallow XML documents (.xml), using \code{\link[xml2]{read_xml}}. The data structure will only be read correctly if the XML file can be converted to a list via \code{\link[xml2]{as_list}}. - \item YAML (.yml), using \code{\link[yaml]{yaml.load}} - \item Clipboard import, using \code{\link[utils]{read.table}} with \code{row.names = FALSE} - \item Google Sheets, as Comma-separated data (.csv) - \item GraphPad Prism (.pzfx) using \code{\link[pzfx]{read_pzfx}} +\item Comma-separated data (.csv), using \code{\link[data.table:fread]{data.table::fread()}} or, if \code{fread = FALSE}, \code{\link[utils:read.table]{utils::read.table()}} with \code{row.names = FALSE} and \code{stringsAsFactors = FALSE} +\item Pipe-separated data (.psv), using \code{\link[data.table:fread]{data.table::fread()}} or, if \code{fread = FALSE}, \code{\link[utils:read.table]{utils::read.table()}} with \code{sep = '|'}, \code{row.names = FALSE} and \code{stringsAsFactors = FALSE} +\item Tab-separated data (.tsv), using \code{\link[data.table:fread]{data.table::fread()}} or, if \code{fread = FALSE}, \code{\link[utils:read.table]{utils::read.table()}} with \code{row.names = FALSE} and \code{stringsAsFactors = FALSE} +\item SAS (.sas7bdat), using \code{\link[haven:read_sas]{haven::read_sas()}}. +\item SAS XPORT (.xpt), using \code{\link[haven:read_xpt]{haven::read_xpt()}} or, if \code{haven = FALSE}, \code{\link[foreign:read.xport]{foreign::read.xport()}}. +\item SPSS (.sav), using \code{\link[haven:read_spss]{haven::read_sav()}}. If \code{haven = FALSE}, \code{\link[foreign:read.spss]{foreign::read.spss()}} can be used. +\item SPSS compressed (.zsav), using \code{\link[haven:read_spss]{haven::read_sav()}}. +\item Stata (.dta), using \code{\link[haven:read_dta]{haven::read_dta()}}. If \code{haven = FALSE}, \code{\link[foreign:read.dta]{foreign::read.dta()}} can be used. +\item SPSS Portable Files (.por), using \code{\link[haven:read_spss]{haven::read_por()}}. +\item Excel (.xls and .xlsx), using \code{\link[readxl:read_excel]{readxl::read_excel()}}. Use \code{which} to specify a sheet number. For .xlsx files, it is possible to set \code{readxl = FALSE}, so that \code{\link[openxlsx:read.xlsx]{openxlsx::read.xlsx()}} can be used instead of readxl (the default). +\item R syntax object (.R), using \code{\link[base:dput]{base::dget()}} +\item Saved R objects (.RData,.rda), using \code{\link[base:load]{base::load()}} for single-object .Rdata files. Use \code{which} to specify an object name for multi-object .Rdata files. This can be any R object (not just a data frame). +\item Serialized R objects (.rds), using \code{\link[base:readRDS]{base::readRDS()}}. This can be any R object (not just a data frame). +\item Epiinfo (.rec), using \code{\link[foreign:read.epiinfo]{foreign::read.epiinfo()}} +\item Minitab (.mtp), using \code{\link[foreign:read.mtp]{foreign::read.mtp()}} +\item Systat (.syd), using \code{\link[foreign:read.systat]{foreign::read.systat()}} +\item "XBASE" database files (.dbf), using \code{\link[foreign:read.dbf]{foreign::read.dbf()}} +\item Weka Attribute-Relation File Format (.arff), using \code{\link[foreign:read.arff]{foreign::read.arff()}} +\item Data Interchange Format (.dif), using \code{\link[utils:read.DIF]{utils::read.DIF()}} +\item Fortran data (no recognized extension), using \code{\link[utils:read.fortran]{utils::read.fortran()}} +\item Fixed-width format data (.fwf), using a faster version of \code{\link[utils:read.fwf]{utils::read.fwf()}} that requires a \code{widths} argument and by default in rio has \code{stringsAsFactors = FALSE}. If \code{readr = TRUE}, import will be performed using \code{\link[readr:read_fwf]{readr::read_fwf()}}, where \code{widths} should be: \code{NULL}, a vector of column widths, or the output of \code{\link[readr:read_fwf]{readr::fwf_empty()}}, \code{\link[readr:read_fwf]{readr::fwf_widths()}}, or \code{\link[readr:read_fwf]{readr::fwf_positions()}}. +\item gzip comma-separated data (.csv.gz), using \code{\link[utils:read.table]{utils::read.table()}} with \code{row.names = FALSE} and \code{stringsAsFactors = FALSE} +\item \href{https://github.com/csvy}{CSVY} (CSV with a YAML metadata header) using \code{\link[data.table:fread]{data.table::fread()}}. +\item Apache Arrow Parquet (.parquet), using \code{\link[arrow:read_parquet]{arrow::read_parquet()}} +\item Feather R/Python interchange format (.feather), using \code{\link[feather:read_feather]{feather::read_feather()}} +\item Fast storage (.fst), using \code{\link[fst:write_fst]{fst::read.fst()}} +\item JSON (.json), using \code{\link[jsonlite:fromJSON]{jsonlite::fromJSON()}} +\item Matlab (.mat), using \code{\link[rmatio:read.mat]{rmatio::read.mat()}} +\item EViews (.wf1), using \code{\link[hexView:readEViews]{hexView::readEViews()}} +\item OpenDocument Spreadsheet (.ods), using \code{\link[readODS:read_ods]{readODS::read_ods()}}. Use \code{which} to specify a sheet number. +\item Single-table HTML documents (.html), using \code{\link[xml2:read_xml]{xml2::read_html()}}. There is no standard HTML table and we have only tested this with HTML tables exported with this package. HTML tables will only be read correctly if the HTML file can be converted to a list via \code{\link[xml2:as_list]{xml2::as_list()}}. This import feature is not robust, especially for HTML tables in the wild. Please use a proper web scraping framework, e.g. \code{rvest}. +\item Shallow XML documents (.xml), using \code{\link[xml2:read_xml]{xml2::read_xml()}}. The data structure will only be read correctly if the XML file can be converted to a list via \code{\link[xml2:as_list]{xml2::as_list()}}. +\item YAML (.yml), using \code{\link[yaml:yaml.load]{yaml::yaml.load()}} +\item Clipboard import, using \code{\link[utils:read.table]{utils::read.table()}} with \code{row.names = FALSE} +\item Google Sheets, as Comma-separated data (.csv) +\item GraphPad Prism (.pzfx) using \code{\link[pzfx:read_pzfx]{pzfx::read_pzfx()}} } -\code{import} attempts to standardize the return value from the various import functions to the extent possible, thus providing a uniform data structure regardless of what import package or function is used. It achieves this by storing any optional variable-related attributes at the variable level (i.e., an attribute for \code{mtcars$mpg} is stored in \code{attributes(mtcars$mpg)} rather than \code{attributes(mtcars)}). If you would prefer these attributes to be stored at the data.frame-level (i.e., in \code{attributes(mtcars)}), see \code{\link{gather_attrs}}. +\code{import} attempts to standardize the return value from the various import functions to the extent possible, thus providing a uniform data structure regardless of what import package or function is used. It achieves this by storing any optional variable-related attributes at the variable level (i.e., an attribute for \code{mtcars$mpg} is stored in \code{attributes(mtcars$mpg)} rather than \code{attributes(mtcars)}). If you would prefer these attributes to be stored at the data.frame-level (i.e., in \code{attributes(mtcars)}), see \code{\link[=gather_attrs]{gather_attrs()}}. -After importing metadata-rich file formats (e.g., from Stata or SPSS), it may be helpful to recode labelled variables to character or factor using \code{\link{characterize}} or \code{\link{factorize}} respectively. +After importing metadata-rich file formats (e.g., from Stata or SPSS), it may be helpful to recode labelled variables to character or factor using \code{\link[=characterize]{characterize()}} or \code{\link[=factorize]{factorize()}} respectively. } \note{ -For csv and txt files with row names exported from \code{\link{export}}, it may be helpful to specify \code{row.names} as the column of the table which contain row names. See example below. +For csv and txt files with row names exported from \code{\link[=export]{export()}}, it may be helpful to specify \code{row.names} as the column of the table which contain row names. See example below. } \examples{ # create CSV to import @@ -109,5 +109,5 @@ unlink(rds_file) } \seealso{ -\code{\link{import_list}}, \code{\link{characterize}}, \code{\link{gather_attrs}}, \code{\link{export}}, \code{\link{convert}} +\code{\link[=import_list]{import_list()}}, \code{\link[=characterize]{characterize()}}, \code{\link[=gather_attrs]{gather_attrs()}}, \code{\link[=export]{export()}}, \code{\link[=convert]{convert()}} } diff --git a/man/import_list.Rd b/man/import_list.Rd index 0d135f7..99e1779 100644 --- a/man/import_list.Rd +++ b/man/import_list.Rd @@ -19,21 +19,21 @@ import_list( \item{setclass}{An optional character vector specifying one or more classes to set on the import. By default, the return object is always a \dQuote{data.frame}. Allowed values include \dQuote{tbl_df}, \dQuote{tbl}, or \dQuote{tibble} (if using dplyr) or \dQuote{data.table} (if using data.table). Other values are ignored, such that a data.frame is returned.} -\item{which}{If \code{file} is a single file path, this specifies which objects should be extracted (passed to \code{\link{import}}'s \code{which} argument). Ignored otherwise.} +\item{which}{If \code{file} is a single file path, this specifies which objects should be extracted (passed to \code{\link[=import]{import()}}'s \code{which} argument). Ignored otherwise.} -\item{rbind}{A logical indicating whether to pass the import list of data frames through \code{\link[data.table]{rbindlist}}.} +\item{rbind}{A logical indicating whether to pass the import list of data frames through \code{\link[data.table:rbindlist]{data.table::rbindlist()}}.} \item{rbind_label}{If \code{rbind = TRUE}, a character string specifying the name of a column to add to the data frame indicating its source file.} \item{rbind_fill}{If \code{rbind = TRUE}, a logical indicating whether to set the \code{fill = TRUE} (and fill missing columns with \code{NA}).} -\item{\dots}{Additional arguments passed to \code{\link{import}}. Behavior may be unexpected if files are of different formats.} +\item{\dots}{Additional arguments passed to \code{\link[=import]{import()}}. Behavior may be unexpected if files are of different formats.} } \value{ -If \code{rbind=FALSE} (the default), a list of a data frames. Otherwise, that list is passed to \code{\link[data.table]{rbindlist}} with \code{fill = TRUE} and returns a data frame object of class set by the \code{setclass} argument; if this operation fails, the list is returned. +If \code{rbind=FALSE} (the default), a list of a data frames. Otherwise, that list is passed to \code{\link[data.table:rbindlist]{data.table::rbindlist()}} with \code{fill = TRUE} and returns a data frame object of class set by the \code{setclass} argument; if this operation fails, the list is returned. } \description{ -Use \code{\link{import}} to import a list of data frames from a vector of file names or from a multi-object file (Excel workbook, .Rdata file, zip directory, or HTML file) +Use \code{\link[=import]{import()}} to import a list of data frames from a vector of file names or from a multi-object file (Excel workbook, .Rdata file, zip directory, or HTML file) } \examples{ library('datasets') @@ -67,5 +67,5 @@ unlink(xlsx_file) } \seealso{ -\code{\link{import}}, \code{\link{export_list}}, \code{\link{export}} +\code{\link[=import]{import()}}, \code{\link[=export_list]{export_list()}}, \code{\link[=export]{export()}} } diff --git a/man/install_formats.Rd b/man/install_formats.Rd index 3c763c7..4872c1f 100644 --- a/man/install_formats.Rd +++ b/man/install_formats.Rd @@ -7,7 +7,7 @@ install_formats(...) } \arguments{ -\item{\dots}{Additional arguments passed to \code{\link[utils]{install.packages}}.} +\item{\dots}{Additional arguments passed to \code{\link[utils:install.packages]{utils::install.packages()}}.} } \value{ \code{NULL} diff --git a/man/rio.Rd b/man/rio.Rd index 58c3175..e83e1bd 100644 --- a/man/rio.Rd +++ b/man/rio.Rd @@ -6,9 +6,9 @@ \alias{rio-package} \title{A Swiss-Army Knife for Data I/O} \description{ -The aim of rio is to make data file input and output as easy as possible. \code{\link{export}} and \code{\link{import}} serve as a Swiss-army knife for painless data I/O for data from almost any file format by inferring the data structure from the file extension, natively reading web-based data sources, setting reasonable defaults for import and export, and relying on efficient data import and export packages. An additional convenience function, \code{\link{convert}}, provides a simple method for converting between file types. +The aim of rio is to make data file input and output as easy as possible. \code{\link[=export]{export()}} and \code{\link[=import]{import()}} serve as a Swiss-army knife for painless data I/O for data from almost any file format by inferring the data structure from the file extension, natively reading web-based data sources, setting reasonable defaults for import and export, and relying on efficient data import and export packages. An additional convenience function, \code{\link[=convert]{convert()}}, provides a simple method for converting between file types. -Note that some of rio's functionality is provided by \sQuote{Suggests} dependendencies, meaning they are not installed by default. Use \code{\link{install_formats}} to make sure these packages are available for use. +Note that some of rio's functionality is provided by \sQuote{Suggests} dependendencies, meaning they are not installed by default. Use \code{\link[=install_formats]{install_formats()}} to make sure these packages are available for use. } \examples{ # export @@ -33,7 +33,7 @@ unlink(c(csv_file, rds_file, sav_file, dta_file)) \href{https://github.com/Stan125/GREA}{GREA} provides an RStudio add-in to import data using rio. } \seealso{ -\code{\link{import}}, \code{\link{import_list}}, \code{\link{export}}, \code{\link{export_list}}, \code{\link{convert}}, \code{\link{install_formats}} +\code{\link[=import]{import()}}, \code{\link[=import_list]{import_list()}}, \code{\link[=export]{export()}}, \code{\link[=export_list]{export_list()}}, \code{\link[=convert]{convert()}}, \code{\link[=install_formats]{install_formats()}} } \author{ \strong{Maintainer}: Chung-hong Chan \email{chainsawtiney@gmail.com} (\href{https://orcid.org/0000-0002-6232-7530}{ORCID}) From 5328dffa5aaf3acdcaa9d446725b574714b0adab Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Thu, 31 Aug 2023 17:15:58 +0200 Subject: [PATCH 33/44] Fix #327 [no ci] (#329) * Improve the examples of `import` #327 * Update examples in `export.R` #327 * Rewrite examples `convert()` #327 * Rewrite example `import_list` #327 * Update examples #327 * Update NEWS.md --- NEWS.md | 1 + R/characterize.R | 14 ++++---- R/convert.R | 49 +++++++++++++-------------- R/export.R | 81 +++++++++++---------------------------------- R/export_list.R | 43 ++++++++++++++---------- R/import.R | 48 ++++++++++++--------------- R/import_list.R | 30 +++++------------ man/characterize.Rd | 14 ++++---- man/convert.Rd | 49 +++++++++++++-------------- man/export.Rd | 81 +++++++++++---------------------------------- man/export_list.Rd | 28 ++++++++++------ man/import.Rd | 60 ++++++++++++++++----------------- man/import_list.Rd | 30 +++++------------ 13 files changed, 207 insertions(+), 321 deletions(-) diff --git a/NEWS.md b/NEWS.md index ff6e0e7..c327d75 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,6 @@ * Stop loading the entire namespace of a suggested package when it is available #296 * Unexport objects: `.import`, `.export`, `is_file_text`; remove documentation for `arg_reconcile` #321 +* Update Examples to make them more realistic #327 * Declutter - remove the obsolete data.table option #323 - write all documentation blocks in markdown #311 diff --git a/R/characterize.R b/R/characterize.R index 25d35a3..3e9acbe 100644 --- a/R/characterize.R +++ b/R/characterize.R @@ -7,24 +7,22 @@ #' @details `characterize` converts a vector with a `labels` attribute of named levels into a character vector. `factorize` does the same but to factors. This can be useful at two stages of a data workflow: (1) importing labelled data from metadata-rich file formats (e.g., Stata or SPSS), and (2) exporting such data to plain text files (e.g., CSV) in a way that preserves information. #' @return a character vector (for `characterize`) or factor vector (for `factorize`) #' @examples -#' # vector method +#' ## vector method #' x <- structure(1:4, labels = c("A" = 1, "B" = 2, "C" = 3)) #' characterize(x) #' factorize(x) #' -#' # data frame method +#' ## data frame method #' x <- data.frame(v1 = structure(1:4, labels = c("A" = 1, "B" = 2, "C" = 3)), #' v2 = structure(c(1,0,0,1), labels = c("foo" = 0, "bar" = 1))) #' str(factorize(x)) #' str(characterize(x)) #' -#' # comparison of exported file contents -#' import(export(x, csv_file <- tempfile(fileext = ".csv"))) +#' ## Application +#' csv_file <- tempfile(fileext = ".csv") +#' ## comparison of exported file contents +#' import(export(x, csv_file)) #' import(export(factorize(x), csv_file)) -#' -#' # cleanup -#' unlink(csv_file) -#' #' @seealso [gather_attrs()] #' @export characterize <- function(x, ...) { diff --git a/R/convert.R b/R/convert.R index a20aab3..e81b6ae 100644 --- a/R/convert.R +++ b/R/convert.R @@ -6,33 +6,30 @@ #' @param out_opts A named list of options to be passed to [export()]. #' @return A character string containing the name of the output file (invisibly). #' @examples -#' # create a file to convert -#' export(mtcars, dta_file <- tempfile(fileext = ".dta")) -#' -#' # convert Stata to CSV and open converted file -#' convert(dta_file, csv_file <- tempfile(fileext = ".csv")) -#' head(import(csv_file)) -#' -#' # correct an erroneous file format -#' export(mtcars, csv_file2 <- tempfile(fileext = ".csv"), format = "tsv") -#' convert(csv_file2, csv_file, in_opts = list(format = "tsv")) -#' -#' # convert serialized R data.frame to JSON -#' export(mtcars, rds_file <- tempfile(fileext = ".rds")) -#' convert(rds_file, json_file <- tempfile(fileext = ".json")) -#' -#' # cleanup -#' unlink(csv_file) -#' unlink(csv_file2) -#' unlink(rds_file) -#' unlink(dta_file) -#' unlink(json_file) -#' -#' \dontrun{\donttest{ -#' # convert from the command line: +#' ## For demo, a temp. file path is created with the file extension .dta (Stata) +#' dta_file <- tempfile(fileext = ".dta") +#' ## .csv +#' csv_file <- tempfile(fileext = ".csv") +#' ## .xlsx +#' xlsx_file <- tempfile(fileext = ".xlsx") +#' +#' +#' ## Create a Stata data file +#' export(mtcars, dta_file) +#' +#' ## convert Stata to CSV and open converted file +#' convert(dta_file, csv_file) +#' import(csv_file) +#' +#' ## correct an erroneous file format +#' export(mtcars, xlsx_file, format = "tsv") ## DON'T DO THIS +#' ## import(xlsx_file) ## ERROR +#' ## convert the file by specifying `in_opts` +#' convert(xlsx_file, xlsx_file, in_opts = list(format = "tsv")) +#' import(xlsx_file) +#' +#' ## convert from the command line: #' ## Rscript -e "rio::convert('mtcars.dta', 'mtcars.csv')" -#' }} -#' #' @seealso [Luca Braglia](https://lbraglia.github.io/) has created a Shiny app called [rioweb](https://github.com/lbraglia/rioweb) that provides access to the file conversion features of rio through a web browser. #' @export convert <- function(in_file, out_file, in_opts=list(), out_opts=list()) { diff --git a/R/export.R b/R/export.R index d40c169..89d932c 100644 --- a/R/export.R +++ b/R/export.R @@ -47,75 +47,32 @@ #' Use [export_list()] to export a list of dataframes to separate files. #' #' @examples -#' library("datasets") -#' # specify only `file` argument -#' export(mtcars, f1 <- tempfile(fileext = ".csv")) +#' ## For demo, a temp. file path is created with the file extension .csv +#' csv_file <- tempfile(fileext = ".csv") +#' ## .xlsx +#' xlsx_file <- tempfile(fileext = ".xlsx") #' -#' \dontrun{ -#' wd <- getwd() -#' setwd(tempdir()) -#' # Stata does not recognize variables names with '.' -#' export(mtcars, f2 <- tempfile(fileext = ".dta")) +#' ## create CSV to import +#' export(iris, csv_file) #' -#' # specify only `format` argument -#' f2 %in% tempdir() -#' export(mtcars, format = "stata") -#' "mtcars.dta" %in% dir() +#' ## You can certainly export your data with the file name, which is not a variable: +#' ## import(mtcars, "car_data.csv") #' -#' setwd(wd) -#' } -#' # specify `file` and `format` to override default format -#' export(mtcars, file = f3 <- tempfile(fileext = ".txt"), format = "csv") -#' -#' # export multiple objects to Rdata -#' export(list(mtcars = mtcars, iris = iris), f4 <- tempfile(fileext = ".rdata")) -#' export(c("mtcars", "iris"), f4) -#' -#' # export to non-data frame R object to RDS or JSON -#' export(mtcars$cyl, f5 <- tempfile(fileext = ".rds")) -#' export(list(iris, mtcars), f6 <- tempfile(fileext = ".json")) -#' -#' # pass arguments to underlying export function -#' export(mtcars, f7 <- tempfile(fileext = ".csv"), col.names = FALSE) +#' ## pass arguments to the underlying function +#' ## data.table::fwrite is the underlying function and `col.names` is an argument +#' export(iris, csv_file, col.names = FALSE) #' -#' # write data to .R syntax file and append additional data -#' export(mtcars, file = f8 <- tempfile(fileext = ".R"), format = "dump") -#' export(mtcars, file = f8, format = "dump", append = TRUE) -#' source(f8, echo = TRUE) +#' ## export a list of data frames as worksheets +#' export(list(a = mtcars, b = iris), xlsx_file) #' -#' # write to an Excel workbook -#' \dontrun{ -#' ## export a single data frame -#' export(mtcars, f9 <- tempfile(fileext = ".xlsx")) -#' -#' ## export NAs to Excel as missing via args passed to `...` -#' mtcars$drat <- NA_real_ -#' mtcars %>% export(f10 <- tempfile(fileext = ".xlsx"), keepNA = TRUE) -#' -#' ## export a list of data frames as worksheets -#' export(list(a = mtcars, b = iris), f11 <- tempfile(fileext = ".xlsx")) -#' -#' ## export, adding a new sheet to an existing workbook -#' export(iris, f12 <- tempfile(fileext = ".xlsx"), which = "iris") -#' } +#' # NOT RECOMMENDED #' -#' # write data to a zip-compressed CSV -#' export(mtcars, f13 <- tempfile(fileext = ".csv.zip")) +#' ## specify `format` to override default format +#' export(iris, xlsx_file, format = "csv") ## That's confusing +#' ## You can also specify only the format; in the following case +#' ## "mtcars.dta" is written [also confusing] #' -#' # cleanup -#' unlink(f1) -#' # unlink(f2) -#' unlink(f3) -#' unlink(f4) -#' unlink(f5) -#' unlink(f6) -#' unlink(f7) -#' unlink(f8) -#' # unlink(f9) -#' # unlink(f10) -#' # unlink(f11) -#' # unlink(f12) -#' # unlink(f13) +#' ## export(mtcars, format = "stata") #' @seealso [characterize()], [import()], [convert()], [export_list()] #' @importFrom haven labelled #' @export diff --git a/R/export_list.R b/R/export_list.R index c6cf22e..28f0dda 100644 --- a/R/export_list.R +++ b/R/export_list.R @@ -6,34 +6,43 @@ #' @return The name(s) of the output file(s) as a character vector (invisibly). #' @details [export()] can export a list of data frames to a single multi-dataset file (e.g., an Rdata or Excel .xlsx file). Use `export_list` to export such a list to *multiple* files. #' @examples +#' ## For demo, a temp. file path is created with the file extension .xlsx +#' xlsx_file <- tempfile(fileext = ".xlsx") +#' export(list(mtcars1 = mtcars[1:10,], +#' mtcars2 = mtcars[11:20,], +#' mtcars3 = mtcars[21:32,]), +#' xlsx_file +#' ) +#' +#' # import a single file from multi-object workbook +#' import(xlsx_file, sheet = "mtcars1") +#' # import all worksheets, the return value is a list +#' import_list(xlsx_file) + #' library('datasets') -#' export(list(mtcars1 = mtcars[1:10,], +#' export(list(mtcars1 = mtcars[1:10,], #' mtcars2 = mtcars[11:20,], #' mtcars3 = mtcars[21:32,]), #' xlsx_file <- tempfile(fileext = ".xlsx") #' ) -#' +#' #' # import all worksheets -#' mylist <- import_list(xlsx_file) -#' +#' list_of_dfs <- import_list(xlsx_file) +#' #' # re-export as separate named files -#' csv_files1 <- sapply(1:3, function(x) tempfile(fileext = paste0("-", x, ".csv"))) -#' export_list(mylist, file = csv_files1) -#' -#' # re-export as separate files using a name pattern -#' export_list(mylist, file = csv_files2 <- tempfile(fileext = "%s.csv")) -#' -#' # cleanup -#' unlink(xlsx_file) -#' unlink(csv_files1) -#' unlink(csv_files2) -#' +#' +#' ## export_list(list_of_dfs, file = c("file1.csv", "file2.csv", "file3.csv")) +#' +#' # re-export as separate files using a name pattern; using the names in the list +#' ## This will be written as "mtcars1.csv", "mtcars2.csv", "mtcars3.csv" +#' +#' ## export_list(list_of_dfs, file = "%s.csv") #' @seealso [import()], [import_list()], [export()] #' @export -export_list <- +export_list <- function( x, - file, + file, ... ) { if (inherits(x, "data.frame")) { diff --git a/R/import.R b/R/import.R index e3c01c5..77cfd48 100644 --- a/R/import.R +++ b/R/import.R @@ -56,38 +56,34 @@ #' #' @note For csv and txt files with row names exported from [export()], it may be helpful to specify `row.names` as the column of the table which contain row names. See example below. #' @examples -#' # create CSV to import -#' export(iris, csv_file <- tempfile(fileext = ".csv")) +#' ## For demo, a temp. file path is created with the file extension .csv +#' csv_file <- tempfile(fileext = ".csv") +#' ## .xlsx +#' xlsx_file <- tempfile(fileext = ".xlsx") +#' ## create CSV to import +#' export(iris, csv_file) +#' ## specify `format` to override default format: see export() +#' export(iris, xlsx_file, format = "csv") #' -#' # specify `format` to override default format -#' export(iris, tsv_file <- tempfile(fileext = ".tsv"), format = "csv") -#' stopifnot(identical(import(csv_file), import(tsv_file, format = "csv"))) +#' ## basic +#' import(csv_file) #' -#' # import CSV as a `data.table` -#' stopifnot(inherits(import(csv_file, setclass = "data.table"), "data.table")) +#' ## You can certainly import your data with the file name, which is not a variable: +#' ## import("starwars.csv"); import("mtcars.xlsx") #' -#' # pass arguments to underlying import function -#' iris1 <- import(csv_file) -#' identical(names(iris), names(iris1)) +#' ## Override the default format +#' ## import(xlsx_file) # Error, it is actually not an Excel file +#' import(xlsx_file, format = "csv") #' -#' export(iris, csv_file2 <- tempfile(fileext = ".csv"), col.names = FALSE) -#' iris2 <- import(csv_file2) -#' identical(names(iris), names(iris2)) +#' ## import CSV as a `data.table` +#' import(csv_file, setclass = "data.table") #' -#' # set class for the response data.frame as "tbl_df" (from dplyr) -#' stopifnot(inherits(import(csv_file, setclass = "tbl_df"), "tbl_df")) -#' -#' # non-data frame formats supported for RDS, Rdata, and JSON -#' export(list(mtcars, iris), rds_file <- tempfile(fileext = ".rds")) -#' li <- import(rds_file) -#' identical(names(mtcars), names(li[[1]])) -#' -#' # cleanup -#' unlink(csv_file) -#' unlink(csv_file2) -#' unlink(tsv_file) -#' unlink(rds_file) +#' ## import CSV as a tibble (or "tbl_df") +#' import(csv_file, setclass = "tbl_df") #' +#' ## pass arguments to underlying import function +#' ## data.table::fread is the underlying import function and `nrows` is its argument +#' import(csv_file, nrows = 20) #' @seealso [import_list()], [characterize()], [gather_attrs()], [export()], [convert()] #' @importFrom tools file_ext file_path_sans_ext #' @importFrom stats na.omit setNames diff --git a/R/import_list.R b/R/import_list.R index 277c2ea..264b589 100644 --- a/R/import_list.R +++ b/R/import_list.R @@ -9,35 +9,21 @@ #' @inheritParams import #' @return If `rbind=FALSE` (the default), a list of a data frames. Otherwise, that list is passed to [data.table::rbindlist()] with `fill = TRUE` and returns a data frame object of class set by the `setclass` argument; if this operation fails, the list is returned. #' @examples -#' library('datasets') +#' ## For demo, a temp. file path is created with the file extension .xlsx +#' xlsx_file <- tempfile(fileext = ".xlsx") #' export(list(mtcars1 = mtcars[1:10,], #' mtcars2 = mtcars[11:20,], #' mtcars3 = mtcars[21:32,]), -#' xlsx_file <- tempfile(fileext = ".xlsx") +#' xlsx_file #' ) #' #' # import a single file from multi-object workbook -#' str(import(xlsx_file, which = "mtcars1")) -#' -#' # import all worksheets -#' str(import_list(xlsx_file), 1) -#' -#' # import and rbind all worksheets -#' mtcars2 <- import_list(xlsx_file, rbind = TRUE) -#' all.equal(mtcars2[,-12], mtcars, check.attributes = FALSE) -#' -#' # import multiple files -#' wd <- getwd() -#' setwd(tempdir()) -#' export(mtcars, "mtcars1.csv") -#' export(mtcars, "mtcars2.csv") -#' str(import_list(dir(pattern = "csv$")), 1) -#' unlink(c("mtcars1.csv", "mtcars2.csv")) -#' setwd(wd) -#' -#' # cleanup -#' unlink(xlsx_file) +#' import(xlsx_file, sheet = "mtcars1") +#' # import all worksheets, the return value is a list +#' import_list(xlsx_file) #' +#' # import and rbind all worksheets, the return valye is a data frame +#' import_list(xlsx_file, rbind = TRUE) #' @seealso [import()], [export_list()], [export()] #' @export import_list <- diff --git a/man/characterize.Rd b/man/characterize.Rd index cfe03c8..6eed1a8 100644 --- a/man/characterize.Rd +++ b/man/characterize.Rd @@ -38,24 +38,22 @@ Convert labelled variables to character or factor \code{characterize} converts a vector with a \code{labels} attribute of named levels into a character vector. \code{factorize} does the same but to factors. This can be useful at two stages of a data workflow: (1) importing labelled data from metadata-rich file formats (e.g., Stata or SPSS), and (2) exporting such data to plain text files (e.g., CSV) in a way that preserves information. } \examples{ -# vector method +## vector method x <- structure(1:4, labels = c("A" = 1, "B" = 2, "C" = 3)) characterize(x) factorize(x) -# data frame method +## data frame method x <- data.frame(v1 = structure(1:4, labels = c("A" = 1, "B" = 2, "C" = 3)), v2 = structure(c(1,0,0,1), labels = c("foo" = 0, "bar" = 1))) str(factorize(x)) str(characterize(x)) -# comparison of exported file contents -import(export(x, csv_file <- tempfile(fileext = ".csv"))) +## Application +csv_file <- tempfile(fileext = ".csv") +## comparison of exported file contents +import(export(x, csv_file)) import(export(factorize(x), csv_file)) - -# cleanup -unlink(csv_file) - } \seealso{ \code{\link[=gather_attrs]{gather_attrs()}} diff --git a/man/convert.Rd b/man/convert.Rd index 867292a..8be2fc5 100644 --- a/man/convert.Rd +++ b/man/convert.Rd @@ -22,33 +22,30 @@ A character string containing the name of the output file (invisibly). This function constructs a data frame from a data file using \code{\link[=import]{import()}} and uses \code{\link[=export]{export()}} to write the data to disk in the format indicated by the file extension. } \examples{ -# create a file to convert -export(mtcars, dta_file <- tempfile(fileext = ".dta")) - -# convert Stata to CSV and open converted file -convert(dta_file, csv_file <- tempfile(fileext = ".csv")) -head(import(csv_file)) - -# correct an erroneous file format -export(mtcars, csv_file2 <- tempfile(fileext = ".csv"), format = "tsv") -convert(csv_file2, csv_file, in_opts = list(format = "tsv")) - -# convert serialized R data.frame to JSON -export(mtcars, rds_file <- tempfile(fileext = ".rds")) -convert(rds_file, json_file <- tempfile(fileext = ".json")) - -# cleanup -unlink(csv_file) -unlink(csv_file2) -unlink(rds_file) -unlink(dta_file) -unlink(json_file) - -\dontrun{\donttest{ -# convert from the command line: -## Rscript -e "rio::convert('mtcars.dta', 'mtcars.csv')" -}} +## For demo, a temp. file path is created with the file extension .dta (Stata) +dta_file <- tempfile(fileext = ".dta") +## .csv +csv_file <- tempfile(fileext = ".csv") +## .xlsx +xlsx_file <- tempfile(fileext = ".xlsx") + + +## Create a Stata data file +export(mtcars, dta_file) +## convert Stata to CSV and open converted file +convert(dta_file, csv_file) +import(csv_file) + +## correct an erroneous file format +export(mtcars, xlsx_file, format = "tsv") ## DON'T DO THIS +## import(xlsx_file) ## ERROR +## convert the file by specifying `in_opts` +convert(xlsx_file, xlsx_file, in_opts = list(format = "tsv")) +import(xlsx_file) + +## convert from the command line: +## Rscript -e "rio::convert('mtcars.dta', 'mtcars.csv')" } \seealso{ \href{https://lbraglia.github.io/}{Luca Braglia} has created a Shiny app called \href{https://github.com/lbraglia/rioweb}{rioweb} that provides access to the file conversion features of rio through a web browser. diff --git a/man/export.Rd b/man/export.Rd index ac0aff4..e2f8002 100644 --- a/man/export.Rd +++ b/man/export.Rd @@ -63,75 +63,32 @@ When exporting a data set that contains label attributes (e.g., if imported from Use \code{\link[=export_list]{export_list()}} to export a list of dataframes to separate files. } \examples{ -library("datasets") -# specify only `file` argument -export(mtcars, f1 <- tempfile(fileext = ".csv")) +## For demo, a temp. file path is created with the file extension .csv +csv_file <- tempfile(fileext = ".csv") +## .xlsx +xlsx_file <- tempfile(fileext = ".xlsx") -\dontrun{ -wd <- getwd() -setwd(tempdir()) -# Stata does not recognize variables names with '.' -export(mtcars, f2 <- tempfile(fileext = ".dta")) +## create CSV to import +export(iris, csv_file) -# specify only `format` argument -f2 \%in\% tempdir() -export(mtcars, format = "stata") -"mtcars.dta" \%in\% dir() +## You can certainly export your data with the file name, which is not a variable: +## import(mtcars, "car_data.csv") -setwd(wd) -} -# specify `file` and `format` to override default format -export(mtcars, file = f3 <- tempfile(fileext = ".txt"), format = "csv") - -# export multiple objects to Rdata -export(list(mtcars = mtcars, iris = iris), f4 <- tempfile(fileext = ".rdata")) -export(c("mtcars", "iris"), f4) - -# export to non-data frame R object to RDS or JSON -export(mtcars$cyl, f5 <- tempfile(fileext = ".rds")) -export(list(iris, mtcars), f6 <- tempfile(fileext = ".json")) - -# pass arguments to underlying export function -export(mtcars, f7 <- tempfile(fileext = ".csv"), col.names = FALSE) +## pass arguments to the underlying function +## data.table::fwrite is the underlying function and `col.names` is an argument +export(iris, csv_file, col.names = FALSE) -# write data to .R syntax file and append additional data -export(mtcars, file = f8 <- tempfile(fileext = ".R"), format = "dump") -export(mtcars, file = f8, format = "dump", append = TRUE) -source(f8, echo = TRUE) +## export a list of data frames as worksheets +export(list(a = mtcars, b = iris), xlsx_file) -# write to an Excel workbook -\dontrun{ - ## export a single data frame - export(mtcars, f9 <- tempfile(fileext = ".xlsx")) - - ## export NAs to Excel as missing via args passed to `...` - mtcars$drat <- NA_real_ - mtcars \%>\% export(f10 <- tempfile(fileext = ".xlsx"), keepNA = TRUE) - - ## export a list of data frames as worksheets - export(list(a = mtcars, b = iris), f11 <- tempfile(fileext = ".xlsx")) - - ## export, adding a new sheet to an existing workbook - export(iris, f12 <- tempfile(fileext = ".xlsx"), which = "iris") -} +# NOT RECOMMENDED -# write data to a zip-compressed CSV -export(mtcars, f13 <- tempfile(fileext = ".csv.zip")) +## specify `format` to override default format +export(iris, xlsx_file, format = "csv") ## That's confusing +## You can also specify only the format; in the following case +## "mtcars.dta" is written [also confusing] -# cleanup -unlink(f1) -# unlink(f2) -unlink(f3) -unlink(f4) -unlink(f5) -unlink(f6) -unlink(f7) -unlink(f8) -# unlink(f9) -# unlink(f10) -# unlink(f11) -# unlink(f12) -# unlink(f13) +## export(mtcars, format = "stata") } \seealso{ \code{\link[=characterize]{characterize()}}, \code{\link[=import]{import()}}, \code{\link[=convert]{convert()}}, \code{\link[=export_list]{export_list()}} diff --git a/man/export_list.Rd b/man/export_list.Rd index 297ee88..71a9418 100644 --- a/man/export_list.Rd +++ b/man/export_list.Rd @@ -23,28 +23,36 @@ Use \code{\link[=export]{export()}} to export a list of data frames to a vector \code{\link[=export]{export()}} can export a list of data frames to a single multi-dataset file (e.g., an Rdata or Excel .xlsx file). Use \code{export_list} to export such a list to \emph{multiple} files. } \examples{ +## For demo, a temp. file path is created with the file extension .xlsx +xlsx_file <- tempfile(fileext = ".xlsx") +export(list(mtcars1 = mtcars[1:10,], + mtcars2 = mtcars[11:20,], + mtcars3 = mtcars[21:32,]), + xlsx_file +) + +# import a single file from multi-object workbook +import(xlsx_file, sheet = "mtcars1") +# import all worksheets, the return value is a list +import_list(xlsx_file) library('datasets') -export(list(mtcars1 = mtcars[1:10,], +export(list(mtcars1 = mtcars[1:10,], mtcars2 = mtcars[11:20,], mtcars3 = mtcars[21:32,]), xlsx_file <- tempfile(fileext = ".xlsx") ) # import all worksheets -mylist <- import_list(xlsx_file) +list_of_dfs <- import_list(xlsx_file) # re-export as separate named files -csv_files1 <- sapply(1:3, function(x) tempfile(fileext = paste0("-", x, ".csv"))) -export_list(mylist, file = csv_files1) -# re-export as separate files using a name pattern -export_list(mylist, file = csv_files2 <- tempfile(fileext = "\%s.csv")) +## export_list(list_of_dfs, file = c("file1.csv", "file2.csv", "file3.csv")) -# cleanup -unlink(xlsx_file) -unlink(csv_files1) -unlink(csv_files2) +# re-export as separate files using a name pattern; using the names in the list +## This will be written as "mtcars1.csv", "mtcars2.csv", "mtcars3.csv" +## export_list(list_of_dfs, file = "\%s.csv") } \seealso{ \code{\link[=import]{import()}}, \code{\link[=import_list]{import_list()}}, \code{\link[=export]{export()}} diff --git a/man/import.Rd b/man/import.Rd index 09af0c7..4674844 100644 --- a/man/import.Rd +++ b/man/import.Rd @@ -75,38 +75,34 @@ After importing metadata-rich file formats (e.g., from Stata or SPSS), it may be For csv and txt files with row names exported from \code{\link[=export]{export()}}, it may be helpful to specify \code{row.names} as the column of the table which contain row names. See example below. } \examples{ -# create CSV to import -export(iris, csv_file <- tempfile(fileext = ".csv")) - -# specify `format` to override default format -export(iris, tsv_file <- tempfile(fileext = ".tsv"), format = "csv") -stopifnot(identical(import(csv_file), import(tsv_file, format = "csv"))) - -# import CSV as a `data.table` -stopifnot(inherits(import(csv_file, setclass = "data.table"), "data.table")) - -# pass arguments to underlying import function -iris1 <- import(csv_file) -identical(names(iris), names(iris1)) - -export(iris, csv_file2 <- tempfile(fileext = ".csv"), col.names = FALSE) -iris2 <- import(csv_file2) -identical(names(iris), names(iris2)) - -# set class for the response data.frame as "tbl_df" (from dplyr) -stopifnot(inherits(import(csv_file, setclass = "tbl_df"), "tbl_df")) - -# non-data frame formats supported for RDS, Rdata, and JSON -export(list(mtcars, iris), rds_file <- tempfile(fileext = ".rds")) -li <- import(rds_file) -identical(names(mtcars), names(li[[1]])) - -# cleanup -unlink(csv_file) -unlink(csv_file2) -unlink(tsv_file) -unlink(rds_file) - +## For demo, a temp. file path is created with the file extension .csv +csv_file <- tempfile(fileext = ".csv") +## .xlsx +xlsx_file <- tempfile(fileext = ".xlsx") +## create CSV to import +export(iris, csv_file) +## specify `format` to override default format: see export() +export(iris, xlsx_file, format = "csv") + +## basic +import(csv_file) + +## You can certainly import your data with the file name, which is not a variable: +## import("starwars.csv"); import("mtcars.xlsx") + +## Override the default format +## import(xlsx_file) # Error, it is actually not an Excel file +import(xlsx_file, format = "csv") + +## import CSV as a `data.table` +import(csv_file, setclass = "data.table") + +## import CSV as a tibble (or "tbl_df") +import(csv_file, setclass = "tbl_df") + +## pass arguments to underlying import function +## data.table::fread is the underlying import function and `nrows` is its argument +import(csv_file, nrows = 20) } \seealso{ \code{\link[=import_list]{import_list()}}, \code{\link[=characterize]{characterize()}}, \code{\link[=gather_attrs]{gather_attrs()}}, \code{\link[=export]{export()}}, \code{\link[=convert]{convert()}} diff --git a/man/import_list.Rd b/man/import_list.Rd index 99e1779..3310cf0 100644 --- a/man/import_list.Rd +++ b/man/import_list.Rd @@ -36,35 +36,21 @@ If \code{rbind=FALSE} (the default), a list of a data frames. Otherwise, that li Use \code{\link[=import]{import()}} to import a list of data frames from a vector of file names or from a multi-object file (Excel workbook, .Rdata file, zip directory, or HTML file) } \examples{ -library('datasets') +## For demo, a temp. file path is created with the file extension .xlsx +xlsx_file <- tempfile(fileext = ".xlsx") export(list(mtcars1 = mtcars[1:10,], mtcars2 = mtcars[11:20,], mtcars3 = mtcars[21:32,]), - xlsx_file <- tempfile(fileext = ".xlsx") + xlsx_file ) # import a single file from multi-object workbook -str(import(xlsx_file, which = "mtcars1")) - -# import all worksheets -str(import_list(xlsx_file), 1) - -# import and rbind all worksheets -mtcars2 <- import_list(xlsx_file, rbind = TRUE) -all.equal(mtcars2[,-12], mtcars, check.attributes = FALSE) - -# import multiple files -wd <- getwd() -setwd(tempdir()) -export(mtcars, "mtcars1.csv") -export(mtcars, "mtcars2.csv") -str(import_list(dir(pattern = "csv$")), 1) -unlink(c("mtcars1.csv", "mtcars2.csv")) -setwd(wd) - -# cleanup -unlink(xlsx_file) +import(xlsx_file, sheet = "mtcars1") +# import all worksheets, the return value is a list +import_list(xlsx_file) +# import and rbind all worksheets, the return valye is a data frame +import_list(xlsx_file, rbind = TRUE) } \seealso{ \code{\link[=import]{import()}}, \code{\link[=export_list]{export_list()}}, \code{\link[=export]{export()}} From 0bb9d618bb8084a772aa46585d85a5c4b03ce395 Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Fri, 1 Sep 2023 14:30:01 +0200 Subject: [PATCH 34/44] Make ... pass Ref #318 (#330) * Make ... pass Ref #318 * Update NEWS.md [no ci] --- NEWS.md | 2 ++ R/export_methods.R | 4 ++-- tests/testthat/test_format_feather.R | 8 ++++++++ tests/testthat/test_format_ods.R | 7 +++++++ 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/NEWS.md b/NEWS.md index c327d75..498ee56 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,6 +1,8 @@ * Stop loading the entire namespace of a suggested package when it is available #296 * Unexport objects: `.import`, `.export`, `is_file_text`; remove documentation for `arg_reconcile` #321 * Update Examples to make them more realistic #327 +* Bug fixes + - ... is correctly passed for exporting ODS and feather #318 * Declutter - remove the obsolete data.table option #323 - write all documentation blocks in markdown #311 diff --git a/R/export_methods.R b/R/export_methods.R index d85afe2..d1fef11 100644 --- a/R/export_methods.R +++ b/R/export_methods.R @@ -146,7 +146,7 @@ export_delim <- function(file, x, fwrite = TRUE, sep = "\t", row.names = FALSE, #' @export .export.rio_feather <- function(file, x, ...) { .check_pkg_availability("feather") - feather::write_feather(x = x, path = file) + feather::write_feather(x = x, path = file, ...) } #' @export @@ -249,7 +249,7 @@ export_delim <- function(file, x, fwrite = TRUE, sep = "\t", row.names = FALSE, #' @export .export.rio_ods <- function(file, x, ...) { .check_pkg_availability("readODS") - readODS::write_ods(x = x, path = file) + readODS::write_ods(x = x, path = file, ...) } #' @export diff --git a/tests/testthat/test_format_feather.R b/tests/testthat/test_format_feather.R index 02cdec4..1f7bf29 100644 --- a/tests/testthat/test_format_feather.R +++ b/tests/testthat/test_format_feather.R @@ -10,4 +10,12 @@ test_that("Import from feather", { skip_if_not_installed(pkg="feather") expect_true(is.data.frame(import("iris.feather"))) }) + +test_that("... correctly passed, #318", { + skip_if_not_installed(pkg="feather") + ## actually feather::write_feather has only two arguments (as of 2023-09-01) + ## it is more for possible future expansion + expect_error(export(mtcars, "mtcars.feather", hello = 42)) +}) + unlink("iris.feather") diff --git a/tests/testthat/test_format_ods.R b/tests/testthat/test_format_ods.R index ae3f050..2d8b3e6 100644 --- a/tests/testthat/test_format_ods.R +++ b/tests/testthat/test_format_ods.R @@ -22,4 +22,11 @@ test_that("Export to ODS", { expect_true(export(iris, "iris.ods") %in% dir()) }) +test_that("... correctly passed #318", { + skip_if_not_installed(pkg = "readODS") + x <- tempfile(fileext = ".ods") + rio::export(mtcars, file = x, sheet = "mtcars") + expect_equal(readODS::list_ods_sheets(x), "mtcars") +}) + unlink("iris.ods") From 14e3bb01c98845fa6d3fbddd41d2220462ced045 Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Fri, 1 Sep 2023 18:14:12 +0200 Subject: [PATCH 35/44] Fix #318 (#331) * Does this work 3.6 Windows * Fix #318 * fix yaml? JSON is working now, why not YAML? * Use yaml::write_yaml * Disable YAML test; add disclaimer * Update NEWS.md [no ci] --- NEWS.md | 4 ++++ R/export.R | 2 +- R/export_methods.R | 6 +++--- R/utils.R | 4 ++++ man/export.Rd | 2 +- tests/testthat/test_format_json.R | 8 ++++++++ tests/testthat/test_format_yml.R | 10 ++++++++++ 7 files changed, 31 insertions(+), 5 deletions(-) diff --git a/NEWS.md b/NEWS.md index 498ee56..aba8160 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,6 +3,10 @@ * Update Examples to make them more realistic #327 * Bug fixes - ... is correctly passed for exporting ODS and feather #318 + - POTENTIALLY BREAKING: JSON are exported in UTF-8 by default; solved encoding issues on + Windows R < 4.2. This won't affect any modern R installation where UTF-8 is the default. #318 + - POTENTIALLY BREAKING: YAML are exported using yaml::write_yaml(). But it can't pass the UTF-8 check on older systems. + Disclaimer added. #318 * Declutter - remove the obsolete data.table option #323 - write all documentation blocks in markdown #311 diff --git a/R/export.R b/R/export.R index 89d932c..cdb47e8 100644 --- a/R/export.R +++ b/R/export.R @@ -38,7 +38,7 @@ #' \item OpenDocument Spreadsheet (.ods), using [readODS::write_ods()]. (Currently only single-sheet exports are supported.) #' \item HTML (.html), using a custom method based on [xml2::xml_add_child()] to create a simple HTML table and [xml2::write_xml()] to write to disk. #' \item XML (.xml), using a custom method based on [xml2::xml_add_child()] to create a simple XML tree and [xml2::write_xml()] to write to disk. -#' \item YAML (.yml), using [yaml::as.yaml()] +#' \item YAML (.yml), using [yaml::write_yaml()], default to write the content with UTF-8. Might not work on some older systems, e.g. default Windows locale for R <= 4.2. #' \item Clipboard export (on Windows and Mac OS), using [utils::write.table()] with `row.names = FALSE` #' } #' diff --git a/R/export_methods.R b/R/export_methods.R index d1fef11..348c8e5 100644 --- a/R/export_methods.R +++ b/R/export_methods.R @@ -104,7 +104,7 @@ export_delim <- function(file, x, fwrite = TRUE, sep = "\t", row.names = FALSE, ' colClasses = c("', paste0(col_classes, collapse = '","') ,'"))\n'), domain = NA) } } - cat(paste0("#", capture.output(write.csv(dict, row.names = FALSE, quote = FALSE))), file = file, sep = "\n") + .write_as_utf8(paste0("#", capture.output(write.csv(dict, row.names = FALSE, quote = FALSE))), file = file, sep = "\n") utils::write.table(dat, file = file, append = TRUE, row.names = row.names, sep = sep, quote = quote, col.names = col.names, ...) } @@ -205,7 +205,7 @@ export_delim <- function(file, x, fwrite = TRUE, sep = "\t", row.names = FALSE, #' @export .export.rio_json <- function(file, x, ...) { .check_pkg_availability("jsonlite") - cat(jsonlite::toJSON(x, ...), file = file) + .write_as_utf8(jsonlite::toJSON(x, ...), file = file) } #' @importFrom foreign write.arff @@ -303,7 +303,7 @@ export_delim <- function(file, x, fwrite = TRUE, sep = "\t", row.names = FALSE, #' @export .export.rio_yml <- function(file, x, ...) { .check_pkg_availability("yaml") - cat(yaml::as.yaml(x, ...), file = file) + yaml::write_yaml(x, file = file, ...) } #' @export diff --git a/R/utils.R b/R/utils.R index a7dee6b..2d130e9 100644 --- a/R/utils.R +++ b/R/utils.R @@ -125,3 +125,7 @@ twrap <- function(value, tag) { } return(invisible(NULL)) } + +.write_as_utf8 <- function(text, file, sep = "") { + writeLines(enc2utf8(text), con = file, sep = sep, useBytes = TRUE) +} diff --git a/man/export.Rd b/man/export.Rd index e2f8002..8797764 100644 --- a/man/export.Rd +++ b/man/export.Rd @@ -54,7 +54,7 @@ The output file can be to a compressed directory, simply by adding an appropriat \item OpenDocument Spreadsheet (.ods), using \code{\link[readODS:write_ods]{readODS::write_ods()}}. (Currently only single-sheet exports are supported.) \item HTML (.html), using a custom method based on \code{\link[xml2:xml_replace]{xml2::xml_add_child()}} to create a simple HTML table and \code{\link[xml2:write_xml]{xml2::write_xml()}} to write to disk. \item XML (.xml), using a custom method based on \code{\link[xml2:xml_replace]{xml2::xml_add_child()}} to create a simple XML tree and \code{\link[xml2:write_xml]{xml2::write_xml()}} to write to disk. -\item YAML (.yml), using \code{\link[yaml:as.yaml]{yaml::as.yaml()}} +\item YAML (.yml), using \code{\link[yaml:write_yaml]{yaml::write_yaml()}}, default to write the content with UTF-8. Might not work on some older systems, e.g. default Windows locale for R <= 4.2. \item Clipboard export (on Windows and Mac OS), using \code{\link[utils:write.table]{utils::write.table()}} with \code{row.names = FALSE} } diff --git a/tests/testthat/test_format_json.R b/tests/testthat/test_format_json.R index 5eb30ab..0848dda 100644 --- a/tests/testthat/test_format_json.R +++ b/tests/testthat/test_format_json.R @@ -18,5 +18,13 @@ test_that("Export to JSON (non-data frame)", { expect_true(length(import("list.json")) == 2L) }) +test_that("utf-8", { + content <- c("\"", "\u010d", "\u0161", "\u00c4", "\u5b57", "\u30a2", "\u30a2\u30e0\u30ed") + x <- data.frame(col = content) + tempjson <- tempfile(fileext = ".json") + y <- import(export(x, tempjson)) + testthat::expect_equal(content, y$col) +}) + unlink("iris.json") unlink("list.json") diff --git a/tests/testthat/test_format_yml.R b/tests/testthat/test_format_yml.R index ca63f9c..ac441a6 100644 --- a/tests/testthat/test_format_yml.R +++ b/tests/testthat/test_format_yml.R @@ -13,4 +13,14 @@ test_that("Import from YAML", { expect_identical(import("iris.yml")$Species, as.character(iris$Species)) }) +test_that("utf-8", { + skip_if(getRversion() <= "4.2") + content <- c("\"", "\u010d", "\u0161", "\u00c4", "\u5b57", "\u30a2", "\u30a2\u30e0\u30ed") + x <- data.frame(col = content) + tempyaml <- tempfile(fileext = ".yaml") + y <- import(export(x, tempyaml)) + testthat::expect_equal(content, y$col) +}) + + unlink("iris.yml") From 6af91048cdeffb221e12056ec75087b3b7148d14 Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Sun, 3 Sep 2023 11:53:51 +0200 Subject: [PATCH 36/44] Zap all sapply fix #319 (#332) --- R/export_methods.R | 2 +- R/fwf2.R | 18 +++++++++--------- R/gather_attrs.R | 2 +- R/import_list.R | 8 ++++---- R/import_methods.R | 24 ++++++++++-------------- 5 files changed, 25 insertions(+), 29 deletions(-) diff --git a/R/export_methods.R b/R/export_methods.R index 348c8e5..7c99c78 100644 --- a/R/export_methods.R +++ b/R/export_methods.R @@ -86,7 +86,7 @@ export_delim <- function(file, x, fwrite = TRUE, sep = "\t", row.names = FALSE, }) dat <- do.call(cbind, dat) n <- nchar(dat[1,]) + c(rep(nchar(sep), ncol(dat)-1), 0) - col_classes <- sapply(x, class) + col_classes <- vapply(x, class, character(1)) col_classes[col_classes == "factor"] <- "integer" dict <- cbind.data.frame(variable = names(n), class = col_classes, diff --git a/R/fwf2.R b/R/fwf2.R index 4bcb401..1eab507 100644 --- a/R/fwf2.R +++ b/R/fwf2.R @@ -1,6 +1,5 @@ #' @importFrom utils read.table -read.fwf2 <- function (file, widths, header = FALSE, sep = "\t", skip = 0, n = -1, quote = "", stringsAsFactors = FALSE, ...) -{ +read.fwf2 <- function (file, widths, header = FALSE, sep = "\t", skip = 0, n = -1, quote = "", stringsAsFactors = FALSE, ...) { doone <- function(x) { x <- substring(x, first, last) x[!nzchar(x)] <- NA_character_ @@ -21,7 +20,7 @@ read.fwf2 <- function (file, widths, header = FALSE, sep = "\t", skip = 0, n = - open(file, "rt") on.exit(close(file), add = TRUE) } - if (skip) + if (skip) readLines(file, n = skip) if (header) { headerline <- readLines(file, n = 1L) @@ -31,8 +30,8 @@ read.fwf2 <- function (file, widths, header = FALSE, sep = "\t", skip = 0, n = - nread <- length(raw) if (recordlength > 1L && nread%%recordlength) { raw <- raw[1L:(nread - nread%%recordlength)] - warning(sprintf(ngettext(nread%%recordlength, "last record incomplete, %d line discarded", - "last record incomplete, %d lines discarded"), + warning(sprintf(ngettext(nread%%recordlength, "last record incomplete, %d line discarded", + "last record incomplete, %d lines discarded"), nread%%recordlength), domain = NA) } if (recordlength > 1L) { @@ -42,9 +41,10 @@ read.fwf2 <- function (file, widths, header = FALSE, sep = "\t", skip = 0, n = - st <- c(1L, 1L + cumsum(widths)) first <- st[-length(st)][!drop] last <- cumsum(widths)[!drop] - if(header) - text <- c(headerline, sapply(raw, doone)) - else - text <- sapply(raw, doone) + if(header) { + text <- c(headerline, vapply(raw, doone, character(1))) + } else { + text <- vapply(raw, doone, character(1)) + } read.table(text = text, header = header, sep = sep, quote = quote, stringsAsFactors = stringsAsFactors, ...) } diff --git a/R/gather_attrs.R b/R/gather_attrs.R index 53e7c06..accefc9 100644 --- a/R/gather_attrs.R +++ b/R/gather_attrs.R @@ -37,7 +37,7 @@ gather_attrs <- function(x) { } rm(f) } - if (any(sapply(varattrs, length))) { + if (any(vapply(varattrs, length, integer(1)))) { attrnames <- sort(unique(unlist(lapply(varattrs, names)))) outattrs <- stats::setNames(lapply(attrnames, function(z) { stats::setNames(lapply(varattrs, `[[`, z), names(x)) diff --git a/R/import_list.R b/R/import_list.R index 264b589..71fe6c2 100644 --- a/R/import_list.R +++ b/R/import_list.R @@ -38,7 +38,7 @@ function(file, setclass <- NULL } strip_exts <- function(file) { - sapply(file, function(x) tools::file_path_sans_ext(basename(x))) + vapply(file, function(x) tools::file_path_sans_ext(basename(x)), character(1)) } if (length(file) > 1) { names(file) <- strip_exts(file) @@ -65,9 +65,9 @@ function(file, if (missing(which)) { which <- seq_along(tables) } - whichnames <- sapply(xml2::xml_attrs(tables[which]), - function(x) if ("class" %in% names(x)) x["class"] else "" - ) + whichnames <- vapply(xml2::xml_attrs(tables[which]), + function(x) if ("class" %in% names(x)) x["class"] else "", + FUN.VALUE = character(1)) names(which) <- whichnames } else if (get_ext(file) %in% c("xls","xlsx")) { .check_pkg_availability("readxl") diff --git a/R/import_methods.R b/R/import_methods.R index 8e80748..4ed2a67 100644 --- a/R/import_methods.R +++ b/R/import_methods.R @@ -394,20 +394,16 @@ function(file, # This is a helper function for .import.rio_html extract_html_row <- function(x, empty_value) { - # Both and are valid for table data, and may be used when - # there is an accented element (e.g. the first row of the table) - to_extract <- x[names(x) %in% c("th", "td")] - # Insert a value into cells that eventually will become empty cells (or they - # will be dropped and the table will not be generated). Note that this more - # complex code for finding the length is required because of html like - #
    - unlist_length <- - sapply( - lapply(to_extract, unlist), - length - ) - to_extract[unlist_length == 0] <- list(empty_value) - unlist(to_extract) + ## Both and are valid for table data, and may be used when + ## there is an accented element (e.g. the first row of the table) + to_extract <- x[names(x) %in% c("th", "td")] + ## Insert a value into cells that eventually will become empty cells (or they + ## will be dropped and the table will not be generated). Note that this more + ## complex code for finding the length is required because of html like + ##
    + unlist_length <- vapply(lapply(to_extract, unlist), length, integer(1)) + to_extract[unlist_length == 0] <- list(empty_value) + unlist(to_extract) } #' @importFrom utils type.convert From 5d28bd6d1360c05d85aae5732d7ac3f27bedfeec Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Sun, 3 Sep 2023 13:56:50 +0200 Subject: [PATCH 37/44] Change the ownership to gesistsa --- DESCRIPTION | 4 ++-- README.Rmd | 2 +- README.md | 2 +- tests/testthat/test_remote.R | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 518e354..c4239af 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -34,8 +34,8 @@ Description: Streamlined data import and export by making assumptions that directly without explicit decompression, and fast import packages are used where appropriate. An additional convenience function, 'convert()', provides a simple method for converting between file types. -URL: https://github.com/chainsawriot/rio -BugReports: https://github.com/chainsawriot/rio/issues +URL: https://github.com/gesistsa/rio +BugReports: https://github.com/gesistsa/rio/issues Depends: R (>= 3.6) Imports: diff --git a/README.Rmd b/README.Rmd index 21eae96..4e6b214 100644 --- a/README.Rmd +++ b/README.Rmd @@ -30,7 +30,7 @@ The latest development version on GitHub can be installed using: if (!require("remotes")){ install.packages("remotes") } -remotes::install_github("chainsawriot/rio") +remotes::install_github("gesistsa/rio") ``` Optional: Installation of additional formats (see below: **Supported file formats**) diff --git a/README.md b/README.md index d32c481..85684dc 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ The latest development version on GitHub can be installed using: if (!require("remotes")){ install.packages("remotes") } -remotes::install_github("chainsawriot/rio") +remotes::install_github("gesistsa/rio") ``` Optional: Installation of additional formats (see below: **Supported diff --git a/tests/testthat/test_remote.R b/tests/testthat/test_remote.R index 6ef4e0d..b078b3c 100644 --- a/tests/testthat/test_remote.R +++ b/tests/testthat/test_remote.R @@ -27,7 +27,7 @@ test_that("Import Remote GitHub File", { ## test_that("Import Remote File from Shortened URL", { ## skip_if_not_installed(pkg = "data.table") -## shorturl <- try(import("https://raw.githubusercontent.com/chainsawriot/rio/main/tests/testdata/example.csvy")) +## shorturl <- try(import("https://raw.githubusercontent.com/gesistsa/rio/main/tests/testdata/example.csvy")) ## if (!inherits(shorturl, "try-error")) { ## expect_true(inherits(shorturl, "data.frame"), label = "Import remote file") ## } From 369a03b35221aa525796b777154bc96efc058482 Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Sun, 3 Sep 2023 14:51:58 +0200 Subject: [PATCH 38/44] Remove code meta [no ci] --- codemeta.json | 480 -------------------------------------------------- 1 file changed, 480 deletions(-) delete mode 100644 codemeta.json diff --git a/codemeta.json b/codemeta.json deleted file mode 100644 index 4413620..0000000 --- a/codemeta.json +++ /dev/null @@ -1,480 +0,0 @@ -{ - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", - "@type": "SoftwareSourceCode", - "identifier": "rio", - "description": "Streamlined data import and export by making assumptions that the user is probably willing to make: 'import()' and 'export()' determine the data structure from the file extension, reasonable defaults are used for data import and export (e.g., 'stringsAsFactors=FALSE'), web-based import is natively supported (including from SSL/HTTPS), compressed files can be read directly without explicit decompression, and fast import packages are used where appropriate. An additional convenience function, 'convert()', provides a simple method for converting between file types.", - "name": "rio: A Swiss-Army Knife for Data I/O", - "codeRepository": "https://github.com/chainsawriot/rio", - "issueTracker": "https://github.com/chainsawriot/rio/issues", - "license": "https://spdx.org/licenses/GPL-2.0", - "version": "0.5.30", - "programmingLanguage": { - "@type": "ComputerLanguage", - "name": "R", - "url": "https://r-project.org" - }, - "runtimePlatform": "R version 4.3.1 (2023-06-16)", - "provider": { - "@id": "https://cran.r-project.org", - "@type": "Organization", - "name": "Comprehensive R Archive Network (CRAN)", - "url": "https://cran.r-project.org" - }, - "author": [ - { - "@type": "Person", - "givenName": "Chung-hong", - "familyName": "Chan", - "email": "chainsawtiney@gmail.com", - "@id": "https://orcid.org/0000-0002-6232-7530" - }, - { - "@type": "Person", - "givenName": "Thomas J.", - "familyName": "Leeper", - "email": "thosjleeper@gmail.com", - "@id": "https://orcid.org/0000-0003-4097-6326" - } - ], - "contributor": [ - { - "@type": "Person", - "givenName": "Jason", - "familyName": "Becker", - "email": "jason@jbecker.co" - }, - { - "@type": "Person", - "givenName": "Geoffrey CH", - "familyName": "Chan", - "email": "gefchchan@gmail.com" - }, - { - "@type": "Person", - "givenName": "Christopher", - "familyName": "Gandrud" - }, - { - "@type": "Person", - "givenName": "Andrew", - "familyName": "MacDonald" - }, - { - "@type": "Person", - "givenName": "Ista", - "familyName": "Zahn" - }, - { - "@type": "Person", - "givenName": "Stanislaus", - "familyName": "Stadlmann" - }, - { - "@type": "Person", - "givenName": "Ruaridh", - "familyName": "Williamson", - "email": "ruaridh.williamson@gmail.com" - }, - { - "@type": "Person", - "givenName": "Patrick", - "familyName": "Kennedy" - }, - { - "@type": "Person", - "givenName": "Ryan", - "familyName": "Price", - "email": "ryapric@gmail.com" - }, - { - "@type": "Person", - "givenName": "Trevor L", - "familyName": "Davis", - "email": "trevor.l.davis@gmail.com" - }, - { - "@type": "Person", - "givenName": "Nathan", - "familyName": "Day", - "email": "nathancday@gmail.com" - }, - { - "@type": "Person", - "givenName": "Bill", - "familyName": "Denney", - "email": "wdenney@humanpredictions.com", - "@id": "https://orcid.org/0000-0002-5759-428X" - }, - { - "@type": "Person", - "givenName": "Alex", - "familyName": "Bokov", - "email": "alex.bokov@gmail.com", - "@id": "https://orcid.org/0000-0002-0511-9815" - } - ], - "maintainer": [ - { - "@type": "Person", - "givenName": "Chung-hong", - "familyName": "Chan", - "email": "chainsawtiney@gmail.com", - "@id": "https://orcid.org/0000-0002-6232-7530" - } - ], - "softwareSuggestions": [ - { - "@type": "SoftwareApplication", - "identifier": "datasets", - "name": "datasets" - }, - { - "@type": "SoftwareApplication", - "identifier": "bit64", - "name": "bit64", - "provider": { - "@id": "https://cran.r-project.org", - "@type": "Organization", - "name": "Comprehensive R Archive Network (CRAN)", - "url": "https://cran.r-project.org" - }, - "sameAs": "https://CRAN.R-project.org/package=bit64" - }, - { - "@type": "SoftwareApplication", - "identifier": "testthat", - "name": "testthat", - "provider": { - "@id": "https://cran.r-project.org", - "@type": "Organization", - "name": "Comprehensive R Archive Network (CRAN)", - "url": "https://cran.r-project.org" - }, - "sameAs": "https://CRAN.R-project.org/package=testthat" - }, - { - "@type": "SoftwareApplication", - "identifier": "knitr", - "name": "knitr", - "provider": { - "@id": "https://cran.r-project.org", - "@type": "Organization", - "name": "Comprehensive R Archive Network (CRAN)", - "url": "https://cran.r-project.org" - }, - "sameAs": "https://CRAN.R-project.org/package=knitr" - }, - { - "@type": "SoftwareApplication", - "identifier": "magrittr", - "name": "magrittr", - "provider": { - "@id": "https://cran.r-project.org", - "@type": "Organization", - "name": "Comprehensive R Archive Network (CRAN)", - "url": "https://cran.r-project.org" - }, - "sameAs": "https://CRAN.R-project.org/package=magrittr" - }, - { - "@type": "SoftwareApplication", - "identifier": "arrow", - "name": "arrow", - "provider": { - "@id": "https://cran.r-project.org", - "@type": "Organization", - "name": "Comprehensive R Archive Network (CRAN)", - "url": "https://cran.r-project.org" - }, - "sameAs": "https://CRAN.R-project.org/package=arrow" - }, - { - "@type": "SoftwareApplication", - "identifier": "clipr", - "name": "clipr", - "provider": { - "@id": "https://cran.r-project.org", - "@type": "Organization", - "name": "Comprehensive R Archive Network (CRAN)", - "url": "https://cran.r-project.org" - }, - "sameAs": "https://CRAN.R-project.org/package=clipr" - }, - { - "@type": "SoftwareApplication", - "identifier": "feather", - "name": "feather", - "provider": { - "@id": "https://cran.r-project.org", - "@type": "Organization", - "name": "Comprehensive R Archive Network (CRAN)", - "url": "https://cran.r-project.org" - }, - "sameAs": "https://CRAN.R-project.org/package=feather" - }, - { - "@type": "SoftwareApplication", - "identifier": "fst", - "name": "fst", - "provider": { - "@id": "https://cran.r-project.org", - "@type": "Organization", - "name": "Comprehensive R Archive Network (CRAN)", - "url": "https://cran.r-project.org" - }, - "sameAs": "https://CRAN.R-project.org/package=fst" - }, - { - "@type": "SoftwareApplication", - "identifier": "hexView", - "name": "hexView", - "provider": { - "@id": "https://cran.r-project.org", - "@type": "Organization", - "name": "Comprehensive R Archive Network (CRAN)", - "url": "https://cran.r-project.org" - }, - "sameAs": "https://CRAN.R-project.org/package=hexView" - }, - { - "@type": "SoftwareApplication", - "identifier": "jsonlite", - "name": "jsonlite", - "provider": { - "@id": "https://cran.r-project.org", - "@type": "Organization", - "name": "Comprehensive R Archive Network (CRAN)", - "url": "https://cran.r-project.org" - }, - "sameAs": "https://CRAN.R-project.org/package=jsonlite" - }, - { - "@type": "SoftwareApplication", - "identifier": "pzfx", - "name": "pzfx", - "provider": { - "@id": "https://cran.r-project.org", - "@type": "Organization", - "name": "Comprehensive R Archive Network (CRAN)", - "url": "https://cran.r-project.org" - }, - "sameAs": "https://CRAN.R-project.org/package=pzfx" - }, - { - "@type": "SoftwareApplication", - "identifier": "readODS", - "name": "readODS", - "version": ">= 1.6.4", - "provider": { - "@id": "https://cran.r-project.org", - "@type": "Organization", - "name": "Comprehensive R Archive Network (CRAN)", - "url": "https://cran.r-project.org" - }, - "sameAs": "https://CRAN.R-project.org/package=readODS" - }, - { - "@type": "SoftwareApplication", - "identifier": "readr", - "name": "readr", - "provider": { - "@id": "https://cran.r-project.org", - "@type": "Organization", - "name": "Comprehensive R Archive Network (CRAN)", - "url": "https://cran.r-project.org" - }, - "sameAs": "https://CRAN.R-project.org/package=readr" - }, - { - "@type": "SoftwareApplication", - "identifier": "rmarkdown", - "name": "rmarkdown", - "provider": { - "@id": "https://cran.r-project.org", - "@type": "Organization", - "name": "Comprehensive R Archive Network (CRAN)", - "url": "https://cran.r-project.org" - }, - "sameAs": "https://CRAN.R-project.org/package=rmarkdown" - }, - { - "@type": "SoftwareApplication", - "identifier": "rmatio", - "name": "rmatio", - "provider": { - "@id": "https://cran.r-project.org", - "@type": "Organization", - "name": "Comprehensive R Archive Network (CRAN)", - "url": "https://cran.r-project.org" - }, - "sameAs": "https://CRAN.R-project.org/package=rmatio" - }, - { - "@type": "SoftwareApplication", - "identifier": "xml2", - "name": "xml2", - "version": ">= 1.2.0", - "provider": { - "@id": "https://cran.r-project.org", - "@type": "Organization", - "name": "Comprehensive R Archive Network (CRAN)", - "url": "https://cran.r-project.org" - }, - "sameAs": "https://CRAN.R-project.org/package=xml2" - }, - { - "@type": "SoftwareApplication", - "identifier": "yaml", - "name": "yaml", - "provider": { - "@id": "https://cran.r-project.org", - "@type": "Organization", - "name": "Comprehensive R Archive Network (CRAN)", - "url": "https://cran.r-project.org" - }, - "sameAs": "https://CRAN.R-project.org/package=yaml" - } - ], - "softwareRequirements": { - "1": { - "@type": "SoftwareApplication", - "identifier": "R", - "name": "R", - "version": ">= 3.6" - }, - "2": { - "@type": "SoftwareApplication", - "identifier": "tools", - "name": "tools" - }, - "3": { - "@type": "SoftwareApplication", - "identifier": "stats", - "name": "stats" - }, - "4": { - "@type": "SoftwareApplication", - "identifier": "utils", - "name": "utils" - }, - "5": { - "@type": "SoftwareApplication", - "identifier": "foreign", - "name": "foreign", - "provider": { - "@id": "https://cran.r-project.org", - "@type": "Organization", - "name": "Comprehensive R Archive Network (CRAN)", - "url": "https://cran.r-project.org" - }, - "sameAs": "https://CRAN.R-project.org/package=foreign" - }, - "6": { - "@type": "SoftwareApplication", - "identifier": "haven", - "name": "haven", - "version": ">= 1.1.2", - "provider": { - "@id": "https://cran.r-project.org", - "@type": "Organization", - "name": "Comprehensive R Archive Network (CRAN)", - "url": "https://cran.r-project.org" - }, - "sameAs": "https://CRAN.R-project.org/package=haven" - }, - "7": { - "@type": "SoftwareApplication", - "identifier": "curl", - "name": "curl", - "version": ">= 0.6", - "provider": { - "@id": "https://cran.r-project.org", - "@type": "Organization", - "name": "Comprehensive R Archive Network (CRAN)", - "url": "https://cran.r-project.org" - }, - "sameAs": "https://CRAN.R-project.org/package=curl" - }, - "8": { - "@type": "SoftwareApplication", - "identifier": "data.table", - "name": "data.table", - "version": ">= 1.9.8", - "provider": { - "@id": "https://cran.r-project.org", - "@type": "Organization", - "name": "Comprehensive R Archive Network (CRAN)", - "url": "https://cran.r-project.org" - }, - "sameAs": "https://CRAN.R-project.org/package=data.table" - }, - "9": { - "@type": "SoftwareApplication", - "identifier": "readxl", - "name": "readxl", - "version": ">= 0.1.1", - "provider": { - "@id": "https://cran.r-project.org", - "@type": "Organization", - "name": "Comprehensive R Archive Network (CRAN)", - "url": "https://cran.r-project.org" - }, - "sameAs": "https://CRAN.R-project.org/package=readxl" - }, - "10": { - "@type": "SoftwareApplication", - "identifier": "openxlsx", - "name": "openxlsx", - "provider": { - "@id": "https://cran.r-project.org", - "@type": "Organization", - "name": "Comprehensive R Archive Network (CRAN)", - "url": "https://cran.r-project.org" - }, - "sameAs": "https://CRAN.R-project.org/package=openxlsx" - }, - "11": { - "@type": "SoftwareApplication", - "identifier": "tibble", - "name": "tibble", - "provider": { - "@id": "https://cran.r-project.org", - "@type": "Organization", - "name": "Comprehensive R Archive Network (CRAN)", - "url": "https://cran.r-project.org" - }, - "sameAs": "https://CRAN.R-project.org/package=tibble" - }, - "SystemRequirements": null - }, - "fileSize": "319.109KB", - "citation": [ - { - "@type": "SoftwareSourceCode", - "datePublished": "2023", - "author": [ - { - "@type": "Person", - "givenName": "Chung-hong", - "familyName": "Chan" - }, - { - "@type": "Person", - "givenName": "Thomas J.", - "familyName": "Leeper" - }, - { - "@type": "Person", - "givenName": "Jason", - "familyName": "Becker" - } - ], - "name": "rio: A Swiss-army knife for data file I/O", - "url": "https://cran.r-project.org/package=rio" - } - ], - "releaseNotes": "https://github.com/chainsawriot/rio/blob/master/NEWS.md", - "readme": "https://github.com/chainsawriot/rio/blob/main/README.md", - "keywords": ["r", "rio", "stata", "spss", "sas", "excel", "io", "data-science", "data", "cran", "csvy", "csv"], - "relatedLink": "https://CRAN.R-project.org/package=rio" -} From 41ef65e4943d05725d2b32f06cb2485a407563a9 Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Sun, 3 Sep 2023 15:10:33 +0200 Subject: [PATCH 39/44] Zap the last sapply [no ci] --- tests/testthat/test_format_dbf.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testthat/test_format_dbf.R b/tests/testthat/test_format_dbf.R index ef6b781..73ee8ad 100644 --- a/tests/testthat/test_format_dbf.R +++ b/tests/testthat/test_format_dbf.R @@ -10,7 +10,7 @@ test_that("Import from XBASE (.dbf)", { skip_if_not_installed("foreign") d <- import("iris.dbf") expect_true(is.data.frame(d)) - expect_true(!"factor" %in% sapply(d, class)) + expect_true(!"factor" %in% vapply(d, class, character(1))) }) unlink("iris.dbf") From 067a0ae805fdd96816fe9103af9f1843df3584a2 Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Sun, 3 Sep 2023 16:04:49 +0200 Subject: [PATCH 40/44] Fix #301 [no ci] (#333) * Fix #301 * Correct test cases * Rename --- NEWS.md | 1 + R/export.R | 7 ++-- R/export_list.R | 3 +- R/import.R | 4 +- R/import_list.R | 1 + R/utils.R | 14 +++++++ tests/testthat/test_check_file.R | 67 ++++++++++++++++++++++++++++++++ tests/testthat/test_import.r | 12 ------ 8 files changed, 90 insertions(+), 19 deletions(-) create mode 100644 tests/testthat/test_check_file.R delete mode 100644 tests/testthat/test_import.r diff --git a/NEWS.md b/NEWS.md index aba8160..0d0b4a2 100644 --- a/NEWS.md +++ b/NEWS.md @@ -7,6 +7,7 @@ Windows R < 4.2. This won't affect any modern R installation where UTF-8 is the default. #318 - POTENTIALLY BREAKING: YAML are exported using yaml::write_yaml(). But it can't pass the UTF-8 check on older systems. Disclaimer added. #318 + - More check for the `file` argument #301 * Declutter - remove the obsolete data.table option #323 - write all documentation blocks in markdown #311 diff --git a/R/export.R b/R/export.R index cdb47e8..428e255 100644 --- a/R/export.R +++ b/R/export.R @@ -77,15 +77,16 @@ #' @importFrom haven labelled #' @export export <- function(x, file, format, ...) { - if (missing(file) & missing(format)) { + .check_file(file, single_only = TRUE) + if (missing(file) && missing(format)) { stop("Must specify 'file' and/or 'format'") - } else if (!missing(file) & !missing(format)) { + } else if (!missing(file) && !missing(format)) { fmt <- tolower(format) cfile <- file f <- find_compress(file) file <- f$file compress <- f$compress - } else if (!missing(file) & missing(format)) { + } else if (!missing(file) && missing(format)) { cfile <- file f <- find_compress(file) file <- f$file diff --git a/R/export_list.R b/R/export_list.R index 28f0dda..aa6d0bc 100644 --- a/R/export_list.R +++ b/R/export_list.R @@ -44,7 +44,8 @@ function( x, file, ... -) { + ) { + .check_file(file, single_only = FALSE) if (inherits(x, "data.frame")) { stop("'x' must be a list. Perhaps you want export()?") } diff --git a/R/import.R b/R/import.R index 77cfd48..12242f1 100644 --- a/R/import.R +++ b/R/import.R @@ -93,9 +93,7 @@ #' @importFrom tibble as_tibble is_tibble #' @export import <- function(file, format, setclass, which, ...) { - if (isFALSE(inherits(file, "character")) || isFALSE(length(file) == 1)) { - stop("Invalid `file` argument.", call. = FALSE) - } + .check_file(file, single_only = TRUE) if (grepl("^http.*://", file)) { file <- remote_to_local(file, format = format) } diff --git a/R/import_list.R b/R/import_list.R index 71fe6c2..f091d97 100644 --- a/R/import_list.R +++ b/R/import_list.R @@ -34,6 +34,7 @@ function(file, rbind_label = "_file", rbind_fill = TRUE, ...) { + .check_file(file, single_only = FALSE) if (missing(setclass)) { setclass <- NULL } diff --git a/R/utils.R b/R/utils.R index 2d130e9..e261684 100644 --- a/R/utils.R +++ b/R/utils.R @@ -129,3 +129,17 @@ twrap <- function(value, tag) { .write_as_utf8 <- function(text, file, sep = "") { writeLines(enc2utf8(text), con = file, sep = sep, useBytes = TRUE) } + +.check_file <- function(file, single_only = TRUE) { + ## check the `file` argument + if (isTRUE(missing(file))) { ## for the case of export(iris, format = "csv") + return(invisible(NULL)) + } + if (isFALSE(inherits(file, "character"))) { + stop("Invalid `file` argument: must be character", call. = FALSE) + } + if (isFALSE(length(file) == 1) && single_only) { + stop("Invalid `file` argument: `file` must be single", call. = FALSE) + } + invisible(NULL) +} diff --git a/tests/testthat/test_check_file.R b/tests/testthat/test_check_file.R new file mode 100644 index 0000000..0093717 --- /dev/null +++ b/tests/testthat/test_check_file.R @@ -0,0 +1,67 @@ +test_that(".check_file", { + data <- data.frame( + x = sample(1:10, 10000, replace = TRUE), + y = sample(1:10, 10000, replace = TRUE) + ) + expect_error(.check_file(1)) + expect_error(.check_file(TRUE)) + expect_error(.check_file(data)) + expect_error(.check_file(iris)) + expect_error(.check_file(c("a.csv", "b.csv"))) + expect_error(.check_file("a.csv"), NA) + expect_error(.check_file(), NA) + ## single_only FALSE + expect_error(.check_file(1, single_only = FALSE)) + expect_error(.check_file(TRUE, single_only = FALSE)) + expect_error(.check_file(data, single_only = FALSE)) + expect_error(.check_file(iris, single_only = FALSE)) + expect_error(.check_file(c("a.csv", "b.csv"), single_only = FALSE), NA) + expect_error(.check_file("a.csv"), NA) + expect_error(.check_file(single_only = FALSE), NA) +}) + +test_that("Invalid file argument - import(), #301", { + data <- data.frame( + x = sample(1:10, 10000, replace = TRUE), + y = sample(1:10, 10000, replace = TRUE) + ) + expect_error(import(data), "Invalid") + expect_error(import(iris), "Invalid") + expect_error(import(1), "Invalid") + expect_error(import(TRUE), "Invalid") + expect_error(import(c("a.csv", "b.csv")), "Invalid") +}) + +test_that("Invalid file argument - import_list(), #301", { + data <- data.frame( + x = sample(1:10, 10000, replace = TRUE), + y = sample(1:10, 10000, replace = TRUE) + ) + expect_error(import_list(data), "Invalid") + expect_error(import_list(iris), "Invalid") + expect_error(import_list(1), "Invalid") + expect_error(import_list(TRUE), "Invalid") +}) + +test_that("Invalid file argument - export(), #301", { + data <- data.frame( + x = sample(1:10, 10000, replace = TRUE), + y = sample(1:10, 10000, replace = TRUE) + ) + expect_error(export(iris, data), "Invalid") + expect_error(export(iris, iris), "Invalid") + expect_error(export(iris, 1), "Invalid") + expect_error(export(iris, TRUE), "Invalid") + expect_error(export(iris, c("abc.csv", "123.csv")), "Invalid") +}) + +test_that("Invalid file argument - export_list(), #301", { + data <- data.frame( + x = sample(1:10, 10000, replace = TRUE), + y = sample(1:10, 10000, replace = TRUE) + ) + expect_error(export_list(iris, data), "Invalid") + expect_error(export_list(iris, iris), "Invalid") + expect_error(export_list(iris, 1), "Invalid") + expect_error(export_list(iris, TRUE), "Invalid") +}) diff --git a/tests/testthat/test_import.r b/tests/testthat/test_import.r deleted file mode 100644 index 6cb4eb6..0000000 --- a/tests/testthat/test_import.r +++ /dev/null @@ -1,12 +0,0 @@ - -test_that("Invalid file argument, #301", { - data <- data.frame( - x = sample(1:10, 10000, replace = TRUE), - y = sample(1:10, 10000, replace = TRUE) - ) - expect_error(import(data), "Invalid") - expect_error(import(iris), "Invalid") - expect_error(import(1), "Invalid") - expect_error(import(TRUE), "Invalid") - expect_error(import(c("a.csv", "b.csv")), "Invalid") -}) From 8bf9a23aa17722d2cd92436e08aea0c706bcedfa Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Mon, 4 Sep 2023 11:41:30 +0200 Subject: [PATCH 41/44] Fix #294 (#337) * Refactor And it passes all existing tests * Update doc on zip directory [no ci] * Add tests for #294 * Update NEWS [no ci] --- NEWS.md | 1 + R/import_list.R | 167 +++++++++++++++++------------- man/import_list.Rd | 4 +- tests/testthat/test_import_list.R | 17 +++ 4 files changed, 113 insertions(+), 76 deletions(-) diff --git a/NEWS.md b/NEWS.md index 0d0b4a2..b49422c 100644 --- a/NEWS.md +++ b/NEWS.md @@ -8,6 +8,7 @@ - POTENTIALLY BREAKING: YAML are exported using yaml::write_yaml(). But it can't pass the UTF-8 check on older systems. Disclaimer added. #318 - More check for the `file` argument #301 + - `import_list` works with single Excel/HTML/Zip online #294 * Declutter - remove the obsolete data.table option #323 - write all documentation blocks in markdown #311 diff --git a/R/import_list.R b/R/import_list.R index f091d97..e42ed80 100644 --- a/R/import_list.R +++ b/R/import_list.R @@ -1,6 +1,6 @@ #' @title Import list of data frames -#' @description Use [import()] to import a list of data frames from a vector of file names or from a multi-object file (Excel workbook, .Rdata file, zip directory, or HTML file) -#' @param file A character string containing a single file name for a multi-object file (e.g., Excel workbook, zip directory, or HTML file), or a vector of file paths for multiple files to be imported. +#' @description Use [import()] to import a list of data frames from a vector of file names or from a multi-object file (Excel workbook, .Rdata file, zipped directory in a zip file, or HTML file) +#' @param file A character string containing a single file name for a multi-object file (e.g., Excel workbook, zip file, or HTML file), or a vector of file paths for multiple files to be imported. #' @param which If `file` is a single file path, this specifies which objects should be extracted (passed to [import()]'s `which` argument). Ignored otherwise. #' @param rbind A logical indicating whether to pass the import list of data frames through [data.table::rbindlist()]. #' @param rbind_label If `rbind = TRUE`, a character string specifying the name of a column to add to the data frame indicating its source file. @@ -38,79 +38,13 @@ function(file, if (missing(setclass)) { setclass <- NULL } - strip_exts <- function(file) { - vapply(file, function(x) tools::file_path_sans_ext(basename(x)), character(1)) - } - if (length(file) > 1) { - names(file) <- strip_exts(file) - x <- lapply(file, function(thisfile) { - out <- try(import(thisfile, setclass = setclass, ...), silent = TRUE) - if (inherits(out, "try-error")) { - warning(sprintf("Import failed for %s", thisfile)) - out <- NULL - } else if (isTRUE(rbind)) { - out[[rbind_label]] <- thisfile - } - structure(out, filename = thisfile) - }) - names(x) <- names(file) + ## special cases + if (length(file) == 1) { + x <- .read_file_as_list(file = file, which = which, setclass = setclass, rbind = rbind, rbind_label = rbind_label, ...) } else { - if (get_ext(file) == "rdata") { - e <- new.env() - load(file, envir = e) - x <- as.list(e) - } else { - if (get_ext(file) == "html") { - .check_pkg_availability("xml2") - tables <- xml2::xml_find_all(xml2::read_html(unclass(file)), ".//table") - if (missing(which)) { - which <- seq_along(tables) - } - whichnames <- vapply(xml2::xml_attrs(tables[which]), - function(x) if ("class" %in% names(x)) x["class"] else "", - FUN.VALUE = character(1)) - names(which) <- whichnames - } else if (get_ext(file) %in% c("xls","xlsx")) { - .check_pkg_availability("readxl") - whichnames <- readxl::excel_sheets(path = file) - if (missing(which)) { - which <- seq_along(whichnames) - names(which) <- whichnames - } else if (is.character(which)) { - whichnames <- which - } else { - whichnames <- whichnames[which] - } - } else if (get_ext(file) %in% c("zip")) { - if (missing(which)) { - whichnames <- utils::unzip(file, list = TRUE)[, "Name"] - which <- seq_along(whichnames) - names(which) <- strip_exts(whichnames) - } else if (is.character(which)) { - whichnames <- utils::unzip(file, list = TRUE)[, "Name"] - whichnames <- whichnames[whichnames %in% which] - } else { - whichnames <- utils::unzip(file, list = TRUE)[, "Name"] - names(which) <- strip_exts(whichnames) - } - } else { - which <- 1 - whichnames <- NULL - } - x <- lapply(which, function(thiswhich) { - out <- try(import(file, setclass = setclass, which = thiswhich, ...), silent = TRUE) - if (inherits(out, "try-error")) { - warning(sprintf("Import failed for %s from %s", thiswhich, file)) - out <- NULL - } else if (isTRUE(rbind) && length(which) > 1) { - out[[rbind_label]] <- thiswhich - } - out - }) - names(x) <- whichnames - } + ## note the plural + x <- .read_multiple_files_as_list(files = file, setclass = setclass, rbind = rbind, rbind_label = rbind_label, ...) } - # optionally rbind if (isTRUE(rbind)) { if (length(x) == 1) { @@ -124,7 +58,7 @@ function(file, x <- x2 } } - # set class + ## set class a <- list(...) if (is.null(setclass)) { if ("data.table" %in% names(a) && isTRUE(a[["data.table"]])) { @@ -148,3 +82,88 @@ function(file, return(x) } + +.strip_exts <- function(file) { + vapply(file, function(x) tools::file_path_sans_ext(basename(x)), character(1)) +} + +.read_multiple_files_as_list <- function(files, setclass, rbind, rbind_label,...) { + names(files) <- .strip_exts(files) + x <- lapply(files, function(thisfile) { + out <- try(import(thisfile, setclass = setclass, ...), silent = TRUE) + if (inherits(out, "try-error")) { + warning(sprintf("Import failed for %s", thisfile)) + out <- NULL + } else if (isTRUE(rbind)) { + out[[rbind_label]] <- thisfile + } + structure(out, filename = thisfile) + }) + names(x) <- names(files) + return(x) +} + +.read_file_as_list <- function(file, which, setclass, rbind, rbind_label,...) { + if (grepl("^http.*://", file)) { + file <- remote_to_local(file) + } + if (get_ext(file) == "rdata") { + e <- new.env() + load(file, envir = e) + return(as.list(e)) + } + if (!get_ext(file) %in% c("html", "xlsx", "xls", "zip")) { + which <- 1 + whichnames <- NULL + } + ## getting list of `whichnames` + if (get_ext(file) == "html") { + .check_pkg_availability("xml2") + tables <- xml2::xml_find_all(xml2::read_html(unclass(file)), ".//table") + if (missing(which)) { + which <- seq_along(tables) + } + whichnames <- vapply(xml2::xml_attrs(tables[which]), + function(x) if ("class" %in% names(x)) x["class"] else "", + FUN.VALUE = character(1)) + names(which) <- whichnames + } + if (get_ext(file) %in% c("xls","xlsx")) { + ##.check_pkg_availability("readxl") + whichnames <- readxl::excel_sheets(path = file) + if (missing(which)) { + which <- seq_along(whichnames) + names(which) <- whichnames + } else if (is.character(which)) { + whichnames <- which + } else { + whichnames <- whichnames[which] + } + } + if (get_ext(file) %in% c("zip")) { + if (missing(which)) { + whichnames <- utils::unzip(file, list = TRUE)[, "Name"] + which <- seq_along(whichnames) + names(which) <- .strip_exts(whichnames) + } else if (is.character(which)) { + whichnames <- utils::unzip(file, list = TRUE)[, "Name"] + whichnames <- whichnames[whichnames %in% which] + } else { + whichnames <- utils::unzip(file, list = TRUE)[, "Name"] + names(which) <- .strip_exts(whichnames) + } + } + ## reading all `whichnames` + x <- lapply(which, function(thiswhich) { + out <- try(import(file, setclass = setclass, which = thiswhich, ...), silent = TRUE) + if (inherits(out, "try-error")) { + warning(sprintf("Import failed for %s from %s", thiswhich, file)) + out <- NULL + } else if (isTRUE(rbind) && length(which) > 1) { + out[[rbind_label]] <- thiswhich + } + out + }) + names(x) <- whichnames + return(x) +} diff --git a/man/import_list.Rd b/man/import_list.Rd index 3310cf0..7158325 100644 --- a/man/import_list.Rd +++ b/man/import_list.Rd @@ -15,7 +15,7 @@ import_list( ) } \arguments{ -\item{file}{A character string containing a single file name for a multi-object file (e.g., Excel workbook, zip directory, or HTML file), or a vector of file paths for multiple files to be imported.} +\item{file}{A character string containing a single file name for a multi-object file (e.g., Excel workbook, zip file, or HTML file), or a vector of file paths for multiple files to be imported.} \item{setclass}{An optional character vector specifying one or more classes to set on the import. By default, the return object is always a \dQuote{data.frame}. Allowed values include \dQuote{tbl_df}, \dQuote{tbl}, or \dQuote{tibble} (if using dplyr) or \dQuote{data.table} (if using data.table). Other values are ignored, such that a data.frame is returned.} @@ -33,7 +33,7 @@ import_list( If \code{rbind=FALSE} (the default), a list of a data frames. Otherwise, that list is passed to \code{\link[data.table:rbindlist]{data.table::rbindlist()}} with \code{fill = TRUE} and returns a data frame object of class set by the \code{setclass} argument; if this operation fails, the list is returned. } \description{ -Use \code{\link[=import]{import()}} to import a list of data frames from a vector of file names or from a multi-object file (Excel workbook, .Rdata file, zip directory, or HTML file) +Use \code{\link[=import]{import()}} to import a list of data frames from a vector of file names or from a multi-object file (Excel workbook, .Rdata file, zipped directory in a zip file, or HTML file) } \examples{ ## For demo, a temp. file path is created with the file extension .xlsx diff --git a/tests/testthat/test_import_list.R b/tests/testthat/test_import_list.R index 8395b98..a520a64 100644 --- a/tests/testthat/test_import_list.R +++ b/tests/testthat/test_import_list.R @@ -89,6 +89,23 @@ test_that("File names are added as attributes by import_list()", { unlink(c("mtcars.csv", "mtcars.tsv")) }) +test_that("URL #294", { + skip_on_cran() + ## url <- "https://evs.nci.nih.gov/ftp1/CDISC/SDTM/SDTM%20Terminology.xls" That's 10MB! + url <- "https://github.com/tidyverse/readxl/raw/main/tests/testthat/sheets/sheet-xml-lookup.xlsx" + expect_error(x <- import_list(url), NA) + expect_true(inherits(x, "list")) + expect_true("Asia" %in% names(x)) + expect_true("Africa" %in% x[[1]]$continent) + expect_false("Africa" %in% x[[2]]$continent) + ## double URLs; it reads twice the first sheet by default + urls <- c(url, url) + expect_error(x2 <- import_list(urls), NA) + expect_true("sheet-xml-lookup" %in% names(x2)) + expect_true("Africa" %in% x2[[1]]$continent) + expect_true("Africa" %in% x2[[2]]$continent) +}) + unlink("data.rdata") unlink("mtcars.rds") unlink("mtcars.csv.zip") From 34f8a02b8b37f16713a870e60f7dfa46073d7921 Mon Sep 17 00:00:00 2001 From: David Schoch Date: Mon, 4 Sep 2023 15:24:00 +0200 Subject: [PATCH 42/44] removed importFrom [no ci] (#325) (#338) --- NAMESPACE | 51 ------- R/compression.R | 8 +- R/export.R | 1 - R/export_methods.R | 97 +++++++------- R/extensions.R | 70 +++++----- R/fwf2.R | 24 ++-- R/gather_attrs.R | 9 +- R/import.R | 8 +- R/import_methods.R | 297 ++++++++++++++++++++--------------------- R/remote_to_local.R | 8 +- R/suggestions.R | 5 +- man/gather_attrs.Rd | 8 +- man/install_formats.Rd | 2 +- 13 files changed, 266 insertions(+), 322 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 7af7280..b8eb497 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -86,54 +86,3 @@ export(import) export(import_list) export(install_formats) export(spread_attrs) -importFrom(curl,curl_fetch_memory) -importFrom(curl,parse_headers) -importFrom(data.table,as.data.table) -importFrom(data.table,fread) -importFrom(data.table,fwrite) -importFrom(data.table,is.data.table) -importFrom(foreign,read.arff) -importFrom(foreign,read.dbf) -importFrom(foreign,read.dta) -importFrom(foreign,read.epiinfo) -importFrom(foreign,read.mtp) -importFrom(foreign,read.spss) -importFrom(foreign,read.systat) -importFrom(foreign,read.xport) -importFrom(foreign,write.arff) -importFrom(foreign,write.dbf) -importFrom(haven,labelled) -importFrom(haven,read_dta) -importFrom(haven,read_por) -importFrom(haven,read_sas) -importFrom(haven,read_sav) -importFrom(haven,read_xpt) -importFrom(haven,write_dta) -importFrom(haven,write_sas) -importFrom(haven,write_sav) -importFrom(haven,write_xpt) -importFrom(openxlsx,read.xlsx) -importFrom(openxlsx,write.xlsx) -importFrom(readxl,read_xls) -importFrom(readxl,read_xlsx) -importFrom(stats,na.omit) -importFrom(stats,setNames) -importFrom(tibble,as_tibble) -importFrom(tibble,is_tibble) -importFrom(tools,file_ext) -importFrom(tools,file_path_sans_ext) -importFrom(utils,capture.output) -importFrom(utils,install.packages) -importFrom(utils,installed.packages) -importFrom(utils,packageName) -importFrom(utils,read.DIF) -importFrom(utils,read.fortran) -importFrom(utils,read.fwf) -importFrom(utils,read.table) -importFrom(utils,tar) -importFrom(utils,type.convert) -importFrom(utils,untar) -importFrom(utils,unzip) -importFrom(utils,write.csv) -importFrom(utils,write.table) -importFrom(utils,zip) diff --git a/R/compression.R b/R/compression.R index 501d519..f0691f6 100644 --- a/R/compression.R +++ b/R/compression.R @@ -35,12 +35,12 @@ compress_out <- function(cfile, filename, type = c("zip", "tar", "gzip", "bzip2" on.exit(setwd(wd), add = TRUE) setwd(tmp) if (type == "zip") { - o <- zip(cfile2, files = basename(filename)) + o <- utils::zip(cfile2, files = basename(filename)) } else { if (type == "tar") { type <- "none" } - o <- tar(cfile2, files = basename(filename), compression = type) + o <- utils::tar(cfile2, files = basename(filename), compression = type) } setwd(wd) if (o != 0) { @@ -66,7 +66,7 @@ parse_zip <- function(file, which, ...) { utils::unzip(file, files = file_list$Name[which], exdir = d) file.path(d, file_list$Name[which]) } else { - if (substring(which, 1,1) != "^") { + if (substring(which, 1, 1) != "^") { which2 <- paste0("^", which) } utils::unzip(file, files = file_list$Name[grep(which2, file_list$Name)[1]], exdir = d) @@ -89,7 +89,7 @@ parse_tar <- function(file, which, ...) { utils::untar(file, files = file_list[which], exdir = d) file.path(d, file_list[which]) } else { - if (substring(which, 1,1) != "^") { + if (substring(which, 1, 1) != "^") { which2 <- paste0("^", which) } utils::untar(file, files = file_list[grep(which2, file_list)[1]], exdir = d) diff --git a/R/export.R b/R/export.R index 428e255..75b2fa8 100644 --- a/R/export.R +++ b/R/export.R @@ -74,7 +74,6 @@ #' #' ## export(mtcars, format = "stata") #' @seealso [characterize()], [import()], [convert()], [export_list()] -#' @importFrom haven labelled #' @export export <- function(x, file, format, ...) { .check_file(file, single_only = TRUE) diff --git a/R/export_methods.R b/R/export_methods.R index 7c99c78..58062e2 100644 --- a/R/export_methods.R +++ b/R/export_methods.R @@ -1,25 +1,31 @@ -#' @importFrom data.table fwrite -#' @importFrom utils write.table export_delim <- function(file, x, fwrite = TRUE, sep = "\t", row.names = FALSE, col.names = TRUE, append = FALSE, ...) { if (isTRUE(fwrite) & !inherits(file, "connection")) { if (isTRUE(append)) { - data.table::fwrite(x, file = file, sep = sep, row.names = row.names, - col.names = FALSE, append = TRUE, ...) + data.table::fwrite(x, + file = file, sep = sep, row.names = row.names, + col.names = FALSE, append = TRUE, ... + ) } else { - data.table::fwrite(x, file = file, sep = sep, row.names = row.names, - col.names = col.names, append = FALSE, ...) + data.table::fwrite(x, + file = file, sep = sep, row.names = row.names, + col.names = col.names, append = FALSE, ... + ) } } else { if (isTRUE(fwrite) & inherits(file, "connection")) { message("data.table::fwrite() does not support writing to connections. Using utils::write.table() instead.") } if (isTRUE(append)) { - write.table(x, file = file, sep = sep, row.names = row.names, - col.names = FALSE, append = TRUE, ...) + utils::write.table(x, + file = file, sep = sep, row.names = row.names, + col.names = FALSE, append = TRUE, ... + ) } else { - write.table(x, file = file, sep = sep, row.names = row.names, - col.names = col.names, append = FALSE, ...) + utils::write.table(x, + file = file, sep = sep, row.names = row.names, + col.names = col.names, append = FALSE, ... + ) } } } @@ -54,17 +60,16 @@ export_delim <- function(file, x, fwrite = TRUE, sep = "\t", row.names = FALSE, export_delim(x = x, file = file, sep = "|", ...) } -#' @importFrom utils capture.output write.csv #' @export .export.rio_fwf <- function(file, x, verbose = getOption("verbose", FALSE), sep = "", row.names = FALSE, quote = FALSE, col.names = FALSE, digits = getOption("digits", 7), ...) { dat <- lapply(x, function(col) { if (is.character(col)) { col <- as.numeric(as.factor(col)) - } else if(is.factor(col)) { + } else if (is.factor(col)) { col <- as.integer(col) } if (is.integer(col)) { - return(sprintf("%i",col)) + return(sprintf("%i", col)) } if (is.numeric(col)) { decimals <- strsplit(as.character(col), ".", fixed = TRUE) @@ -79,34 +84,40 @@ export_delim <- function(file, x, fwrite = TRUE, sep = "\t", row.names = FALSE, if (!is.finite(m2)) { m2 <- digits } - return(formatC(sprintf(fmt = paste0("%0.",m2,"f"), col), width = (m1+m2+1))) - } else if(is.logical(col)) { - return(sprintf("%i",col)) + return(formatC(sprintf(fmt = paste0("%0.", m2, "f"), col), width = (m1 + m2 + 1))) + } else if (is.logical(col)) { + return(sprintf("%i", col)) } }) dat <- do.call(cbind, dat) - n <- nchar(dat[1,]) + c(rep(nchar(sep), ncol(dat)-1), 0) + n <- nchar(dat[1, ]) + c(rep(nchar(sep), ncol(dat) - 1), 0) col_classes <- vapply(x, class, character(1)) col_classes[col_classes == "factor"] <- "integer" - dict <- cbind.data.frame(variable = names(n), - class = col_classes, - width = unname(n), - columns = paste0(c(1, cumsum(n)+1)[-length(n)], "-", cumsum(n)), - stringsAsFactors = FALSE) + dict <- cbind.data.frame( + variable = names(n), + class = col_classes, + width = unname(n), + columns = paste0(c(1, cumsum(n) + 1)[-length(n)], "-", cumsum(n)), + stringsAsFactors = FALSE + ) if (isTRUE(verbose)) { message("Columns:") - message(paste0(capture.output(dict), collapse = "\n")) + message(paste0(utils::capture.output(dict), collapse = "\n")) if (sep == "") { - message(paste0('\nRead in with:\n', - 'import("', file, '",\n', - ' widths = c(', paste0(n, collapse = ","), '),\n', - ' col.names = c("', paste0(names(n), collapse = '","'), '"),\n', - ' colClasses = c("', paste0(col_classes, collapse = '","') ,'"))\n'), domain = NA) + message(paste0( + "\nRead in with:\n", + 'import("', file, '",\n', + " widths = c(", paste0(n, collapse = ","), "),\n", + ' col.names = c("', paste0(names(n), collapse = '","'), '"),\n', + ' colClasses = c("', paste0(col_classes, collapse = '","'), '"))\n' + ), domain = NA) } } - .write_as_utf8(paste0("#", capture.output(write.csv(dict, row.names = FALSE, quote = FALSE))), file = file, sep = "\n") - utils::write.table(dat, file = file, append = TRUE, row.names = row.names, sep = sep, quote = quote, - col.names = col.names, ...) + .write_as_utf8(paste0("#", utils::capture.output(utils::write.csv(dict, row.names = FALSE, quote = FALSE))), file = file, sep = "\n") + utils::write.table(dat, + file = file, append = TRUE, row.names = row.names, sep = sep, quote = quote, + col.names = col.names, ... + ) } #' @export @@ -161,42 +172,36 @@ export_delim <- function(file, x, fwrite = TRUE, sep = "\t", row.names = FALSE, rmatio::write.mat(object = x, filename = file, ...) } -#' @importFrom haven write_sav #' @export .export.rio_sav <- function(file, x, ...) { x <- restore_labelled(x) haven::write_sav(data = x, path = file, ...) } -#' @importFrom haven write_sav #' @export .export.rio_zsav <- function(file, x, compress = TRUE, ...) { x <- restore_labelled(x) haven::write_sav(data = x, path = file, compress = compress, ...) } -#' @importFrom haven write_dta #' @export .export.rio_dta <- function(file, x, ...) { x <- restore_labelled(x) haven::write_dta(data = x, path = file, ...) } -#' @importFrom haven write_sas #' @export .export.rio_sas7bdat <- function(file, x, ...) { x <- restore_labelled(x) haven::write_sas(data = x, path = file, ...) } -#' @importFrom haven write_xpt #' @export .export.rio_xpt <- function(file, x, ...) { x <- restore_labelled(x) haven::write_xpt(data = x, path = file, ...) } -#' @importFrom foreign write.dbf #' @export .export.rio_dbf <- function(file, x, ...) { foreign::write.dbf(dataframe = x, file = file, ...) @@ -208,13 +213,11 @@ export_delim <- function(file, x, fwrite = TRUE, sep = "\t", row.names = FALSE, .write_as_utf8(jsonlite::toJSON(x, ...), file = file) } -#' @importFrom foreign write.arff #' @export .export.rio_arff <- function(file, x, ...) { foreign::write.arff(x = x, file = file, ...) } -#' @importFrom openxlsx write.xlsx #' @export .export.rio_xlsx <- function(file, x, which, ...) { dots <- list(...) @@ -262,8 +265,8 @@ export_delim <- function(file, x, fwrite = TRUE, sep = "\t", row.names = FALSE, } for (i in seq_along(x)) { x[[i]][] <- lapply(x[[i]], as.character) - x[[i]][] <- lapply(x[[i]], function(v) gsub('&','&',v)) - names(x[[i]]) <- gsub('&','&',names(x[[i]])) + x[[i]][] <- lapply(x[[i]], function(v) gsub("&", "&", v)) + names(x[[i]]) <- gsub("&", "&", names(x[[i]])) tab <- xml2::xml_add_child(bod, "table") # add header row invisible(xml2::xml_add_child(tab, xml2::read_xml(paste0(twrap(paste0(twrap(names(x[[i]]), "th"), collapse = ""), "tr"), "\n")))) @@ -279,15 +282,15 @@ export_delim <- function(file, x, fwrite = TRUE, sep = "\t", row.names = FALSE, .export.rio_xml <- function(file, x, ...) { .check_pkg_availability("xml2") root <- "" - xml <- xml2::read_xml(paste0("<",as.character(substitute(x)),">\n\n")) + xml <- xml2::read_xml(paste0("<", as.character(substitute(x)), ">\n\n")) att <- attributes(x)[!names(attributes(x)) %in% c("names", "row.names", "class")] for (a in seq_along(att)) { xml2::xml_attr(xml, names(att)[a]) <- att[[a]] } # remove illegal characters - row.names(x) <- gsub('&', '&', row.names(x)) - colnames(x) <- gsub('[ &]', '.', colnames(x)) - x[] <- lapply(x, function(v) gsub('&', '&', v)) + row.names(x) <- gsub("&", "&", row.names(x)) + colnames(x) <- gsub("[ &]", ".", colnames(x)) + x[] <- lapply(x, function(v) gsub("&", "&", v)) # add data for (i in seq_len(nrow(x))) { thisrow <- xml2::xml_add_child(xml, "Observation") @@ -315,11 +318,11 @@ export_delim <- function(file, x, fwrite = TRUE, sep = "\t", row.names = FALSE, #' @export .export.rio_pzfx <- function(file, x, ..., row_names = FALSE) { .check_pkg_availability("pzfx") - pzfx::write_pzfx(x=x, path=file, ..., row_names=row_names) + pzfx::write_pzfx(x = x, path = file, ..., row_names = row_names) } #' @export .export.rio_parquet <- function(file, x, ...) { .check_pkg_availability("arrow") - arrow::write_parquet(x=x, sink = file, ...) + arrow::write_parquet(x = x, sink = file, ...) } diff --git a/R/extensions.R b/R/extensions.R index c327cfe..a0674ca 100644 --- a/R/extensions.R +++ b/R/extensions.R @@ -12,58 +12,58 @@ ## ## As general guidance, if an import method creates many attributes, these attributes should be stored --- to the extent possible --- in variable-level attributes fields. These can be \dQuote{gathered} to the data.frame level by the user via \code{\link{gather_attrs}}. ## @seealso \code{\link{import}}, \code{\link{export}} -.import <- function(file, ...){ - UseMethod('.import') +.import <- function(file, ...) { + UseMethod(".import") } ## @rdname extensions -## @importFrom tools file_ext -.import.default <- function(file, ...){ +.import.default <- function(file, ...) { x <- gettext("%s format not supported. Consider using the '%s()' function") xA <- gettext("Import support for the %s format is exported by the %s package. Run 'library(%s)' then try again.") fmt <- tools::file_ext(file) out <- switch(fmt, - bean = sprintf(xA, fmt, "ledger", "ledger"), - beancount = sprintf(xA, fmt, "ledger", "ledger"), - bib = sprintf(x, fmt, "bib2df::bib2df"), - bmp = sprintf(x, fmt, "bmp::read.bmp"), - doc = sprintf(x, fmt, "docxtractr::docx_extract_all_tbls"), - docx = sprintf(x, fmt, "docxtractr::docx_extract_all_tbls"), - gexf = sprintf(x, fmt, "rgexf::read.gexf"), - gnumeric = sprintf(x, fmt, "gnumeric::read.gnumeric.sheet"), - hledger = sprintf(xA, fmt, "ledger", "ledger"), - jpeg = sprintf(x, fmt, "jpeg::readJPEG"), - jpg = sprintf(x, fmt, "jpeg::readJPEG"), - ledger = sprintf(xA, fmt, "ledger", "ledger"), - npy = sprintf(x, fmt, "RcppCNPy::npyLoad"), - qs = sprintf(x, fmt, "qs::qread"), - pdf = sprintf(x, fmt, "tabulizer::extract_tables"), - png = sprintf(x, fmt, "png::readPNG"), - sdmx = sprintf(x, fmt, "sdmx::readSDMX"), - sss = sprintf(x, fmt, "sss::read.sss"), - tiff = sprintf(x, fmt, "tiff::readTIFF"), - gettext("Format not supported")) + bean = sprintf(xA, fmt, "ledger", "ledger"), + beancount = sprintf(xA, fmt, "ledger", "ledger"), + bib = sprintf(x, fmt, "bib2df::bib2df"), + bmp = sprintf(x, fmt, "bmp::read.bmp"), + doc = sprintf(x, fmt, "docxtractr::docx_extract_all_tbls"), + docx = sprintf(x, fmt, "docxtractr::docx_extract_all_tbls"), + gexf = sprintf(x, fmt, "rgexf::read.gexf"), + gnumeric = sprintf(x, fmt, "gnumeric::read.gnumeric.sheet"), + hledger = sprintf(xA, fmt, "ledger", "ledger"), + jpeg = sprintf(x, fmt, "jpeg::readJPEG"), + jpg = sprintf(x, fmt, "jpeg::readJPEG"), + ledger = sprintf(xA, fmt, "ledger", "ledger"), + npy = sprintf(x, fmt, "RcppCNPy::npyLoad"), + qs = sprintf(x, fmt, "qs::qread"), + pdf = sprintf(x, fmt, "tabulizer::extract_tables"), + png = sprintf(x, fmt, "png::readPNG"), + sdmx = sprintf(x, fmt, "sdmx::readSDMX"), + sss = sprintf(x, fmt, "sss::read.sss"), + tiff = sprintf(x, fmt, "tiff::readTIFF"), + gettext("Format not supported") + ) stop(out, call. = FALSE) } ## @rdname extensions -.export <- function(file, x, ...){ +.export <- function(file, x, ...) { UseMethod(".export") } ## @rdname extensions -## @importFrom tools file_ext -.export.default <- function(file, x, ...){ +.export.default <- function(file, x, ...) { x <- gettext("%s format not supported. Consider using the '%s()' function") fmt <- tools::file_ext(file) out <- switch(fmt, - gexf = sprintf(x, fmt, "rgexf::write.gexf"), - jpg = sprintf(x, fmt, "jpeg::writeJPEG"), - npy = sprintf(x, fmt, "RcppCNPy::npySave"), - png = sprintf(x, fmt, "png::writePNG"), - qs = sprintf(x, fmt, "qs::qsave"), - tiff = sprintf(x, fmt, "tiff::writeTIFF"), - xpt = sprintf(x, fmt, "SASxport::write.xport"), - gettext("Format not supported")) + gexf = sprintf(x, fmt, "rgexf::write.gexf"), + jpg = sprintf(x, fmt, "jpeg::writeJPEG"), + npy = sprintf(x, fmt, "RcppCNPy::npySave"), + png = sprintf(x, fmt, "png::writePNG"), + qs = sprintf(x, fmt, "qs::qsave"), + tiff = sprintf(x, fmt, "tiff::writeTIFF"), + xpt = sprintf(x, fmt, "SASxport::write.xport"), + gettext("Format not supported") + ) stop(out, call. = FALSE) } diff --git a/R/fwf2.R b/R/fwf2.R index 1eab507..98cccd7 100644 --- a/R/fwf2.R +++ b/R/fwf2.R @@ -1,5 +1,4 @@ -#' @importFrom utils read.table -read.fwf2 <- function (file, widths, header = FALSE, sep = "\t", skip = 0, n = -1, quote = "", stringsAsFactors = FALSE, ...) { +read.fwf2 <- function(file, widths, header = FALSE, sep = "\t", skip = 0, n = -1, quote = "", stringsAsFactors = FALSE, ...) { doone <- function(x) { x <- substring(x, first, last) x[!nzchar(x)] <- NA_character_ @@ -20,19 +19,24 @@ read.fwf2 <- function (file, widths, header = FALSE, sep = "\t", skip = 0, n = - open(file, "rt") on.exit(close(file), add = TRUE) } - if (skip) + if (skip) { readLines(file, n = skip) + } if (header) { headerline <- readLines(file, n = 1L) text[1] <- headerline } raw <- readLines(file, n = n) nread <- length(raw) - if (recordlength > 1L && nread%%recordlength) { - raw <- raw[1L:(nread - nread%%recordlength)] - warning(sprintf(ngettext(nread%%recordlength, "last record incomplete, %d line discarded", - "last record incomplete, %d lines discarded"), - nread%%recordlength), domain = NA) + if (recordlength > 1L && nread %% recordlength) { + raw <- raw[1L:(nread - nread %% recordlength)] + warning(sprintf( + ngettext( + nread %% recordlength, "last record incomplete, %d line discarded", + "last record incomplete, %d lines discarded" + ), + nread %% recordlength + ), domain = NA) } if (recordlength > 1L) { raw <- matrix(raw, nrow = recordlength) @@ -41,10 +45,10 @@ read.fwf2 <- function (file, widths, header = FALSE, sep = "\t", skip = 0, n = - st <- c(1L, 1L + cumsum(widths)) first <- st[-length(st)][!drop] last <- cumsum(widths)[!drop] - if(header) { + if (header) { text <- c(headerline, vapply(raw, doone, character(1))) } else { text <- vapply(raw, doone, character(1)) } - read.table(text = text, header = header, sep = sep, quote = quote, stringsAsFactors = stringsAsFactors, ...) + utils::read.table(text = text, header = header, sep = sep, quote = quote, stringsAsFactors = stringsAsFactors, ...) } diff --git a/R/gather_attrs.R b/R/gather_attrs.R index accefc9..196c774 100644 --- a/R/gather_attrs.R +++ b/R/gather_attrs.R @@ -7,13 +7,12 @@ #' @examples #' e <- try(import("http://www.stata-press.com/data/r13/auto.dta")) #' if (!inherits(e, "try-error")) { -#' str(e) -#' g <- gather_attrs(e) -#' str(attributes(e)) -#' str(g) +#' str(e) +#' g <- gather_attrs(e) +#' str(attributes(e)) +#' str(g) #' } #' @seealso [import()], [characterize()] -#' @importFrom stats setNames #' @export gather_attrs <- function(x) { if (!inherits(x, "data.frame")) { diff --git a/R/import.R b/R/import.R index 12242f1..2a0ec03 100644 --- a/R/import.R +++ b/R/import.R @@ -85,12 +85,6 @@ #' ## data.table::fread is the underlying import function and `nrows` is its argument #' import(csv_file, nrows = 20) #' @seealso [import_list()], [characterize()], [gather_attrs()], [export()], [convert()] -#' @importFrom tools file_ext file_path_sans_ext -#' @importFrom stats na.omit setNames -#' @importFrom utils installed.packages untar unzip tar zip type.convert capture.output -#' @importFrom curl curl_fetch_memory parse_headers -#' @importFrom data.table as.data.table is.data.table -#' @importFrom tibble as_tibble is_tibble #' @export import <- function(file, format, setclass, which, ...) { .check_file(file, single_only = TRUE) @@ -106,7 +100,7 @@ import <- function(file, format, setclass, which, ...) { } else { file <- parse_zip(file, which = which) } - } else if(grepl("\\.tar", file)) { + } else if (grepl("\\.tar", file)) { if (missing(which)) { which <- 1 } diff --git a/R/import_methods.R b/R/import_methods.R index 4ed2a67..783993d 100644 --- a/R/import_methods.R +++ b/R/import_methods.R @@ -1,33 +1,36 @@ -#' @importFrom data.table fread import_delim <- - function(file, which = 1, fread = TRUE, sep = "auto", - header = "auto", stringsAsFactors = FALSE, data.table = FALSE, ...) { - if (isTRUE(fread) & !inherits(file, "connection")) { - arg_reconcile(data.table::fread, input = file, sep = sep, header = header, - stringsAsFactors = stringsAsFactors, - data.table = data.table, ..., .docall = TRUE) - } else { - if (isTRUE(fread) & inherits(file, "connection")) { - message("data.table::fread() does not support reading from connections. Using utils::read.table() instead.") - } - if (missing(sep) || is.null(sep) || sep == "auto") { - if (inherits(file, "rio_csv")) { - sep <- "," - } else if (inherits(file, "rio_csv2")) { - sep <- ";" - } else if (inherits(file, "rio_psv")) { - sep <- "|" + function(file, which = 1, fread = TRUE, sep = "auto", + header = "auto", stringsAsFactors = FALSE, data.table = FALSE, ...) { + if (isTRUE(fread) & !inherits(file, "connection")) { + arg_reconcile(data.table::fread, + input = file, sep = sep, header = header, + stringsAsFactors = stringsAsFactors, + data.table = data.table, ..., .docall = TRUE + ) } else { - sep <- "\t" + if (isTRUE(fread) & inherits(file, "connection")) { + message("data.table::fread() does not support reading from connections. Using utils::read.table() instead.") + } + if (missing(sep) || is.null(sep) || sep == "auto") { + if (inherits(file, "rio_csv")) { + sep <- "," + } else if (inherits(file, "rio_csv2")) { + sep <- ";" + } else if (inherits(file, "rio_psv")) { + sep <- "|" + } else { + sep <- "\t" + } + } + if (missing(header) || is.null(header) || header == "auto") { + header <- TRUE + } + arg_reconcile(utils::read.table, + file = file, sep = sep, header = header, + stringsAsFactors = stringsAsFactors, ..., .docall = TRUE + ) } - } - if (missing(header) || is.null(header) || header == "auto") { - header <- TRUE - } - arg_reconcile(utils::read.table, file=file, sep=sep, header=header, - stringsAsFactors = stringsAsFactors, ..., .docall = TRUE) } - } #' @export @@ -66,72 +69,73 @@ import_delim <- import_delim(file = file, sep = if (sep == "|") "auto" else sep, fread = fread, dec = dec, ...) } -#' @importFrom utils read.fwf #' @export .import.rio_fwf <- -function(file, - which = 1, - widths, - header = FALSE, - col.names, - comment = "#", - readr = FALSE, - progress = getOption("verbose", FALSE), - ...) { - if (missing(widths)) { - stop("Import of fixed-width format data requires a 'widths' argument. See ? read.fwf().") - } - a <- list(...) - if (isTRUE(readr)) { - .check_pkg_availability("readr") - if (is.null(widths)) { - if (!missing(col.names)) { - widths <- readr::fwf_empty(file = file, col_names = col.names) - } else { - widths <- readr::fwf_empty(file = file) - } - readr::read_fwf(file = file, col_positions = widths, progress = progress, comment = comment, ...) - } else if (is.numeric(widths)) { - if (any(widths < 0)) { - if (!"col_types" %in% names(a)) { - col_types <- rep("?", length(widths)) - col_types[widths < 0] <- "?" - col_types <- paste0(col_types, collapse = "") - } - if (!missing(col.names)) { - widths <- readr::fwf_widths(abs(widths), col_names = col.names) - } else { - widths <- readr::fwf_widths(abs(widths)) - } - readr::read_fwf(file = file, col_positions = widths, - col_types = col_types, progress = progress, - comment = comment, ...) - } else { + function(file, + which = 1, + widths, + header = FALSE, + col.names, + comment = "#", + readr = FALSE, + progress = getOption("verbose", FALSE), + ...) { + if (missing(widths)) { + stop("Import of fixed-width format data requires a 'widths' argument. See ? read.fwf().") + } + a <- list(...) + if (isTRUE(readr)) { + .check_pkg_availability("readr") + if (is.null(widths)) { if (!missing(col.names)) { - widths <- readr::fwf_widths(abs(widths), col_names = col.names) + widths <- readr::fwf_empty(file = file, col_names = col.names) } else { - widths <- readr::fwf_widths(abs(widths)) + widths <- readr::fwf_empty(file = file) } readr::read_fwf(file = file, col_positions = widths, progress = progress, comment = comment, ...) - } - } else if (is.list(widths)) { - if (!c("begin", "end") %in% names(widths)) { - if (!missing(col.names)) { - widths <- readr::fwf_widths(widths, col_names = col.names) + } else if (is.numeric(widths)) { + if (any(widths < 0)) { + if (!"col_types" %in% names(a)) { + col_types <- rep("?", length(widths)) + col_types[widths < 0] <- "?" + col_types <- paste0(col_types, collapse = "") + } + if (!missing(col.names)) { + widths <- readr::fwf_widths(abs(widths), col_names = col.names) + } else { + widths <- readr::fwf_widths(abs(widths)) + } + readr::read_fwf( + file = file, col_positions = widths, + col_types = col_types, progress = progress, + comment = comment, ... + ) } else { - widths <- readr::fwf_widths(widths) + if (!missing(col.names)) { + widths <- readr::fwf_widths(abs(widths), col_names = col.names) + } else { + widths <- readr::fwf_widths(abs(widths)) + } + readr::read_fwf(file = file, col_positions = widths, progress = progress, comment = comment, ...) + } + } else if (is.list(widths)) { + if (!c("begin", "end") %in% names(widths)) { + if (!missing(col.names)) { + widths <- readr::fwf_widths(widths, col_names = col.names) + } else { + widths <- readr::fwf_widths(widths) + } } + readr::read_fwf(file = file, col_positions = widths, progress = progress, comment = comment, ...) } - readr::read_fwf(file = file, col_positions = widths, progress = progress, comment = comment, ...) - } - } else { - if (!missing(col.names)) { - read.fwf2(file = file, widths = widths, header = header, col.names = col.names, ...) } else { - read.fwf2(file = file, widths = widths, header = header, ...) + if (!missing(col.names)) { + read.fwf2(file = file, widths = widths, header = header, col.names = col.names, ...) + } else { + read.fwf2(file = file, widths = widths, header = header, ...) + } } } -} #' @export .import.rio_r <- function(file, which = 1, ...) { @@ -142,7 +146,7 @@ function(file, .import.rio_dump <- function(file, which = 1, envir = new.env(), ...) { source(file = file, local = envir) if (length(list(...)) > 0) { - warning("File imported using load. Arguments to '...' ignored.") + warning("File imported using load. Arguments to '...' ignored.") } if (missing(which)) { if (length(ls(envir)) > 1) { @@ -159,17 +163,17 @@ function(file, #' @export .import.rio_rds <- function(file, which = 1, ...) { - if (length(list(...))>0) { - warning("File imported using readRDS. Arguments to '...' ignored.") - } - readRDS(file = file) + if (length(list(...)) > 0) { + warning("File imported using readRDS. Arguments to '...' ignored.") + } + readRDS(file = file) } #' @export .import.rio_rdata <- function(file, which = 1, envir = new.env(), ...) { load(file = file, envir = envir) if (length(list(...)) > 0) { - warning("File imported using load. Arguments to '...' ignored.") + warning("File imported using load. Arguments to '...' ignored.") } if (missing(which)) { if (length(ls(envir)) > 1) { @@ -205,67 +209,62 @@ function(file, rmatio::read.mat(filename = file) } -#' @importFrom foreign read.dta -#' @importFrom haven read_dta #' @export .import.rio_dta <- function(file, haven = TRUE, - convert.factors = FALSE,...) { - if (isTRUE(haven)) { - arg_reconcile(haven::read_dta, file = file, ..., .docall = TRUE, - .finish = standardize_attributes) - } else { - out <- arg_reconcile(foreign::read.dta, file = file, - convert.factors = convert.factors, ..., .docall = TRUE) - attr(out, "expansion.fields") <- NULL - attr(out, "time.stamp") <- NULL - standardize_attributes(out) - } + convert.factors = FALSE, ...) { + if (isTRUE(haven)) { + arg_reconcile(haven::read_dta, + file = file, ..., .docall = TRUE, + .finish = standardize_attributes + ) + } else { + out <- arg_reconcile(foreign::read.dta, + file = file, + convert.factors = convert.factors, ..., .docall = TRUE + ) + attr(out, "expansion.fields") <- NULL + attr(out, "time.stamp") <- NULL + standardize_attributes(out) + } } -#' @importFrom foreign read.dbf #' @export .import.rio_dbf <- function(file, which = 1, as.is = TRUE, ...) { foreign::read.dbf(file = file, as.is = as.is) } -#' @importFrom utils read.DIF #' @export .import.rio_dif <- function(file, which = 1, ...) { utils::read.DIF(file = file, ...) } -#' @importFrom haven read_sav -#' @importFrom foreign read.spss #' @export .import.rio_sav <- function(file, which = 1, haven = TRUE, to.data.frame = TRUE, use.value.labels = FALSE, ...) { if (isTRUE(haven)) { standardize_attributes(haven::read_sav(file = file)) } else { - standardize_attributes(foreign::read.spss(file = file, to.data.frame = to.data.frame, - use.value.labels = use.value.labels, ...)) + standardize_attributes(foreign::read.spss( + file = file, to.data.frame = to.data.frame, + use.value.labels = use.value.labels, ... + )) } } -#' @importFrom haven read_sav #' @export .import.rio_zsav <- function(file, which = 1, ...) { standardize_attributes(haven::read_sav(file = file)) } -#' @importFrom haven read_por #' @export .import.rio_spss <- function(file, which = 1, ...) { standardize_attributes(haven::read_por(file = file)) } -#' @importFrom haven read_sas #' @export .import.rio_sas7bdat <- function(file, which = 1, column.labels = FALSE, ...) { standardize_attributes(haven::read_sas(data_file = file, ...)) } -#' @importFrom foreign read.xport -#' @importFrom haven read_xpt #' @export .import.rio_xpt <- function(file, which = 1, haven = TRUE, ...) { if (isTRUE(haven)) { @@ -275,13 +274,11 @@ function(file, } } -#' @importFrom foreign read.mtp #' @export .import.rio_mtp <- function(file, which = 1, ...) { foreign::read.mtp(file = file, ...) } -#' @importFrom foreign read.systat #' @export .import.rio_syd <- function(file, which = 1, ...) { foreign::read.systat(file = file, to.data.frame = TRUE, ...) @@ -293,45 +290,45 @@ function(file, jsonlite::fromJSON(txt = file, ...) } -#' @importFrom foreign read.epiinfo #' @export .import.rio_rec <- function(file, which = 1, ...) { foreign::read.epiinfo(file = file, ...) } -#' @importFrom foreign read.arff #' @export .import.rio_arff <- function(file, which = 1, ...) { foreign::read.arff(file = file) } -#' @importFrom readxl read_xls #' @export .import.rio_xls <- function(file, which = 1, ...) { - .check_pkg_availability("readxl") - arg_reconcile(read_xls, path = file, ..., sheet = which, - .docall = TRUE, - .remap = c(colNames = 'col_names', na.strings = 'na')) + .check_pkg_availability("readxl") + arg_reconcile(readxl::read_xls, + path = file, ..., sheet = which, + .docall = TRUE, + .remap = c(colNames = "col_names", na.strings = "na") + ) } -#' @importFrom readxl read_xlsx -#' @importFrom openxlsx read.xlsx #' @export .import.rio_xlsx <- function(file, which = 1, readxl = TRUE, ...) { if (isTRUE(readxl)) { .check_pkg_availability("readxl") - arg_reconcile(read_xlsx, path = file, ..., sheet = which, - .docall = TRUE, - .remap = c(colNames = 'col_names', na.strings = 'na')) + arg_reconcile(readxl::read_xlsx, + path = file, ..., sheet = which, + .docall = TRUE, + .remap = c(colNames = "col_names", na.strings = "na") + ) } else { .check_pkg_availability("openxlsx") - arg_reconcile(read.xlsx, xlsxFile = file, ..., sheet = which, - .docall = TRUE, - .remap = c(col_names = 'colNames', na = 'na.strings')) + arg_reconcile(openxlsx::read.xlsx, + xlsxFile = file, ..., sheet = which, + .docall = TRUE, + .remap = c(col_names = "colNames", na = "na.strings") + ) } } -#' @importFrom utils read.fortran #' @export .import.rio_fortran <- function(file, which = 1, style, ...) { if (missing(style)) { @@ -356,19 +353,22 @@ function(file, frml <- formals(readODS::read_ods) unused <- setdiff(names(a), names(frml)) if ("path" %in% names(a)) { - unused <- c(unused, 'path') + unused <- c(unused, "path") a[["path"]] <- NULL } - if (length(unused)>0) { - warning("The following arguments were ignored for read_ods:\n", - paste(unused, collapse = ', ')) + if (length(unused) > 0) { + warning( + "The following arguments were ignored for read_ods:\n", + paste(unused, collapse = ", ") + ) } a <- a[intersect(names(a), names(frml))] - do.call("read_ods", - c(list(path = file, sheet = which, col_names = header),a)) + do.call( + "read_ods", + c(list(path = file, sheet = which, col_names = header), a) + ) } -#' @importFrom utils type.convert #' @export .import.rio_xml <- function(file, which = 1, stringsAsFactors = FALSE, ...) { .check_pkg_availability("xml2") @@ -406,34 +406,33 @@ extract_html_row <- function(x, empty_value) { unlist(to_extract) } -#' @importFrom utils type.convert #' @export .import.rio_html <- function(file, which = 1, stringsAsFactors = FALSE, ..., empty_value = "") { # find all tables tables <- xml2::xml_find_all(xml2::read_html(unclass(file)), ".//table") if (which > length(tables)) { - stop(paste0("Requested table exceeds number of tables found in file (", length(tables),")!")) + stop(paste0("Requested table exceeds number of tables found in file (", length(tables), ")!")) } x <- xml2::as_list(tables[[which]]) if ("tbody" %in% names(x)) { # Note that "tbody" may be specified multiple times in a valid html table - x <- unlist(x[names(x) %in% "tbody"], recursive=FALSE) + x <- unlist(x[names(x) %in% "tbody"], recursive = FALSE) } # loop row-wise over the table and then rbind() ## check for table header to use as column names col_names <- NULL if ("th" %in% names(x[[1]])) { - col_names <- extract_html_row(x[[1]], empty_value=empty_value) - # Drop the first row since column names have already been extracted from it. - x <- x[-1] + col_names <- extract_html_row(x[[1]], empty_value = empty_value) + # Drop the first row since column names have already been extracted from it. + x <- x[-1] } - out <- do.call("rbind", lapply(x, extract_html_row, empty_value=empty_value)) + out <- do.call("rbind", lapply(x, extract_html_row, empty_value = empty_value)) colnames(out) <- - if (is.null(col_names)) { - paste0("V", seq_len(ncol(out))) - } else { - col_names - } + if (is.null(col_names)) { + paste0("V", seq_len(ncol(out))) + } else { + col_names + } out <- as.data.frame(out, ..., stringsAsFactors = stringsAsFactors) # set row names rownames(out) <- seq_len(nrow(out)) @@ -461,9 +460,9 @@ extract_html_row <- function(x, empty_value) { } #' @export -.import.rio_pzfx <- function(file, which=1, ...) { +.import.rio_pzfx <- function(file, which = 1, ...) { .check_pkg_availability("pzfx") - pzfx::read_pzfx(path=file, table=which, ...) + pzfx::read_pzfx(path = file, table = which, ...) } #' @export diff --git a/R/remote_to_local.R b/R/remote_to_local.R index 60ada77..7cc7730 100644 --- a/R/remote_to_local.R +++ b/R/remote_to_local.R @@ -30,13 +30,13 @@ remote_to_local <- function(file, format) { temp_file <- tempfile(fileext = paste0(".", fmt)) u <- curl::curl_fetch_memory(file) writeBin(object = u$content, con = temp_file) - + if (fmt == "TMP") { # try to extract format from curl's final URL fmt <- try(get_ext(u$url), silent = TRUE) if (inherits(fmt, "try-error")) { # try to extract format from headers - h1 <- parse_headers(u$headers) + h1 <- curl::parse_headers(u$headers) # check `Content-Disposition` header if (any(grepl("^Content-Disposition", h1))) { h <- h1[grep("filename", h1)] @@ -54,10 +54,10 @@ remote_to_local <- function(file, format) { stop("Unrecognized file format. Try specifying with the format argument.") } # check `Content-Type` header - #if (any(grepl("^Content-Type", h1))) { + # if (any(grepl("^Content-Type", h1))) { # h <- h1[grep("^Content-Type", h1)] # ## PARSE MIME TYPE - #} + # } } else { f <- sub("TMP$", fmt, temp_file) file.copy(from = temp_file, to = f) diff --git a/R/suggestions.R b/R/suggestions.R index 952860d..e518292 100644 --- a/R/suggestions.R +++ b/R/suggestions.R @@ -2,16 +2,14 @@ #' @description This function installs various \sQuote{Suggests} dependencies for rio that expand its support to the full range of support import and export formats. These packages are not installed or loaded by default in order to create a slimmer and faster package build, install, and load. #' @param \dots Additional arguments passed to [utils::install.packages()]. #' @return `NULL` -#' @importFrom utils install.packages #' @examples #' \donttest{ #' if (interactive()) { -#' install_formats() +#' install_formats() #' } #' } #' @export install_formats <- function(...) { - to_install <- uninstalled_formats() if (length(to_install)) { @@ -20,7 +18,6 @@ install_formats <- function(...) { return(TRUE) } -#' @importFrom utils packageName uninstalled_formats <- function() { # Suggested packages (robust to changes in DESCRIPTION file) # Instead of flagging *new* suggestions by hand, this method only requires diff --git a/man/gather_attrs.Rd b/man/gather_attrs.Rd index 1589e43..e7c58a3 100644 --- a/man/gather_attrs.Rd +++ b/man/gather_attrs.Rd @@ -24,10 +24,10 @@ spread_attrs(x) \examples{ e <- try(import("http://www.stata-press.com/data/r13/auto.dta")) if (!inherits(e, "try-error")) { - str(e) - g <- gather_attrs(e) - str(attributes(e)) - str(g) + str(e) + g <- gather_attrs(e) + str(attributes(e)) + str(g) } } \seealso{ diff --git a/man/install_formats.Rd b/man/install_formats.Rd index 4872c1f..b1bccf2 100644 --- a/man/install_formats.Rd +++ b/man/install_formats.Rd @@ -18,7 +18,7 @@ This function installs various \sQuote{Suggests} dependencies for rio that expan \examples{ \donttest{ if (interactive()) { -install_formats() + install_formats() } } } From bef768bafbb4dfef305e848d9497de874ce9d22a Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Mon, 4 Sep 2023 15:28:15 +0200 Subject: [PATCH 43/44] Add schochastics as ctb [no ci] --- DESCRIPTION | 2 ++ man/rio.Rd | 1 + 2 files changed, 3 insertions(+) diff --git a/DESCRIPTION b/DESCRIPTION index c4239af..7f7edb8 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -5,6 +5,8 @@ Version: 0.5.30 Authors@R: c(person("Jason", "Becker", role = "ctb", email = "jason@jbecker.co"), person("Chung-hong", "Chan", role = c("aut", "cre"), email = "chainsawtiney@gmail.com", comment = c(ORCID = "0000-0002-6232-7530")), + person("David", "Schoch", email = "david@schochastics.net", role = c("ctb"), + comment = c(ORCID = "0000-0003-2952-4812")), person("Geoffrey CH", "Chan", role = "ctb", email = "gefchchan@gmail.com"), person("Thomas J.", "Leeper", role = "aut", diff --git a/man/rio.Rd b/man/rio.Rd index e83e1bd..a995c86 100644 --- a/man/rio.Rd +++ b/man/rio.Rd @@ -46,6 +46,7 @@ Authors: Other contributors: \itemize{ \item Jason Becker \email{jason@jbecker.co} [contributor] + \item David Schoch \email{david@schochastics.net} (\href{https://orcid.org/0000-0003-2952-4812}{ORCID}) [contributor] \item Geoffrey CH Chan \email{gefchchan@gmail.com} [contributor] \item Christopher Gandrud [contributor] \item Andrew MacDonald [contributor] From 442b7d350e555fd55aec4e76a4f68c56e20dede4 Mon Sep 17 00:00:00 2001 From: chainsawriot Date: Mon, 4 Sep 2023 15:31:17 +0200 Subject: [PATCH 44/44] Update NEWS.md [no ci] --- NEWS.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NEWS.md b/NEWS.md index b49422c..6a3fef4 100644 --- a/NEWS.md +++ b/NEWS.md @@ -12,6 +12,9 @@ * Declutter - remove the obsolete data.table option #323 - write all documentation blocks in markdown #311 + - remove all @importFrom #325 h/t David Schoch +* New Contributors + - David Schoch @schochastics # rio 0.5.30