reshape_wide <-
  function(data, widen, response, ID, prefix=NULL, sep="_", ...) {

  # capture unquoted parameter names as strings first
  ID <- deparse(substitute(ID))
  widen <- deparse(substitute(widen))
  response <- deparse(substitute(response))

  # apply dot alias AFTER deparse so we get the caller's string, not "widen"
  dots <- list(...)
  if (length(dots) > 0) {
    for (i in seq_along(dots)) {
      if (names(dots)[i] == "group") widen <- as.character(dots[[i]])
    }
  }
 
  # if a tibble, convert to data frame
  df.name <- deparse(substitute(data))  # is NULL if from shiny
  if (exists(df.name, envir=parent.frame())) {
    if (any(grepl("tbl", class(data), fixed=TRUE)))
      data <- data.frame(data)
  }

    
  # note: extra columns beyond ID, widen, response are dropped here
  data <- data[, c(ID, widen, response)]
  dw <- reshape(data, direction="wide",
                idvar=ID, timevar=widen, v.names=response,
                sep=sep)

  sep.nm <- sep
  pattern <- paste(response, sep.nm, sep="")

  if (is.null(prefix)) {
    if (!is.numeric(data[, widen]))
      prefix <- FALSE
    else
      prefix <- TRUE
  }

  if (!prefix)
    names(dw) <- gsub(pattern, "", names(dw), fixed=TRUE)

  return(dw)
}

