Last active
August 29, 2015 14:16
-
-
Save mtmorgan/9f98871adb9f0c1891a4 to your computer and use it in GitHub Desktop.
wrap methods() to report S3 and S4 methods for generic or class
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ## compatibility | |
| if (!exists("lengths")) | |
| lengths <- function(x) vapply(x, length, integer(1)) | |
| ## | |
| ## methods | |
| ## | |
| .S4methodsForClass <- | |
| function(generic.function, class, .methods_info) | |
| { | |
| def <- tryCatch(getClass(class), error=function(...) NULL) | |
| if (is.null(def)) | |
| return(.methods_info()) | |
| mtable <- ".MTable" | |
| classes <- c(class, names(getClass(class)@contains)) | |
| generics <- getGenerics(where=search()) | |
| nms <- setNames(as.vector(generics), as.vector(generics)) | |
| packages <- lapply(nms, function(generic) { | |
| table <- get(mtable, environment(getGeneric(generic))) | |
| lapply(names(table), function(nm, table) { | |
| environmentName(environment(table[[nm]])) | |
| }, table) | |
| }) | |
| methods <- lapply(nms, function(generic, classes) { | |
| table <- get(mtable, environment(getGeneric(generic))) | |
| methods <- names(table) | |
| lapply(methods, function(method, classes) { | |
| m <- table[[method]] | |
| if (is(m, "MethodDefinition") && any(m@defined %in% classes)) | |
| setNames(as.vector(m@defined), names(m@defined)) | |
| else | |
| NULL | |
| }, classes) | |
| }, classes) | |
| geom <- lapply(methods, function(method) { | |
| !vapply(method, is.null, logical(1)) | |
| }) | |
| filter <- function(elt, geom) elt[geom] | |
| packages <- Map(filter, packages, geom) | |
| methods <- Map(filter, methods, geom) | |
| packages <- packages[lengths(methods) != 0L] | |
| methods <- methods[lengths(methods) != 0L] | |
| ## only derived methods | |
| geom <- lapply(methods, function(method, classes) { | |
| sig <- simplify2array(method) | |
| if (!is.matrix(sig)) | |
| sig <- matrix(sig, ncol=length(method)) | |
| idx <- apply(sig, 2, match, classes, 0) | |
| if (!is.matrix(idx)) | |
| idx <- matrix(idx, ncol=ncol(sig)) | |
| keep <- colSums(idx != 0) != 0 | |
| sidx <- idx[,keep, drop=FALSE] | |
| ## 'nearest' method | |
| shift <- c(0, cumprod(pmax(1, apply(sidx, 1, max)))[-nrow(sidx)]) | |
| score <- colSums(sidx + shift) | |
| sig0 <- sig <- sig[,keep, drop=FALSE] | |
| sig0[sidx != 0] <- "*" | |
| sig0 <- apply(sig0, 2, paste, collapse="#") | |
| split(score, sig0) <- | |
| lapply(split(score, sig0), function(elt) elt == min(elt)) | |
| score == 1 | |
| }, classes) | |
| filter <- function(elt, geom) elt[geom] | |
| packages <- Map(filter, packages, geom) | |
| methods <- Map(filter, methods, geom) | |
| generic <- rep(names(methods), lengths(methods)) | |
| signature <- unlist(lapply(methods, function(method) { | |
| vapply(method, paste0, character(1L), collapse=",") | |
| }), use.names=FALSE) | |
| package <- unlist(packages, use.names=FALSE) | |
| .methods_info(generic=generic, signature=signature, from=package, | |
| isS4=rep(TRUE, length(signature))) | |
| } | |
| .S4methodsForGeneric <- | |
| function(generic.function, class, .methods_info) | |
| { | |
| if (is.null(getGeneric(generic.function))) | |
| return(.methods_info()) | |
| mtable <- ".MTable" | |
| generic <- generic.function | |
| table <- get(mtable, environment(getGeneric(generic))) | |
| packages <- sapply(names(table), function(nm, table) { | |
| environmentName(environment(table[[nm]])) | |
| }, table) | |
| methods <- names(table) | |
| signatures <- lapply(methods, function(method, classes) { | |
| m <- table[[method]] | |
| if (is(m, "MethodDefinition")) | |
| setNames(as.vector(m@defined), names(m@defined)) | |
| else | |
| NULL | |
| }) | |
| geom <- vapply(signatures, Negate(is.null), logical(1)) | |
| packages <- packages[geom] | |
| methods <- methods[geom] | |
| signatures <- sapply(signatures[geom], function(elt) { | |
| paste0(as.vector(elt), collapse=",") | |
| }) | |
| .methods_info(generic=rep(generic.function, length(packages)), from=packages, | |
| signature=signatures, isS4=rep(TRUE, length(signatures))) | |
| } | |
| ## | |
| ## utils | |
| ## | |
| print.MethodsFunction <- | |
| function(x, ...) | |
| { | |
| info <- attr(x, "info") | |
| if (attr(x, "bygeneric")) { | |
| visible <- ifelse(info$visible, "", "*") | |
| values <- paste0(rownames(info), visible) | |
| } else { | |
| values <- unique(info$generic) | |
| } | |
| if (length(values)) | |
| print(noquote(values)) | |
| else | |
| print(noquote("no methods found")) | |
| cat("\n see '?methods' for accessing help and source code\n") | |
| } | |
| ## class constructors | |
| .MethodsFunction <- | |
| function(s3, s4, bygeneric) | |
| { | |
| df <- rbind(s3, s4) | |
| rownames <- ifelse(df$isS4, | |
| paste0(df$generic, ",", df$signature, "-method"), | |
| paste0(df$generic, ".", df$signature)) | |
| keep <- !duplicated(rownames) | |
| df <- df[keep, , drop=FALSE] | |
| rownames(df) <- rownames[keep] | |
| df <- df[order(rownames(df)), c("generic", "visible", "isS4", "from"), | |
| drop=FALSE] | |
| structure(rownames(df), info=df, bygeneric=bygeneric, | |
| class="MethodsFunction") | |
| } | |
| .methods_info <- | |
| function(generic=character(), signature=character(), | |
| visible=rep(TRUE, length(signature)), from=character(), | |
| isS4=logical(length(signature))) | |
| { | |
| data.frame(generic=generic, signature=signature, from=from, | |
| isS4=isS4, visible=visible, stringsAsFactors=FALSE) | |
| } | |
| ## S3 | |
| .S3methods <- | |
| function(generic.function, class) | |
| { | |
| x <- utils::methods(generic.function, class) | |
| if (!length(x)) | |
| return(.methods_info()) | |
| info <- attr(x, "info") | |
| method <- rownames(info) | |
| package <- sub("package:", "", info[["from"]]) | |
| if (missing(generic.function)) { | |
| re <- "(.*)\\.([[:alnum:]_]+)$" | |
| generic <- sub(re, "\\1", method) | |
| class <- sub(re, "\\2", method) | |
| } else { | |
| generic <- generic.function | |
| class <- sub(sprintf("%s.", generic.function), "", method, | |
| fixed=TRUE) | |
| } | |
| ## FIXME: not always dispatch on first argument | |
| sig <- vapply(generic, function(elt) { | |
| fun <- get(elt) | |
| if (is.primitive(fun)) "x" # FIXME: ??? | |
| else names(formals(fun))[[1]] | |
| }, character(1)) | |
| .methods_info(generic=generic, signature=class, from=package, | |
| visible=info[["visible"]]) | |
| } | |
| ## All | |
| .methodsForClass <- | |
| function(generic.function, class) | |
| { | |
| s3 <- .S3methods(generic.function, class) | |
| s4 <- if (.isMethodsDispatchOn()) | |
| .S4methodsForClass(generic.function, class, .methods_info) | |
| else .methods_info() | |
| .MethodsFunction(s3, s4, FALSE) | |
| } | |
| .methodsForGeneric <- | |
| function(generic.function, class) | |
| { | |
| s3 <- tryCatch(.S3methods(generic.function, class), | |
| error=function(...) .methods_info()) | |
| s4 <- if (.isMethodsDispatchOn()) | |
| .S4methodsForGeneric(generic.function, class, .methods_info) | |
| else .methods_info() | |
| .MethodsFunction(s3, s4, TRUE) | |
| } | |
| methods <- | |
| function(generic.function, class) | |
| { | |
| if (!missing(generic.function)) { | |
| if (!is.character(generic.function)) | |
| generic.function <- deparse(substitute(generic.function)) | |
| .methodsForGeneric(generic.function, class) | |
| } else if (!missing(class)) { | |
| .methodsForClass(generic.function, class) | |
| } else | |
| stop("must supply 'generic.function' or 'class'") | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment