R/whoami.R

Defines functions whoami

Documented in whoami

################################################################################
# This file is released under the GNU General Public License, Version 3, GPL-3 #
# Copyright (C) 2020 Yohann Demont                                             #
#                                                                              #
# It is part of IFC package, please cite:                                      #
# -IFC: An R Package for Imaging Flow Cytometry                                #
# -YEAR: 2020                                                                  #
# -COPYRIGHT HOLDERS: Yohann Demont, Gautier Stoll, Guido Kroemer,             #
#                     Jean-Pierre Marolleau, Loïc Garçon,                      #
#                     INSERM, UPD, CHU Amiens                                  #
#                                                                              #
# DISCLAIMER:                                                                  #
# -You are using this package on your own risk!                                #
# -We do not guarantee privacy nor confidentiality.                            #
# -This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or        #
# FITNESS FOR A PARTICULAR PURPOSE. In no event shall the copyright holders or #
# contributors be liable for any direct, indirect, incidental, special,        #
# exemplary, or consequential damages (including, but not limited to,          #
# procurement of substitute goods or services; loss of use, data, or profits;  #
# or business interruption) however caused and on any theory of liability,     #
# whether in contract, strict liability, or tort (including negligence or      #
# otherwise) arising in any way out of the use of this software, even if       #
# advised of the possibility of such damage.                                   #
#                                                                              #
# You should have received a copy of the GNU General Public License            #
# along with IFC. If not, see <http://www.gnu.org/licenses/>.                  #
################################################################################

#' @title Input Identification
#' @description
#' Helper that identifies input arguments thanks to their IFC classes even if they are not or mis named.
#' @param entries arguments from the function \code{\link{whoami}} is called.
#' /!\ \code{\link{whoami}} MUST be called explicitly this way: whoami(entries = as.list(match.call())).
#' @param search a non duplicated named list of classes to search for entries.
#' @param reinit whether to reinitialize arguments to their default values in called environment. Default is TRUE.
#' @details if two argument of the same 'search' class are found an error will be thrown.
#' 'fileName' will be searched every time.\cr
#' -at first, as an argument (named or not) of the class designated in 'search' to be the "fileName",\cr
#' -otherwise, as an argument (named or not) of class `fileName`,\cr
#' -otherwise, as a named argument of name "fileName" that was not found using 'search',\cr
#' -and finally, if still not found as the first not named argument not found in 'search' of type string.
#' @return a list whose members are 'fileName': value of fileName if provided as a named argument 
#' in entries and all classes defined in 'search'
#' @keywords internal
whoami = function(entries = as.list(match.call()),
                  search = list(info = "IFC_info", 
                                param = "IFC_param",
                                offsets = "IFC_offset"),
                  reinit = TRUE) {
  eval_from = parent.frame(2)
  entry1 = entries[[1]]
  if(typeof(entry1) == "closure") {
    from = entry1
  } else {
    from = as.character(entry1)
  }
  args = entries[-1]
  L = length(args)
  
  # check for fileName class
  has_filename = names(search) %in% "fileName"
  if(any(has_filename)) { # reorder classes to place fileName 1st
    classes = c(search[has_filename], search[!has_filename])
  } else { # add "fileName" in classes
    classes = c(list("fileName" = "fileName"), search)
  }
  if(anyDuplicated(names(classes))) stop("'search' should be a named list of non duplicated elements")
  
  
  # empty 
  if(L == 0) {
    new = sapply(classes, simplify = FALSE, FUN = function(x) return(NULL))
    attr(new, "was") <- rep(0, times = length(classes))
    attr(new, "from") <- entry1
    return(new)
  }
  
  # retrieve arguments values
  val = lapply(1:L, FUN=function(i) {
    switch(typeof(args[[i]]),
           "symbol" = return(get(as.character(args[[i]]), eval_from)),
           "language" = return(eval(args[[i]], eval_from))
    )
    return(args[[i]])
  })
  
  # identify arguments of classes we look for
  found = sapply(1:L, FUN = function(i) {
    sapply(classes, FUN = function(k) {
      if(length(k) == 0) return(FALSE)
      return(inherits(x = val[[i]], what = k, which = FALSE))
    })
  })
  
  # count how many times a classes is present
  times = apply(found, 1, sum)
  
  # error if at least 2 arguments are with same class
  foo = times > 1
  if(any(foo)) {
    N = names(args)
    NN = sapply(1:L, FUN=function(i) {
      return(ifelse(N[i] == "", "<unk>", N[i]))
    })
    dup = which(foo)
    msg = sapply(1:length(dup), FUN = function(i) {
      idx = which(found[dup[i], ]==1)
      nam = NN[idx]
      paste0("too many elements of class `", classes[dup[i]], "`: [", paste0(paste(idx, nam, sep = "="), collapse = ",") ,"]")
    })
    stop(paste0("\nIn ", entry1, ":\n", msg, collapse = "\n"))
  }
  
  # if not error identify who is who and where it was
  iam = lapply(1:length(classes), FUN=function(i) {
    return(which(found[i, ] == 1))
  })
  was = rep(0, times = length(classes))
  was[times == 1] <- unlist(iam)
  new = lapply(iam, FUN = function(i) {
    if(length(i) != 0) return(val[[i]])
  })
  names(new) = names(classes)
  
  if(length(new$fileName) == 0) { # fileName was not found in classes
    # search fileName in named arguments that were not identified in search
    fil = (names(args) %in% "fileName")
    if(any(was > 0)) fil = fil[-was[was > 0]]
    if(any(fil)) {
      new$fileName = val[[which(fil)[1]]]
      was = c(which(fil)[1], was)
    } else {
      no_name = names(args) %in% ""
      # search for a character string in non named argument that were not identified in search
      if(any(no_name)) {
        fil = unlist(lapply((1:L)[no_name], FUN = function(i) {
          if(i %in% was) return(NULL)
          if(typeof(val[[i]]) == "character") return(i)
          return(NULL)
        }))
        if(length(fil) != 0) {
          new$fileName = val[[fil[1]]]
          was = c(fil[1], was)
        }  else {
          was = c(0, was)
        }
      } else {
        was = c(0, was)
      }
    }
  }
  new$fileName = as.character(new$fileName)
  attr(new, "was") <- was 
  attr(new, "from") <- entry1
  
  # reinit to arguments of searched classes found to their default value
  if(reinit) {
    call_from = parent.frame(1)
    if((typeof(from) != "closure") && any(from[1] %in% c("::",":::"))) {
      form = formals(fun = from[3], envir = asNamespace(from[2], base.OK = FALSE))
    } else {
      form = formals(fun = from)
    }
    mism = setdiff(na.omit(names(args)[was]), "")
    sapply(mism, FUN = function(x) assign(x = x, value = form[[x]], inherits = FALSE, envir = call_from, immediate = TRUE))
  }
  return(new)
}

Try the IFC package in your browser

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

IFC documentation built on Sept. 14, 2023, 1:08 a.m.