forked from RConsortium/S7
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgeneric-spec.R
121 lines (102 loc) · 2.89 KB
/
generic-spec.R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
is_generic <- function(x) {
is_S7_generic(x) || is_external_generic(x) || is_S3_generic(x) || is_S4_generic(x)
}
as_generic <- function(x) {
if (is_generic(x)) {
x
} else if (is.function(x)) {
as_S3_generic(x)
} else {
msg <- sprintf("`generic` must be a function, not a %s", obj_desc(x))
stop(msg, call. = FALSE)
}
}
as_S3_generic <- function(x) {
use_method <- find_call(body(x), quote(UseMethod))
if (!is.null(use_method)) {
return(S3_generic(x, as.character(use_method[[2]])))
} else {
name <- find_base_name(x)
if (name %in% names(base_ops)) {
return(base_ops[[name]])
} else if (name %in% names(base_matrix_ops)) {
return(base_matrix_ops[[name]])
} else if (!is.na(name) && is_internal_generic(name)) {
return(S3_generic(x, name))
}
}
stop("`generic` is a function, but not an S3 generic function: \n",
deparse_trunc(x, 100), call. = FALSE)
}
S3_generic <- function(generic, name) {
out <- list(generic = generic, name = name)
class(out) <- "S7_S3_generic"
out
}
is_S3_generic <- function(x) inherits(x, "S7_S3_generic")
is_S4_generic <- function(x) inherits(x, "genericFunction")
# Is the generic defined in the "current" package
is_local_generic <- function(generic, package) {
if (is_external_generic(generic)) {
return(FALSE)
}
generic_pkg <- package_name(generic)
is.null(generic_pkg) || generic_pkg == package
}
package_name <- function(f) {
env <- environment(f)
if (is.null(env)) {
"base"
} else {
(packageName(env))
}
}
generic_n_dispatch <- function(x) {
if (is_S7_generic(x)) {
length(x@dispatch_args)
} else if (is_external_generic(x)) {
length(x$dispatch_args)
} else if (is_S3_generic(x)) {
1
} else if (is_S4_generic(x)) {
length(x@signature)
} else {
stop(sprintf("Invalid input %", obj_desc(x)), call. = FALSE)
}
}
# Internal generics -------------------------------------------------------
find_base_name <- function(f, candidates = NULL) {
env <- baseenv()
candidates <- candidates %||% names(env)
for (name in candidates) {
if (identical(f, env[[name]])) {
return(name)
}
}
NA
}
is_internal_generic <- function(x) {
x %in% internal_generics()
}
internal_generics <- function() {
group <- unlist(group_generics(), use.names = FALSE)
primitive <- .S3PrimitiveGenerics
# Extracted from ?"internal generic"
internal <- c("[", "[[", "$", "[<-", "[[<-", "$<-", "unlist",
"cbind", "rbind", "as.vector")
c(group, primitive, internal)
}
group_generics <- function() {
# S3 group generics can be defined by combining S4 group generics
groups <- list(
Ops = c("Arith", "Compare", "Logic"),
Math = c("Math", "Math2"),
Summary = "Summary",
Complex = "Complex"
)
out <- lapply(groups, function(x) unlist(lapply(x, methods::getGroupMembers)))
if (getRversion() >= "4.3") {
out$matrixOps <- c("%*%")
}
out
}