-
Notifications
You must be signed in to change notification settings - Fork 1
/
s3methodtests.R
99 lines (69 loc) · 2.94 KB
/
s3methodtests.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
my_fun <- function(f, params) {
if (is.null(names(params)) || any(!names(params) %in% names(formals(f)))) {
stop("names of params must match arguments of f")
}
do.call(f, params)
}
my_fun(f = caret::train, params = list(x = data.frame(x = 1:10), y = rep(1,10), method = 'rf'))
my_fun(f = caret::train, params = list(x = data.frame(x = 1:10)))
####
# Edward solution
library(caret)
f <- caret::train
f.default <- try(getS3method(deparse(substitute(f)), "default"), silent=TRUE)
if(class(f.default)=="try-error")
stop("Function f has no default method.")
ff <- formals(f.default)
fargs <- formalArgs(f.default)
pargs <- names(params)
my_fun <- function(f, params) {
f.default <- try(getS3method(deparse(substitute(f)), "default"), silent=TRUE)
if(class(f.default)=="try-error")
stop("Function f has no default method.")
ff <- formals(f.default)
fargs <- formalArgs(f.default)
pargs <- names(params)
excessive.pargs <- setdiff(pargs, fargs)
# Ignore non-optional arguments, including the "..."
ff.symbol <- lapply(ff, is.symbol)
ff.symbol$`...` <- FALSE
fargs <- fargs[unlist(ff.symbol)]
missing.pargs <- setdiff(fargs, pargs)
if (length(excessive.pargs)>0)
stop("You have extra arguments that don't match arguments of f: ", excessive.pargs)
if (length(missing.pargs)>0)
stop("Some arguments of f are missing with no default: ", missing.pargs)
do.call(f, params)
}
library(caret)
my_fun(f = train, params = list(x = data.frame(x = 1:10)))
#Error in my_fun(f = train, params = list(x = data.frame(x = 1:10))) :
#Some arguments of f are missing with no no default: y
my_fun(f = train, params = list(x = data.frame(x = 1:10), z="Invalid argument"))
#Error in my_fun(f = train, params = list(x = data.frame(x = 1:10), z = "Invalid argument")) :
#You have extra arguments that don't match arguments of f: z
my_fun(f = train, params = list(x = data.frame(x = 1:10), y = rep(1,10), method = 'rf'))
# Works
#### Axeman solution
my_fun <- function(f, params, env = parent.frame()) {
# check for S3 generic
if (!is.primitive(f) && isS3stdGeneric(f)) {
s <- deparse(substitute(f))
dispatch_arg <- formalArgs(f)[1]
classes_to_check <- c(class(params[[dispatch_arg]]), 'default')
for (i in seq_along(classes_to_check)) {
f <- getS3method(s, classes_to_check[i], optional = TRUE, parent.frame(n = 2))
if (is.function(f)) break
}
}
if (is.null(names(params)) || !all(names(params) %in% formalArgs(f))) {
stop("names of params must match arguments of f", call. = FALSE)
}
do.call(f, params)
}
library(caret)
my_fun(f = train, params = list(x = data.frame(x = 1:10), y = rep(1,10), method = 'rf'))
# works
my_fun(f = train, params = list(x = data.frame(x = 1:10)))
# argument "y" is missing, with no default
my_fun(f = log, params = list(x = 1:10))