Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
2701 views
1
## COMMENT ON S3 METHODS: It is not feasible and, quite frankly, a bad practice
2
## to check all the assigned function names for "." separator. Thus, S3 methods
3
## are not automatically registered. You can register them manually after you
4
## have inserted method_name.my_class into your package environment using
5
## ess-developer, like follows:
6
##
7
## registerS3method("method_name", "my_class", my_package:::method_name.my_class)
8
##
9
## Otherwise R will call the registered (i.e. cached) S3 method instead of the
10
## new method that ess-developer inserted in the package environment.
11
12
.essDev.eval <- function(string, package, file = tempfile("ESSDev")){
13
cat(string, file = file)
14
on.exit(file.remove(file))
15
.essDev_source(file,, package = package)
16
}
17
18
.essDev_source <- function(source, expr, package = "")
19
{
20
## require('methods')
21
oldopts <- options(warn = 1)
22
on.exit(options(oldopts))
23
MPattern <- methods:::.TableMetaPattern()
24
CPattern <- methods:::.ClassMetaPattern()
25
allPlainObjects <- function() allObjects[!(grepl(MPattern, allObjects) |
26
grepl(CPattern, allObjects))]
27
allMethodTables <- function() allObjects[grepl(MPattern, allObjects)]
28
allClassDefs <- function() allObjects[grepl(CPattern, allObjects)]
29
pname <- paste("package:", package, sep = "")
30
envpkg <- tryCatch(as.environment(pname), error = function(cond) NULL)
31
if(is.null(envpkg)){
32
library(package, character.only = TRUE)
33
envpkg <- tryCatch(as.environment(pname), error = function(cond) NULL)
34
}
35
if (is.null(envpkg))
36
stop(gettextf("Can't find an environment corresponding to package name '%s'",
37
package), domain = NA)
38
envns <- tryCatch(asNamespace(package), error = function(cond) NULL)
39
if (is.null(envns))
40
stop(gettextf("Can't find a namespace environment corresponding to package name '%s\"",
41
package), domain = NA)
42
env <- .essDev_evalSource(source, substitute(expr), package)
43
envPackage <- getPackageName(env, FALSE)
44
if (nzchar(envPackage) && envPackage != package)
45
warning(gettextf("Supplied package, %s, differs from package inferred from source, %s",
46
sQuote(package), sQuote(envPackage)), domain = NA)
47
allObjects <- objects(envir = env, all.names = TRUE)
48
allObjects <- allObjects[!(allObjects %in% c(".cacheOnAssign", ".packageName"))]
49
50
## PLAIN OBJECTS and FUNCTIONS:
51
funcNs <- funcPkg <- newFunc <- newNs <- newObjects <- newPkg <-
52
objectsNs <- objectsPkg <- character()
53
for (this in allPlainObjects()) {
54
thisEnv <- get(this, envir = env)
55
thisNs <- NULL
56
## NS
57
if (exists(this, envir = envns, inherits = FALSE)){
58
thisNs <- get(this, envir = envns)
59
if(is.function(thisNs) || is.function(thisEnv)){
60
if(is.function(thisNs) && is.function(thisEnv)){
61
if(.essDev_differs(thisEnv, thisNs)){
62
environment(thisEnv) <- environment(thisNs)
63
.essDev_assign(this, thisEnv, envns)
64
funcNs <- c(funcNs, this)
65
if(exists(".__S3MethodsTable__.", envir = envns, inherits = FALSE)){
66
S3_table <- get(".__S3MethodsTable__.", envir = envns)
67
if(exists(this, envir = S3_table, inherits = FALSE))
68
.essDev_assign(this, thisEnv, S3_table)
69
}
70
}
71
}else{
72
newNs <- c(newNs, this)
73
}
74
}else{
75
if(!identical(thisEnv, thisNs)){
76
.essDev_assign(this, thisEnv, envns)
77
objectsNs <- c(objectsNs, this)}
78
}
79
}else{
80
newNs <- c(newNs, this)
81
}
82
## PKG
83
if (exists(this, envir = envpkg, inherits = FALSE)){
84
thisPkg <- get(this, envir = envpkg)
85
if(is.function(thisPkg) || is.function(thisEnv)){
86
if(is.function(thisPkg) && is.function(thisEnv)){
87
if(.essDev_differs(thisPkg, thisEnv)){
88
environment(thisEnv) <- environment(thisPkg)
89
.essDev_assign(this, thisEnv, envpkg)
90
funcPkg <- c(funcPkg, this)}
91
}else{
92
newPkg <- c(newPkg, this)}
93
}else{
94
if(!identical(thisPkg, thisEnv)){
95
.essDev_assign(this, thisEnv, envpkg)
96
objectsPkg <- c(objectsPkg, this)}}
97
}else{
98
newPkg <- c(newPkg, this)}
99
}
100
for(this in intersect(newPkg, newNs)){
101
thisEnv <- get(this, envir = env, inherits = FALSE)
102
if(exists(this, envir = .GlobalEnv, inherits = FALSE)){
103
thisGl <- get(this, envir = .GlobalEnv)
104
if(.essDev_differs(thisEnv, thisGl)){
105
if(is.function(thisEnv)){
106
environment(thisEnv) <- envns
107
newFunc <- c(newFunc, this)
108
}else{
109
newObjects <- c(newObjects, this)
110
}
111
.essDev_assign(this, thisEnv, .GlobalEnv)
112
}
113
}else{
114
if(is.function(thisEnv)){
115
environment(thisEnv) <- envns
116
newFunc <- c(newFunc, this)
117
}else{
118
newObjects <- c(newObjects, this)
119
}
120
.essDev_assign(this, thisEnv, .GlobalEnv)
121
}
122
}
123
if(length(funcNs))
124
objectsNs <- c(objectsNs, sprintf("FUN[%s]", paste(funcNs, collapse = ", ")))
125
if(length(funcPkg))
126
objectsPkg <- c(objectsPkg, sprintf("FUN[%s]", paste(funcPkg, collapse = ", ")))
127
if(length(newFunc))
128
newObjects <- c(newObjects, sprintf("FUN[%s]", paste(newFunc, collapse = ", ")))
129
130
## CLASSES
131
classesPkg <- classesNs <- newClasses <- character()
132
for(this in allClassDefs()){
133
newPkg <- newNs <- FALSE
134
thisEnv <- get(this, envir = env)
135
if(exists(this, envir = envpkg, inherits = FALSE)){
136
if(!.essDev_identicalClass(thisEnv, get(this, envir = envpkg))){
137
.essDev_assign(this, thisEnv, envir = envpkg)
138
classesPkg <- c(classesPkg, this)
139
}
140
}else{
141
newPkg <- TRUE
142
}
143
if(exists(this, envir = envns, inherits = FALSE)){
144
if(!.essDev_identicalClass(thisEnv, get(this, envir = envns))){
145
.essDev_assign(this, thisEnv, envir = envns)
146
classesNs <- c(classesNs, this)
147
}
148
}else{
149
newNs <- TRUE
150
}
151
if(newNs && newPkg){
152
if(exists(this, envir = .GlobalEnv, inherits = FALSE)){
153
if(!.essDev_identicalClass(thisEnv, get(this, envir = .GlobalEnv))){
154
.essDev_assign(this, thisEnv, envir = .GlobalEnv)
155
newClasses <- c(newClasses, this)
156
}
157
}else{
158
.essDev_assign(this, thisEnv, envir = .GlobalEnv)
159
newClasses <- c(newClasses, this)
160
}
161
}
162
}
163
if(length(classesPkg))
164
objectsPkg <- gettextf("CLS[%s]", sub(methods:::.ClassMetaPattern(), "", paste(classesPkg, collapse = ", ")))
165
if(length(classesNs))
166
objectsNs <- gettextf("CLS[%s]", sub(methods:::.ClassMetaPattern(), "", paste(classesNs, collapse = ", ")))
167
if(length(newClasses))
168
newObjects <- gettextf("CLS[%s]", sub(methods:::.ClassMetaPattern(), "", paste(newClasses, collapse = ", ")))
169
170
## METHODS:
171
## Method internals: For efficiency reasons setMethod() caches
172
## method definition into a global table which you can get with
173
## 'getMethodsForDispatch' function, and when a method is dispatched that
174
## table is used. When ess-developer is used to source method definitions the
175
## two copies of the functions are identical up to the environment. The
176
## environment of the cached object has namespace:foo as it's parent but the
177
## environment of the object in local table is precisely namspace:foo. This
178
## does not cause any difference in evaluation.
179
methodNames <- allMethodTables()
180
methods <- sub(methods:::.TableMetaPrefix(), "", methodNames)
181
methods <- sub(":.*", "", methods)
182
methodsNs <- newMethods <- character()
183
for (i in seq_along(methods)){
184
table <- methodNames[[i]]
185
tableEnv <- get(table, envir = env)
186
if(exists(table, envir = envns, inherits = FALSE)){
187
inserted <- .essDev_insertMethods(tableEnv, get(table, envir = envns), envns)
188
if(length(inserted))
189
methodsNs <- c(methodsNs, gettextf("%s{%s}", methods[[i]], paste(inserted, collapse = ", ")))
190
}else if(exists(table, envir = .GlobalEnv, inherits = FALSE)){
191
inserted <- .essDev_insertMethods(tableEnv, get(table, envir = .GlobalEnv), envns)
192
if(length(inserted))
193
newMethods <- c(newMethods, gettextf("%s{%s}", methods[[i]], paste(inserted, collapse = ", ")))
194
}else{
195
.essDev_assign(table, tableEnv, envir = .GlobalEnv)
196
newMethods <- c(newMethods, gettextf("%s{%s}", methods[[i]], paste(objects(envir = tableEnv, all.names = T), collapse = ", ")))
197
}
198
}
199
if(length(methodsNs))
200
objectsNs <- c(objectsNs, gettextf("METH[%s]", paste(methodsNs, collapse = ", ")))
201
if(length(newMethods))
202
newObjects <- c(newObjects, gettextf("METH[%s]", paste(newMethods, collapse = ", ")))
203
204
if(length(objectsPkg))
205
cat(sprintf("%s PKG: %s ", package, paste(objectsPkg, collapse = ", ")))
206
if(length(objectsNs))
207
cat(sprintf("NS: %s ", paste(objectsNs, collapse = ", ")))
208
if(length(newObjects))
209
cat(sprintf("GE: %s\n", paste(newObjects, collapse = ", ")))
210
if(length(c(objectsNs, objectsPkg, newObjects)) == 0)
211
cat(sprintf("*** Nothing explicitly assigned ***\n"))
212
invisible(env)
213
}
214
215
.essDev_insertMethods <- function(tableEnv, tablePkg, envns)
216
{
217
inserted <- character()
218
for(m in ls(envir = tableEnv, all.names = T)){
219
if(exists(m, envir = tablePkg, inherits = FALSE)){
220
thisEnv <- get(m, envir = tableEnv)
221
thisPkg <- get(m, envir = tablePkg)
222
if(is(thisEnv, "MethodDefinition") && is(thisPkg, "MethodDefinition") &&
223
.essDev_differs(thisEnv@.Data, thisPkg@.Data)){
224
environment(thisEnv@.Data) <- envns
225
## environment of cached method in getMethodsForDispatch table is still env
226
## not a problem as such, but might confuse users
227
.essDev_assign(m, thisEnv, tablePkg)
228
inserted <- c(inserted, m)
229
}}}
230
inserted
231
}
232
233
234
.essDev_evalSource <- function (source, expr, package = "")
235
{
236
envns <- tryCatch(asNamespace(package), error = function(cond) NULL)
237
if(is.null(envns))
238
stop(gettextf("Package \"%s\" is not attached and no namespace found for it",
239
package), domain = NA)
240
env <- new.env(parent = envns)
241
env[[".packageName"]] <- package
242
methods:::setCacheOnAssign(env, TRUE)
243
if (missing(source))
244
eval(expr, envir = env)
245
else if (is(source, "character"))
246
for (text in source) sys.source(text, envir = env, keep.source = TRUE)
247
else stop(gettextf("Invalid source argument: got an object of class \"%s\"",
248
class(source)[[1]]), domain = NA)
249
env
250
}
251
252
253
.essDev_assign <- function (x, value, envir)
254
{
255
if (exists(x, envir = envir, inherits = FALSE) && bindingIsLocked(x, envir)) {
256
unlockBinding(x, envir)
257
assign(x, value, envir = envir, inherits = FALSE)
258
w <- options("warn")
259
on.exit(options(w))
260
options(warn = -1)
261
lockBinding(x, envir)
262
} else {
263
assign(x, value, envir = envir, inherits = FALSE)
264
}
265
invisible(NULL)
266
}
267
268
.essDev_identicalClass <- function(cls1, cls2, printInfo = FALSE){
269
slots1 <- slotNames(class(cls1))
270
slots2 <- slotNames(class(cls2))
271
if(identical(slots1, slots2)){
272
vK <- grep("versionKey", slots1)
273
if(length(vK))
274
slots1 <- slots2 <- slots1[-vK]
275
out <- sapply(slots1, function(nm) identical(slot(cls1, nm), slot(cls2, nm)))
276
if(printInfo) print(out)
277
all(out)
278
}
279
}
280
281
282
.essDev_differs <- function(f1, f2) {
283
if (is.function(f1) && is.function(f2)){
284
!(identical(body(f1), body(f2)) && identical(args(f1), args(f2)))
285
}else
286
!identical(f1, f2)
287
}
288
289