├── .Rbuildignore ├── .github ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md ├── ISSUE_TEMPLATE │ └── issue_template.md ├── SUPPORT.md ├── move.yml └── workflows │ ├── R-CMD-check.yaml │ ├── pkgdown.yaml │ ├── pr-commands.yaml │ └── test-coverage.yaml ├── .gitignore ├── DESCRIPTION ├── LICENSE ├── LICENSE.md ├── NAMESPACE ├── NEWS.md ├── R ├── aaa.R ├── ensure.R ├── highlight.R ├── prex.R ├── reprex-addin.R ├── reprex-locale.R ├── reprex-options.R ├── reprex-package.R ├── reprex-undo.R ├── reprex.R ├── reprex_document.R ├── reprex_impl.R ├── reprex_render.R ├── stringify_expression.R ├── sysdata.rda ├── utils-clipboard.R ├── utils-interactivity.R ├── utils-io.R ├── utils-ui.R ├── utils.R └── venues.R ├── README.md ├── _pkgdown.yml ├── codecov.yml ├── cran-comments.md ├── data-raw ├── adjective_animal.R ├── github_css.R ├── pandoc-syntax-highlighting.R ├── pygments.theme ├── r-syntax-definition.R ├── r.xml ├── starry-night-dark.css └── starry-night-light.css ├── img ├── ProgrammerInterrupted.png ├── datapasta_w_reprex_sheet_to_tribble.gif ├── debugging │ ├── needle-in-a-haystack.png │ ├── science-and-art.png │ ├── solve-your-own-problem.png │ └── what-you-think-vs-day.png ├── dpasta_datapasta_reprex.gif ├── logo │ ├── reprex-og-1280x640.png │ └── reprex.png ├── reprex-copy.gif ├── reprex-fail-1.gif ├── reprex-github.gif ├── reprex-si.gif ├── reprex-success-1.gif └── reprex_rtf_jennybryan.gif ├── inst ├── WORDLIST ├── addins │ └── reprex.css ├── rmarkdown │ └── templates │ │ ├── reprex-featureful │ │ ├── skeleton │ │ │ └── skeleton.Rmd │ │ └── template.yaml │ │ ├── reprex-minimal │ │ ├── skeleton │ │ │ └── skeleton.Rmd │ │ └── template.yaml │ │ └── reprex_document │ │ └── resources │ │ ├── github-dark.css │ │ ├── github-light.css │ │ ├── r.xml │ │ ├── starry-nights-dark.theme │ │ └── starry-nights-light.theme ├── rstudio │ └── addins.dcf └── templates │ └── BETTER_THAN_NOTHING.R ├── internal ├── adjective-animal.txt ├── language-codes.csv ├── loadedNamespaces-study.R ├── logo.png ├── message-language-probe.R ├── notes.md ├── render-notes.txt ├── vignette-ideas.Rmd ├── windows-clipboard-data-persistence.Rmd ├── windows-clipboard-data-persistence.md ├── windows-shell-system-system2.Rmd ├── windows-shell-system-system2.md ├── write-clipboard-rtf-windows.md ├── write_clipboard_rtf_alfa.ps1 └── write_clipboard_rtf_beta.ps1 ├── man ├── figures │ ├── README-viewer-screenshot.png │ ├── help-me-help-you.png │ ├── lifecycle-archived.svg │ ├── lifecycle-defunct.svg │ ├── lifecycle-deprecated.svg │ ├── lifecycle-experimental.svg │ ├── lifecycle-maturing.svg │ ├── lifecycle-questioning.svg │ ├── lifecycle-soft-deprecated.svg │ ├── lifecycle-stable.svg │ ├── lifecycle-superseded.svg │ └── logo.png ├── reprex-package.Rd ├── reprex.Rd ├── reprex_addin.Rd ├── reprex_document.Rd ├── reprex_locale.Rd ├── reprex_options.Rd ├── reprex_render.Rd ├── reprex_venue.Rd └── un-reprex.Rd ├── pkgdown └── favicon │ ├── apple-touch-icon-120x120.png │ ├── apple-touch-icon-152x152.png │ ├── apple-touch-icon-180x180.png │ ├── apple-touch-icon-60x60.png │ ├── apple-touch-icon-76x76.png │ ├── apple-touch-icon.png │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ └── favicon.ico ├── reprex.Rproj ├── revdep ├── .gitignore ├── README.md ├── cran.md ├── email.yml ├── failures.md └── problems.md ├── talks ├── 2018-09_reprex-rstudio-webinar │ ├── 00_install-and-setup-snippets.R │ ├── 01_factor-wut-snippet.R │ ├── 02_reprex-fail-tour.R │ ├── 03_inline-data-frame-creation.R │ ├── 04_readr-issue-784.R │ ├── 05_shock-and-awe.R │ ├── 06_rprofile-option-fodder.R │ ├── 10_resolution-to-factor-wut.R │ ├── 2018-09_reprex-rstudio-webinar.pdf │ └── jehyun-sung-477894-unsplash.jpg └── 2021-10-12_rstudio-inside-look │ ├── 00_install-and-setup-snippets.R │ ├── 01_factor-wut.R │ ├── 02_gapminder-ggplot2-imgur.R │ ├── 03_venues-and-suffix-forms.R │ ├── 04_session-info.R │ ├── 05_wd-control.R │ ├── 06_std-out-err.R │ ├── 07_renv.R │ └── 08_prex.R ├── tests ├── spelling.R ├── testthat.R └── testthat │ ├── _snaps │ ├── input.md │ ├── reprex.md │ ├── reprex_document.md │ ├── rprofile.md │ ├── utils-clipboard.md │ ├── utils-io.md │ └── utils-ui.md │ ├── expressions.rds │ ├── fixtures │ └── a-reprex-document.Rmd │ ├── helper.R │ ├── setup.R │ ├── test-env.R │ ├── test-input.R │ ├── test-knitr-options.R │ ├── test-outfiles.R │ ├── test-pandoc.R │ ├── test-reprex-addin.R │ ├── test-reprex-options.R │ ├── test-reprex-undo.R │ ├── test-reprex.R │ ├── test-reprex_document.R │ ├── test-reprex_impl.R │ ├── test-reprex_render.R │ ├── test-rprofile.R │ ├── test-session-info.R │ ├── test-stdout-stderr.R │ ├── test-stringify_expression.R │ ├── test-utf8.R │ ├── test-utils-clipboard.R │ ├── test-utils-io.R │ ├── test-utils-ui.R │ ├── test-utils.R │ └── test-venues.R └── vignettes ├── .gitignore ├── articles ├── datapasta-reprex.Rmd ├── img │ ├── anotherdark-andale-60-line-numbers.png │ ├── bizarro-selective-reveal.png │ ├── dusk-fira-35-line-numbers.png │ ├── eval-false.png │ └── keynote-w00t.png ├── learn-reprex.Rmd ├── magic-reprex.Rmd ├── rtf.Rmd └── suppress-startup-messages.Rmd └── reprex-dos-and-donts.Rmd /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^pkgdown$ 2 | ^talks 3 | ^cran-correspondence$ 4 | ^CRAN-RELEASE$ 5 | ^.*\.Rproj$ 6 | ^\.Rproj\.user$ 7 | ^README\.Rmd$ 8 | ^internal$ 9 | ^\.travis\.yml$ 10 | ^appveyor\.yml$ 11 | ^codecov\.yml$ 12 | ^docs$ 13 | ^cran-comments\.md$ 14 | ^_pkgdown\.yml$ 15 | ^img$ 16 | ^CONTRIBUTING\.md$ 17 | ^ISSUE_TEMPLATE\.md$ 18 | ^SUPPORT\.md$ 19 | ^\.github$ 20 | ^LICENSE\.md$ 21 | ^\.github/workflows/R-CMD-check\.yaml$ 22 | ^\.github/workflows/pkgdown\.yaml$ 23 | ^revdep$ 24 | ^img/debugging$ 25 | ^data-raw$ 26 | ^CRAN-SUBMISSION$ 27 | -------------------------------------------------------------------------------- /.github/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to reprex 2 | 3 | This outlines how to propose a change to reprex. For more detailed 4 | info about contributing to this, and other tidyverse packages, please see the 5 | [**development contributing guide**](https://rstd.io/tidy-contrib). 6 | 7 | ### Fixing typos 8 | 9 | Small typos or grammatical errors in documentation may be edited directly using 10 | the GitHub web interface, so long as the changes are made in the _source_ file. 11 | 12 | * YES: you edit a roxygen comment in a `.R` file below `R/`. 13 | * NO: you edit an `.Rd` file below `man/`. 14 | 15 | ### Prerequisites 16 | 17 | Before you make a substantial pull request, you should always file an issue and 18 | make sure someone from the team agrees that it’s a problem. If you’ve found a 19 | bug, create an associated issue and illustrate the bug with a minimal 20 | [reprex](https://www.tidyverse.org/help/#reprex). 21 | 22 | ### Pull request process 23 | 24 | * We recommend that you create a Git branch for each pull request (PR). 25 | * Look at the Travis and AppVeyor build status before and after making changes. 26 | The `README` should contain badges for any continuous integration services used 27 | by the package. 28 | * New code should follow the tidyverse [style guide](http://style.tidyverse.org). 29 | You can use the [styler](https://CRAN.R-project.org/package=styler) package to 30 | apply these styles, but please don't restyle code that has nothing to do with 31 | your PR. 32 | * We use [roxygen2](https://cran.r-project.org/package=roxygen2), with 33 | [Markdown syntax](https://roxygen2.r-lib.org/articles/rd-formatting.html), 34 | for documentation. 35 | * We use [testthat](https://cran.r-project.org/package=testthat). Contributions 36 | with test cases included are easier to accept. 37 | * For user-facing changes, add a bullet to the top of `NEWS.md` below the current 38 | development version header describing the changes made followed by your GitHub 39 | username, and links to relevant issue(s)/PR(s). 40 | 41 | ### Code of Conduct 42 | 43 | Please note that this project is released with a [Contributor Code of 44 | Conduct](CODE_OF_CONDUCT.md). By participating in this project you agree to 45 | abide by its terms. 46 | 47 | ### See tidyverse [development contributing guide](https://rstd.io/tidy-contrib) for further details. 48 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Please briefly describe your problem and what output you expect. If 2 | you have a question, please don't use this form. Instead, ask on 3 | or . 4 | 5 | --- 6 | 7 | Brief description of the problem 8 | 9 | ```r 10 | # insert reprex here 11 | ``` 12 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/issue_template.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report or feature request 3 | about: Describe a bug you've seen or make a case for a new feature 4 | --- 5 | 6 | Please briefly describe your problem and what output you expect. If you have a question, please don't use this form. Instead, ask on or . 7 | 8 | Please include a minimal reproducible example (AKA a reprex). If you've never heard of a [reprex](http://reprex.tidyverse.org/) before, start by reading . 9 | 10 | Brief description of the problem 11 | 12 | ```r 13 | # insert reprex here 14 | ``` 15 | -------------------------------------------------------------------------------- /.github/SUPPORT.md: -------------------------------------------------------------------------------- 1 | # Getting help with reprex 2 | 3 | Thanks for using reprex. Before filing an issue, there are a few places 4 | to explore and pieces to put together to make the process as smooth as possible. 5 | 6 | Start by making a minimal **repr**oducible **ex**ample using the 7 | [reprex](https://reprex.tidyverse.org/) package. OK, that's funny, 8 | because this is the very package we're talking about! Do your best to 9 | provide your input, the `reprex()` call, the expected result, and the 10 | actual result. Make it easy to reproduce your problem. For additional 11 | reprex pointers, check out the [Get 12 | help!](https://www.tidyverse.org/help/) section of the tidyverse site. 13 | 14 | Armed with your reprex, the next step is to figure out [where to ask](https://www.tidyverse.org/help/#where-to-ask). 15 | 16 | * If it's a question: start with [community.rstudio.com](https://community.rstudio.com/), 17 | and/or StackOverflow. There are more people there to answer questions. 18 | * If it's a bug: you're in the right place, file an issue. 19 | * If you're not sure: let the community help you figure it out! If your 20 | problem _is_ a bug or a feature request, you can easily return here and 21 | report it. 22 | 23 | Before opening a new issue, be sure to [search issues and pull requests](https://github.com/tidyverse/reprex/issues) to make sure the 24 | bug hasn't been reported and/or already fixed in the development version. By 25 | default, the search will be pre-populated with `is:issue is:open`. You can 26 | [edit the qualifiers](https://help.github.com/articles/searching-issues-and-pull-requests/) 27 | (e.g. `is:pr`, `is:closed`) as needed. For example, you'd simply 28 | remove `is:open` to search _all_ issues in the repo, open or closed. 29 | 30 | 31 | If you _are_ in the right place, and need to file an issue, please review the 32 | ["File issues"](https://www.tidyverse.org/contribute/#issues) paragraph from 33 | the tidyverse contributing guidelines. 34 | 35 | Thanks for your help! 36 | -------------------------------------------------------------------------------- /.github/move.yml: -------------------------------------------------------------------------------- 1 | # Configuration for move-issues bot - https://github.com/dessant/move-issues 2 | 3 | # Delete the command comment when it contains no other content 4 | deleteCommand: true 5 | 6 | # Close the source issue after moving 7 | closeSourceIssue: true 8 | 9 | # Lock the source issue after moving 10 | lockSourceIssue: false 11 | 12 | # Mention issue and comment authors 13 | mentionAuthors: true 14 | 15 | # Preserve mentions in the issue content 16 | keepContentMentions: true 17 | 18 | # Set custom aliases for targets 19 | # aliases: 20 | # r: repo 21 | # or: owner/repo 22 | -------------------------------------------------------------------------------- /.github/workflows/R-CMD-check.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | # 4 | # NOTE: This workflow is overkill for most R packages and 5 | # check-standard.yaml is likely a better choice. 6 | # usethis::use_github_action("check-standard") will install it. 7 | on: 8 | push: 9 | branches: [main, master] 10 | pull_request: 11 | branches: [main, master] 12 | 13 | name: R-CMD-check.yaml 14 | 15 | permissions: read-all 16 | 17 | jobs: 18 | R-CMD-check: 19 | runs-on: ${{ matrix.config.os }} 20 | 21 | name: ${{ matrix.config.os }} (${{ matrix.config.r }}) 22 | 23 | strategy: 24 | fail-fast: false 25 | matrix: 26 | config: 27 | - {os: macos-latest, r: 'release'} 28 | 29 | - {os: windows-latest, r: 'release'} 30 | # use 4.0 or 4.1 to check with rtools40's older compiler 31 | - {os: windows-latest, r: 'oldrel-4'} 32 | 33 | - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} 34 | - {os: ubuntu-latest, r: 'release'} 35 | - {os: ubuntu-latest, r: 'oldrel-1'} 36 | - {os: ubuntu-latest, r: 'oldrel-2'} 37 | - {os: ubuntu-latest, r: 'oldrel-3'} 38 | - {os: ubuntu-latest, r: 'oldrel-4'} 39 | 40 | env: 41 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 42 | R_KEEP_PKG_SOURCE: yes 43 | 44 | steps: 45 | - uses: actions/checkout@v4 46 | 47 | - uses: r-lib/actions/setup-pandoc@v2 48 | 49 | - uses: r-lib/actions/setup-r@v2 50 | with: 51 | r-version: ${{ matrix.config.r }} 52 | http-user-agent: ${{ matrix.config.http-user-agent }} 53 | use-public-rspm: true 54 | 55 | - uses: r-lib/actions/setup-r-dependencies@v2 56 | with: 57 | extra-packages: any::rcmdcheck 58 | needs: check 59 | 60 | - uses: r-lib/actions/check-r-package@v2 61 | with: 62 | upload-snapshots: true 63 | build_args: 'c("--no-manual","--compact-vignettes=gs+qpdf")' 64 | -------------------------------------------------------------------------------- /.github/workflows/pkgdown.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | branches: [main, master] 8 | release: 9 | types: [published] 10 | workflow_dispatch: 11 | 12 | name: pkgdown.yaml 13 | 14 | permissions: read-all 15 | 16 | jobs: 17 | pkgdown: 18 | runs-on: ubuntu-latest 19 | # Only restrict concurrency for non-PR jobs 20 | concurrency: 21 | group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }} 22 | env: 23 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 24 | permissions: 25 | contents: write 26 | steps: 27 | - uses: actions/checkout@v4 28 | 29 | - uses: r-lib/actions/setup-pandoc@v2 30 | 31 | - uses: r-lib/actions/setup-r@v2 32 | with: 33 | use-public-rspm: true 34 | 35 | - uses: r-lib/actions/setup-r-dependencies@v2 36 | with: 37 | extra-packages: any::pkgdown, local::. 38 | needs: website 39 | 40 | - name: Build site 41 | run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE) 42 | shell: Rscript {0} 43 | 44 | - name: Deploy to GitHub pages 🚀 45 | if: github.event_name != 'pull_request' 46 | uses: JamesIves/github-pages-deploy-action@v4.5.0 47 | with: 48 | clean: false 49 | branch: gh-pages 50 | folder: docs 51 | -------------------------------------------------------------------------------- /.github/workflows/pr-commands.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 | issue_comment: 5 | types: [created] 6 | 7 | name: pr-commands.yaml 8 | 9 | permissions: read-all 10 | 11 | jobs: 12 | document: 13 | if: ${{ github.event.issue.pull_request && (github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER') && startsWith(github.event.comment.body, '/document') }} 14 | name: document 15 | runs-on: ubuntu-latest 16 | env: 17 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 18 | permissions: 19 | contents: write 20 | steps: 21 | - uses: actions/checkout@v4 22 | 23 | - uses: r-lib/actions/pr-fetch@v2 24 | with: 25 | repo-token: ${{ secrets.GITHUB_TOKEN }} 26 | 27 | - uses: r-lib/actions/setup-r@v2 28 | with: 29 | use-public-rspm: true 30 | 31 | - uses: r-lib/actions/setup-r-dependencies@v2 32 | with: 33 | extra-packages: any::roxygen2 34 | needs: pr-document 35 | 36 | - name: Document 37 | run: roxygen2::roxygenise() 38 | shell: Rscript {0} 39 | 40 | - name: commit 41 | run: | 42 | git config --local user.name "$GITHUB_ACTOR" 43 | git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com" 44 | git add man/\* NAMESPACE 45 | git commit -m 'Document' 46 | 47 | - uses: r-lib/actions/pr-push@v2 48 | with: 49 | repo-token: ${{ secrets.GITHUB_TOKEN }} 50 | 51 | style: 52 | if: ${{ github.event.issue.pull_request && (github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER') && startsWith(github.event.comment.body, '/style') }} 53 | name: style 54 | runs-on: ubuntu-latest 55 | env: 56 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 57 | permissions: 58 | contents: write 59 | steps: 60 | - uses: actions/checkout@v4 61 | 62 | - uses: r-lib/actions/pr-fetch@v2 63 | with: 64 | repo-token: ${{ secrets.GITHUB_TOKEN }} 65 | 66 | - uses: r-lib/actions/setup-r@v2 67 | 68 | - name: Install dependencies 69 | run: install.packages("styler") 70 | shell: Rscript {0} 71 | 72 | - name: Style 73 | run: styler::style_pkg() 74 | shell: Rscript {0} 75 | 76 | - name: commit 77 | run: | 78 | git config --local user.name "$GITHUB_ACTOR" 79 | git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com" 80 | git add \*.R 81 | git commit -m 'Style' 82 | 83 | - uses: r-lib/actions/pr-push@v2 84 | with: 85 | repo-token: ${{ secrets.GITHUB_TOKEN }} 86 | -------------------------------------------------------------------------------- /.github/workflows/test-coverage.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | branches: [main, master] 8 | 9 | name: test-coverage.yaml 10 | 11 | permissions: read-all 12 | 13 | jobs: 14 | test-coverage: 15 | runs-on: ubuntu-latest 16 | env: 17 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 18 | 19 | steps: 20 | - uses: actions/checkout@v4 21 | 22 | - uses: r-lib/actions/setup-pandoc@v2 23 | 24 | - uses: r-lib/actions/setup-r@v2 25 | with: 26 | use-public-rspm: true 27 | 28 | - uses: r-lib/actions/setup-r-dependencies@v2 29 | with: 30 | extra-packages: any::covr, any::xml2 31 | needs: coverage 32 | 33 | - name: Test coverage 34 | run: | 35 | cov <- covr::package_coverage( 36 | quiet = FALSE, 37 | clean = FALSE, 38 | install_path = file.path(normalizePath(Sys.getenv("RUNNER_TEMP"), winslash = "/"), "package") 39 | ) 40 | covr::to_cobertura(cov) 41 | shell: Rscript {0} 42 | 43 | - uses: codecov/codecov-action@v4 44 | with: 45 | fail_ci_if_error: ${{ github.event_name != 'pull_request' && true || false }} 46 | file: ./cobertura.xml 47 | plugin: noop 48 | disable_search: true 49 | token: ${{ secrets.CODECOV_TOKEN }} 50 | 51 | - name: Show testthat output 52 | if: always() 53 | run: | 54 | ## -------------------------------------------------------------------- 55 | find '${{ runner.temp }}/package' -name 'testthat.Rout*' -exec cat '{}' \; || true 56 | shell: bash 57 | 58 | - name: Upload test results 59 | if: failure() 60 | uses: actions/upload-artifact@v4 61 | with: 62 | name: coverage-test-failures 63 | path: ${{ runner.temp }}/package 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | docs 2 | .Rproj.user 3 | .Rhistory 4 | .RData 5 | README.html 6 | inst/doc 7 | img/help-me-help-you.gif 8 | *.key 9 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: reprex 2 | Title: Prepare Reproducible Example Code via the Clipboard 3 | Version: 2.1.1.9000 4 | Authors@R: c( 5 | person("Jennifer", "Bryan", , "jenny@posit.co", role = c("aut", "cre"), 6 | comment = c(ORCID = "0000-0002-6983-2759")), 7 | person("Jim", "Hester", role = "aut", 8 | comment = c(ORCID = "0000-0002-2739-7082")), 9 | person("David", "Robinson", , "admiral.david@gmail.com", role = "aut"), 10 | person("Hadley", "Wickham", , "hadley@posit.co", role = "aut", 11 | comment = c(ORCID = "0000-0003-4757-117X")), 12 | person("Christophe", "Dervieux", , "cderv@posit.co", role = "aut", 13 | comment = c(ORCID = "0000-0003-4474-2498")), 14 | person("Posit Software, PBC", role = c("cph", "fnd")) 15 | ) 16 | Description: Convenience wrapper that uses the 'rmarkdown' package to 17 | render small snippets of code to target formats that include both code 18 | and output. The goal is to encourage the sharing of small, 19 | reproducible, and runnable examples on code-oriented websites, such as 20 | and , or in email. The 21 | user's clipboard is the default source of input code and the default 22 | target for rendered output. 'reprex' also extracts clean, runnable R 23 | code from various common formats, such as copy/paste from an R 24 | session. 25 | License: MIT + file LICENSE 26 | URL: https://reprex.tidyverse.org, https://github.com/tidyverse/reprex 27 | BugReports: https://github.com/tidyverse/reprex/issues 28 | Depends: 29 | R (>= 3.6) 30 | Imports: 31 | callr (>= 3.6.0), 32 | cli (>= 3.2.0), 33 | clipr (>= 0.4.0), 34 | fs, 35 | glue, 36 | knitr (>= 1.23), 37 | lifecycle, 38 | rlang (>= 1.0.0), 39 | rmarkdown, 40 | rstudioapi, 41 | utils, 42 | withr (>= 2.3.0) 43 | Suggests: 44 | covr, 45 | fortunes, 46 | miniUI, 47 | rprojroot, 48 | sessioninfo, 49 | shiny, 50 | spelling, 51 | styler (>= 1.2.0), 52 | testthat (>= 3.2.1) 53 | VignetteBuilder: 54 | knitr 55 | Config/Needs/website: dplyr, tidyverse/tidytemplate 56 | Config/testthat/edition: 3 57 | Config/testthat/parallel: TRUE 58 | Config/testthat/start-first: knitr-options, venues, reprex 59 | Encoding: UTF-8 60 | Language: en-US 61 | Roxygen: list(markdown = TRUE) 62 | RoxygenNote: 7.3.2 63 | SystemRequirements: pandoc (>= 2.0) - https://pandoc.org/ 64 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2024 2 | COPYRIGHT HOLDER: reprex authors 3 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright (c) 2024 reprex authors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(reprex) 4 | export(reprex_addin) 5 | export(reprex_clean) 6 | export(reprex_document) 7 | export(reprex_html) 8 | export(reprex_invert) 9 | export(reprex_locale) 10 | export(reprex_r) 11 | export(reprex_render) 12 | export(reprex_rescue) 13 | export(reprex_rtf) 14 | export(reprex_selection) 15 | export(reprex_slack) 16 | import(fs) 17 | import(rlang) 18 | importFrom(glue,glue) 19 | importFrom(glue,glue_collapse) 20 | importFrom(lifecycle,deprecated) 21 | -------------------------------------------------------------------------------- /R/aaa.R: -------------------------------------------------------------------------------- 1 | .onLoad <- function(libname, pkgname) { 2 | withr::with_preserve_seed({ 3 | # create a new random permutation every time we load 4 | adjective_animal <<- sample(adjective_animal, size = length(adjective_animal)) 5 | }) 6 | invisible() 7 | } 8 | -------------------------------------------------------------------------------- /R/ensure.R: -------------------------------------------------------------------------------- 1 | ensure_not_empty <- function(x) { 2 | if (length(x) > 0) { 3 | x 4 | } else { 5 | read_lines(path_package("reprex", "templates", "BETTER_THAN_NOTHING.R")) 6 | } 7 | } 8 | 9 | ensure_not_dogfood <- function(x) { 10 | looks_like_fenced_md <- any(grepl("^```", x)) 11 | if (looks_like_fenced_md) { 12 | lines <- paste0(" ", x[1:3]) 13 | ## I negate yep(), instead of using nope(), to get desired behaviour in 14 | ## a non-interactive call 15 | if (!yep( 16 | "First three lines of putative code are:\n", 17 | glue_collapse(lines, sep = "\n"), "\n", 18 | "which doesn't look like R code.\n", 19 | "Are we going in circles? Did you just run reprex()?\n", 20 | "In that case, the clipboard or selection now holds the *rendered* result.\n", 21 | "Carry on with this reprex?" 22 | )) { 23 | cli::cli_abort("Cancelling.", call = quote(reprex())) 24 | } 25 | } 26 | 27 | looks_like_r <- any(grepl("^#>", x)) 28 | if (looks_like_r) { 29 | if (!yep( 30 | "Putative code contains lines that start with `#>`.\n", 31 | "Are we going in circles? Did you just run `reprex(..., venue = \"r\")`?\n", 32 | "In that case, the clipboard or selection now holds the *rendered* result.\n", 33 | "Carry on with this reprex?" 34 | )) { 35 | cli::cli_abort("Cancelling.", call = quote(reprex())) 36 | } 37 | } 38 | 39 | html_start <- grep("^
", x)
40 |   if (length(html_start) > 0) {
41 |     lines <- paste0("  ", x[html_start + 0:2])
42 |     if (!yep(
43 |       "First three lines of putative code are:\n",
44 |       glue_collapse(lines, sep = "\n"), "\n",
45 |       "which looks like html, not R code.\n",
46 |       "Are we going in circles? Did you just run `reprex(..., venue = \"html\")`?\n",
47 |       "In that case, the clipboard or selection now holds the *rendered* result.\n",
48 |       "Carry on with this reprex?"
49 |     )) {
50 |       cli::cli_abort("Cancelling.", call = quote(reprex()))
51 |     }
52 |   }
53 | 
54 |   x
55 | }
56 | 
57 | ensure_no_prompts <- function(x, prompt = getOption("prompt")) {
58 |   regex <- paste0("^", escape_regex(prompt))
59 |   prompts <- grepl(regex, x)
60 |   if (any(prompts)) {
61 |     reprex_info("Removing leading prompts from reprex source.")
62 |   }
63 |   sub(regex, "", x)
64 | }
65 | 


--------------------------------------------------------------------------------
/R/highlight.R:
--------------------------------------------------------------------------------
 1 | reprex_highlight <- function(rout_file, reprex_file, arg_string = NULL) {
 2 |   arg_string <- arg_string %||% highlight_args()
 3 |   cmd <- paste0(
 4 |     "highlight ",
 5 |     " -i ", shQuote(rout_file),
 6 |     " --out-format=rtf --no-trailing-nl --encoding=UTF-8",
 7 |     arg_string,
 8 |     " -o ", shQuote(reprex_file)
 9 |   )
10 |   if (is_windows()) {
11 |     res <- shell(cmd)
12 |   } else {
13 |     res <- system(cmd)
14 |   }
15 |   if (res > 0) {
16 |     # I am OK with a non-exported function appearing in this error.
17 |     # This whole feature is "use at your own risk".
18 |     cli::cli_abort(
19 |       "Call to the {.pkg highlight} command line tool was unsuccessful."
20 |     )
21 |   }
22 |   res
23 | }
24 | 
25 | rtf_requires_highlight <- function(venue) {
26 |   if (venue == "rtf" && !highlight_found()) {
27 |     # I am OK with a non-exported function appearing in this error.
28 |     # This whole feature is "use at your own risk".
29 |     cli::cli_abort(c(
30 |       "The {.pkg highlight} command line tool doesn't appear to be installed.",
31 |       '{.code venue = "rtf"} is only supported if R can find {.pkg highlight}.'
32 |     ))
33 |   }
34 |   invisible(venue)
35 | }
36 | 
37 | highlight_found <- function() Sys.which("highlight") != ""
38 | 
39 | highlight_args <- function() {
40 |   hl_style  <-         getOption("reprex.highlight.hl_style", "darkbone")
41 |   font      <- shQuote(getOption("reprex.highlight.font", "Courier Regular"))
42 |   font_size <-         getOption("reprex.highlight.font_size", 50)
43 |   other     <-         getOption("reprex.highlight.other", "")
44 | 
45 |   paste0(
46 |     " --style ",     hl_style,
47 |     " --font ",      font,
48 |     " --font-size ", font_size,
49 |     " ", other
50 |   )
51 | }
52 | 


--------------------------------------------------------------------------------
/R/prex.R:
--------------------------------------------------------------------------------
 1 | # nocov start
 2 | 
 3 | #' Render a "prex"
 4 | #'
 5 | #' @description
 6 | #' `prex()` is like [reprex()], but much less reproducible!
 7 | #'   * Code is evaluated in the global environment of the current R session.
 8 | #'   * Current working directory is used.
 9 | #'   * `advertise = FALSE` is the default.
10 | #' This violates many principles of a true reprex, which is why the `prex()`
11 | #' family of functions is unexported. The main motivation is to make
12 | #' `prex_rtf()` available for preparing code snippets that are scattered around
13 | #' a talk and that can't necessarily be self-contained.
14 | #'
15 | #' Specific `reprex()` arguments do not appear as `prex()` arguments or may have
16 | #' different capabilities (i.e., more limited).
17 | #' * `std_out_err`: not offered in `prex()`
18 | #'
19 | #' @noRd
20 | #' @keywords internal
21 | #'
22 | #' @examples
23 | #' # compare and contrast to get a feel for reprex() vs prex()
24 | #' reprex(ls())     # character(0)
25 | #' prex(ls())       # whatever is lying around your current workspace
26 | #'
27 | #' reprex(search()) # won't reflect anything you attach in .Rprofile
28 | #' prex(search())   # generally does reflect packages attached in .Rprofile
29 | #'
30 | #' reprex(getwd())  # a reprex directory below session temp directory
31 | #' prex(getwd())    # current working directory
32 | prex <- function(x = NULL,
33 |                  input = NULL,
34 |                  venue = c("gh", "r", "rtf", "html", "slack", "so", "ds"),
35 | 
36 |                  render = TRUE,
37 | 
38 |                  advertise       = FALSE,       # <-- different from reprex
39 |                  session_info    = opt(FALSE),
40 |                  style           = opt(FALSE),
41 |                  html_preview    = opt(TRUE),
42 |                  comment         = opt("#>"),
43 |                  tidyverse_quiet = opt(TRUE)) {
44 |   reprex_impl(
45 |     x_expr = substitute(x),
46 |     input = input,
47 |     wd = ".",                                   # <-- different from reprex
48 |     venue = venue,
49 | 
50 |     render = render,
51 |     new_session = FALSE,                        # <-- different from reprex()
52 | 
53 |     advertise       = advertise,
54 |     session_info    = session_info,
55 |     style           = style,
56 |     comment         = comment,
57 |     tidyverse_quiet = tidyverse_quiet,
58 |     std_out_err     = FALSE,                    # <-- different from reprex()
59 |     html_preview    = html_preview
60 |   )
61 | }
62 | 
63 | prex_html  <- function(...) prex(..., venue = "html")
64 | prex_r     <- function(...) prex(..., venue = "r")
65 | prex_rtf   <- function(...) prex(..., venue = "rtf")
66 | prex_slack <- function(...) prex(..., venue = "slack")
67 | 
68 | # these should exist for completeness, but I predict they'd never get used and
69 | # they just clutter the auto-complete landscape
70 | # prex_gh   <- function(...) prex(..., venue = "gh")
71 | # prex_so   <- function(...) prex(..., venue = "so")
72 | # prex_ds   <- function(...) prex(..., venue = "ds")
73 | 
74 | # nocov end
75 | 


--------------------------------------------------------------------------------
/R/reprex-addin.R:
--------------------------------------------------------------------------------
  1 | #' Render a reprex, conveniently
  2 | #'
  3 | #' @description `reprex_addin()` opens an [RStudio
  4 | #'   gadget](https://shiny.rstudio.com/articles/gadgets.html) and
  5 | #'   [addin](https://rstudio.github.io/rstudioaddins/) that allows you to say
  6 | #'   where the reprex source is (clipboard? current selection? active file?
  7 | #'   other file?) and to control a few other arguments. Appears as "Render
  8 | #'   reprex" in the RStudio Addins menu.
  9 | #'
 10 | #' @description `reprex_selection()` is an
 11 | #'   [addin](https://docs.posit.co/ide/user/ide/guide/productivity/add-ins.html) that reprexes the current
 12 | #'   selection, optionally customised by options. Appears as "Reprex selection"
 13 | #'   in the RStudio Addins menu. Heavy users might want to [create a keyboard
 14 | #'   shortcut](https://docs.posit.co/ide/user/ide/guide/productivity/custom-shortcuts.html).
 15 | #'   Suggested shortcut: Cmd + Shift + R (macOS) or Ctrl + Shift + R (Windows).
 16 | #'
 17 | #' @export
 18 | reprex_addin <- function() { # nocov start
 19 | 
 20 |   check_installed(
 21 |     c("shiny", "miniUI"),
 22 |     "in order to use the reprex addin"
 23 |   )
 24 |   resource_path <- path_package("reprex", "addins")
 25 |   shiny::addResourcePath("reprex_addins", resource_path)
 26 | 
 27 |   ui <- miniUI::miniPage(
 28 |     shiny::tags$head(shiny::includeCSS(path(resource_path, "reprex.css"))),
 29 |     miniUI::gadgetTitleBar(
 30 |       shiny::p(
 31 |         "Use",
 32 |         shiny::a(href = "https://reprex.tidyverse.org", "reprex"),
 33 |         "to render a bit of code"
 34 |       ),
 35 |       right = miniUI::miniTitleBarButton("done", "Render", primary = TRUE)
 36 |     ),
 37 |     miniUI::miniContentPanel(
 38 |       shiny::radioButtons(
 39 |         "source",
 40 |         "Where is reprex source?",
 41 |         c(
 42 |           "on the clipboard" = if (reprex_clipboard()) "clipboard",
 43 |           "current selection" = "cur_sel",
 44 |           "current file" = "cur_file",
 45 |           "another file" = "input_file"
 46 |         )
 47 |       ),
 48 |       shiny::conditionalPanel(
 49 |         condition = "input.source == 'input_file'",
 50 |         shiny::fileInput(
 51 |           inputId = "source_file",
 52 |           label = "Source file"
 53 |         )
 54 |       ),
 55 |       shiny::radioButtons(
 56 |         "venue",
 57 |         "Target venue:",
 58 |         c(
 59 |           "GitHub or Stack Overflow" = "gh",
 60 |           "R script (output appears as comments)" = "r",
 61 |           "HTML" = "html",
 62 |           "Rich Text Format" = "rtf",
 63 |           "Slack message" = "slack"
 64 |         ),
 65 |         selected = getOption("reprex.venue", "gh")
 66 |       ),
 67 |       shiny::tags$hr(),
 68 |       shiny::checkboxInput(
 69 |         "session_info",
 70 |         "Append session info",
 71 |         getOption("reprex.session_info", FALSE)
 72 |       ),
 73 |       shiny::checkboxInput(
 74 |         "html_preview",
 75 |         "Preview HTML",
 76 |         getOption("reprex.html_preview", TRUE)
 77 |       )
 78 |     )
 79 |   )
 80 | 
 81 |   server <- function(input, output, session) {
 82 |     shiny::observeEvent(input$done, {
 83 |       shiny::stopApp(reprex_guess(
 84 |         input$source,
 85 |         input$venue,
 86 |         input$source_file,
 87 |         as.logical(input$session_info),
 88 |         as.logical(input$html_preview)
 89 |       ))
 90 |     })
 91 |   }
 92 | 
 93 |   app <- shiny::shinyApp(ui, server, options = list(quiet = TRUE))
 94 |   shiny::runGadget(app, viewer = shiny::dialogViewer("Render reprex"))
 95 | }
 96 | 
 97 | reprex_guess <- function(source, venue = "gh", source_file = NULL,
 98 |                          session_info = FALSE, html_preview = FALSE) {
 99 |   reprex_input <- switch(source,
100 |     clipboard = NULL,
101 |     cur_sel = rstudio_selection(),
102 |     cur_file = rstudio_file(),
103 |     input_file = source_file$datapath
104 |   )
105 | 
106 |   reprex(
107 |     input = reprex_input,
108 |     venue = venue,
109 |     session_info = session_info,
110 |     html_preview = html_preview
111 |   )
112 | }
113 | 
114 | #' @export
115 | #' @rdname reprex_addin
116 | #' @inheritParams reprex
117 | reprex_selection <- function(venue = getOption("reprex.venue", "gh")) {
118 |   reprex(input = rstudio_selection(), venue = venue)
119 | }
120 | 
121 | # RStudio helpers ---------------------------------------------------------
122 | 
123 | rstudio_file <- function(context = rstudio_context()) {
124 |   rstudio_text_tidy(context$contents)
125 | }
126 | 
127 | rstudio_selection <- function(context = rstudio_context()) {
128 |   text <- rstudioapi::primary_selection(context)[["text"]]
129 |   rstudio_text_tidy(text)
130 | }
131 | 
132 | rstudio_context <- function() {
133 |   rstudioapi::getSourceEditorContext()
134 | }
135 | # nocov end
136 | 
137 | rstudio_text_tidy <- function(x) {
138 |   if (identical(x, "")) {
139 |     return(character())
140 |   }
141 |   Encoding(x) <- "UTF-8"
142 |   if (length(x) == 1) {
143 |     ## rstudio_selection() returns catenated text
144 |     x <- strsplit(x, "\n")[[1]]
145 |   }
146 | 
147 |   n <- length(x)
148 |   if (!grepl("\n$", x[[n]])) {
149 |     x[[n]] <- newline(x[[n]])
150 |   }
151 |   x
152 | }
153 | 


--------------------------------------------------------------------------------
/R/reprex-locale.R:
--------------------------------------------------------------------------------
  1 | #' Render a reprex in a specific locale
  2 | #'
  3 | #' Render a [reprex()], with control over the localization of error messages and
  4 | #' aspects of the locale. Note that these are related but distinct issues!
  5 | #' Typical usage is for someone on a Spanish system to create a reprex that is
  6 | #' easier for an English-speaking audience to follow.
  7 | #'
  8 | #' @section `language`:
  9 | #' Use the `language` argument to express the preferred language of error
 10 | #' messages. The output of `dir(system.file(package = "translations"))` may
 11 | #' provide some helpful ideas. The `language` should generally follow "XPG
 12 | #' syntax": a two-letter language code, optionally followed by other modifiers.
 13 | #'
 14 | #' Examples: `"en"`, `"de"`, `"en_GB"`, `"pt_BR"`.
 15 | #'
 16 | #' @section `locale`:
 17 | #' Use the `locale` argument only if you want to affect something like how
 18 | #' day-of-the-week or month is converted to character. You are less likely to
 19 | #' need to set this than the `language` argument. You may have more success
 20 | #' setting specific categories, such as `"LC_TIME"`, than multi-category
 21 | #' shortcuts like `"LC_ALL"` or `"LANG"`. The `locale` values must follow the
 22 | #' format dictated by your operating system and the requested locale must be
 23 | #' installed. On *nix systems, `locale -a` is a good way to see which locales
 24 | #' are installed. Note that the format for `locale` and `language` are different
 25 | #' from each other on Windows.
 26 | #'
 27 | #' Examples: `"en_CA.UTF-8"` (macOS), `"French_France.1252"` (Windows).
 28 | #'
 29 | #' @param ... Inputs passed through to [reprex()].
 30 | #' @param language A string specifying the preferred language for messages. It
 31 | #'   is enacted via the `LANGUAGE` environment variable, for the duration of the
 32 | #'   `reprex()` call. Examples: `"en"` for English and `"fr"` for French. See
 33 | #'   Details for more.
 34 | #' @param locale A named character vector, specifying aspects of the locale, in
 35 | #'   the [Sys.setlocale()] sense. It is enacted by setting one or more
 36 | #'   environment variables, for the duration of the `reprex()` call. See Details
 37 | #'   for more.
 38 | #'
 39 | #' @seealso
 40 | #'   * The [Locale
 41 | #'   Names](https://www.gnu.org/software/libc/manual/html_node/Locale-Names.html)
 42 | #'   section of the GNU C docs, for more about XPG syntax
 43 | #'   * The [Internationalization and
 44 | #'   Localization](https://cran.r-project.org/doc/manuals/r-patched/R-admin.html#Internationalization)
 45 | #'   section of the R Installation and Administration manual
 46 | #'
 47 | #' @return Character vector of rendered reprex, invisibly.
 48 | #' @examples
 49 | #' \dontrun{
 50 | #'
 51 | #' # if all you want to do is make sure messages are in English
 52 | #' reprex_locale("a" / 2)
 53 | #'
 54 | #' # change messages to a specific language
 55 | #' reprex_locale(
 56 | #'   {
 57 | #'     "a" / 2
 58 | #'   },
 59 | #'   language = "it"
 60 | #' )
 61 | #'
 62 | #' reprex_locale(
 63 | #'   {
 64 | #'     "a" / 2
 65 | #'   },
 66 | #'   language = "fr_CA"
 67 | #' )
 68 | #'
 69 | #' reprex_locale(
 70 | #'   {
 71 | #'     "a" / 2
 72 | #'   },
 73 | #'   language = "pt_BR"
 74 | #' )
 75 | #'
 76 | #' # get day-of-week and month to print in French (not Windows)
 77 | #' reprex_locale(
 78 | #'   {
 79 | #'     format(as.Date(c("2019-01-01", "2019-02-01")), "%a %b %d")
 80 | #'   },
 81 | #'   locale = c(LC_TIME = "fr_FR")
 82 | #' )
 83 | #'
 84 | #' # get day-of-week and month to print in French (Windows)
 85 | #' # assumes that the relevant language is installed on the system
 86 | #' # LC_TIME can also be specified as "French" or "French_France" here
 87 | #' reprex_locale(
 88 | #'   {
 89 | #'     format(as.Date(c("2019-01-01", "2019-02-01")), "%a %b %d")
 90 | #'   },
 91 | #'   locale = c(LC_TIME = "French_France.1252")
 92 | #' )
 93 | #' }
 94 | #' @export
 95 | reprex_locale <- function(...,
 96 |                           language = "en",
 97 |                           locale = NULL) {
 98 |   withr::local_envvar(c(LANGUAGE = language))
 99 |   if (!is.null(locale)) {
100 |     # If we use withr::local_locale(), the new locale is NOT inherited by the
101 |     # reprexing child process. Whereas it is if we use an env var approach.
102 |     withr::local_envvar(locale)
103 |   }
104 |   reprex(...)
105 | }
106 | 


--------------------------------------------------------------------------------
/R/reprex-options.R:
--------------------------------------------------------------------------------
  1 | #' reprex options
  2 | #'
  3 | #' @description
  4 | #' Some [reprex()] behaviour can be controlled via an option, providing a way
  5 | #' for the user to set personal defaults. The pattern for such option names is
  6 | #' `reprex.`, where `` is an argument of [reprex()]. Here are the main
  7 | #' ones:
  8 | #'   * `reprex.advertise`
  9 | #'   * `reprex.session_info` (previously, `reprex.si`)
 10 | #'   * `reprex.style`
 11 | #'   * `reprex.html_preview` (previously, `reprex.show`)
 12 | #'   * `reprex.comment`
 13 | #'   * `reprex.tidyverse_quiet`
 14 | #'   * `reprex.std_out_err`
 15 | #'
 16 | #' A few more options exist, but are only relevant to specific situations:
 17 | #'   * `reprex.venue`: Can be used to control the `venue` used by the
 18 | #'   [reprex_selection()] addin.
 19 | #'   * `reprex.current_venue`: Read-only option that is set during
 20 | #'   [reprex_render()]. Other packages that want to generate reprex-compatible
 21 | #'   output can consult it via `getOption("reprex.current_venue")`, if they want
 22 | #'   to tailor their output to the `venue`.
 23 | #'   * `reprex.clipboard`: When `FALSE`, reprex makes no attempt to access the
 24 | #'   user's clipboard, ever. This exists mostly for internal use, i.e. we set it
 25 | #'   to `FALSE` when we detect use from RStudio Server. But a user could set
 26 | #'   this to `FALSE` to explicitly opt-out of clipboard functionality. A Linux
 27 | #'   user with no intention of installing `xclip` or `xsel` might also do this.
 28 | #'   * `reprex.highlight.hl_style`: Only relevant to `venue = "rtf`. Details are
 29 | #'     in the article
 30 | #'     [reprex venue RTF](https://reprex.tidyverse.org/articles/articles/rtf.html).
 31 | #'   * `reprex.highlight.font`: See above.
 32 | #'   * `reprex.highlight.font_size`: See above.
 33 | #'   * `reprex.highlight.other`: See above.
 34 | #'
 35 | #' Here's code you could put in `.Rprofile` to set reprex options. It would be
 36 | #' rare to want non-default behaviour for all of these! We only do so here for
 37 | #' the sake of exposition:
 38 | #' ```
 39 | #' options(
 40 | #'   reprex.advertise       = FALSE,
 41 | #'   reprex.session_info    = TRUE,
 42 | #'   reprex.style           = TRUE,
 43 | #'   reprex.html_preview    = FALSE,
 44 | #'   reprex.comment         = "#;-)",
 45 | #'   reprex.tidyverse_quiet = FALSE,
 46 | #'   reprex.std_out_err     = TRUE,
 47 | #'   reprex.venue           = "html", # NOTE: only affects reprex_selection()!
 48 | #'   reprex.highlight.hl_style  = "acid", # NOTE: only affects RTF venue
 49 | #'   reprex.highlight.font      = "Andale Mono Regular",
 50 | #'   reprex.highlight.font_size = 35,
 51 | #'   reprex.highlight.other     = "--line-numbers"
 52 | #' )
 53 | #' ```
 54 | #' The function `usethis::edit_r_profile()` is handy for creating and/or opening
 55 | #' your `.Rprofile`.
 56 | #'
 57 | #' @section Explaining the `opt()` helper:
 58 | #' Arguments that appear like so in [reprex()]:
 59 | #' ```
 60 | #' reprex(..., arg = opt(DEFAULT), ...)
 61 | #' ````
 62 | #' get their value according to this logic:
 63 | #' ```
 64 | #' user-specified value or, if not given,
 65 | #'   getOption("reprex.arg") or, if does not exist,
 66 | #'     DEFAULT
 67 | #' ```
 68 | #' It's shorthand for:
 69 | #' ```
 70 | #' f(..., arg = getOption("reprex.arg", DEFAULT), ...)
 71 | #' ```
 72 | #' This is not an exported function and should not be called directly.
 73 | #'
 74 | #' @name reprex_options
 75 | #' @aliases opt
 76 | NULL
 77 | 
 78 | optionally <- function(x, opt_name = NA_character_) {
 79 |   if (!is.na(opt_name)) {
 80 |     attr(x, "opt_name") <- opt_name
 81 |   }
 82 |   attr(x, "optional") <- TRUE
 83 |   x
 84 | }
 85 | 
 86 | opt <- optionally
 87 | 
 88 | arg_option <- function(arg) {
 89 |   arg_expr <- enexpr(arg)
 90 |   if (!is_symbol(arg_expr)) {
 91 |     cli::cli_abort(
 92 |       "{.fun arg_option} expects a symbol.",
 93 |       .internal = TRUE
 94 |     )
 95 |   }
 96 | 
 97 |   opt_name <- attr(arg, "opt_name") %||% make_opt_name(as_string(arg_expr))
 98 | 
 99 |   if (is_optional(arg)) {
100 |     getOption(opt_name) %||% de_opt(arg)
101 |   } else {
102 |     arg
103 |   }
104 | }
105 | 
106 | is_optional <- function(x) isTRUE(attr(x, "optional"))
107 | 
108 | de_opt <- function(x) {
109 |   attr(x, "optional") <- NULL
110 |   attr(x, "opt_name") <- NULL
111 |   x
112 | }
113 | 
114 | make_opt_name <- function(x) {
115 |   pkg_name <- tryCatch(ns_env_name(), error = function(e) NULL)
116 |   paste(c(pkg_name, x), collapse = ".")
117 | }
118 | 


--------------------------------------------------------------------------------
/R/reprex-package.R:
--------------------------------------------------------------------------------
 1 | #' @keywords internal
 2 | "_PACKAGE"
 3 | 
 4 | ## usethis namespace: start
 5 | #' @import fs
 6 | #' @import rlang
 7 | #' @importFrom glue glue
 8 | #' @importFrom glue glue_collapse
 9 | #' @importFrom lifecycle deprecated
10 | ## usethis namespace: end
11 | NULL
12 | 


--------------------------------------------------------------------------------
/R/stringify_expression.R:
--------------------------------------------------------------------------------
 1 | ## input is quote()'ed expression
 2 | ## reprex() takes care of that or, to use directly:
 3 | ## x <- quote({a + b})
 4 | 
 5 | stringify_expression <- function(x) {
 6 |   if (is.null(x)) {
 7 |     return(NULL)
 8 |   }
 9 | 
10 |   .srcref <- utils::getSrcref(x)
11 | 
12 |   if (is.null(.srcref)) {
13 |     return(enc2utf8(deparse(x)))
14 |   }
15 | 
16 |   ## Construct a new srcref with the first_line, first_byte, etc. from the
17 |   ## first expression and the last_line, last_byte, etc. from the last one.
18 |   first_src <- .srcref[[1]]
19 |   last_src <- .srcref[[length(.srcref)]]
20 | 
21 |   .srcfile <- attr(first_src, "srcfile")
22 | 
23 |   src <- srcref(
24 |     .srcfile,
25 |     c(
26 |       first_src[[1]], first_src[[2]],
27 |       last_src[[3]], last_src[[4]],
28 |       first_src[[5]], last_src[[6]],
29 |       first_src[[7]], last_src[[8]]
30 |     )
31 |   )
32 | 
33 |   lines <- enc2utf8(as.character(src, useSource = TRUE))
34 | 
35 |   ## remove the first brace and line if the brace is the only thing on the line
36 |   lines[[1L]] <- sub("^[{]", "", lines[[1L]])
37 |   if (!nzchar(lines[[1L]])) {
38 |     lines <- lines[-1L]
39 |   }
40 | 
41 |   ## identify the last source line affiliated with an expression
42 |   n <- utils::getSrcLocation(last_src, which = "line", first = FALSE)
43 | 
44 |   ## rescue trailing comment on (current) last surviving line
45 |   last_source_line <- getSrcLines(.srcfile, n, n) ## "raw"
46 |   last_line <- lines[length(lines)] ## srcref'd
47 |   m <- regexpr(last_line, last_source_line, fixed = TRUE)
48 |   rescue_me <- substring(last_source_line, m + attr(m, "match.length"))
49 |   if (grepl("^\\s*#", rescue_me)) {
50 |     lines[length(lines)] <- paste0(last_line, rescue_me)
51 |   }
52 | 
53 |   ## rescue trailing comment lines
54 |   tail_lines <- getSrcLines(.srcfile, n + 1, Inf)
55 |   closing_bracket_line <- max(grep("^\\s*[}]", tail_lines), 0)
56 |   tail_lines <- utils::head(tail_lines, closing_bracket_line - 1)
57 | 
58 |   trim_common_leading_ws(c(lines, tail_lines))
59 | }
60 | 


--------------------------------------------------------------------------------
/R/sysdata.rda:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tidyverse/reprex/07cd5d74fd25005523a57db97589ff8c3e74c02f/R/sysdata.rda


--------------------------------------------------------------------------------
/R/utils-clipboard.R:
--------------------------------------------------------------------------------
 1 | ingest_clipboard <- function() {
 2 |   if (reprex_clipboard()) {
 3 |     return(suppressWarnings(
 4 |       enc2utf8(clipr::read_clip() %||% character())
 5 |     ))
 6 |   }
 7 |   reprex_warning("No input provided and clipboard is not available.")
 8 |   character()
 9 | }
10 | 
11 | write_clip_windows_rtf <- function(path) {
12 |   path <- gsub("\\s", "` ", path)
13 |   cmd <- glue('
14 |     powershell -Command "\\
15 |     Add-Type -AssemblyName System.Windows.Forms | Out-Null;\\
16 |     [Windows.Forms.Clipboard]::SetText(
17 |     (Get-Content -Raw {path}),\\
18 |     [Windows.Forms.TextDataFormat]::Rtf
19 |     )"')
20 |   res <- system(cmd)
21 |   if (res > 0) {
22 |     # abort("Failed to put RTF on the Windows clipboard")
23 |     reprex_danger("Failed to put RTF on the Windows clipboard :(")
24 |     invisible(FALSE)
25 |   } else {
26 |     invisible(TRUE)
27 |   }
28 | }
29 | 
30 | # reports clipr::clipr_available(), with some exceptions and niceties
31 | # - if we detect RStudio server, hard FALSE
32 | # - otherwise, if clipr_available() reports FALSE, call dr_clipr() ONCE
33 | # - use an option to persist this finding in current session
34 | reprex_clipboard <- function() {
35 |   x <- getOption("reprex.clipboard", NA)
36 |   if (length(x) != 1 || !is.logical(x)) {
37 |     cli::cli_abort("
38 |       The {.arg reprex.clipboard} option must be {.code TRUE}, {.code FALSE}, \\
39 |       or (logical) {.code NA}.",
40 |       call = NULL
41 |     )
42 |   }
43 |   if (is_rstudio_server()) {
44 |     x <- FALSE
45 |     options(reprex.clipboard = x)
46 |   }
47 |   if (is.na(x)) {
48 |     y <- clipr::clipr_available()
49 |     if (isFALSE(y)) {
50 |       clipr::dr_clipr()
51 |     }
52 |     options(reprex.clipboard = y)
53 |   }
54 |   getOption("reprex.clipboard")
55 | }
56 | 


--------------------------------------------------------------------------------
/R/utils-interactivity.R:
--------------------------------------------------------------------------------
 1 | interactive <- function(...) {
 2 |   cli::cli_abort("
 3 |     Inside {.pkg reprex}, we use {.fun rlang::is_interactive}, \\
 4 |     not {.fun interactive}, for mocking reasons.",
 5 |     .internal = TRUE
 6 |   )
 7 | }
 8 | 
 9 | ## returns TRUE if user says "no"
10 | ##         FALSE otherwise
11 | nope <- function(..., yes = "yes", no = "no") {
12 |   if (is_interactive()) {
13 |     cat(paste0(..., collapse = ""))
14 |     return(utils::menu(c(yes, no)) == 2)
15 |   }
16 |   FALSE
17 | }
18 | 
19 | ## returns TRUE if user says "yes"
20 | ##         FALSE otherwise
21 | yep <- function(..., yes = "yes", no = "no") {
22 |   if (is_interactive()) {
23 |     cat(paste0(..., collapse = ""))
24 |     return(utils::menu(c(yes, no)) == 1)
25 |   }
26 |   FALSE
27 | }
28 | 


--------------------------------------------------------------------------------
/R/utils-ui.R:
--------------------------------------------------------------------------------
 1 | reprex_quiet <- function() {
 2 |   as.logical(Sys.getenv("REPREX_QUIET", unset = "NA"))
 3 | }
 4 | 
 5 | local_reprex_quiet <- function(reprex_quiet = "TRUE", env = parent.frame()) {
 6 |   withr::local_envvar(c(REPREX_QUIET = reprex_quiet), .local_envir = env)
 7 | }
 8 | 
 9 | local_reprex_loud <- function(env = parent.frame()) {
10 |   local_reprex_quiet("FALSE", env = env)
11 | }
12 | 
13 | reprex_alert <- function(text,
14 |                          type = c("success", "info", "warning", "danger"),
15 |                          .envir = parent.frame()) {
16 |   quiet <- reprex_quiet() %|% is_testing()
17 |   if (quiet) {
18 |     return(invisible())
19 |   }
20 |   cli_fun <- switch(type,
21 |     success = cli::cli_alert_success,
22 |     info    = cli::cli_alert_info,
23 |     warning = cli::cli_alert_warning,
24 |     danger  = cli::cli_alert_danger,
25 |     cli::cli_alert
26 |   )
27 |   cli_fun(text = text, wrap = TRUE, .envir = .envir)
28 | }
29 | 
30 | reprex_success <- function(text, .envir = parent.frame()) {
31 |   reprex_alert(text, type = "success", .envir = .envir)
32 | }
33 | 
34 | reprex_info <- function(text, .envir = parent.frame()) {
35 |   reprex_alert(text, type = "info", .envir = .envir)
36 | }
37 | 
38 | reprex_warning <- function(text, .envir = parent.frame()) {
39 |   reprex_alert(text, type = "warning", .envir = .envir)
40 | }
41 | 
42 | reprex_danger <- function(text, .envir = parent.frame()) {
43 |   reprex_alert(text, type = "danger", .envir = .envir)
44 | }
45 | 
46 | # TODO: if a better built-in solution arises in the semantic UI, use it
47 | # https://github.com/r-lib/cli/issues/211
48 | reprex_path <- function(header, path, type = "success", .envir = parent.frame()) {
49 |   quiet <- reprex_quiet() %|% is_testing()
50 |   if (quiet) {
51 |     return(invisible())
52 |   }
53 |   reprex_alert(header, type = type, .envir = .envir)
54 |   cli::cli_div(theme = list(.alert = list(`margin-left` = 2, before = "")))
55 |   cli::cli_alert("{.path {path}}")
56 |   cli::cli_end()
57 | }
58 | 
59 | message <- function(...) {
60 |   cli::cli_abort(
61 |     "Inside {.pkg reprex}, we use our own UI functions, not {.fun message}.",
62 |     .internal = TRUE
63 |   )
64 | }
65 | 


--------------------------------------------------------------------------------
/R/utils.R:
--------------------------------------------------------------------------------
 1 | is_windows <- function() {
 2 |   .Platform$OS.type == "windows"
 3 | }
 4 | 
 5 | is_path <- function(x) {
 6 |   length(x) == 1 && is.character(x) && !grepl("\n$", x)
 7 | }
 8 | 
 9 | isFALSE <- function(x) identical(x, FALSE)
10 | 
11 | is_rstudio_server <- function() {
12 |   if (rstudioapi::hasFun("versionInfo")) {
13 |     rstudioapi::versionInfo()$mode == "server"
14 |   } else {
15 |     FALSE
16 |   }
17 | }
18 | 
19 | in_rstudio <- function() {
20 |   .Platform$GUI == "RStudio"
21 | }
22 | 
23 | trim_ws <- function(x) {
24 |   sub("\\s*$", "", sub("^\\s*", "", x))
25 | }
26 | 
27 | trim_common_leading_ws <- function(x) {
28 |   m <- regexpr("^(\\s*)", x)
29 |   n_chars <- nchar(x)
30 |   n_spaces <- attr(m, which = "match.length")
31 |   num <- min(n_spaces[n_chars > 0])
32 |   substring(x, num + 1)
33 | }
34 | 
35 | escape_regex <- function(x) {
36 |   chars <- c("*", ".", "?", "^", "+", "$", "|", "(", ")", "[", "]", "{", "}", "\\")
37 |   gsub(paste0("([\\", paste(chars, collapse = "\\"), "])"), "\\\\\\1", x, perl = TRUE)
38 | }
39 | 
40 | escape_newlines <- function(x) {
41 |   gsub("\n", "\\\\n", x, perl = TRUE)
42 | }
43 | 
44 | roxygen_comment <- function(x) paste0("#' ", x)
45 | 
46 | r_chunk <- function(code, label = NULL) {
47 |   c(sprintf("```{r %s}", label %||% ""), label, code, "```")
48 | }
49 | 
50 | details <- function(txt, desc = "Details") {
51 |   c(
52 |     "
", 53 | glue("{desc}"), 54 | txt, 55 | "
" 56 | ) 57 | } 58 | 59 | backtick <- function(x) encodeString(x, quote = "`") 60 | 61 | newline <- function(x) paste0(x, "\n") 62 | 63 | is_testing <- function() { 64 | identical(Sys.getenv("TESTTHAT"), "true") 65 | } 66 | 67 | is_dark_mode <- function() { 68 | if (rstudioapi::isAvailable() && rstudioapi::hasFun("getThemeInfo")) { 69 | theme_info <- rstudioapi::getThemeInfo() 70 | theme_info$dark 71 | } else { 72 | FALSE 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /R/venues.R: -------------------------------------------------------------------------------- 1 | # nocov start 2 | 3 | #' Venue-specific shortcuts 4 | #' 5 | #' These are thin wrappers around `reprex()` that incorporate the target `venue` 6 | #' as a suffix in the function name, for easier access via auto-completion. 7 | #' 8 | #' @param ... Passed along to [reprex()]. 9 | #' 10 | #' @name reprex_venue 11 | NULL 12 | 13 | #' @export 14 | #' @rdname reprex_venue 15 | reprex_html <- function(...) reprex(..., venue = "html") 16 | 17 | #' @export 18 | #' @rdname reprex_venue 19 | reprex_r <- function(...) reprex(..., venue = "r") 20 | 21 | #' @export 22 | #' @rdname reprex_venue 23 | reprex_rtf <- function(...) reprex(..., venue = "rtf") 24 | 25 | #' @export 26 | #' @rdname reprex_venue 27 | reprex_slack <- function(...) reprex(..., venue = "slack") 28 | 29 | # these should exist for completeness, but I predict they'd never get used and 30 | # they just clutter the auto-complete landscape 31 | # reprex_gh <- function(...) reprex(..., venue = "gh") 32 | # reprex_so <- function(...) reprex(..., venue = "so") 33 | # reprex_ds <- function(...) reprex(..., venue = "ds") 34 | 35 | # nocov ends 36 | 37 | normalize_venue <- function(venue) { 38 | venue <- ds_is_gh(venue) 39 | venue <- so_is_gh(venue) 40 | venue <- rtf_requires_highlight(venue) 41 | venue 42 | } 43 | 44 | ds_is_gh <- function(venue) { 45 | if (venue == "ds") { 46 | reprex_info(' 47 | The Discourse venue "ds" is an alias for the default GitHub venue "gh". 48 | There is no need to specify the venue.') 49 | venue <- "gh" 50 | } 51 | venue 52 | } 53 | 54 | so_is_gh <- function(venue) { 55 | if (venue == "so") { 56 | reprex_info(' 57 | The Stack Overflow venue "so" is an alias for the default GitHub venue 58 | "gh". There is no need to specify the venue.') 59 | venue <- "gh" 60 | } 61 | venue 62 | } 63 | -------------------------------------------------------------------------------- /_pkgdown.yml: -------------------------------------------------------------------------------- 1 | url: https://reprex.tidyverse.org 2 | 3 | template: 4 | package: tidytemplate 5 | bootstrap: 5 6 | 7 | includes: 8 | in_header: | 9 | 10 | 11 | development: 12 | mode: auto 13 | 14 | news: 15 | releases: 16 | - text: "reprex 2.0.0" 17 | href: https://www.tidyverse.org/blog/2021/04/reprex-2-0-0/ 18 | - text: "reprex 1.0.0" 19 | href: https://www.tidyverse.org/blog/2021/02/reprex-1-0-0/ 20 | 21 | reference: 22 | - title: The main function 23 | contents: 24 | - reprex 25 | - title: Convenience 26 | contents: 27 | - reprex_addin 28 | - reprex_venue 29 | - reprex_locale 30 | - title: Going backwards 31 | contents: 32 | - reprex_clean 33 | - title: Internals 34 | contents: 35 | - reprex_options 36 | - reprex_document 37 | - reprex_render 38 | 39 | articles: 40 | - title: Pro tips 41 | navbar: ~ 42 | contents: 43 | - reprex-dos-and-donts 44 | - articles/rtf 45 | - articles/datapasta-reprex 46 | - articles/suppress-startup-messages 47 | 48 | - title: How to use reprex 49 | contents: 50 | - articles/learn-reprex 51 | - articles/magic-reprex 52 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | comment: false 2 | 3 | coverage: 4 | status: 5 | project: 6 | default: 7 | target: auto 8 | threshold: 1% 9 | informational: true 10 | patch: 11 | default: 12 | target: auto 13 | threshold: 1% 14 | informational: true 15 | -------------------------------------------------------------------------------- /cran-comments.md: -------------------------------------------------------------------------------- 1 | ## revdepcheck results 2 | 3 | We checked 6 reverse dependencies, comparing R CMD check results across CRAN and dev versions of this package. 4 | 5 | * We saw 0 new problems 6 | * We failed to check 0 packages 7 | -------------------------------------------------------------------------------- /data-raw/adjective_animal.R: -------------------------------------------------------------------------------- 1 | ## code to prepare `adjective_animal` dataset goes here 2 | library(ids) 3 | 4 | set.seed(1031) 5 | adjective_animal <- adjective_animal(n = 100, max_len = 5, style = "kebab") 6 | anyDuplicated(adjective_animal) 7 | 8 | usethis::use_data(adjective_animal, internal = TRUE, overwrite = TRUE) 9 | -------------------------------------------------------------------------------- /data-raw/github_css.R: -------------------------------------------------------------------------------- 1 | # use the CSS found here: 2 | # https://github.com/sindresorhus/github-markdown-css 3 | # which aims to be: 4 | # "The minimal amount of CSS to replicate the GitHub Markdown style" 5 | 6 | library(usethis) 7 | 8 | use_directory("inst/rmarkdown/templates/reprex_document/resources") 9 | 10 | use_github_file( 11 | repo_spec = "sindresorhus/github-markdown-css", 12 | path = "github-markdown-dark.css", 13 | save_as = "inst/rmarkdown/templates/reprex_document/resources/github-dark.css" 14 | ) 15 | 16 | use_github_file( 17 | repo_spec = "sindresorhus/github-markdown-css", 18 | path = "github-markdown-light.css", 19 | save_as = "inst/rmarkdown/templates/reprex_document/resources/github-light.css" 20 | ) 21 | -------------------------------------------------------------------------------- /data-raw/r-syntax-definition.R: -------------------------------------------------------------------------------- 1 | library(usethis) 2 | 3 | # the true source lives in KDE's GitLab instance, but I think this GitHub mirror 4 | # is good enough 5 | # https://invent.kde.org/frameworks/syntax-highlighting 6 | # https://github.com/KDE/syntax-highlighting/blob/master/data/syntax/r.xml 7 | use_github_file( 8 | repo_spec = "KDE/syntax-highlighting", 9 | path = "data/syntax/r.xml", 10 | save_as = "data-raw/r.xml" 11 | ) 12 | 13 | fs::file_copy( 14 | "data-raw/r.xml", 15 | "inst/rmarkdown/templates/reprex_document/resources/r.xml" 16 | ) 17 | 18 | # I then made some edits in the itemDatas section 19 | # I changed some of the default styles 20 | -------------------------------------------------------------------------------- /data-raw/starry-night-dark.css: -------------------------------------------------------------------------------- 1 | /* This is a theme distributed by `starry-night`. 2 | * It’s based on what GitHub uses on their site. 3 | * See for more info. */ 4 | :root { 5 | --color-prettylights-syntax-comment: #9198a1; 6 | --color-prettylights-syntax-constant: #79c0ff; 7 | --color-prettylights-syntax-constant-other-reference-link: #a5d6ff; 8 | --color-prettylights-syntax-entity: #d2a8ff; 9 | --color-prettylights-syntax-storage-modifier-import: #f0f6fc; 10 | --color-prettylights-syntax-entity-tag: #7ee787; 11 | --color-prettylights-syntax-keyword: #ff7b72; 12 | --color-prettylights-syntax-string: #a5d6ff; 13 | --color-prettylights-syntax-variable: #ffa657; 14 | --color-prettylights-syntax-brackethighlighter-unmatched: #f85149; 15 | --color-prettylights-syntax-brackethighlighter-angle: #9198a1; 16 | --color-prettylights-syntax-invalid-illegal-text: #f0f6fc; 17 | --color-prettylights-syntax-invalid-illegal-bg: #8e1519; 18 | --color-prettylights-syntax-carriage-return-text: #f0f6fc; 19 | --color-prettylights-syntax-carriage-return-bg: #b62324; 20 | --color-prettylights-syntax-string-regexp: #7ee787; 21 | --color-prettylights-syntax-markup-list: #f2cc60; 22 | --color-prettylights-syntax-markup-heading: #1f6feb; 23 | --color-prettylights-syntax-markup-italic: #f0f6fc; 24 | --color-prettylights-syntax-markup-bold: #f0f6fc; 25 | --color-prettylights-syntax-markup-deleted-text: #ffdcd7; 26 | --color-prettylights-syntax-markup-deleted-bg: #67060c; 27 | --color-prettylights-syntax-markup-inserted-text: #aff5b4; 28 | --color-prettylights-syntax-markup-inserted-bg: #033a16; 29 | --color-prettylights-syntax-markup-changed-text: #ffdfb6; 30 | --color-prettylights-syntax-markup-changed-bg: #5a1e02; 31 | --color-prettylights-syntax-markup-ignored-text: #f0f6fc; 32 | --color-prettylights-syntax-markup-ignored-bg: #1158c7; 33 | --color-prettylights-syntax-meta-diff-range: #d2a8ff; 34 | --color-prettylights-syntax-sublimelinter-gutter-mark: #3d444d; 35 | } 36 | 37 | .pl-c { 38 | color: var(--color-prettylights-syntax-comment); 39 | } 40 | 41 | .pl-c1, 42 | .pl-s .pl-v { 43 | color: var(--color-prettylights-syntax-constant); 44 | } 45 | 46 | .pl-e, 47 | .pl-en { 48 | color: var(--color-prettylights-syntax-entity); 49 | } 50 | 51 | .pl-smi, 52 | .pl-s .pl-s1 { 53 | color: var(--color-prettylights-syntax-storage-modifier-import); 54 | } 55 | 56 | .pl-ent { 57 | color: var(--color-prettylights-syntax-entity-tag); 58 | } 59 | 60 | .pl-k { 61 | color: var(--color-prettylights-syntax-keyword); 62 | } 63 | 64 | .pl-s, 65 | .pl-pds, 66 | .pl-s .pl-pse .pl-s1, 67 | .pl-sr, 68 | .pl-sr .pl-cce, 69 | .pl-sr .pl-sre, 70 | .pl-sr .pl-sra { 71 | color: var(--color-prettylights-syntax-string); 72 | } 73 | 74 | .pl-v, 75 | .pl-smw { 76 | color: var(--color-prettylights-syntax-variable); 77 | } 78 | 79 | .pl-bu { 80 | color: var(--color-prettylights-syntax-brackethighlighter-unmatched); 81 | } 82 | 83 | .pl-ii { 84 | color: var(--color-prettylights-syntax-invalid-illegal-text); 85 | background-color: var(--color-prettylights-syntax-invalid-illegal-bg); 86 | } 87 | 88 | .pl-c2 { 89 | color: var(--color-prettylights-syntax-carriage-return-text); 90 | background-color: var(--color-prettylights-syntax-carriage-return-bg); 91 | } 92 | 93 | .pl-sr .pl-cce { 94 | font-weight: bold; 95 | color: var(--color-prettylights-syntax-string-regexp); 96 | } 97 | 98 | .pl-ml { 99 | color: var(--color-prettylights-syntax-markup-list); 100 | } 101 | 102 | .pl-mh, 103 | .pl-mh .pl-en, 104 | .pl-ms { 105 | font-weight: bold; 106 | color: var(--color-prettylights-syntax-markup-heading); 107 | } 108 | 109 | .pl-mi { 110 | font-style: italic; 111 | color: var(--color-prettylights-syntax-markup-italic); 112 | } 113 | 114 | .pl-mb { 115 | font-weight: bold; 116 | color: var(--color-prettylights-syntax-markup-bold); 117 | } 118 | 119 | .pl-md { 120 | color: var(--color-prettylights-syntax-markup-deleted-text); 121 | background-color: var(--color-prettylights-syntax-markup-deleted-bg); 122 | } 123 | 124 | .pl-mi1 { 125 | color: var(--color-prettylights-syntax-markup-inserted-text); 126 | background-color: var(--color-prettylights-syntax-markup-inserted-bg); 127 | } 128 | 129 | .pl-mc { 130 | color: var(--color-prettylights-syntax-markup-changed-text); 131 | background-color: var(--color-prettylights-syntax-markup-changed-bg); 132 | } 133 | 134 | .pl-mi2 { 135 | color: var(--color-prettylights-syntax-markup-ignored-text); 136 | background-color: var(--color-prettylights-syntax-markup-ignored-bg); 137 | } 138 | 139 | .pl-mdr { 140 | font-weight: bold; 141 | color: var(--color-prettylights-syntax-meta-diff-range); 142 | } 143 | 144 | .pl-ba { 145 | color: var(--color-prettylights-syntax-brackethighlighter-angle); 146 | } 147 | 148 | .pl-sg { 149 | color: var(--color-prettylights-syntax-sublimelinter-gutter-mark); 150 | } 151 | 152 | .pl-corl { 153 | text-decoration: underline; 154 | color: var(--color-prettylights-syntax-constant-other-reference-link); 155 | } 156 | -------------------------------------------------------------------------------- /data-raw/starry-night-light.css: -------------------------------------------------------------------------------- 1 | /* This is a theme distributed by `starry-night`. 2 | * It’s based on what GitHub uses on their site. 3 | * See for more info. */ 4 | :root { 5 | --color-prettylights-syntax-comment: #59636e; 6 | --color-prettylights-syntax-constant: #0550ae; 7 | --color-prettylights-syntax-constant-other-reference-link: #0a3069; 8 | --color-prettylights-syntax-entity: #6639ba; 9 | --color-prettylights-syntax-storage-modifier-import: #1f2328; 10 | --color-prettylights-syntax-entity-tag: #0550ae; 11 | --color-prettylights-syntax-keyword: #cf222e; 12 | --color-prettylights-syntax-string: #0a3069; 13 | --color-prettylights-syntax-variable: #953800; 14 | --color-prettylights-syntax-brackethighlighter-unmatched: #82071e; 15 | --color-prettylights-syntax-brackethighlighter-angle: #59636e; 16 | --color-prettylights-syntax-invalid-illegal-text: #f6f8fa; 17 | --color-prettylights-syntax-invalid-illegal-bg: #82071e; 18 | --color-prettylights-syntax-carriage-return-text: #f6f8fa; 19 | --color-prettylights-syntax-carriage-return-bg: #cf222e; 20 | --color-prettylights-syntax-string-regexp: #116329; 21 | --color-prettylights-syntax-markup-list: #3b2300; 22 | --color-prettylights-syntax-markup-heading: #0550ae; 23 | --color-prettylights-syntax-markup-italic: #1f2328; 24 | --color-prettylights-syntax-markup-bold: #1f2328; 25 | --color-prettylights-syntax-markup-deleted-text: #82071e; 26 | --color-prettylights-syntax-markup-deleted-bg: #ffebe9; 27 | --color-prettylights-syntax-markup-inserted-text: #116329; 28 | --color-prettylights-syntax-markup-inserted-bg: #dafbe1; 29 | --color-prettylights-syntax-markup-changed-text: #953800; 30 | --color-prettylights-syntax-markup-changed-bg: #ffd8b5; 31 | --color-prettylights-syntax-markup-ignored-text: #d1d9e0; 32 | --color-prettylights-syntax-markup-ignored-bg: #0550ae; 33 | --color-prettylights-syntax-meta-diff-range: #8250df; 34 | --color-prettylights-syntax-sublimelinter-gutter-mark: #818b98; 35 | } 36 | 37 | .pl-c { 38 | color: var(--color-prettylights-syntax-comment); 39 | } 40 | 41 | .pl-c1, 42 | .pl-s .pl-v { 43 | color: var(--color-prettylights-syntax-constant); 44 | } 45 | 46 | .pl-e, 47 | .pl-en { 48 | color: var(--color-prettylights-syntax-entity); 49 | } 50 | 51 | .pl-smi, 52 | .pl-s .pl-s1 { 53 | color: var(--color-prettylights-syntax-storage-modifier-import); 54 | } 55 | 56 | .pl-ent { 57 | color: var(--color-prettylights-syntax-entity-tag); 58 | } 59 | 60 | .pl-k { 61 | color: var(--color-prettylights-syntax-keyword); 62 | } 63 | 64 | .pl-s, 65 | .pl-pds, 66 | .pl-s .pl-pse .pl-s1, 67 | .pl-sr, 68 | .pl-sr .pl-cce, 69 | .pl-sr .pl-sre, 70 | .pl-sr .pl-sra { 71 | color: var(--color-prettylights-syntax-string); 72 | } 73 | 74 | .pl-v, 75 | .pl-smw { 76 | color: var(--color-prettylights-syntax-variable); 77 | } 78 | 79 | .pl-bu { 80 | color: var(--color-prettylights-syntax-brackethighlighter-unmatched); 81 | } 82 | 83 | .pl-ii { 84 | color: var(--color-prettylights-syntax-invalid-illegal-text); 85 | background-color: var(--color-prettylights-syntax-invalid-illegal-bg); 86 | } 87 | 88 | .pl-c2 { 89 | color: var(--color-prettylights-syntax-carriage-return-text); 90 | background-color: var(--color-prettylights-syntax-carriage-return-bg); 91 | } 92 | 93 | .pl-sr .pl-cce { 94 | font-weight: bold; 95 | color: var(--color-prettylights-syntax-string-regexp); 96 | } 97 | 98 | .pl-ml { 99 | color: var(--color-prettylights-syntax-markup-list); 100 | } 101 | 102 | .pl-mh, 103 | .pl-mh .pl-en, 104 | .pl-ms { 105 | font-weight: bold; 106 | color: var(--color-prettylights-syntax-markup-heading); 107 | } 108 | 109 | .pl-mi { 110 | font-style: italic; 111 | color: var(--color-prettylights-syntax-markup-italic); 112 | } 113 | 114 | .pl-mb { 115 | font-weight: bold; 116 | color: var(--color-prettylights-syntax-markup-bold); 117 | } 118 | 119 | .pl-md { 120 | color: var(--color-prettylights-syntax-markup-deleted-text); 121 | background-color: var(--color-prettylights-syntax-markup-deleted-bg); 122 | } 123 | 124 | .pl-mi1 { 125 | color: var(--color-prettylights-syntax-markup-inserted-text); 126 | background-color: var(--color-prettylights-syntax-markup-inserted-bg); 127 | } 128 | 129 | .pl-mc { 130 | color: var(--color-prettylights-syntax-markup-changed-text); 131 | background-color: var(--color-prettylights-syntax-markup-changed-bg); 132 | } 133 | 134 | .pl-mi2 { 135 | color: var(--color-prettylights-syntax-markup-ignored-text); 136 | background-color: var(--color-prettylights-syntax-markup-ignored-bg); 137 | } 138 | 139 | .pl-mdr { 140 | font-weight: bold; 141 | color: var(--color-prettylights-syntax-meta-diff-range); 142 | } 143 | 144 | .pl-ba { 145 | color: var(--color-prettylights-syntax-brackethighlighter-angle); 146 | } 147 | 148 | .pl-sg { 149 | color: var(--color-prettylights-syntax-sublimelinter-gutter-mark); 150 | } 151 | 152 | .pl-corl { 153 | text-decoration: underline; 154 | color: var(--color-prettylights-syntax-constant-other-reference-link); 155 | } 156 | -------------------------------------------------------------------------------- /img/ProgrammerInterrupted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/reprex/07cd5d74fd25005523a57db97589ff8c3e74c02f/img/ProgrammerInterrupted.png -------------------------------------------------------------------------------- /img/datapasta_w_reprex_sheet_to_tribble.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/reprex/07cd5d74fd25005523a57db97589ff8c3e74c02f/img/datapasta_w_reprex_sheet_to_tribble.gif -------------------------------------------------------------------------------- /img/debugging/needle-in-a-haystack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/reprex/07cd5d74fd25005523a57db97589ff8c3e74c02f/img/debugging/needle-in-a-haystack.png -------------------------------------------------------------------------------- /img/debugging/science-and-art.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/reprex/07cd5d74fd25005523a57db97589ff8c3e74c02f/img/debugging/science-and-art.png -------------------------------------------------------------------------------- /img/debugging/solve-your-own-problem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/reprex/07cd5d74fd25005523a57db97589ff8c3e74c02f/img/debugging/solve-your-own-problem.png -------------------------------------------------------------------------------- /img/debugging/what-you-think-vs-day.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/reprex/07cd5d74fd25005523a57db97589ff8c3e74c02f/img/debugging/what-you-think-vs-day.png -------------------------------------------------------------------------------- /img/dpasta_datapasta_reprex.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/reprex/07cd5d74fd25005523a57db97589ff8c3e74c02f/img/dpasta_datapasta_reprex.gif -------------------------------------------------------------------------------- /img/logo/reprex-og-1280x640.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/reprex/07cd5d74fd25005523a57db97589ff8c3e74c02f/img/logo/reprex-og-1280x640.png -------------------------------------------------------------------------------- /img/logo/reprex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/reprex/07cd5d74fd25005523a57db97589ff8c3e74c02f/img/logo/reprex.png -------------------------------------------------------------------------------- /img/reprex-copy.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/reprex/07cd5d74fd25005523a57db97589ff8c3e74c02f/img/reprex-copy.gif -------------------------------------------------------------------------------- /img/reprex-fail-1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/reprex/07cd5d74fd25005523a57db97589ff8c3e74c02f/img/reprex-fail-1.gif -------------------------------------------------------------------------------- /img/reprex-github.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/reprex/07cd5d74fd25005523a57db97589ff8c3e74c02f/img/reprex-github.gif -------------------------------------------------------------------------------- /img/reprex-si.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/reprex/07cd5d74fd25005523a57db97589ff8c3e74c02f/img/reprex-si.gif -------------------------------------------------------------------------------- /img/reprex-success-1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/reprex/07cd5d74fd25005523a57db97589ff8c3e74c02f/img/reprex-success-1.gif -------------------------------------------------------------------------------- /img/reprex_rtf_jennybryan.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/reprex/07cd5d74fd25005523a57db97589ff8c3e74c02f/img/reprex_rtf_jennybryan.gif -------------------------------------------------------------------------------- /inst/WORDLIST: -------------------------------------------------------------------------------- 1 | Addins 2 | CMD 3 | Cmd 4 | Codecov 5 | CommonMark 6 | Ctrl 7 | Heeris 8 | McBain 9 | ORCID 10 | Pandoc 11 | Pandoc's 12 | PowerShell 13 | Powerpoint 14 | RMarkdown 15 | RStudio's 16 | RTF 17 | Romain 18 | SpeakerDeck 19 | StackOverflow 20 | SystemRequirements 21 | Tierney 22 | Tierney's 23 | Un 24 | XPG 25 | YAML 26 | addin 27 | andre 28 | backtrace 29 | backtraces 30 | behaviour 31 | bryan 32 | callr 33 | chocolatey 34 | cli 35 | customised 36 | datapasta 37 | datapasta's 38 | de 39 | devtools 40 | doku 41 | don'ts 42 | dplyr 43 | ds 44 | else's 45 | eval 46 | executability 47 | filepath 48 | findable 49 | formatR 50 | frontmatter 51 | fs 52 | funder 53 | gh 54 | github 55 | hacky 56 | homebrew 57 | http 58 | https 59 | httr 60 | imgur 61 | ing 62 | jennybc 63 | knitr 64 | knitr's 65 | knitrthemesoverview 66 | lifecycle 67 | lockfile 68 | macOS 69 | metapackage 70 | noninteractive 71 | oducible 72 | outfiles 73 | pandoc 74 | php 75 | producibility 76 | rclickhandbuch 77 | realise 78 | regexes 79 | renv 80 | repr 81 | reprex's 82 | reprexing 83 | reproducibility 84 | rlang 85 | rlang's 86 | rmarkdown 87 | roxygen 88 | rstudio 89 | rstudioapi 90 | rtf 91 | runnable 92 | sessioninfo 93 | signalling 94 | simon 95 | speakerdeck 96 | srcrefs 97 | stderr 98 | stdout 99 | styler 100 | templated 101 | testthat 102 | tibble 103 | tidyeval 104 | tidymodels 105 | tidyverse 106 | tribble 107 | un 108 | withr 109 | wordpress 110 | workspaces 111 | www 112 | xclip 113 | xsel 114 | PBC 115 | RStudio 116 | mockr 117 | traceback 118 | -------------------------------------------------------------------------------- /inst/addins/reprex.css: -------------------------------------------------------------------------------- 1 | .progress-bar { 2 | color: transparent; 3 | } 4 | -------------------------------------------------------------------------------- /inst/rmarkdown/templates/reprex-featureful/skeleton/skeleton.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | output: 3 | reprex::reprex_document: 4 | venue: "gh" 5 | advertise: FALSE 6 | session_info: TRUE 7 | style: TRUE 8 | comment: "#;-)" 9 | tidyverse_quiet: FALSE 10 | std_out_err: TRUE 11 | knit: reprex::reprex_render 12 | --- 13 | 14 | This template demonstrates many of the bells and whistles of the `reprex::reprex_document()` output format. The YAML sets many options to non-default values, such as using `#;-)` as the comment in front of output. 15 | 16 | ## Code style 17 | 18 | Since `style` is `TRUE`, this difficult-to-read code (look at the `.Rmd` source file) will be restyled according to the Tidyverse style guide when it's rendered. Whitespace rationing is not in effect! 19 | 20 | ```{r} 21 | x=1;y=2;z=x+y;z 22 | ``` 23 | 24 | ## Quiet tidyverse 25 | 26 | The tidyverse meta-package is quite chatty at startup, which can be very useful in exploratory, interactive work. It is often less useful in a reprex, so by default, we suppress this. 27 | 28 | However, when `tidyverse_quiet` is `FALSE`, the rendered result will include a tidyverse startup message about package versions and function masking. 29 | 30 | ```{r, eval = requireNamespace("tidyverse", quietly = TRUE)} 31 | library(tidyverse) 32 | ``` 33 | 34 | ## Chunks in languages other than R 35 | 36 | Remember: knitr supports many other languages than R, so you can reprex bits of code in Python, Ruby, Julia, C++, SQL, and more. Note that, in many cases, this still requires that you have the relevant external interpreter installed. 37 | 38 | Let's try Python! 39 | 40 | ```{python, eval = Sys.which("python") != "", python.reticulate = requireNamespace("reticulate", quietly = TRUE)} 41 | x = 'hello, python world!' 42 | print(x.split(' ')) 43 | ``` 44 | 45 | And bash! 46 | 47 | ```{bash, eval = Sys.which("bash") != ""} 48 | echo "Hello Bash!"; 49 | pwd; 50 | ls | head; 51 | ``` 52 | 53 | Write a function in C++, use Rcpp to wrap it and ... 54 | 55 | ```{Rcpp, eval = requireNamespace("Rcpp", quietly = TRUE)} 56 | #include 57 | using namespace Rcpp; 58 | 59 | // [[Rcpp::export]] 60 | NumericVector timesTwo(NumericVector x) { 61 | return x * 2; 62 | } 63 | ``` 64 | 65 | then immediately call your C++ function from R! 66 | 67 | ```{r, eval = requireNamespace("Rcpp", quietly = TRUE)} 68 | timesTwo(1:4) 69 | ``` 70 | 71 | ## Standard output and error 72 | 73 | Some output that you see in an interactive session is not actually captured by rmarkdown, when that same code is executed in the context of an `.Rmd` document. When `std_out_err` is `TRUE`, `reprex::reprex_render()` uses a feature of `callr:r()` to capture such output and then injects it into the rendered result. 74 | 75 | Look for this output in a special section of the rendered document (and notice that it does not appear right here). 76 | 77 | ```{r} 78 | system2("echo", args = "Output that would normally be lost") 79 | ``` 80 | 81 | ## Session info 82 | 83 | Because `session_info` is `TRUE`, the rendered result includes session info, even though no such code is included here in the source document. 84 | -------------------------------------------------------------------------------- /inst/rmarkdown/templates/reprex-featureful/template.yaml: -------------------------------------------------------------------------------- 1 | name: reprex (lots of features) 2 | description: > 3 | A reprex template that demonstrates many features 4 | create_dir: FALSE 5 | -------------------------------------------------------------------------------- /inst/rmarkdown/templates/reprex-minimal/skeleton/skeleton.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | output: reprex::reprex_document 3 | knit: reprex::reprex_render 4 | --- 5 | 6 | Describe your issue very briefly here. Then show it with a minimal, self-contained example in the following R chunk. 7 | 8 | ```{r} 9 | x <- 1 10 | y <- "2" 11 | x + y 12 | ``` 13 | -------------------------------------------------------------------------------- /inst/rmarkdown/templates/reprex-minimal/template.yaml: -------------------------------------------------------------------------------- 1 | name: reprex (minimal) 2 | description: > 3 | A minimal template for making a reprex 4 | create_dir: FALSE 5 | -------------------------------------------------------------------------------- /inst/rstudio/addins.dcf: -------------------------------------------------------------------------------- 1 | Name: Render reprex... 2 | Description: Run `reprex::reprex()` to prepare a reproducible example for sharing. 3 | Binding: reprex_addin 4 | Interactive: true 5 | 6 | Name: Reprex selection 7 | Description: Prepare reprex from current selection 8 | Binding: reprex_selection 9 | Interactive: false 10 | -------------------------------------------------------------------------------- /inst/templates/BETTER_THAN_NOTHING.R: -------------------------------------------------------------------------------- 1 | #' No user-supplied code found ... so we've made some up. You're welcome! 2 | 3 | #+ fortunes, include = requireNamespace("fortunes", quietly = TRUE), eval = requireNamespace("fortunes", quietly = TRUE) 4 | fortunes::fortune() 5 | 6 | #+ no-fortunes, include = !requireNamespace("fortunes", quietly = TRUE) 7 | sprintf("Happy %s!", weekdays(Sys.Date())) 8 | -------------------------------------------------------------------------------- /internal/adjective-animal.txt: -------------------------------------------------------------------------------- 1 | http://assets.gfycat.com/adjectives 2 | 3 | http://assets.gfycat.com/animals 4 | -------------------------------------------------------------------------------- /internal/language-codes.csv: -------------------------------------------------------------------------------- 1 | # from https://datahub.io/core/language-codes#readme 2 | # downloaded 2019-07-18 3 | alpha2,English 4 | aa,Afar 5 | ab,Abkhazian 6 | ae,Avestan 7 | af,Afrikaans 8 | ak,Akan 9 | am,Amharic 10 | an,Aragonese 11 | ar,Arabic 12 | as,Assamese 13 | av,Avaric 14 | ay,Aymara 15 | az,Azerbaijani 16 | ba,Bashkir 17 | be,Belarusian 18 | bg,Bulgarian 19 | bh,Bihari languages 20 | bi,Bislama 21 | bm,Bambara 22 | bn,Bengali 23 | bo,Tibetan 24 | br,Breton 25 | bs,Bosnian 26 | ca,Catalan; Valencian 27 | ce,Chechen 28 | ch,Chamorro 29 | co,Corsican 30 | cr,Cree 31 | cs,Czech 32 | cu,Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic 33 | cv,Chuvash 34 | cy,Welsh 35 | da,Danish 36 | de,German 37 | dv,Divehi; Dhivehi; Maldivian 38 | dz,Dzongkha 39 | ee,Ewe 40 | el,"Greek, Modern (1453-)" 41 | en,English 42 | eo,Esperanto 43 | es,Spanish; Castilian 44 | et,Estonian 45 | eu,Basque 46 | fa,Persian 47 | ff,Fulah 48 | fi,Finnish 49 | fj,Fijian 50 | fo,Faroese 51 | fr,French 52 | fy,Western Frisian 53 | ga,Irish 54 | gd,Gaelic; Scottish Gaelic 55 | gl,Galician 56 | gn,Guarani 57 | gu,Gujarati 58 | gv,Manx 59 | ha,Hausa 60 | he,Hebrew 61 | hi,Hindi 62 | ho,Hiri Motu 63 | hr,Croatian 64 | ht,Haitian; Haitian Creole 65 | hu,Hungarian 66 | hy,Armenian 67 | hz,Herero 68 | ia,Interlingua (International Auxiliary Language Association) 69 | id,Indonesian 70 | ie,Interlingue; Occidental 71 | ig,Igbo 72 | ii,Sichuan Yi; Nuosu 73 | ik,Inupiaq 74 | io,Ido 75 | is,Icelandic 76 | it,Italian 77 | iu,Inuktitut 78 | ja,Japanese 79 | jv,Javanese 80 | ka,Georgian 81 | kg,Kongo 82 | ki,Kikuyu; Gikuyu 83 | kj,Kuanyama; Kwanyama 84 | kk,Kazakh 85 | kl,Kalaallisut; Greenlandic 86 | km,Central Khmer 87 | kn,Kannada 88 | ko,Korean 89 | kr,Kanuri 90 | ks,Kashmiri 91 | ku,Kurdish 92 | kv,Komi 93 | kw,Cornish 94 | ky,Kirghiz; Kyrgyz 95 | la,Latin 96 | lb,Luxembourgish; Letzeburgesch 97 | lg,Ganda 98 | li,Limburgan; Limburger; Limburgish 99 | ln,Lingala 100 | lo,Lao 101 | lt,Lithuanian 102 | lu,Luba-Katanga 103 | lv,Latvian 104 | mg,Malagasy 105 | mh,Marshallese 106 | mi,Maori 107 | mk,Macedonian 108 | ml,Malayalam 109 | mn,Mongolian 110 | mr,Marathi 111 | ms,Malay 112 | mt,Maltese 113 | my,Burmese 114 | na,Nauru 115 | nb,"BokmÃ¥l, Norwegian; Norwegian BokmÃ¥l" 116 | nd,"Ndebele, North; North Ndebele" 117 | ne,Nepali 118 | ng,Ndonga 119 | nl,Dutch; Flemish 120 | nn,"Norwegian Nynorsk; Nynorsk, Norwegian" 121 | no,Norwegian 122 | nr,"Ndebele, South; South Ndebele" 123 | nv,Navajo; Navaho 124 | ny,Chichewa; Chewa; Nyanja 125 | oc,Occitan (post 1500); Provençal 126 | oj,Ojibwa 127 | om,Oromo 128 | or,Oriya 129 | os,Ossetian; Ossetic 130 | pa,Panjabi; Punjabi 131 | pi,Pali 132 | pl,Polish 133 | ps,Pushto; Pashto 134 | pt,Portuguese 135 | qu,Quechua 136 | rm,Romansh 137 | rn,Rundi 138 | ro,Romanian; Moldavian; Moldovan 139 | ru,Russian 140 | rw,Kinyarwanda 141 | sa,Sanskrit 142 | sc,Sardinian 143 | sd,Sindhi 144 | se,Northern Sami 145 | sg,Sango 146 | si,Sinhala; Sinhalese 147 | sk,Slovak 148 | sl,Slovenian 149 | sm,Samoan 150 | sn,Shona 151 | so,Somali 152 | sq,Albanian 153 | sr,Serbian 154 | ss,Swati 155 | st,"Sotho, Southern" 156 | su,Sundanese 157 | sv,Swedish 158 | sw,Swahili 159 | ta,Tamil 160 | te,Telugu 161 | tg,Tajik 162 | th,Thai 163 | ti,Tigrinya 164 | tk,Turkmen 165 | tl,Tagalog 166 | tn,Tswana 167 | to,Tonga (Tonga Islands) 168 | tr,Turkish 169 | ts,Tsonga 170 | tt,Tatar 171 | tw,Twi 172 | ty,Tahitian 173 | ug,Uighur; Uyghur 174 | uk,Ukrainian 175 | ur,Urdu 176 | uz,Uzbek 177 | ve,Venda 178 | vi,Vietnamese 179 | vo,Volapük 180 | wa,Walloon 181 | wo,Wolof 182 | xh,Xhosa 183 | yi,Yiddish 184 | yo,Yoruba 185 | za,Zhuang; Chuang 186 | zh,Chinese 187 | zu,Zulu 188 | -------------------------------------------------------------------------------- /internal/loadedNamespaces-study.R: -------------------------------------------------------------------------------- 1 | # it is interesting to look at this with and without styler installed 2 | 3 | callr_pkgs <- callr::r(function() loadedNamespaces()) 4 | 5 | writeLines("loadedNamespaces()", "foo.R") 6 | callr::r(function() { 7 | rmarkdown::render("foo.R", output_format = "md_document") 8 | }) 9 | x <- unlist(stringr::str_extract_all(readLines("foo.md"), '".+?"')) 10 | render_pkgs <- gsub('"', '', x) 11 | 12 | sort(setdiff(render_pkgs, callr_pkgs)) 13 | 14 | out <- reprex::reprex(loadedNamespaces()) 15 | x <- unlist(stringr::str_extract_all(out, '".+?"')) 16 | reprex_pkgs <- gsub('"', '', x) 17 | 18 | (hmm <- sort(setdiff(reprex_pkgs, render_pkgs))) 19 | 20 | d <- desc::desc(package = "reprex") 21 | reprex_deps <- d$get_deps() 22 | reprex_imports <- sort(reprex_deps$package[reprex_deps$type == "Imports"]) 23 | reprex_suggests <- sort(reprex_deps$package[reprex_deps$type == "Suggests"]) 24 | reprex_imports_and_suggests <- c(reprex_imports, reprex_suggests) 25 | 26 | setdiff(hmm, reprex_imports) 27 | setdiff(hmm, reprex_imports_and_suggests) 28 | -------------------------------------------------------------------------------- /internal/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/reprex/07cd5d74fd25005523a57db97589ff8c3e74c02f/internal/logo.png -------------------------------------------------------------------------------- /internal/message-language-probe.R: -------------------------------------------------------------------------------- 1 | # probe a system for which two-letter language codes can be used in the 2 | # LANGUAGE env var to influence the language used for messages 3 | 4 | library(tidyverse) 5 | library(withr) 6 | 7 | #x <- read_csv(here::here("internal/language-codes.csv"), comment = "#") 8 | x <- read_csv("https://datahub.io/core/language-codes/r/language-codes.csv") 9 | 10 | oops <- function() tryCatch("a"/1, error = function(e) e)$message 11 | probe_language <- function(l) with_envvar(c(LANGUAGE = l), oops()) 12 | 13 | x <- x %>% 14 | mutate( 15 | error = map_chr(alpha2, probe_language), 16 | english = error == probe_language("en") 17 | ) 18 | 19 | x %>% 20 | filter(!english) 21 | -------------------------------------------------------------------------------- /internal/notes.md: -------------------------------------------------------------------------------- 1 | ### Formatting principles 2 | 3 | Notes and links re: best formatting for different venues. 4 | 5 | Stack Overflow 6 | 7 | * 8 | * specifics re: [code highlighting](http://stackoverflow.com/editing-help#syntax-highlighting) 9 | 10 | GitHub 11 | 12 | * GitHub issues use [GitHub-flavored markdown](https://help.github.com/articles/github-flavored-markdown/) 13 | 14 | gist.github.com 15 | 16 | - In theory, this is the domain of [`gistr`](https://github.com/ropensci/gistr), but people also tend to post `.R` or `.Rmd` and NOT resulting `.md` ... is there a gap in tools or is this just an unfortunate behavior pattern? I don't always want to render these files to see what someone's trying to show me. 17 | 18 | ### Notes to self 19 | 20 | Lines where a `.R` file gets spun in `render()`: [render.R\#L129-L154](https://github.com/rstudio/rmarkdown/blob/88afb8d4d6f4371d67b82059baaee1052d2bc55f/R/render.R#L129-L154) 21 | 22 | #### Other work 23 | 24 | The "great R reproducible example" Stack Overflow thread referenced above has some discussion of practical details, such as [this comment](http://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example/16532098#16532098). 25 | 26 | The "Code to import data from a Stack overflow query into R" [stackoverflow thread](http://stackoverflow.com/questions/10849270/code-to-import-data-from-a-stack-overflow-query-into-r/10849315). This is from the perspective of someone considering *answering* a question, in which the OP has not provided a proper reprex. Specifically: it addresses input data that is in suboptimal form. 27 | 28 | A collection of R scripts by GitHub user rsaporta contains some functions related to Stack Overflow: [so\_functions.r](https://github.com/rsaporta/pubR/blob/fe487d7020311b19b92d80e214800813188ad793/so_functions.r). No license. 29 | 30 | The [GitHub package `overflow`](https://github.com/sebastian-c/overflow/). Appears to also emphasize the difficulty above, e.g., getting data out of Stack Overflow questions that don't follow reprex best practices. A bit hard to tell what's there, not much in README, no vignette. License is GPL-3. 31 | -------------------------------------------------------------------------------- /internal/render-notes.txt: -------------------------------------------------------------------------------- 1 | What happens inside render()? 2 | Notes made when preparing to write my own output format 3 | 4 | https://github.com/rstudio/rmarkdown/blame/master/R/render.R 5 | 6 | 1. knitr::spin(spin_input, knit = FALSE, envir = envir, format = "Rmd") 7 | line 397 8 | 9 | Only thought here is that default metadata is added unconditionally, 10 | so I will need to find a way to make sure that is ignored (by having 11 | user metadata elsewhere in the file) or removed. 12 | 13 | I suppose I will still be including my own frontmatter, in order to 14 | specify the output format. This could be a good reason to do so via 15 | YAML instead of in the render() call. 16 | 17 | 2. YAML front matter is read 18 | line 420 19 | 20 | Seems pretty boring / irrelevant? 21 | 22 | 3. output format is read from YAML, if wasn't specified in the call 23 | line 461 24 | 25 | Seems pretty important but unless I start doing something with options 26 | doesn't seem to affect me. 27 | 28 | 4. pandoc_to is set 29 | line 469 30 | 31 | Determined from the output format: `output_format$pandoc$to` 32 | 33 | 5. output_format$intermediates_generator is called 34 | line 502 35 | 36 | Seems irrelevant to me but this is my first chance to do something via 37 | the custom output format. 38 | 39 | 6. pre_knit handler is called 40 | line 532 41 | 42 | Chance to act on the input file, which at this point is the Rmd output of 43 | spin(knit = FALSE). 44 | 45 | 7. knitr options and hooks are set 46 | line 615 47 | 48 | Calls to knitr::opts_knit$set(), knitr::opts_chunk$set(). 49 | I'd need to figure out how to the the tidyverse_quiet R option. 50 | 51 | 8. Main knit 52 | line 740 53 | 54 | 9. post_knit handler is called 55 | line 748 56 | 57 | Well, this is what the comment says, but the code seems a bit surprising. I 58 | think it's more accurate to say we're registering a post_knit handler. 59 | 60 | 10. pre-processor 61 | line 819 62 | 63 | Again, feels like we're registering a pre-processor. 64 | 65 | 11. Call pandoc 66 | line 890 67 | 68 | output_format$pandoc$args is a very important argument 69 | 70 | 12. Call post processor 71 | line 949 72 | -------------------------------------------------------------------------------- /internal/vignette-ideas.Rmd: -------------------------------------------------------------------------------- 1 | Tricks beyond basic usage in README 2 | 3 | Show a multi-line expression example 4 | 5 | ```{r eval = FALSE} 6 | reprex({ 7 | x <- 1:4 8 | y <- 2:5 9 | x + y 10 | }) 11 | ``` 12 | 13 | and point out one can then "select all" + RStudio Run button or keyboard shortcut. Or, with cursor in reprex-containing source editor, RStudio Source button or keyboard shortcut. 14 | 15 | Remind people you can use all your usual `knitr::spin` tricks, like create headings, insert regular prose, and set chunk options. Put this code on the clipboard and the `reprex()` it. (Hey, our expression parsing doesn't handle this but probably should...) 16 | 17 | ```{r eval = FALSE} 18 | #' ## Hey I'm a heading 19 | x <- 1:4 20 | #' blah blah 21 | #+ eval = FALSE 22 | y <- 2:5 23 | x + y 24 | ``` 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /internal/windows-clipboard-data-persistence.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Windows clipboard data persistence" 3 | output: github_document 4 | editor_options: 5 | chunk_output_type: console 6 | --- 7 | 8 | ```{r setup, include = FALSE} 9 | knitr::opts_chunk$set( 10 | collapse = TRUE, 11 | comment = "#>", 12 | error = TRUE 13 | ) 14 | ``` 15 | 16 | Document what I learned about data persistence while writing to the Windows clipboard 17 | 18 | First, write a function to expose RTF on the clipboard from R, then call it to establish baseline: 19 | 20 | ```{r} 21 | read_clipboard_rtf <- function() { 22 | stopifnot(.Platform$OS.type == "windows") 23 | system( 24 | 'powershell -Command "Get-Clipboard -TextFormatType Rtf"', 25 | # `intern = TRUE` is a concession to knitr and making sure we see what 26 | # `Get-Clipboard` returns in our rendered result 27 | # it would not be necessary if you execute this interactively 28 | intern = TRUE) 29 | } 30 | read_clipboard_rtf() 31 | ``` 32 | 33 | The approach I ultimately used in reprex based on the `SetText` method: 34 | 35 | ```{r} 36 | rtf <- r"({\rtf1\ansi\deff0 {\fonttbl {\f0 Times New Roman;}} \f0\fs60 Hello, World!})" 37 | cmd <- glue::glue(' 38 | powershell -Command "\\ 39 | Add-Type -AssemblyName System.Windows.Forms | Out-Null;\\ 40 | [Windows.Forms.Clipboard]::SetText(\\ 41 | \'{rtf}\',\\ 42 | [Windows.Forms.TextDataFormat]::Rtf\\ 43 | )"') 44 | system(cmd) 45 | read_clipboard_rtf() 46 | ``` 47 | 48 | The more complicated approach based on `SetDataObject`, before I appreciated the persistence problem: 49 | 50 | ```{r} 51 | rtf <- r"({\rtf1\ansi\deff0 {\fonttbl {\f0 Times New Roman;}} \f0\fs60 Hello, World!})" 52 | cmd <- glue::glue(' 53 | powershell -Command "\\ 54 | Add-Type -AssemblyName System.Windows.Forms | Out-Null;\\ 55 | $data = New-Object Windows.Forms.DataObject 56 | $data.SetData([Windows.Forms.DataFormats]::Rtf, \'{rtf}\') 57 | [Windows.Forms.Clipboard]::SetDataObject($data)"') 58 | system(cmd) 59 | read_clipboard_rtf() 60 | 61 | ``` 62 | 63 | Adding the all important `$true` to the `SetDataObject` call: 64 | 65 | ```{r} 66 | rtf <- r"({\rtf1\ansi\deff0 {\fonttbl {\f0 Times New Roman;}} \f0\fs60 Hello, World!})" 67 | cmd <- glue::glue(' 68 | powershell -Command "\\ 69 | Add-Type -AssemblyName System.Windows.Forms | Out-Null;\\ 70 | $data = New-Object Windows.Forms.DataObject 71 | $data.SetData([Windows.Forms.DataFormats]::Rtf, \'{rtf}\') 72 | [Windows.Forms.Clipboard]::SetDataObject($data, $true)"') 73 | system(cmd) 74 | read_clipboard_rtf() 75 | 76 | ``` 77 | 78 | Conclusion: `SetText` write persistent data, whereas by default `SetDataObject` does not (although it can if you use the second argument, `copy`). 79 | -------------------------------------------------------------------------------- /internal/windows-clipboard-data-persistence.md: -------------------------------------------------------------------------------- 1 | Windows clipboard data persistence 2 | ================ 3 | 4 | Document what I learned about data persistence while writing to the 5 | Windows clipboard 6 | 7 | First, write a function to expose RTF on the clipboard from R, then call 8 | it to establish baseline: 9 | 10 | ``` r 11 | read_clipboard_rtf <- function() { 12 | stopifnot(.Platform$OS.type == "windows") 13 | system( 14 | 'powershell -Command "Get-Clipboard -TextFormatType Rtf"', 15 | # `intern = TRUE` is a concession to knitr and making sure we see what 16 | # `Get-Clipboard` returns in our rendered result 17 | # it would not be necessary if you execute this interactively 18 | intern = TRUE) 19 | } 20 | read_clipboard_rtf() 21 | #> character(0) 22 | ``` 23 | 24 | The approach I ultimately used in reprex based on the `SetText` method: 25 | 26 | ``` r 27 | rtf <- r"({\rtf1\ansi\deff0 {\fonttbl {\f0 Times New Roman;}} \f0\fs60 Hello, World!})" 28 | cmd <- glue::glue(' 29 | powershell -Command "\\ 30 | Add-Type -AssemblyName System.Windows.Forms | Out-Null;\\ 31 | [Windows.Forms.Clipboard]::SetText(\\ 32 | \'{rtf}\',\\ 33 | [Windows.Forms.TextDataFormat]::Rtf\\ 34 | )"') 35 | system(cmd) 36 | #> [1] 0 37 | read_clipboard_rtf() 38 | #> [1] "{\\rtf1\\ansi\\deff0 {\\fonttbl {\\f0 Times New Roman;}} \\f0\\fs60 Hello, World!}" 39 | ``` 40 | 41 | The more complicated approach based on `SetDataObject`, before I 42 | appreciated the persistence problem: 43 | 44 | ``` r 45 | rtf <- r"({\rtf1\ansi\deff0 {\fonttbl {\f0 Times New Roman;}} \f0\fs60 Hello, World!})" 46 | cmd <- glue::glue(' 47 | powershell -Command "\\ 48 | Add-Type -AssemblyName System.Windows.Forms | Out-Null;\\ 49 | $data = New-Object Windows.Forms.DataObject 50 | $data.SetData([Windows.Forms.DataFormats]::Rtf, \'{rtf}\') 51 | [Windows.Forms.Clipboard]::SetDataObject($data)"') 52 | system(cmd) 53 | #> [1] 0 54 | read_clipboard_rtf() 55 | #> character(0) 56 | ``` 57 | 58 | Adding the all important `$true` to the `SetDataObject` call: 59 | 60 | ``` r 61 | rtf <- r"({\rtf1\ansi\deff0 {\fonttbl {\f0 Times New Roman;}} \f0\fs60 Hello, World!})" 62 | cmd <- glue::glue(' 63 | powershell -Command "\\ 64 | Add-Type -AssemblyName System.Windows.Forms | Out-Null;\\ 65 | $data = New-Object Windows.Forms.DataObject 66 | $data.SetData([Windows.Forms.DataFormats]::Rtf, \'{rtf}\') 67 | [Windows.Forms.Clipboard]::SetDataObject($data, $true)"') 68 | system(cmd) 69 | #> [1] 0 70 | read_clipboard_rtf() 71 | #> [1] "{\\rtf1\\ansi\\deff0 {\\fonttbl {\\f0 Times New Roman;}} \\f0\\fs60 Hello, World!}" 72 | ``` 73 | 74 | Conclusion: `SetText` write persistent data, whereas by default 75 | `SetDataObject` does not (although it can if you use the second 76 | argument, `copy`). 77 | -------------------------------------------------------------------------------- /internal/windows-shell-system-system2.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Running an external process on Windows" 3 | output: github_document 4 | editor_options: 5 | chunk_output_type: console 6 | --- 7 | 8 | ```{r setup, include = FALSE} 9 | knitr::opts_chunk$set( 10 | collapse = TRUE, 11 | comment = "#>", 12 | error = TRUE 13 | ) 14 | ``` 15 | 16 | Figuring out how to write RTF to the Windows clipboard made me think more about the functions `system()`, `system2()`, and (Windows only) `shell()`. 17 | 18 | Here's the highlight call used in `reprex_rtf()`, which converts such a `.R` file into RTF: 19 | 20 | ```{sh eval = FALSE} 21 | highlight -i foo_reprex.R --out-format rtf --no-trailing-nl --encoding=UTF-8 --style darkbone --font 'Courier Regular' --font-size 50 -o gamma_reprex.rtf 22 | ``` 23 | 24 | There are many ways to invoke this from R: 25 | 26 | * `system()`: Docs say "not recommended for new code". 27 | * `system2()`: Officially, the "right" thing to use, at least on *nix. 28 | * `shell()`: Exists only on Windows. Explicitly runs `cmd` under a shell, which 29 | is not the case for `system()` or `system2()` on Windows. 30 | * `processx::run()` 31 | 32 | `system()` and `system2()` only differ with respect to how the ultimately-run command is constructed. 33 | `system2()` is recommended for new code and takes care of some fiddly details, e.g. quoting. 34 | However, due to quoting nightmares, there are calls that can only be formed by `system()` and some that can't be formed at all (which is one of the reasons processx exists). 35 | The main thing to know is that on Windows `command` is executed directly, not within a shell, such as `cmd.exe` or `powershell.exe`. 36 | 37 | This is easiest to see in an example. 38 | `dir` is a command built into `cmd.exe`. 39 | It will work inside `shell()` but not within `system()` or `system2()`. 40 | 41 | ```{r} 42 | shell("dir", intern = TRUE) 43 | print(system("dir")) 44 | print(system2("dir")) 45 | ``` 46 | 47 | How did this come up? 48 | Depending on how you have installed highlight, the `system()` and `shell()` calls below might produce different results. 49 | Specifically, the `system()` call is reported to fail here if highlight was installed via scoop, which uses a shim-based method of putting things it installs on the `PATH`. 50 | This may additionally have something to do with Windows short paths (?). 51 | 52 | ```{r} 53 | system("highlight --version") 54 | shell("highlight --version") 55 | Sys.which("highlight") 56 | ``` 57 | 58 | In any case, my current hypothesis is that I should invoke highlight via `shell()` on Windows, to be more resilient to the different ways users may have installed highlight. 59 | 60 | Let's prove I can invoke highlight in several ways by implementing `reprex_rtf()` "by hand". 61 | First, we render a reprex to the "r" venue and explicitly write a local output file. 62 | 63 | ```{r} 64 | library(reprex) 65 | 66 | reprex_r(sample(LETTERS, 5), outfile = here::here("internal/gamma")) 67 | ``` 68 | 69 | The output of this `gamma_reprex_rendered.R` is the input for the next step, which is to form RTF. 70 | 71 | More objects and helpers we'll use: 72 | 73 | ```{r} 74 | r_file <- here::here("internal/gamma_reprex_rendered.R") 75 | rtf_file <- here::here("internal/gamma_reprex_rendered.rtf") 76 | ``` 77 | 78 | ### `system()` 79 | 80 | ```{r} 81 | (cmd <- glue::glue(" 82 | highlight -i {r_file} --out-format=rtf --no-trailing-nl --encoding=UTF-8 \\ 83 | -o {rtf_file}")) 84 | 85 | system(cmd) 86 | 87 | readLines(rtf_file) 88 | ``` 89 | 90 | ### `system2()` 91 | 92 | ```{r} 93 | unlink(rtf_file) 94 | 95 | (args <- c( 96 | glue::glue("-i {r_file}"), 97 | "--out-format=rtf", "--no-trailing-nl", "--encoding=UTF-8", 98 | glue::glue("-o {rtf_file}") 99 | )) 100 | 101 | print(system2("highlight", args)) 102 | 103 | readLines(rtf_file) 104 | ``` 105 | 106 | ### `shell()` 107 | 108 | ```{r} 109 | unlink(rtf_file) 110 | 111 | (cmd <- glue::glue(" 112 | highlight -i {r_file} --out-format=rtf --no-trailing-nl --encoding=UTF-8 \\ 113 | -o {rtf_file}")) 114 | 115 | print(shell(cmd)) 116 | 117 | readLines(rtf_file) 118 | 119 | unlink(rtf_file) 120 | 121 | print(shell(cmd, shell = "cmd")) 122 | 123 | readLines(rtf_file) 124 | 125 | unlink(rtf_file) 126 | 127 | print(shell(cmd, shell = "powershell")) 128 | 129 | readLines(rtf_file) 130 | ``` 131 | 132 | ### Clean up 133 | 134 | ```{r} 135 | unlink(list.files(here::here("internal"), pattern = "gamma_reprex", full.names = TRUE)) 136 | ``` 137 | -------------------------------------------------------------------------------- /internal/write_clipboard_rtf_alfa.ps1: -------------------------------------------------------------------------------- 1 | Add-Type -AssemblyName System.Windows.Forms 2 | $rtf = Get-Content -Path alfa_reprex.rtf 3 | [Windows.Forms.Clipboard]::SetText($rtf, [System.Windows.Forms.TextDataFormat]::Rtf) 4 | -------------------------------------------------------------------------------- /internal/write_clipboard_rtf_beta.ps1: -------------------------------------------------------------------------------- 1 | Add-Type -AssemblyName "System.Windows.Forms" 2 | $data = New-Object Windows.Forms.DataObject 3 | $rtf = Get-Content -Path beta_reprex.rtf 4 | $data.SetData([Windows.Forms.DataFormats]::Rtf, $rtf) 5 | [Windows.Forms.Clipboard]::SetDataObject($data) 6 | -------------------------------------------------------------------------------- /man/figures/README-viewer-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/reprex/07cd5d74fd25005523a57db97589ff8c3e74c02f/man/figures/README-viewer-screenshot.png -------------------------------------------------------------------------------- /man/figures/help-me-help-you.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/reprex/07cd5d74fd25005523a57db97589ff8c3e74c02f/man/figures/help-me-help-you.png -------------------------------------------------------------------------------- /man/figures/lifecycle-archived.svg: -------------------------------------------------------------------------------- 1 | 2 | lifecycle: archived 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | lifecycle 18 | 19 | archived 20 | 21 | 22 | -------------------------------------------------------------------------------- /man/figures/lifecycle-defunct.svg: -------------------------------------------------------------------------------- 1 | 2 | lifecycle: defunct 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | lifecycle 18 | 19 | defunct 20 | 21 | 22 | -------------------------------------------------------------------------------- /man/figures/lifecycle-deprecated.svg: -------------------------------------------------------------------------------- 1 | 2 | lifecycle: deprecated 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | lifecycle 18 | 19 | deprecated 20 | 21 | 22 | -------------------------------------------------------------------------------- /man/figures/lifecycle-experimental.svg: -------------------------------------------------------------------------------- 1 | 2 | lifecycle: experimental 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | lifecycle 18 | 19 | experimental 20 | 21 | 22 | -------------------------------------------------------------------------------- /man/figures/lifecycle-maturing.svg: -------------------------------------------------------------------------------- 1 | 2 | lifecycle: maturing 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | lifecycle 18 | 19 | maturing 20 | 21 | 22 | -------------------------------------------------------------------------------- /man/figures/lifecycle-questioning.svg: -------------------------------------------------------------------------------- 1 | 2 | lifecycle: questioning 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | lifecycle 18 | 19 | questioning 20 | 21 | 22 | -------------------------------------------------------------------------------- /man/figures/lifecycle-soft-deprecated.svg: -------------------------------------------------------------------------------- 1 | 2 | lifecycle: soft-deprecated 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | lifecycle 18 | 19 | soft-deprecated 20 | 21 | 22 | -------------------------------------------------------------------------------- /man/figures/lifecycle-stable.svg: -------------------------------------------------------------------------------- 1 | 2 | lifecycle: stable 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 19 | 20 | lifecycle 21 | 22 | 25 | 26 | stable 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /man/figures/lifecycle-superseded.svg: -------------------------------------------------------------------------------- 1 | 2 | lifecycle: superseded 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | lifecycle 18 | 19 | superseded 20 | 21 | 22 | -------------------------------------------------------------------------------- /man/figures/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/reprex/07cd5d74fd25005523a57db97589ff8c3e74c02f/man/figures/logo.png -------------------------------------------------------------------------------- /man/reprex-package.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/reprex-package.R 3 | \docType{package} 4 | \name{reprex-package} 5 | \alias{reprex-package} 6 | \title{reprex: Prepare Reproducible Example Code via the Clipboard} 7 | \description{ 8 | \if{html}{\figure{logo.png}{options: style='float: right' alt='logo' width='120'}} 9 | 10 | Convenience wrapper that uses the 'rmarkdown' package to render small snippets of code to target formats that include both code and output. The goal is to encourage the sharing of small, reproducible, and runnable examples on code-oriented websites, such as \url{https://stackoverflow.com} and \url{https://github.com}, or in email. The user's clipboard is the default source of input code and the default target for rendered output. 'reprex' also extracts clean, runnable R code from various common formats, such as copy/paste from an R session. 11 | } 12 | \seealso{ 13 | Useful links: 14 | \itemize{ 15 | \item \url{https://reprex.tidyverse.org} 16 | \item \url{https://github.com/tidyverse/reprex} 17 | \item Report bugs at \url{https://github.com/tidyverse/reprex/issues} 18 | } 19 | 20 | } 21 | \author{ 22 | \strong{Maintainer}: Jennifer Bryan \email{jenny@posit.co} (\href{https://orcid.org/0000-0002-6983-2759}{ORCID}) 23 | 24 | Authors: 25 | \itemize{ 26 | \item Jim Hester (\href{https://orcid.org/0000-0002-2739-7082}{ORCID}) 27 | \item David Robinson \email{admiral.david@gmail.com} 28 | \item Hadley Wickham \email{hadley@posit.co} (\href{https://orcid.org/0000-0003-4757-117X}{ORCID}) 29 | \item Christophe Dervieux \email{cderv@posit.co} (\href{https://orcid.org/0000-0003-4474-2498}{ORCID}) 30 | } 31 | 32 | Other contributors: 33 | \itemize{ 34 | \item Posit Software, PBC [copyright holder, funder] 35 | } 36 | 37 | } 38 | \keyword{internal} 39 | -------------------------------------------------------------------------------- /man/reprex_addin.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/reprex-addin.R 3 | \name{reprex_addin} 4 | \alias{reprex_addin} 5 | \alias{reprex_selection} 6 | \title{Render a reprex, conveniently} 7 | \usage{ 8 | reprex_addin() 9 | 10 | reprex_selection(venue = getOption("reprex.venue", "gh")) 11 | } 12 | \arguments{ 13 | \item{venue}{Character. Must be one of the following (case insensitive): 14 | \itemize{ 15 | \item "gh" for \href{https://github.github.com/gfm/}{GitHub-Flavored Markdown}, the 16 | default 17 | \item "r" for a runnable R script, with commented output interleaved. Also useful 18 | for \href{https://slack.com/intl/en-ca/slack-tips/share-code-snippets}{Slack code snippets}; 19 | select "R" from the "Type" drop-down menu to enjoy nice syntax 20 | highlighting. 21 | \item "rtf" for 22 | \href{https://en.wikipedia.org/wiki/Rich_Text_Format}{Rich Text Format} 23 | (not supported for un-reprexing) 24 | \item "html" for an HTML fragment suitable for inclusion in a larger HTML 25 | document (not supported for un-reprexing) 26 | \item "slack" for pasting into a Slack message. Optimized for people who opt out 27 | of Slack's WYSIWYG interface. Go to 28 | \strong{Preferences > Advanced > Input options} and select "Format messages with 29 | markup". (If there is demand for a second Slack venue optimized for use 30 | with WYSIWYG, please open an issue to discuss.) 31 | \item "so" for 32 | \href{https://stackoverflow.com/editing-help#syntax-highlighting}{Stack Overflow Markdown}. 33 | Note: this is just an alias for "gh", since Stack Overflow started to 34 | support CommonMark-style fenced code blocks in January 2019. 35 | \item "ds" for Discourse, e.g., 36 | \href{https://forum.posit.co/}{forum.posit.co}. Note: this is 37 | currently just an alias for "gh". 38 | }} 39 | } 40 | \description{ 41 | \code{reprex_addin()} opens an \href{https://shiny.rstudio.com/articles/gadgets.html}{RStudio gadget} and 42 | \href{https://rstudio.github.io/rstudioaddins/}{addin} that allows you to say 43 | where the reprex source is (clipboard? current selection? active file? 44 | other file?) and to control a few other arguments. Appears as "Render 45 | reprex" in the RStudio Addins menu. 46 | 47 | \code{reprex_selection()} is an 48 | \href{https://docs.posit.co/ide/user/ide/guide/productivity/add-ins.html}{addin} that reprexes the current 49 | selection, optionally customised by options. Appears as "Reprex selection" 50 | in the RStudio Addins menu. Heavy users might want to \href{https://docs.posit.co/ide/user/ide/guide/productivity/custom-shortcuts.html}{create a keyboard shortcut}. 51 | Suggested shortcut: Cmd + Shift + R (macOS) or Ctrl + Shift + R (Windows). 52 | } 53 | -------------------------------------------------------------------------------- /man/reprex_document.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/reprex_document.R 3 | \name{reprex_document} 4 | \alias{reprex_document} 5 | \title{reprex output format} 6 | \usage{ 7 | reprex_document( 8 | venue = c("gh", "r", "rtf", "html", "slack", "so", "ds"), 9 | advertise = NULL, 10 | session_info = opt(FALSE), 11 | style = opt(FALSE), 12 | comment = opt("#>"), 13 | tidyverse_quiet = opt(TRUE), 14 | std_out_err = opt(FALSE), 15 | pandoc_args = NULL 16 | ) 17 | } 18 | \arguments{ 19 | \item{venue}{Character. Must be one of the following (case insensitive): 20 | \itemize{ 21 | \item "gh" for \href{https://github.github.com/gfm/}{GitHub-Flavored Markdown}, the 22 | default 23 | \item "r" for a runnable R script, with commented output interleaved. Also useful 24 | for \href{https://slack.com/intl/en-ca/slack-tips/share-code-snippets}{Slack code snippets}; 25 | select "R" from the "Type" drop-down menu to enjoy nice syntax 26 | highlighting. 27 | \item "rtf" for 28 | \href{https://en.wikipedia.org/wiki/Rich_Text_Format}{Rich Text Format} 29 | (not supported for un-reprexing) 30 | \item "html" for an HTML fragment suitable for inclusion in a larger HTML 31 | document (not supported for un-reprexing) 32 | \item "slack" for pasting into a Slack message. Optimized for people who opt out 33 | of Slack's WYSIWYG interface. Go to 34 | \strong{Preferences > Advanced > Input options} and select "Format messages with 35 | markup". (If there is demand for a second Slack venue optimized for use 36 | with WYSIWYG, please open an issue to discuss.) 37 | \item "so" for 38 | \href{https://stackoverflow.com/editing-help#syntax-highlighting}{Stack Overflow Markdown}. 39 | Note: this is just an alias for "gh", since Stack Overflow started to 40 | support CommonMark-style fenced code blocks in January 2019. 41 | \item "ds" for Discourse, e.g., 42 | \href{https://forum.posit.co/}{forum.posit.co}. Note: this is 43 | currently just an alias for "gh". 44 | }} 45 | 46 | \item{advertise}{Logical. Whether to include a footer that describes when and 47 | how the reprex was created. If unspecified, the option \code{reprex.advertise} 48 | is consulted and, if that is not defined, default is \code{TRUE} for venues 49 | \code{"gh"}, \code{"html"}, \code{"so"}, \code{"ds"} and \code{FALSE} for \code{"r"}, \code{"rtf"}, \code{"slack"}.} 50 | 51 | \item{session_info}{Logical. Whether to include 52 | \code{\link[sessioninfo:session_info]{sessioninfo::session_info()}}, if available, or \code{\link[=sessionInfo]{sessionInfo()}} at the end 53 | of the reprex. When \code{venue} is "gh", the session info is wrapped in a 54 | collapsible details tag. Read more about \code{\link[=opt]{opt()}}.} 55 | 56 | \item{style}{Logical. Whether to set the knitr chunk option \code{tidy = "styler"}, which re-styles code with the \href{https://styler.r-lib.org}{styler package}. Read more about \code{\link[=opt]{opt()}}.} 57 | 58 | \item{comment}{Character. Prefix with which to comment out output, defaults 59 | to \code{"#>"}. Read more about \code{\link[=opt]{opt()}}.} 60 | 61 | \item{tidyverse_quiet}{Logical. Sets the options \code{tidyverse.quiet} and 62 | \code{tidymodels.quiet}, which suppress (\code{TRUE}, the default) or include 63 | (\code{FALSE}) the startup messages for the tidyverse and tidymodels packages. 64 | Read more about \code{\link[=opt]{opt()}}.} 65 | 66 | \item{std_out_err}{Logical. Whether to append a section for output sent to 67 | stdout and stderr by the reprex rendering process. This can be necessary to 68 | reveal output if the reprex spawns child processes or \code{system()} calls. 69 | Note this cannot be properly interleaved with output from the main R 70 | process, nor is there any guarantee that the lines from standard output and 71 | standard error are in correct chronological order. See \code{\link[callr:r]{callr::r()}} for 72 | more. Read more about \code{\link[=opt]{opt()}}.} 73 | 74 | \item{pandoc_args}{Additional command line options to pass to pandoc} 75 | } 76 | \value{ 77 | An R Markdown output format to pass to \code{\link[rmarkdown:render]{rmarkdown::render()}}. 78 | } 79 | \description{ 80 | This is an R Markdown output format designed specifically for making 81 | "reprexes", typically created via the \code{\link[=reprex]{reprex()}} function, which ultimately 82 | renders the document with \code{\link[=reprex_render]{reprex_render()}}. It is a heavily modified version 83 | of \code{\link[rmarkdown:md_document]{rmarkdown::md_document()}}. The arguments have different spheres of 84 | influence: 85 | \itemize{ 86 | \item \code{venue} potentially affects input preparation and \code{\link[=reprex_render]{reprex_render()}}. 87 | \item Add content to the primary input, prior to rendering: 88 | \itemize{ 89 | \item \code{advertise} 90 | \item \code{session_info} 91 | \item \code{std_out_err} (also consulted by \code{\link[=reprex_render]{reprex_render()}}) 92 | } 93 | \item Influence knitr package or chunk options: 94 | \itemize{ 95 | \item \code{style} 96 | \item \code{comment} 97 | \item \code{tidyverse_quiet} 98 | } 99 | } 100 | 101 | RStudio users can create new R Markdown documents with the 102 | \code{reprex_document()} format using built-in templates. Do 103 | \emph{File > New File > R Markdown ... > From Template} and choose one of: 104 | \itemize{ 105 | \item reprex (minimal) 106 | \item reprex (lots of features) 107 | } 108 | 109 | Both include \code{knit: reprex::reprex_render} in the YAML, which causes the 110 | RStudio "Knit" button to use \code{reprex_render()}. If you render these documents 111 | yourself, you should do same. 112 | } 113 | \examples{ 114 | reprex_document() 115 | } 116 | -------------------------------------------------------------------------------- /man/reprex_locale.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/reprex-locale.R 3 | \name{reprex_locale} 4 | \alias{reprex_locale} 5 | \title{Render a reprex in a specific locale} 6 | \usage{ 7 | reprex_locale(..., language = "en", locale = NULL) 8 | } 9 | \arguments{ 10 | \item{...}{Inputs passed through to \code{\link[=reprex]{reprex()}}.} 11 | 12 | \item{language}{A string specifying the preferred language for messages. It 13 | is enacted via the \code{LANGUAGE} environment variable, for the duration of the 14 | \code{reprex()} call. Examples: \code{"en"} for English and \code{"fr"} for French. See 15 | Details for more.} 16 | 17 | \item{locale}{A named character vector, specifying aspects of the locale, in 18 | the \code{\link[=Sys.setlocale]{Sys.setlocale()}} sense. It is enacted by setting one or more 19 | environment variables, for the duration of the \code{reprex()} call. See Details 20 | for more.} 21 | } 22 | \value{ 23 | Character vector of rendered reprex, invisibly. 24 | } 25 | \description{ 26 | Render a \code{\link[=reprex]{reprex()}}, with control over the localization of error messages and 27 | aspects of the locale. Note that these are related but distinct issues! 28 | Typical usage is for someone on a Spanish system to create a reprex that is 29 | easier for an English-speaking audience to follow. 30 | } 31 | \section{\code{language}}{ 32 | 33 | Use the \code{language} argument to express the preferred language of error 34 | messages. The output of \code{dir(system.file(package = "translations"))} may 35 | provide some helpful ideas. The \code{language} should generally follow "XPG 36 | syntax": a two-letter language code, optionally followed by other modifiers. 37 | 38 | Examples: \code{"en"}, \code{"de"}, \code{"en_GB"}, \code{"pt_BR"}. 39 | } 40 | 41 | \section{\code{locale}}{ 42 | 43 | Use the \code{locale} argument only if you want to affect something like how 44 | day-of-the-week or month is converted to character. You are less likely to 45 | need to set this than the \code{language} argument. You may have more success 46 | setting specific categories, such as \code{"LC_TIME"}, than multi-category 47 | shortcuts like \code{"LC_ALL"} or \code{"LANG"}. The \code{locale} values must follow the 48 | format dictated by your operating system and the requested locale must be 49 | installed. On *nix systems, \code{locale -a} is a good way to see which locales 50 | are installed. Note that the format for \code{locale} and \code{language} are different 51 | from each other on Windows. 52 | 53 | Examples: \code{"en_CA.UTF-8"} (macOS), \code{"French_France.1252"} (Windows). 54 | } 55 | 56 | \examples{ 57 | \dontrun{ 58 | 59 | # if all you want to do is make sure messages are in English 60 | reprex_locale("a" / 2) 61 | 62 | # change messages to a specific language 63 | reprex_locale( 64 | { 65 | "a" / 2 66 | }, 67 | language = "it" 68 | ) 69 | 70 | reprex_locale( 71 | { 72 | "a" / 2 73 | }, 74 | language = "fr_CA" 75 | ) 76 | 77 | reprex_locale( 78 | { 79 | "a" / 2 80 | }, 81 | language = "pt_BR" 82 | ) 83 | 84 | # get day-of-week and month to print in French (not Windows) 85 | reprex_locale( 86 | { 87 | format(as.Date(c("2019-01-01", "2019-02-01")), "\%a \%b \%d") 88 | }, 89 | locale = c(LC_TIME = "fr_FR") 90 | ) 91 | 92 | # get day-of-week and month to print in French (Windows) 93 | # assumes that the relevant language is installed on the system 94 | # LC_TIME can also be specified as "French" or "French_France" here 95 | reprex_locale( 96 | { 97 | format(as.Date(c("2019-01-01", "2019-02-01")), "\%a \%b \%d") 98 | }, 99 | locale = c(LC_TIME = "French_France.1252") 100 | ) 101 | } 102 | } 103 | \seealso{ 104 | \itemize{ 105 | \item The \href{https://www.gnu.org/software/libc/manual/html_node/Locale-Names.html}{Locale Names} 106 | section of the GNU C docs, for more about XPG syntax 107 | \item The \href{https://cran.r-project.org/doc/manuals/r-patched/R-admin.html#Internationalization}{Internationalization and Localization} 108 | section of the R Installation and Administration manual 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /man/reprex_options.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/reprex-options.R 3 | \name{reprex_options} 4 | \alias{reprex_options} 5 | \alias{opt} 6 | \title{reprex options} 7 | \description{ 8 | Some \code{\link[=reprex]{reprex()}} behaviour can be controlled via an option, providing a way 9 | for the user to set personal defaults. The pattern for such option names is 10 | \verb{reprex.}, where \verb{} is an argument of \code{\link[=reprex]{reprex()}}. Here are the main 11 | ones: 12 | \itemize{ 13 | \item \code{reprex.advertise} 14 | \item \code{reprex.session_info} (previously, \code{reprex.si}) 15 | \item \code{reprex.style} 16 | \item \code{reprex.html_preview} (previously, \code{reprex.show}) 17 | \item \code{reprex.comment} 18 | \item \code{reprex.tidyverse_quiet} 19 | \item \code{reprex.std_out_err} 20 | } 21 | 22 | A few more options exist, but are only relevant to specific situations: 23 | \itemize{ 24 | \item \code{reprex.venue}: Can be used to control the \code{venue} used by the 25 | \code{\link[=reprex_selection]{reprex_selection()}} addin. 26 | \item \code{reprex.current_venue}: Read-only option that is set during 27 | \code{\link[=reprex_render]{reprex_render()}}. Other packages that want to generate reprex-compatible 28 | output can consult it via \code{getOption("reprex.current_venue")}, if they want 29 | to tailor their output to the \code{venue}. 30 | \item \code{reprex.clipboard}: When \code{FALSE}, reprex makes no attempt to access the 31 | user's clipboard, ever. This exists mostly for internal use, i.e. we set it 32 | to \code{FALSE} when we detect use from RStudio Server. But a user could set 33 | this to \code{FALSE} to explicitly opt-out of clipboard functionality. A Linux 34 | user with no intention of installing \code{xclip} or \code{xsel} might also do this. 35 | \item \code{reprex.highlight.hl_style}: Only relevant to \verb{venue = "rtf}. Details are 36 | in the article 37 | \href{https://reprex.tidyverse.org/articles/articles/rtf.html}{reprex venue RTF}. 38 | \item \code{reprex.highlight.font}: See above. 39 | \item \code{reprex.highlight.font_size}: See above. 40 | \item \code{reprex.highlight.other}: See above. 41 | } 42 | 43 | Here's code you could put in \code{.Rprofile} to set reprex options. It would be 44 | rare to want non-default behaviour for all of these! We only do so here for 45 | the sake of exposition: 46 | 47 | \if{html}{\out{
}}\preformatted{options( 48 | reprex.advertise = FALSE, 49 | reprex.session_info = TRUE, 50 | reprex.style = TRUE, 51 | reprex.html_preview = FALSE, 52 | reprex.comment = "#;-)", 53 | reprex.tidyverse_quiet = FALSE, 54 | reprex.std_out_err = TRUE, 55 | reprex.venue = "html", # NOTE: only affects reprex_selection()! 56 | reprex.highlight.hl_style = "acid", # NOTE: only affects RTF venue 57 | reprex.highlight.font = "Andale Mono Regular", 58 | reprex.highlight.font_size = 35, 59 | reprex.highlight.other = "--line-numbers" 60 | ) 61 | }\if{html}{\out{
}} 62 | 63 | The function \code{usethis::edit_r_profile()} is handy for creating and/or opening 64 | your \code{.Rprofile}. 65 | } 66 | \section{Explaining the \code{opt()} helper}{ 67 | 68 | Arguments that appear like so in \code{\link[=reprex]{reprex()}}: 69 | 70 | \if{html}{\out{
}}\preformatted{reprex(..., arg = opt(DEFAULT), ...) 71 | }\if{html}{\out{
}} 72 | 73 | get their value according to this logic: 74 | 75 | \if{html}{\out{
}}\preformatted{user-specified value or, if not given, 76 | getOption("reprex.arg") or, if does not exist, 77 | DEFAULT 78 | }\if{html}{\out{
}} 79 | 80 | It's shorthand for: 81 | 82 | \if{html}{\out{
}}\preformatted{f(..., arg = getOption("reprex.arg", DEFAULT), ...) 83 | }\if{html}{\out{
}} 84 | 85 | This is not an exported function and should not be called directly. 86 | } 87 | 88 | -------------------------------------------------------------------------------- /man/reprex_render.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/reprex_render.R 3 | \name{reprex_render} 4 | \alias{reprex_render} 5 | \title{Render a document in a new R session} 6 | \usage{ 7 | reprex_render(input, html_preview = NULL, encoding = "UTF-8") 8 | } 9 | \arguments{ 10 | \item{input}{The input file to be rendered. This can be a \code{.R} script or a 11 | \code{.Rmd} R Markdown document.} 12 | 13 | \item{html_preview}{Logical. Whether to show rendered output in a viewer 14 | (RStudio or browser). Always \code{FALSE} in a noninteractive session. Read more 15 | about \code{\link[=opt]{opt()}}.} 16 | 17 | \item{encoding}{The encoding of the input file. Note that the only acceptable 18 | value is "UTF-8", which is required by knitr as of v1.24. This is exposed 19 | as an argument purely for technical convenience, relating to the "Knit" 20 | button in the RStudio IDE.} 21 | } 22 | \value{ 23 | The output of \code{\link[rmarkdown:render]{rmarkdown::render()}} is passed through, i.e. the path 24 | of the output file. 25 | } 26 | \description{ 27 | This is a wrapper around \code{\link[rmarkdown:render]{rmarkdown::render()}} that enforces the "reprex" 28 | mentality. Here's a simplified version of what happens: 29 | 30 | \if{html}{\out{
}}\preformatted{callr::r( 31 | function(input) \{ 32 | rmarkdown::render(input, envir = globalenv(), encoding = "UTF-8") 33 | \}, 34 | args = list(input = input), 35 | spinner = is_interactive(), 36 | stdout = std_file, stderr = std_file 37 | ) 38 | }\if{html}{\out{
}} 39 | 40 | Key features to note 41 | \itemize{ 42 | \item \code{\link[rmarkdown:render]{rmarkdown::render()}} is executed in a new R session, by using 43 | \code{\link[callr:r]{callr::r()}}. The goal is to eliminate the leakage of objects, attached 44 | packages, and other aspects of session state from the current session into 45 | the rendering session. Also, the system and user-level \code{.Rprofile}s are 46 | ignored. 47 | \item Code is evaluated in the \code{globalenv()} of this new R session, which means 48 | that method dispatch works the way most people expect it to. 49 | \item The input file is assumed to be UTF-8, which is a knitr requirement as of 50 | v1.24. 51 | \item If the YAML frontmatter includes \code{std_err_out: TRUE}, standard output and 52 | error of the rendering R session are captured in \code{std_file}, which is 53 | then injected into the rendered result. 54 | } 55 | 56 | \code{reprex_render()} is designed to work with the \code{\link[=reprex_document]{reprex_document()}} output 57 | format, typically through a call to \code{\link[=reprex]{reprex()}}. \code{reprex_render()} may work 58 | with other R Markdown output formats, but it is not well-tested. 59 | } 60 | \examples{ 61 | \dontrun{ 62 | reprex_render("input.Rmd") 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /man/reprex_venue.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/venues.R 3 | \name{reprex_venue} 4 | \alias{reprex_venue} 5 | \alias{reprex_html} 6 | \alias{reprex_r} 7 | \alias{reprex_rtf} 8 | \alias{reprex_slack} 9 | \title{Venue-specific shortcuts} 10 | \usage{ 11 | reprex_html(...) 12 | 13 | reprex_r(...) 14 | 15 | reprex_rtf(...) 16 | 17 | reprex_slack(...) 18 | } 19 | \arguments{ 20 | \item{...}{Passed along to \code{\link[=reprex]{reprex()}}.} 21 | } 22 | \description{ 23 | These are thin wrappers around \code{reprex()} that incorporate the target \code{venue} 24 | as a suffix in the function name, for easier access via auto-completion. 25 | } 26 | -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/reprex/07cd5d74fd25005523a57db97589ff8c3e74c02f/pkgdown/favicon/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/reprex/07cd5d74fd25005523a57db97589ff8c3e74c02f/pkgdown/favicon/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/reprex/07cd5d74fd25005523a57db97589ff8c3e74c02f/pkgdown/favicon/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/reprex/07cd5d74fd25005523a57db97589ff8c3e74c02f/pkgdown/favicon/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/reprex/07cd5d74fd25005523a57db97589ff8c3e74c02f/pkgdown/favicon/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/reprex/07cd5d74fd25005523a57db97589ff8c3e74c02f/pkgdown/favicon/apple-touch-icon.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/reprex/07cd5d74fd25005523a57db97589ff8c3e74c02f/pkgdown/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/reprex/07cd5d74fd25005523a57db97589ff8c3e74c02f/pkgdown/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/reprex/07cd5d74fd25005523a57db97589ff8c3e74c02f/pkgdown/favicon/favicon.ico -------------------------------------------------------------------------------- /reprex.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: No 4 | SaveWorkspace: No 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | 18 | BuildType: Package 19 | PackageUseDevtools: Yes 20 | PackageInstallArgs: --no-multiarch --with-keep.source 21 | PackageRoxygenize: rd,collate,namespace 22 | -------------------------------------------------------------------------------- /revdep/.gitignore: -------------------------------------------------------------------------------- 1 | checks 2 | library 3 | checks.noindex 4 | library.noindex 5 | data.sqlite 6 | *.html 7 | cloud.noindex 8 | -------------------------------------------------------------------------------- /revdep/README.md: -------------------------------------------------------------------------------- 1 | # Revdeps 2 | 3 | -------------------------------------------------------------------------------- /revdep/cran.md: -------------------------------------------------------------------------------- 1 | ## revdepcheck results 2 | 3 | We checked 6 reverse dependencies, comparing R CMD check results across CRAN and dev versions of this package. 4 | 5 | * We saw 0 new problems 6 | * We failed to check 0 packages 7 | 8 | -------------------------------------------------------------------------------- /revdep/email.yml: -------------------------------------------------------------------------------- 1 | release_date: ??? 2 | rel_release_date: ??? 3 | my_news_url: ??? 4 | release_version: ??? 5 | release_details: ??? 6 | -------------------------------------------------------------------------------- /revdep/failures.md: -------------------------------------------------------------------------------- 1 | *Wow, no problems at all. :)* -------------------------------------------------------------------------------- /revdep/problems.md: -------------------------------------------------------------------------------- 1 | *Wow, no problems at all. :)* -------------------------------------------------------------------------------- /talks/2018-09_reprex-rstudio-webinar/00_install-and-setup-snippets.R: -------------------------------------------------------------------------------- 1 | #+ eval = FALSE 2 | ## install JUST reprex 3 | install.packages("reprex") 4 | 5 | ## install reprex, as part of the tidyverse 6 | install.packages("tidyverse") 7 | 8 | #+ eval = FALSE 9 | ## before you can use reprex(), do this: 10 | library(reprex) 11 | 12 | #+ eval = FALSE 13 | ## put this in ~/.Rprofile to make reprex 14 | ## available 24/7 15 | if (interactive()) { 16 | suppressMessages(require(reprex)) 17 | } 18 | 19 | ## one way to create or open your .Rprofile 20 | ## install.packages("usethis") 21 | usethis::edit_r_profile() 22 | 23 | #+ eval = FALSE 24 | reprex() 25 | -------------------------------------------------------------------------------- /talks/2018-09_reprex-rstudio-webinar/01_factor-wut-snippet.R: -------------------------------------------------------------------------------- 1 | x <- factor("a") 2 | y <- factor("b") 3 | c(x, y) 4 | -------------------------------------------------------------------------------- /talks/2018-09_reprex-rstudio-webinar/02_reprex-fail-tour.R: -------------------------------------------------------------------------------- 1 | template <- "${EXCLAMATION} - your reprex is ${adjective}!" 2 | praise(template) 3 | 4 | 5 | 6 | library(praise) 7 | praise(template) 8 | 9 | 10 | 11 | library(praise) 12 | template <- "${EXCLAMATION} - your reprex is ${adjective}!" 13 | praise(template) 14 | -------------------------------------------------------------------------------- /talks/2018-09_reprex-rstudio-webinar/03_inline-data-frame-creation.R: -------------------------------------------------------------------------------- 1 | x <- read.csv(text = "a,b\n1,2\n3,4") 2 | x 3 | 4 | x <- data.frame( 5 | a = c(1, 2), 6 | b = c(3, 4) 7 | ) 8 | x 9 | 10 | library(readr) 11 | x <- read_csv("a,b\n1,2\n3,4") 12 | x 13 | 14 | library(tibble) 15 | x <- tribble( 16 | ~a, ~b, 17 | 1, 2, 18 | 3, 4 19 | ) 20 | x 21 | 22 | x <- tibble( 23 | a = c(1, 2), 24 | b = c(3, 4) 25 | ) 26 | x 27 | 28 | ## what if you already have an object and you want 29 | ## the tribble() call to define it? 30 | library(datapasta) 31 | x <- tribble_construct(head(iris)) 32 | cat(x) 33 | 34 | ## what if you already have an object and you want 35 | ## the tribble() call to define it? 36 | ## install.packages("krlmlr/deparse") 37 | library(deparse) 38 | x <- deparse(head(iris), as_tribble = TRUE) 39 | cat(x) 40 | -------------------------------------------------------------------------------- /talks/2018-09_reprex-rstudio-webinar/04_readr-issue-784.R: -------------------------------------------------------------------------------- 1 | test1 <- "\"Header\nLine Two\"\nValue" 2 | cat(test1) 3 | readr::read_csv(test1) 4 | -------------------------------------------------------------------------------- /talks/2018-09_reprex-rstudio-webinar/05_shock-and-awe.R: -------------------------------------------------------------------------------- 1 | #+ eval = FALSE 2 | ## figures are uploaded to imgur.com and linked, by default 3 | library(gapminder) 4 | library(ggplot2) 5 | 6 | ggplot(subset(gapminder, continent != "Oceania"), 7 | aes(x = year, y = lifeExp, group = country, color = country)) + 8 | geom_line(lwd = 1, show.legend = FALSE) + facet_wrap(~ continent) + 9 | scale_color_manual(values = country_colors) + 10 | theme_bw() + theme(strip.text = element_text(size = rel(1.1))) 11 | 12 | ## copy the above ^^ to clipboard 13 | reprex() 14 | ## paste into, e.g., GitHub issue 15 | ## OMG the figure is there! w00t! 16 | 17 | #+ eval = FALSE 18 | ## provide input as an expression 19 | reprex({ 20 | x <- rnorm(100) 21 | y <- rnorm(100) 22 | cor(x, y) 23 | }) 24 | 25 | #+ eval = FALSE 26 | ## ask to work in working directory (vs session temp directory) 27 | ## helpful if reprex does file I/O 28 | reprex( 29 | writeLines(letters[1:6]), 30 | outfile = NA 31 | ) 32 | 33 | ## provide a humane base for the filename 34 | reprex( 35 | writeLines(letters[21:26]), 36 | outfile = "shock-and-awe" 37 | ) 38 | 39 | #+ eval = FALSE 40 | ## render to markdown tuned to Stack Overflow (vs GitHub or Discourse) 41 | reprex( 42 | mean(rnorm(100)), 43 | venue = "so" 44 | ) 45 | 46 | ## render to a commented R script 47 | ## great for email or Slack 48 | reprex( 49 | mean(rnorm(100)), 50 | venue = "r" 51 | ) 52 | 53 | ## render to RTF to paste into Keynote or PowerPoint 54 | reprex( 55 | mean(rnorm(100)), 56 | venue = "rtf" 57 | ) 58 | 59 | #+ eval = FALSE 60 | ## suppress the "advertisement" (toggle it!) 61 | reprex( 62 | mean(rnorm(100)), 63 | advertise = TRUE 64 | ) 65 | 66 | ## include session info (toggle it!) 67 | reprex( 68 | mean(rnorm(100)), 69 | si = TRUE 70 | ) 71 | 72 | ## re-style the code (toggle it!) 73 | reprex( 74 | input = c( 75 | 'if (TRUE) "true branch" else {', 76 | '"else branch"', 77 | ' }' 78 | ), 79 | style = TRUE 80 | ) 81 | 82 | ## whimsical comment string ;-) 83 | reprex( 84 | cat(letters[1:3], sep = "\n"), 85 | comment = "#;-)" 86 | ) 87 | 88 | ## suppress tidyverse startup messaging (or not ... toggle it!) 89 | reprex( 90 | library(tidyverse), 91 | tidyverse_quiet = TRUE 92 | ) 93 | 94 | #+ eval = FALSE 95 | ## include output from standard output and standard error 96 | remove.packages("bench") 97 | reprex( 98 | devtools::install_github("r-lib/bench"), 99 | std_out_err = TRUE 100 | ) 101 | -------------------------------------------------------------------------------- /talks/2018-09_reprex-rstudio-webinar/06_rprofile-option-fodder.R: -------------------------------------------------------------------------------- 1 | #+ eval = FALSE 2 | options( 3 | reprex.advertise = FALSE, 4 | reprex.si = TRUE, 5 | reprex.style = TRUE, 6 | reprex.comment = "#;-)", 7 | reprex.tidyverse_quiet = FALSE 8 | ) 9 | 10 | #+ eval = FALSE 11 | reprex( 12 | x = NULL, input = NULL, outfile = NULL, 13 | venue = c("gh", "so", "ds", "r", "rtf"), 14 | render = TRUE, advertise = NULL, 15 | si = opt(FALSE), style = opt(FALSE), 16 | show = opt(TRUE), comment = opt("#>"), 17 | tidyverse_quiet = opt(TRUE), std_out_err = opt(FALSE) 18 | ) 19 | -------------------------------------------------------------------------------- /talks/2018-09_reprex-rstudio-webinar/10_resolution-to-factor-wut.R: -------------------------------------------------------------------------------- 1 | x <- factor("a") 2 | y <- factor("b") 3 | c(x, y) 4 | 5 | factor(c(as.character(x), as.character(y))) 6 | forcats::fct_c(x, y) 7 | -------------------------------------------------------------------------------- /talks/2018-09_reprex-rstudio-webinar/2018-09_reprex-rstudio-webinar.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/reprex/07cd5d74fd25005523a57db97589ff8c3e74c02f/talks/2018-09_reprex-rstudio-webinar/2018-09_reprex-rstudio-webinar.pdf -------------------------------------------------------------------------------- /talks/2018-09_reprex-rstudio-webinar/jehyun-sung-477894-unsplash.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/reprex/07cd5d74fd25005523a57db97589ff8c3e74c02f/talks/2018-09_reprex-rstudio-webinar/jehyun-sung-477894-unsplash.jpg -------------------------------------------------------------------------------- /talks/2021-10-12_rstudio-inside-look/00_install-and-setup-snippets.R: -------------------------------------------------------------------------------- 1 | #+ eval = FALSE 2 | # install JUST reprex 3 | install.packages("reprex") 4 | 5 | # install reprex, as part of the tidyverse 6 | install.packages("tidyverse") 7 | 8 | #+ eval = FALSE 9 | library(reprex) 10 | 11 | #+ eval = FALSE 12 | # put this in ~/.Rprofile to make reprex 13 | # available 24/7 14 | if (interactive()) { 15 | suppressMessages(require(reprex)) 16 | } 17 | 18 | # one way to create or open your .Rprofile 19 | # install.packages("usethis") 20 | usethis::edit_r_profile() 21 | 22 | #+ eval = FALSE 23 | reprex() 24 | -------------------------------------------------------------------------------- /talks/2021-10-12_rstudio-inside-look/01_factor-wut.R: -------------------------------------------------------------------------------- 1 | x <- factor("a") 2 | x 3 | y <- 1 4 | y 5 | c(x, y) 6 | -------------------------------------------------------------------------------- /talks/2021-10-12_rstudio-inside-look/02_gapminder-ggplot2-imgur.R: -------------------------------------------------------------------------------- 1 | library(gapminder) 2 | library(ggplot2) 3 | 4 | ggplot(subset(gapminder, continent != "Oceania"), 5 | aes(x = year, y = lifeExp, group = country, color = country)) + 6 | geom_line(lwd = 1, show.legend = FALSE) + facet_wrap(~ continent) + 7 | scale_color_manual(values = country_colors) + 8 | theme_bw() + theme(strip.text = element_text(size = rel(1.1))) 9 | -------------------------------------------------------------------------------- /talks/2021-10-12_rstudio-inside-look/03_venues-and-suffix-forms.R: -------------------------------------------------------------------------------- 1 | #+ eval = FALSE 2 | reprex(..., venue = "gh") 3 | reprex(..., venue = "slack") 4 | reprex(..., venue = "r") 5 | reprex(..., venue = "rtf") 6 | 7 | #+ eval = FALSE 8 | reprex() 9 | reprex_slack() 10 | reprex_r() 11 | reprex_rtf() 12 | -------------------------------------------------------------------------------- /talks/2021-10-12_rstudio-inside-look/04_session-info.R: -------------------------------------------------------------------------------- 1 | #+ eval = FALSE 2 | reprex(..., session_info = TRUE) 3 | 4 | 1 + 2 5 | -------------------------------------------------------------------------------- /talks/2021-10-12_rstudio-inside-look/05_wd-control.R: -------------------------------------------------------------------------------- 1 | #+ eval = FALSE 2 | reprex(..., wd = NULL) 3 | 4 | #+ eval = FALSE 5 | reprex(..., wd = ".") 6 | 7 | getwd() 8 | -------------------------------------------------------------------------------- /talks/2021-10-12_rstudio-inside-look/06_std-out-err.R: -------------------------------------------------------------------------------- 1 | #+ eval = FALSE 2 | reprex(..., std_out_err = TRUE) 3 | 4 | 5 | system2("echo", args = "Output that would normally be lost") 6 | -------------------------------------------------------------------------------- /talks/2021-10-12_rstudio-inside-look/07_renv.R: -------------------------------------------------------------------------------- 1 | #+ eval = FALSE 2 | renv::snapshot(reprex = TRUE) 3 | 4 | 5 | x <- 1:5 6 | mean(x) 7 | 8 | renv::snapshot(reprex = TRUE) 9 | -------------------------------------------------------------------------------- /talks/2021-10-12_rstudio-inside-look/08_prex.R: -------------------------------------------------------------------------------- 1 | #+ eval = FALSE 2 | reprex:::prex() 3 | reprex:::prex_rtf() 4 | 5 | 6 | -------------------------------------------------------------------------------- /tests/spelling.R: -------------------------------------------------------------------------------- 1 | if (requireNamespace("spelling", quietly = TRUE)) { 2 | spelling::spell_check_test( 3 | vignettes = TRUE, error = FALSE, 4 | skip_on_cran = TRUE 5 | ) 6 | } 7 | -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library(reprex) 3 | 4 | if (rmarkdown::pandoc_available("2.0.0")) { 5 | test_check("reprex") 6 | } 7 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/input.md: -------------------------------------------------------------------------------- 1 | # reprex: expression input works 2 | 3 | Code 4 | cli::cat_line(reprex({ 5 | x <- 1:5 6 | mean(x) 7 | }, render = FALSE)) 8 | Output 9 | #' --- 10 | #' output: reprex::reprex_document 11 | #' --- 12 | 13 | x <- 1:5 14 | mean(x) 15 | 16 | # reprex: character input works 17 | 18 | Code 19 | cli::cat_line(reprex(input = c("x <- 5:1", "mean(x)"), render = FALSE)) 20 | Output 21 | #' --- 22 | #' output: reprex::reprex_document 23 | #' --- 24 | 25 | x <- 5:1 26 | mean(x) 27 | 28 | # reprex: file input works 29 | 30 | Code 31 | cli::cat_line(reprex(input = "foo.R", render = FALSE)) 32 | Output 33 | #' --- 34 | #' output: reprex::reprex_document 35 | #' --- 36 | 37 | x <- 6:10 38 | mean(x) 39 | 40 | # reprex: file input in a subdirectory works 41 | 42 | Code 43 | cli::cat_line(reprex(input = path("foo", "foo.R"), render = FALSE)) 44 | Output 45 | #' --- 46 | #' output: reprex::reprex_document 47 | #' --- 48 | 49 | x <- 11:15 50 | mean(x) 51 | 52 | # Circular use is detected before source file written 53 | 54 | Code 55 | reprex(input = ret, render = FALSE) 56 | Condition 57 | Error in `reprex()`: 58 | ! Cancelling. 59 | 60 | --- 61 | 62 | Code 63 | reprex(input = ret, render = FALSE) 64 | Condition 65 | Error in `reprex()`: 66 | ! Cancelling. 67 | 68 | --- 69 | 70 | Code 71 | reprex(input = ret, render = FALSE) 72 | Condition 73 | Error in `reprex()`: 74 | ! Cancelling. 75 | 76 | # Leading prompts are removed 77 | 78 | Code 79 | res2 <- reprex(input = input2, render = FALSE) 80 | Message 81 | i Removing leading prompts from reprex source. 82 | 83 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/reprex.md: -------------------------------------------------------------------------------- 1 | # reprex() works with code that deals with srcrefs 2 | 3 | [1] "``` r" 4 | [2] "utils::getParseData(parse(text = 'a'))" 5 | [3] "#> line1 col1 line2 col2 id parent token terminal text" 6 | [4] "#> 1 1 1 1 1 1 3 SYMBOL TRUE a" 7 | [5] "#> 3 1 1 1 1 3 0 expr FALSE" 8 | [6] "```" 9 | 10 | # reprex() errors for an R crash, by default 11 | 12 | Code 13 | code <- "rlang::node_car(0)\n" 14 | reprex(input = code) 15 | Condition 16 | Error in `reprex_render()`: 17 | ! This reprex appears to crash R. Call `reprex()` again with `std_out_err = TRUE` to get more info. 18 | 19 | # reprex() copes with an R crash, when `std_out_err = TRUE` 20 | 21 | Code 22 | out 23 | Output 24 | [1] "This reprex appears to crash R." 25 | [2] "See standard output and standard error for more details." 26 | [3] "" 27 | [4] "#### Standard output and error" 28 | [5] "" 29 | [6] "``` sh" 30 | [7] "" 31 | [8] " *** caught segfault ***" 32 | [9] "address ADDRESS, cause 'CAUSE'" 33 | [10] "" 34 | [11] "Traceback:" 35 | 36 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/reprex_document.md: -------------------------------------------------------------------------------- 1 | # ad responds to venue 2 | 3 | Code 4 | ad("gh") 5 | Output 6 | Created on `r Sys.Date()` with [reprex v`r utils::packageVersion("reprex")`](https://reprex.tidyverse.org) 7 | 8 | --- 9 | 10 | Code 11 | ad("slack") 12 | Output 13 | Created on `r Sys.Date()` with [reprex v`r utils::packageVersion("reprex")`](https://reprex.tidyverse.org) 14 | 15 | --- 16 | 17 | Code 18 | ad("r") 19 | Output 20 | Created on `r Sys.Date()` with reprex v`r utils::packageVersion("reprex")` https://reprex.tidyverse.org 21 | 22 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/rprofile.md: -------------------------------------------------------------------------------- 1 | # local .Rprofile reporting responds to venue 2 | 3 | Code 4 | rprofile_alert("gh") 5 | Output 6 | [1] "```{r, results = 'asis', echo = FALSE, include = file.exists('.Rprofile'), eval = file.exists('.Rprofile')}" 7 | [2] "cat(sprintf(\"*Local `.Rprofile` detected at `%s`*\", normalizePath(\".Rprofile\")))" 8 | [3] "```" 9 | 10 | --- 11 | 12 | Code 13 | rprofile_alert("r") 14 | Output 15 | [1] "```{r, results = 'asis', echo = FALSE, include = file.exists('.Rprofile'), eval = file.exists('.Rprofile')}" 16 | [2] "cat(sprintf(\"Local .Rprofile detected at %s\", normalizePath(\".Rprofile\")))" 17 | [3] "```" 18 | 19 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/utils-clipboard.md: -------------------------------------------------------------------------------- 1 | # reprex_clipboard() insists on length one logical 2 | 3 | Code 4 | reprex_clipboard() 5 | Condition 6 | Error: 7 | ! The `reprex.clipboard` option must be `TRUE`, `FALSE`, or (logical) `NA`. 8 | 9 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/utils-io.md: -------------------------------------------------------------------------------- 1 | # retrofit_files() works 2 | 3 | The `outfile` argument of `reprex()` is deprecated as of reprex 2.0.0. 4 | i Please use the `wd` argument instead. 5 | 6 | --- 7 | 8 | The `outfile` argument of `reprex()` is deprecated as of reprex 2.0.0. 9 | i Use `reprex(wd = ".")` instead of `reprex(outfile = NA)`. 10 | 11 | --- 12 | 13 | The `outfile` argument of `reprex()` is deprecated as of reprex 2.0.0. 14 | i To control output filename, provide a filepath to `input`. 15 | i Only taking working directory from `outfile`. 16 | 17 | --- 18 | 19 | The `outfile` argument of `reprex()` is deprecated as of reprex 2.0.0. 20 | i Working directory will be derived from `input`. 21 | 22 | --- 23 | 24 | The `outfile` argument of `reprex()` is deprecated as of reprex 2.0.0. 25 | i Working directory and output filename will be determined from `input`. 26 | 27 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/utils-ui.md: -------------------------------------------------------------------------------- 1 | # reprex_alert() and friends work 2 | 3 | Code 4 | reprex_alert("alert", type = "") 5 | Message 6 | > alert 7 | Code 8 | reprex_success("success") 9 | Message 10 | v success 11 | Code 12 | reprex_info("info") 13 | Message 14 | i info 15 | Code 16 | reprex_warning("warning") 17 | Message 18 | ! warning 19 | Code 20 | reprex_danger("danger") 21 | Message 22 | x danger 23 | 24 | # reprex_alert() is under the control of REPREX_QUIET env var 25 | 26 | Code 27 | reprex_alert("alert", type = "") 28 | 29 | --- 30 | 31 | Code 32 | reprex_alert("alert", type = "") 33 | Message 34 | > alert 35 | 36 | # reprex_path() works and respects REPREX_QUIET 37 | 38 | Code 39 | reprex_path("Something descriptive:", "path/to/file") 40 | 41 | --- 42 | 43 | Code 44 | reprex_path("Something descriptive:", "path/to/file") 45 | Message 46 | v Something descriptive: 47 | 'path/to/file' 48 | Code 49 | x <- "path/to/file" 50 | reprex_path("Something descriptive:", x) 51 | Message 52 | v Something descriptive: 53 | 'path/to/file' 54 | Code 55 | y <- c("path", "to", "file") 56 | reprex_path("Something descriptive:", path_join(y)) 57 | Message 58 | v Something descriptive: 59 | 'path/to/file' 60 | 61 | -------------------------------------------------------------------------------- /tests/testthat/expressions.rds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/reprex/07cd5d74fd25005523a57db97589ff8c3e74c02f/tests/testthat/expressions.rds -------------------------------------------------------------------------------- /tests/testthat/fixtures/a-reprex-document.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | output: 3 | reprex::reprex_document: 4 | venue: "gh" 5 | advertise: TRUE 6 | session_info: TRUE 7 | std_out_err: TRUE 8 | knit: reprex::reprex_render 9 | --- 10 | 11 | Used in a test to make sure we don't add the reprex advertisement and stubs for session info and standard output/error to a source `.Rmd` document. 12 | Potentially over and over again. 13 | 14 | ```{r} 15 | x <- rnorm(10) 16 | quantile(x) 17 | ``` 18 | -------------------------------------------------------------------------------- /tests/testthat/helper.R: -------------------------------------------------------------------------------- 1 | # Work around some bug in R.cache and/or styler that affects CI ---- 2 | # 2024-01: Since this went in, I have seen yet another CI failure due to what I 3 | # assume is this directory not existing, presumably because some code in styler 4 | # deleted it, after we created it here. 5 | # The problem seemed to go away upon further investigation, so it seems 6 | # somewhat stochastic. 7 | # See https://github.com/tidyverse/reprex/pull/455. 8 | # If we have to debug this again, these are some thoughts: 9 | # * When we forcibly create the directory, also put a file in it. That might 10 | # keep styler from deleting it. 11 | # * Figure out how to deactivate all styler caching for reprex, at least on CI. 12 | # Seems to require `options(styler.cache_name = NULL)`. 13 | if (getRversion() >= "4.0.0" && identical(Sys.getenv("CI"), "true")) { 14 | dir.create( 15 | tools::R_user_dir("R.cache", which = "cache"), 16 | recursive = TRUE, 17 | showWarnings = FALSE 18 | ) 19 | } 20 | 21 | expect_messages_to_include <- function(haystack, needles) { 22 | lapply( 23 | needles, 24 | function(x) expect_match(haystack, x, all = FALSE) 25 | ) 26 | invisible() 27 | } 28 | 29 | # 1. creates a subdirectory within session temp 30 | # 2. makes that the current working directory 31 | # 3. schedules these cleanup actions for when env goes out of scope: 32 | # - restore original working directory 33 | # - delete the directory 34 | local_temp_wd <- function(pattern = "reprextests", 35 | env = parent.frame()) { 36 | old_wd <- getwd() 37 | tmp <- withr::local_tempdir(pattern = pattern, .local_envir = env) 38 | withr::local_dir(tmp, .local_envir = env) 39 | reprex_path("Switching to temporary working directory:", tmp) 40 | withr::defer( 41 | reprex_path("Restoring original working directory:", old_wd), 42 | envir = env 43 | ) 44 | invisible(tmp) 45 | } 46 | -------------------------------------------------------------------------------- /tests/testthat/setup.R: -------------------------------------------------------------------------------- 1 | withr::local_options( 2 | list(reprex.clipboard = FALSE, reprex.html_preview = FALSE), 3 | .local_envir = teardown_env() 4 | ) 5 | -------------------------------------------------------------------------------- /tests/testthat/test-env.R: -------------------------------------------------------------------------------- 1 | test_that("can't see environment of caller", { 2 | skip_on_cran() 3 | z <- "don't touch me" 4 | ret <- reprex(z) 5 | expect_match(ret, "object 'z' not found", all = FALSE) 6 | }) 7 | 8 | test_that("reprex doesn't write into environment of caller", { 9 | skip_on_cran() 10 | z <- "don't touch me" 11 | ret <- reprex((z <- "I touched it!"), advertise = FALSE) 12 | expect_identical(ret[3], "#> [1] \"I touched it!\"") 13 | expect_identical(z, "don't touch me") 14 | 15 | ## concrete example I have suffered from: 16 | ## assign object to name of object inside reprex_impl() 17 | expect_match(reprex(r_file <- 0L), "r_file <- 0L", all = FALSE) 18 | }) 19 | 20 | test_that("reprex env doesn't bear traces of reprex or its dependencies", { 21 | skip_on_cran() 22 | 23 | ret <- reprex(input = c("a <- 'a'", "ls(all.names = TRUE)")) 24 | ret <- ret[grepl("^#>", ret)] 25 | 26 | # https://github.com/r-lib/debugme/issues/50 27 | # styler --> tibble --> pillar --> debugme --> tickles RNG 28 | pkg <- "debugme" 29 | if (requireNamespace(pkg, quietly = TRUE)) { 30 | # until debugme updates on CRAN, let's tolerate .Random.seed, but not 31 | # require it either 32 | expect_match(ret, '"a"', all = FALSE) 33 | } else { 34 | expect_identical(ret, "#> [1] \"a\"") 35 | } 36 | }) 37 | -------------------------------------------------------------------------------- /tests/testthat/test-input.R: -------------------------------------------------------------------------------- 1 | # test_that("reprex: clipboard input works") 2 | # This test was removed: 3 | # * Feels like I'm just testing clipr, which seems silly. 4 | # * Because clipr and reprex have erected so many safeguards against 5 | # clipboard access in a noninteractive session, for CRAN reasons, this test 6 | # requires a great deal of gymnastics to bypass all of that. 7 | # * Normal usage will absolutely and immediately reveal clipboard problems. 8 | 9 | test_that("reprex: expression input works", { 10 | expect_snapshot(cli::cat_line( 11 | reprex({x <- 1:5; mean(x)}, render = FALSE) 12 | )) 13 | }) 14 | 15 | ## https://github.com/tidyverse/reprex/issues/241 16 | test_that("reprex: expression input preserves `!!`", { 17 | res <- reprex( 18 | {f <- function(c6d573e) rlang::qq_show(how_many(!!rlang::enquo(c6d573e)))}, 19 | render = FALSE 20 | ) 21 | expect_match(res, "!!rlang::enquo(c6d573e)", all = FALSE, fixed = TRUE) 22 | }) 23 | 24 | test_that("reprex: character input works", { 25 | expect_snapshot(cli::cat_line( 26 | reprex(input = c("x <- 5:1", "mean(x)"), render = FALSE) 27 | )) 28 | }) 29 | 30 | test_that("reprex: file input works", { 31 | local_temp_wd() 32 | write_lines(c("x <- 6:10", "mean(x)"), "foo.R") 33 | expect_snapshot(cli::cat_line( 34 | reprex(input = "foo.R", render = FALSE) 35 | )) 36 | }) 37 | 38 | test_that("reprex: file input in a subdirectory works", { 39 | local_temp_wd() 40 | dir_create("foo") 41 | write_lines(c("x <- 11:15", "mean(x)"), path("foo", "foo.R")) 42 | expect_snapshot(cli::cat_line( 43 | reprex(input = path("foo", "foo.R"), render = FALSE) 44 | )) 45 | }) 46 | 47 | test_that("Circular use is detected before source file written", { 48 | skip_on_cran() 49 | ret <- reprex(exp(1), venue = "gh") 50 | expect_snapshot(error = TRUE, reprex(input = ret, render = FALSE)) 51 | ret <- reprex(exp(1), venue = "r") 52 | expect_snapshot(error = TRUE, reprex(input = ret, render = FALSE)) 53 | ret <- reprex(exp(1), venue = "html") 54 | expect_snapshot(error = TRUE, reprex(input = ret, render = FALSE)) 55 | }) 56 | 57 | test_that("Leading prompts are removed", { 58 | skip_on_cran() 59 | 60 | input <- c("x <- 1:3", "median(x)") 61 | res <- reprex(input = input, render = FALSE) 62 | input2 <- paste0(getOption("prompt"), input) 63 | 64 | local_reprex_loud() 65 | expect_snapshot( 66 | res2 <- reprex(input = input2, render = FALSE) 67 | ) 68 | expect_identical(res, res2) 69 | }) 70 | 71 | test_that("newlines in code are protected and uniformly so across venues", { 72 | # NOTE: use of single vs double quotes is counter-intuitive, but deliberate 73 | input <- 'paste(letters[1:3], collapse = "\n")\n' 74 | chr_input <- reprex(input = input, render = FALSE) 75 | 76 | input_file <- path_temp("foo.R") 77 | withr::local_file(input_file) 78 | write_lines( 79 | escape_newlines('paste(letters[1:3], collapse = "\n")'), 80 | input_file 81 | ) 82 | path_input <- reprex(input = input_file, render = FALSE) 83 | 84 | expr_input <- reprex(paste(letters[1:3], collapse = "\n"), render = FALSE) 85 | 86 | expect_identical(chr_input, path_input) 87 | expect_identical(chr_input, expr_input) 88 | }) 89 | -------------------------------------------------------------------------------- /tests/testthat/test-knitr-options.R: -------------------------------------------------------------------------------- 1 | test_that("`comment` works", { 2 | skip_on_cran() 3 | out <- reprex(1, comment = "#?#") 4 | expect_match(out, "#?#", all = FALSE, fixed = TRUE) 5 | }) 6 | 7 | test_that("reprex() suppresses tidyverse startup message by default", { 8 | skip_on_cran() 9 | skip_if_not_installed("tidyverse", minimum_version = "1.2.1") 10 | ret <- reprex(input = sprintf("library(%s)\n", "tidyverse")) 11 | expect_no_match(ret, "Attaching") 12 | }) 13 | 14 | test_that("`tidyverse_quiet` works", { 15 | skip_on_cran() 16 | skip_if_not_installed("tidyverse", minimum_version = "1.2.1") 17 | 18 | ret <- reprex( 19 | input = "library(tidyverse)\n", 20 | tidyverse_quiet = TRUE 21 | ) 22 | expect_no_match(ret, "Attaching") 23 | 24 | ret <- reprex( 25 | input = "library(tidyverse)\n", 26 | tidyverse_quiet = FALSE 27 | ) 28 | expect_match(ret, "Attaching", all = FALSE) 29 | }) 30 | 31 | test_that("`tidyverse_quiet` works for tidymodels", { 32 | skip_on_cran() 33 | skip_if_not_installed("tidymodels") 34 | 35 | ret <- reprex( 36 | input = "library(tidymodels)\n", 37 | tidyverse_quiet = TRUE 38 | ) 39 | expect_no_match(ret, "Attaching") 40 | 41 | ret <- reprex( 42 | input = "library(tidymodels)\n", 43 | tidyverse_quiet = FALSE 44 | ) 45 | expect_match(ret, "Attaching", all = FALSE) 46 | }) 47 | 48 | 49 | test_that("`style` works", { 50 | skip_on_cran() 51 | skip_if_not_installed("styler") 52 | ret <- reprex(input = c("a<-function( x){", "1+1} "), style = TRUE) 53 | i <- grep("^a", ret) 54 | expect_identical( 55 | ret[i + 0:2], 56 | c("a <- function(x) {", " 1 + 1", "}") 57 | ) 58 | }) 59 | 60 | test_that("bang bang bang is not mangled with parentheses", { 61 | skip_on_cran() 62 | skip_if_not_installed("styler") 63 | input <- c( 64 | 'nameshift <- c(SL = "Sepal.Length")', 65 | "head(dplyr::rename(iris[, 1:2], !!!nameshift), 3)" 66 | ) 67 | ret <- reprex(input = input, style = TRUE) 68 | ret <- grep("dplyr::rename", ret, value = TRUE) 69 | expect_match(ret, "!!!") 70 | }) 71 | -------------------------------------------------------------------------------- /tests/testthat/test-outfiles.R: -------------------------------------------------------------------------------- 1 | test_that("expected outfiles are written and messaged, venue = 'gh'", { 2 | skip_on_cran() 3 | local_temp_wd() 4 | local_reprex_loud() 5 | 6 | msg <- trimws(capture_messages( 7 | ret <- reprex(1:5, wd = ".") 8 | )) 9 | 10 | outfiles <- dir_ls() 11 | expect_setequal( 12 | gsub("[a-z-]+(_reprex.+)", "\\1", outfiles), 13 | c("_reprex.R", "_reprex.md") 14 | ) 15 | r_file <- grep("_reprex[.]R", outfiles, value = TRUE) 16 | expect_match(read_lines(r_file), "1:5", all = FALSE) 17 | md_file <- grep("_reprex[.]md", outfiles, value = TRUE) 18 | expect_equal(ret, read_lines(md_file)) 19 | 20 | expect_messages_to_include( 21 | msg, 22 | c("Preparing reprex as .*.R.* file", "Writing reprex file", outfiles) 23 | ) 24 | }) 25 | 26 | test_that("expected outfiles are written and messaged, venue = 'R'", { 27 | skip_on_cran() 28 | local_temp_wd() 29 | local_reprex_loud() 30 | 31 | msg <- trimws(capture_messages( 32 | ret <- reprex(1:5, wd = ".", venue = "R") 33 | )) 34 | 35 | outfiles <- dir_ls() 36 | expect_setequal( 37 | gsub("[a-z-]+(_reprex.+)", "\\1", outfiles), 38 | c("_reprex.R", "_reprex.md", "_reprex_r.R") 39 | ) 40 | rout_file <- grep("_reprex_r[.]R", outfiles, value = TRUE) 41 | expect_equal(ret, read_lines(rout_file)) 42 | 43 | expect_messages_to_include( 44 | msg, 45 | c("Preparing reprex as .*R.* file", "Writing reprex file", rout_file) 46 | ) 47 | }) 48 | 49 | test_that("expected outfiles are written and messaged, venue = 'html'", { 50 | skip_on_cran() 51 | local_temp_wd() 52 | local_reprex_loud() 53 | 54 | msg <- trimws(capture_messages( 55 | ret <- reprex(1:5, wd = ".", venue = "html") 56 | )) 57 | 58 | outfiles <- dir_ls() 59 | # punting on the issue of the `utf8.md` file and folder of files 60 | expect_contains( 61 | gsub("[a-z-]+(_reprex.+)", "\\1", outfiles), 62 | c("_reprex.R", "_reprex.md", "_reprex.html") 63 | ) 64 | html_file <- grep("_reprex[.]html", outfiles, value = TRUE) 65 | expect_equal(ret, read_lines(html_file)) 66 | 67 | expect_messages_to_include( 68 | msg, 69 | c("Preparing reprex as .*R.* file", "Writing reprex file", html_file) 70 | ) 71 | }) 72 | 73 | test_that(".R outfile doesn't clobber .R infile", { 74 | skip_on_cran() 75 | local_temp_wd() 76 | 77 | write_lines("1:5", "foo.R") 78 | ret <- reprex(input = "foo.R") 79 | expect_identical("1:5", read_lines("foo.R")) 80 | }) 81 | 82 | test_that("infile can have path components", { 83 | skip_on_cran() 84 | local_temp_wd() 85 | local_reprex_loud() 86 | 87 | dir_create("aaa") 88 | write_lines("1:5", "aaa/bbb.R") 89 | msg <- capture_messages( 90 | ret <- reprex(input = "aaa/bbb.R") 91 | ) 92 | expect_messages_to_include( 93 | msg, 94 | c( 95 | "Preparing reprex as .*.R.* file", "aaa/bbb_reprex.R", 96 | "Writing reprex file", "aaa/bbb_reprex.md" 97 | ) 98 | ) 99 | }) 100 | 101 | test_that("pre-existing xyz_reprex.R doesn't get clobbered w/o user's OK", { 102 | skip_on_cran() 103 | local_temp_wd() 104 | 105 | write_lines("5:1", "xyz.R") 106 | ret <- reprex(input = "xyz.R") 107 | expect_match(read_lines("xyz_reprex.md"), "5:1", all = FALSE, fixed = TRUE) 108 | write_lines("max(4:6)", "xyz.R") 109 | reprex(input = "xyz.R") 110 | expect_match(read_lines("xyz_reprex.md"), "5:1", all = FALSE, fixed = TRUE) 111 | }) 112 | -------------------------------------------------------------------------------- /tests/testthat/test-pandoc.R: -------------------------------------------------------------------------------- 1 | test_that("pandoc does not add hard linebreak in the ad", { 2 | skip_on_cran() 3 | out <- reprex(input = "1:3\n", venue = "gh", advertise = TRUE) 4 | expect_match(out[length(out)], "Created on") 5 | }) 6 | -------------------------------------------------------------------------------- /tests/testthat/test-reprex-addin.R: -------------------------------------------------------------------------------- 1 | test_that("rstudio_text_tidy() can handle 'no input'", { 2 | expect_equal(rstudio_text_tidy(""), character()) 3 | }) 4 | -------------------------------------------------------------------------------- /tests/testthat/test-reprex-options.R: -------------------------------------------------------------------------------- 1 | test_that("reprex.current_venue is set", { 2 | skip_on_cran() 3 | input <- "getOption('reprex.current_venue')" 4 | ret <- reprex(input = paste0(input, "\n")) 5 | expect_match(ret, "gh", all = FALSE) 6 | ret <- reprex(input = paste0(input, "\n"), venue = "html") 7 | expect_match(ret, "html", all = FALSE) 8 | }) 9 | 10 | test_that("`session_info` can be set via option", { 11 | skip_on_cran() 12 | withr::with_options( 13 | list(reprex.session_info = TRUE), 14 | out <- reprex(1, render = FALSE) 15 | ) 16 | expect_match(out, "session_*[iI]nfo", all = FALSE) 17 | }) 18 | 19 | test_that("`advertise` can be set via option", { 20 | skip_on_cran() 21 | withr::with_options( 22 | list(reprex.advertise = FALSE), 23 | out <- reprex(1, render = FALSE) 24 | ) 25 | expect_no_match(out, "#+ reprex-ad", fixed = TRUE) 26 | }) 27 | 28 | test_that("`comment` can be set via option", { 29 | skip_on_cran() 30 | withr::with_options( 31 | list(reprex.comment = "#? "), 32 | out <- reprex(rnorm(1)) 33 | ) 34 | expect_match(out, "^#\\?", all = FALSE) 35 | }) 36 | 37 | test_that("`tidyverse_quiet` can be set via option", { 38 | skip_on_cran() 39 | withr::with_options( 40 | list(reprex.tidyverse_quiet = FALSE), 41 | out <- reprex(mean(1:3), render = FALSE) 42 | ) 43 | expect_match(out, "tidyverse_quiet: FALSE", fixed = TRUE, all = FALSE) 44 | }) 45 | 46 | test_that("`std_out_err` can be set via option", { 47 | skip_on_cran() 48 | withr::with_options( 49 | list(reprex.std_out_err = TRUE), 50 | out <- reprex(1, render = FALSE) 51 | ) 52 | expect_match(out, "std_out_err", all = FALSE) 53 | }) 54 | -------------------------------------------------------------------------------- /tests/testthat/test-reprex-undo.R: -------------------------------------------------------------------------------- 1 | ## intentionally forcing continuation lines 2 | input <- c( 3 | "## a comment", 4 | "x <- 1:4", 5 | "#' hi", 6 | "y <- c(2,", 7 | " 3, 4,", 8 | " 5)", 9 | "x + y" 10 | ) 11 | 12 | test_that("round trip, venue = 'gh': reprex() --> reprex_invert()", { 13 | skip_on_cran() 14 | output <- reprex(input = input, advertise = FALSE) 15 | res <- reprex_invert(output) 16 | expect_identical(input, res[nzchar(res)]) 17 | }) 18 | 19 | test_that("round trip, venue = 'r': reprex() --> reprex_invert()", { 20 | skip_on_cran() 21 | output <- reprex(input = input, advertise = FALSE, venue = "r") 22 | res <- reprex_clean(output) 23 | expect_identical(input, res[nzchar(res)]) 24 | }) 25 | 26 | test_that("reprex_rescue() rescues code from R Console copy/paste", { 27 | skip_on_cran() 28 | console <- c( 29 | "> ## a regular comment, which is retained", 30 | "> (y <- c(2,", 31 | "+ 3, 4,", 32 | "+ 5))", 33 | "[1] 2 3 4 5", 34 | "> median(y)", 35 | "[1] 3.5" 36 | ) 37 | output <- c( 38 | "## a regular comment, which is retained", 39 | "(y <- c(2,", 40 | " 3, 4,", 41 | " 5))", 42 | "median(y)" 43 | ) 44 | expect_identical(reprex_rescue(console), output) 45 | }) 46 | 47 | test_that("reprex_rescue()'s prompt argument works", { 48 | skip_on_cran() 49 | code <- c( 50 | ":-) ## a regular comment, which is retained", 51 | ":-) (x <- 1:4)", 52 | "[1] 1 2 3 4", 53 | ":-) median(x)", 54 | "[1] 2.5" 55 | ) 56 | output <- c( 57 | "## a regular comment, which is retained", 58 | "(x <- 1:4)", 59 | "median(x)" 60 | ) 61 | expect_identical(reprex_rescue(code, prompt = ":-) "), output) 62 | }) 63 | 64 | test_that("reprex_rescue()'s continue argument works", { 65 | skip_on_cran() 66 | code <- c( 67 | "> ## a regular comment, which is retained", 68 | "> (y <- c(2,", 69 | "yes, and? 3, 4,", 70 | "yes, and? 5))", 71 | "[1] 2 3 4 5", 72 | "> median(y)", 73 | "[1] 3.5" 74 | ) 75 | output <- c( 76 | "## a regular comment, which is retained", 77 | "(y <- c(2,", 78 | " 3, 4,", 79 | " 5))", 80 | "median(y)" 81 | ) 82 | expect_identical(reprex_rescue(code, continue = "yes, and? "), output) 83 | }) 84 | 85 | test_that("reprex_rescue() can cope with leading whitespace", { 86 | skip_on_cran() 87 | console <- c( 88 | "> ## a regular comment, which is retained", 89 | " > (x <- 1:4)", 90 | " [1] 1 2 3 4", 91 | " > median(x)", 92 | "2.5" 93 | ) 94 | output <- c( 95 | "## a regular comment, which is retained", 96 | "(x <- 1:4)", 97 | "median(x)" 98 | ) 99 | expect_identical(reprex_rescue(console), output) 100 | }) 101 | 102 | test_that("reprex_invert() can write to specific outfile", { 103 | skip_on_cran() 104 | local_temp_wd() 105 | 106 | write_lines(c("x <- 1:3", "median(x)"), "foo.R") 107 | reprex(input = "foo.R", advertise = FALSE) 108 | out <- reprex_invert(input = "foo_reprex.md") 109 | expect_identical(read_lines("foo_reprex_clean.R"), out) 110 | }) 111 | 112 | test_that("reprex_invert() can name its own outfile", { 113 | skip_on_cran() 114 | local_temp_wd() 115 | 116 | code <- c("x <- 1:3", "median(x)") 117 | invert_me <- reprex(input = code, advertise = FALSE) 118 | out <- reprex_invert(input = invert_me, wd = ".") 119 | r_file <- dir_ls(regexp = "_clean[.]R$") 120 | expect_identical(read_lines(r_file), out) 121 | }) 122 | 123 | test_that("reprex_invert(venue = 'gh') doesn't strip leading ws", { 124 | skip_on_cran() 125 | local_temp_wd() 126 | 127 | src <- c("head(", " letters)") 128 | write_lines(src, "whitespace.R") 129 | invert_me <- reprex(input = "whitespace.R", venue = "gh", advertise = FALSE) 130 | inverted <- reprex_invert(input = "whitespace_reprex.md", venue = "gh") 131 | expect_equal(inverted, src) 132 | }) 133 | -------------------------------------------------------------------------------- /tests/testthat/test-reprex.R: -------------------------------------------------------------------------------- 1 | ## https://github.com/tidyverse/reprex/issues/152 2 | test_that("keep.source is TRUE inside the reprex()", { 3 | skip_on_cran() 4 | ret <- reprex(input = "getOption('keep.source')\n") 5 | expect_match(ret, "TRUE", all = FALSE) 6 | }) 7 | 8 | test_that("reprex() works with code that deals with srcrefs", { 9 | skip_on_cran() 10 | ret <- reprex( 11 | input = "utils::getParseData(parse(text = 'a'))\n", 12 | advertise = FALSE 13 | ) 14 | expect_snapshot_output(print(ret)) 15 | }) 16 | 17 | ## https://github.com/tidyverse/reprex/issues/183 18 | test_that("reprex() doesn't leak files by default", { 19 | skip_on_cran() 20 | reprex(base::writeLines("test", "test.txt"), advertise = FALSE) 21 | ret <- reprex(base::readLines("test.txt"), advertise = FALSE) 22 | expect_match(ret, "cannot open file 'test.txt'", all = FALSE) 23 | }) 24 | 25 | test_that("rmarkdown::render() context is trimmed from rlang backtrace", { 26 | skip_on_cran() 27 | input <- c( 28 | "f <- function() rlang::abort('foo')", 29 | "f()", 30 | "rlang::last_error()", 31 | "rlang::last_trace()" 32 | ) 33 | ret <- reprex(input = input, advertise = FALSE) 34 | expect_no_match(ret, regexp = "tryCatch|rmarkdown::render") 35 | }) 36 | 37 | test_that("rlang::last_error() and last_trace() work", { 38 | skip_on_cran() 39 | 40 | input <- c( 41 | "f <- function() rlang::abort('foo')", 42 | "f()", 43 | # as of rlang 1.0.0 (2022-01-26) 44 | # https://github.com/r-lib/rlang/blame/0e2718639d7b87effbf47cf17d6e0288a69454e6/NEWS.md#L350-L354 45 | "#'", # currently, this must be in a new chunk 46 | "rlang::last_error()", 47 | "rlang::last_trace()" 48 | ) 49 | ret <- reprex(input = input, advertise = FALSE) 50 | m <- match("rlang::last_error()", ret) 51 | expect_no_match(ret[m + 1], "Error") 52 | m <- match("rlang::last_trace()", ret) 53 | expect_no_match(ret[m + 1], "Error") 54 | }) 55 | 56 | test_that("reprex() works even if user uses fancy quotes", { 57 | skip_on_cran() 58 | withr::local_options(list(useFancyQuotes = TRUE)) 59 | # use non-default venue to force some quoted yaml to be written 60 | expect_no_error(reprex(1, venue = "R")) 61 | }) 62 | 63 | test_that("reprex() errors for an R crash, by default", { 64 | skip_on_cran() 65 | expect_snapshot(error = TRUE, { 66 | code <- 'rlang::node_car(0)\n' 67 | reprex(input = code) 68 | }) 69 | }) 70 | 71 | test_that("reprex() copes with an R crash, when `std_out_err = TRUE`", { 72 | skip_on_cran() 73 | code <- 'rlang::node_car(0)\n' 74 | expect_no_error( 75 | out <- reprex(input = code, std_out_err = TRUE) 76 | ) 77 | 78 | skip_on_os("windows") 79 | 80 | scrubber <- function(x) { 81 | # I don't want to snapshot the actual traceback 82 | out <- x[seq_len(min(grep("Traceback", x)))] 83 | # on macOS and windows, cause is 'invalid permissions' 84 | # on ubuntu, cause is 'memory not mapped' 85 | out <- sub( 86 | "address 0x[0-9a-fA-F]+, cause '.*'", 87 | "address ADDRESS, cause 'CAUSE'", 88 | out 89 | ) 90 | trimws(out) 91 | } 92 | 93 | expect_snapshot(out, transform = scrubber) 94 | }) 95 | -------------------------------------------------------------------------------- /tests/testthat/test-reprex_document.R: -------------------------------------------------------------------------------- 1 | test_that("upload.fun responds to venue", { 2 | x <- reprex_document(venue = "gh") 3 | expect_identical(x$knitr$opts_knit$upload.fun, knitr::imgur_upload) 4 | x <- reprex_document(venue = "r") 5 | expect_identical(x$knitr$opts_knit$upload.fun, identity) 6 | }) 7 | 8 | test_that("ad responds to venue", { 9 | expect_snapshot(ad("gh")) 10 | expect_snapshot(ad("slack")) 11 | expect_snapshot(ad("r")) 12 | }) 13 | -------------------------------------------------------------------------------- /tests/testthat/test-reprex_impl.R: -------------------------------------------------------------------------------- 1 | # https://github.com/tidyverse/reprex/issues/363 2 | # ironically, reprex.advertise = FALSE + reprex(advertise = FALSE) 3 | # resulted in reprex(advertise = TRUE) behaviour 4 | test_that("reprex.advertise default detection isn't affected by the option", { 5 | full_list <- list(advertise = FALSE, venue = "gh", session_info = FALSE) 6 | non_default <- list(advertise = FALSE) 7 | 8 | withr::with_options( 9 | list(reprex.advertise = TRUE), 10 | expect_equal(remove_defaults(full_list), non_default) 11 | ) 12 | withr::with_options( 13 | list(reprex.advertise = FALSE), 14 | expect_equal(remove_defaults(full_list), non_default) 15 | ) 16 | withr::with_options( 17 | list(reprex.advertise = NULL), 18 | expect_equal(remove_defaults(full_list), non_default) 19 | ) 20 | }) 21 | -------------------------------------------------------------------------------- /tests/testthat/test-reprex_render.R: -------------------------------------------------------------------------------- 1 | # https://github.com/tidyverse/reprex/issues/349 2 | test_that("reprex additions are added to a *copy* of an Rmd input file", { 3 | skip_on_cran() 4 | fixture_path <- path_abs(test_path("fixtures/a-reprex-document.Rmd")) 5 | local_temp_wd() 6 | 7 | file_copy(fixture_path, "foo.Rmd") 8 | n_before <- read_lines("foo.Rmd") 9 | reprex_render("foo.Rmd") 10 | n_after <- read_lines("foo.Rmd") 11 | expect_equal(n_before, n_after) 12 | }) 13 | 14 | test_that("remove_info_strings() gets rid of 'info strings'", { 15 | f <- function(x) strsplit(glue::glue(x), split = "\n")[[1]] 16 | # examples from https://spec.commonmark.org/0.29/#info-string 17 | x <- f(" 18 | ``` 19 | < 20 | > 21 | ```") 22 | expect_equal(x, remove_info_strings(x)) 23 | 24 | x <- f(" 25 | ```ruby 26 | def foo(x) 27 | return 3 28 | end 29 | ```") 30 | expect_equal(sub("ruby", "", x), remove_info_strings(x)) 31 | 32 | x <- f(" 33 | ``` ruby startline=3 $%@#$ 34 | def foo(x) 35 | return 3 36 | end 37 | ```") 38 | expect_equal(c("```", tail(x, -1)), remove_info_strings(x)) 39 | }) 40 | 41 | test_that("preview() works with the 'Knit' button", { 42 | skip_on_cran() 43 | 44 | local_temp_wd() 45 | write_lines("3 * 5\n", "foo.R") 46 | reprex(input = "foo.R") 47 | 48 | withr::local_envvar(c(RMARKDOWN_PREVIEW_DIR = ".")) 49 | rlang::local_interactive(FALSE) 50 | 51 | msg <- capture.output( 52 | preview_file <- preview("foo_reprex.md"), 53 | type = "message" 54 | ) 55 | 56 | expect_true(file_exists("foo_reprex_preview.html")) 57 | expect_equal(path_file(preview_file), "foo_reprex_preview.html") 58 | expect_messages_to_include( 59 | msg, 60 | c("^Preview created:", "foo_reprex_preview.html$") 61 | ) 62 | }) 63 | 64 | test_that("preview() calls viewer() in the interactive RStudio scenario", { 65 | skip_on_cran() 66 | 67 | local_temp_wd() 68 | write_lines("10 / 5\n", "foo.R") 69 | reprex(input = "foo.R") 70 | 71 | rlang::local_interactive(TRUE) 72 | local_options(viewer = function(...) cat("viewer!", file = stderr())) 73 | 74 | msg <- capture.output( 75 | preview_file <- preview("foo_reprex.md"), 76 | type = "message" 77 | ) 78 | 79 | expect_true(file_exists(preview_file)) 80 | expect_equal(path_file(preview_file), "foo_reprex_preview.html") 81 | expect_messages_to_include(msg, "viewer!") 82 | }) 83 | -------------------------------------------------------------------------------- /tests/testthat/test-rprofile.R: -------------------------------------------------------------------------------- 1 | test_that(".Rprofile local to reprex target directory is consulted & messaged", { 2 | local_temp_wd("reprextests-aaa-") 3 | cat("x <- 'aaa'\n", file = ".Rprofile") 4 | cat("x\n", file = "foo.R") 5 | aaa_foo <- path_abs("foo.R") 6 | 7 | local_temp_wd("reprextests-bbb-") 8 | cat("x <- 'bbb'\n", file = ".Rprofile") 9 | 10 | local_reprex_loud() 11 | msg <- capture_messages( 12 | out <- reprex(x, wd = ".", advertise = FALSE) 13 | ) 14 | expect_match(out, "bbb", all = FALSE) 15 | expect_messages_to_include( 16 | msg, 17 | c("Local '[.]Rprofile' detected", "bbb") 18 | ) 19 | 20 | msg <- capture_messages( 21 | out <- reprex(input = aaa_foo, wd = ".", advertise = FALSE) 22 | ) 23 | expect_match(out, "aaa", all = FALSE) 24 | expect_messages_to_include( 25 | msg, 26 | c("Local '[.]Rprofile' detected", "aaa") 27 | ) 28 | }) 29 | 30 | test_that("local .Rprofile reporting responds to venue", { 31 | expect_snapshot(rprofile_alert("gh")) 32 | expect_snapshot(rprofile_alert("r")) 33 | }) 34 | 35 | test_that("local .Rprofile not reported when it's not there", { 36 | local_reprex_loud() 37 | msg <- capture_messages( 38 | reprex(1 + 1, advertise = FALSE) 39 | ) 40 | expect_no_match(msg, ".Rprofile", fixed = TRUE) 41 | }) 42 | -------------------------------------------------------------------------------- /tests/testthat/test-session-info.R: -------------------------------------------------------------------------------- 1 | test_that("session info is omitted / included", { 2 | skip_on_cran() 3 | if (rlang::is_installed("sessioninfo")) { 4 | regex <- "^sessioninfo::session_info" 5 | } else { 6 | regex <- "^sessionInfo" 7 | } 8 | input <- c("(y <- 1:4)", "mean(y)") 9 | ret <- reprex(input = input) 10 | expect_no_match(ret, regex) 11 | ret <- reprex(input = input, session_info = TRUE) 12 | expect_match(ret, regex, all = FALSE) 13 | }) 14 | 15 | test_that("session info is folded for `venue = 'gh'`", { 16 | skip_on_cran() 17 | input <- c("(y <- 1:4)", "mean(y)") 18 | ret <- reprex(input = input, session_info = TRUE, venue = "gh") 19 | expect_match(ret, "", all = FALSE) 20 | expect_match(ret, "", fixed = TRUE, all = FALSE) 21 | }) 22 | -------------------------------------------------------------------------------- /tests/testthat/test-stdout-stderr.R: -------------------------------------------------------------------------------- 1 | test_that("stdout is captured", { 2 | skip_on_cran() 3 | out <- reprex(system2("echo", args = "blah"), std_out_err = TRUE) 4 | expect_match(out, "Standard output and standard error", all = FALSE) 5 | expect_match(out, "^blah$", all = FALSE) 6 | }) 7 | 8 | test_that("stdout placeholder appears if nothing is captured", { 9 | skip_on_cran() 10 | out <- reprex(1:4, std_out_err = TRUE) 11 | expect_match(out, "Standard output and standard error", all = FALSE) 12 | expect_match(out, "nothing to show", all = FALSE) 13 | }) 14 | 15 | test_that("stdout placeholder is absent if explicitly excluded", { 16 | skip_on_cran() 17 | out <- reprex(1:4, std_out_err = FALSE) 18 | expect_no_match(out, "standard output and standard error") 19 | }) 20 | -------------------------------------------------------------------------------- /tests/testthat/test-stringify_expression.R: -------------------------------------------------------------------------------- 1 | test_that("simple statements are stringified", { 2 | expect_identical(stringify_expression(1:5), "1:5") 3 | expect_identical(stringify_expression({1:5}), "1:5") 4 | expect_identical(stringify_expression(quote(mean(x))), "mean(x)") 5 | }) 6 | 7 | ## it is very difficult to create quoted multi-line expressions in tests 8 | ## that mimic what a user can create interactively re: the srcrefs 9 | ## therefore, I executed this interactively to create expressions.rds 10 | if (FALSE) { 11 | e <- new.env() 12 | e$e01 <- quote({ 13 | 1:5 14 | }) 15 | e$e02 <- quote({1:5 16 | }) 17 | e$e03 <- quote({ 18 | 1:5}) 19 | e$e04 <- quote({1:3;4:6}) 20 | e$e05 <- quote({ 21 | #' Leading comment 22 | x <- rnorm(3) 23 | #' Embedded comment 24 | mean(x) 25 | #' Trailing comment 26 | }) 27 | e$e06 <- quote({mean(1:4) # comment 28 | }) 29 | e$e07 <- quote({ 30 | #' Leading comment 31 | y <- 1:4 # comment 32 | #' Trailing comment 33 | } 34 | ) 35 | e$e08 <- quote({ 36 | x <- 1:2 37 | {x + 3:4} %>% sum() 38 | }) 39 | saveRDS( 40 | e, 41 | rprojroot::find_testthat_root_file("expressions.rds"), 42 | version = 2 43 | ) 44 | } 45 | 46 | e <- readRDS(rprojroot::find_testthat_root_file("expressions.rds")) 47 | 48 | test_that("one statement, brackets, multiple lines, take 1", { 49 | # quote({ 50 | # 1:5 51 | # }) 52 | expect_identical( 53 | stringify_expression(e$e01), 54 | "1:5" 55 | ) 56 | }) 57 | 58 | test_that("one statement, brackets, multiple lines, take 2", { 59 | # expr <- quote({1:5 60 | # }) 61 | expect_identical( 62 | stringify_expression(e$e02), 63 | "1:5" 64 | ) 65 | }) 66 | 67 | test_that("one statement, brackets, multiple lines, take 3", { 68 | # expr <- quote({ 69 | # 1:5}) 70 | expect_identical( 71 | stringify_expression(e$e03), 72 | "1:5" 73 | ) 74 | }) 75 | 76 | test_that("multiple statements, brackets, semicolon", { 77 | # quote({1:3;4:6}) 78 | expect_identical( 79 | stringify_expression(e$e04), 80 | "1:3;4:6" 81 | ) 82 | }) 83 | 84 | test_that("leading, embedded, trailing comment, #89", { 85 | # expr <- quote({ 86 | # #' Leading comment 87 | # x <- rnorm(3) 88 | # #' Embedded comment 89 | # mean(x) 90 | # #' Trailing comment 91 | # }) 92 | out <- c( 93 | "#' Leading comment", 94 | "x <- rnorm(3)", 95 | "#' Embedded comment", 96 | "mean(x)", 97 | "#' Trailing comment" 98 | ) 99 | expect_identical( 100 | stringify_expression(e$e05), 101 | out 102 | ) 103 | }) 104 | 105 | test_that("trailing inline comment, #91", { 106 | # expr <- quote({mean(1:4) # comment 107 | # }) 108 | out <- "mean(1:4) # comment" 109 | expect_identical( 110 | stringify_expression(e$e06), 111 | out 112 | ) 113 | }) 114 | 115 | test_that("trailing inline comment AND trailing comment line", { 116 | # expr <- quote({ 117 | # #' Leading comment 118 | # y <- 1:4 # comment 119 | # #' Trailing comment 120 | # } 121 | out <- c( 122 | "#' Leading comment", 123 | "y <- 1:4 # comment", 124 | "#' Trailing comment" 125 | ) 126 | expect_identical( 127 | stringify_expression(e$e07), 128 | out 129 | ) 130 | }) 131 | 132 | test_that("leading bracket that should not be removed", { 133 | # e$e08 <- quote({ 134 | # x <- 1:2 135 | # {x + 3:4} %>% sum() 136 | # }) 137 | out <- c( 138 | "x <- 1:2", 139 | "{x + 3:4} %>% sum()" 140 | ) 141 | expect_identical( 142 | stringify_expression(e$e08), 143 | out 144 | ) 145 | }) 146 | -------------------------------------------------------------------------------- /tests/testthat/test-utf8.R: -------------------------------------------------------------------------------- 1 | test_that("UTF-8 encoding, string input", { 2 | skip_on_cran() 3 | 4 | in_utf8 <- c( 5 | # a-grave e-diaeresis Eth 6 | "x <- c('\u00C0', '\u00CB', '\u00D0')", 7 | "print(x)" 8 | ) 9 | out_utf8 <- reprex(input = in_utf8) 10 | 11 | expect_in(Encoding(out_utf8), c("unknown", "UTF-8")) 12 | 13 | line_in <- grep("^x <-", in_utf8, value = TRUE) 14 | line_out <- grep("^x <-", out_utf8, value = TRUE) 15 | expect_identical(charToRaw(line_in), charToRaw(line_out)) 16 | 17 | line_out <- grep("^#> \\[1\\]", out_utf8, value = TRUE) 18 | expect_match(line_out, "[\u00C0]") 19 | expect_match(line_out, "[\u00CB]") 20 | expect_match(line_out, "[\u00D0]") 21 | 22 | in_latin1 <- iconv(in_utf8, from = "UTF-8", to = "latin1") 23 | out_latin1 <- reprex(input = in_latin1) 24 | 25 | expect_identical( 26 | charToRaw(paste0(out_utf8, collapse = "\n")), 27 | charToRaw(paste0(out_latin1, collapse = "\n")) 28 | ) 29 | }) 30 | -------------------------------------------------------------------------------- /tests/testthat/test-utils-clipboard.R: -------------------------------------------------------------------------------- 1 | test_that("reprex_clipboard() works", { 2 | withr::local_options(list(reprex.clipboard = FALSE)) 3 | expect_false(reprex_clipboard()) 4 | }) 5 | 6 | test_that("reprex_clipboard() insists on length one logical", { 7 | withr::local_options(list(reprex.clipboard = function() "wut")) 8 | expect_snapshot(error = TRUE, reprex_clipboard()) 9 | }) 10 | 11 | test_that("ingest_clipboard() copes when clipboard not available", { 12 | withr::local_options(list(reprex.clipboard = FALSE)) 13 | local_reprex_loud() 14 | msg <- capture_messages( 15 | out <- ingest_clipboard() 16 | ) 17 | expect_equal(out, character()) 18 | expect_match(msg, "clipboard is not available") 19 | }) 20 | -------------------------------------------------------------------------------- /tests/testthat/test-utils-io.R: -------------------------------------------------------------------------------- 1 | test_that("retrofit_files() works", { 2 | local_reprex_loud() 3 | withr::local_options(lifecycle_verbosity = "warning") 4 | 5 | # when `outfile` is not specified, there's nothing to do 6 | expect_equal( 7 | retrofit_files(infile = NULL, wd = NULL), 8 | list(infile = NULL, wd = NULL) 9 | ) 10 | expect_equal( 11 | retrofit_files(infile = "foo.R", wd = "whatever"), 12 | list(infile = "foo.R", wd = "whatever") 13 | ) 14 | 15 | # `wd` takes precedence over `outfile` and we say something 16 | expect_snapshot_warning( 17 | x <- retrofit_files(wd = "this", outfile = "that") 18 | ) 19 | expect_equal(x, list(infile = NULL, wd = "this")) 20 | 21 | # `outfile = NA` morphs into `wd = "."`, if no `infile` 22 | expect_snapshot_warning( 23 | x <- retrofit_files(outfile = NA) 24 | ) 25 | expect_equal(x, list(infile = NULL, wd = ".")) 26 | 27 | # only `wd` is salvaged from `outfile = some/path/blah` and we mention `input` 28 | expect_snapshot_warning( 29 | x <- retrofit_files(outfile = "some/path/blah") 30 | ) 31 | expect_equal(x, list(infile = NULL, wd = "some/path")) 32 | 33 | # `infile` takes over much of `outfile`'s previous role 34 | expect_snapshot_warning( 35 | x <- retrofit_files(infile = "a/path/foo.R", outfile = NA) 36 | ) 37 | expect_equal(x, list(infile = "a/path/foo.R", wd = NULL)) 38 | expect_snapshot_warning( 39 | x <- retrofit_files(infile = "a/path/foo.R", outfile = "other/path/blah") 40 | ) 41 | expect_equal(x, list(infile = "a/path/foo.R", wd = NULL)) 42 | }) 43 | 44 | # root cause of 45 | # https://github.com/tidyverse/reprex/issues/379 46 | test_that("we don't add a suffix more than once", { 47 | x <- "blah_r.R" 48 | expect_equal(x, add_suffix(x, suffix = "r")) 49 | }) 50 | 51 | test_that("make_filebase() works with no input", { 52 | x <- make_filebase(infile = NULL, wd = NULL) 53 | 54 | filebase_base <- path_file(x) 55 | # adjective-animal 56 | expect_match(filebase_base, "^[a-z]+[-][a-z]+$") 57 | 58 | filebase_parent <- path_file(path_dir(x)) 59 | # reprex-[hexademical from tempfile()]-adjective-animal 60 | expect_match(filebase_parent, "^reprex-[[:xdigit:]]+[-][a-z]+[-][a-z]+$") 61 | 62 | temp <- path_real(path_temp()) 63 | expect_identical(path_common(c(x, temp)), temp) 64 | }) 65 | 66 | test_that("make_filebase(wd = '.') works", { 67 | x <- make_filebase(infile = NULL, wd = ".") 68 | expect_equal(path_dir(x), ".") 69 | # adjective-animal 70 | expect_match(x, "^[a-z]+[-][a-z]+$") 71 | }) 72 | 73 | test_that("make_filebase(wd = 'blah') works", { 74 | wd <- path_temp("xyz") 75 | x <- make_filebase(infile = NULL, wd = wd) 76 | expect_equal(path_file(path_dir(x)), "xyz") 77 | # adjective-animal 78 | expect_match(path_file(x), "^[a-z]+[-][a-z]+$") 79 | }) 80 | 81 | test_that("make_filebase(infile = 'blah') works", { 82 | # relative path 83 | expect_equal(make_filebase(infile = "foo.R"), "foo") 84 | expect_equal(make_filebase(infile = "blah/foo.R"), "blah/foo") 85 | 86 | # `wd` should be ignored 87 | expect_equal(make_filebase(infile = "foo.R", wd = "wut"), "foo") 88 | expect_equal(make_filebase(infile = "blah/foo.R", wd = "wut"), "blah/foo") 89 | 90 | # absolute path 91 | infile <- path_temp("abcde.R") 92 | x <- make_filebase(infile = infile) 93 | expect_equal(path_file(x), "abcde") 94 | expect_equal(path_dir(x), path_dir(infile)) 95 | }) 96 | -------------------------------------------------------------------------------- /tests/testthat/test-utils-ui.R: -------------------------------------------------------------------------------- 1 | test_that("reprex_quiet() defaults to NA", { 2 | expect_true(is.na(reprex_quiet())) 3 | }) 4 | 5 | test_that("reprex_alert() and friends work", { 6 | local_reprex_loud() 7 | 8 | expect_snapshot({ 9 | reprex_alert("alert", type = "") 10 | reprex_success("success") 11 | reprex_info("info") 12 | reprex_warning("warning") 13 | reprex_danger("danger") 14 | }) 15 | }) 16 | 17 | test_that("reprex_alert() is under the control of REPREX_QUIET env var", { 18 | local_reprex_quiet() 19 | expect_snapshot(reprex_alert("alert", type = "")) 20 | 21 | local_reprex_loud() 22 | expect_snapshot(reprex_alert("alert", type = "")) 23 | }) 24 | 25 | test_that("reprex_path() works and respects REPREX_QUIET", { 26 | local_reprex_quiet() 27 | expect_snapshot(reprex_path("Something descriptive:", "path/to/file")) 28 | 29 | local_reprex_loud() 30 | expect_snapshot({ 31 | reprex_path("Something descriptive:", "path/to/file") 32 | x <- "path/to/file" 33 | reprex_path("Something descriptive:", x) 34 | y <- c("path", "to", "file") 35 | reprex_path("Something descriptive:", path_join(y)) 36 | }) 37 | }) 38 | -------------------------------------------------------------------------------- /tests/testthat/test-utils.R: -------------------------------------------------------------------------------- 1 | test_that("locate_input() works", { 2 | with_mocked_bindings( 3 | reprex_clipboard = function() TRUE, 4 | expect_identical("clipboard", locate_input(NULL)) 5 | ) 6 | with_mocked_bindings( 7 | reprex_clipboard = function() FALSE, 8 | in_rstudio = function() TRUE, 9 | expect_identical("selection", locate_input(NULL)) 10 | ) 11 | with_mocked_bindings( 12 | reprex_clipboard = function() FALSE, 13 | in_rstudio = function() FALSE, 14 | expect_null(locate_input(NULL)) 15 | ) 16 | expect_identical("path", locate_input(path_temp())) 17 | expect_identical("input", locate_input(c("a", "b"))) 18 | expect_identical("input", locate_input("a\n")) 19 | }) 20 | 21 | test_that("nope() defaults to 'yes' if user not available", { 22 | expect_false(nope()) 23 | }) 24 | 25 | test_that("yep() defaults to 'no' if user not available", { 26 | expect_false(yep()) 27 | }) 28 | -------------------------------------------------------------------------------- /tests/testthat/test-venues.R: -------------------------------------------------------------------------------- 1 | test_that("venue = 'gh' works with/without leading prose", { 2 | skip_on_cran() 3 | input <- c( 4 | "#' Hello world", 5 | "## comment", 6 | "1:5" 7 | ) 8 | output <- c( 9 | "Hello world", 10 | "", 11 | "``` r", 12 | "## comment", 13 | "1:5", 14 | "#> [1] 1 2 3 4 5", 15 | "```" 16 | ) 17 | ret <- reprex(input = input, venue = "gh", advertise = FALSE) 18 | expect_identical(ret, output) 19 | 20 | input <- grep("Hello", input, invert = TRUE, value = TRUE) 21 | output <- grep("Hello", output, invert = TRUE, value = TRUE) 22 | output <- output[nzchar(output)] 23 | ret <- reprex(input = input, venue = "gh", advertise = FALSE) 24 | expect_identical(ret, output) 25 | }) 26 | 27 | test_that("venue = 'R' works, regardless of case", { 28 | skip_on_cran() 29 | input <- c( 30 | "#' Hello world", 31 | "## comment", 32 | "1:5" 33 | ) 34 | output <- c( 35 | "#' Hello world", 36 | "## comment", 37 | "1:5", 38 | "#> [1] 1 2 3 4 5" 39 | ) 40 | ret <- reprex(input = input, venue = "R", advertise = FALSE) 41 | expect_identical(ret[nzchar(ret)], output) 42 | ret <- reprex(input = input, venue = "r", advertise = FALSE) 43 | expect_identical(ret[nzchar(ret)], output) 44 | }) 45 | 46 | test_that("venues = 'ds' and 'so' are aliases for 'gh'", { 47 | skip_on_cran() 48 | input <- c( 49 | "#' Hello world", 50 | "## comment", 51 | "1:5" 52 | ) 53 | ds <- reprex(input = input, venue = "ds", session_info = TRUE, advertise = FALSE) 54 | so <- reprex(input = input, venue = "so", session_info = TRUE, advertise = FALSE) 55 | gh <- reprex(input = input, venue = "gh", session_info = TRUE, advertise = FALSE) 56 | expect_identical(so, gh) 57 | expect_identical(ds, gh) 58 | }) 59 | 60 | test_that("local image link is not interrupted by hard line break for 'gh'", { 61 | skip_on_cran() 62 | input <- c( 63 | "#+ setup, include = FALSE", 64 | "knitr::opts_knit$set(upload.fun = identity)", 65 | "", 66 | "#+ incredibly-long-chunk-name-to-make-image-path-also-incredibly-long", 67 | "plot(1:3)" 68 | ) 69 | out <- reprex(input = input, venue = "gh") 70 | line <- grep("incredibly-long", out, value = TRUE) 71 | expect_length(line, 1) 72 | expect_match(line, "[)]") 73 | }) 74 | 75 | test_that("venue = 'html' works", { 76 | skip_on_cran() 77 | input <- c( 78 | "#' Hello world", 79 | "## comment", 80 | "1:5" 81 | ) 82 | output <- c( 83 | "", 84 | "", 85 | "", 86 | "

Hello world

", 87 | "
## comment",
 88 |     "1:5",
 89 |     "#> [1] 1 2 3 4 5
" 90 | ) 91 | ret <- reprex(input = input, venue = "html", advertise = FALSE) 92 | ret <- ret[nzchar(ret)] 93 | expect_identical(ret, output) 94 | }) 95 | 96 | test_that("venue = 'slack' works", { 97 | skip_on_cran() 98 | input <- c( 99 | "#' Hello world", 100 | "## comment", 101 | "1:5" 102 | ) 103 | output <- c( 104 | "Hello world", 105 | "```", 106 | "## comment", 107 | "1:5", 108 | "#> [1] 1 2 3 4 5", 109 | "```" 110 | ) 111 | ret <- reprex(input = input, venue = "slack") 112 | ret <- ret[nzchar(ret)] 113 | expect_identical(ret, output) 114 | }) 115 | -------------------------------------------------------------------------------- /vignettes/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | *.R 3 | -------------------------------------------------------------------------------- /vignettes/articles/datapasta-reprex.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Using datapasta with reprex" 3 | author: "Mara Averick" 4 | --- 5 | 6 | ```{r setup, include=FALSE} 7 | knitr::opts_chunk$set(echo = TRUE) 8 | ``` 9 | 10 | While using a built-in dataset for a reprex is ideal, sometimes you need to troubleshoot code with a bit of outside data. Meet [datapasta](https://github.com/MilesMcBain/datapasta), a package by [Miles McBain](https://twitter.com/milesmcbain) for "reducing resistance associated with copying and pasting data to and from R." Like reprex, datapasta has addin functionality, so you can select commands from the RStudio Addins and/or associate keyboard shortcuts with them for easy use. 11 | 12 | ## Scenario 1: From spreadsheet to reprex with `tribble_paste()` 13 | 14 | It's easy to copy and paste nicely formatted data from a spreadsheet with datapasta's `tribble_paste()` functionality. I've found the simplest method to be: 15 | 16 | 1. Copy data from a source onto your clipboard. 17 | 2. Click **Paste as tribble** from the datapasta section of the RStudio Addins drop-down. 18 | 3. Be sure to assign your data frame to a name, so you can use it elsewhere in your reprex. 19 | 20 |
21 | Gif of using datapasta::tribble_paste() to get data from a spreadsheet as R code for use in a reprex 22 |

datapasta::tribble_paste()

23 |
24 | 25 | While the output of `tribble_paste()` doesn't have the same level of detail it would with [`dput()`](https://stat.ethz.ch/R-manual/R-patched/library/base/html/dput.html), it works well enough for most scenarios, with the added benefit of being easy to read on the screen. 26 | 27 | ## Scenario 2: From R object to tibble with `dpasta()` 28 | 29 | Now let’s say you have a data frame in R that you want to use in a reprex. You can use datapasta's `dpasta()` function to render your object into the same format as the result of `tribble_paste()`, above. 30 | 31 |
32 | Gif of using datapasta::dpasta() to convert an R data frame into the R code needed to define it in a reprex 33 |

datapasta::dpasta()

34 |
35 | 36 | ## Fin 37 | 38 | There's more to datapasta than discussed here, so be sure to check out its [documentation](https://github.com/MilesMcBain/datapasta). Don't forget, when it comes to reprex, less is always more, so wield the power of datapasta wisely. 39 | 40 | -------------------------------------------------------------------------------- /vignettes/articles/img/anotherdark-andale-60-line-numbers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/reprex/07cd5d74fd25005523a57db97589ff8c3e74c02f/vignettes/articles/img/anotherdark-andale-60-line-numbers.png -------------------------------------------------------------------------------- /vignettes/articles/img/bizarro-selective-reveal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/reprex/07cd5d74fd25005523a57db97589ff8c3e74c02f/vignettes/articles/img/bizarro-selective-reveal.png -------------------------------------------------------------------------------- /vignettes/articles/img/dusk-fira-35-line-numbers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/reprex/07cd5d74fd25005523a57db97589ff8c3e74c02f/vignettes/articles/img/dusk-fira-35-line-numbers.png -------------------------------------------------------------------------------- /vignettes/articles/img/eval-false.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/reprex/07cd5d74fd25005523a57db97589ff8c3e74c02f/vignettes/articles/img/eval-false.png -------------------------------------------------------------------------------- /vignettes/articles/img/keynote-w00t.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/reprex/07cd5d74fd25005523a57db97589ff8c3e74c02f/vignettes/articles/img/keynote-w00t.png -------------------------------------------------------------------------------- /vignettes/articles/learn-reprex.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "How to use reprex" 3 | --- 4 | 5 | Materials from an [RStudio webinar](https://resources.rstudio.com/webinars) delivered September 2018: 6 | 7 | ### Help me help you: Creating reproducible examples with reprex 8 | 9 | What is a reprex? It’s a **repr**oducible **ex**ample. Making a great reprex is both an art and a science and this webinar will cover both aspects. A reprex makes a conversation about code more efficient and pleasant for all. This comes up whenever you ask someone for help, report a bug in software, or propose a new feature. The reprex package (https://reprex.tidyverse.org) makes it especially easy to prepare R code as a reprex, in order to share on sites such as https://community.rstudio.com, https://github.com, or https://stackoverflow.com. The habit of making little, rigorous, self-contained examples also has the great side effect of making you think more clearly about your programming problems. 10 | 11 | Webinar page: 12 | 13 |
Video of September 2018 RStudio webinar about reprex
14 | 15 | Slides on SpeakerDeck: 16 | 17 | 18 | 19 | 20 | 21 | 26 | 27 | -------------------------------------------------------------------------------- /vignettes/articles/suppress-startup-messages.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Suppress package startup messages" 3 | output: rmarkdown::html_vignette 4 | vignette: > 5 | %\VignetteIndexEntry{Suppress package startup messages} 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 | Sometimes your reprex uses packages that emit messages and warnings at startup (dplyr is a very common culprit). In general, these are worth reading! They can alert you to the root cause of your problem, such as a function in one package masking a function in another. But in many cases, this is just distracting, startup noise. 18 | 19 | How can you silence this chatter, specifically? We don't want to suppress messages and warnings, in general, because they are an important part of the reprex. 20 | 21 | ## TL;DR 22 | 23 | Here's a quick look at various techniques. They are described in more detail below. 24 | 25 | Call `library()` with `warn.conflicts = FALSE`. 26 | 27 | ```{r, eval = FALSE} 28 | library(dplyr, warn.conflicts = FALSE) 29 | ``` 30 | 31 | Surround a chatty `library()` call with `suppressPackageStartupMessages()`. 32 | 33 | ```{r, eval = FALSE} 34 | suppressPackageStartupMessages(library(dplyr)) 35 | ``` 36 | 37 | Break your reprex into "chunks", in the `.Rmd` sense, and use a special `#+` comment to silence messages and/or warnings for the chunk that holds a chatty `library()` call. Note that the second `#+` comment is very important, so you don't silence messages and warnings for the entire reprex. 38 | 39 | ```{r, eval = FALSE} 40 | #+ message = FALSE, warning = FALSE 41 | library(dplyr) 42 | 43 | #+ 44 | slice(iris, 1) 45 | ``` 46 | 47 | If you're using one or more tidyverse packages, consider using the tidyverse metapackage, literally. `reprex::reprex()` has an argument `tidyverse_quiet`, which defaults to `TRUE` and silences the startup messages. 48 | 49 | ```{r, eval = FALSE} 50 | library(tidyverse) 51 | 52 | slice(iris, 1) 53 | ``` 54 | 55 | `tidyverse_quiet` also silences startup messages from the [tidymodels](https://www.tidymodels.org) meta-package. 56 | 57 | ## dplyr is chatty at startup 58 | 59 | dplyr is a common culprit for noisy startup, so we use it as an example. Note this messaging as a baseline. 60 | 61 | ```{r} 62 | library(dplyr) 63 | ``` 64 | 65 | ```{r include = FALSE} 66 | unloadNamespace("dplyr") 67 | ``` 68 | 69 | ## `warn.conflicts = FALSE` 70 | 71 | To suppress warnings about conflicts, set the `warn.conflicts` argument of `library()` to `FALSE`. 72 | 73 | ```{r} 74 | library(dplyr, warn.conflicts = FALSE) 75 | 76 | slice(iris, 1) 77 | ``` 78 | 79 | ```{r include = FALSE} 80 | unloadNamespace("dplyr") 81 | ``` 82 | 83 | ## `suppressPackageStartupMessages()` 84 | 85 | Surround `library()` with `suppressPackageStartupMessages()`. 86 | 87 | ```{r} 88 | suppressPackageStartupMessages(library(dplyr)) 89 | 90 | slice(iris, 1) 91 | ``` 92 | 93 | ```{r include = FALSE} 94 | unloadNamespace("dplyr") 95 | ``` 96 | 97 | ## Set `message = FALSE` and `warning = FALSE` for a chunk 98 | 99 | If we were working in R Markdown, we could suppress messages and warnings in the chunk containing `library()` calls, then put our "real code" in a different chunk: 100 | 101 |
```{r, message = FALSE, warning = FALSE}  
102 | library(dplyr)  
103 | ```
104 | 
105 | Some text.
106 | 
107 | `r ''````{r}     
108 | slice(iris, 1)
109 | ```
110 | 111 | We can do the same in plain R code, suitable for `reprex()`ing, by using special comments that start with `#+`. Note that the second `#+` is significant, because it begins a new chunk capable of emitting messages and warnings. 112 | 113 | 114 | ```{r eval = FALSE} 115 | #+ message = FALSE, warning = FALSE 116 | library(dplyr) 117 | message("You CANNOT hear me!") 118 | 119 | #+ 120 | message("You can hear me!") 121 | slice(iris, 1) 122 | ``` 123 | 124 | ## reprex knows about `tidyverse_quiet` 125 | 126 | The `reprex::reprex()` function has a `tidyverse_quiet` argument that defaults to `TRUE`. If your reprex uses one or more tidyverse packages, consider attaching the tidyverse metapackage, instead of individual packages, in order to enjoy a quiet startup. 127 | 128 | 129 | ```{r eval = FALSE} 130 | library(tidyverse) # instead of library(dplyr) 131 | 132 | slice(iris, 1) 133 | ``` 134 | 135 | ```{r echo = FALSE} 136 | suppressPackageStartupMessages(library(dplyr)) 137 | 138 | slice(iris, 1) 139 | ``` 140 | 141 | Note that this default behaviour can be overridden by setting `tidyverse_quiet = FALSE` in a specific `reprex()` call or by setting the option `reprex.tidyverse_quiet = FALSE` in the `.Rprofile` startup file. The `tidyverse_quiet` argument and `reprex.tidyverse_quiet` option also affect startup messages from the [tidymodels](https://www.tidymodels.org) meta-package. 142 | -------------------------------------------------------------------------------- /vignettes/reprex-dos-and-donts.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Reprex do's and don'ts" 3 | output: rmarkdown::html_vignette 4 | vignette: > 5 | %\VignetteIndexEntry{Reprex do's and don'ts} 6 | %\VignetteEngine{knitr::rmarkdown} 7 | %\VignetteEncoding{UTF-8} 8 | --- 9 | 10 | If you're asking for R help, reporting a bug, or requesting a new feature, you're more likely to succeed if you include a good reprex. 11 | 12 | ## Main requirements 13 | 14 | **Use the smallest, simplest, most [built-in data](https://stat.ethz.ch/R-manual/R-patched/library/datasets/html/00Index.html) possible.** 15 | 16 | - Think: `iris` or `mtcars`. Bore me. 17 | - If you must make some objects, minimize their size and complexity. 18 | - Many of the functions and packages you already use offer a way to create a small data frame "inline": 19 | - `read.table()` and friends have a `text` argument. Example: 20 | 21 | ```{r eval = FALSE} 22 | read.csv(text = "a,b\n1,2\n3,4") 23 | #> a b 24 | #> 1 1 2 25 | #> 2 3 4 26 | ``` 27 | 28 | - `tibble::tribble()` lets you use a natural and readable layout. Example: 29 | 30 | ```{r eval = FALSE} 31 | tibble::tribble( 32 | ~ a, ~ b, 33 | 1, 2, 34 | 3, 4 35 | ) 36 | #> # A tibble: 2 x 2 37 | #> a b 38 | #> 39 | #> 1 1 2 40 | #> 2 3 4 41 | ``` 42 | 43 | - Get just a bit of something with `head()` or by indexing with the result of `sample()`. If anything is random, consider using `set.seed()` to make it repeatable. 44 | - The [datapasta package](https://milesmcbain.github.io/datapasta/) can generate code for `data.frame()`, `tibble::tribble()`, or `data.table::data.table()` based on an existing R data frame. For example, a call to `tribble_format(head(ChickWeight, 3))` leaves this on the clipboard, ready to paste into your reprex: 45 | 46 | ```{r eval = FALSE} 47 | tibble::tribble( 48 | ~weight, ~Time, ~Chick, ~Diet, 49 | 42, 0, "1", "1", 50 | 51, 2, "1", "1", 51 | 59, 4, "1", "1" 52 | ) 53 | ``` 54 | - `dput()` is a decent last resort, i.e. if you simply cannot make do with built-in or simulated data or inline data creation in a more readable format. But `dput()` output is not very human-readable. Avoid if at all possible. 55 | - Look at official examples and try to write in that style. Consider adapting one. 56 | 57 | **Include commands on a strict "need to run" basis.** 58 | 59 | - Ruthlessly strip out anything unrelated to the specific matter at hand. 60 | - Include every single command that is required, e.g. loading specific packages via `library(foo)`. 61 | 62 | **Consider including so-called "session info"**, i.e. your OS and versions of R and add-on packages, if it's conceivable that it matters. 63 | 64 | - Use `reprex(..., session_info = TRUE)` for this. 65 | 66 | **Whitespace rationing is not in effect.** 67 | 68 | - Use good [coding style](https://style.tidyverse.org). 69 | - Use `reprex(..., style = TRUE)` to request automated styling of your code. 70 | 71 | **Pack it in, pack it out, and don't take liberties with other people's computers.** You are asking people to run this code! 72 | 73 | - Don't start with `rm(list = ls())`. It is anti-social to clobber other people's workspaces. 74 | - Don't start with `setwd("C:\Users\jenny\path\that\only\I\have")`, because it won't work on anyone else's computer. 75 | - Don't mask built-in functions, i.e. don't define a new function named `c` or `mean`. 76 | - If you change options, store original values at the start, do your thing, then restore them: 77 | 78 | ```{r eval = FALSE} 79 | opar <- par(pch = 19) 80 | 81 | par(opar) 82 | ``` 83 | - If you create files, delete them when you're done: 84 | 85 | ```{r eval = FALSE} 86 | write(x, "foo.txt") 87 | 88 | file.remove("foo.txt") 89 | ``` 90 | - Don't delete files or objects that you didn't create in the first place. 91 | - Take advantage of R's built-in ability to create temporary files and directories. Read up on [`tempfile()` and `tempdir()`](https://stat.ethz.ch/R-manual/R-patched/library/base/html/tempfile.html). 92 | 93 | ## This seems like a lot of work! 94 | 95 | Yes, creating a great reprex requires work. You are asking other people to do work too. It's a partnership. 96 | 97 | 80% of the time you will solve your own problem in the course of writing an excellent reprex. YMMV. 98 | 99 | The remaining 20% of the time, you will create a reprex that is more likely to elicit the desired behavior in others. 100 | 101 | ## Further reading: 102 | 103 | [How to make a great R reproducible example?](https://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example/16532098) thread on StackOverflow 104 | 105 | ## Package philosophy 106 | 107 | The reprex code: 108 | 109 | * Must run and, therefore, should be run **by the person posting**. No faking it. 110 | 111 | * Should be easy for others to digest, so **they don't necessarily have to run it**. You are encouraged to include selected bits of output. :scream: 112 | 113 | * Should be easy for others to copy + paste + run, **if and only if they so choose**. Don't let inclusion of output break executability. 114 | 115 | Accomplished like so: 116 | 117 | * Use `rmarkdown::render()` to run the code and capture output that you would normally see on your screen. This is done in a separate R process, via [callr](https://callr.r-lib.org), to guarantee it is self-contained. 118 | 119 | * Use chunk option `comment = "#>"` to include the output while retaining executability. 120 | --------------------------------------------------------------------------------