R/brew.R

Defines functions brew_interactive brew_package brew

Documented in brew brew_interactive brew_package

#' Set up potions for easy data retrieval
#' 
#' Function to place a list into `options()`, or to update previously-stored 
#' data.
#' @param ... One or named arguments giving attributes to be stored; or 
#' alternatively a `list` containing the same.
#' @param file string: optional file containing data to be stored via `options()`.
#' Valid formats are `.yml` or `.json`. 
#' @param .slot string: optional name to mandate where data is stored. Defaults 
#' to a random string generated by `stringi::stri_rand_strings()`.
#' @param .pkg string: package name that `potions` is being used within. 
#' Typically only used during `onLoad()`, after which later calls do not
#' require this argument to be set.
#' @param method string: How should new data be written to `options()`? See 
#' details for specifics.
#' @importFrom rlang abort
#' @details 
#' The default method is to use `brew` without setting either `.pkg` or `.slot`
#' (but not both), and letting `potions` determine which slot to use. If greater
#' control is needed, you can use `brew_package()` or `brew_interactive()`. 
#' Note that if neither `.slot` or `.pkg` are set, `potions` defaults to `.slot`
#' , unless `.pkg` information has previously been supplied (and `.slot` 
#' information has not). This might be undesirable in a package development 
#' situation.
#' 
#' If both `...` and `file` arguments are empty, this function sets up an 
#' empty `potions` object in `options("potions-pkg")`; See `potions-class` for 
#' more information on this data type. If `...` and `file` arguments 
#' are provided, they will be amalgamated using `purrr::list_modify()`. If there
#' are identical names in both lists, those in `...` are chosen.
#'  
#' If the user repeatedly calls `brew()`, later list entries overwrite early 
#' entries. Whole lists are not overwritten unless all top-level entry names 
#' match, or `method` is set to `"overwrite"`, which is a shortcut to using
#' `drain()` before `brew()`. The default behaviour is `method = "modify"`, 
#' which uses `purrr::list_modify()` to do the joining. Similarly `"merge"` uses 
#' `purrr::list_merge()`. `method = "leaves"` only overwrites terminal nodes, 
#' leaving the structure of the list otherwise unaffected. For non-nested lists, 
#' this behaviour is identical to `"modify"`, but for nested lists it can be a 
#' useful shortcut.
#' @returns This function never returns an object; it is called for its' side-
#' effect of caching data using `options()`.
#' @examples 
#' # basic usage is to pass arguments using `=`
#' brew(x = 1)
#' 
#' # lists are also permitted
#' list(x = 2) |> brew()
#' 
#' # as are passing lists as objects
#' my_list <- list(x = 3)
#' my_list |> brew()
#' 
#' # or within a function
#' my_fun <- function(){list(x = 1, y = 2)}
#' my_fun() |> brew()
#' 
#' # optional clean-up
#' drain()
#' @export
brew <- function(..., file, .slot, .pkg, 
                 method = c("modify", "merge", "overwrite", "leaves")){
  
  method <- match.arg(method)
  
  # determine behavior based on supplied arguments
  has_slot <- !missing(.slot)
  has_pkg <- !missing(.pkg)
  if(has_slot){
    if(has_pkg){
      abort("Both `.slot` and `.pkg` have been set; please choose one")
    }
    brew_interactive(..., 
                     file = file, 
                     .slot = .slot, 
                     method = method)
  }else{
    if(has_pkg){
      brew_package(..., 
                   file = file, 
                   .pkg = .pkg,
                   method = method)
    }else{ # if .slot and .pkg missing, choose based on call location
      package_check <- trace_back()$namespace |> 
        check_within_pkg()
      if(package_check$within){
        brew_package(..., 
                     file = file, 
                     .pkg = package_check$pkg, 
                     method = method)
      }else{
        lookup <- check_existing_slots()
        switch(lookup$method,
               "all_empty" = {brew_interactive(..., 
                                               file = file,
                                               method = method)}, # no data; .slot is random
               ".slot" = {brew_interactive(..., 
                                           file = file, 
                                           .slot = lookup$value,
                                           method = method)}) 
      }
    }
  }
}

#' @rdname brew
#' @importFrom rlang enquos
#' @export
brew_package <- function(..., file, .pkg, method){
  # check supplied data
  # check_is_logical(leaves)
  data <- check_potions_data(list(...), file)
  # check package info
  check_is_character(.pkg)
  check_length_one(.pkg)
  # update data
  current_list <- check_potions_storage() |>
    update_package_names(.pkg) |>
    update_data(provided = data, .pkg = .pkg, method = method)
  # push to options
  options(list("potions-pkg" = current_list))
}

#' @rdname brew
#' @importFrom rlang enquos
#' @export
brew_interactive <- function(..., file, .slot, method){
  # check supplied data
  # check_is_logical(leaves)
  data <- check_potions_data(list(...), file) 
  .slot <- check_slot_name(.slot)
  # update data
  current_list <- check_potions_storage() |> 
                  update_default_name(.slot = .slot) |>
                  update_data(data, .slot = .slot, method = method)
  options(list("potions-pkg" = current_list))
}

Try the potions package in your browser

Any scripts or data that you put into this service are public.

potions documentation built on Aug. 23, 2023, 9:07 a.m.