Nothing
object_from_call <- function(call, env, block, file) {
if (is.character(call)) {
if (identical(call, "_PACKAGE")) {
parser_package(file)
} else {
parser_data(call, env, file)
}
} else if (is_set_call(call)) {
parser_r6_set(call, env)
} else if (is.call(call)) {
if (is_s7_method_call(call)) {
return(parser_s7_method(call, env, block))
}
call <- call_match(call, eval(call[[1]], env))
name <- deparse(call[[1]])
switch(
name,
"=" = ,
"<-" = ,
"<<-" = parser_assignment(call, env, block),
"delayedAssign" = parser_delayedAssign(call, env, block),
"::" = parser_import(call, env, block),
"methods::setClass" = ,
"setClass" = parser_setClass(call, env, block),
"methods::setClassUnion" = ,
"setClassUnion" = parser_setClassUnion(call, env, block),
"methods::setRefClass" = ,
"setRefClass" = parser_setRefClass(call, env, block),
"methods::setGeneric" = ,
"setGeneric" = parser_setGeneric(call, env, block),
"methods::setMethod" = ,
"setMethod" = parser_setMethod(call, env, block),
"methods::setReplaceMethod" = ,
"setReplaceMethod" = parser_setReplaceMethod(call, env, block),
"R.methodsS3::setMethodS3" = ,
"setMethodS3" = parser_setMethodS3(call, env, block),
"R.oo::setConstructorS3" = ,
"setConstructorS3" = parser_setConstructorS3(call, env, block),
NULL
)
} else {
# Patch @docType package to ensure that it gets a default alias
# and other "_PACKAGE" features
if (block_has_tags(block, "docType")) {
docType <- block_get_tag_value(block, "docType")
if (docType == "package") {
warn_roxy_block(
block,
c(
'`@docType "package"` is deprecated',
i = 'Please document "_PACKAGE" instead.'
)
)
return(parser_package(file))
}
}
NULL
}
}
object_from_name <- function(name, env, block) {
value <- get(name, env)
if (inherits(value, "R6ClassGenerator")) {
type <- "r6class"
} else if (methods::is(value, "refObjectGenerator")) {
value <- methods::getClass(as.character(value@className), where = env)
type <- "rcclass"
} else if (methods::is(value, "classGeneratorFunction")) {
value <- methods::getClass(as.character(value@className), where = env)
type <- "s4class"
} else if (methods::is(value, "MethodDefinition")) {
# S4 methods need munging to get real function def
value@.Data <- extract_method_fun(value@.Data)
type <- "s4method"
} else if (methods::is(value, "standardGeneric")) {
type <- "s4generic"
} else if (inherits(value, "S7_class")) {
type <- "s7class"
} else if (inherits(value, "S7_generic")) {
type <- "s7generic"
} else if (is.function(value)) {
# Potential S3 methods/generics need metadata added
method <- block_get_tag_value(block, "method")
value <- add_s3_metadata(value, name, env, block)
if (inherits(value, "s3generic")) {
type <- "s3generic"
} else if (inherits(value, "s3method")) {
type <- "s3method"
} else {
type <- "function"
}
} else {
type <- "value"
}
object(value, name, type)
}
# Parsers for individual calls --------------------------------------------
is_set_call <- function(call) {
is_call(call) &&
is_call(call[[1]], "$", n = 2) &&
is_symbol(call[[1]][[3]], "set")
}
parser_r6_set <- function(call, env) {
lhs <- call[[1]]
obj_name <- deparse(lhs[[2]])
obj <- tryCatch(get(obj_name, envir = env), error = function(e) NULL)
if (!inherits(obj, "R6ClassGenerator")) {
return(NULL)
}
class_name <- obj$classname
method_name <- call[[3]]
if (!is.character(method_name)) {
return(NULL)
}
object(list(class = class_name, method = method_name), NULL, "r6method")
}
parser_data <- function(call, env, block) {
if (isNamespace(env)) {
value <- getExportedValue(call, ns = asNamespace(env))
} else {
value <- get(call, envir = env)
}
object(value, call, type = "data")
}
parser_package <- function(file) {
pkg_path <- dirname(dirname(file))
value <- list(
desc = desc::desc(file = pkg_path),
path = pkg_path
)
object(value, NULL, type = "package")
}
parser_assignment <- function(call, env, block) {
name <- as.character(call[[2]])
# If it's a compound assignment like x[[2]] <- ignore it
if (length(name) > 1) {
return()
}
# If it doesn't exist (any more), don't document it.
if (!exists(name, env)) {
return()
}
object_from_name(name, env, block)
}
parser_delayedAssign <- function(call, env, block) {
name <- as.character(call$x)
object_from_name(name, env, block)
}
parser_setClass <- function(call, env, block) {
name <- as.character(call$Class)
value <- methods::getClass(name, where = env)
object(value, NULL, "s4class")
}
parser_setClassUnion <- function(call, env, block) {
name <- as.character(call$name)
value <- methods::getClass(name, where = env)
object(value, NULL, "s4class")
}
parser_setRefClass <- function(call, env, block) {
name <- as.character(call$Class)
value <- methods::getClass(name, where = env)
object(value, NULL, "rcclass")
}
parser_setGeneric <- function(call, env, block) {
name <- as.character(call$name)
value <- methods::getGeneric(name, where = env)
object(value, NULL, "s4generic")
}
parser_setMethod <- function(call, env, block) {
name <- as.character(call$f)
value <- methods::getMethod(name, eval(call$signature), where = env)
value@.Data <- extract_method_fun(value@.Data)
object(value, NULL, "s4method")
}
parser_setReplaceMethod <- function(call, env, block) {
name <- paste0(as.character(call$f), "<-")
value <- methods::getMethod(name, eval(call[[3]]), where = env)
value@.Data <- extract_method_fun(value@.Data)
object(value, NULL, "s4method")
}
parser_import <- function(call, env, block) {
pkg <- as.character(call[[2]])
fun <- as.character(call[[3]])
object(list(pkg = pkg, fun = fun), alias = fun, type = "import")
}
parser_setMethodS3 <- function(call, env, block) {
# R.methodsS3::setMethodS3(name, class, ...)
method <- as.character(call[[2]])
class <- as.character(call[[3]])
name <- paste(method, class, sep = ".")
value <- add_s3_metadata(get(name, env), name, env, block)
object(value, name, "s3method")
}
parser_setConstructorS3 <- function(call, env, block) {
# R.oo::setConstructorS3(name, ...)
name <- as.character(call[[2]])
object(get(name, env), name, "function")
}
# method(generic, class) <- fn
# `<-`(method(generic, class), fn)
is_s7_method_call <- function(call) {
is_call(call, "<-", n = 2) && is_call(call[[2]], "method", ns = c("", "S7"))
}
parser_s7_method <- function(call, env, block) {
generic_call <- call[[2]][[2]]
class_call <- call[[2]][[3]]
method_call <- call[[3]]
generic <- eval(generic_call, env)
if (inherits(generic, "S7_generic")) {
generic_name <- generic@name
} else {
# S3 or S4 generic passed by name
generic_name <- deparse(generic_call)
}
# Evaluate class spec: either a single class, a union, or list() for
# multi-dispatch
classes <- eval(class_call, env)
if (!is_bare_list(classes)) {
classes <- list(classes)
}
class_names <- lapply(classes, s7_class_name, block = block)
fn <- eval(method_call, env)
value <- list(fn = fn, generic = generic_name, classes = class_names)
aliases <- s7_method_aliases(generic_name, class_names)
object(value, aliases, "s7method")
}
s7_method_aliases <- function(generic, classes) {
if (!any(lengths(classes) > 1)) {
return(NULL)
}
combos <- expand.grid(classes, stringsAsFactors = FALSE)
apply(combos, 1, function(row) {
paste0(generic, ",", paste0(row, collapse = ","), "-method")
})
}
# https://github.com/RConsortium/S7/issues/594
s7_class_name <- function(cls, block) {
name <- nameOfClass(cls)
if (!is.null(name)) {
# Regular S7 class + base wrappers
name
} else if (inherits(cls, "S7_union")) {
# Unions return vector of member names, recursing for nested types
unlist(lapply(cls$classes, s7_class_name, block = block))
} else if (inherits(cls, "S7_S3_class")) {
cls$class
} else if (inherits(cls, "S7_any")) {
"any"
} else if (inherits(cls, "S7_missing")) {
"missing"
} else {
warn_roxy_block(block, "Unknown S7 class type")
paste0(deparse(cls), collapse = " ")
}
}
# helpers -----------------------------------------------------------------
add_s3_metadata <- function(val, name, env, block) {
if (block_has_tags(block, "method")) {
method <- block_get_tag_value(block, "method")
return(s3_method(val, method))
}
if (block_has_tags(block, "exportS3Method")) {
method <- block_get_tag_value(block, "exportS3Method")
if (length(method) == 1 && grepl("::", method, fixed = TRUE)) {
generic <- re_split_half(method, "::")[[2]]
class <- gsub(paste0("^", generic, "\\."), "", name)
return(s3_method(val, c(generic, class)))
}
}
if (is_s3_generic(name, env)) {
class(val) <- c("s3generic", "function")
return(val)
}
method <- find_generic(name, env)
if (is.null(method)) {
val
} else {
s3_method(val, method)
}
}
# When a generic has ... and a method adds new arguments, the S4 method
# wraps the definition inside another function which has the same arguments
# as the generic. This function figures out if that's the case, and extracts
# the original function if so.
#
# It's based on expression processing based on the structure of the
# constructed method which looks like:
#
# function (x, ...) {
# .local <- function (x, ..., y = 7) {}
# .local(x, ...)
# }
extract_method_fun <- function(fun) {
method_body <- body(fun)
if (!is_call(method_body, "{")) {
return(fun)
}
if (length(method_body) < 2) {
return(fun)
}
first_line <- method_body[[2]]
if (!is_call(first_line, name = "<-", n = 2)) {
return(fun)
}
if (!identical(first_line[[2]], quote(`.local`))) {
return(fun)
}
local_fun <- eval(first_line[[3]])
if (!is.function(local_fun)) {
return(fun)
}
local_fun
}
#' Constructors for S3 object to represent R objects
#'
#' These objects are usually created by the parsers, but it is also
#' useful to generate them by hand for testing.
#'
#' @param value The object itself.
#' @param alias Alias for object being documented, in case you create a
#' generator function with different name.
#' @export
#' @keywords internal
#' @param type Type of the object, character. E.g. `"data"` or `"s4method"`.
object <- function(value, alias, type) {
structure(
list(
alias = alias,
value = value,
methods = if (type == "rcclass") rc_methods(value),
topic = object_topic(value, alias, type)
),
class = c(type, "object")
)
}
#' @export
format.object <- function(x, ...) {
c(
paste0("<", class(x)[1], "> ", x$name),
paste0(" $topic ", x$topic),
if (!is.null(x$alias)) paste0(" $alias ", x$alias)
)
}
#' @export
print.object <- function(x, ...) {
cat_line(format(x, ...))
}
object_topic <- function(value, alias, type) {
switch(
type,
s4method = method_topic(value@generic, value@defined),
s4class = paste0(value@className, "-class"),
s4generic = value@generic,
rcclass = paste0(value@className, "-class"),
r6class = alias,
r6method = alias,
rcmethod = value@name,
s7class = alias,
s7generic = alias,
s7method = method_topic(value$generic, value$classes),
s3generic = alias,
s3method = alias,
import = alias,
`function` = alias,
package = alias,
data = alias,
value = alias,
cli::cli_abort("Unsupported type {.str {type}}.", .internal = TRUE)
)
}
method_topic <- function(generic, classes) {
class_strings <- vapply(classes, paste0, character(1), collapse = "/")
paste0(generic, ",", paste0(class_strings, collapse = ","), "-method")
}
call_to_object <- function(code, env = pkg_env(), file = NULL) {
code <- enexpr(code)
eval(code, envir = env)
if (is_call(code, "{")) {
call <- code[[length(code)]]
} else {
call <- code
}
object_from_call(call, env, block = NULL, file = file)
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.