├── .Rbuildignore ├── .editorconfig ├── .github ├── .gitignore └── workflows │ ├── R-CMD-check.yaml │ ├── pkgdown.yml │ └── test-coverage.yaml ├── .gitignore ├── CONTRIBUTING.md ├── DESCRIPTION ├── Makefile ├── NAMESPACE ├── NEWS.md ├── R ├── characterize.R ├── compression.R ├── convert.R ├── export.R ├── export_list.R ├── export_methods.R ├── extensions.R ├── gather_attrs.R ├── import.R ├── import_list.R ├── import_methods.R ├── onLoad.R ├── remote_to_local.R ├── rio.R ├── set_class.R ├── standardize_attributes.R ├── suggestions.R ├── sysdata.rda └── utils.R ├── README.Rmd ├── README.md ├── _pkgdown.yml ├── codecov.yml ├── data-raw ├── convert.R ├── obsolete │ ├── arg_reconcile.R │ ├── is_file_text.R │ ├── old_logo │ │ ├── logo.png │ │ └── logo.svg │ ├── test_arg_reconcile.R │ └── test_is_file_text.R ├── readme.md └── single.json ├── inst └── CITATION ├── man ├── characterize.Rd ├── convert.Rd ├── export.Rd ├── export_list.Rd ├── figures │ ├── logo.png │ └── logo.svg ├── gather_attrs.Rd ├── get_info.Rd ├── import.Rd ├── import_list.Rd ├── install_formats.Rd └── rio.Rd ├── po └── R-rio.pot ├── rio.Rproj ├── starwars.csv ├── starwars.xlsx ├── tests ├── testdata │ ├── br-in-header.html │ ├── br-in-td.html │ ├── example.csvy │ ├── iris.xls │ ├── iris_no_extension_xls │ ├── mtcars.ods │ ├── noheader.csv │ ├── th-as-row-element.html │ ├── two-tbody.html │ └── twotables.html ├── testthat.R └── testthat │ ├── test_characterize.R │ ├── test_check_file.R │ ├── test_compress.R │ ├── test_convert.R │ ├── test_create_outfiles.R │ ├── test_errors.R │ ├── test_export_corner_cases.R │ ├── test_export_list.R │ ├── test_extensions.R │ ├── test_format_R.R │ ├── test_format_arff.R │ ├── test_format_csv.R │ ├── test_format_csvy.R │ ├── test_format_dbf.R │ ├── test_format_dif.R │ ├── test_format_dta.R │ ├── test_format_eviews.R │ ├── test_format_external_packages.R │ ├── test_format_feather.R │ ├── test_format_fortran.R │ ├── test_format_fst.R │ ├── test_format_fwf.R │ ├── test_format_html.R │ ├── test_format_json.R │ ├── test_format_matlab.R │ ├── test_format_mtp.R │ ├── test_format_ods.R │ ├── test_format_parquet.R │ ├── test_format_psv.R │ ├── test_format_pzfx.R │ ├── test_format_qs.R │ ├── test_format_rdata.R │ ├── test_format_rds.R │ ├── test_format_rec.R │ ├── test_format_sas.R │ ├── test_format_sav.R │ ├── test_format_syd.R │ ├── test_format_tsv.R │ ├── test_format_xls.R │ ├── test_format_xml.R │ ├── test_format_yml.R │ ├── test_gather_attrs.R │ ├── test_guess.R │ ├── test_identical.R │ ├── test_import_list.R │ ├── test_mapping.R │ ├── test_matrix.R │ ├── test_remote.R │ ├── test_set_class.R │ ├── test_suggestions.R │ └── test_trust.R └── vignettes ├── .gitignore ├── extension.Rmd ├── labelled.Rmd ├── philosophy.Rmd ├── remap.Rmd └── rio.Rmd /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^pkgdown/.+$ 2 | .github/* 3 | ^\.travis\.yml$ 4 | ^appveyor\.yml$ 5 | ^travis-tool\.sh$ 6 | ^Makefile$ 7 | ^README\.Rmd$ 8 | ^README\.html$ 9 | ^README_files$ 10 | ^README_files/.+$ 11 | ^CONTRIBUTING\.md$ 12 | ^inst/standarderrors\.pdf$ 13 | ^figure$ 14 | ^figure/.+$ 15 | ^man-roxygen$ 16 | ^man-roxygen/.+$ 17 | ^revdep$ 18 | ^revdep/.+$ 19 | ^cache/.+$ 20 | ^docs$ 21 | ^docs/.+$ 22 | ^ignore$ 23 | ^inst/doc/.+\.log$ 24 | ^vignettes/figure$ 25 | ^vignettes/figure/.+$ 26 | ^vignettes/.+\.aux$ 27 | ^vignettes/.+\.bbl$ 28 | ^vignettes/.+\.blg$ 29 | ^vignettes/.+\.dvi$ 30 | ^vignettes/.+\.log$ 31 | ^vignettes/.+\.out$ 32 | ^vignettes/.+\.pdf$ 33 | ^vignettes/.+\.sty$ 34 | ^vignettes/.+\.tex$ 35 | ^data-raw$ 36 | ^.*\.Rproj$ 37 | ^\.Rproj\.user$ 38 | ^\.github$ 39 | ^\.editorconfig$ 40 | ^starwars.xlsx$ 41 | ^starwars.csv$ 42 | ^codecov\.yml$ 43 | ^cran-comments\.md$ 44 | ^CRAN-SUBMISSION$ 45 | ^codemeta\.json$ 46 | ^_pkgdown\.yml$ 47 | ^pkgdown$ 48 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | 4 | [*] 5 | charset = utf8 6 | end_of_line = lf 7 | insert_final_newline = true 8 | indent_style = space 9 | 10 | 11 | [*.{r,R,rmd,Rmd,cpp}] 12 | indent_size = 4 13 | trim_trailing_whitespace = true 14 | 15 | [Makefile] 16 | indent_style = tab 17 | -------------------------------------------------------------------------------- /.github/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | -------------------------------------------------------------------------------- /.github/workflows/R-CMD-check.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | branches: [main, master] 8 | 9 | name: R-CMD-check 10 | 11 | jobs: 12 | R-CMD-check: 13 | runs-on: ${{ matrix.config.os }} 14 | 15 | name: ${{ matrix.config.os }} (${{ matrix.config.r }}) 16 | 17 | strategy: 18 | fail-fast: false 19 | matrix: 20 | config: 21 | - {os: macos-latest, r: 'release'} 22 | - {os: windows-latest, r: 'release'} 23 | - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} 24 | - {os: ubuntu-latest, r: 'release'} 25 | - {os: ubuntu-latest, r: 'oldrel-1'} 26 | - {os: ubuntu-latest, r: 'oldrel-2'} 27 | - {os: ubuntu-latest, r: 'oldrel-3'} 28 | 29 | env: 30 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 31 | R_KEEP_PKG_SOURCE: yes 32 | 33 | steps: 34 | - uses: actions/checkout@v3 35 | 36 | - uses: r-lib/actions/setup-pandoc@v2 37 | 38 | - uses: r-lib/actions/setup-r@v2 39 | with: 40 | r-version: ${{ matrix.config.r }} 41 | http-user-agent: ${{ matrix.config.http-user-agent }} 42 | use-public-rspm: true 43 | 44 | - uses: r-lib/actions/setup-r-dependencies@v2 45 | with: 46 | extra-packages: any::rcmdcheck, arrow=?ignore-before-r=4.0.0 47 | needs: check 48 | 49 | - uses: r-lib/actions/check-r-package@v2 50 | with: 51 | upload-snapshots: true 52 | -------------------------------------------------------------------------------- /.github/workflows/pkgdown.yml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | # pull_request: 7 | # branches: [main, master] 8 | release: 9 | types: [published] 10 | workflow_dispatch: 11 | 12 | name: pkgdown 13 | 14 | jobs: 15 | pkgdown: 16 | runs-on: ubuntu-latest 17 | # Only restrict concurrency for non-PR jobs 18 | concurrency: 19 | group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }} 20 | env: 21 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 22 | permissions: 23 | contents: write 24 | steps: 25 | - uses: actions/checkout@v3 26 | 27 | - uses: r-lib/actions/setup-pandoc@v2 28 | 29 | - uses: r-lib/actions/setup-r@v2 30 | with: 31 | use-public-rspm: true 32 | 33 | - uses: r-lib/actions/setup-r-dependencies@v2 34 | with: 35 | extra-packages: any::pkgdown, local::. 36 | needs: website 37 | 38 | - name: Build site 39 | run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE) 40 | shell: Rscript {0} 41 | 42 | - name: Deploy to GitHub pages 🚀 43 | if: github.event_name != 'pull_request' 44 | uses: JamesIves/github-pages-deploy-action@v4.4.1 45 | with: 46 | clean: false 47 | branch: gh-pages 48 | folder: docs 49 | -------------------------------------------------------------------------------- /.github/workflows/test-coverage.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | branches: [main, master] 8 | 9 | name: test-coverage 10 | 11 | jobs: 12 | test-coverage: 13 | runs-on: ubuntu-latest 14 | env: 15 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 16 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} 17 | 18 | steps: 19 | - uses: actions/checkout@v3 20 | 21 | - uses: r-lib/actions/setup-r@v2 22 | with: 23 | use-public-rspm: true 24 | 25 | - uses: r-lib/actions/setup-r-dependencies@v2 26 | with: 27 | extra-packages: any::covr 28 | needs: coverage 29 | 30 | - name: Test coverage 31 | run: | 32 | covr::codecov( 33 | quiet = FALSE, 34 | clean = FALSE, 35 | install_path = file.path(Sys.getenv("RUNNER_TEMP"), "package") 36 | ) 37 | shell: Rscript {0} 38 | 39 | - name: Show testthat output 40 | if: always() 41 | run: | 42 | ## -------------------------------------------------------------------- 43 | find ${{ runner.temp }}/package -name 'testthat.Rout*' -exec cat '{}' \; || true 44 | shell: bash 45 | 46 | - name: Upload test results 47 | if: failure() 48 | uses: actions/upload-artifact@v3 49 | with: 50 | name: coverage-test-failures 51 | path: ${{ runner.temp }}/package 52 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | .Rhistory 3 | .Rproj.user 4 | revdep/* 5 | README.html 6 | inst/doc 7 | docs 8 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributions to **rio** are welcome from anyone and are best sent as pull requests on [the GitHub repository](https://github.com/gesistsa/rio/). This page provides some instructions to potential contributors about how to add to the package. 2 | 3 | 1. Contributions can be submitted as [a pull request](https://help.github.com/articles/creating-a-pull-request/) on GitHub by forking or cloning the [repo](https://github.com/gesistsa/rio/), making changes and submitting the pull request. 4 | 5 | 2. 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. 6 | 7 | 3. All contributions must be submitted consistent with the package license ([GPL-2](http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)). 8 | 9 | 4. All contributions need to be noted in the `Authors@R` field in the [DESCRIPTION](https://github.com/gesistsa/rio/blob/master/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`](https://github.com/gesistsa/rio/blob/master/inst/CITATION). 10 | 11 | 5. 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. 12 | 13 | 6. Please run `R CMD BUILD rio` and `R CMD CHECK rio_VERSION.tar.gz` before submitting the pull request to check for any errors. 14 | 15 | Some specific types of changes that you might make are: 16 | 17 | 1. Documentation-only changes (e.g., to Rd files, README, vignettes). This is great! All contributions are welcome. 18 | 19 | 2. Addition of new file format imports or exports. This is also great! Some advice: 20 | 21 | - 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. See the Vignette: `remap`. 22 | 23 | - The S3 methods should be documented in [NAMESPACE](https://github.com/gesistsa/rio/blob/master/NAMESPACE) using `S3method()`, which is handled automatically by roxygen markup in the source code. 24 | - Any new format support needs to be documented in each of the following places: [README.Rmd](https://github.com/gesistsa/rio/blob/master/README.Rmd), [the vignette](https://github.com/gesistsa/rio/blob/master/vignettes/rio.Rmd), and the appropriate Rd file in [`/man`](https://github.com/gesistsa/rio/tree/master/man). 25 | 26 | - New formats or new options for handling formats should have a test added in [`/tests/testthat`](https://github.com/gesistsa/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/gesistsa/rio/tree/master/inst/examples) (e.g., for testing `import()`). 27 | 28 | 3. Changes requiring a new package dependency should be discussed on the GitHub issues page before submitting a pull request. 29 | 30 | 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. 31 | 32 | Any questions you have can be opened as GitHub issues. 33 | 34 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: rio 2 | Type: Package 3 | Title: A Swiss-Army Knife for Data I/O 4 | Version: 1.2.4 5 | Authors@R: c(person("Jason", "Becker", role = "aut", email = "jason@jbecker.co"), 6 | person("Chung-hong", "Chan", role = c("aut", "cre"), email = "chainsawtiney@gmail.com", 7 | comment = c(ORCID = "0000-0002-6232-7530")), 8 | person("David", "Schoch", email = "david@schochastics.net", role = c("aut"), 9 | comment = c(ORCID = "0000-0003-2952-4812")), 10 | person("Geoffrey CH", "Chan", role = "ctb", email = "gefchchan@gmail.com"), 11 | person("Thomas J.", "Leeper", 12 | role = "aut", 13 | email = "thosjleeper@gmail.com", 14 | comment = c(ORCID = "0000-0003-4097-6326")), 15 | person("Christopher", "Gandrud", role = "ctb"), 16 | person("Andrew", "MacDonald", role = "ctb"), 17 | person("Ista", "Zahn", role = "ctb"), 18 | person("Stanislaus", "Stadlmann", role = "ctb"), 19 | person("Ruaridh", "Williamson", role = "ctb", email = "ruaridh.williamson@gmail.com"), 20 | person("Patrick", "Kennedy", role = "ctb"), 21 | person("Ryan", "Price", email = "ryapric@gmail.com", role = "ctb"), 22 | person("Trevor L", "Davis", email = "trevor.l.davis@gmail.com", role = "ctb"), 23 | person("Nathan", "Day", email = "nathancday@gmail.com", role = "ctb"), 24 | person("Bill", "Denney", 25 | email="wdenney@humanpredictions.com", 26 | role="ctb", 27 | comment=c(ORCID="0000-0002-5759-428X")), 28 | person("Alex", "Bokov", email = "alex.bokov@gmail.com", role = "ctb", 29 | comment=c(ORCID="0000-0002-0511-9815")), 30 | person("Hugo", "Gruson", role = "ctb", comment = c(ORCID = "0000-0002-4094-1476")) 31 | ) 32 | Description: Streamlined data import and export by making assumptions that 33 | the user is probably willing to make: 'import()' and 'export()' determine 34 | the data format from the file extension, reasonable defaults are used for 35 | data import and export, web-based import is natively supported (including 36 | from SSL/HTTPS), compressed files can be read directly, and fast import 37 | packages are used where appropriate. An additional convenience function, 38 | 'convert()', provides a simple method for converting between file types. 39 | URL: https://gesistsa.github.io/rio/, https://github.com/gesistsa/rio 40 | BugReports: https://github.com/gesistsa/rio/issues 41 | Depends: 42 | R (>= 4.0) 43 | Imports: 44 | tools, 45 | stats, 46 | utils, 47 | foreign, 48 | haven (>= 1.1.2), 49 | curl (>= 0.6), 50 | data.table (>= 1.11.2), 51 | readxl (>= 0.1.1), 52 | tibble, 53 | writexl, 54 | lifecycle, 55 | R.utils, 56 | readr 57 | Suggests: 58 | datasets, 59 | bit64, 60 | testthat, 61 | knitr, 62 | magrittr, 63 | clipr, 64 | fst, 65 | hexView, 66 | jsonlite, 67 | pzfx, 68 | readODS (>= 2.1.0), 69 | rmarkdown, 70 | rmatio, 71 | xml2 (>= 1.2.0), 72 | yaml, 73 | qs, 74 | arrow (>= 0.17.0), 75 | stringi, 76 | withr, 77 | nanoparquet 78 | License: GPL-2 79 | VignetteBuilder: knitr 80 | Encoding: UTF-8 81 | RoxygenNote: 7.3.1 82 | Roxygen: list(markdown = TRUE) 83 | Config/Needs/website: gesistsa/tsatemplate 84 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | pkg = $(shell basename $(CURDIR)) 2 | 3 | all: build 4 | 5 | NAMESPACE: R/* 6 | Rscript -e "devtools::document()" 7 | 8 | README.md: README.Rmd 9 | Rscript -e "knitr::knit('README.Rmd')" 10 | 11 | R/sysdata.rda: data-raw/single.json 12 | Rscript data-raw/convert.R 13 | Rscript -e "devtools::build_readme()" 14 | README.html: README.md 15 | pandoc -o README.html README.md 16 | 17 | ../$(pkg)*.tar.gz: DESCRIPTION NAMESPACE README.md R/* man/* tests/testthat/* po/R-rio.pot R/sysdata.rda 18 | cd ../ && R CMD build $(pkg) 19 | 20 | build: ../$(pkg)*.tar.gz 21 | 22 | check: ../$(pkg)*.tar.gz 23 | cd ../ && R CMD check $(pkg)*.tar.gz 24 | rm ../$(pkg)*.tar.gz 25 | 26 | install: ../$(pkg)*.tar.gz 27 | cd ../ && R CMD INSTALL $(pkg)*.tar.gz 28 | rm ../$(pkg)*.tar.gz 29 | 30 | website: R/* README.md DESCRIPTION 31 | Rscript -e "pkgdown::build_site()" 32 | 33 | po/R-rio.pot: R/* DESCRIPTION 34 | Rscript -e "tools::update_pkg_po('.')" 35 | 36 | translations: po/R-rio.pot 37 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | S3method(.export,rio_arff) 4 | S3method(.export,rio_clipboard) 5 | S3method(.export,rio_csv) 6 | S3method(.export,rio_csv2) 7 | S3method(.export,rio_csvy) 8 | S3method(.export,rio_dbf) 9 | S3method(.export,rio_dta) 10 | S3method(.export,rio_dump) 11 | S3method(.export,rio_feather) 12 | S3method(.export,rio_fods) 13 | S3method(.export,rio_fst) 14 | S3method(.export,rio_fwf) 15 | S3method(.export,rio_html) 16 | S3method(.export,rio_json) 17 | S3method(.export,rio_matlab) 18 | S3method(.export,rio_ods) 19 | S3method(.export,rio_parquet) 20 | S3method(.export,rio_psv) 21 | S3method(.export,rio_pzfx) 22 | S3method(.export,rio_qs) 23 | S3method(.export,rio_r) 24 | S3method(.export,rio_rda) 25 | S3method(.export,rio_rdata) 26 | S3method(.export,rio_rds) 27 | S3method(.export,rio_sas7bdat) 28 | S3method(.export,rio_sav) 29 | S3method(.export,rio_tsv) 30 | S3method(.export,rio_txt) 31 | S3method(.export,rio_xlsx) 32 | S3method(.export,rio_xml) 33 | S3method(.export,rio_xpt) 34 | S3method(.export,rio_yml) 35 | S3method(.export,rio_zsav) 36 | S3method(.import,rio_arff) 37 | S3method(.import,rio_clipboard) 38 | S3method(.import,rio_csv) 39 | S3method(.import,rio_csv2) 40 | S3method(.import,rio_csvy) 41 | S3method(.import,rio_dat) 42 | S3method(.import,rio_dbf) 43 | S3method(.import,rio_dif) 44 | S3method(.import,rio_dta) 45 | S3method(.import,rio_dump) 46 | S3method(.import,rio_eviews) 47 | S3method(.import,rio_feather) 48 | S3method(.import,rio_fods) 49 | S3method(.import,rio_fortran) 50 | S3method(.import,rio_fst) 51 | S3method(.import,rio_fwf) 52 | S3method(.import,rio_html) 53 | S3method(.import,rio_json) 54 | S3method(.import,rio_matlab) 55 | S3method(.import,rio_mtp) 56 | S3method(.import,rio_ods) 57 | S3method(.import,rio_parquet) 58 | S3method(.import,rio_psv) 59 | S3method(.import,rio_pzfx) 60 | S3method(.import,rio_qs) 61 | S3method(.import,rio_r) 62 | S3method(.import,rio_rda) 63 | S3method(.import,rio_rdata) 64 | S3method(.import,rio_rds) 65 | S3method(.import,rio_rec) 66 | S3method(.import,rio_sas7bdat) 67 | S3method(.import,rio_sav) 68 | S3method(.import,rio_spss) 69 | S3method(.import,rio_syd) 70 | S3method(.import,rio_tsv) 71 | S3method(.import,rio_txt) 72 | S3method(.import,rio_xls) 73 | S3method(.import,rio_xlsx) 74 | S3method(.import,rio_xml) 75 | S3method(.import,rio_xpt) 76 | S3method(.import,rio_yml) 77 | S3method(.import,rio_zsav) 78 | S3method(characterize,data.frame) 79 | S3method(characterize,default) 80 | S3method(factorize,data.frame) 81 | S3method(factorize,default) 82 | export(characterize) 83 | export(convert) 84 | export(export) 85 | export(export_list) 86 | export(factorize) 87 | export(gather_attrs) 88 | export(get_ext) 89 | export(get_info) 90 | export(import) 91 | export(import_list) 92 | export(install_formats) 93 | export(show_unsupported_formats) 94 | export(spread_attrs) 95 | -------------------------------------------------------------------------------- /R/characterize.R: -------------------------------------------------------------------------------- 1 | #' @rdname characterize 2 | #' @title Character conversion of labelled data 3 | #' @description Convert labelled variables to character or factor 4 | #' @param x A vector or data frame. 5 | #' @param coerce_character A logical indicating whether to additionally coerce character columns to factor (in `factorize`). Default `FALSE`. 6 | #' @param \dots additional arguments passed to methods 7 | #' @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. 8 | #' @return a character vector (for `characterize`) or factor vector (for `factorize`) 9 | #' @examples 10 | #' ## vector method 11 | #' x <- structure(1:4, labels = c("A" = 1, "B" = 2, "C" = 3)) 12 | #' characterize(x) 13 | #' factorize(x) 14 | #' 15 | #' ## data frame method 16 | #' x <- data.frame(v1 = structure(1:4, labels = c("A" = 1, "B" = 2, "C" = 3)), 17 | #' v2 = structure(c(1,0,0,1), labels = c("foo" = 0, "bar" = 1))) 18 | #' str(factorize(x)) 19 | #' str(characterize(x)) 20 | #' 21 | #' ## Application 22 | #' csv_file <- tempfile(fileext = ".csv") 23 | #' ## comparison of exported file contents 24 | #' import(export(x, csv_file)) 25 | #' import(export(factorize(x), csv_file)) 26 | #' @seealso [gather_attrs()] 27 | #' @export 28 | characterize <- function(x, ...) { 29 | UseMethod("characterize") 30 | } 31 | 32 | #' @rdname characterize 33 | #' @export 34 | factorize <- function(x, ...) { 35 | UseMethod("factorize") 36 | } 37 | 38 | #' @rdname characterize 39 | #' @export 40 | characterize.default <- function(x, ...) { 41 | # retain variable label, if present 42 | if (!is.null(attributes(x)[["label"]])) { 43 | varlab <- attributes(x)[["label"]] 44 | } else { 45 | varlab <- NULL 46 | } 47 | 48 | if (!is.null(attributes(x)[["labels"]])) { 49 | x <- as.character(factorize(x, ...)) 50 | if (!is.null(varlab)) { 51 | attr(x, "label") <- varlab 52 | } 53 | } 54 | 55 | return(x) 56 | } 57 | 58 | #' @rdname characterize 59 | #' @export 60 | characterize.data.frame <- function(x, ...) { 61 | x[] <- lapply(x, characterize, ...) 62 | x 63 | } 64 | 65 | #' @rdname characterize 66 | #' @export 67 | factorize.default <- function(x, coerce_character=FALSE, ...) { 68 | # retain variable label, if present 69 | if (!is.null(attributes(x)[["label"]])) { 70 | varlab <- attributes(x)[["label"]] 71 | } else { 72 | varlab <- NULL 73 | } 74 | 75 | if (!is.null(attributes(x)[["labels"]])) { 76 | x <- factor(x, attributes(x)[["labels"]], names(attributes(x)[["labels"]]), ...) 77 | } else if (is.character(x) && isTRUE(coerce_character)) { 78 | levs <- sort(unique(x)) 79 | x <- factor(x, levs) 80 | } 81 | 82 | if (!is.null(varlab)) { 83 | attr(x, "label") <- varlab 84 | } 85 | 86 | return(x) 87 | } 88 | 89 | #' @rdname characterize 90 | #' @export 91 | factorize.data.frame <- function(x, ...) { 92 | x[] <- lapply(x, factorize, ...) 93 | x 94 | } 95 | -------------------------------------------------------------------------------- /R/compression.R: -------------------------------------------------------------------------------- 1 | find_compress <- function(f) { 2 | if (endsWith(f, ".zip")) { 3 | return(list(file = sub("\\.zip$", "", f), compress = "zip")) 4 | } 5 | if (endsWith(f, ".tar.gz")) { 6 | return(list(file = sub("\\.tar\\.gz$", "", f), compress = "tar.gz")) 7 | } 8 | if (endsWith(f, ".tgz")) { 9 | return(list(file = sub("\\.tgz$", "", f), compress = "tar.gz")) 10 | } 11 | if (endsWith(f, ".tar.bz2")) { 12 | return(list(file = sub("\\.tar\\.bz2$", "", f), compress = "tar.bz2")) 13 | } 14 | if (endsWith(f, ".tbz2")) { 15 | return(list(file = sub("\\.tbz2$", "", f), compress = "tar.bz2")) 16 | } 17 | if (endsWith(f, ".tar")) { 18 | return(list(file = sub("\\.tar$", "", f), compress = "tar")) 19 | } 20 | if (endsWith(f, ".gzip")) { 21 | ## weird 22 | return(list(file = sub("\\.gzip$", "", f), compress = "gzip")) 23 | } 24 | if (endsWith(f, ".gz")) { 25 | return(list(file = sub("\\.gz$", "", f), compress = "gzip")) 26 | } 27 | if (endsWith(f, ".bz2")) { 28 | return(list(file = sub("\\.bz2$", "", f), compress = "bzip2")) 29 | } 30 | if (endsWith(f, ".bzip2")) { 31 | ## weird 32 | return(list(file = sub("\\.bzip2$", "", f), compress = "bzip2")) 33 | } 34 | return(list(file = f, compress = NA_character_)) 35 | } 36 | 37 | compress_out <- function(cfile, filename, type = c("zip", "tar", "tar.gz", "tar.bz2", "gzip", "bzip2")) { 38 | type <- ext <- match.arg(type) 39 | cfile2 <- basename(cfile) 40 | filename <- normalizePath(filename) 41 | if (type %in% c("gzip", "bzip2")) { 42 | return(.compress_rutils(filename, cfile, ext = ext)) 43 | } 44 | tmp <- tempfile() 45 | dir.create(tmp) 46 | on.exit(unlink(tmp, recursive = TRUE), add = TRUE) 47 | file.copy(from = filename, to = file.path(tmp, basename(filename)), overwrite = TRUE) 48 | wd <- getwd() 49 | on.exit(setwd(wd), add = TRUE) ## for security, see #438 and #319 50 | setwd(tmp) 51 | if (type == "zip") { 52 | o <- utils::zip(cfile2, files = basename(filename)) 53 | } 54 | if (type == "tar") { 55 | o <- utils::tar(cfile2, files = basename(filename), compression = "none") 56 | } 57 | if (type == "tar.gz") { 58 | o <- utils::tar(cfile2, files = basename(filename), compression = "gzip") 59 | } 60 | if (type == "tar.bz2") { 61 | o <- utils::tar(cfile2, files = basename(filename), compression = "bzip2") 62 | } 63 | setwd(wd) ## see #438 64 | if (o != 0) { 65 | stop(sprintf("File compression failed for %s!", cfile)) 66 | } 67 | file.copy(from = file.path(tmp, cfile2), to = cfile, overwrite = TRUE) 68 | return(cfile) 69 | } 70 | 71 | parse_archive <- function(file, which, file_type, ...) { 72 | if (file_type %in% c("gzip", "bzip2")) { 73 | ## it doesn't have the same interface as unzip 74 | return(.parse_rutils(filename = file, file_type = file_type)) 75 | } 76 | if (file_type == "zip") { 77 | extract_func <- utils::unzip 78 | } 79 | if (file_type %in% c("tar", "tar.gz", "tar.bz2")) { 80 | extract_func <- utils::untar 81 | } 82 | file_list <- .list_archive(file, file_type) 83 | d <- tempfile() 84 | dir.create(d) 85 | 86 | if (is.numeric(which)) { 87 | extract_func(file, files = file_list[which], exdir = d) 88 | return(file.path(d, file_list[which])) 89 | } 90 | if (substring(which, 1, 1) != "^") { 91 | which2 <- paste0("^", which) 92 | } 93 | extract_func(file, files = file_list[grep(which2, file_list)[1]], exdir = d) 94 | return(file.path(d, which)) 95 | } 96 | 97 | .list_archive <- function(file, file_type = c("zip", "tar", "tar.gz", "tar.bz2")) { 98 | ## just a simple wrapper to unify the interface of utils::unzip and utils::untar 99 | file_type <- match.arg(file_type) 100 | if (file_type == "zip") { 101 | file_list <- utils::unzip(file, list = TRUE)$Name 102 | } 103 | if (file_type %in% c("tar", "tar.gz", "tar.bz2")) { 104 | file_list <- utils::untar(file, list = TRUE) 105 | } 106 | return(file_list) 107 | } 108 | 109 | .compress_rutils <- function(filename, cfile, ext, remove = TRUE, FUN = gzfile) { 110 | ## Caution: Please note that remove = TRUE by default, it will delete `filename`! 111 | if (ext == "bzip2") { 112 | FUN <- bzfile 113 | } 114 | tmp_cfile <- R.utils::compressFile(filename = filename, destname = tempfile(), ext = ext, FUN = FUN, overwrite = TRUE, remove = remove) 115 | file.copy(from = tmp_cfile, to = cfile, overwrite = TRUE) 116 | unlink(tmp_cfile) 117 | return(cfile) 118 | } 119 | 120 | .parse_rutils <- function(filename, file_type) { 121 | if (file_type == "gzip") { 122 | decompression_fun <- gzfile 123 | } 124 | if (file_type == "bzip2") { 125 | decompression_fun <- bzfile 126 | } 127 | destname <- tempfile() 128 | R.utils::decompressFile(filename = filename, destname = destname, temporary = TRUE, remove = FALSE, overwrite = TRUE, FUN = decompression_fun, ext = file_type) 129 | } 130 | 131 | .check_tar_support <- function(file_type, rversion) { 132 | if (file_type %in% c("tar", "tar.gz", "tar.bz2") && rversion < "4.0.3") { 133 | stop("Exporting to tar formats is not supported for this version of R.", call. = FALSE) 134 | } 135 | NULL 136 | } 137 | 138 | .get_compressed_format <- function(cfile, file, file_type, format) { 139 | if (file_type %in% c("gzip", "bzip2")) { 140 | return(ifelse(isFALSE(missing(format)), tolower(format), get_info(find_compress(cfile)$file)$input)) 141 | } 142 | ## zip or tar formats, use the decompressed file path 143 | return(ifelse(isFALSE(missing(format)), tolower(format), get_info(file)$input)) 144 | } 145 | -------------------------------------------------------------------------------- /R/convert.R: -------------------------------------------------------------------------------- 1 | #' @title Convert from one file format to another 2 | #' @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. 3 | #' @param in_file A character string naming an input file. 4 | #' @param out_file A character string naming an output file. 5 | #' @param in_opts A named list of options to be passed to [import()]. 6 | #' @param out_opts A named list of options to be passed to [export()]. 7 | #' @return A character string containing the name of the output file (invisibly). 8 | #' @examples 9 | #' ## For demo, a temp. file path is created with the file extension .dta (Stata) 10 | #' dta_file <- tempfile(fileext = ".dta") 11 | #' ## .csv 12 | #' csv_file <- tempfile(fileext = ".csv") 13 | #' ## .xlsx 14 | #' xlsx_file <- tempfile(fileext = ".xlsx") 15 | #' 16 | #' 17 | #' ## Create a Stata data file 18 | #' export(mtcars, dta_file) 19 | #' 20 | #' ## convert Stata to CSV and open converted file 21 | #' convert(dta_file, csv_file) 22 | #' import(csv_file) 23 | #' 24 | #' ## correct an erroneous file format 25 | #' export(mtcars, xlsx_file, format = "tsv") ## DON'T DO THIS 26 | #' ## import(xlsx_file) ## ERROR 27 | #' ## convert the file by specifying `in_opts` 28 | #' convert(xlsx_file, xlsx_file, in_opts = list(format = "tsv")) 29 | #' import(xlsx_file) 30 | #' 31 | #' ## convert from the command line: 32 | #' ## Rscript -e "rio::convert('mtcars.dta', 'mtcars.csv')" 33 | #' @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. 34 | #' @export 35 | convert <- function(in_file, out_file, in_opts=list(), out_opts=list()) { 36 | if (missing(out_file)) { 37 | stop("'outfile' is missing with no default") 38 | } 39 | invisible(do.call("export", c(list(file = out_file, x = do.call("import", c(list(file=in_file), in_opts))), out_opts))) 40 | } 41 | -------------------------------------------------------------------------------- /R/export.R: -------------------------------------------------------------------------------- 1 | #' @rdname export 2 | #' @title Export 3 | #' @description Write data.frame to a file 4 | #' @param x A data frame, matrix or a single-item list of data frame to be written into a file. Exceptions to this rule are that `x` can be a list of multiple data frames if the output file format is an OpenDocument Spreadsheet (.ods, .fods), 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. 5 | #' @param file A character string naming a file. Must specify `file` and/or `format`. 6 | #' @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()]. 7 | #' @param \dots Additional arguments for the underlying export functions. This can be used to specify non-standard arguments. See examples. 8 | #' @return The name of the output file as a character string (invisibly). 9 | #' @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). 10 | #' 11 | #' 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}. 12 | #' 13 | #' `export` supports many file formats. See the documentation for the underlying export functions for optional arguments that can be passed via `...` 14 | #' 15 | #' \itemize{ 16 | #' \item Comma-separated data (.csv), using [data.table::fwrite()] 17 | #' \item Pipe-separated data (.psv), using [data.table::fwrite()] 18 | #' \item Tab-separated data (.tsv), using [data.table::fwrite()] 19 | #' \item SAS (.sas7bdat), using [haven::write_sas()]. 20 | #' \item SAS XPORT (.xpt), using [haven::write_xpt()]. 21 | #' \item SPSS (.sav), using [haven::write_sav()] 22 | #' \item SPSS compressed (.zsav), using [haven::write_sav()] 23 | #' \item Stata (.dta), using [haven::write_dta()]. Note that variable/column names containing dots (.) are not allowed and will produce an error. 24 | #' \item Excel (.xlsx), using [writexl::write_xlsx()]. `x` can also be a list of data frames; the list entry names are used as sheet names. 25 | #' \item R syntax object (.R), using [base::dput()] (by default) or [base::dump()] (if `format = 'dump'`) 26 | #' \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. 27 | #' \item Serialized R objects (.rds), using [base::saveRDS()]. In this case, `x` can be any serializable R object. 28 | #' \item Serialized R objects (.qs), using [qs::qsave()], which is 29 | #' significantly faster than .rds. This can be any R 30 | #' object (not just a data frame). 31 | #' \item "XBASE" database files (.dbf), using [foreign::write.dbf()] 32 | #' \item Weka Attribute-Relation File Format (.arff), using [foreign::write.arff()] 33 | #' \item Fixed-width format data (.fwf), using [utils::write.table()] with `row.names = FALSE`, `quote = FALSE`, and `col.names = FALSE` 34 | #' \item [CSVY](https://github.com/csvy) (CSV with a YAML metadata header) using [data.table::fwrite()]. 35 | #' \item Apache Arrow Parquet (.parquet), using [nanoparquet::write_parquet()] 36 | #' \item Feather R/Python interchange format (.feather), using [arrow::write_feather()] 37 | #' \item Fast storage (.fst), using [fst::write.fst()] 38 | #' \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). 39 | #' \item Matlab (.mat), using [rmatio::write.mat()] 40 | #' \item OpenDocument Spreadsheet (.ods, .fods), using [readODS::write_ods()] or [readODS::write_fods()]. 41 | #' \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. 42 | #' \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. 43 | #' \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. 44 | #' \item Clipboard export (on Windows and Mac OS), using [utils::write.table()] with `row.names = FALSE` 45 | #' } 46 | #' 47 | #' 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. 48 | #' 49 | #' Use [export_list()] to export a list of dataframes to separate files. 50 | #' 51 | #' @examples 52 | #' ## For demo, a temp. file path is created with the file extension .csv 53 | #' csv_file <- tempfile(fileext = ".csv") 54 | #' ## .xlsx 55 | #' xlsx_file <- tempfile(fileext = ".xlsx") 56 | #' 57 | #' ## create CSV to import 58 | #' export(iris, csv_file) 59 | #' 60 | #' ## You can certainly export your data with the file name, which is not a variable: 61 | #' ## import(mtcars, "car_data.csv") 62 | #' 63 | #' ## pass arguments to the underlying function 64 | #' ## data.table::fwrite is the underlying function and `col.names` is an argument 65 | #' export(iris, csv_file, col.names = FALSE) 66 | #' 67 | #' ## export a list of data frames as worksheets 68 | #' export(list(a = mtcars, b = iris), xlsx_file) 69 | #' 70 | #' # NOT RECOMMENDED 71 | #' 72 | #' ## specify `format` to override default format 73 | #' export(iris, xlsx_file, format = "csv") ## That's confusing 74 | #' ## You can also specify only the format; in the following case 75 | #' ## "mtcars.dta" is written [also confusing] 76 | #' 77 | #' ## export(mtcars, format = "stata") 78 | #' @seealso [characterize()], [import()], [convert()], [export_list()] 79 | #' @export 80 | export <- function(x, file, format, ...) { 81 | .check_file(file, single_only = TRUE) 82 | if (missing(file) && missing(format)) { 83 | stop("Must specify 'file' and/or 'format'") 84 | } 85 | if (!missing(file)) { 86 | cfile <- file 87 | f <- find_compress(file) 88 | file <- f$file 89 | compress <- f$compress 90 | format <- ifelse(isFALSE(missing(format)), tolower(format), get_info(file)$input) 91 | } else { 92 | format <- .standardize_format(format) 93 | file <- paste0(as.character(substitute(x)), ".", format) 94 | compress <- NA_character_ 95 | } 96 | .check_tar_support(compress, getRversion()) 97 | format <- .standardize_format(format) 98 | outfile <- file 99 | if (is.matrix(x) || inherits(x, "ArrowTabular")) { 100 | x <- as.data.frame(x) 101 | } 102 | if (!is.data.frame(x) && is.list(x) && length(x) == 1 && is.data.frame(x[[1]]) && 103 | !format %in% c("xlsx", "html", "rdata", "rds", "json", "qs", "fods", "ods")) { 104 | x <- x[[1]] ## fix 385 105 | } 106 | if (!is.data.frame(x) && !format %in% c("xlsx", "html", "rdata", "rds", "json", "qs", "fods", "ods")) { 107 | stop("'x' is not a data.frame or matrix", call. = FALSE) 108 | } 109 | if (format == "gz") { 110 | format <- get_info(tools::file_path_sans_ext(file, compression = FALSE))$format 111 | if (format != "csv") { 112 | stop("gz is only supported for csv (for now).", call. = FALSE) 113 | } 114 | } 115 | .create_directory_if_not_exists(file = file) ## fix 347 116 | class(file) <- c(paste0("rio_", format), class(file)) 117 | .export(file = file, x = x, ...) 118 | if (!is.na(compress)) { 119 | cfile <- compress_out(cfile = cfile, filename = file, type = compress) 120 | unlink(file) 121 | return(invisible(cfile)) 122 | } 123 | invisible(unclass(outfile)) 124 | } 125 | -------------------------------------------------------------------------------- /R/export_list.R: -------------------------------------------------------------------------------- 1 | #' @title Export list of data frames to files 2 | #' @description Use [export()] to export a list of data frames to a vector of file names or a filename pattern. 3 | #' @param x A list of data frames to be written to files. 4 | #' @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. 5 | #' @param archive character. Either empty string (default) to save files in current 6 | #' directory, a path to a (new) directory, or a .zip/.tar file to compress all 7 | #' files into an archive. 8 | #' @param \dots Additional arguments passed to [export()]. 9 | #' @return The name(s) of the output file(s) as a character vector (invisibly). 10 | #' @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. 11 | #' @examples 12 | #' ## For demo, a temp. file path is created with the file extension .xlsx 13 | #' xlsx_file <- tempfile(fileext = ".xlsx") 14 | #' export( 15 | #' list( 16 | #' mtcars1 = mtcars[1:10, ], 17 | #' mtcars2 = mtcars[11:20, ], 18 | #' mtcars3 = mtcars[21:32, ] 19 | #' ), 20 | #' xlsx_file 21 | #' ) 22 | #' 23 | #' # import a single file from multi-object workbook 24 | #' import(xlsx_file, sheet = "mtcars1") 25 | #' # import all worksheets, the return value is a list 26 | #' import_list(xlsx_file) 27 | 28 | #' library('datasets') 29 | #' export(list(mtcars1 = mtcars[1:10,], 30 | #' mtcars2 = mtcars[11:20,], 31 | #' mtcars3 = mtcars[21:32,]), 32 | #' xlsx_file <- tempfile(fileext = ".xlsx") 33 | #' ) 34 | #' 35 | #' # import all worksheets 36 | #' list_of_dfs <- import_list(xlsx_file) 37 | #' 38 | #' # re-export as separate named files 39 | #' 40 | #' ## export_list(list_of_dfs, file = c("file1.csv", "file2.csv", "file3.csv")) 41 | #' 42 | #' # re-export as separate files using a name pattern; using the names in the list 43 | #' ## This will be written as "mtcars1.csv", "mtcars2.csv", "mtcars3.csv" 44 | #' 45 | #' ## export_list(list_of_dfs, file = "%s.csv") 46 | #' @seealso [import()], [import_list()], [export()] 47 | #' @export 48 | export_list <- function(x, file, archive = "", ...) { 49 | .check_file(file, single_only = FALSE) 50 | archive_format <- find_compress(archive) 51 | supported_archive_formats <- c("zip", "tar", "tar.gz", "tar.bz2") 52 | if (!is.na(archive_format$compress) && !archive_format$compress %in% supported_archive_formats) { 53 | stop("'archive' is specified but format is not supported. Only zip and tar formats are supported.", call. = FALSE) 54 | } 55 | if (inherits(x, "data.frame")) { 56 | stop("'x' must be a list. Perhaps you want export()?", call. = FALSE) 57 | } 58 | .check_tar_support(archive_format$compress, getRversion()) 59 | 60 | outfiles <- .create_outfiles(file, x) 61 | 62 | if (is.na(archive_format$compress) && archive_format$file != "") { 63 | outfiles <- file.path(archive_format$file, outfiles) 64 | } 65 | outfiles_normalized <- normalizePath(outfiles, mustWork = FALSE) 66 | 67 | out <- list() 68 | for (f in seq_along(x)) { 69 | out[[f]] <- try(export(x[[f]], file = outfiles_normalized[f], ...), silent = TRUE) 70 | if (inherits(out[[f]], "try-error")) { 71 | warning(sprintf("Export failed for element %d, filename: %s", f, outfiles[f])) 72 | } 73 | } 74 | if (!is.na(archive_format$compress)) { 75 | .create_directory_if_not_exists(archive) 76 | compress_out(archive, outfiles_normalized, type = archive_format$compress) 77 | unlink(outfiles_normalized) 78 | return(invisible(archive)) 79 | } 80 | return(invisible(outfiles)) 81 | } 82 | -------------------------------------------------------------------------------- /R/extensions.R: -------------------------------------------------------------------------------- 1 | .import <- function(file, ...) { 2 | UseMethod(".import") 3 | } 4 | 5 | .import.default <- function(file, ...) { 6 | fileinfo <- get_info(file) ## S3 can't be dispatched 7 | if (fileinfo$type == "unknown" || is.na(fileinfo$import_function) || fileinfo$import_function == "") { 8 | stop("Format not supported", call. = FALSE) 9 | } 10 | if (fileinfo$type == "known") { 11 | stop(sprintf(gettext("%s format not supported. Consider using the '%s()' function"), 12 | fileinfo$format, fileinfo$import_function), call. = FALSE) 13 | } 14 | if (fileinfo$type == "enhance") { 15 | pkg <- strsplit(fileinfo$import_function, "::", fixed = TRUE)[[1]][1] 16 | stop(sprintf(gettext("Import support for the %s format is exported by the %s package. Run 'library(%s)' then try again."), 17 | fileinfo$format, pkg, pkg), call. = FALSE) 18 | } 19 | } 20 | 21 | .export <- function(file, x, ...) { 22 | UseMethod(".export") 23 | } 24 | 25 | .export.default <- function(file, x, ...) { 26 | fileinfo <- get_info(file) 27 | if (fileinfo$type == "unknown" || is.na(fileinfo$export_function) || fileinfo$export_function == "") { 28 | stop("Format not supported", call. = FALSE) 29 | } 30 | if (fileinfo$type == "known") { 31 | stop(sprintf(gettext("%s format not supported. Consider using the '%s()' function"), 32 | fileinfo$format, fileinfo$export_function), call. = FALSE) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /R/gather_attrs.R: -------------------------------------------------------------------------------- 1 | #' @rdname gather_attrs 2 | #' @title Gather attributes from data frame variables 3 | #' @description `gather_attrs` moves variable-level attributes to the data frame level and `spread_attrs` reverses that operation. 4 | #' @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. 5 | #' @param x A data frame. 6 | #' @return `x`, with variable-level attributes stored at the data frame level. 7 | #' @seealso [import()], [characterize()] 8 | #' @export 9 | gather_attrs <- function(x) { 10 | if (!inherits(x, "data.frame")) { 11 | stop("'x' is not a data.frame") 12 | } 13 | dfattrs <- attributes(x) 14 | if ("label" %in% names(dfattrs)) { 15 | names(dfattrs)[names(dfattrs) == "label"] <- "title" 16 | } 17 | varattrs <- rep(list(list()), length(x)) 18 | for (i in seq_along(x)) { 19 | a <- attributes(x[[i]]) 20 | varattrs[[i]] <- a[!names(a) %in% c("levels", "class")] 21 | attr(x[[i]], "label") <- NULL 22 | if (any(grepl("labelled", class(x[[i]]), fixed = TRUE))) { 23 | x[[i]] <- haven::zap_labels(x[[i]]) 24 | } 25 | f <- grep("^format", names(attributes(x[[i]])), value = TRUE) 26 | if (length(f)) { 27 | attr(x[[i]], f) <- NULL 28 | } 29 | rm(f) 30 | } 31 | if (any(lengths(varattrs))) { 32 | attrnames <- sort(unique(unlist(lapply(varattrs, names)))) 33 | outattrs <- stats::setNames(lapply(attrnames, function(z) { 34 | stats::setNames(lapply(varattrs, `[[`, z), names(x)) 35 | }), attrnames) 36 | attributes(x) <- c(dfattrs, outattrs) 37 | } 38 | x 39 | } 40 | 41 | #' @rdname gather_attrs 42 | #' @export 43 | spread_attrs <- function(x) { 44 | if (!inherits(x, "data.frame")) { 45 | stop("'x' is not a data.frame") 46 | } 47 | dfattrs <- attributes(x) 48 | d_level_attrs <- names(dfattrs) %in% c("row.names", "class", "names", "notes", "title") 49 | varattrs <- dfattrs[!d_level_attrs] 50 | for (i in seq_along(x)) { 51 | a <- attributes(x[[i]]) 52 | attributes(x[[i]]) <- c(a, lapply(varattrs, `[[`, i)) 53 | } 54 | if ("title" %in% names(dfattrs)) { 55 | names(dfattrs)[names(dfattrs) == "title"] <- "label" 56 | } 57 | attributes(x) <- dfattrs[d_level_attrs] 58 | x 59 | } 60 | -------------------------------------------------------------------------------- /R/import_list.R: -------------------------------------------------------------------------------- 1 | #' @title Import list of data frames 2 | #' @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, compressed directory in a zip file or tar archive, or HTML file) 3 | #' @param file A character string containing a single file name for a multi-object file (e.g., Excel workbook, zip file, tar archive, or HTML file), or a vector of file paths for multiple files to be imported. 4 | #' @param which If `file` is a single file path, this specifies which objects should be extracted (passed to [import()]'s `which` argument). Ignored otherwise. 5 | #' @param rbind A logical indicating whether to pass the import list of data frames through [data.table::rbindlist()]. 6 | #' @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. 7 | #' @param rbind_fill If `rbind = TRUE`, a logical indicating whether to set the `fill = TRUE` (and fill missing columns with `NA`). 8 | #' @param \dots Additional arguments passed to [import()]. Behavior may be unexpected if files are of different formats. 9 | #' @inheritParams import 10 | #' @inheritSection import Trust 11 | #' @inheritSection import Which 12 | #' @inherit import references 13 | #' @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. 14 | #' @details When file is a vector of file paths and any files are missing, those files are ignored (with warnings) and this function will not raise any error. For compressed files, the file name must also contain information about the file format of all compressed files, e.g. `files.csv.zip` for this function to work. 15 | #' @examples 16 | #' ## For demo, a temp. file path is created with the file extension .xlsx 17 | #' xlsx_file <- tempfile(fileext = ".xlsx") 18 | #' export( 19 | #' list( 20 | #' mtcars1 = mtcars[1:10, ], 21 | #' mtcars2 = mtcars[11:20, ], 22 | #' mtcars3 = mtcars[21:32, ] 23 | #' ), 24 | #' xlsx_file 25 | #' ) 26 | #' 27 | #' # import a single file from multi-object workbook 28 | #' import(xlsx_file, sheet = "mtcars1") 29 | #' # import all worksheets, the return value is a list 30 | #' import_list(xlsx_file) 31 | #' 32 | #' # import and rbind all worksheets, the return value is a data frame 33 | #' import_list(xlsx_file, rbind = TRUE) 34 | #' @seealso [import()], [export_list()], [export()] 35 | #' @export 36 | import_list <- function(file, setclass = getOption("rio.import.class", "data.frame"), which, rbind = FALSE, 37 | rbind_label = "_file", rbind_fill = TRUE, ...) { 38 | .check_file(file, single_only = FALSE) 39 | ## special cases 40 | if (length(file) == 1) { 41 | x <- .read_file_as_list(file = file, which = which, setclass = setclass, rbind = rbind, rbind_label = rbind_label, ...) 42 | } else { 43 | ## note the plural 44 | x <- .read_multiple_files_as_list(files = file, setclass = setclass, rbind = rbind, rbind_label = rbind_label, ...) 45 | } 46 | ## optionally rbind 47 | if (isTRUE(rbind)) { 48 | if (length(x) == 1) { 49 | x <- x[[1L]] 50 | } else { 51 | x2 <- try(data.table::rbindlist(x, fill = rbind_fill), silent = TRUE) 52 | if (inherits(x2, "try-error")) { 53 | warning("Attempt to rbindlist() the data did not succeed. List returned instead.", call. = FALSE) 54 | return(x) 55 | } 56 | x <- x2 57 | } 58 | x <- set_class(x, class = setclass) 59 | } 60 | return(x) 61 | } 62 | 63 | .strip_exts <- function(file) { 64 | vapply(file, function(x) tools::file_path_sans_ext(basename(x)), character(1)) 65 | } 66 | 67 | .read_multiple_files_as_list <- function(files, setclass, rbind, rbind_label, ...) { 68 | names(files) <- .strip_exts(files) 69 | x <- lapply(files, function(thisfile) { 70 | out <- try(import(thisfile, setclass = setclass, ...), silent = TRUE) 71 | if (inherits(out, "try-error")) { 72 | warning(sprintf("Import failed for %s", thisfile), call. = FALSE) 73 | ##out <- NULL 74 | return(NULL) 75 | } else if (isTRUE(rbind)) { 76 | out[[rbind_label]] <- thisfile 77 | } 78 | structure(out, filename = thisfile) 79 | }) 80 | names(x) <- names(files) 81 | return(x) 82 | } 83 | 84 | .read_file_as_list <- function(file, which, setclass, rbind, rbind_label, ...) { 85 | if (R.utils::isUrl(file)) { 86 | file <- remote_to_local(file) 87 | } 88 | if (get_info(file)$format == "rdata") { 89 | return(.import.rio_rdata(file = file, .return_everything = TRUE, ...)) 90 | } 91 | archive_format <- find_compress(file) 92 | if (!get_info(file)$format %in% c("html", "xlsx", "xls") && !archive_format$compress %in% c("zip", "tar", "tar.gz", "tar.bz2")) { 93 | which <- 1 94 | whichnames <- NULL 95 | } 96 | ## getting list of `whichnames` 97 | if (get_info(file)$format == "html") { 98 | .check_pkg_availability("xml2") 99 | tables <- xml2::xml_find_all(xml2::read_html(unclass(file)), ".//table") 100 | if (missing(which)) { 101 | which <- seq_along(tables) 102 | } 103 | whichnames <- vapply(xml2::xml_attrs(tables[which]), 104 | function(x) if ("class" %in% names(x)) x["class"] else "", 105 | FUN.VALUE = character(1) 106 | ) 107 | names(which) <- whichnames 108 | } 109 | if (get_info(file)$format %in% c("xls", "xlsx")) { 110 | ## .check_pkg_availability("readxl") 111 | whichnames <- readxl::excel_sheets(path = file) 112 | if (missing(which)) { 113 | which <- seq_along(whichnames) 114 | names(which) <- whichnames 115 | } else if (is.character(which)) { 116 | whichnames <- which 117 | } else { 118 | whichnames <- whichnames[which] 119 | } 120 | } 121 | if (archive_format$compress %in% c("zip", "tar", "tar.gz", "tar.bz2")) { 122 | whichnames <- .list_archive(file, archive_format$compress) 123 | if (missing(which)) { 124 | which <- seq_along(whichnames) 125 | names(which) <- .strip_exts(whichnames) 126 | } else if (is.character(which)) { 127 | whichnames <- whichnames[whichnames %in% which] 128 | } else { 129 | names(which) <- .strip_exts(whichnames) 130 | } 131 | } 132 | ## reading all `whichnames` 133 | x <- lapply(which, function(thiswhich) { 134 | out <- try(import(file, setclass = setclass, which = thiswhich, ...), silent = TRUE) 135 | if (inherits(out, "try-error")) { 136 | warning(sprintf("Import failed for %s from %s", thiswhich, file)) 137 | out <- NULL 138 | } else if (isTRUE(rbind) && length(which) > 1) { 139 | out[[rbind_label]] <- thiswhich 140 | } 141 | out 142 | }) 143 | names(x) <- whichnames 144 | return(x) 145 | } 146 | -------------------------------------------------------------------------------- /R/onLoad.R: -------------------------------------------------------------------------------- 1 | .onAttach <- function(libname, pkgname) { 2 | if (interactive()) { 3 | w <- uninstalled_formats() 4 | if (length(w)) { 5 | msg <- "Some optional R packages were not installed and therefore some file formats are not supported. Check file support with show_unsupported_formats()" 6 | packageStartupMessage(msg) 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /R/remote_to_local.R: -------------------------------------------------------------------------------- 1 | remote_to_local <- function(file, format) { 2 | if (grepl("docs.google.com/spreadsheets", file, fixed = TRUE)) { 3 | if (missing(format) || (!missing(format) && !format %in% c("csv", "tsv", "xlsx", "ods"))) { 4 | format <- "csv" 5 | } 6 | file <- .convert_google_url(file, export_as = format) 7 | } 8 | if (missing(format)) { 9 | ## try to extract format from URL, see below 10 | format <- .get_ext_temp(file) 11 | } else { 12 | format <- .standardize_format(format) 13 | } 14 | # save file locally 15 | temp_file <- tempfile(fileext = paste0(".", format)) 16 | u <- curl::curl_fetch_memory(file) 17 | writeBin(object = u$content, con = temp_file) 18 | if (format != "TMP") { ## the happiest path 19 | return(temp_file) 20 | } 21 | ## fomart = "TMP": try to extract format from curl's final URL 22 | format <- .get_ext_temp(u$url) 23 | if (format != "TMP") { ## contain a file extension, also happy 24 | renamed_file <- sub("TMP$", format, temp_file) 25 | file.copy(from = temp_file, to = renamed_file) 26 | unlink(temp_file) 27 | return(renamed_file) 28 | } 29 | ## try to extract format from headers: read #403 about whether this code is doing anything 30 | h1 <- curl::parse_headers(u$headers) 31 | ## check `Content-Disposition` header 32 | if (!any(grepl("^Content-Disposition", h1))) { 33 | stop("Unrecognized file format. Try specifying with the format argument.") 34 | } 35 | h <- h1[grep("filename", h1, fixed = TRUE)] 36 | if (length(h)) { 37 | f <- regmatches(h, regexpr("(?<=\")(.*)(?", value, "") 70 | } 71 | 72 | 73 | escape_xml <- function(x, replacement = c("&", """, "<", ">", "'")) { 74 | stringi::stri_replace_all_fixed( 75 | str = stringi::stri_enc_toutf8(x), pattern = c("&", "\"", "<", ">", "'"), 76 | replacement = replacement, vectorize_all = FALSE 77 | ) 78 | } 79 | 80 | .check_pkg_availability <- function(pkg, lib.loc = NULL) { 81 | if (identical(find.package(pkg, quiet = TRUE, lib.loc = lib.loc), character(0))) { 82 | stop("Suggested package `", pkg, "` is not available. Please install it individually or use `install_formats()`", call. = FALSE) 83 | } 84 | return(invisible(NULL)) 85 | } 86 | 87 | .write_as_utf8 <- function(text, file, sep = "") { 88 | writeLines(enc2utf8(text), con = file, sep = sep, useBytes = TRUE) 89 | } 90 | 91 | .check_file <- function(file, single_only = TRUE) { 92 | ## check the `file` argument 93 | if (isTRUE(missing(file))) { ## for the case of export(iris, format = "csv") 94 | return(invisible(NULL)) 95 | } 96 | if (isFALSE(inherits(file, "character"))) { 97 | stop("Invalid `file` argument: must be character", call. = FALSE) 98 | } 99 | if (isFALSE(length(file) == 1) && single_only) { 100 | stop("Invalid `file` argument: `file` must be single", call. = FALSE) 101 | } 102 | if (any(is.na(file))) { 103 | stop("Invalid `file` argument: `file` must not be NA", call. = FALSE) 104 | } 105 | invisible(NULL) 106 | } 107 | 108 | .create_directory_if_not_exists <- function(file) { 109 | R.utils::mkdirs(dirname(normalizePath(file, mustWork = FALSE))) 110 | invisible(NULL) 111 | } 112 | 113 | .create_outfiles <- function(file, x) { 114 | names_x <- names(x) 115 | if (length(file) == 1L) { 116 | if (!grepl("%s", file, fixed = TRUE)) { 117 | stop("'file' must have a %s placeholder") 118 | } 119 | if (is.null(names_x)) { 120 | return(sprintf(file, seq_along(x))) 121 | } 122 | if (!all(nzchar(names_x))) { 123 | stop("All elements of 'x' must be named or all must be unnamed") 124 | } 125 | if (anyDuplicated(names_x)) { 126 | stop("Names of elements in 'x' are not unique") 127 | } 128 | return(sprintf(file, names_x)) 129 | } 130 | if (length(x) != length(file)) { 131 | stop("'file' must be same length as 'x', or a single pattern with a %s placeholder") 132 | } 133 | if (anyDuplicated(file)) { 134 | stop("File names are not unique") 135 | } 136 | return(file) 137 | } 138 | 139 | .check_trust <- function(trust, format) { 140 | if (is.null(trust)) { 141 | warning("Missing `trust` will be set to FALSE by default for ", format, " in 2.0.0.", call. = FALSE) 142 | trust <- TRUE ## Change this for version 2.0.0 143 | } 144 | if (isFALSE(trust)) { 145 | stop(format, " files may execute arbitary code. Only load ", format, " files that you personally generated or can trust the origin.", call. = FALSE) 146 | } 147 | NULL 148 | } 149 | 150 | .reset_which <- function(file_type, which) { 151 | ## see #412 152 | if (file_type %in% c("zip", "tar", "tar.gz", "tar.bz2")) { 153 | return(1) 154 | } 155 | return(which) 156 | } 157 | -------------------------------------------------------------------------------- /README.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | output: github_document 3 | --- 4 | 5 | # rio: A Swiss-Army Knife for Data I/O 6 | 7 | 8 | [![CRAN Version](https://www.r-pkg.org/badges/version/rio)](https://cran.r-project.org/package=rio) 9 | ![Downloads](https://cranlogs.r-pkg.org/badges/rio) 10 | 11 | 12 | ## Overview 13 | 14 | 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: 15 | 16 | - `import()` provides a painless data import experience by automatically choosing the appropriate import/read function based on file extension (or a specified `format` argument) 17 | - `export()` provides the same painless file recognition for data export/write functionality 18 | 19 | ## Installation 20 | 21 | The package is available on [CRAN](https://cran.r-project.org/package=rio) and can be installed directly in R using `install.packages()`. 22 | 23 | ```R 24 | install.packages("rio") 25 | ``` 26 | 27 | The latest development version on GitHub can be installed using: 28 | 29 | ```R 30 | if (!require("remotes")){ 31 | install.packages("remotes") 32 | } 33 | remotes::install_github("gesistsa/rio") 34 | ``` 35 | 36 | Optional: Installation of additional formats (see below: **Supported file formats**) 37 | 38 | ```R 39 | library(rio) 40 | install_formats() 41 | ``` 42 | 43 | ## Usage 44 | 45 | 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. 46 | 47 | ### Import 48 | 49 | Importing data is handled with one function, `import()`: 50 | 51 | ```{r import1} 52 | library("rio") 53 | import("starwars.xlsx") 54 | ``` 55 | 56 | ```{r import2} 57 | import("starwars.csv") 58 | ``` 59 | 60 | ### Export 61 | 62 | Exporting data is handled with one function, `export()`: 63 | 64 | ```{r exports} 65 | export(mtcars, "mtcars.csv") # comma-separated values 66 | export(mtcars, "mtcars.rds") # R serialized 67 | export(mtcars, "mtcars.sav") # SPSS 68 | ``` 69 | 70 | A particularly useful feature of rio is the ability to import from and export to compressed archives (e.g., zip), saving users the extra step of compressing a large exported file, e.g.: 71 | 72 | ```{r export_zip} 73 | export(mtcars, "mtcars.tsv.zip") 74 | ``` 75 | 76 | `export()` can also write multiple data frames to respective sheets of an Excel workbook or an HTML file: 77 | 78 | ```{r export_a_list} 79 | export(list(mtcars = mtcars, iris = iris), file = "mtcars.xlsx") 80 | ``` 81 | 82 | ## Supported file formats 83 | 84 | **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. You can check which formats are **not** supported via: 85 | 86 | ```R 87 | show_unsupported_formats() 88 | ``` 89 | 90 | You can install the suggested packages individually, depending your own needs. If you want to install all suggested packages: 91 | 92 | ```R 93 | install_formats() 94 | ``` 95 | 96 | The full list of supported formats is below: 97 | 98 | ```{r, include = FALSE} 99 | suppressPackageStartupMessages(library(data.table)) 100 | ``` 101 | 102 | ```{r featuretable, echo = FALSE} 103 | rf <- data.table(rio:::rio_formats)[!input %in% c(",", ";", "|", "\\t") & type %in% c("import", "suggest", "archive"),] 104 | short_rf <- rf[, paste(input, collapse = " / "), by = format_name] 105 | type_rf <- unique(rf[,c("format_name", "type", "import_function", "export_function", "note")]) 106 | 107 | feature_table <- short_rf[type_rf, on = .(format_name)] 108 | 109 | colnames(feature_table)[2] <- "signature" 110 | 111 | setorder(feature_table, "type", "format_name") 112 | feature_table$import_function <- stringi::stri_extract_first(feature_table$import_function, regex = "[a-zA-Z0-9\\.]+") 113 | feature_table$import_function[is.na(feature_table$import_function)] <- "" 114 | feature_table$export_function <- stringi::stri_extract_first(feature_table$export_function, regex = "[a-zA-Z0-9\\.]+") 115 | feature_table$export_function[is.na(feature_table$export_function)] <- "" 116 | 117 | feature_table$type <- ifelse(feature_table$type %in% c("suggest"), "Suggest", "Default") 118 | feature_table <- feature_table[,c("format_name", "signature", "import_function", "export_function", "type", "note")] 119 | 120 | colnames(feature_table) <- c("Name", "Extensions / \"format\"", "Import Package", "Export Package", "Type", "Note") 121 | 122 | knitr::kable(feature_table) 123 | ``` 124 | 125 | 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. 126 | 127 | ## Other functions 128 | 129 | ### Convert 130 | 131 | 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. 132 | 133 | ```{r convert} 134 | convert("mtcars.sav", "mtcars.dta") 135 | ``` 136 | 137 | 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: 138 | 139 | ``` 140 | Rscript -e "rio::convert('iris.dta', 'iris.csv')" 141 | ``` 142 | 143 | ### *_list 144 | 145 | `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): 146 | 147 | ```{r import_list} 148 | str(m <- import_list("mtcars.xlsx")) 149 | ``` 150 | 151 | `export_list()` makes it easy to export a list of (possibly named) data frames to multiple files: 152 | 153 | ```{r export_list} 154 | export_list(m, "%s.tsv") 155 | c("mtcars.tsv", "iris.tsv") %in% dir() 156 | ``` 157 | 158 | ```{r cleanup, echo=FALSE, results="hide"} 159 | unlink("mtcars.csv") 160 | unlink("mtcars.dta") 161 | unlink("mtcars.sav") 162 | unlink("mtcars.rds") 163 | unlink("mtcars.xlsx") 164 | unlink("mtcars.tsv.zip") 165 | unlink("mtcars.tsv") 166 | unlink("iris.tsv") 167 | ``` 168 | 169 | ## Other projects 170 | 171 | ### GUIs 172 | 173 | * [**datamods**](https://cran.r-project.org/package=datamods) provides Shiny modules for importing data via `rio`. 174 | * [**rioweb**](https://github.com/lbraglia/rioweb) that provides access to the file conversion features of `rio`. 175 | * [**GREA**](https://github.com/Stan125/GREA/) is an RStudio add-in that provides an interactive interface for reading in data using `rio`. 176 | 177 | ### Similar packages 178 | 179 | * [**reader**](https://cran.r-project.org/package=reader) handles certain text formats and R binary files 180 | * [**io**](https://cran.r-project.org/package=io) offers a set of custom formats 181 | * [**ImportExport**](https://cran.r-project.org/package=ImportExport) focuses on select binary formats (Excel, SPSS, and Access files) and provides a Shiny interface. 182 | * [**SchemaOnRead**](https://cran.r-project.org/package=SchemaOnRead) iterates through a large number of possible import methods until one works successfully 183 | -------------------------------------------------------------------------------- /_pkgdown.yml: -------------------------------------------------------------------------------- 1 | url: http://gesistsa.github.io/rio/ 2 | template: 3 | package: tsatemplate 4 | 5 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | comment: false 2 | 3 | coverage: 4 | status: 5 | patch: off 6 | -------------------------------------------------------------------------------- /data-raw/convert.R: -------------------------------------------------------------------------------- 1 | writeLines( 2 | jsonlite::prettify(jsonlite::toJSON(jsonlite::read_json(here::here("data-raw/single.json"), TRUE))), 3 | here::here("data-raw/single.json") 4 | ) 5 | rio_formats <- rio::import(here::here("data-raw", "single.json")) 6 | 7 | all_functions <- unlist(rio_formats[rio_formats$type == "suggest", c("import_function", "export_function")], use.names = FALSE) 8 | suggestions <- unique(stats::na.omit(stringi::stri_extract_first(all_functions, regex = "[a-zA-Z0-9\\.]+"))) 9 | attr(rio_formats, "suggested_packages") <- c(suggestions, "stringi") 10 | usethis::use_data(rio_formats, overwrite = TRUE, internal = TRUE) 11 | 12 | ## #351 13 | 14 | ## old_data <- jsonlite::read_json(here::here("data-raw/single.json"), TRUE) 15 | 16 | ## new_data <- old_data 17 | ## colnames(new_data)[2] <- "format" 18 | 19 | ## writeLines(jsonlite::prettify(jsonlite::toJSON(new_data)), here::here("data-raw/single.json")) 20 | ## rio_formats <- rio::import(here::here("data-raw", "single.json")) 21 | ## usethis::use_data(rio_formats, overwrite = TRUE, internal = TRUE) 22 | 23 | ## #351 remove ext 24 | ## old_data <- jsonlite::read_json(here::here("data-raw/single.json"), TRUE) 25 | ## new_data <- old_data[, -3] 26 | ## writeLines(jsonlite::prettify(jsonlite::toJSON(new_data)), here::here("data-raw/single.json")) 27 | ## rio_formats <- rio::import(here::here("data-raw", "single.json")) 28 | ## usethis::use_data(rio_formats, overwrite = TRUE, internal = TRUE) 29 | -------------------------------------------------------------------------------- /data-raw/obsolete/arg_reconcile.R: -------------------------------------------------------------------------------- 1 | ## @title Reconcile an argument list to any function signature. 2 | ## 3 | ## @description Adapt an argument list to a function excluding arguments that 4 | ## will not be recognized by it, redundant arguments, and un-named 5 | ## arguments. 6 | ## 7 | ## @param fun A function to which an argument list needs to be adapted. Use 8 | ## the unquoted name of the function. If it's in a different 9 | ## package then the fully qualified unquoted name (e.g. 10 | ## \code{utils::read.table}) 11 | ## @param ... An arbitrary list of named arguments (unnamed ones will be 12 | ## ignored). Arguments in \code{.args} are overridden by 13 | ## arguments of the same name (if any) in \code{...} 14 | ## @param .args A list or \code{alist} of named arguments, to be merged 15 | ## with \code{...}. Arguments in \code{.args} are overridden by 16 | ## arguments of the same name (if any) in \code{...} 17 | ## @param .docall If set to \code{TRUE} will not only clean up the arguments 18 | ## but also execute \code{fun} with those arguments 19 | ## (\code{FALSE} by default) and return the results 20 | ## @param .include Whitelist. If not empty, only arguments named here will be 21 | ## permitted, and only if they satisfy the conditions implied by 22 | ## the other arguments. Evaluated before \code{.remap}. 23 | ## @param .exclude Blacklist. If not empty, arguments named here will be removed 24 | ## even if they satisfy the conditions implied by the other 25 | ## arguments. Evaluated before \code{.remap}. 26 | ## @param .remap An optional named character vector or named list of character 27 | ## values for standardizing arguments that play the same role 28 | ## but have different names in different functions. Evaluated 29 | ## after \code{.exclude} and \code{.include}. 30 | ## @param .warn Whether to issue a warning message (default) when invalid 31 | ## arguments need to be discarded. 32 | ## @param .error If specified, should be the object to return in the event of 33 | ## error. This object will have the error as its 34 | ## \code{error} attribute. If not specified an ordinary error is 35 | ## thrown with an added hint on the documentation to read for 36 | ## troubleshooting. Ignored if \code{.docall} is \code{FALSE}. 37 | ## The point of doing this is fault-tolerance-- if this function 38 | ## is part of a lengthy process where you want to document an 39 | ## error but keep going, you can set \code{.error} to some 40 | ## object of a compatible type. That object will be returned in 41 | ## the event of error and will have as its \code{"error"} 42 | ## attribute the error object. 43 | ## @param .finish A function to run on the result before returning it. Ignored 44 | ## if \code{.docall} is \code{FALSE}. 45 | ## 46 | ## @return Either a named list or the result of calling \code{fun} with the 47 | ## supplied arguments 48 | ## 49 | arg_reconcile <- function(fun, ..., .args = alist(), .docall = FALSE, 50 | .include = c(), .exclude= c(), .remap = list(), 51 | .warn = TRUE, .error = "default", .finish = identity) { 52 | ## capture the formal arguments of the target function 53 | frmls <- formals(fun) 54 | ## both freeform and an explicit list 55 | args <- match.call(expand.dots = FALSE)[["..."]] 56 | if (isTRUE(.docall)) { 57 | for (ii in names(args)) { 58 | try(args[[ii]] <- eval(args[[ii]], parent.frame())) 59 | } 60 | } 61 | ## get rid of duplicate arguments, with freeform arguments 62 | dupes <- names(args)[duplicated(names(args))] 63 | for (ii in dupes) { 64 | args[which(names(args) == ii)[-1]] <- NULL 65 | } 66 | ## Merge ... with .args 67 | args <- c(args, .args) 68 | ## Apply whitelist and blacklist. This step also removes duplicates _between_ 69 | ## the freeform (...) and pre-specified (.args) arguments, with ... versions 70 | ## taking precedence over the .args versions. This is a consequence of the 71 | ## intersect() and setdiff() operations and works even if there is no blacklist 72 | ## nor whitelist 73 | if (!missing(.include)) { 74 | args <- args[intersect(names(args), .include)] 75 | } 76 | args <- args[setdiff(names(args), .exclude)] 77 | ## if any remappings of one argument to another are specified, perform them 78 | for (ii in names(.remap)) { 79 | if (!.remap[[ii]] %in% names(args) && ii %in% names(args)) { 80 | args[[.remap[[ii]] ]] <- args[[ii]] 81 | } 82 | } 83 | ## remove any unnamed arguments 84 | args[names(args) == ""] <- NULL 85 | ## if the target function doesn't have "..." as an argument, check to make sure 86 | ## only recognized arguments get passed, optionally with a warning 87 | if (!"..." %in% names(frmls)) { 88 | unused <- setdiff(names(args), names(frmls)) 89 | if (length(unused)>0) { 90 | if (isTRUE(.warn)) { 91 | warning("The following arguments were ignored for ", 92 | deparse(substitute(fun)), ":\n", paste(unused, collapse = ", ")) 93 | } 94 | args <- args[intersect(names(args), names(frmls))] 95 | } 96 | } 97 | ## the final, cleaned-up arguments either get returned as a list or used on the 98 | ## function, depending on how .docall is set 99 | if (!isTRUE(.docall)) { 100 | return(args) 101 | } else { 102 | ## run the function and return the result case 103 | oo <- try(do.call(fun, args), silent = TRUE) 104 | if (!inherits(oo, "try-error")) { 105 | return(.finish(oo)) 106 | } else { 107 | ## construct an informative error... eventually there will be more 108 | ## detailed info here 109 | errorhint <- paste("\nThis error was generated by: ", 110 | deparse(match.call()$fun), 111 | "\nWith the following arguments:\n", 112 | gsub("^list\\(|\\)$", "", 113 | paste(deparse(args, control=c("delayPromises")), 114 | collapse = "\n"))) 115 | if (missing(.error)) { 116 | stop(attr(oo, "condition")$message, errorhint) 117 | } else { 118 | attr(.error, "error") <- oo 119 | return(.error) 120 | } 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /data-raw/obsolete/is_file_text.R: -------------------------------------------------------------------------------- 1 | ## @title Determine whether a file is \dQuote{plain-text} or some sort of binary format 2 | ## 3 | ## @param file Path to the file 4 | ## @param maxsize Maximum number of bytes to read 5 | ## @param text_bytes Which characters are used by normal text (though not 6 | ## necessarily just ASCII). To detect just ASCII, the 7 | ## following value can be used: 8 | ## \code{as.raw(c(7:16, 18, 19, 32:127))} 9 | ## 10 | ## @return A logical 11 | ## @export 12 | ## @examples 13 | ## library(datasets) 14 | ## export(iris, yml_file <- tempfile(fileext = ".yml")) 15 | ## is_file_text(yml_file) # TRUE 16 | ## 17 | ## export(iris, sav_file <- tempfile(fileext = ".sav")) 18 | ## is_file_text(sav_file) # FALSE 19 | ## 20 | ## # cleanup 21 | ## unlink(yml_file) 22 | ## unlink(sav_file) 23 | ## 24 | is_file_text <- function( 25 | file, 26 | maxsize = Inf, 27 | text_bytes = as.raw(c(0x7:0x10, 0x12, 0x13, 0x20:0xFF)) 28 | ) { 29 | 30 | ff <- file(file, "rb") 31 | bytes <- readBin( 32 | ff, 33 | raw(), 34 | n = min(file.info(file)$size, maxsize) 35 | ) 36 | close(ff) 37 | 38 | return(length(setdiff(bytes, text_bytes)) == 0) 39 | } 40 | -------------------------------------------------------------------------------- /data-raw/obsolete/old_logo/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gesistsa/rio/f1094bf636f95f5dfcb05408d2ca0960fa792c8e/data-raw/obsolete/old_logo/logo.png -------------------------------------------------------------------------------- /data-raw/obsolete/old_logo/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 24 | 25 | 27 | image/svg+xml 28 | 30 | 31 | 32 | 33 | 34 | 36 | 56 | 62 | 68 | 74 | 80 | 86 | 92 | RIO 111 | 117 | 123 | 131 | 139 | 147 | 148 | -------------------------------------------------------------------------------- /data-raw/obsolete/test_is_file_text.R: -------------------------------------------------------------------------------- 1 | context("correctly identifying files as text vs binary") 2 | require("datasets") 3 | 4 | txtformats <- c("arff", "csv", "csv2", "dump", "fwf", "psv", "r", "tsv", "txt") 5 | binformats <- c("dbf", "dta", "rda", "rdata", "rds", "sas7bdat", "sav", "xlsx", 6 | "xpt") 7 | names(iris) <- gsub("\\.", "_", names(iris)) 8 | 9 | test_that("Required text formats recognized as text", { 10 | for (xx in txtformats) { 11 | expect_true(is_file_text(export(iris, paste0("iris.", xx))), 12 | label = paste0(xx, " should be text")) 13 | } 14 | }) 15 | 16 | test_that("Required non-text formats recognized as non-text", { 17 | for (xx in binformats) { 18 | expect_false(is_file_text(export(iris, paste0("iris.", xx))), 19 | label = paste0(xx, " should not be text")) 20 | } 21 | }) 22 | 23 | test_that("csvy recognized as text", { 24 | skip_if_not_installed(pkg = "data.table") 25 | expect_true(is_file_text(export(iris, "iris.csvy"))) 26 | }) 27 | 28 | test_that("xml and html recognized as text", { 29 | skip_if_not_installed(pkg = "xml2") 30 | expect_true(is_file_text(export(iris, "iris.xml"))) 31 | expect_true(is_file_text(export(iris, "iris.html"))) 32 | }) 33 | 34 | test_that("json recognized as text", { 35 | skip_if_not_installed(pkg = "jsonlite") 36 | expect_true(is_file_text(export(iris, "iris.json"))) 37 | }) 38 | 39 | test_that("yml recognized as text", { 40 | skip_if_not_installed(pkg = "yaml") 41 | expect_true(is_file_text(export(iris, "iris.yml"))) 42 | }) 43 | 44 | test_that("pzfx recognized as text", { 45 | skip_if_not_installed(pkg = "pzfx") 46 | expect_true(is_file_text(export(iris[,-5], "iris.pzfx"))) 47 | }) 48 | 49 | test_that("matlab recognized as binary", { 50 | skip("failing mysteriously") 51 | # skip_if_not_installed(pkg = "rmatio") 52 | expect_false(is_file_text(export(iris, "iris.matlab"))) 53 | }) 54 | 55 | test_that("ods recognized as binary", { 56 | skip_if_not_installed(pkg = "readODS") 57 | expect_false(is_file_text(export(iris, "iris.ods"))) 58 | }) 59 | 60 | test_that("fst recognized as binary", { 61 | skip_if_not_installed(pkg = "fst") 62 | expect_false(is_file_text(export(iris, "iris.fst"))) 63 | }) 64 | 65 | test_that("feather recognized as binary", { 66 | skip_if_not_installed(pkg = "feather") 67 | expect_false(is_file_text(export(iris, "iris.feather"))) 68 | }) 69 | 70 | unlink(paste0("iris.", c(txtformats, binformats, "csvy", "xml", "html", "json", 71 | "yml", "pzfx", "matlab", "ods", "fst", "feather"))) 72 | rm(iris, txtformats, binformats) 73 | 74 | -------------------------------------------------------------------------------- /data-raw/readme.md: -------------------------------------------------------------------------------- 1 | 2 | Please edit the json file if you have made change related to formats. 3 | 4 | `convert.R` will prettify the json file as well as regenerate the internal data (`R/sysdata.rda`) 5 | 6 | If you prefer, you can also use the `Makefile` 7 | 8 | ```R 9 | make R/sysdata.rda 10 | ``` 11 | 12 | -------------------------------------------------------------------------------- /inst/CITATION: -------------------------------------------------------------------------------- 1 | citHeader("To cite package 'rio' in publications use:") 2 | 3 | bibentry(bibtype = "Manual", 4 | title = "rio: A Swiss-army knife for data file I/O", 5 | author = c(person("Chung-hong", "Chan"), person("Thomas J.", "Leeper"), person("Jason", "Becker"), person("David", "Schoch")), 6 | url = "https://cran.r-project.org/package=rio", 7 | year = 2023) 8 | -------------------------------------------------------------------------------- /man/characterize.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/characterize.R 3 | \name{characterize} 4 | \alias{characterize} 5 | \alias{factorize} 6 | \alias{characterize.default} 7 | \alias{characterize.data.frame} 8 | \alias{factorize.default} 9 | \alias{factorize.data.frame} 10 | \title{Character conversion of labelled data} 11 | \usage{ 12 | characterize(x, ...) 13 | 14 | factorize(x, ...) 15 | 16 | \method{characterize}{default}(x, ...) 17 | 18 | \method{characterize}{data.frame}(x, ...) 19 | 20 | \method{factorize}{default}(x, coerce_character = FALSE, ...) 21 | 22 | \method{factorize}{data.frame}(x, ...) 23 | } 24 | \arguments{ 25 | \item{x}{A vector or data frame.} 26 | 27 | \item{\dots}{additional arguments passed to methods} 28 | 29 | \item{coerce_character}{A logical indicating whether to additionally coerce character columns to factor (in \code{factorize}). Default \code{FALSE}.} 30 | } 31 | \value{ 32 | a character vector (for \code{characterize}) or factor vector (for \code{factorize}) 33 | } 34 | \description{ 35 | Convert labelled variables to character or factor 36 | } 37 | \details{ 38 | \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. 39 | } 40 | \examples{ 41 | ## vector method 42 | x <- structure(1:4, labels = c("A" = 1, "B" = 2, "C" = 3)) 43 | characterize(x) 44 | factorize(x) 45 | 46 | ## data frame method 47 | x <- data.frame(v1 = structure(1:4, labels = c("A" = 1, "B" = 2, "C" = 3)), 48 | v2 = structure(c(1,0,0,1), labels = c("foo" = 0, "bar" = 1))) 49 | str(factorize(x)) 50 | str(characterize(x)) 51 | 52 | ## Application 53 | csv_file <- tempfile(fileext = ".csv") 54 | ## comparison of exported file contents 55 | import(export(x, csv_file)) 56 | import(export(factorize(x), csv_file)) 57 | } 58 | \seealso{ 59 | \code{\link[=gather_attrs]{gather_attrs()}} 60 | } 61 | -------------------------------------------------------------------------------- /man/convert.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/convert.R 3 | \name{convert} 4 | \alias{convert} 5 | \title{Convert from one file format to another} 6 | \usage{ 7 | convert(in_file, out_file, in_opts = list(), out_opts = list()) 8 | } 9 | \arguments{ 10 | \item{in_file}{A character string naming an input file.} 11 | 12 | \item{out_file}{A character string naming an output file.} 13 | 14 | \item{in_opts}{A named list of options to be passed to \code{\link[=import]{import()}}.} 15 | 16 | \item{out_opts}{A named list of options to be passed to \code{\link[=export]{export()}}.} 17 | } 18 | \value{ 19 | A character string containing the name of the output file (invisibly). 20 | } 21 | \description{ 22 | 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. 23 | } 24 | \examples{ 25 | ## For demo, a temp. file path is created with the file extension .dta (Stata) 26 | dta_file <- tempfile(fileext = ".dta") 27 | ## .csv 28 | csv_file <- tempfile(fileext = ".csv") 29 | ## .xlsx 30 | xlsx_file <- tempfile(fileext = ".xlsx") 31 | 32 | 33 | ## Create a Stata data file 34 | export(mtcars, dta_file) 35 | 36 | ## convert Stata to CSV and open converted file 37 | convert(dta_file, csv_file) 38 | import(csv_file) 39 | 40 | ## correct an erroneous file format 41 | export(mtcars, xlsx_file, format = "tsv") ## DON'T DO THIS 42 | ## import(xlsx_file) ## ERROR 43 | ## convert the file by specifying `in_opts` 44 | convert(xlsx_file, xlsx_file, in_opts = list(format = "tsv")) 45 | import(xlsx_file) 46 | 47 | ## convert from the command line: 48 | ## Rscript -e "rio::convert('mtcars.dta', 'mtcars.csv')" 49 | } 50 | \seealso{ 51 | \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. 52 | } 53 | -------------------------------------------------------------------------------- /man/export.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/export.R 3 | \name{export} 4 | \alias{export} 5 | \title{Export} 6 | \usage{ 7 | export(x, file, format, ...) 8 | } 9 | \arguments{ 10 | \item{x}{A data frame, matrix or a single-item list of data frame to be written into a file. Exceptions to this rule are that \code{x} can be a list of multiple data frames if the output file format is an OpenDocument Spreadsheet (.ods, .fods), 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.} 11 | 12 | \item{file}{A character string naming a file. Must specify \code{file} and/or \code{format}.} 13 | 14 | \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()}}.} 15 | 16 | \item{\dots}{Additional arguments for the underlying export functions. This can be used to specify non-standard arguments. See examples.} 17 | } 18 | \value{ 19 | The name of the output file as a character string (invisibly). 20 | } 21 | \description{ 22 | Write data.frame to a file 23 | } 24 | \details{ 25 | 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). 26 | 27 | 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}. 28 | 29 | \code{export} supports many file formats. See the documentation for the underlying export functions for optional arguments that can be passed via \code{...} 30 | 31 | \itemize{ 32 | \item Comma-separated data (.csv), using \code{\link[data.table:fwrite]{data.table::fwrite()}} 33 | \item Pipe-separated data (.psv), using \code{\link[data.table:fwrite]{data.table::fwrite()}} 34 | \item Tab-separated data (.tsv), using \code{\link[data.table:fwrite]{data.table::fwrite()}} 35 | \item SAS (.sas7bdat), using \code{\link[haven:write_sas]{haven::write_sas()}}. 36 | \item SAS XPORT (.xpt), using \code{\link[haven:read_xpt]{haven::write_xpt()}}. 37 | \item SPSS (.sav), using \code{\link[haven:read_spss]{haven::write_sav()}} 38 | \item SPSS compressed (.zsav), using \code{\link[haven:read_spss]{haven::write_sav()}} 39 | \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. 40 | \item Excel (.xlsx), using \code{\link[writexl:write_xlsx]{writexl::write_xlsx()}}. \code{x} can also be a list of data frames; the list entry names are used as sheet names. 41 | \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'}) 42 | \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. 43 | \item Serialized R objects (.rds), using \code{\link[base:readRDS]{base::saveRDS()}}. In this case, \code{x} can be any serializable R object. 44 | \item Serialized R objects (.qs), using \code{\link[qs:qsave]{qs::qsave()}}, which is 45 | significantly faster than .rds. This can be any R 46 | object (not just a data frame). 47 | \item "XBASE" database files (.dbf), using \code{\link[foreign:write.dbf]{foreign::write.dbf()}} 48 | \item Weka Attribute-Relation File Format (.arff), using \code{\link[foreign:write.arff]{foreign::write.arff()}} 49 | \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} 50 | \item \href{https://github.com/csvy}{CSVY} (CSV with a YAML metadata header) using \code{\link[data.table:fwrite]{data.table::fwrite()}}. 51 | \item Apache Arrow Parquet (.parquet), using \code{\link[nanoparquet:write_parquet]{nanoparquet::write_parquet()}} 52 | \item Feather R/Python interchange format (.feather), using \code{\link[arrow:write_feather]{arrow::write_feather()}} 53 | \item Fast storage (.fst), using \code{\link[fst:write_fst]{fst::write.fst()}} 54 | \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}. 55 | \item Matlab (.mat), using \code{\link[rmatio:write.mat-methods]{rmatio::write.mat()}} 56 | \item OpenDocument Spreadsheet (.ods, .fods), using \code{\link[readODS:write_ods]{readODS::write_ods()}} or \code{\link[readODS:write_ods]{readODS::write_fods()}}. 57 | \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. 58 | \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. 59 | \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. 60 | \item Clipboard export (on Windows and Mac OS), using \code{\link[utils:write.table]{utils::write.table()}} with \code{row.names = FALSE} 61 | } 62 | 63 | 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. 64 | 65 | Use \code{\link[=export_list]{export_list()}} to export a list of dataframes to separate files. 66 | } 67 | \examples{ 68 | ## For demo, a temp. file path is created with the file extension .csv 69 | csv_file <- tempfile(fileext = ".csv") 70 | ## .xlsx 71 | xlsx_file <- tempfile(fileext = ".xlsx") 72 | 73 | ## create CSV to import 74 | export(iris, csv_file) 75 | 76 | ## You can certainly export your data with the file name, which is not a variable: 77 | ## import(mtcars, "car_data.csv") 78 | 79 | ## pass arguments to the underlying function 80 | ## data.table::fwrite is the underlying function and `col.names` is an argument 81 | export(iris, csv_file, col.names = FALSE) 82 | 83 | ## export a list of data frames as worksheets 84 | export(list(a = mtcars, b = iris), xlsx_file) 85 | 86 | # NOT RECOMMENDED 87 | 88 | ## specify `format` to override default format 89 | export(iris, xlsx_file, format = "csv") ## That's confusing 90 | ## You can also specify only the format; in the following case 91 | ## "mtcars.dta" is written [also confusing] 92 | 93 | ## export(mtcars, format = "stata") 94 | } 95 | \seealso{ 96 | \code{\link[=characterize]{characterize()}}, \code{\link[=import]{import()}}, \code{\link[=convert]{convert()}}, \code{\link[=export_list]{export_list()}} 97 | } 98 | -------------------------------------------------------------------------------- /man/export_list.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/export_list.R 3 | \name{export_list} 4 | \alias{export_list} 5 | \title{Export list of data frames to files} 6 | \usage{ 7 | export_list(x, file, archive = "", ...) 8 | } 9 | \arguments{ 10 | \item{x}{A list of data frames to be written to files.} 11 | 12 | \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.} 13 | 14 | \item{archive}{character. Either empty string (default) to save files in current 15 | directory, a path to a (new) directory, or a .zip/.tar file to compress all 16 | files into an archive.} 17 | 18 | \item{\dots}{Additional arguments passed to \code{\link[=export]{export()}}.} 19 | } 20 | \value{ 21 | The name(s) of the output file(s) as a character vector (invisibly). 22 | } 23 | \description{ 24 | Use \code{\link[=export]{export()}} to export a list of data frames to a vector of file names or a filename pattern. 25 | } 26 | \details{ 27 | \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. 28 | } 29 | \examples{ 30 | ## For demo, a temp. file path is created with the file extension .xlsx 31 | xlsx_file <- tempfile(fileext = ".xlsx") 32 | export( 33 | list( 34 | mtcars1 = mtcars[1:10, ], 35 | mtcars2 = mtcars[11:20, ], 36 | mtcars3 = mtcars[21:32, ] 37 | ), 38 | xlsx_file 39 | ) 40 | 41 | # import a single file from multi-object workbook 42 | import(xlsx_file, sheet = "mtcars1") 43 | # import all worksheets, the return value is a list 44 | import_list(xlsx_file) 45 | library('datasets') 46 | export(list(mtcars1 = mtcars[1:10,], 47 | mtcars2 = mtcars[11:20,], 48 | mtcars3 = mtcars[21:32,]), 49 | xlsx_file <- tempfile(fileext = ".xlsx") 50 | ) 51 | 52 | # import all worksheets 53 | list_of_dfs <- import_list(xlsx_file) 54 | 55 | # re-export as separate named files 56 | 57 | ## export_list(list_of_dfs, file = c("file1.csv", "file2.csv", "file3.csv")) 58 | 59 | # re-export as separate files using a name pattern; using the names in the list 60 | ## This will be written as "mtcars1.csv", "mtcars2.csv", "mtcars3.csv" 61 | 62 | ## export_list(list_of_dfs, file = "\%s.csv") 63 | } 64 | \seealso{ 65 | \code{\link[=import]{import()}}, \code{\link[=import_list]{import_list()}}, \code{\link[=export]{export()}} 66 | } 67 | -------------------------------------------------------------------------------- /man/figures/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gesistsa/rio/f1094bf636f95f5dfcb05408d2ca0960fa792c8e/man/figures/logo.png -------------------------------------------------------------------------------- /man/gather_attrs.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/gather_attrs.R 3 | \name{gather_attrs} 4 | \alias{gather_attrs} 5 | \alias{spread_attrs} 6 | \title{Gather attributes from data frame variables} 7 | \usage{ 8 | gather_attrs(x) 9 | 10 | spread_attrs(x) 11 | } 12 | \arguments{ 13 | \item{x}{A data frame.} 14 | } 15 | \value{ 16 | \code{x}, with variable-level attributes stored at the data frame level. 17 | } 18 | \description{ 19 | \code{gather_attrs} moves variable-level attributes to the data frame level and \code{spread_attrs} reverses that operation. 20 | } 21 | \details{ 22 | \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. 23 | } 24 | \seealso{ 25 | \code{\link[=import]{import()}}, \code{\link[=characterize]{characterize()}} 26 | } 27 | -------------------------------------------------------------------------------- /man/get_info.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \name{get_info} 4 | \alias{get_info} 5 | \alias{get_ext} 6 | \title{Get File Info} 7 | \usage{ 8 | get_info(file) 9 | 10 | get_ext(file) 11 | } 12 | \arguments{ 13 | \item{file}{A character string containing a filename, file path, or URL.} 14 | } 15 | \value{ 16 | For \code{\link[=get_info]{get_info()}}, a list is return with the following slots 17 | \itemize{ 18 | \item \code{input} file extension or information used to identify the possible file format 19 | \item \code{format} file format, see \code{format} argument of \code{\link[=import]{import()}} 20 | \item \code{type} "import" (supported by default); "suggest" (supported by suggested packages, see \code{\link[=install_formats]{install_formats()}}); "enhance" and "known " are not directly supported; \code{NA} is unsupported 21 | \item \code{format_name} name of the format 22 | \item \code{import_function} What function is used to import this file 23 | \item \code{export_function} What function is used to export this file 24 | \item \code{file} \code{file} 25 | } 26 | For \code{\link[=get_ext]{get_ext()}}, just \code{input} (usually file extension) is returned; retained for backward compatibility. 27 | } 28 | \description{ 29 | A utility function to retrieve the file information of a filename, path, or URL. 30 | } 31 | \examples{ 32 | get_info("starwars.xlsx") 33 | get_info("starwars.ods") 34 | get_info("https://github.com/ropensci/readODS/raw/v2.1/starwars.ods") 35 | get_info("~/duran_duran_rio.mp3") 36 | get_ext("clipboard") ## "clipboard" 37 | get_ext("https://github.com/ropensci/readODS/raw/v2.1/starwars.ods") 38 | } 39 | -------------------------------------------------------------------------------- /man/import_list.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/import_list.R 3 | \name{import_list} 4 | \alias{import_list} 5 | \title{Import list of data frames} 6 | \usage{ 7 | import_list( 8 | file, 9 | setclass = getOption("rio.import.class", "data.frame"), 10 | which, 11 | rbind = FALSE, 12 | rbind_label = "_file", 13 | rbind_fill = TRUE, 14 | ... 15 | ) 16 | } 17 | \arguments{ 18 | \item{file}{A character string containing a single file name for a multi-object file (e.g., Excel workbook, zip file, tar archive, or HTML file), or a vector of file paths for multiple files to be imported.} 19 | 20 | \item{setclass}{An optional character vector specifying one or more classes 21 | to set on the import. By default, the return object is always a 22 | \dQuote{data.frame}. Allowed values include \dQuote{tbl_df}, \dQuote{tbl}, or 23 | \dQuote{tibble} (if using tibble), \dQuote{arrow}, \dQuote{arrow_table} (if using arrow table; the suggested package \code{arrow} must be installed) or \dQuote{data.table} (if using 24 | data.table). Other values are ignored, such that a data.frame is returned. 25 | The parameter takes precedents over parameters in \dots which set a different class.} 26 | 27 | \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.} 28 | 29 | \item{rbind}{A logical indicating whether to pass the import list of data frames through \code{\link[data.table:rbindlist]{data.table::rbindlist()}}.} 30 | 31 | \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.} 32 | 33 | \item{rbind_fill}{If \code{rbind = TRUE}, a logical indicating whether to set the \code{fill = TRUE} (and fill missing columns with \code{NA}).} 34 | 35 | \item{\dots}{Additional arguments passed to \code{\link[=import]{import()}}. Behavior may be unexpected if files are of different formats.} 36 | } 37 | \value{ 38 | 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. 39 | } 40 | \description{ 41 | 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, compressed directory in a zip file or tar archive, or HTML file) 42 | } 43 | \details{ 44 | When file is a vector of file paths and any files are missing, those files are ignored (with warnings) and this function will not raise any error. For compressed files, the file name must also contain information about the file format of all compressed files, e.g. \code{files.csv.zip} for this function to work. 45 | } 46 | \section{Trust}{ 47 | For serialization formats (.R, .RDS, and .RData), please note that you should only load these files from trusted sources. It is because these formats are not necessarily for storing rectangular data and can also be used to store many things, e.g. code. Importing these files could lead to arbitary code execution. Please read the security principles by the R Project (Plummer, 2024). When importing these files via \code{rio}, you should affirm that you trust these files, i.e. \code{trust = TRUE}. See example below. If this affirmation is missing, the current version assumes \code{trust} to be true for backward compatibility and a deprecation notice will be printed. In the next major release (2.0.0), you must explicitly affirm your trust when importing these files. 48 | } 49 | 50 | \section{Which}{ 51 | For compressed archives (zip and tar, where a compressed file can contain multiple files), it is possible to come to a situation where the parameter \code{which} is used twice to indicate two different concepts. For example, it is unclear for \code{.xlsx.zip}whether \code{which} refers to the selection of an exact file in the archive or the selection of an exact sheet in the decompressed Excel file. In these cases, \code{rio} assumes that \code{which} is only used for the selection of file. After the selection of file with \code{which}, \code{rio} will return the first item, e.g. the first sheet. 52 | 53 | Please note, however, \code{.gz} and \code{.bz2} (e.g. \code{.xlsx.gz}) are compressed, but not archive format. In those cases, \code{which} is used the same way as the non-compressed format, e.g. selection of sheet for Excel. 54 | } 55 | 56 | \examples{ 57 | ## For demo, a temp. file path is created with the file extension .xlsx 58 | xlsx_file <- tempfile(fileext = ".xlsx") 59 | export( 60 | list( 61 | mtcars1 = mtcars[1:10, ], 62 | mtcars2 = mtcars[11:20, ], 63 | mtcars3 = mtcars[21:32, ] 64 | ), 65 | xlsx_file 66 | ) 67 | 68 | # import a single file from multi-object workbook 69 | import(xlsx_file, sheet = "mtcars1") 70 | # import all worksheets, the return value is a list 71 | import_list(xlsx_file) 72 | 73 | # import and rbind all worksheets, the return value is a data frame 74 | import_list(xlsx_file, rbind = TRUE) 75 | } 76 | \references{ 77 | Plummer, M (2024). Statement on CVE-2024-27322. \url{https://blog.r-project.org/2024/05/10/statement-on-cve-2024-27322/} 78 | } 79 | \seealso{ 80 | \code{\link[=import]{import()}}, \code{\link[=export_list]{export_list()}}, \code{\link[=export]{export()}} 81 | } 82 | -------------------------------------------------------------------------------- /man/install_formats.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/suggestions.R 3 | \name{install_formats} 4 | \alias{install_formats} 5 | \alias{show_unsupported_formats} 6 | \title{Install rio's \sQuote{Suggests} Dependencies} 7 | \usage{ 8 | install_formats(...) 9 | 10 | show_unsupported_formats() 11 | } 12 | \arguments{ 13 | \item{\dots}{Additional arguments passed to \code{\link[utils:install.packages]{utils::install.packages()}}.} 14 | } 15 | \value{ 16 | For \code{show_unsupported_formats()}, if there is any missing unsupported formats, it return TRUE invisibly; otherwise FALSE. For \code{install_formats()} it returns TRUE invisibly if the installation is succuessful; otherwise errors. 17 | } 18 | \description{ 19 | Not all suggested packages are installed by default. These packages are not installed or loaded by default in order to create a slimmer and faster package build, install, and load. Use \code{show_unsupported_formats()} to check all unsupported formats. \code{install_formats()} installs all missing \sQuote{Suggests} dependencies for rio that expand its support to the full range of support import and export formats. 20 | } 21 | \examples{ 22 | \donttest{ 23 | if (interactive()) { 24 | install_formats() 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /man/rio.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/rio.R 3 | \docType{package} 4 | \name{rio} 5 | \alias{rio-package} 6 | \alias{rio} 7 | \title{A Swiss-Army Knife for Data I/O} 8 | \description{ 9 | 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. 10 | 11 | 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. 12 | } 13 | \examples{ 14 | # export 15 | library("datasets") 16 | export(mtcars, csv_file <- tempfile(fileext = ".csv")) # comma-separated values 17 | export(mtcars, rds_file <- tempfile(fileext = ".rds")) # R serialized 18 | export(mtcars, sav_file <- tempfile(fileext = ".sav")) # SPSS 19 | 20 | # import 21 | x <- import(csv_file) 22 | y <- import(rds_file) 23 | z <- import(sav_file) 24 | 25 | # convert sav (SPSS) to dta (Stata) 26 | convert(sav_file, dta_file <- tempfile(fileext = ".dta")) 27 | 28 | # cleanup 29 | unlink(c(csv_file, rds_file, sav_file, dta_file)) 30 | 31 | } 32 | \references{ 33 | \href{https://cran.r-project.org/package=datamods}{datamods} provides Shiny modules for importing data via \code{rio}. 34 | 35 | \href{https://github.com/Stan125/GREA}{GREA} provides an RStudio add-in to import data using rio. 36 | } 37 | \seealso{ 38 | \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()}} 39 | } 40 | \author{ 41 | \strong{Maintainer}: Chung-hong Chan \email{chainsawtiney@gmail.com} (\href{https://orcid.org/0000-0002-6232-7530}{ORCID}) 42 | 43 | Authors: 44 | \itemize{ 45 | \item Jason Becker \email{jason@jbecker.co} 46 | \item David Schoch \email{david@schochastics.net} (\href{https://orcid.org/0000-0003-2952-4812}{ORCID}) 47 | \item Thomas J. Leeper \email{thosjleeper@gmail.com} (\href{https://orcid.org/0000-0003-4097-6326}{ORCID}) 48 | } 49 | 50 | Other contributors: 51 | \itemize{ 52 | \item Geoffrey CH Chan \email{gefchchan@gmail.com} [contributor] 53 | \item Christopher Gandrud [contributor] 54 | \item Andrew MacDonald [contributor] 55 | \item Ista Zahn [contributor] 56 | \item Stanislaus Stadlmann [contributor] 57 | \item Ruaridh Williamson \email{ruaridh.williamson@gmail.com} [contributor] 58 | \item Patrick Kennedy [contributor] 59 | \item Ryan Price \email{ryapric@gmail.com} [contributor] 60 | \item Trevor L Davis \email{trevor.l.davis@gmail.com} [contributor] 61 | \item Nathan Day \email{nathancday@gmail.com} [contributor] 62 | \item Bill Denney \email{wdenney@humanpredictions.com} (\href{https://orcid.org/0000-0002-5759-428X}{ORCID}) [contributor] 63 | \item Alex Bokov \email{alex.bokov@gmail.com} (\href{https://orcid.org/0000-0002-0511-9815}{ORCID}) [contributor] 64 | \item Hugo Gruson (\href{https://orcid.org/0000-0002-4094-1476}{ORCID}) [contributor] 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /po/R-rio.pot: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "Project-Id-Version: rio 0.5.27\n" 4 | "POT-Creation-Date: 2021-06-18 09:36\n" 5 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 6 | "Last-Translator: FULL NAME \n" 7 | "Language-Team: LANGUAGE \n" 8 | "MIME-Version: 1.0\n" 9 | "Content-Type: text/plain; charset=CHARSET\n" 10 | "Content-Transfer-Encoding: 8bit\n" 11 | 12 | 13 | msgid "The following arguments were ignored for" 14 | msgstr "" 15 | 16 | msgid ":" 17 | msgstr "" 18 | 19 | msgid "," 20 | msgstr "" 21 | 22 | msgid "condition" 23 | msgstr "" 24 | 25 | msgid "File compression failed for %s!" 26 | msgstr "" 27 | 28 | msgid "Zip archive contains multiple files. Attempting first file." 29 | msgstr "" 30 | 31 | msgid "Tar archive contains multiple files. Attempting first file." 32 | msgstr "" 33 | 34 | msgid "'outfile' is missing with no default" 35 | msgstr "" 36 | 37 | msgid "Must specify 'file' and/or 'format'" 38 | msgstr "" 39 | 40 | msgid "'x' is not a data.frame or matrix" 41 | msgstr "" 42 | 43 | msgid "'x' must be a list. Perhaps you want export()?" 44 | msgstr "" 45 | 46 | msgid "'file' must be a character vector" 47 | msgstr "" 48 | 49 | msgid "'file' must have a %s placehold" 50 | msgstr "" 51 | 52 | msgid "All elements of 'x' must be named or all must be unnamed" 53 | msgstr "" 54 | 55 | msgid "Names of elements in 'x' are not unique" 56 | msgstr "" 57 | 58 | msgid "'file' must be same length as 'x', or a single pattern with a %s placeholder" 59 | msgstr "" 60 | 61 | msgid "File names are not unique" 62 | msgstr "" 63 | 64 | msgid "Export failed for element %d, filename: %s" 65 | msgstr "" 66 | 67 | msgid "data.table::fwrite() does not support writing to connections. Using utils::write.table() instead." 68 | msgstr "" 69 | 70 | msgid "Columns:" 71 | msgstr "" 72 | 73 | msgid "'x' must be a data.frame, list, or environment" 74 | msgstr "" 75 | 76 | msgid "%s format not supported. Consider using the '%s()' function" 77 | msgstr "" 78 | 79 | msgid "Import support for the %s format is exported by the %s package. Run 'library(%s)' then try again." 80 | msgstr "" 81 | 82 | msgid "Format not supported" 83 | msgstr "" 84 | 85 | msgid "'x' is not a data.frame" 86 | msgstr "" 87 | 88 | msgid "No such file" 89 | msgstr "" 90 | 91 | msgid "'data.table = TRUE' argument overruled. Using setclass = '%s'" 92 | msgstr "" 93 | 94 | msgid "Import failed for %s" 95 | msgstr "" 96 | 97 | msgid "Import failed for %s from %s" 98 | msgstr "" 99 | 100 | msgid "Attempt to rbindlist() the data did not succeed. List returned instead." 101 | msgstr "" 102 | 103 | msgid "data.table::fread() does not support reading from connections. Using utils::read.table() instead." 104 | msgstr "" 105 | 106 | msgid "Ambiguous file format ('.dat'), but attempting 'data.table::fread(\"%s\")'" 107 | msgstr "" 108 | 109 | msgid "Import of fixed-width format data requires a 'widths' argument. See ? read.fwf()." 110 | msgstr "" 111 | 112 | msgid "File imported using load. Arguments to '...' ignored." 113 | msgstr "" 114 | 115 | msgid "Dump file contains multiple objects. Returning first object." 116 | msgstr "" 117 | 118 | msgid "File imported using readRDS. Arguments to '...' ignored." 119 | msgstr "" 120 | 121 | msgid "Rdata file contains multiple objects. Returning first object." 122 | msgstr "" 123 | 124 | msgid "Import of Fortran format data requires a 'style' argument. See ? utils::read.fortran()." 125 | msgstr "" 126 | 127 | msgid "The following arguments were ignored for read_ods:" 128 | msgstr "" 129 | 130 | msgid "Requested table exceeds number of tables found in file (" 131 | msgstr "" 132 | 133 | msgid ")!" 134 | msgstr "" 135 | 136 | msgid "Unrecognized file format. Try specifying with the format argument." 137 | msgstr "" 138 | 139 | msgid "'file' is not a string" 140 | msgstr "" 141 | 142 | msgid "'file' has no extension" 143 | msgstr "" 144 | 145 | msgid "last record incomplete, %d line discarded" 146 | msgid_plural "last record incomplete, %d lines discarded" 147 | msgstr[0] "" 148 | msgstr[1] "" 149 | -------------------------------------------------------------------------------- /rio.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: No 4 | SaveWorkspace: No 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 4 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: XeLaTeX 14 | 15 | LineEndingConversion: Posix 16 | 17 | BuildType: Package 18 | PackageUseDevtools: Yes 19 | PackageInstallArgs: --no-multiarch --with-keep.source 20 | PackageRoxygenize: rd,namespace,vignette 21 | -------------------------------------------------------------------------------- /starwars.csv: -------------------------------------------------------------------------------- 1 | Name,homeworld,species 2 | Luke Skywalker,Tatooine,Human 3 | C-3PO,Tatooine,Human 4 | R2-D2,Alderaan,Human 5 | Darth Vader,Tatooine,Human 6 | Leia Organa,Tatooine,Human 7 | Owen Lars,Tatooine,Human 8 | Beru Whitesun lars,Stewjon,Human 9 | R5-D4,Tatooine,Human 10 | Biggs Darklighter,Kashyyyk,Wookiee 11 | Obi-Wan Kenobi,Corellia,Human 12 | -------------------------------------------------------------------------------- /starwars.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gesistsa/rio/f1094bf636f95f5dfcb05408d2ca0960fa792c8e/starwars.xlsx -------------------------------------------------------------------------------- /tests/testdata/br-in-header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |

Date
1December 15, 2003 13:14:17.123
6 | -------------------------------------------------------------------------------- /tests/testdata/br-in-td.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
RowSTUDYID
1
2
8 | 9 | -------------------------------------------------------------------------------- /tests/testdata/example.csvy: -------------------------------------------------------------------------------- 1 | --- 2 | name: my-dataset 3 | fields: 4 | - name: var1 5 | title: variable 1 6 | type: string 7 | description: explaining var1 8 | constraints: 9 | - required: true 10 | - name: var2 11 | title: variable 2 12 | type: integer 13 | - name: var3 14 | title: variable 3 15 | type: number 16 | --- 17 | var1,var2,var3 18 | A,1,2.5 19 | B,3,4.3 20 | -------------------------------------------------------------------------------- /tests/testdata/iris.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gesistsa/rio/f1094bf636f95f5dfcb05408d2ca0960fa792c8e/tests/testdata/iris.xls -------------------------------------------------------------------------------- /tests/testdata/iris_no_extension_xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gesistsa/rio/f1094bf636f95f5dfcb05408d2ca0960fa792c8e/tests/testdata/iris_no_extension_xls -------------------------------------------------------------------------------- /tests/testdata/mtcars.ods: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gesistsa/rio/f1094bf636f95f5dfcb05408d2ca0960fa792c8e/tests/testdata/mtcars.ods -------------------------------------------------------------------------------- /tests/testdata/noheader.csv: -------------------------------------------------------------------------------- 1 | 0,??,?,Total,1998,46991171,23594034,23397137 2 | 0,??,0 - 4?,0 ,1998,3390678,1788561,1602117 3 | 0,??,5 - 9?,5 ,1998,3428387,1820224,1608163 4 | 0,??,10 - 14?,10,1998,3195174,1668531,1526643 5 | 0,??,15 - 19?,15,1998,4094035,2102515,1991520 6 | 0,??,20 - 24?,20,1998,3942827,2022535,1920292 7 | 0,??,25 - 29?,25,1998,4637577,2371635,2265942 8 | 0,??,30 - 34?,30,1998,4375695,2239107,2136588 9 | 0,??,35 - 39?,35,1998,4502137,2308132,2194005 10 | 0,??,40 - 44?,40,1998,3754895,1924704,1830191 11 | -------------------------------------------------------------------------------- /tests/testdata/th-as-row-element.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
RowSTUDYID
1ABC
2ABC
8 | 9 | 10 | -------------------------------------------------------------------------------- /tests/testdata/two-tbody.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
DatasetDescription
COComments
11 | 12 | 13 | -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | library("testthat") 2 | library("rio") 3 | test_check("rio", reporter = "summary") 4 | -------------------------------------------------------------------------------- /tests/testthat/test_characterize.R: -------------------------------------------------------------------------------- 1 | context("characterize()/factorize()") 2 | x <- structure(1:4, labels = c("A" = 1, "B" = 2, "C" = 3)) 3 | xdf <- data.frame(v1 = structure(1:4, labels = c("A" = 1, "B" = 2, "C" = 3), label = "variable 1"), 4 | v2 = structure(c(1,0,0,1), labels = c("foo" = 0, "bar" = 1)), 5 | v3 = 4:1, label = "variable 2") 6 | 7 | 8 | test_that("test characterize.default()", { 9 | expect_true(identical(characterize(x), c(LETTERS[1:3], NA))) 10 | }) 11 | 12 | test_that("test characterize.default()", { 13 | expect_true(identical(characterize(xdf), {xdf[] <- lapply(xdf, characterize); xdf})) 14 | }) 15 | 16 | test_that("test factorize.data.frame()", { 17 | expect_true(identical(factorize(x), factor(x, attributes(x)$labels, names(attributes(x)$labels)))) 18 | }) 19 | 20 | test_that("test factorize.data.frame()", { 21 | expect_true(identical(factorize(xdf), {xdf[] <- lapply(xdf, factorize); xdf})) 22 | }) 23 | 24 | test_that("test factorize coerce_character", { 25 | expect_true(identical(letters[1:3], factorize(letters[1:3]))) 26 | expect_true( 27 | identical( 28 | factorize(letters[3:1], coerce_character = TRUE), 29 | factor(letters[3:1], levels = letters[1:3]) 30 | ) 31 | ) 32 | }) -------------------------------------------------------------------------------- /tests/testthat/test_check_file.R: -------------------------------------------------------------------------------- 1 | test_that(".check_file", { 2 | data <- data.frame( 3 | x = sample(1:10, 10000, replace = TRUE), 4 | y = sample(1:10, 10000, replace = TRUE) 5 | ) 6 | expect_error(.check_file(1)) 7 | expect_error(.check_file(TRUE)) 8 | expect_error(.check_file(data)) 9 | expect_error(.check_file(iris)) 10 | expect_error(.check_file(c("a.csv", "b.csv"))) 11 | expect_error(.check_file(NA)) 12 | expect_error(.check_file(NA_character_)) 13 | expect_error(.check_file(c(NA, "a.csv"))) 14 | expect_error(.check_file(c(NA_character_, "a.csv"))) 15 | expect_error(.check_file("a.csv"), NA) 16 | expect_error(.check_file(), NA) 17 | ## single_only FALSE 18 | expect_error(.check_file(1, single_only = FALSE)) 19 | expect_error(.check_file(TRUE, single_only = FALSE)) 20 | expect_error(.check_file(data, single_only = FALSE)) 21 | expect_error(.check_file(iris, single_only = FALSE)) 22 | expect_error(.check_file(c("a.csv", "b.csv"), single_only = FALSE), NA) 23 | expect_error(.check_file("a.csv"), NA) 24 | expect_error(.check_file(single_only = FALSE), NA) 25 | }) 26 | 27 | test_that("Invalid file argument - import(), #301", { 28 | data <- data.frame( 29 | x = sample(1:10, 10000, replace = TRUE), 30 | y = sample(1:10, 10000, replace = TRUE) 31 | ) 32 | expect_error(import(data), "Invalid") 33 | expect_error(import(iris), "Invalid") 34 | expect_error(import(1), "Invalid") 35 | expect_error(import(TRUE), "Invalid") 36 | expect_error(import(c("a.csv", "b.csv")), "Invalid") 37 | }) 38 | 39 | test_that("Invalid file argument - import_list(), #301", { 40 | data <- data.frame( 41 | x = sample(1:10, 10000, replace = TRUE), 42 | y = sample(1:10, 10000, replace = TRUE) 43 | ) 44 | expect_error(import_list(data), "Invalid") 45 | expect_error(import_list(iris), "Invalid") 46 | expect_error(import_list(1), "Invalid") 47 | expect_error(import_list(TRUE), "Invalid") 48 | }) 49 | 50 | test_that("Invalid file argument - export(), #301", { 51 | data <- data.frame( 52 | x = sample(1:10, 10000, replace = TRUE), 53 | y = sample(1:10, 10000, replace = TRUE) 54 | ) 55 | expect_error(export(iris, data), "Invalid") 56 | expect_error(export(iris, iris), "Invalid") 57 | expect_error(export(iris, 1), "Invalid") 58 | expect_error(export(iris, TRUE), "Invalid") 59 | expect_error(export(iris, c("abc.csv", "123.csv")), "Invalid") 60 | }) 61 | 62 | test_that("Invalid file argument - export_list(), #301", { 63 | data <- data.frame( 64 | x = sample(1:10, 10000, replace = TRUE), 65 | y = sample(1:10, 10000, replace = TRUE) 66 | ) 67 | expect_error(export_list(iris, data), "Invalid") 68 | expect_error(export_list(iris, iris), "Invalid") 69 | expect_error(export_list(iris, 1), "Invalid") 70 | expect_error(export_list(iris, TRUE), "Invalid") 71 | }) 72 | -------------------------------------------------------------------------------- /tests/testthat/test_compress.R: -------------------------------------------------------------------------------- 1 | context("Compressed files") 2 | 3 | test_that("Recognize compressed file types", { 4 | expect_true(rio:::find_compress("file.zip")$compress == "zip") 5 | expect_true(rio:::find_compress("file.tar")$compress == "tar") 6 | expect_true(rio:::find_compress("file.tar.gz")$compress == "tar.gz") 7 | expect_true(rio:::find_compress("file.gzip")$compress == "gzip") 8 | expect_true(rio:::find_compress("file.gz")$compress == "gzip") 9 | expect_true(is.na(rio:::find_compress("file.notcompressed")$compress)) 10 | }) 11 | 12 | test_that("Export to compressed (zip, tar) / import", { 13 | skip_if(getRversion() <= "4.0") 14 | formats <- c("zip", "tar", "tar.gz", "tgz", "tar.bz2", "tbz2") 15 | for (format in formats) { 16 | withr::with_tempfile("iris_path", fileext = paste0(".csv.", format), code = { 17 | e1 <- export(iris, iris_path) 18 | expect_true(file.exists(iris_path)) 19 | expect_true(is.data.frame(import(iris_path))) 20 | expect_true(is.data.frame(import(iris_path, which = 1))) 21 | base_file_name <- gsub(paste0("\\.", format), "", basename(iris_path)) 22 | expect_true(is.data.frame(import(iris_path, which = base_file_name))) 23 | if (format %in% c("tar.gz", "tgz")) { 24 | expect_true(R.utils::isGzipped(iris_path, method = "content")) 25 | } 26 | if (format %in% c("tar.bzip2", "tbz2")) { 27 | expect_true(R.utils::isBzipped(iris_path, method = "content")) 28 | } 29 | }) 30 | } 31 | }) 32 | 33 | test_that("Multi-item zip", { 34 | formats <- c("zip") 35 | for (format in formats) { 36 | withr::with_tempfile("iris_path", fileext = paste0(".csv.", format), code = { 37 | list_of_df <- list(mtcars1 = mtcars[1:10, ], mtcars2 = mtcars[11:20, ], mtcars3 = mtcars[21:32, ]) 38 | export_list(list_of_df, file = "%s.csv", archive = iris_path) 39 | y <- import(iris_path) 40 | expect_true(is.data.frame(y)) 41 | expect_silent(z1 <- import(iris_path, which = 1)) 42 | expect_silent(z2 <- import(iris_path, which = 2)) 43 | expect_true(identical(y, z1)) 44 | expect_false(identical(y, z2)) 45 | }) 46 | } 47 | }) 48 | 49 | test_that("Export to compressed (gz, bz2) / import", { 50 | formats <- c("gz", "gzip", "bz2", "bzip2") 51 | for (format in formats) { 52 | withr::with_tempfile("iris_path", fileext = paste0(".csv.", format), code = { 53 | e1 <- export(iris, iris_path) 54 | expect_true(file.exists(iris_path)) 55 | expect_true(is.data.frame(import(iris_path))) 56 | if (format %in% c("gzip", "gz")) { 57 | expect_true(R.utils::isGzipped(iris_path, method = "content")) 58 | } 59 | if (format %in% c("bzip2", "bz2")) { 60 | expect_true(R.utils::isBzipped(iris_path, method = "content")) 61 | } 62 | }) 63 | } 64 | }) 65 | 66 | test_that("Prevent the reuse of `which` for zip and tar", { 67 | skip_if(getRversion() <= "4.0") 68 | formats <- c("zip", "tar", "tar.gz", "tgz", "tar.bz2", "tbz2") 69 | for (format in formats) { 70 | withr::with_tempfile("data_path", fileext = paste0(".xlsx.", format), code = { 71 | rio::export(list(some_iris = head(iris)), data_path) 72 | expect_error(import(data_path), NA) 73 | raw_file <- .list_archive(data_path, find_compress(data_path)$compress)[1] 74 | expect_error(import(data_path, which = raw_file), NA) 75 | expect_error(suppressWarnings(import(data_path, which = "some_iris"))) 76 | }) 77 | } 78 | ## but not for non-archive format, e.g. .xlsx.gz 79 | formats <- c("gz", "bz2") 80 | for (format in formats) { 81 | withr::with_tempfile("data_path", fileext = paste0(".xlsx.", format), code = { 82 | rio::export(list(some_iris = head(iris)), data_path) 83 | expect_error(import(data_path), NA) 84 | expect_error(import(data_path, which = "some_iris"), NA) 85 | }) 86 | } 87 | }) 88 | 89 | test_that(".check_tar_support ref #421", { 90 | expect_error(.check_tar_support("tar", R_system_version("4.0.2")), "^Exporting") 91 | expect_error(.check_tar_support("tar.gz", R_system_version("4.0.2")), "^Exporting") 92 | expect_error(.check_tar_support("tar.bz2", R_system_version("4.0.2")), "^Exporting") 93 | expect_error(.check_tar_support("tar", R_system_version("4.0.3")), NA) 94 | expect_error(.check_tar_support("tar.gz", R_system_version("4.0.3")), NA) 95 | expect_error(.check_tar_support("tar.bz2", R_system_version("4.0.3")), NA) 96 | expect_error(.check_tar_support("zip", R_system_version("4.0.2")), NA) 97 | expect_error(.check_tar_support(NA, R_system_version("4.0.2")), NA) 98 | }) 99 | 100 | test_that("tar export error for R < 4.0.3", { 101 | skip_if(getRversion() >= "4.0.3") 102 | withr::with_tempfile("iris_path", fileext = paste0(".csv.", "tar"), code = { 103 | expect_error(export(iris, iris_path), "^Exporting") 104 | }) 105 | }) 106 | 107 | test_that("Wild zip and tar ref $425", { 108 | skip_if(getRversion() <= "4.0") 109 | ##skip_on_os("windows") 110 | withr::with_tempfile("test_files", fileext = c(".csv", ".zip"), code = { 111 | filename <- test_files[1] 112 | zip_file <- test_files[2] 113 | write.csv(1, filename) 114 | zip(zip_file, filename) 115 | expect_error(rio::import(zip_file), NA) 116 | }) 117 | for (tar_format in c("tar", "tar.gz", "tar.bz2")) { 118 | withr::with_tempfile("test_files", fileext = c(".csv", paste0(".", tar_format)), code = { 119 | filename <- test_files[1] 120 | tar_file <- test_files[2] 121 | write.csv(1, filename) 122 | compress_out(tar_file, filename, type = tar_format) 123 | expect_error(rio::import(tar_file), NA) 124 | }) 125 | } 126 | }) 127 | 128 | test_that("Relative path #438", { 129 | ## see test_export_list.R 130 | withr::with_tempdir({ 131 | mylist <- list( 132 | mtcars3 = mtcars[1:10, ], 133 | mtcars2 = mtcars[11:20, ], 134 | mtcars1 = mtcars[21:32, ] 135 | ) 136 | rio::export_list(mylist, file = paste0("file_", 1:3, ".csv"), archive = "arch/archive.zip") 137 | expect_true(file.exists("arch/archive.zip")) 138 | }) 139 | }) 140 | 141 | test_that("Integration test #435", { 142 | ## filter out all NA cases so that #437 works 143 | withr::with_tempfile("iris_path", fileext = "csv.zip", code = { 144 | expect_error(rio::export(iris, NA), "must be character") ## strange to be honest 145 | expect_error(rio::export(iris, NA_character_), "must not be NA") 146 | }) 147 | }) 148 | -------------------------------------------------------------------------------- /tests/testthat/test_convert.R: -------------------------------------------------------------------------------- 1 | library("datasets") 2 | 3 | test_that("Basic file conversion", { 4 | withr::with_tempfile("mtcars_files", fileext = c(".dta", ".csv"), code = { 5 | export(mtcars, mtcars_files[1]) 6 | convert(mtcars_files[1], mtcars_files[2]) 7 | convert(mtcars_files[2], mtcars_files[1]) 8 | x <- import(mtcars_files[1]) 9 | expect_true(identical(names(mtcars), names(x))) 10 | expect_true(identical(dim(mtcars), dim(x))) 11 | }) 12 | }) 13 | 14 | test_that("File conversion with arguments", { 15 | withr::with_tempfile("mtcars_files", fileext = c(".csv", ".tsv"), code = { 16 | export(mtcars, mtcars_files[1], format = "tsv") 17 | convert(mtcars_files[1], mtcars_files[1], in_opts = list(format = "tsv")) 18 | expect_true(file.exists(mtcars_files[1])) 19 | expect_true(!file.exists(mtcars_files[2])) 20 | convert(mtcars_files[1], mtcars_files[2], 21 | in_opts = list(format = "tsv"), out_opts = list(format = "csv")) 22 | expect_true(file.exists(mtcars_files[2])) 23 | }) 24 | }) 25 | 26 | test_that("File conversion w/o out_file errors", { 27 | withr::with_tempfile("mtcars_file", fileext = ".dta", { 28 | export(mtcars, mtcars_file) 29 | expect_error(convert(mtcars_file)) 30 | }) 31 | }) 32 | -------------------------------------------------------------------------------- /tests/testthat/test_create_outfiles.R: -------------------------------------------------------------------------------- 1 | test_that(".create_outfiles works", { 2 | x <- list( 3 | a = data.frame(), 4 | b = data.frame(), 5 | c = data.frame() 6 | ) 7 | y <- list( 8 | data.frame(), 9 | data.frame(), 10 | data.frame() 11 | ) 12 | expect_identical(.create_outfiles("d_%s.csv", x), c("d_a.csv", "d_b.csv", "d_c.csv")) 13 | expect_identical(.create_outfiles("d_%s.csv", y), c("d_1.csv", "d_2.csv", "d_3.csv")) 14 | expect_identical(.create_outfiles(c("a.csv", "b.csv", "c.csv"), x), c("a.csv", "b.csv", "c.csv")) 15 | }) 16 | 17 | test_that(".create_outfiles errors", { 18 | x <- list( 19 | a = data.frame(), 20 | a = data.frame(), 21 | c = data.frame() 22 | ) 23 | y <- list( 24 | a = data.frame(), 25 | b = data.frame(), 26 | data.frame() 27 | ) 28 | expect_error(.create_outfiles("d_%s.csv", x)) 29 | expect_error(.create_outfiles(c("a.csv", "a.csv", "c.csv"), x)) 30 | expect_error(.create_outfiles(c("a.csv", "b.csv"), x)) 31 | expect_error(.create_outfiles(c("a.csv"), x)) 32 | expect_error(.create_outfiles(c("d_%s.csv"), y)) 33 | }) 34 | -------------------------------------------------------------------------------- /tests/testthat/test_errors.R: -------------------------------------------------------------------------------- 1 | library("datasets") 2 | 3 | test_that("Function suggestions for unsupported export", { 4 | expect_error(export(data.frame(1), "test.jpg"), 5 | "jpg format not supported. Consider using the 'jpeg::writeJPEG()' function", 6 | fixed = TRUE) 7 | }) 8 | 9 | test_that("Error for unsupported file types", { 10 | withr::with_tempfile("test_file", fileext = ".faketype", code = { 11 | writeLines("123", con = test_file) 12 | expect_error(import(test_file), "Format not supported") 13 | expect_error(export(mtcars, test_file), "Format not supported") 14 | }) 15 | expect_equal(.standardize_format("faketype"), "faketype") 16 | expect_error(get_ext("noextension"), "'file' has no extension") 17 | }) 18 | 19 | test_that("Error for mixed support file types", { 20 | expect_error(import("test.por"), "No such file") 21 | withr::with_tempfile("mtcars_file", fileext = ".por", code = { 22 | expect_error(export(mtcars, mtcars_file), "Format not supported") 23 | }) 24 | }) 25 | 26 | test_that("Only export data.frame or matrix", { 27 | withr::with_tempfile("test_file", fileext = ".csv", code = { 28 | expect_error(export(1, test_file), "'x' is not a data.frame or matrix") 29 | }) 30 | }) 31 | 32 | test_that("Column widths printed for fixed-width format", { 33 | withr::with_tempfile("test_file", fileext = ".txt", code = { 34 | expect_true(is.character(export(data.frame(1), test_file, format = "fwf", verbose = FALSE))) 35 | expect_message(export(data.frame(1), test_file, format = "fwf", verbose = TRUE)) 36 | }) 37 | }) 38 | 39 | test_that("Warning for import_list() with missing file", { 40 | expect_warning(import_list("fake_file.csv")) ## no error 41 | }) 42 | -------------------------------------------------------------------------------- /tests/testthat/test_export_corner_cases.R: -------------------------------------------------------------------------------- 1 | test_that("export to nonexisting directory #347", { 2 | withr::with_tempdir({ 3 | output_dir <- file.path(".", "this_doesnt_exist") 4 | expect_false(dir.exists(output_dir)) 5 | expect_error(export(iris, file.path(output_dir, "iris.csv")), NA) 6 | expect_true(file.exists(file.path(output_dir, "iris.csv"))) 7 | }) 8 | }) 9 | 10 | test_that("export to existing directory (contra previous one) #347", { 11 | withr::with_tempdir({ 12 | output_dir <- file.path(".", "this_surely_exist1") 13 | dir.create(output_dir, recursive = TRUE) ## right? 14 | expect_true(dir.exists(output_dir)) 15 | expect_error(export(iris, file.path(output_dir, "iris.csv")), NA) 16 | expect_true(file.exists(file.path(output_dir, "iris.csv"))) 17 | }) 18 | }) 19 | 20 | test_that("export to nonexisting directory also for compressed file #347", { 21 | withr::with_tempdir({ 22 | output_dir <- file.path(".", "this_doesnt_exist") 23 | expect_false(dir.exists(output_dir)) 24 | expect_error(export(iris, file.path(output_dir, "iris.csv.gz")), NA) 25 | expect_true(file.exists(file.path(output_dir, "iris.csv.gz"))) 26 | }) 27 | }) 28 | -------------------------------------------------------------------------------- /tests/testthat/test_export_list.R: -------------------------------------------------------------------------------- 1 | library("datasets") 2 | 3 | test_that("export_list() works", { 4 | withr::with_tempdir({ 5 | export(list( 6 | mtcars3 = mtcars[1:10, ], 7 | mtcars2 = mtcars[11:20, ], 8 | mtcars1 = mtcars[21:32, ] 9 | ), "mtcars.xlsx") 10 | mylist <- import_list("mtcars.xlsx") 11 | 12 | expect_error(export_list(mtcars), label = "export_list() fails on exporting single data frame") 13 | expect_error(export_list(mylist, file = NULL), label = "export_list() fails when file is NULL") 14 | 15 | expect_true(identical(export_list(mylist, file = paste0("mtcars_", 3:1, ".csv")), paste0("mtcars_", 3:1, ".csv"))) 16 | expect_true(identical(export_list(mylist, file = "%s.csv"), paste0("mtcars", 3:1, ".csv"))) 17 | 18 | expect_true(identical(export_list(mylist, file = paste0("file_", 1:3, ".csv"), archive = "archive.zip"), "archive.zip")) 19 | expect_true(identical(export_list(mylist, file = paste0("file_", 1:3, ".csv"), archive = "arch/archive.zip"), "arch/archive.zip")) 20 | 21 | expect_true(all.equal(mylist[["mtcars1"]], import("mtcars1.csv"))) 22 | expect_true(all.equal(mylist[["mtcars2"]], import("mtcars2.csv"))) 23 | expect_true(all.equal(mylist[["mtcars3"]], import("mtcars3.csv"))) 24 | 25 | names(mylist) <- NULL 26 | expect_true(identical(export_list(mylist, file = "mtcars_%s.csv"), paste0("mtcars_", 1:3, ".csv"))) 27 | 28 | names(mylist) <- c("a", "", "c") 29 | expect_error(export_list(mylist), label = "export_list() fails without 'file' argument") 30 | expect_error(export_list(mylist, file = "%.csv"), label = "export_list() fails without missing names") 31 | expect_error(export_list(mylist, file = c("a.csv", "b.csv")), label = "export_list() fails with mismatched argument lengths") 32 | 33 | names(mylist) <- c("a", "a", "c") 34 | expect_error(export_list(mylist, file = "mtcars_%s.csv"), label = "export_list() fails with duplicated data frame names") 35 | expect_error(export_list(mylist, file = c("mtcars1.csv", "mtcars1.csv", "mtcars3.csv")), label = "export_list() fails with duplicated data frame names") 36 | }) 37 | }) 38 | 39 | test_that("archive formats, #415", { 40 | skip_if(getRversion() <= "4.0") 41 | withr::with_tempdir({ 42 | mylist <- list(mtcars3 = mtcars[1:10, ], mtcars2 = mtcars[11:20, ], mtcars1 = mtcars[21:32, ]) 43 | expect_error(export_list(mylist, file = paste0("file_", 1:3, ".csv"), archive = "archive.csv.gz"), "specified but format is not supported") 44 | expect_error(export_list(mylist, file = paste0("file_", 1:3, ".csv"), archive = "archive.csv.bz2"), "specified but format is not supported") 45 | expect_error(export_list(mylist, file = paste0("file_", 1:3, ".csv"), archive = "archive.csv.zip"), NA) 46 | expect_error(export_list(mylist, file = paste0("file_", 1:3, ".csv"), archive = "archive.csv.tar"), NA) 47 | expect_error(export_list(mylist, file = paste0("file_", 1:3, ".csv"), archive = "archive.csv.tar.gz"), NA) 48 | expect_error(export_list(mylist, file = paste0("file_", 1:3, ".csv"), archive = "archive.csv.tar.bz2"), NA) 49 | }) 50 | }) 51 | 52 | test_that("List length of one, #385", { 53 | withr::with_tempdir({ 54 | example1 <- list("iris" = iris) 55 | tempfile <- tempfile(fileext = ".csv") 56 | expect_error(export(example1, tempfile), NA) 57 | tempfile <- tempfile(fileext = ".xlsx") 58 | expect_error(export(example1, tempfile), NA) 59 | expect_equal(readxl::excel_sheets(tempfile), "iris") ## name is retained 60 | tempfile <- tempfile(fileext = ".rds") 61 | expect_error(export(example1, tempfile), NA) 62 | expect_true(is.list(readRDS(tempfile)) && !is.data.frame(readRDS(tempfile))) 63 | }) 64 | }) 65 | 66 | test_that("tar export error for R < 4.0.3", { 67 | skip_if(getRversion() >= "4.0.3") 68 | withr::with_tempdir({ 69 | mylist <- list(mtcars3 = mtcars[1:10, ], mtcars2 = mtcars[11:20, ], mtcars1 = mtcars[21:32, ]) 70 | expect_error(export_list(mylist, file = paste0("file_", 1:3, ".csv"), archive = "archive.csv.tar"), "^Exporting") 71 | }) 72 | }) 73 | -------------------------------------------------------------------------------- /tests/testthat/test_extensions.R: -------------------------------------------------------------------------------- 1 | library("datasets") 2 | skip_on_cran() 3 | 4 | test_that("S3 extension mechanism works for imports", { 5 | withr::with_tempdir({ 6 | write.csv(iris, "iris.custom") 7 | expect_error(import("iris.custom"), "Format not supported") 8 | .import.rio_custom <- function(file, ...) { 9 | read.csv(file, ...) 10 | } 11 | expect_error(.import.rio_custom("iris.custom"), NA) 12 | assign(".import.rio_custom", .import.rio_custom, envir = .GlobalEnv) 13 | expect_true(is.data.frame(import("iris.custom"))) 14 | rm(list = ".import.rio_custom", envir = .GlobalEnv) 15 | }) 16 | }) 17 | 18 | test_that("S3 extension mechanism works for exports", { 19 | withr::with_tempdir({ 20 | expect_error(export(iris, "iris.custom")) 21 | .export.rio_custom <- function(file, x, ...) { 22 | write.csv(x, file, ...) 23 | invisible(file) 24 | } 25 | expect_error(.export.rio_custom("iris.custom", iris), NA) 26 | assign(".export.rio_custom", .export.rio_custom, envir = .GlobalEnv) 27 | expect_true(is.character(export(iris, "iris.custom"))) 28 | rm(list = ".export.rio_custom", envir = .GlobalEnv) 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /tests/testthat/test_format_R.R: -------------------------------------------------------------------------------- 1 | require("datasets") 2 | 3 | test_that("Export / Import to .R dump file", { 4 | withr::with_tempfile("iris_file", fileext = ".R", code = { 5 | export(iris, iris_file) 6 | expect_true(file.exists(iris_file)) 7 | expect_true(is.data.frame(import(iris_file, trust = TRUE))) 8 | 9 | }) 10 | withr::with_tempfile("iris_file", fileext = ".dump", code = { 11 | export(iris, iris_file) 12 | expect_true(file.exists(iris_file)) 13 | expect_true(is.data.frame(import(iris_file, trust = TRUE))) 14 | }) 15 | }) 16 | -------------------------------------------------------------------------------- /tests/testthat/test_format_arff.R: -------------------------------------------------------------------------------- 1 | test_that("Weka (.arff) imports/exports", { 2 | withr::with_tempfile("iris_file", fileext = ".arff", code = { 3 | export(iris, iris_file) 4 | expect_true(file.exists(iris_file)) 5 | expect_true(is.data.frame(import(iris_file))) 6 | }) 7 | }) 8 | -------------------------------------------------------------------------------- /tests/testthat/test_format_csv.R: -------------------------------------------------------------------------------- 1 | require("datasets") 2 | 3 | test_that("Export to CSV", { 4 | withr::with_tempfile("iris_file", fileext = ".csv", code = { 5 | export(iris, iris_file) 6 | expect_true(file.exists(iris_file)) 7 | }) 8 | }) 9 | 10 | test_that("Export (Append) to CSV", { 11 | withr::with_tempfile("iris_file", fileext = ".csv", code = { 12 | export(iris, iris_file) 13 | nlines <- length(readLines(iris_file)) 14 | export(iris, iris_file, append = FALSE) 15 | expect_true(identical(length(readLines(iris_file)), nlines)) 16 | export(iris, iris_file, append = TRUE) 17 | expect_true(identical(length(readLines(iris_file)), (2L * nlines) - 1L)) 18 | }) 19 | }) 20 | 21 | test_that("Import from CSV", { 22 | noheadercsv <- import("../testdata/noheader.csv", header = FALSE) 23 | expect_that(colnames(noheadercsv)[1], equals("V1"), label = "Header is correctly specified") 24 | }) 25 | 26 | test_that("Import from (European-style) CSV with semicolon separator", { 27 | withr::with_tempfile("iris_file", fileext = ".csv", code = { 28 | write.table(iris, iris_file, dec = ",", sep = ";", row.names = FALSE) 29 | expect_true(file.exists(iris_file)) 30 | ## import works (even if column classes are incorrect) 31 | expect_true(is.data.frame(import(iris_file, header = TRUE))) 32 | iris_imported <- import(iris_file, format = ";", header = TRUE) 33 | ## import works with correct, numeric column classes 34 | expect_true(is.data.frame(iris_imported)) 35 | expect_true(is.numeric(iris_imported[["Sepal.Length"]])) 36 | }) 37 | }) 38 | 39 | test_that("Export to and Import from CSV2", { 40 | withr::with_tempfile("iris_file", fileext = ".csv", code = { 41 | export(iris, iris_file, format = "csv2") 42 | expect_true(file.exists(iris_file)) 43 | expect_true(is.data.frame(import(iris_file, format = "csv2"))) 44 | }) 45 | }) 46 | 47 | test_that("Export to and Import from TSV with CSV extension", { 48 | withr::with_tempfile("iris_file", fileext = ".csv", code = { 49 | export(iris, iris_file, format = "tsv") 50 | expect_true(file.exists(iris_file)) 51 | expect_true(ncol(import(iris_file)) == 5L) 52 | expect_true(ncol(import(iris_file, format = "tsv")) == 5L) 53 | expect_true(ncol(import(iris_file, format = "tsv", sep = "\t")) == 5L) 54 | expect_true(ncol(import(iris_file, sep = ",")) == 5L) # use `data.table::fread(sep = "auto")` even if `sep` set explicitly to "," 55 | expect_true(ncol(import(iris_file, format = "csv")) == 5L) 56 | expect_true(ncol(import(iris_file, sep = "auto")) == 5L) 57 | }) 58 | }) 59 | 60 | test_that("fread is deprecated", { 61 | withr::with_tempfile("iris_file", fileext = ".csv", code = { 62 | export(iris, iris_file) 63 | lifecycle::expect_deprecated(import(iris_file, fread = TRUE)) 64 | lifecycle::expect_deprecated(import(iris_file, fread = FALSE)) 65 | }) 66 | }) 67 | 68 | test_that("dat (ambiguous file format) will be attempted #430", { 69 | withr::with_tempfile("iris_file", fileext = ".dat", code = { 70 | readr::write_delim(iris, file = iris_file) 71 | expect_error(suppressMessages(import(iris_file)), NA) 72 | expect_message(z <- import(iris_file)) 73 | ## export is not supported though 74 | expect_error(export(iris, iris_file)) 75 | }) 76 | }) 77 | -------------------------------------------------------------------------------- /tests/testthat/test_format_csvy.R: -------------------------------------------------------------------------------- 1 | test_that("Export to and import from CSVY", { 2 | withr::with_tempfile("iris_file", fileext = ".csvy", code = { 3 | suppressWarnings(export(iris, iris_file)) 4 | expect_true(file.exists(export(iris, iris_file))) 5 | suppressWarnings(d <- import(iris_file)) 6 | expect_true(is.data.frame(d)) 7 | }) 8 | }) 9 | -------------------------------------------------------------------------------- /tests/testthat/test_format_dbf.R: -------------------------------------------------------------------------------- 1 | test_that("Export to and import from XBASE (.dbf)", { 2 | skip_if_not_installed("foreign") 3 | withr::with_tempfile("iris_file", fileext = ".dbf", code = { 4 | export(iris, iris_file) 5 | expect_true(file.exists(iris_file)) 6 | d <- import(iris_file) 7 | expect_true(is.data.frame(d)) 8 | expect_true(!"factor" %in% vapply(d, class, character(1))) 9 | }) 10 | }) 11 | -------------------------------------------------------------------------------- /tests/testthat/test_format_dif.R: -------------------------------------------------------------------------------- 1 | test_that("Import from DIF", { 2 | dd <- import(file.path(system.file("misc", package = "utils"), "exDIF.dif"), transpose = TRUE) 3 | expect_true(is.data.frame(dd)) 4 | }) 5 | -------------------------------------------------------------------------------- /tests/testthat/test_format_dta.R: -------------------------------------------------------------------------------- 1 | test_that("Export to Stata", { 2 | withr::with_tempfile("mtcars_file", fileext = ".dta", code = { 3 | export(mtcars, mtcars_file) 4 | expect_true(file.exists(mtcars_file)) 5 | mtcars3 <- mtcars 6 | names(mtcars3)[1] <- "foo.bar" 7 | expect_error(export(mtcars3, mtcars_file), label = "Export fails on invalid Stata names") 8 | }) 9 | }) 10 | 11 | test_that("Import from Stata (read_dta)", { 12 | withr::with_tempfile("mtcars_file", fileext = ".dta", code = { 13 | export(mtcars, mtcars_file) 14 | expect_true(is.data.frame(import(mtcars_file))) 15 | ## arguments ignored 16 | expect_error(import(mtcars_file, extraneous.argument = TRUE), NA) 17 | expect_silent(import(mtcars_file,extraneous.argument = TRUE)) 18 | }) 19 | }) 20 | 21 | test_that("Import from Stata with extended Haven features (read_dta)", { 22 | withr::with_tempfile("mtcars_file", fileext = ".dta", code = { 23 | export(mtcars, mtcars_file) 24 | 25 | expect_true(is.data.frame(mtcars_wtam <- import(mtcars_file, 26 | col_select = c("wt", "am"), 27 | n_max = 10 28 | ))) 29 | expect_identical(c(10L, 2L), dim(mtcars_wtam)) 30 | expect_identical(c("wt", "am"), names(mtcars_wtam)) 31 | }) 32 | }) 33 | 34 | test_that("haven is deprecated", { 35 | withr::with_tempfile("mtcars_file", fileext = ".dta", code = { 36 | export(mtcars, mtcars_file) 37 | lifecycle::expect_deprecated(import(mtcars_file, haven = TRUE)) 38 | lifecycle::expect_deprecated(import(mtcars_file, haven = FALSE)) 39 | }) 40 | }) 41 | -------------------------------------------------------------------------------- /tests/testthat/test_format_eviews.R: -------------------------------------------------------------------------------- 1 | test_that("Import from EViews", { 2 | skip_if_not_installed(pkg = "hexView") 3 | expect_true(is.data.frame(suppressWarnings(import(hexView::hexViewFile("data4-1.wf1"))))) 4 | }) 5 | -------------------------------------------------------------------------------- /tests/testthat/test_format_external_packages.R: -------------------------------------------------------------------------------- 1 | test_that("External read functions without an import method", { 2 | extensions <- c("bib", "bmp", "gexf", "gnumeric", "jpeg", "jpg", "npy", "png", "sss", "sdmx", "tiff") 3 | for (ext in extensions) { 4 | withr::with_tempfile("dummyfile", fileext = paste0(".", ext), code = { 5 | file.create(dummyfile) 6 | expect_error(import(dummyfile)) 7 | }) 8 | } 9 | }) 10 | 11 | test_that("import method exported by an external package", { 12 | extensions <- c("bean", "beancount", "ledger", "hledger") 13 | for (ext in extensions) { 14 | withr::with_tempfile("dummyfile", fileext = paste0(".", ext), code = { 15 | file.create(dummyfile) 16 | expect_error(import(dummyfile)) 17 | }) 18 | } 19 | }) 20 | -------------------------------------------------------------------------------- /tests/testthat/test_format_feather.R: -------------------------------------------------------------------------------- 1 | skip_if_not_installed("arrow") 2 | 3 | test_that("Export to and import from feather", { 4 | withr::with_tempfile("iris_file", fileext = ".feather", code = { 5 | export(iris, iris_file) 6 | expect_true(file.exists(iris_file)) 7 | expect_true(is.data.frame(import(iris_file))) 8 | }) 9 | }) 10 | -------------------------------------------------------------------------------- /tests/testthat/test_format_fortran.R: -------------------------------------------------------------------------------- 1 | test_that("Import from Fortran", { 2 | ## no fixed file extension 3 | withr::with_tempfile("fortran_file", code = { 4 | cat(file = fortran_file, "123456", "987654", sep = "\n") 5 | expect_true(is.data.frame(import(fortran_file, format = "fortran", style = c("F2.1","F2.0","I2")))) 6 | }) 7 | }) 8 | -------------------------------------------------------------------------------- /tests/testthat/test_format_fst.R: -------------------------------------------------------------------------------- 1 | skip_if_not_installed(pkg="fst") 2 | 3 | test_that("Export to and import from fst", { 4 | withr::with_tempfile("iris_file", fileext = ".fst", code = { 5 | export(iris, iris_file) 6 | expect_true(file.exists(iris_file)) 7 | expect_true(is.data.frame(import(iris_file))) 8 | }) 9 | }) 10 | -------------------------------------------------------------------------------- /tests/testthat/test_format_fwf.R: -------------------------------------------------------------------------------- 1 | simport <- function(...) { 2 | suppressWarnings(import(...)) 3 | } 4 | 5 | test_that("Export to and import from FWF .fwf", { 6 | withr::with_tempfile("iris_file", fileext = ".fwf", code = { 7 | export(iris, iris_file) 8 | expect_true(file.exists(iris_file)) 9 | expect_true(is.data.frame(simport(iris_file, widths = c(3, 3, 3, 3, 1)))) 10 | expect_true(is.data.frame(simport(iris_file, widths = list(c(3, 3, 3, 3, 1))))) 11 | expect_true(is.data.frame(simport(iris_file, widths = c(3, 3, 3, 3, 1), col.names = names(iris)))) 12 | ## negative column widths 13 | expect_true(is.data.frame(simport(iris_file, widths = c(-3, 3, 3, 3, 1)))) 14 | ##use col_position instead 15 | expect_error(x <- import(iris_file, col_position = readr::fwf_widths(c(1, 3, 3, 3, 1), col_names = names(iris))), NA) 16 | expect_equal(x[1,1, drop = TRUE], 5) 17 | }) 18 | }) 19 | 20 | test_that("Export to and import from FWF .txt", { 21 | withr::with_tempfile("iris_file", fileext = ".txt", code = { 22 | export(iris, iris_file) 23 | expect_true(file.exists(iris_file)) 24 | expect_true(is.data.frame(simport(iris_file, widths = c(3, 3, 3, 3, 1), format = "fwf"))) 25 | }) 26 | }) 27 | 28 | test_that("Deprecation of `width` and `col.names`", { 29 | withr::with_tempfile("iris_file", fileext = ".fwf", code = { 30 | export(iris, iris_file) 31 | lifecycle::expect_deprecated(import(iris_file, widths = c(-3, 3, 3, 3, 1))) 32 | lifecycle::expect_deprecated(import(iris_file, col.names = names(iris))) 33 | }) 34 | }) 35 | -------------------------------------------------------------------------------- /tests/testthat/test_format_html.R: -------------------------------------------------------------------------------- 1 | skip_if_not_installed("xml2") 2 | 3 | test_html <- function(breaker = "&") { 4 | mtcars2 <- mtcars 5 | colnames(mtcars2)[1] <- paste0("mp", breaker, breaker, "g") 6 | mtcars2[1,1] <- paste0("mp", breaker, breaker, "g") 7 | withr::with_tempfile("mtcars_file", fileext = ".html", code = { 8 | expect_error(x <- rio::export(mtcars2, mtcars_file), NA) 9 | temp_df <- rio::import(x) 10 | expect_equal(colnames(temp_df)[1], paste0("mp", breaker, breaker, "g")) 11 | expect_equal(temp_df[1,1], paste0("mp", breaker, breaker, "g")) 12 | }) 13 | } 14 | 15 | test_that("Export to and import from HTML", { 16 | withr::with_tempfile("iris_file", fileext = ".html", code = { 17 | export(iris, iris_file) 18 | expect_true(file.exists(iris_file)) 19 | expect_true(is.data.frame(import(iris_file)), label = "import from single-table html works") 20 | }) 21 | }) 22 | 23 | test_that("Export to HTML with ampersands",{ 24 | withr::with_tempfile("iris_file", fileext = ".html", code = { 25 | 26 | iris$`R & D` <- paste(sample(letters,nrow(iris), replace = TRUE), 27 | "&", 28 | sample(LETTERS,nrow(iris), replace = TRUE)) 29 | export(iris, iris_file) 30 | expect_true(file.exists(iris_file), 31 | label = "export to html with ampersands works") 32 | }) 33 | }) 34 | 35 | test_that("Import from HTML", { 36 | f <- "../testdata/twotables.html" 37 | expect_true(all(dim(import(f, which = 1)) == c(32, 11)), label = "import from two-table html works (which = 1)") 38 | expect_true(all(dim(import(f, which = 2)) == c(150, 5)), label = "import from two-table html works (which = 2)") 39 | }) 40 | 41 | test_that("Import from HTML with multiple tbody elements", { 42 | expect_true(is.data.frame(import("../testdata/two-tbody.html")), label="import with two tbody elements in a single html table works") 43 | expect_true(is.data.frame(import("../testdata/br-in-header.html")), label="import with an empty header cell in an html table works") 44 | expect_true(is.data.frame(import("../testdata/br-in-td.html")), label="import with an empty data cell in a single html table works") 45 | 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") 46 | }) 47 | 48 | test_that("html with &, >, ', \", >, <", { 49 | ## test all 50 | useless <- lapply(c("&", "\"", "'", "<", ">"), test_html) 51 | }) 52 | -------------------------------------------------------------------------------- /tests/testthat/test_format_json.R: -------------------------------------------------------------------------------- 1 | skip_if_not_installed("jsonlite") 2 | 3 | test_that("Export to and import from JSON", { 4 | withr::with_tempfile("iris_file", fileext = ".json", code = { 5 | export(iris, iris_file) 6 | expect_true(file.exists(iris_file)) 7 | expect_true(is.data.frame(import(iris_file))) 8 | }) 9 | }) 10 | 11 | test_that("Export to JSON (non-data frame)", { 12 | withr::with_tempfile("list_file", fileext = ".json", code = { 13 | export(list(1:10, letters), list_file) 14 | expect_true(file.exists(list_file)) 15 | expect_true(inherits(import(list_file), "list")) 16 | expect_false(inherits(import(list_file), "data.frame")) 17 | expect_true(length(import(list_file)) == 2L) 18 | }) 19 | }) 20 | 21 | test_that("utf-8", { 22 | content <- c("\"", "\u010d", "\u0161", "\u00c4", "\u5b57", "\u30a2", "\u30a2\u30e0\u30ed") 23 | x <- data.frame(col = content) 24 | withr::with_tempfile("tempjson", fileext = ".json", code = { 25 | y <- import(export(x, tempjson)) 26 | testthat::expect_equal(content, y$col) 27 | }) 28 | }) 29 | -------------------------------------------------------------------------------- /tests/testthat/test_format_matlab.R: -------------------------------------------------------------------------------- 1 | skip_if_not_installed("rmatio") 2 | 3 | test_that("Export to and import from matlab", { 4 | skip("failing mysteriously") 5 | withr::with_tempfile("iris_file", fileext = ".matlab", code = { 6 | export(iris, iris_file) 7 | expect_true(file.exists(iris_file)) 8 | expect_true(is.data.frame(import(iris_file))) 9 | expect_true(identical(dim(import(iris_file)), dim(iris))) 10 | 11 | }) 12 | }) 13 | -------------------------------------------------------------------------------- /tests/testthat/test_format_mtp.R: -------------------------------------------------------------------------------- 1 | ##test_that("Import from Minitab", {}) 2 | -------------------------------------------------------------------------------- /tests/testthat/test_format_ods.R: -------------------------------------------------------------------------------- 1 | skip_if_not_installed("readODS") 2 | 3 | test_that("Import from ODS", { 4 | ods0 <- import("../testdata/mtcars.ods") 5 | expect_error(ods <- import("../testdata/mtcars.ods", 6 | sheet = 1, col_names = TRUE, 7 | invalid_argument = 42), NA) 8 | expect_identical(ods0, ods, label = "ODS import ignored arguments don't affect output") 9 | expect_true(is.data.frame(ods), label = "ODS import returns data.frame") 10 | expect_true(identical(names(mtcars), names(ods)), label = "ODS import returns correct names") 11 | expect_true(identical(dim(mtcars), dim(ods)), label = "ODS import returns correct dimensions") 12 | expect_equivalent(ods, mtcars, label = "ODS import returns correct values") 13 | }) 14 | 15 | test_that("Export to and import from ODS", { 16 | withr::with_tempfile("iris_file", fileext = ".ods", code = { 17 | export(iris, iris_file) 18 | expect_true(file.exists(iris_file)) 19 | expect_true(is.data.frame(import(iris_file))) 20 | }) 21 | }) 22 | 23 | test_that("... correctly passed #318", { 24 | withr::with_tempfile("mtcars_file", fileext = ".ods", code = { 25 | export(iris, mtcars_file, sheet = "mtcars") 26 | expect_equal(readODS::list_ods_sheets(mtcars_file), "mtcars") 27 | }) 28 | }) 29 | 30 | test_that("Export and Import FODS", { 31 | withr::with_tempfile("fods_file", fileext = ".fods", code = { 32 | export(iris, fods_file) 33 | expect_true(file.exists(fods_file)) 34 | expect_true(is.data.frame(import(fods_file))) 35 | export(iris, fods_file, sheet = "mtcars") 36 | expect_equal(readODS::list_fods_sheets(fods_file), "mtcars") 37 | expect_error(y <- import(fods_file), NA) 38 | expect_true(is.data.frame(y)) 39 | 40 | }) 41 | }) 42 | 43 | test_that("Export list of data frames", { 44 | withr::with_tempfile("ods_files", fileext = c(".ods", ".fods"), code = { 45 | dfs <- list("cars" = mtcars, "flowers" = iris) 46 | expect_error(export(dfs, ods_files[1]), NA) 47 | expect_error(export(dfs, ods_files[2]), NA) 48 | expect_equal(import(ods_files[1], which = "flowers"), import(ods_files[2], which = "flowers")) 49 | }) 50 | }) 51 | -------------------------------------------------------------------------------- /tests/testthat/test_format_parquet.R: -------------------------------------------------------------------------------- 1 | skip_if_not_installed("nanoparquet") 2 | skip_on_os("mac") ## apache/arrow#40991 3 | 4 | test_that("Export to and import from parquet", { 5 | withr::with_tempfile("iris_path", fileext = ".parquet", code = { 6 | export(iris, iris_path) 7 | expect_true(file.exists(iris_path)) 8 | expect_true(is.data.frame(import(iris_path))) 9 | }) 10 | }) 11 | -------------------------------------------------------------------------------- /tests/testthat/test_format_psv.R: -------------------------------------------------------------------------------- 1 | test_that("Export to and import from PSV", { 2 | withr::with_tempfile("iris_file", fileext = ".psv", code = { 3 | export(iris, iris_file) 4 | expect_true(file.exists(iris_file)) 5 | expect_true(is.data.frame(import(iris_file))) 6 | }) 7 | }) 8 | 9 | 10 | test_that("fread is deprecated", { 11 | withr::with_tempfile("iris_file", fileext = ".psv", code = { 12 | export(iris, iris_file) 13 | lifecycle::expect_deprecated(import(iris_file, fread = TRUE)) 14 | lifecycle::expect_deprecated(import(iris_file, fread = FALSE)) 15 | }) 16 | 17 | }) 18 | -------------------------------------------------------------------------------- /tests/testthat/test_format_pzfx.R: -------------------------------------------------------------------------------- 1 | skip_if_not_installed("pzfx") 2 | 3 | test_that("Export to and import from pzfx", { 4 | ## pzfx support only numeric data 5 | iris_numeric <- iris 6 | iris_numeric$Species <- as.numeric(iris_numeric$Species) 7 | withr::with_tempfile("iris_file", fileext = ".pzfx", code = { 8 | export(iris_numeric, iris_file) 9 | expect_true(file.exists(iris_file)) 10 | expect_true(is.data.frame(import(iris_file))) 11 | ## Note that the dim test is only true as long as the data are exported with 12 | ## write_pzfx(..., row_names=FALSE) which is the default in the export 13 | ## method, but it is not default in pzfx::write_pzfx() 14 | expect_true(identical(dim(import(iris_file)), dim(iris_numeric))) 15 | expect_true(identical(dim(import(iris_file, which = "Data 1")), dim(iris_numeric))) 16 | expect_true(identical(dim(import(iris_file, table = "Data 1")), dim(iris_numeric))) 17 | }) 18 | }) 19 | -------------------------------------------------------------------------------- /tests/testthat/test_format_qs.R: -------------------------------------------------------------------------------- 1 | skip_if_not_installed("qs") 2 | 3 | test_that("Export to and import from qs", { 4 | withr::with_tempfile("iris_file", fileext = ".qs", code = { 5 | export(iris, iris_file) 6 | expect_true(file.exists(iris_file)) 7 | expect_true(is.data.frame(import(iris_file))) 8 | }) 9 | }) 10 | -------------------------------------------------------------------------------- /tests/testthat/test_format_rdata.R: -------------------------------------------------------------------------------- 1 | test_that("Export to and import from Rdata", { 2 | withr::with_tempfile("iris_file", fileext = ".Rdata", code = { 3 | ## data frame 4 | export(iris, iris_file) 5 | expect_true(file.exists(iris_file)) 6 | expect_true(is.data.frame(import(iris_file, trust = TRUE))) 7 | expect_true(is.data.frame(import(iris_file, which = 1, trust = TRUE))) 8 | }) 9 | withr::with_tempfile("iris_file", fileext = ".Rdata", code = { 10 | ## environment 11 | e <- new.env() 12 | e$iris <- iris 13 | export(e, iris_file) 14 | expect_true(file.exists(iris_file)) 15 | expect_true(is.data.frame(import(iris_file, trust = TRUE))) 16 | expect_true(is.data.frame(import(iris_file, which = 1, trust = TRUE))) 17 | }) 18 | withr::with_tempfile("iris_file", fileext = ".Rdata", code = { 19 | ## character 20 | export("iris", iris_file) 21 | expect_true(file.exists(iris_file)) 22 | expect_true(is.data.frame(import(iris_file, trust = TRUE))) 23 | expect_true(is.data.frame(import(iris_file, which = 1, trust = TRUE))) 24 | }) 25 | withr::with_tempfile("iris_file", fileext = ".Rdata", code = { 26 | ## expect error otherwise 27 | expect_error(export(iris$Species, iris_file)) 28 | }) 29 | }) 30 | 31 | test_that("Export to and import from rda", { 32 | withr::with_tempfile("iris_file", fileext = ".rda", code = { 33 | ## data frame 34 | export(iris, iris_file) 35 | expect_true(file.exists(iris_file)) 36 | expect_true(is.data.frame(import(iris_file, trust = TRUE))) 37 | expect_true(is.data.frame(import(iris_file, which = 1, trust = TRUE))) 38 | }) 39 | withr::with_tempfile("iris_file", fileext = ".rda", code = { 40 | ## environment 41 | e <- new.env() 42 | e$iris <- iris 43 | export(e, iris_file) 44 | expect_true(file.exists(iris_file)) 45 | expect_true(is.data.frame(import(iris_file, trust = TRUE))) 46 | expect_true(is.data.frame(import(iris_file, which = 1, trust = TRUE))) 47 | }) 48 | withr::with_tempfile("iris_file", fileext = ".rda", code = { 49 | ## character 50 | export("iris", iris_file) 51 | expect_true(file.exists(iris_file)) 52 | expect_true(is.data.frame(import(iris_file, trust = TRUE))) 53 | expect_true(is.data.frame(import(iris_file, which = 1, trust = TRUE))) 54 | }) 55 | withr::with_tempfile("iris_file", fileext = ".rda", code = { 56 | ## expect error otherwise 57 | expect_error(export(iris$Species, iris_file)) 58 | }) 59 | }) 60 | -------------------------------------------------------------------------------- /tests/testthat/test_format_rds.R: -------------------------------------------------------------------------------- 1 | test_that("Export to and import from rds", { 2 | withr::with_tempfile("iris_file", fileext = ".rds", code = { 3 | export(iris, iris_file) 4 | expect_true(file.exists(iris_file)) 5 | expect_true(is.data.frame(import(iris_file, trust = TRUE))) 6 | }) 7 | }) 8 | 9 | test_that("Export to rds (non-data frame)", { 10 | withr::with_tempfile("list_file", fileext = ".rds", code = { 11 | export(list(1:10, letters), list_file) 12 | expect_true(file.exists(list_file)) 13 | expect_true(inherits(import(list_file, trust = TRUE), "list")) 14 | expect_true(length(import(list_file, trust = TRUE)) == 2L) 15 | }) 16 | }) 17 | -------------------------------------------------------------------------------- /tests/testthat/test_format_rec.R: -------------------------------------------------------------------------------- 1 | #test_that("Import from Epiinfo", {}) 2 | -------------------------------------------------------------------------------- /tests/testthat/test_format_sas.R: -------------------------------------------------------------------------------- 1 | test_that("Export to and import from SAS (.xpt)", { 2 | withr::with_tempfile("mtcars_file", fileext = ".xpt", code = { 3 | export(mtcars, mtcars_file) 4 | expect_true(file.exists(mtcars_file)) 5 | expect_true(is.data.frame(import(mtcars_file))) 6 | }) 7 | }) 8 | 9 | test_that("Export SAS (.sas7bdat)", { 10 | withr::with_tempfile("mtcars_file", fileext = ".sas7bdat", code = { 11 | suppressWarnings(export(mtcars, mtcars_file)) 12 | expect_true(file.exists(mtcars_file)) 13 | }) 14 | }) 15 | -------------------------------------------------------------------------------- /tests/testthat/test_format_sav.R: -------------------------------------------------------------------------------- 1 | 2 | test_that("Export to SPSS (.sav)", { 3 | mtcars2 <- mtcars 4 | ## label and value labels 5 | mtcars2[["cyl"]] <- factor(mtcars2[["cyl"]], c(4, 6, 8), c("four", "six", "eight")) 6 | attr(mtcars2[["cyl"]], "label") <- "cylinders" 7 | ## value labels only 8 | mtcars2[["am"]] <- factor(mtcars2[["am"]], c(0, 1), c("automatic", "manual")) 9 | ## variable label only 10 | attr(mtcars2[["mpg"]], "label") <- "miles per gallon" 11 | withr::with_tempfile("mtcars_file", fileext = ".sav", code = { 12 | export(mtcars2, mtcars_file) 13 | expect_true(file.exists(mtcars_file)) 14 | expect_true(d <- is.data.frame(import(mtcars_file))) 15 | expect_true(!"labelled" %in% unlist(lapply(d, class))) 16 | ##Variable label and value labels preserved on SPSS (.sav) roundtrip 17 | d <- import(mtcars_file) 18 | a_cyl <- attributes(d[["cyl"]]) 19 | expect_true("label" %in% names(a_cyl)) 20 | expect_true("labels" %in% names(a_cyl)) 21 | expect_true(identical(a_cyl[["label"]], "cylinders")) 22 | expect_true(identical(a_cyl[["labels"]], stats::setNames(c(1.0, 2.0, 3.0), c("four", "six", "eight")))) 23 | a_am <- attributes(d[["am"]]) 24 | expect_true("labels" %in% names(a_am)) 25 | expect_true(identical(a_am[["labels"]], stats::setNames(c(1.0, 2.0), c("automatic", "manual")))) 26 | 27 | a_mpg <- attributes(d[["mpg"]]) 28 | expect_true("label" %in% names(a_mpg)) 29 | expect_true(identical(a_mpg[["label"]], "miles per gallon")) 30 | ##haven is deprecated" 31 | lifecycle::expect_deprecated(import(mtcars_file, haven = TRUE)) 32 | lifecycle::expect_deprecated(import(mtcars_file, haven = FALSE)) 33 | }) 34 | }) 35 | 36 | test_that("Export to SPSS compressed (.zsav)", { 37 | mtcars2 <- mtcars 38 | ## label and value labels 39 | mtcars2[["cyl"]] <- factor(mtcars2[["cyl"]], c(4, 6, 8), c("four", "six", "eight")) 40 | attr(mtcars2[["cyl"]], "label") <- "cylinders" 41 | ## value labels only 42 | mtcars2[["am"]] <- factor(mtcars2[["am"]], c(0, 1), c("automatic", "manual")) 43 | ## variable label only 44 | attr(mtcars2[["mpg"]], "label") <- "miles per gallon" 45 | withr::with_tempfile("mtcars_file", fileext = ".zsav", code = { 46 | export(mtcars2, mtcars_file) 47 | expect_true(file.exists(mtcars_file)) 48 | expect_true(d <- is.data.frame(import(mtcars_file))) 49 | expect_true(!"labelled" %in% unlist(lapply(d, class))) 50 | d <- import(mtcars_file) 51 | a_cyl <- attributes(d[["cyl"]]) 52 | expect_true("label" %in% names(a_cyl)) 53 | expect_true("labels" %in% names(a_cyl)) 54 | expect_true(identical(a_cyl[["label"]], "cylinders")) 55 | expect_true(identical(a_cyl[["labels"]], stats::setNames(c(1.0, 2.0, 3.0), c("four", "six", "eight")))) 56 | 57 | a_am <- attributes(d[["am"]]) 58 | expect_true("labels" %in% names(a_am)) 59 | expect_true(identical(a_am[["labels"]], stats::setNames(c(1.0, 2.0), c("automatic", "manual")))) 60 | 61 | a_mpg <- attributes(d[["mpg"]]) 62 | expect_true("label" %in% names(a_mpg)) 63 | expect_true(identical(a_mpg[["label"]], "miles per gallon")) 64 | }) 65 | }) 66 | -------------------------------------------------------------------------------- /tests/testthat/test_format_syd.R: -------------------------------------------------------------------------------- 1 | skip_if_not_installed("foreign") 2 | 3 | test_that("Import from Systat", { 4 | expect_true(is.data.frame(import(system.file("files/Iris.syd", package = "foreign")[1]))) 5 | }) 6 | -------------------------------------------------------------------------------- /tests/testthat/test_format_tsv.R: -------------------------------------------------------------------------------- 1 | test_that("Export to and import from TSV", { 2 | withr::with_tempfile("iris_file", fileext = ".tsv", code = { 3 | export(iris, iris_file) 4 | expect_true(file.exists(iris_file)) 5 | expect_true(is.data.frame(import(iris_file))) 6 | }) 7 | }) 8 | 9 | test_that("fread is deprecated", { 10 | withr::with_tempfile("iris_file", fileext = ".tsv", code = { 11 | export(iris, iris_file) 12 | lifecycle::expect_deprecated(import(iris_file, fread = TRUE)) 13 | lifecycle::expect_deprecated(import(iris_file, fread = FALSE)) 14 | }) 15 | }) 16 | -------------------------------------------------------------------------------- /tests/testthat/test_format_xls.R: -------------------------------------------------------------------------------- 1 | test_that("Export to Excel (.xlsx)", { 2 | withr::with_tempfile("iris_file", fileext = ".xlsx", code = { 3 | export(iris, iris_file) 4 | expect_true(file.exists(iris_file)) 5 | expect_true(is.data.frame(import(iris_file))) 6 | expect_true(is.data.frame(import(iris_file, sheet = 1))) 7 | expect_true(is.data.frame(import(iris_file, which = 1))) 8 | expect_true(nrow(import(iris_file, n_max = 42)) == 42) 9 | }) 10 | }) 11 | 12 | test_that("Expert to Excel (.xlsx) a list", { 13 | withr::with_tempfile("tempxlsx", fileext = ".xlsx", code = { 14 | export(list( 15 | mtcars3 = mtcars[1:10, ], 16 | mtcars2 = mtcars[11:20, ], 17 | mtcars1 = mtcars[21:32, ] 18 | ), tempxlsx) 19 | expect_equal(readxl::excel_sheets(tempxlsx), c("mtcars3", "mtcars2", "mtcars1")) 20 | }) 21 | }) 22 | 23 | test_that("Is `sheet` passed?", { 24 | withr::with_tempfile("tempxlsx", fileext = ".xlsx", code = { 25 | export(list( 26 | mtcars3 = mtcars[1:10, ], 27 | mtcars2 = mtcars[11:20, ], 28 | mtcars1 = mtcars[21:32, ] 29 | ), tempxlsx) 30 | expect_equal(readxl::excel_sheets(tempxlsx), c("mtcars3", "mtcars2", "mtcars1")) 31 | content <- import(tempxlsx, sheet = "mtcars2") 32 | expect_equal(content$mpg, mtcars[11:20, ]$mpg) 33 | content <- import(tempxlsx, which = 2) 34 | expect_equal(content$mpg, mtcars[11:20, ]$mpg) 35 | }) 36 | }) 37 | 38 | 39 | test_that("readxl is deprecated", { 40 | withr::with_tempfile("iris_file", fileext = ".xlsx", code = { 41 | export(iris, iris_file) 42 | lifecycle::expect_deprecated(import(iris_file, readxl = TRUE)) 43 | lifecycle::expect_deprecated(import(iris_file, readxl = FALSE)) 44 | }) 45 | }) 46 | 47 | test_that("Import from Excel (.xls)", { 48 | expect_true(is.data.frame(import("../testdata/iris.xls"))) 49 | expect_true(is.data.frame(import("../testdata/iris.xls", sheet = 1))) 50 | expect_true(is.data.frame(import("../testdata/iris.xls", which = 1))) 51 | }) 52 | -------------------------------------------------------------------------------- /tests/testthat/test_format_xml.R: -------------------------------------------------------------------------------- 1 | skip_if_not_installed("xml2") 2 | 3 | test_xml <- function(breaker = "&") { 4 | mtcars2 <- mtcars 5 | colnames(mtcars2)[1] <- paste0("mp", breaker, breaker, "g") 6 | mtcars2[1,1] <- paste0("mp", breaker, breaker, "g") 7 | withr::with_tempfile("mtcars_file", fileext = ".xml", code = { 8 | expect_error(x <- rio::export(mtcars2, mtcars_file), NA) 9 | temp_df <- rio::import(mtcars_file) 10 | expect_equal(colnames(temp_df)[1], paste0("mp..g")) 11 | expect_equal(temp_df[1,1], paste0("mp", breaker, breaker, "g")) 12 | }) 13 | } 14 | 15 | test_that("Export to and import from XML", { 16 | withr::with_tempfile("iris_file", fileext = ".xml", code = { 17 | export(iris, iris_file) 18 | expect_true(file.exists(iris_file)) 19 | expect_true(is.data.frame(import(iris_file))) 20 | }) 21 | }) 22 | 23 | test_that("Export to XML with &, >, ', \", >, <",{ 24 | ## test all 25 | useless <- lapply(c("&", "\"", "'", "<", ">"), test_xml) 26 | }) 27 | -------------------------------------------------------------------------------- /tests/testthat/test_format_yml.R: -------------------------------------------------------------------------------- 1 | skip_if_not_installed("yaml") 2 | 3 | test_that("Export to and import from YAML", { 4 | withr::with_tempfile("iris_file", fileext = ".yaml", code = { 5 | export(iris, iris_file) 6 | expect_true(file.exists(iris_file)) 7 | expect_true(is.data.frame(import(iris_file))) 8 | expect_identical(import(iris_file)[, 1:4], iris[, 1:4]) 9 | expect_identical(import(iris_file)$Species, as.character(iris$Species)) 10 | }) 11 | }) 12 | 13 | test_that("utf-8", { 14 | skip_if(getRversion() <= "4.2") 15 | withr::with_tempfile("tempyaml", fileext = ".yaml", code = { 16 | content <- c("\"", "\u010d", "\u0161", "\u00c4", "\u5b57", "\u30a2", "\u30a2\u30e0\u30ed") 17 | x <- data.frame(col = content) 18 | y <- import(export(x, tempyaml)) 19 | testthat::expect_equal(content, y$col) 20 | }) 21 | }) 22 | -------------------------------------------------------------------------------- /tests/testthat/test_gather_attrs.R: -------------------------------------------------------------------------------- 1 | e <- try(import("http://www.stata-press.com/data/r13/auto.dta")) 2 | 3 | if (!inherits(e, "try-error")) { 4 | 5 | g <- gather_attrs(e) 6 | test_that("Gather attrs from Stata", { 7 | expect_true(length(attributes(e[[1]])) >= 1) 8 | expect_true(length(attributes(g[[1]])) == 0) 9 | expect_true(length(attributes(e)) == 5) 10 | expect_true(length(attributes(g)) == 8) 11 | expect_true("label" %in% names(attributes(e[[1]]))) 12 | expect_true(!"label" %in% names(attributes(g[[1]]))) 13 | expect_true("label" %in% names(attributes(g))) 14 | expect_true("labels" %in% names(attributes(g))) 15 | expect_true("format.stata" %in% names(attributes(g))) 16 | expect_true(!"format.stata" %in% names(attributes(g[[1]]))) 17 | }) 18 | 19 | test_that("Spread attrs from Stata", { 20 | s <- spread_attrs(g) 21 | # df-level attributes 22 | expect_true("label" %in% names(attributes(s))) 23 | expect_true("notes" %in% names(attributes(s))) 24 | # spread attributes 25 | expect_true("format.stata" %in% names(attributes(s[[1]]))) 26 | expect_true(!"format.stata" %in% names(attributes(s))) 27 | expect_true("label" %in% names(attributes(s[[1]]))) 28 | expect_true(!"labels" %in% names(attributes(s))) 29 | }) 30 | 31 | test_that("Gather empty attributes", { 32 | require("datasets") 33 | g <- gather_attrs(iris) 34 | expect_true(length(attributes(iris[[1]])) == 0) 35 | expect_true(length(attributes(g[[1]])) == 0) 36 | expect_true(length(attributes(iris)) == 3) 37 | expect_true(length(attributes(g)) == 3) 38 | }) 39 | 40 | test_that("gather_attrs() fails on non-data frame", { 41 | expect_error(gather_attrs(letters)) 42 | }) 43 | 44 | test_that("spread_attrs() fails on non-data frame", { 45 | expect_error(spread_attrs(letters)) 46 | }) 47 | } 48 | -------------------------------------------------------------------------------- /tests/testthat/test_guess.R: -------------------------------------------------------------------------------- 1 | test_that("File extension converted correctly", { 2 | expect_that(get_ext("hello.csv"), equals("csv")) 3 | expect_that(get_ext("hello.CSV"), equals("csv")) 4 | expect_that(get_ext("hello.sav.CSV"), equals("csv")) 5 | expect_that(get_ext("clipboard"), equals("clipboard")) 6 | expect_error(get_ext(1L)) 7 | }) 8 | 9 | test_that("Format converted correctly", { 10 | expect_that(.standardize_format(","), equals("csv")) 11 | expect_that(.standardize_format(";"), equals("csv2")) 12 | expect_that(.standardize_format("|"), equals("psv")) 13 | expect_that(.standardize_format("\t"), equals("tsv")) 14 | expect_that(.standardize_format("excel"), equals("xlsx")) 15 | expect_that(.standardize_format("stata"), equals("dta")) 16 | expect_that(.standardize_format("spss"), equals("sav")) 17 | expect_that(.standardize_format("sas"), equals("sas7bdat")) 18 | }) 19 | 20 | test_that("Export without file specified", { 21 | withr::with_tempdir(code = { 22 | project_path <- getwd() 23 | export(iris, format = "csv") 24 | expect_true(file.exists(file.path(project_path, "iris.csv"))) 25 | }) 26 | }) 27 | 28 | test_that(".check_pkg_availability", { 29 | expect_error(.check_pkg_availability("nonexistingpkg1233222"), "Suggested package `nonexisting") 30 | expect_error(.check_pkg_availability("rio"), NA) 31 | }) 32 | -------------------------------------------------------------------------------- /tests/testthat/test_identical.R: -------------------------------------------------------------------------------- 1 | test_that("Data identical (text formats)", { 2 | withr::with_tempdir(code = { 3 | expect_equivalent(import(export(mtcars, "mtcars.txt")), mtcars) 4 | expect_equivalent(import(export(mtcars, "mtcars.csv")), mtcars) 5 | expect_equivalent(import(export(mtcars, "mtcars.tsv")), mtcars) 6 | }) 7 | }) 8 | 9 | test_that("Data identical (R formats)", { 10 | withr::with_tempdir(code = { 11 | expect_equivalent(import(export(mtcars, "mtcars.rds"), trust = TRUE), mtcars) 12 | expect_equivalent(import(export(mtcars, "mtcars.R"), trust = TRUE), mtcars) 13 | expect_equivalent(import(export(mtcars, "mtcars.RData"), trust = TRUE), mtcars) 14 | expect_equivalent(import(export(mtcars, "mtcars.R", format = "dump"), trust = TRUE), mtcars) 15 | }) 16 | }) 17 | 18 | test_that("Data identical (R formats), feather", { 19 | skip_if_not_installed("arrow") 20 | withr::with_tempdir(code = { 21 | expect_equivalent(import(export(mtcars, "mtcars.feather")), mtcars) 22 | }) 23 | }) 24 | 25 | test_that("Data identical (haven formats)", { 26 | withr::with_tempdir(code = { 27 | expect_equivalent(import(export(mtcars, "mtcars.dta")), mtcars) 28 | expect_equivalent(import(export(mtcars, "mtcars.sav")), mtcars) 29 | }) 30 | }) 31 | 32 | test_that("Data identical (Excel formats)", { 33 | withr::with_tempdir(code = { 34 | expect_equivalent(import(export(mtcars, "mtcars.xlsx")), mtcars) 35 | }) 36 | }) 37 | 38 | test_that("Data identical (other formats)", { 39 | skip_if_not_installed("xml2") 40 | skip_if_not_installed("jsonlite") 41 | withr::with_tempdir(code = { 42 | expect_equivalent(import(export(mtcars, "mtcars.dbf")), mtcars) 43 | expect_equivalent(import(export(mtcars, "mtcars.json")), mtcars) 44 | expect_equivalent(import(export(mtcars, "mtcars.arff")), mtcars) 45 | expect_equivalent(import(export(mtcars, "mtcars.xml")), mtcars) 46 | }) 47 | }) 48 | 49 | test_that("Data identical (optional arguments)", { 50 | withr::with_tempdir(code = { 51 | ##expect_equivalent(import(export(mtcars, "mtcars.csv", format = "csv2"), format = "csv2"), mtcars) 52 | expect_equivalent(import(export(mtcars, "mtcars.csv"), nrows = 4), mtcars[1:4,]) 53 | expect_equivalent(import(export(mtcars, "mtcars.csv", format = "tsv"), format = "tsv"), mtcars) 54 | expect_true(all.equal(import(export(mtcars, "mtcars", format = "csv"), format = "csv"), mtcars, check.attributes = FALSE)) 55 | }) 56 | }) 57 | -------------------------------------------------------------------------------- /tests/testthat/test_mapping.R: -------------------------------------------------------------------------------- 1 | test_that("mapping; both base and tidy conventions work", { 2 | withr::with_tempfile("tempxlsx", fileext = ".xlsx", code = { 3 | export(list("mtcars" = mtcars, "iris" = iris), tempxlsx) 4 | expect_error(y <- import(tempxlsx, n_max = 42, sheet = "iris"), NA) 5 | expect_equal(nrow(y), 42) 6 | expect_error(y2 <- import(tempxlsx, n_max = 42, which = "iris"), NA) 7 | expect_equal(nrow(y2), 42) 8 | expect_equal(y, y2) 9 | expect_error(y <- import(tempxlsx, n_max = 42, col_names = FALSE, which = 2), NA) 10 | expect_equal(nrow(y), 42) 11 | expect_error(y2 <- import(tempxlsx, n_max = 42, header = FALSE, which = 2), NA) 12 | expect_equal(y, y2) 13 | }) 14 | }) 15 | 16 | test_that("Unused arguments are by default ignored silently", { 17 | withr::with_tempfile("tempxlsx", fileext = ".xlsx", code = { 18 | export(list("mtcars" = mtcars, "iris" = iris), tempxlsx) 19 | expect_error(y <- import(tempxlsx, n_max = 42, whatever = TRUE, sheet = 2), NA) 20 | }) 21 | }) 22 | 23 | test_that("Unused arguments with option", { 24 | withr::with_tempfile("tempxlsx", fileext = ".xlsx", code = { 25 | export(list("mtcars" = mtcars, "iris" = iris), tempxlsx) 26 | expect_error(R.utils::withOptions({ 27 | y <- import(tempxlsx, n_max = 42, whatever = TRUE) 28 | }, rio.ignoreunusedargs = FALSE)) 29 | expect_error(R.utils::withOptions({ 30 | y <- import(tempxlsx, n_max = 42, sheet = 2, whatever = TRUE) 31 | }, rio.ignoreunusedargs = FALSE), "whatever") ## not sheet 32 | }) 33 | }) 34 | -------------------------------------------------------------------------------- /tests/testthat/test_matrix.R: -------------------------------------------------------------------------------- 1 | test_that("Export matrix to and import from CSV", { 2 | withr::with_tempfile("temp_files", fileext = c(".csv", ".csv"), code = { 3 | export(warpbreaks, temp_files[1]) 4 | export(as.matrix(warpbreaks), temp_files[2]) 5 | expect_true(file.exists(temp_files[1])) 6 | expect_true(file.exists(temp_files[2])) 7 | expect_true(identical(import(temp_files[1], colClasses = rep("character", 3)), 8 | import(temp_files[2], colClasses = rep("character", 3)))) 9 | }) 10 | }) 11 | -------------------------------------------------------------------------------- /tests/testthat/test_remote.R: -------------------------------------------------------------------------------- 1 | skip_on_cran() 2 | 3 | test_that("Import Remote Stata File", { 4 | f <- try(import("http://www.stata-press.com/data/r13/auto.dta")) 5 | if (!inherits(f, "try-error")) { 6 | expect_true(is.data.frame(f)) 7 | } 8 | }) 9 | 10 | test_that("Import Remote GitHub File", { 11 | rfile <- "https://raw.githubusercontent.com/gesistsa/rio/main/tests/testdata/noheader.csv" 12 | rfile_imported1 <- try(import(rfile)) 13 | if (!inherits(rfile_imported1, "try-error")) { 14 | expect_true(inherits(rfile_imported1, "data.frame"), label = "Import remote file (implied format)") 15 | } 16 | rfile_imported2 <- try(import(rfile, format = "csv")) 17 | if (!inherits(rfile_imported2, "try-error")) { 18 | expect_true(inherits(rfile_imported2, "data.frame"), label = "Import remote file (explicit format)") 19 | } 20 | 21 | lfile <- remote_to_local(rfile) 22 | if (!inherits(lfile, "try-error")) { 23 | expect_true(file.exists(lfile), label = "Remote file copied successfully") 24 | expect_true(inherits(import(lfile), "data.frame"), label = "Import local copy successfully") 25 | } 26 | ## short url 27 | payload <- try(import("https://is.gd/NLAxtg")) 28 | if (!inherits(payload, "try-error")) { 29 | expect_true(inherits(payload, "data.frame"), label = "Import remote file from shorten url (implied format)") 30 | } 31 | ## no extension 32 | noextension_url <- "https://github.com/gesistsa/rio/raw/main/tests/testdata/iris_no_extension_xls" 33 | expect_error(import(noextension_url)) 34 | expect_error(import(noextension_url, format = "xls"), NA) 35 | }) 36 | 37 | test_that("Import from Google Sheets", { 38 | googleurl1 <- "https://docs.google.com/spreadsheets/d/1I9mJsS5QnXF2TNNntTy-HrcdHmIF9wJ8ONYvEJTXSNo/edit#gid=0" 39 | expect_true(inherits(import(googleurl1), "data.frame"), label = "Import google sheets (specified sheet)") 40 | 41 | googleurl2 <- "https://docs.google.com/spreadsheets/d/1I9mJsS5QnXF2TNNntTy-HrcdHmIF9wJ8ONYvEJTXSNo/edit" 42 | expect_true(inherits(import(googleurl2), "data.frame"), label = "Import google sheets (unspecified sheet)") 43 | 44 | expect_true(inherits(import(googleurl1, format = "tsv"), "data.frame"), label = "Import google sheets (specified sheet, specified format)") 45 | }) 46 | -------------------------------------------------------------------------------- /tests/testthat/test_set_class.R: -------------------------------------------------------------------------------- 1 | mtcars_tibble <- tibble::as_tibble(mtcars) 2 | mtcars_datatable <- data.table::as.data.table(mtcars) 3 | 4 | test_that("Set object class", { 5 | mtcars_tibble <- tibble::as_tibble(mtcars) 6 | mtcars_datatable <- data.table::as.data.table(mtcars) 7 | expect_true(inherits(set_class(mtcars), "data.frame")) 8 | expect_true(inherits(set_class(mtcars_tibble), "data.frame")) 9 | expect_true(inherits(set_class(mtcars_datatable), "data.frame")) 10 | expect_true(inherits(set_class(mtcars, class = "fakeclass"), "data.frame")) 11 | expect_true(!"fakeclass" %in% class(set_class(mtcars, class = "fakeclass"))) 12 | }) 13 | 14 | test_that("Set object class as tibble", { 15 | mtcars_tibble <- tibble::as_tibble(mtcars) 16 | mtcars_datatable <- data.table::as.data.table(mtcars) 17 | expect_true(inherits(set_class(mtcars, class = "tbl_df"), "tbl_df")) 18 | expect_true(inherits(set_class(mtcars, class = "tibble"), "tbl_df")) 19 | expect_true(inherits(set_class(mtcars_tibble, class = "tibble"), "tbl_df")) 20 | }) 21 | 22 | test_that("Set object class as data.table", { 23 | expect_true(inherits(set_class(mtcars, class = "data.table"), "data.table")) 24 | withr::with_tempfile("data_file", fileext = ".csv", code = { 25 | export(mtcars, data_file) 26 | expect_true(inherits(import(data_file, setclass = "data.table"), "data.table")) 27 | expect_true(inherits(import(data_file, data.table = TRUE, setclass = "data.table"), "data.table")) 28 | }) 29 | }) 30 | 31 | test_that("Set object class as arrow table", { 32 | skip_if(getRversion() <= "4.2") 33 | skip_if_not_installed("arrow") 34 | mtcars_arrow <- arrow::arrow_table(mtcars) 35 | expect_false(inherits(set_class(mtcars_arrow), "data.frame")) ## arrow table is not data.frame 36 | expect_true(inherits(set_class(mtcars, class = "arrow"), "ArrowTabular")) 37 | expect_true(inherits(set_class(mtcars, class = "arrow_table"), "ArrowTabular")) 38 | withr::with_tempfile("data_file", fileext = ".csv", code = { 39 | export(mtcars, data_file) 40 | expect_true(inherits(import(data_file, setclass = "arrow"), "ArrowTabular")) 41 | expect_true(inherits(import(data_file, data.table = TRUE, setclass = "arrow"), "ArrowTabular")) 42 | }) 43 | }) 44 | 45 | test_that("ArrowTabular can be exported", { 46 | skip_if(getRversion() <= "4.2") 47 | skip_if_not_installed("arrow") 48 | mtcars_arrow <- arrow::arrow_table(mtcars) 49 | withr::with_tempfile("data_file", fileext = ".csv", code = { 50 | expect_error(export(mtcars_arrow, data_file), NA) ## no concept of rownames 51 | expect_true(inherits(import(data_file), "data.frame")) 52 | }) 53 | }) 54 | 55 | test_that("Simulate arrow is not installed, #376", { 56 | ## although this is pretty meaningless 57 | withr::with_tempfile("data_file", fileext = ".csv", code = { 58 | with_mocked_bindings({ 59 | export(mtcars, data_file) 60 | expect_error(import(data_file, setclass = "arrow"), "Suggested package") 61 | }, .check_pkg_availability = function(pkg, lib.loc = NULL) { 62 | stop("Suggested package `", pkg, "` is not available. Please install it individually or use `install_formats()`", call. = FALSE) 63 | }) 64 | }) 65 | }) 66 | -------------------------------------------------------------------------------- /tests/testthat/test_suggestions.R: -------------------------------------------------------------------------------- 1 | test_that("uninstalled_formats()", { 2 | skip_on_cran() 3 | formats <- uninstalled_formats() 4 | if (is.null(formats)) { 5 | expect_true(install_formats()) 6 | } else { 7 | expect_type(formats, "character") 8 | } 9 | }) 10 | 11 | 12 | test_that("show_unsupported_formats (in the fully supported environment) on CI", { 13 | skip_on_cran() 14 | for (pkg in attr(rio_formats, "suggested_packages")) { 15 | skip_if_not_installed(pkg) 16 | } 17 | expect_false(show_unsupported_formats()) 18 | expect_message(show_unsupported_formats(), "All default") 19 | }) 20 | 21 | test_that("show_unsupported_formats (in the partial supported environment) on CI", { 22 | skip_on_cran() 23 | fake_uninstalled_formats <- function() { 24 | return(c("readODS")) 25 | } 26 | with_mocked_bindings(code = { 27 | expect_true(show_unsupported_formats()) 28 | expect_message(show_unsupported_formats(), "These formats are not supported") 29 | }, `uninstalled_formats` = fake_uninstalled_formats) 30 | }) 31 | -------------------------------------------------------------------------------- /tests/testthat/test_trust.R: -------------------------------------------------------------------------------- 1 | test_that("Deprecation of untrusted dump", { 2 | withr::with_tempfile("iris_file", fileext = ".dump", code = { 3 | export(iris, iris_file) 4 | ## expect deprecation to work 5 | expect_warning(import(iris_file), regexp = "set to FALSE by default") 6 | ## expect false to error 7 | expect_error(import(iris_file, trust = FALSE)) 8 | }) 9 | }) 10 | 11 | test_that("Deprecation of untrusted Rdata", { 12 | withr::with_tempfile("iris_file", fileext = ".Rdata", code = { 13 | export(iris, iris_file) 14 | ## expect deprecation to work 15 | expect_warning(import(iris_file), regexp = "set to FALSE by default") 16 | ## expect false to error 17 | expect_error(import(iris_file, trust = FALSE)) 18 | }) 19 | }) 20 | 21 | test_that("Deprecation of untrusted rds", { 22 | withr::with_tempfile("iris_file", fileext = ".rds", code = { 23 | export(iris, iris_file) 24 | ## expect deprecation to work 25 | expect_warning(import(iris_file), regexp = "set to FALSE by default") 26 | ## expect false to error 27 | expect_error(import(iris_file, trust = FALSE)) 28 | }) 29 | }) 30 | 31 | test_that("No deprecation warning if `trust` is explicit", { 32 | withr::with_tempfile("iris_file", fileext = ".rds", code = { 33 | export(iris, iris_file) 34 | expect_silent(import(iris_file, trust = TRUE)) 35 | expect_error(import(iris_file, trust = FALSE)) ## no warning right? 36 | }) 37 | }) 38 | 39 | test_that("Undocumented feature, options", { 40 | withr::with_options(list(rio.import.trust = TRUE), { 41 | withr::with_tempfile("iris_file", fileext = ".rds", code = { 42 | export(iris, iris_file) 43 | expect_silent(import(iris_file)) 44 | expect_error(import(iris_file), NA) 45 | }) 46 | }) 47 | withr::with_options(list(rio.import.trust = FALSE), { 48 | withr::with_tempfile("iris_file", fileext = ".rds", code = { 49 | export(iris, iris_file) 50 | expect_error(import(iris_file)) 51 | }) 52 | }) 53 | }) 54 | 55 | test_that("`trust` wont cause problems for other import methods", { 56 | withr::with_tempfile("iris_file", fileext = ".xlsx", code = { 57 | export(iris, iris_file) 58 | expect_silent(import(iris_file, trust = TRUE)) 59 | expect_error(import(iris_file, trust = FALSE), NA) 60 | }) 61 | }) 62 | 63 | test_that("`trust` for import_list()", { 64 | withr::with_tempfile("iris_file", fileext = ".rdata", code = { 65 | export(iris, iris_file) 66 | expect_warning(import_list(iris_file), regexp = "set to FALSE by default") 67 | expect_silent(import_list(iris_file, trust = TRUE)) 68 | expect_error(import_list(iris_file, trust = FALSE)) 69 | 70 | }) 71 | }) 72 | 73 | test_that("`trust` wont cause problems for other formats in import_list", { 74 | withr::with_tempfile("data_file", fileext = ".xlsx", code = { 75 | export(list(a = mtcars, b = iris), data_file) 76 | expect_silent(import(data_file)) 77 | expect_silent(import(data_file, trust = TRUE)) 78 | expect_error(import(data_file, trust = FALSE), NA) 79 | }) 80 | }) 81 | -------------------------------------------------------------------------------- /vignettes/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | *.R 3 | -------------------------------------------------------------------------------- /vignettes/extension.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Extending rio" 3 | output: rmarkdown::html_vignette 4 | vignette: > 5 | %\VignetteIndexEntry{Extending rio} 6 | %\VignetteEngine{knitr::rmarkdown} 7 | %\VignetteEncoding{UTF-8} 8 | --- 9 | 10 | ```{r, include = FALSE} 11 | knitr::opts_chunk$set( 12 | collapse = TRUE, 13 | comment = "#>" 14 | ) 15 | ``` 16 | 17 | ```{r setup} 18 | library(rio) 19 | ``` 20 | 21 | 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`). 22 | 23 | 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")`. 24 | 25 | The way to develop `export` method is same: `.export.rio_csv`. The first two parameters of `.export` are `file` (file name) and `x` (data frame to be exported). 26 | 27 | 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`. 28 | 29 | # Examples 30 | 31 | ## arff 32 | 33 | The following example shows how the arff import and export methods are implemented internally. 34 | 35 | ```r 36 | .import.rio_arff <- function(file, which = 1, ...) { 37 | foreign::read.arff(file = file) 38 | } 39 | .export.rio_arff <- function(file, x, ...) { 40 | foreign::write.arff(x = x, file = file, ...) 41 | } 42 | ``` 43 | 44 | ## ledger 45 | 46 | This is the example from the `ledger` package (MIT) by Dr Trevor L David . 47 | 48 | ```r 49 | .import.rio_ledger <- register # nolint 50 | register <- function(file, ..., toolchain = default_toolchain(file), date = NULL) { 51 | .assert_toolchain(toolchain) 52 | switch(toolchain, 53 | "ledger" = register_ledger(file, ..., date = date), 54 | "hledger" = register_hledger(file, ..., date = date), 55 | "beancount" = register_beancount(file, ..., date = date), 56 | "bean-report_ledger" = { 57 | file <- .bean_report(file, "ledger") 58 | on.exit(unlink(file)) 59 | register_ledger(file, ..., date = date) 60 | }, 61 | "bean-report_hledger" = { 62 | file <- .bean_report(file, "hledger") 63 | on.exit(unlink(file)) 64 | register_hledger(file, ..., date = date) 65 | } 66 | ) 67 | } 68 | ``` 69 | -------------------------------------------------------------------------------- /vignettes/labelled.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Working with labelled data" 3 | output: rmarkdown::html_vignette 4 | vignette: > 5 | %\VignetteIndexEntry{Working with labelled data} 6 | %\VignetteEngine{knitr::rmarkdown} 7 | %\VignetteEncoding{UTF-8} 8 | --- 9 | 10 | ```{r, include = FALSE} 11 | knitr::opts_chunk$set( 12 | collapse = TRUE, 13 | comment = "#>" 14 | ) 15 | ``` 16 | 17 | ```{r} 18 | library(rio) 19 | library(haven) 20 | ``` 21 | 22 | Formats SAS, SPSS, and Stata use `haven` as import and export functions. And these formats can have the so-called labelled data. For more information, please read `vignette("semantics", "haven")`. Here, we provide a quick guide on how to work with labelled data using `rio`. 23 | 24 | You can use `haven::labelled()` to create labelled data. 25 | 26 | ```{r} 27 | gender <- haven::labelled( 28 | c("M", "F", "F", "F", "M"), 29 | c(Male = "M", Female = "F")) 30 | ``` 31 | 32 | Or directly using `attrs` 33 | 34 | ```{r} 35 | rating <- sample(1:5) 36 | attr(rating, "labels") <- c(c(Good = 1, Bad = 5)) 37 | ``` 38 | 39 | ```{r} 40 | mydata <- data.frame(gender, rating) 41 | ``` 42 | 43 | Round trip: The data labels are retained. But they are at the variable level. 44 | 45 | ```{r} 46 | export(mydata, "mydata.sav") 47 | restored_data <- rio::import("mydata.sav") 48 | str(restored_data) 49 | ``` 50 | 51 | `rio::gather_attrs()` converts attributes to the data.frame level 52 | 53 | ```{r} 54 | g <- rio::gather_attrs(restored_data) 55 | str(g) 56 | attr(g, "labels") 57 | ``` 58 | 59 | ```{r include = FALSE} 60 | unlink("mydata.sav") 61 | ``` 62 | -------------------------------------------------------------------------------- /vignettes/philosophy.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Package Philosophy" 3 | output: rmarkdown::html_vignette 4 | vignette: > 5 | %\VignetteIndexEntry{Package Philosophy} 6 | %\VignetteEngine{knitr::rmarkdown} 7 | %\VignetteEncoding{UTF-8} 8 | --- 9 | The core advantage of **rio** is that it makes assumptions that the user is probably willing to make. Eight of these are important: 10 | 11 | 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. 12 | 13 | 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. 14 | 15 | 3. **rio**, wherever possible, does not import character strings as factors. 16 | 17 | 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. 18 | 19 | 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. 20 | 21 | 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 [**writexl**](https://cran.r-project.org/package=writexl) for reading and writing Excel workbooks. 22 | 23 | 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: 24 | 25 | - `label`: a description of variable 26 | - `labels`: a vector mapping numeric values to character strings those values represent 27 | - `format`: a character string describing the variable storage type in the original file 28 | 29 | 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: 30 | 31 | ```R 32 | dat <- gather_attrs(rio::import("data.sav")) 33 | attr(dat, "labels") <- lapply(attributes(dat)$labels, function(x) { 34 | if (!is.null(x)) { 35 | names(x) <- substring(names(x), 1, 32) 36 | } 37 | x 38 | }) 39 | export(spread_attrs(dat), "data.dta") 40 | ``` 41 | 42 | 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")`. 43 | 44 | 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). 45 | -------------------------------------------------------------------------------- /vignettes/remap.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Remapping and Ellipsis" 3 | output: rmarkdown::html_vignette 4 | vignette: > 5 | %\VignetteIndexEntry{Remapping and Ellipsis} 6 | %\VignetteEngine{knitr::rmarkdown} 7 | %\VignetteEncoding{UTF-8} 8 | --- 9 | 10 | ```{r, include = FALSE} 11 | knitr::opts_chunk$set( 12 | collapse = TRUE, 13 | comment = "#>" 14 | ) 15 | ``` 16 | 17 | # Remapping 18 | 19 | There are two conventions of arguments among the underlying functions used by `rio`. Let's call them *Base Convention* and *"Tidy" Convention*. 20 | 21 | | Convention | file location | selection of sheet | header | examples | 22 | |------------|---------------|--------------------|-------------|--------------------------------------------------------------| 23 | | Base | `file` | `which` | `header` | `clipr::read_clip_tbl` | 24 | | "Tidy" | `path` | `sheet` | `col_names` | `readxl::read_xlsx`, `readxl::read_xls`, `readODS::read_ods` | 25 | 26 | `rio` can map Base Convention into "Tidy" Convention (but not vice versa). 27 | 28 | ```{r map1} 29 | library(rio) 30 | export(list("mtcars" = mtcars, "iris" = iris), "example.xlsx") 31 | import("example.xlsx", which = "mtcars") 32 | ``` 33 | 34 | But you can still use the "Tidy" Convention, if the underlying function supports it. 35 | 36 | ```{r map2} 37 | import("example.xlsx", sheet = "mtcars") 38 | ``` 39 | 40 | # Ellipsis or "dot dot dot" 41 | 42 | Additional parameters are usually passed to the underlying function as ellipsis (`...`). 43 | 44 | ```{r map3} 45 | ## n_max is an argument of readxl::read_xlsx 46 | import("example.xlsx", sheet = "iris", n_max = 10) 47 | ``` 48 | 49 | Parameters that the underlying function do not recognize are silently ignored by default. 50 | 51 | ```{r map4} 52 | import("example.xlsx", sheet = "iris", n_max = 10, pizza = "pineapple") 53 | ``` 54 | 55 | If you don't like this behavior, please change the option `rio.ignoreunusedargs` to `FALSE`, i.e. `options(rio.ignoreunusedargs = FALSE)`. 56 | 57 | ```r 58 | options(rio.ignoreunusedargs = FALSE) 59 | import("example.xlsx", sheet = "iris", n_max = 10, pizza = "pineapple") 60 | ``` 61 | 62 | ```{r map5, error = TRUE, echo = FALSE, purl = FALSE} 63 | R.utils::withOptions({ 64 | import("example.xlsx", sheet = "iris", n_max = 10, pizza = "pineapple") 65 | }, rio.ignoreunusedargs = FALSE) 66 | ``` 67 | 68 | ```{r, echo = FALSE, results = 'hide'} 69 | unlink("example.xlsx") 70 | ``` 71 | --------------------------------------------------------------------------------