17 Case study: rgb()

Interface: * Function name and argument names. * alpha has no default but isn’t required. * names not required (imo). * maxColorValue doens’t have most useful default, and not really needed (imo). * Data frame rather than matrix. * Error if function specification is correct * Check for data type, not missingness.

library(rlang)

rgba <- function(r, g, b, a = NULL) {
  if (is.data.frame(r)) {
    df <- r
    if (!ncol(df) %in% c(3L, 4L)) {
      abort("If `r` is data frame, it must have 3 or 4 columns.")
    }
    
    if (!missing(b) || !missing(g) || !missing(a)) {
      abort("If `r` is a data frame, `b`, `g`, and `a` must not be set.")
    }
    
    r <- df[[1L]]
    g <- df[[2L]]
    b <- df[[3L]]
    if (ncol(df) == 4) {
      a <- df[[4L]]
    }
  }
  
  rgb(r, g, b, alpha = a, maxColorValue = 255)
}

rgba(16, 16, 16)
## [1] "#101010"
rgba(data.frame(16, 16, 16))
## [1] "#101010"
rgba(data.frame(16, 16))
## If `r` is data frame, it must have 3 or 4 columns.
rgba(data.frame(16, 16, 16), 1)
## If `r` is a data frame, `b`, `g`, and `a` must not be set.
rgba <- function(r, g, b, a = NULL) {
  if (is.data.frame(r)) {
    df <- r
    if (!all(c("r", "g", "b")) %in% names(df)) {
      abort("If first argument is a data frame, it must have r, g, and b columns.")
    }
    
    if (!missing(b) || !missing(g) || !missing(a)) {
      abort("If `r` is a data frame, `b`, `g`, and `a` must not be set.")
    }
  } else {
    # Handles vectorisation
    df <- tibble(r = r, g = g, b = b, a = a) 
  }
  
  # Assumes this function checks types and gives informative error messages
  rgb(df$r, df$g, df$b, alpha = df$a, maxColorValue = 255)
}