├── .github ├── .gitignore ├── FUNDING.yml └── workflows │ ├── pkgdown.yaml │ └── R-CMD-check.yaml ├── vignettes ├── .gitignore └── personalr.Rmd ├── .gitignore ├── LICENSE ├── data-raw ├── icon.png ├── logo_seb.png ├── dependency-helper.R ├── build_logo.R └── icon.svg ├── man ├── figures │ └── logo.png ├── personalr-package.Rd ├── update_core.Rd └── setup_package.Rd ├── pkgdown ├── favicon │ ├── favicon.ico │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── apple-touch-icon.png │ ├── apple-touch-icon-60x60.png │ ├── apple-touch-icon-76x76.png │ ├── apple-touch-icon-120x120.png │ ├── apple-touch-icon-152x152.png │ └── apple-touch-icon-180x180.png ├── extra.css └── _pkgdown.yml ├── NAMESPACE ├── inst └── templates │ ├── packagename-package.R │ ├── pipe.R │ ├── zzz.R │ ├── package-README │ ├── utils.R │ ├── attach.R │ └── conflicts.R ├── NEWS.md ├── .Rbuildignore ├── R ├── personalr-package.R ├── update_core.R ├── setup_package.R └── utils.R ├── cran-comments.md ├── personalr.Rproj ├── DESCRIPTION ├── LICENSE.md ├── README.md └── README.Rmd /.github/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | -------------------------------------------------------------------------------- /vignettes/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | *.R 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | docs 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2020 2 | COPYRIGHT HOLDER: Sebastian Carl 3 | -------------------------------------------------------------------------------- /data-raw/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrcaseb/personalr/HEAD/data-raw/icon.png -------------------------------------------------------------------------------- /man/figures/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrcaseb/personalr/HEAD/man/figures/logo.png -------------------------------------------------------------------------------- /data-raw/logo_seb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrcaseb/personalr/HEAD/data-raw/logo_seb.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrcaseb/personalr/HEAD/pkgdown/favicon/favicon.ico -------------------------------------------------------------------------------- /pkgdown/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrcaseb/personalr/HEAD/pkgdown/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrcaseb/personalr/HEAD/pkgdown/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrcaseb/personalr/HEAD/pkgdown/favicon/apple-touch-icon.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrcaseb/personalr/HEAD/pkgdown/favicon/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrcaseb/personalr/HEAD/pkgdown/favicon/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrcaseb/personalr/HEAD/pkgdown/favicon/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrcaseb/personalr/HEAD/pkgdown/favicon/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrcaseb/personalr/HEAD/pkgdown/favicon/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(setup_package) 4 | export(update_core) 5 | importFrom(magrittr,"%>%") 6 | importFrom(withr,with_tempdir) 7 | -------------------------------------------------------------------------------- /inst/templates/packagename-package.R: -------------------------------------------------------------------------------- 1 | #' @keywords internal 2 | "_PACKAGE" 3 | 4 | # The following block is used by usethis to automatically manage 5 | # roxygen namespace tags. Modify with care! 6 | ## usethis namespace: start 7 | ## usethis namespace: end 8 | NULL 9 | -------------------------------------------------------------------------------- /inst/templates/pipe.R: -------------------------------------------------------------------------------- 1 | #' Pipe operator 2 | #' 3 | #' See \code{magrittr::\link[magrittr:pipe]{\%>\%}} for details. 4 | #' 5 | #' @name %>% 6 | #' @rdname pipe 7 | #' @keywords internal 8 | #' @export 9 | #' @importFrom magrittr %>% 10 | #' @usage lhs \%>\% rhs 11 | NULL 12 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | # personalr 1.0.3 2 | 3 | * The installation of the personal package does not prompt the user with package upgrades. 4 | * Documentation update for R4.2 5 | 6 | # personalr 1.0.1 7 | 8 | * Preparation for CRAN 9 | 10 | # personalr 1.0.0 11 | 12 | * Initial release 13 | -------------------------------------------------------------------------------- /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^personalr\.Rproj$ 2 | ^\.Rproj\.user$ 3 | ^LICENSE\.md$ 4 | ^README\.Rmd$ 5 | ^cran-comments\.md$ 6 | ^data-raw$ 7 | ^vignettes/articles$ 8 | ^_pkgdown\.yml$ 9 | ^docs$ 10 | ^pkgdown$ 11 | ^\.github$ 12 | ^vignettes$ 13 | ^\.travis\.yml$ 14 | ^CRAN-RELEASE$ 15 | ^CRAN-SUBMISSION$ 16 | -------------------------------------------------------------------------------- /R/personalr-package.R: -------------------------------------------------------------------------------- 1 | #' @keywords internal 2 | "_PACKAGE" 3 | 4 | # The following block is used by usethis to automatically manage 5 | # roxygen namespace tags. Modify with care! 6 | ## usethis namespace: start 7 | #' @importFrom magrittr %>% 8 | #' @importFrom withr with_tempdir 9 | ## usethis namespace: end 10 | NULL 11 | -------------------------------------------------------------------------------- /pkgdown/extra.css: -------------------------------------------------------------------------------- 1 | /* 2 | Check: https://www.w3schools.com/css/css_rwd_mediaqueries.asp 3 | for Responsive Web Design - Media Queries 4 | */ 5 | .row > main { 6 | max-width: 100%; 7 | } 8 | 9 | @media only screen and (min-width: 640px) { 10 | main + .col-md-3 { 11 | margin-left: unset; 12 | padding-left: 5rem; 13 | max-width: 75%; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /data-raw/dependency-helper.R: -------------------------------------------------------------------------------- 1 | # Run this to update the DESCRIPTION 2 | imports <- c( 3 | "purrr", 4 | "usethis", 5 | "rstudioapi", 6 | "glue", 7 | "xfun", 8 | "devtools", 9 | "utils", 10 | "desc", 11 | "rprojroot", 12 | "magrittr", 13 | "fs", 14 | "withr" 15 | ) 16 | purrr::walk(imports, usethis::use_package, "Imports") 17 | usethis::use_tidy_description() 18 | rm(imports) 19 | -------------------------------------------------------------------------------- /cran-comments.md: -------------------------------------------------------------------------------- 1 | ## Submission 2 | 3 | This is a minor release that updates that fixes html 5 docs. 4 | 5 | ## R CMD check results 6 | 7 | 0 errors | 0 warnings | 0 notes 8 | 9 | ## revdepcheck results 10 | 11 | We checked 0 reverse dependencies, comparing R CMD check results across CRAN and dev versions of this package. 12 | 13 | * We saw 0 new problems 14 | * We failed to check 0 packages 15 | -------------------------------------------------------------------------------- /personalr.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | ProjectId: 6b174bb7-cce2-4f1f-a3d4-fff70038b18f 3 | 4 | RestoreWorkspace: No 5 | SaveWorkspace: No 6 | AlwaysSaveHistory: Default 7 | 8 | EnableCodeIndexing: Yes 9 | UseSpacesForTab: Yes 10 | NumSpacesForTab: 2 11 | Encoding: UTF-8 12 | 13 | RnwWeave: Sweave 14 | LaTeX: pdfLaTeX 15 | 16 | AutoAppendNewline: Yes 17 | StripTrailingWhitespace: Yes 18 | 19 | BuildType: Package 20 | PackageUseDevtools: Yes 21 | PackageInstallArgs: --no-multiarch --with-keep.source 22 | PackageRoxygenize: rd,collate,namespace 23 | -------------------------------------------------------------------------------- /inst/templates/zzz.R: -------------------------------------------------------------------------------- 1 | .onAttach <- function(...) { 2 | needed <- core[!is_attached(core)] 3 | if (length(needed) == 0) 4 | return() 5 | 6 | crayon::num_colors(TRUE) 7 | personalr_to_replace_attach() 8 | 9 | # if (!"package:conflicted" %in% search()) { 10 | # x <- personalr_to_replace_conflicts() 11 | # msg(personalr_to_replace_conflict_message(x), startup = TRUE) 12 | # } 13 | 14 | msg(cli::rule(right = crayon::bold("Ready to go!")),startup = TRUE) 15 | 16 | } 17 | 18 | is_attached <- function(x) { 19 | paste0("package:", x) %in% search() 20 | } 21 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: mrcaseb # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /data-raw/build_logo.R: -------------------------------------------------------------------------------- 1 | library(hexSticker) 2 | library(showtext) 3 | 4 | ## Loading Google fonts (http://www.google.com/fonts) 5 | # font_add_google("Turret Road", "seb") 6 | # font_add_google("Comfortaa", "seb") 7 | font_add_google("Architects Daughter", "seb") 8 | # font_add_google("Russo One", "seb") 9 | ## Automatically use showtext to render text for future devices 10 | showtext_auto() 11 | 12 | sticker( 13 | "data-raw/icon.png", # icon is 2000x1600 Pixel 14 | package = "personalr", 15 | p_family = "seb", 16 | # asp = 2000 / 1600, 17 | # p_size = 20, 18 | s_x = 1.02, 19 | s_y = .75, 20 | s_width = 0.45, 21 | s_height = (0.45 * 1600 / 2000), 22 | spotlight = TRUE, 23 | l_y = 1.5, 24 | l_alpha = 0.2, 25 | h_fill = "#2c4f67", 26 | h_color = "#192D3B", 27 | h_size = 0.8, 28 | filename = "data-raw/logo_seb.png" 29 | ) 30 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: personalr 2 | Title: Automated Personal Package Setup 3 | Version: 1.0.3 4 | Authors@R: 5 | person("Sebastian", "Carl", , "mrcaseb@gmail.com", role = c("aut", "cre")) 6 | Description: Functions to setup a personal R package that attaches given 7 | libraries and exports personal helper functions. 8 | License: MIT + file LICENSE 9 | URL: https://mrcaseb.github.io/personalr/index.html, 10 | https://github.com/mrcaseb/personalr 11 | BugReports: https://github.com/mrcaseb/personalr/issues 12 | Imports: 13 | desc, 14 | devtools, 15 | fs, 16 | glue, 17 | magrittr, 18 | purrr, 19 | rprojroot, 20 | rstudioapi, 21 | usethis, 22 | utils, 23 | withr, 24 | xfun 25 | Suggests: 26 | dplyr, 27 | tibble 28 | Encoding: UTF-8 29 | Roxygen: list(markdown = TRUE) 30 | RoxygenNote: 7.3.2 31 | -------------------------------------------------------------------------------- /man/personalr-package.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/personalr-package.R 3 | \docType{package} 4 | \name{personalr-package} 5 | \alias{personalr} 6 | \alias{personalr-package} 7 | \title{personalr: Automated Personal Package Setup} 8 | \description{ 9 | \if{html}{\figure{logo.png}{options: style='float: right' alt='logo' width='120'}} 10 | 11 | Functions to setup a personal R package that attaches given libraries and exports personal helper functions. 12 | } 13 | \seealso{ 14 | Useful links: 15 | \itemize{ 16 | \item \url{https://mrcaseb.github.io/personalr/index.html} 17 | \item \url{https://github.com/mrcaseb/personalr} 18 | \item Report bugs at \url{https://github.com/mrcaseb/personalr/issues} 19 | } 20 | 21 | } 22 | \author{ 23 | \strong{Maintainer}: Sebastian Carl \email{mrcaseb@gmail.com} 24 | 25 | } 26 | \keyword{internal} 27 | -------------------------------------------------------------------------------- /pkgdown/_pkgdown.yml: -------------------------------------------------------------------------------- 1 | url: https://mrcaseb.github.io/personalr/ 2 | 3 | template: 4 | bootstrap: 5 5 | bootswatch: flatly 6 | bslib: 7 | font_scale: 1.2 8 | base_font: {google: "IBM Plex Sans"} 9 | heading_font: {google: "Kanit"} 10 | code_font: {google: "Fira Code"} 11 | opengraph: 12 | twitter: 13 | creator: "@mrcaseb" 14 | site: "@mrcaseb" 15 | card: summary_large_image 16 | 17 | authors: 18 | Sebastian Carl: 19 | href: https://mrcaseb.com 20 | 21 | home: 22 | title: An R Package for Automated Personal Package Setup 23 | 24 | navbar: 25 | structure: 26 | left: [home, intro, reference, news, articles] 27 | right: [search, sponsor, twitter, github] 28 | components: 29 | twitter: 30 | icon: "fa-brands fa-bluesky fa-lg" 31 | href: https://mrcaseb.com 32 | alt: Bluesky 33 | reference: 34 | text: "Functions" 35 | href: reference/index.html 36 | sponsor: 37 | icon: "fas fa-heart fa-lg" 38 | href: https://patreon.com/mrcaseb 39 | alt: Patreon 40 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright (c) 2020 Sebastian Carl 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 | -------------------------------------------------------------------------------- /inst/templates/package-README: -------------------------------------------------------------------------------- 1 | {{#Rmd}} 2 | --- 3 | output: github_document 4 | --- 5 | 6 | 7 | 8 | ```{r, include = FALSE} 9 | knitr::opts_chunk$set( 10 | collapse = TRUE, 11 | comment = "#>", 12 | fig.path = "man/figures/README-", 13 | out.width = "100%" 14 | ) 15 | ``` 16 | {{/Rmd}} 17 | 18 | # {{{ Package }}} 19 | 20 | 21 | 22 | 23 | The goal of {{{ Package }}} is to attach a list of chosen 'core' packages when {{{ Package }}} is loaded. It can also be used to export some additional helper functions to make them available on other machines or scripts. 24 | 25 | More information about how to update the core list or add own functions can be found on the [personalr home page](https://mrcaseb.github.io/personalr/articles/personalr.html). 26 | 27 | ## Usage 28 | 29 | {{{ Package }}} is already installed on your machine and can be called with 30 | 31 | ``` r 32 | library({{{ Package }}}) 33 | ``` 34 | If you make changes and want to reinstall it, please open the corresponding project and run 35 | 36 | ``` r 37 | devtools::document() 38 | devtools::install() 39 | ``` 40 | -------------------------------------------------------------------------------- /inst/templates/utils.R: -------------------------------------------------------------------------------- 1 | msg <- function(..., startup = FALSE) { 2 | if (startup) { 3 | if (!isTRUE(getOption("personalr_to_replace.quiet"))) { 4 | packageStartupMessage(text_col(...)) 5 | } 6 | } else { 7 | message(text_col(...)) 8 | } 9 | } 10 | 11 | text_col <- function(x) { 12 | # If RStudio not available, messages already printed in black 13 | if (!rstudioapi::isAvailable()) { 14 | return(x) 15 | } 16 | 17 | if (!rstudioapi::hasFun("getThemeInfo")) { 18 | return(x) 19 | } 20 | 21 | theme <- rstudioapi::getThemeInfo() 22 | 23 | if (isTRUE(theme$dark)) crayon::white(x) else crayon::black(x) 24 | 25 | } 26 | 27 | personalr_to_replace_packages <- function(include_self = TRUE) { 28 | raw <- utils::packageDescription("personalr_to_replace")$Imports 29 | imports <- strsplit(raw, ",")[[1]] 30 | parsed <- gsub("^\\s+|\\s+$", "", imports) 31 | names <- vapply(strsplit(parsed, "\\s+"), "[[", 1, FUN.VALUE = character(1)) 32 | 33 | if (include_self) { 34 | names <- c(names, "personalr_to_replace") 35 | } 36 | 37 | names 38 | } 39 | 40 | invert <- function(x) { 41 | if (length(x) == 0) return() 42 | stacked <- utils::stack(x) 43 | tapply(as.character(stacked$ind), stacked$values, list) 44 | } 45 | -------------------------------------------------------------------------------- /man/update_core.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/update_core.R 3 | \name{update_core} 4 | \alias{update_core} 5 | \title{Update Core of Personal Package} 6 | \usage{ 7 | update_core(path, packagename, core = NULL, append = TRUE) 8 | } 9 | \arguments{ 10 | \item{path}{The path in which the package shall be created. 11 | If it exists, it is used. If it does not exist, it is created, provided 12 | that the parent path exists.} 13 | 14 | \item{packagename}{The name of the newly generated package. It will be 15 | checked to make sure it meets R package naming conventions.} 16 | 17 | \item{core}{A vector or list containing package names that shall be attached 18 | when the newly generated package is loaded. The packages must be installed 19 | on the current system, otherwise an error will be shown.} 20 | 21 | \item{append}{If \code{TRUE} the packages of the argument \code{core} will 22 | be appended to the current core and the package version will be increased 23 | on the "patch" level. Otherwise \code{core} will be overwritten and the 24 | package version will be increased on the "minor" level.} 25 | } 26 | \description{ 27 | Updates the "core" of a personal package created with personalr. It can 28 | either append another package to the current core or overwrite it 29 | with a new core. 30 | } 31 | -------------------------------------------------------------------------------- /man/setup_package.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/setup_package.R 3 | \name{setup_package} 4 | \alias{setup_package} 5 | \title{Setup Personal Package} 6 | \usage{ 7 | setup_package(path, packagename, core = NULL) 8 | } 9 | \arguments{ 10 | \item{path}{The path in which the package shall be created. 11 | If it exists, it is used. If it does not exist, it is created, provided 12 | that the parent path exists.} 13 | 14 | \item{packagename}{The name of the newly generated package. It will be 15 | checked to make sure it meets R package naming conventions.} 16 | 17 | \item{core}{A vector or list containing package names that shall be attached 18 | when the newly generated package is loaded. The packages must be installed 19 | on the current system, otherwise an error will be shown.} 20 | } 21 | \description{ 22 | A function to setup a new personal package or update an existing package. 23 | } 24 | \examples{ 25 | \donttest{ 26 | # create package "mypackage" in temporary directory with 27 | # the core packages dplyr, glue and purrr 28 | withr::with_tempdir({ 29 | install.packages( 30 | c("dplyr", "glue", "purrr"), 31 | repos = "http://cran.us.r-project.org" 32 | ) 33 | setup_package( 34 | path = tempdir(), 35 | packagename = "mypackage", 36 | core = c("dplyr", "glue", "purrr") 37 | ) 38 | }) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /.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 | release: 8 | types: [published] 9 | workflow_dispatch: 10 | 11 | name: pkgdown.yaml 12 | 13 | permissions: read-all 14 | 15 | jobs: 16 | pkgdown: 17 | runs-on: ubuntu-latest 18 | # Only restrict concurrency for non-PR jobs 19 | concurrency: 20 | group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }} 21 | env: 22 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 23 | permissions: 24 | contents: write 25 | steps: 26 | - uses: actions/checkout@v4 27 | 28 | - uses: r-lib/actions/setup-pandoc@v2 29 | 30 | - uses: r-lib/actions/setup-r@v2 31 | with: 32 | use-public-rspm: true 33 | 34 | - uses: r-lib/actions/setup-r-dependencies@v2 35 | with: 36 | extra-packages: any::pkgdown, local::. 37 | needs: website 38 | 39 | - name: Build site 40 | run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE) 41 | shell: Rscript {0} 42 | 43 | - name: Deploy to GitHub pages 🚀 44 | if: github.event_name != 'pull_request' 45 | uses: JamesIves/github-pages-deploy-action@v4.5.0 46 | with: 47 | clean: false 48 | branch: gh-pages 49 | folder: docs 50 | -------------------------------------------------------------------------------- /.github/workflows/R-CMD-check.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | 8 | name: R-CMD-check.yaml 9 | 10 | permissions: read-all 11 | 12 | jobs: 13 | R-CMD-check: 14 | runs-on: ${{ matrix.config.os }} 15 | 16 | name: ${{ matrix.config.os }} (${{ matrix.config.r }}) 17 | 18 | strategy: 19 | fail-fast: false 20 | matrix: 21 | config: 22 | - {os: macos-latest, r: 'release'} 23 | - {os: windows-latest, r: 'release'} 24 | - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} 25 | - {os: ubuntu-latest, r: 'release'} 26 | - {os: ubuntu-latest, r: 'oldrel-1'} 27 | 28 | env: 29 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 30 | R_KEEP_PKG_SOURCE: yes 31 | 32 | steps: 33 | - uses: actions/checkout@v4 34 | 35 | - uses: r-lib/actions/setup-pandoc@v2 36 | 37 | - uses: r-lib/actions/setup-r@v2 38 | with: 39 | r-version: ${{ matrix.config.r }} 40 | http-user-agent: ${{ matrix.config.http-user-agent }} 41 | use-public-rspm: true 42 | 43 | - uses: r-lib/actions/setup-r-dependencies@v2 44 | with: 45 | extra-packages: any::rcmdcheck 46 | needs: check 47 | 48 | - uses: r-lib/actions/check-r-package@v2 49 | with: 50 | upload-snapshots: true 51 | build_args: 'c("--no-manual","--compact-vignettes=gs+qpdf")' 52 | -------------------------------------------------------------------------------- /inst/templates/attach.R: -------------------------------------------------------------------------------- 1 | core_unloaded <- function() { 2 | search <- paste0("package:", core) 3 | core[!search %in% search()] 4 | } 5 | 6 | # Attach the package from the same package library it was 7 | # loaded from before. https://github.com/tidyverse/tidyverse/issues/171 8 | same_library <- function(pkg) { 9 | loc <- if (pkg %in% loadedNamespaces()) dirname(getNamespaceInfo(pkg, "path")) 10 | do.call( 11 | "library", 12 | list(pkg, lib.loc = loc, character.only = TRUE, warn.conflicts = FALSE) 13 | ) 14 | } 15 | 16 | personalr_to_replace_attach <- function() { 17 | to_load <- core_unloaded() 18 | if (length(to_load) == 0) { 19 | return(invisible()) 20 | } 21 | 22 | msg( 23 | cli::rule( 24 | left = crayon::bold("Attaching packages"), 25 | right = crayon::cyan(crayon::bold(paste0( 26 | "personalr_to_replace ", 27 | package_version("personalr_to_replace") 28 | ))) 29 | ), 30 | startup = TRUE 31 | ) 32 | 33 | versions <- vapply(to_load, package_version, character(1)) 34 | packages <- paste0( 35 | crayon::green(cli::symbol$tick), " ", crayon::cyan(format(to_load)), " ", 36 | crayon::col_align(versions, max(crayon::col_nchar(versions))) 37 | ) 38 | 39 | if (length(packages) %% 2 == 1) { 40 | packages <- append(packages, "") 41 | } 42 | col1 <- seq_len(length(packages) / 2) 43 | info <- paste0(packages[col1], " ", packages[-col1]) 44 | 45 | msg(paste(info, collapse = "\n"), startup = TRUE) 46 | 47 | suppressPackageStartupMessages( 48 | lapply(to_load, same_library) 49 | ) 50 | 51 | invisible() 52 | } 53 | 54 | package_version <- function(x) { 55 | version <- as.character(unclass(utils::packageVersion(x))[[1]]) 56 | 57 | if (length(version) > 3) { 58 | version[4:length(version)] <- 59 | crayon::yellow(as.character(version[4:length(version)])) 60 | } 61 | paste0(version, collapse = ".") 62 | } 63 | -------------------------------------------------------------------------------- /inst/templates/conflicts.R: -------------------------------------------------------------------------------- 1 | personalr_to_replace_conflicts <- function() { 2 | envs <- grep("^package:", search(), value = TRUE) 3 | envs <- purrr::set_names(envs) 4 | objs <- invert(lapply(envs, ls_env)) 5 | 6 | conflicts <- purrr::keep(objs, ~ length(.x) > 1) 7 | 8 | personalr_to_replace_names <- 9 | paste0("package:", personalr_to_replace_packages()) 10 | conflicts <- purrr::keep(conflicts, ~ any(.x %in% personalr_to_replace_names)) 11 | 12 | conflict_funs <- purrr::imap(conflicts, confirm_conflict) 13 | conflict_funs <- purrr::compact(conflict_funs) 14 | 15 | structure(conflict_funs, class = "personalr_to_replace_conflicts") 16 | } 17 | 18 | personalr_to_replace_conflict_message <- function(x) { 19 | if (length(x) == 0) { 20 | return("") 21 | } 22 | 23 | header <- cli::rule( 24 | left = crayon::bold("Conflicts"), 25 | right = "personalr_to_replace_conflicts()" 26 | ) 27 | 28 | pkgs <- x %>% purrr::map(~ gsub("^package:", "", .)) 29 | others <- pkgs %>% purrr::map(`[`, -1) 30 | other_calls <- purrr::map2_chr( 31 | others, names(others), 32 | ~ paste0(crayon::blue(.x), "::", .y, "()", collapse = ", ") 33 | ) 34 | 35 | winner <- pkgs %>% purrr::map_chr(1) 36 | funs <- format(paste0( 37 | crayon::blue(winner), 38 | "::", 39 | crayon::green(paste0(names(x), "()")) 40 | )) 41 | bullets <- paste0( 42 | crayon::red(cli::symbol$cross), " ", funs, 43 | " masks ", other_calls, 44 | collapse = "\n" 45 | ) 46 | 47 | paste0(header, "\n", bullets) 48 | } 49 | 50 | 51 | print.personalr_to_replace_conflicts <- function(x, ..., startup = FALSE) { 52 | cli::cat_line(personalr_to_replace_conflict_message(x)) 53 | } 54 | 55 | 56 | confirm_conflict <- function(packages, name) { 57 | # Only look at functions 58 | objs <- packages %>% 59 | purrr::map(~ get(name, pos = .)) %>% 60 | purrr::keep(is.function) 61 | 62 | if (length(objs) <= 1) { 63 | return() 64 | } 65 | 66 | # Remove identical functions 67 | objs <- objs[!duplicated(objs)] 68 | packages <- packages[!duplicated(packages)] 69 | if (length(objs) == 1) { 70 | return() 71 | } 72 | 73 | packages 74 | } 75 | 76 | ls_env <- function(env) { 77 | x <- ls(pos = env) 78 | if (identical(env, "package:dplyr")) { 79 | x <- setdiff(x, c("intersect", "setdiff", "setequal", "union")) 80 | } 81 | x 82 | } 83 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # personalr 5 | 6 | 7 | 8 | [![CRAN 9 | status](https://www.r-pkg.org/badges/version-ago/personalr)](https://CRAN.R-project.org/package=personalr) 10 | [![CRAN 11 | downloads](http://cranlogs.r-pkg.org/badges/grand-total/personalr)](https://CRAN.R-project.org/package=personalr) 12 | [![Lifecycle: 13 | stable](https://img.shields.io/badge/lifecycle-stable-brightgreen.svg)](https://lifecycle.r-lib.org/articles/stages.html#stable) 14 | [![R-CMD-check](https://github.com/mrcaseb/personalr/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/mrcaseb/personalr/actions/workflows/R-CMD-check.yaml) 15 | 16 | 17 | ## Preface 18 | 19 | If you work with R or any other programming language for a while, you 20 | will come to the point where you want to use already written code when 21 | developing a script and often need the same packages to do your work.The 22 | easiest solution is to save the loading of the regularly used packages 23 | and maybe some helper functions in a separate script and then load this 24 | script with `source(...)` into the Global Environment. 25 | 26 | However, this approach has two disadvantages: 27 | 28 | 1. Over time, the Global Environment becomes littered, making it harder 29 | to find important objects and 30 | 2. The `source` script must either be available and up-to-date on the 31 | local machine or be made available on the Internet. 32 | 33 | ## Package Purpose 34 | 35 | The best solution for the above mentioned disadvantages is an own 36 | (personal) package, but for the setup it needs a basic understanding of 37 | how to develop packages. 38 | 39 | The goal of personalr is to do exactly that. A basic setup of a personal 40 | package, which loads a modifiable list of packages and some basic 41 | functions. 42 | 43 | ## Installation 44 | 45 | You can install the released version of personalr from 46 | [CRAN](https://cran.r-project.org/package=personalr) with: 47 | 48 | ``` r 49 | install.packages("personalr") 50 | ``` 51 | 52 | You can install the development version from 53 | [GitHub](https://github.com/mrcaseb/personalr/) with: 54 | 55 | ``` r 56 | if (!require("pak")) install.packages("pak") 57 | pak::pak("mrcaseb/personalr") 58 | ``` 59 | -------------------------------------------------------------------------------- /R/update_core.R: -------------------------------------------------------------------------------- 1 | #' Update Core of Personal Package 2 | #' 3 | #' Updates the "core" of a personal package created with personalr. It can 4 | #' either append another package to the current core or overwrite it 5 | #' with a new core. 6 | #' 7 | #' @inheritParams setup_package 8 | #' @param append If \code{TRUE} the packages of the argument \code{core} will 9 | #' be appended to the current core and the package version will be increased 10 | #' on the "patch" level. Otherwise \code{core} will be overwritten and the 11 | #' package version will be increased on the "minor" level. 12 | #' @export 13 | update_core <- function(path, packagename, core = NULL, append = TRUE) { 14 | # check the core vector 15 | purrr::walk(core, check_for_package) 16 | 17 | # create the package and use the path for next steps 18 | if (!is_package(path)) { 19 | path <- fs::path_expand(glue::glue("{path}/{packagename}")) 20 | } 21 | 22 | # move to the correct working directory 23 | usethis::local_project(path) 24 | 25 | # Remove deps if append = FALSE 26 | if (!isTRUE(append)) { 27 | desc::desc_del_deps() 28 | } 29 | 30 | # write new deps and tidy up DESCRIPTION 31 | purrr::walk(c(core, "cli", "crayon", "rstudioapi"), use_dependency, "Imports") 32 | usethis::use_tidy_description() 33 | 34 | # get old core packages 35 | if (isTRUE(append)) { 36 | old_core <- utils::packageDescription(packagename)$Imports %>% 37 | strsplit(",\n") %>% 38 | unlist() 39 | } else { 40 | old_core <- NULL 41 | } 42 | 43 | # combine old and new core 44 | new_core <- c( 45 | core, 46 | old_core[which(!old_core %in% c("cli", "crayon", "rstudioapi"))] 47 | ) %>% 48 | sort() 49 | 50 | output_string <- glue::glue( 51 | "If you really want to update your core you'll have to", 52 | "confirm the following dialogue...!" 53 | ) 54 | 55 | usethis::ui_info("{output_string}\n") 56 | 57 | # write new core file 58 | usethis::write_over( 59 | usethis::proj_path("R/core.R"), 60 | create_core_script(new_core) 61 | ) 62 | 63 | if (isTRUE(append)) { 64 | usethis::use_version("patch") 65 | } else { 66 | usethis::use_version("minor") 67 | } 68 | 69 | # Now document and install the package 70 | usethis::ui_todo("Updating documentation and installing {packagename}...") 71 | devtools::document(pkg = path, quiet = TRUE) 72 | devtools::install( 73 | pkg = path, 74 | reload = FALSE, 75 | build = FALSE, 76 | force = TRUE, 77 | quiet = FALSE 78 | ) 79 | 80 | return(invisible(TRUE)) 81 | } 82 | -------------------------------------------------------------------------------- /README.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | output: github_document 3 | --- 4 | 5 | 6 | 7 | ```{r, include = FALSE} 8 | knitr::opts_chunk$set( 9 | collapse = TRUE, 10 | comment = "#>", 11 | fig.path = "man/figures/README-", 12 | out.width = "100%" 13 | ) 14 | ``` 15 | 16 | # personalr 17 | 18 | 19 | [![CRAN status](https://www.r-pkg.org/badges/version-ago/personalr)](https://CRAN.R-project.org/package=personalr) 20 | [![CRAN downloads](http://cranlogs.r-pkg.org/badges/grand-total/personalr)](https://CRAN.R-project.org/package=personalr) 21 | [![Lifecycle: stable](https://img.shields.io/badge/lifecycle-stable-brightgreen.svg)](https://lifecycle.r-lib.org/articles/stages.html#stable) 22 | [![R-CMD-check](https://github.com/mrcaseb/personalr/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/mrcaseb/personalr/actions/workflows/R-CMD-check.yaml) 23 | 24 | 25 | ## Preface 26 | 27 | If you work with R or any other programming language for a while, you will come to the point where you want to use already written code when developing a script and often need the same packages to do your work.The easiest solution is to save the loading of the regularly used packages and maybe some helper functions in a separate script and then load this script with `source(...)` into the Global Environment. 28 | 29 | However, this approach has two disadvantages: 30 | 31 | 1. Over time, the Global Environment becomes littered, making it harder to find important objects and 32 | 1. The `source` script must either be available and up-to-date on the local machine or be made available on the Internet. 33 | 34 | ## Package Purpose 35 | 36 | The best solution for the above mentioned disadvantages is an own (personal) package, but for the setup it needs a basic understanding of how to develop packages. 37 | 38 | The goal of personalr is to do exactly that. A basic setup of a personal package, which loads a modifiable list of packages and some basic functions. 39 | 40 | ## Installation 41 | 42 | You can install the released version of personalr from [CRAN](https://cran.r-project.org/package=personalr) with: 43 | 44 | ``` {r eval = FALSE} 45 | install.packages("personalr") 46 | ``` 47 | 48 | You can install the development version from [GitHub](https://github.com/mrcaseb/personalr/) with: 49 | 50 | ``` {r eval = FALSE} 51 | if (!require("pak")) install.packages("pak") 52 | pak::pak("mrcaseb/personalr") 53 | ``` 54 | 55 | ## One more thing 56 | 57 | personalr is open source and it builds on top of other open source projects. However, maintaining this package will be a lot of work so I kindly ask you to consider donating at [patreon](https://www.patreon.com/mrcaseb). 58 | -------------------------------------------------------------------------------- /R/setup_package.R: -------------------------------------------------------------------------------- 1 | #' Setup Personal Package 2 | #' 3 | #' A function to setup a new personal package or update an existing package. 4 | #' 5 | #' @param path The path in which the package shall be created. 6 | #' If it exists, it is used. If it does not exist, it is created, provided 7 | #' that the parent path exists. 8 | #' @param packagename The name of the newly generated package. It will be 9 | #' checked to make sure it meets R package naming conventions. 10 | #' @param core A vector or list containing package names that shall be attached 11 | #' when the newly generated package is loaded. The packages must be installed 12 | #' on the current system, otherwise an error will be shown. 13 | #' @export 14 | #' @examples 15 | #' \donttest{ 16 | #' # create package "mypackage" in temporary directory with 17 | #' # the core packages dplyr, glue and purrr 18 | #' withr::with_tempdir({ 19 | #' install.packages( 20 | #' c("dplyr", "glue", "purrr"), 21 | #' repos = "http://cran.us.r-project.org" 22 | #' ) 23 | #' setup_package( 24 | #' path = tempdir(), 25 | #' packagename = "mypackage", 26 | #' core = c("dplyr", "glue", "purrr") 27 | #' ) 28 | #' }) 29 | #' } 30 | setup_package <- function(path, packagename, core = NULL) { 31 | # check the core vector 32 | purrr::walk(core, check_for_package) 33 | 34 | # create the package and use the path for next steps 35 | path <- usethis::create_package( 36 | glue::glue("{path}/{packagename}"), 37 | rstudio = rstudioapi::isAvailable(), 38 | open = FALSE, 39 | fields = list( 40 | Version = "1.0.0" 41 | ) 42 | ) 43 | 44 | # move to the correct working directory 45 | usethis::local_project(path) 46 | 47 | # Add package doc file 48 | usethis::use_template( 49 | "packagename-package.R", 50 | glue::glue("R/{packagename}-package.R") 51 | ) 52 | 53 | # Add Readme as markdown file because we want to keep it easy 54 | usethis::use_template( 55 | "package-README", 56 | "README.md", 57 | data = package_data(), 58 | open = FALSE, 59 | package = "personalr" 60 | ) 61 | 62 | # Add core packages to "Imports" and save core script 63 | purrr::walk(c(core, "cli", "crayon", "rstudioapi"), use_dependency, "Imports") 64 | usethis::use_tidy_description() 65 | usethis::write_over(usethis::proj_path("R/core.R"), create_core_script(core)) 66 | 67 | # Add template files 68 | templates <- c("attach", "conflicts", "pipe", "utils", "zzz") 69 | purrr::walk(templates, add_template) 70 | 71 | # Use the package name in all templates 72 | xfun::gsub_dir( 73 | "personalr_to_replace", 74 | packagename, 75 | dir = usethis::proj_path("R"), 76 | ext = "R" 77 | ) 78 | 79 | # Now document and install the package 80 | usethis::ui_todo("Updating documentation and installing {packagename}...") 81 | devtools::document(pkg = path, quiet = TRUE) 82 | devtools::install( 83 | pkg = path, 84 | reload = FALSE, 85 | build = FALSE, 86 | force = TRUE, 87 | quiet = FALSE, 88 | upgrade = FALSE 89 | ) 90 | 91 | # Now activate project 92 | usethis::proj_activate(path) 93 | } 94 | 95 | 96 | -------------------------------------------------------------------------------- /data-raw/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 64 | -------------------------------------------------------------------------------- /R/utils.R: -------------------------------------------------------------------------------- 1 | # Taken from usethis ------------------------------------------------------ 2 | 3 | use_dependency <- function(package, type, min_version = NULL) { 4 | stopifnot(is_string(package)) 5 | stopifnot(is_string(type)) 6 | 7 | if (package != "R" && !is_installed(package)) { 8 | usethis::ui_stop(c( 9 | "{usethis::ui_value(package)} must be installed before you can ", 10 | "take a dependency on it." 11 | )) 12 | } 13 | 14 | if (isTRUE(min_version)) { 15 | min_version <- utils::packageVersion(package) 16 | } 17 | version <- if (is.null(min_version)) "*" else paste0(">= ", min_version) 18 | 19 | types <- c("Depends", "Imports", "Suggests", "Enhances", "LinkingTo") 20 | names(types) <- tolower(types) 21 | type <- types[[match.arg(tolower(type), names(types))]] 22 | 23 | deps <- desc::desc_get_deps(usethis::proj_get()) 24 | 25 | existing_dep <- deps$package == package 26 | existing_type <- deps$type[existing_dep] 27 | existing_ver <- deps$version[existing_dep] 28 | is_linking_to <- (existing_type != "LinkingTo" & type == "LinkingTo") | 29 | (existing_type == "LinkingTo" & type != "LinkingTo") 30 | 31 | # No existing dependency, so can simply add 32 | if (!any(existing_dep) || any(is_linking_to)) { 33 | usethis::ui_done("Adding {usethis::ui_value(package)} to {usethis::ui_field(type)} field in DESCRIPTION") 34 | desc::desc_set_dep(package, type, version = version, file = usethis::proj_get()) 35 | return(invisible()) 36 | } 37 | 38 | existing_type <- setdiff(existing_type, "LinkingTo") 39 | delta <- sign(match(existing_type, types) - match(type, types)) 40 | if (delta < 0) { 41 | # don't downgrade 42 | usethis::ui_warn( 43 | "Package {usethis::ui_value(package)} is already listed in \\ 44 | {usethis::ui_value(existing_type)} in DESCRIPTION, no change made." 45 | ) 46 | } else if (delta == 0 && !is.null(min_version)) { 47 | # change version 48 | upgrade <- existing_ver == "*" || numeric_version(min_version) > version_spec(existing_ver) 49 | if (upgrade) { 50 | usethis::ui_done( 51 | "Increasing {usethis::ui_value(package)} version to {usethis::ui_value(version)} in DESCRIPTION" 52 | ) 53 | desc::desc_set_dep(package, type, version = version, file = usethis::proj_get()) 54 | } 55 | } else if (delta > 0) { 56 | # upgrade 57 | if (existing_type != "LinkingTo") { 58 | usethis::ui_done( 59 | " 60 | Moving {usethis::ui_value(package)} from {usethis::ui_field(existing_type)} to {usethis::ui_field(type)} \\ 61 | field in DESCRIPTION 62 | " 63 | ) 64 | desc::desc_del_dep(package, existing_type, file = usethis::proj_get()) 65 | desc::desc_set_dep(package, type, version = version, file = usethis::proj_get()) 66 | } 67 | } 68 | 69 | invisible() 70 | } 71 | 72 | is_installed <- function(pkg) { 73 | requireNamespace(pkg, quietly = TRUE) 74 | } 75 | 76 | check_for_package <- function(package){ 77 | if (package != "R" && !is_installed(package)) { 78 | usethis::ui_stop(c( 79 | "Package {usethis::ui_value(package)} must be installed before you can ", 80 | "take a dependency on it." 81 | )) 82 | } 83 | } 84 | 85 | package_data <- function(base_path = usethis::proj_get()){ 86 | desc <- desc::description$new(base_path) 87 | as.list(desc$get(desc$fields())) 88 | } 89 | 90 | version_spec <- function(x) { 91 | x <- gsub("(<=|<|>=|>|==)\\s*", "", x) 92 | numeric_version(x) 93 | } 94 | 95 | is_package <- function(base_path = usethis::proj_get()) { 96 | res <- tryCatch( 97 | rprojroot::find_package_root_file(path = base_path), 98 | error = function(e) NULL 99 | ) 100 | !is.null(res) 101 | } 102 | 103 | # Taken from https://github.com/radiant-rstats/radiant.data/blob/m -------- 104 | 105 | is_string <- function(x) { 106 | length(x) == 1 && is.character(x) && !is_empty(x) 107 | } 108 | 109 | is_empty <- function(x, empty = "\\s*") { 110 | is_not(x) || (length(x) == 1 && grepl(paste0("^", empty, "$"), x)) 111 | } 112 | 113 | is_not <- function(x) { 114 | length(x) == 0 || (length(x) == 1 && is.na(x)) 115 | } 116 | 117 | 118 | # Own stuff --------------------------------------------------------------- 119 | 120 | add_template <- function(template_name){ 121 | usethis::use_template( 122 | glue::glue("{template_name}.R"), 123 | glue::glue("R/{template_name}.R"), 124 | package = "personalr") 125 | } 126 | 127 | create_core_script <- function(pkgs){ 128 | paste( 129 | 'core <- c( \n"', 130 | paste0(pkgs, collapse = '",\n"'), '"\n)', 131 | collapse = "\n", 132 | sep = "" 133 | ) 134 | } 135 | -------------------------------------------------------------------------------- /vignettes/personalr.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Introduction to personalr" 3 | author: "Sebastian Carl" 4 | --- 5 | 6 | ```{r, include = FALSE} 7 | knitr::opts_chunk$set( 8 | collapse = TRUE, 9 | comment = "#>" 10 | ) 11 | options(cli.num_colors = 1, crayon.enabled = FALSE) 12 | ``` 13 | 14 | # Acknowledgement 15 | 16 | Setting up an R package isn't really intuitive as the developer needs a basic understanding of some package conventions and good practice methods. There are multiple packages in the R landscape that help doing exactly this. `personalr` makes heavy usage of the most important package development helper package: [`usethis`](https://usethis.r-lib.org/). It has a ton of useful functions but the developer has to know which of them is needed for the individual purpose. 17 | 18 | `personalr` is more or less a wrapper around several usethis functions and completes the whole thing with some helper functions. The package setup that personalr creates is also based on the [`tidyverse`](https://tidyverse.tidyverse.org/) package. 19 | 20 | Everything you need to know about R package development is perfectly summarized in [Hadley Wickham's book R Packages](https://r-pkgs.org/). 21 | 22 | # Usage 23 | 24 | ## First setup 25 | 26 | The main function of `personalr` is `setup_package()`. Handed a valid path, the desired package name and a vector or list of package names (the 'core' of the personal package that is about to be created) it does the following things: 27 | 28 | - create the project with the intended package name 29 | - create all basic package files like DESCRIPTION (including the Imports of the 'core' packages), NAMESPACE or the "R" directory 30 | - create a basic Readme 31 | - create all scripts and functions in the R directory that are required to attach the core packages 32 | - add the pipe operator `magrittr::%>%()` to your exported functions so it is usable as soon as the package is loaded 33 | - document and install the package 34 | - open the new package in a separate R session. 35 | 36 | The following example creates the new package `"mypackage"` with the `core` packages dplyr, glue and purrr in a temporary directory. 37 | 38 | ```{r, eval=FALSE} 39 | library(personalr) 40 | temp_directory <- tempdir() 41 | setup_package(path = temp_directory, packagename = "mypackage", core = c("dplyr", "glue", "purrr")) 42 | ``` 43 | 44 | ```{r setup, eval=TRUE, echo=FALSE} 45 | library(personalr) 46 | temp_directory <- tempdir() 47 | setup_package(path = temp_directory, packagename = "mypackage", core = c("dplyr", "glue", "purrr")) 48 | ``` 49 | 50 | Once the setup is finished and the new package installed, the new package should be opened in a separate R session. It will show the following files and directories 51 | 52 | ```{r, echo=FALSE} 53 | library(fs) 54 | fs::dir_tree(fs::path(temp_directory, "mypackage")) 55 | ``` 56 | 57 | ## Update your package 58 | 59 | There are basically two reasons why you want to update your personal package: 60 | 61 | 1. You want to update the list of `core` packages 62 | 1. You want to add a helper function so you can call it when the package is loaded (i.e. 'export' a function) 63 | 64 | ### Update your 'core' packages 65 | 66 | There is a separate function in `personalr` to update your list of `core` packages: `update_core()`. It can either append new packages to the existing `core` or overwrite it completely (with the logical argument `append`). 67 | 68 | Assuming you have run the above code and have created the personal package `"mypackage"` with the `core` packages "dplyr", "glue" and "purrr" you can add another package, e.g. "tibble" by running the following code (please note that the example uses temporary directories and if you run this on your machine it's easier to open the project and set `path = "."`). 69 | 70 | ```{r, eval=FALSE} 71 | update_core(path = temp_directory, packagename = "mypackage", core = "tibble", append = TRUE) 72 | ``` 73 | 74 | ```{r, eval=TRUE, echo=FALSE} 75 | update_core(path = temp_directory, packagename = "mypackage", core = "tibble", append = TRUE) 76 | ``` 77 | 78 | Now `"mypackage"` attaches "dplyr", "glue", "purrr" and "tibble" when it is loaded. If you want to overwrite the core (i.e. only use "tibble" and drop the other packages) just set `append = FALSE` in the above code chunk. 79 | 80 | ### Add your own exported helper function 81 | 82 | One of the strengths of a package is that you are able to save your helper functions inside the package and make them available in your code without littering the Global Environment. 83 | 84 | Let's say you often use the negated version of `%in%` to select values that are *not* in a vector. The typical way to do it is `!value %in% vector`. This is somewhat annoying as it's hard to read the code and see the exclamation mark at the beginning of the expression. So now we want to write and export our own little helper for the negated version of `%in%`, and we call it `%nin%`. 85 | 86 | If you run this inside your project 87 | 88 | ```{r, eval=FALSE} 89 | usethis::use_r("nin") 90 | ``` 91 | 92 | it will create a new script `"R/nin.R"` and open it directly. Add the code of your helper function and don't forget to export it with `#' @export` (this means the next time you document and install your package the new function will be exported and available for usage). 93 | 94 | ```{r, eval=FALSE} 95 | #' @export 96 | '%nin%' <- Negate(`%in%`) 97 | ``` 98 | 99 | To update your package you should consider changing the package version to make more clear something changed by running 100 | 101 | ```{r, eval=FALSE} 102 | usethis::use_version() 103 | ``` 104 | 105 | and afterwards documenting and installing the new version by running 106 | 107 | ```{r, eval=FALSE} 108 | devtools::document() 109 | devtools::install() 110 | ``` 111 | 112 | --------------------------------------------------------------------------------