| 52960 |
jmc |
1 |
## simple call, only field names
|
|
|
2 |
fg <- setRefClass("foo", c("bar", "flag"))
|
| 61035 |
jmc |
3 |
f0 <- new("foo") # deprecated, but should still work
|
|
|
4 |
f1 <- fg(flag = "testing")
|
| 52960 |
jmc |
5 |
f1$bar <- 1
|
|
|
6 |
stopifnot(identical(f1$bar, 1))
|
| 61035 |
jmc |
7 |
## add method
|
| 52960 |
jmc |
8 |
fg$methods(showAll = function() c(bar, flag))
|
|
|
9 |
stopifnot(all.equal(f1$showAll(), c(1, "testing")))
|
| 56985 |
maechler |
10 |
str(f1)
|
| 52960 |
jmc |
11 |
|
| 56211 |
maechler |
12 |
fg <- setRefClass("foo", list(bar = "numeric", flag = "character",
|
|
|
13 |
tag = "ANY"),
|
|
|
14 |
methods = list(addToBar = function(incr) {
|
|
|
15 |
b <- bar + incr
|
|
|
16 |
bar <<- b
|
|
|
17 |
b
|
|
|
18 |
} )
|
|
|
19 |
)
|
| 57589 |
jmc |
20 |
fg$lock("flag")
|
|
|
21 |
stopifnot(identical(fg$lock(), "flag"))
|
|
|
22 |
|
| 56211 |
maechler |
23 |
ff <- new("foo", bar = 1.5)
|
| 52816 |
jmc |
24 |
stopifnot(identical(ff$bar, 1.5))
|
|
|
25 |
ff$bar <- pi
|
|
|
26 |
stopifnot(identical(ff$bar, pi))
|
| 57589 |
jmc |
27 |
## flag has not yet been set
|
|
|
28 |
ff$flag <- "flag test"
|
|
|
29 |
stopifnot(identical(ff$flag, "flag test"))
|
|
|
30 |
## but no second assign
|
|
|
31 |
stopifnot(is(tryCatch(ff$flag <- "new", error = function(e)e), "error"))
|
|
|
32 |
|
| 52903 |
jmc |
33 |
## test against generator
|
| 52816 |
jmc |
34 |
|
| 61035 |
jmc |
35 |
f2 <- fg(bar = pi, flag = "flag test")
|
| 52903 |
jmc |
36 |
## identical does not return TRUE if *contents* of env are identical
|
|
|
37 |
stopifnot(identical(ff$bar, f2$bar), identical(ff$flag, f2$flag))
|
| 57589 |
jmc |
38 |
## but flag was now assigned once
|
|
|
39 |
stopifnot(is(tryCatch(f2$flag <- "new", error = function(e)e), "error"))
|
| 52903 |
jmc |
40 |
|
| 56985 |
maechler |
41 |
str(f2)
|
|
|
42 |
|
| 52816 |
jmc |
43 |
|
| 52960 |
jmc |
44 |
## add some accessor methods
|
|
|
45 |
fg$accessors("bar")
|
|
|
46 |
|
| 52816 |
jmc |
47 |
ff$setBar(1:3)
|
| 52960 |
jmc |
48 |
stopifnot(identical(ff$getBar(), 1:3))
|
| 52816 |
jmc |
49 |
|
|
|
50 |
ff$getBar()
|
|
|
51 |
stopifnot(all.equal(ff$addToBar(1), 2:4))
|
|
|
52 |
|
| 52960 |
jmc |
53 |
|
| 52903 |
jmc |
54 |
## Add a method
|
|
|
55 |
fg$methods(barTimes = function(x) {
|
|
|
56 |
"This method multiples field bar by argument x
|
|
|
57 |
and this string is self-documentation"
|
|
|
58 |
setBar(getBar() * x)})
|
|
|
59 |
|
|
|
60 |
ffbar <- ff$getBar()
|
|
|
61 |
ff$barTimes(10)
|
|
|
62 |
stopifnot(all.equal(ffbar * 10, ff$getBar()))
|
|
|
63 |
ff$barTimes(.1)
|
|
|
64 |
|
| 52846 |
jmc |
65 |
## inheritance. redefines flag so should fail:
|
| 56211 |
maechler |
66 |
stopifnot(is(tryCatch(setRefClass("foo2", list(b2 = "numeric",
|
|
|
67 |
flag = "complex"),
|
| 52816 |
jmc |
68 |
contains = "foo",
|
| 52903 |
jmc |
69 |
refMethods = list(addBoth = function(incr) {
|
| 52816 |
jmc |
70 |
addToBar(incr) #uses inherited class method
|
|
|
71 |
setB2(getB2() + incr)
|
| 52903 |
jmc |
72 |
})),
|
|
|
73 |
error = function(e)e), "error"))
|
| 57604 |
jmc |
74 |
## but with flag as a subclass of "characters", should work
|
| 56045 |
jmc |
75 |
## Also subclasses "tag" which had class "ANY before
|
| 56211 |
maechler |
76 |
setClass("ratedChar", contains = "character",
|
|
|
77 |
representation(score = "numeric"))
|
|
|
78 |
foo2 <- setRefClass("foo2", list(b2 = "numeric", flag = "ratedChar",
|
|
|
79 |
tag = "numeric"),
|
|
|
80 |
contains = "foo",
|
|
|
81 |
methods = list(addBoth = function(incr) {
|
| 52846 |
jmc |
82 |
addToBar(incr) #uses inherited class method
|
| 56211 |
maechler |
83 |
b2 <<- b2 + incr
|
| 52816 |
jmc |
84 |
}))
|
| 52960 |
jmc |
85 |
## now lock the flag field; should still allow one write
|
|
|
86 |
foo2$lock("flag")
|
| 61035 |
jmc |
87 |
f2 <- foo2(bar = -3, flag = as("ANY", "ratedChar"),
|
| 56211 |
maechler |
88 |
b2 = ff$bar, tag = 1.5)
|
| 52960 |
jmc |
89 |
## but not a second one
|
|
|
90 |
stopifnot(is(tryCatch(f2$flag <- "Try again",
|
|
|
91 |
error = function(e)e), "error"))
|
| 56985 |
maechler |
92 |
str(f2)
|
| 61035 |
jmc |
93 |
f22 <- foo2(bar = f2$bar)
|
| 52960 |
jmc |
94 |
## same story if assignment follows the initialization
|
|
|
95 |
f22$flag <- f2$flag
|
|
|
96 |
stopifnot(is(tryCatch(f22$flag <- "Try again",
|
|
|
97 |
error = function(e)e), "error"))
|
|
|
98 |
## Exporting superclass object
|
| 61035 |
jmc |
99 |
f22 <- fg(bar = f2$bar, flag = f2$flag)
|
| 52903 |
jmc |
100 |
f2e <- f2$export("foo")
|
|
|
101 |
stopifnot(identical(f2e$bar, f22$bar), identical(f2e$flag, f22$flag),
|
|
|
102 |
identical(class(f2e), class(f22)))
|
| 56211 |
maechler |
103 |
stopifnot(identical(f2$flag, as("ANY", "ratedChar")),
|
|
|
104 |
identical(f2$bar, -3),
|
| 52816 |
jmc |
105 |
all.equal(f2$b2, 2:4+0))
|
|
|
106 |
f2$addBoth(-1)
|
|
|
107 |
stopifnot(all.equal(f2$bar, -4), all.equal(f2$b2, 1:3+0))
|
|
|
108 |
|
| 52960 |
jmc |
109 |
## test callSuper()
|
| 57183 |
jmc |
110 |
foo3 <- setRefClass("foo3", fields = list(flag2 = "ratedChar"),
|
| 52960 |
jmc |
111 |
contains = "foo2",
|
| 56211 |
maechler |
112 |
methods = list(addBoth = function(incr) {
|
|
|
113 |
callSuper(incr)
|
|
|
114 |
flag2 <<- as(paste(flag, paste(incr, collapse = ", "),
|
|
|
115 |
sep = "; "),
|
|
|
116 |
"ratedChar")
|
| 52816 |
jmc |
117 |
incr
|
|
|
118 |
}))
|
|
|
119 |
|
| 61035 |
jmc |
120 |
f2 <- foo2(bar = -3, flag = as("ANY", "ratedChar"), b2 = 1:3)
|
|
|
121 |
f3 <- foo3()
|
| 52846 |
jmc |
122 |
f3$import(f2)
|
| 56211 |
maechler |
123 |
stopifnot(all.equal(f3$b2, f2$b2), all.equal(f3$bar, f2$bar),
|
|
|
124 |
all.equal(f3$flag, f2$flag))
|
| 52871 |
jmc |
125 |
f3$addBoth(1)
|
| 52960 |
jmc |
126 |
stopifnot(all.equal(f3$bar, -2), all.equal(f3$b2, 2:4+0),
|
|
|
127 |
all.equal(f3$flag2, as("ANY; 1", "ratedChar")))
|
| 52871 |
jmc |
128 |
|
| 52960 |
jmc |
129 |
## but the import should have used up the one write for $flag
|
|
|
130 |
stopifnot(is(tryCatch(f3$flag <- "Try again",
|
|
|
131 |
error = function(e)e), "error"))
|
| 56985 |
maechler |
132 |
str(f3)
|
| 52960 |
jmc |
133 |
|
| 57604 |
jmc |
134 |
## importing the same class (not very useful but documented to work)
|
| 61035 |
jmc |
135 |
f3 <- foo3()
|
|
|
136 |
f4 <- foo3(bar = -3, flag = as("More", "ratedChar"), b2 = 1:3, flag2 = f2$flag)
|
| 57604 |
jmc |
137 |
f3$import(f4)
|
|
|
138 |
stopifnot(identical(f3$bar, f4$bar),
|
|
|
139 |
identical(f3$flag, f4$flag),
|
|
|
140 |
identical(f3$b2, f4$b2),
|
|
|
141 |
identical(f3$flag2, f4$flag2))
|
|
|
142 |
|
| 61035 |
jmc |
143 |
## similar to $import() but using superclass object in the generator call
|
| 57183 |
jmc |
144 |
## The explicitly supplied flag= should override and be allowed
|
| 57589 |
jmc |
145 |
## by the default $initialize()
|
| 61035 |
jmc |
146 |
f3b <- foo3(f2, flag = as("Other", "ratedChar"),
|
| 57183 |
jmc |
147 |
flag2 = as("More", "ratedChar"))
|
|
|
148 |
## check that inherited and direct field assignments worked
|
|
|
149 |
stopifnot(identical(f3b$tag, f2$tag),
|
|
|
150 |
identical(f3b$flag, as("Other", "ratedChar")),
|
|
|
151 |
identical(f3b$flag2, as("More", "ratedChar")))
|
| 61035 |
jmc |
152 |
## the $new() method should match the generator function
|
|
|
153 |
f3b <- foo3$new(f2, flag = as("Other", "ratedChar"),
|
|
|
154 |
flag2 = as("More", "ratedChar"))
|
|
|
155 |
stopifnot(identical(f3b$tag, f2$tag),
|
|
|
156 |
identical(f3b$flag, as("Other", "ratedChar")),
|
|
|
157 |
identical(f3b$flag2, as("More", "ratedChar")))
|
| 57589 |
jmc |
158 |
## a class with an initialize method, and an extra slot (legal, not a good idea)
|
| 52960 |
jmc |
159 |
setOldClass(c("simple.list", "list"))
|
|
|
160 |
fg4 <- setRefClass("foo4",
|
|
|
161 |
contains = "foo2",
|
|
|
162 |
methods = list(
|
|
|
163 |
initialize = function(...) {
|
| 55779 |
jmc |
164 |
.self$initFields(...)
|
|
|
165 |
.self@made <<- R.version
|
| 52960 |
jmc |
166 |
.self
|
|
|
167 |
}),
|
|
|
168 |
representation = list(made = "simple.list")
|
|
|
169 |
)
|
|
|
170 |
|
| 57589 |
jmc |
171 |
f4 <- new("foo4", flag = as("another test", "ratedChar"), bar = 1:3)
|
| 52960 |
jmc |
172 |
stopifnot(identical(f4@made, R.version))
|
| 52985 |
jmc |
173 |
|
| 56036 |
jmc |
174 |
## a trivial class with no fields, using fields = list(), failed up to rev 56035
|
|
|
175 |
foo5 <- setRefClass("foo5", fields = list(),
|
| 56211 |
maechler |
176 |
methods = list(bar = function(test)
|
|
|
177 |
paste("*",test,"*")))
|
| 56036 |
jmc |
178 |
|
| 61035 |
jmc |
179 |
f5 <- foo5()
|
| 56036 |
jmc |
180 |
stopifnot(identical( f5$bar("xxx"), paste("*","xxx", "*")))
|
|
|
181 |
|
|
|
182 |
|
| 52985 |
jmc |
183 |
## simple active binding test
|
|
|
184 |
abGen <- setRefClass("ab",
|
|
|
185 |
fields = list(a = "ANY",
|
|
|
186 |
b = function(x) if(missing(x)) a else {a <<- x; x}))
|
|
|
187 |
|
| 61035 |
jmc |
188 |
ab1 <- abGen(a = 1)
|
| 52985 |
jmc |
189 |
|
|
|
190 |
stopifnot(identical(ab1$a, 1), identical(ab1$b, 1))
|
|
|
191 |
|
|
|
192 |
ab1$b <- 2
|
|
|
193 |
|
|
|
194 |
stopifnot(identical(ab1$a, 2), identical(ab1$b, 2))
|
| 53068 |
jmc |
195 |
|
|
|
196 |
## a simple editor for matrix objects. Method $edit() changes some
|
|
|
197 |
## range of values; method $undo() undoes the last edit.
|
|
|
198 |
mEditor <- setRefClass("matrixEditor",
|
| 56211 |
maechler |
199 |
fields = list(data = "matrix",
|
|
|
200 |
edits = "list"),
|
|
|
201 |
methods = list(
|
| 53068 |
jmc |
202 |
edit = function(i, j, value) {
|
|
|
203 |
## the following string documents the edit method
|
|
|
204 |
'Replaces the range [i, j] of the
|
| 56211 |
maechler |
205 |
object by value.
|
| 53068 |
jmc |
206 |
'
|
|
|
207 |
backup <-
|
|
|
208 |
list(i, j, data[i,j])
|
|
|
209 |
data[i,j] <<- value
|
|
|
210 |
edits <<- c(list(backup),
|
|
|
211 |
edits)
|
|
|
212 |
invisible(value)
|
|
|
213 |
},
|
|
|
214 |
undo = function() {
|
|
|
215 |
'Undoes the last edit() operation
|
|
|
216 |
and update the edits field accordingly.
|
|
|
217 |
'
|
|
|
218 |
prev <- edits
|
|
|
219 |
if(length(prev)) prev <- prev[[1]]
|
|
|
220 |
else stop("No more edits to undo")
|
|
|
221 |
edit(prev[[1]], prev[[2]], prev[[3]])
|
|
|
222 |
## trim the edits list
|
|
|
223 |
length(edits) <<- length(edits) - 2
|
|
|
224 |
invisible(prev)
|
|
|
225 |
}
|
|
|
226 |
))
|
|
|
227 |
xMat <- matrix(1:12,4,3)
|
| 61035 |
jmc |
228 |
xx <- mEditor(data = xMat)
|
| 53068 |
jmc |
229 |
xx$edit(2, 2, 0)
|
|
|
230 |
xx$data
|
|
|
231 |
xx$undo()
|
|
|
232 |
mEditor$help("undo")
|
|
|
233 |
stopifnot(all.equal(xx$data, xMat))
|
|
|
234 |
|
|
|
235 |
## add a method to save the object
|
|
|
236 |
mEditor$methods(
|
|
|
237 |
save = function(file) {
|
|
|
238 |
'Save the current object on the file
|
| 59654 |
jmc |
239 |
in R external object format.
|
|
|
240 |
'
|
| 53068 |
jmc |
241 |
base::save(.self, file = file)
|
| 59654 |
jmc |
242 |
},
|
|
|
243 |
counter = function(i) {
|
|
|
244 |
'The number of items in the i-th edit.
|
|
|
245 |
(Used to test usingMethods())
|
|
|
246 |
'
|
|
|
247 |
if(i > 0 && i <= length(edits))
|
|
|
248 |
length(edits[[i]][[3]])
|
|
|
249 |
else
|
|
|
250 |
0L
|
| 53068 |
jmc |
251 |
}
|
|
|
252 |
)
|
|
|
253 |
|
|
|
254 |
tf <- tempfile()
|
|
|
255 |
xx$save(tf) #$
|
|
|
256 |
load(tf)
|
|
|
257 |
unlink(tf)
|
|
|
258 |
stopifnot(identical(xx$data, .self$data))
|
|
|
259 |
|
| 62700 |
jmc |
260 |
## tests of $trace() methods
|
|
|
261 |
## debugging an object
|
|
|
262 |
xx$trace(edit, quote(xxTrace <<- TRUE))
|
|
|
263 |
|
|
|
264 |
## debugging all objects from class mEditor in method $undo()
|
|
|
265 |
mEditor$trace(undo, quote(mETrace <<- TRUE))
|
|
|
266 |
|
|
|
267 |
xxTrace <- mETrace <- FALSE
|
|
|
268 |
xx$edit(2,3,100)
|
|
|
269 |
xx$undo()
|
|
|
270 |
|
|
|
271 |
## will not have changed the xx$undo() method (already used)
|
|
|
272 |
stopifnot(identical(xxTrace, TRUE), identical(mETrace, FALSE))
|
|
|
273 |
|
|
|
274 |
## but a new object works the other way around
|
|
|
275 |
xxTrace <- mETrace <- FALSE
|
|
|
276 |
xx <- mEditor(data = xMat)
|
|
|
277 |
xx$edit(2,3,100)
|
|
|
278 |
xx$undo()
|
|
|
279 |
stopifnot(identical(xxTrace, FALSE), identical(mETrace, TRUE))
|
|
|
280 |
|
|
|
281 |
|
|
|
282 |
|
| 53068 |
jmc |
283 |
markViewer <- ""
|
|
|
284 |
setMarkViewer <- function(what)
|
|
|
285 |
markViewer <<- what
|
|
|
286 |
|
|
|
287 |
## Inheriting a reference class: a matrix viewer
|
|
|
288 |
mv <- setRefClass("matrixViewer",
|
|
|
289 |
fields = c("viewerDevice", "viewerFile"),
|
|
|
290 |
contains = "matrixEditor",
|
|
|
291 |
methods = list( view = function() {
|
|
|
292 |
dd <- dev.cur(); dev.set(viewerDevice)
|
|
|
293 |
devAskNewPage(FALSE)
|
|
|
294 |
matplot(data, main = paste("After",length(edits),"edits"))
|
|
|
295 |
dev.set(dd)},
|
|
|
296 |
edit = # invoke previous method, then replot
|
|
|
297 |
function(i, j, value) {
|
|
|
298 |
callSuper(i, j, value)
|
|
|
299 |
view()
|
|
|
300 |
}))
|
|
|
301 |
|
|
|
302 |
## initialize and finalize methods
|
| 53470 |
jmc |
303 |
mv$methods( initialize = function(file = "./matrixView.pdf", ...) {
|
|
|
304 |
viewerFile <<- file
|
| 53068 |
jmc |
305 |
pdf(viewerFile)
|
|
|
306 |
viewerDevice <<- dev.cur()
|
|
|
307 |
message("Plotting to ", viewerFile)
|
|
|
308 |
dev.set(dev.prev())
|
|
|
309 |
setMarkViewer("ON")
|
|
|
310 |
initFields(...)
|
|
|
311 |
},
|
|
|
312 |
finalize = function() {
|
|
|
313 |
dev.off(viewerDevice)
|
|
|
314 |
setMarkViewer("OFF")
|
|
|
315 |
})
|
|
|
316 |
|
| 59654 |
jmc |
317 |
## a counts method to test usingMethods()
|
|
|
318 |
mv$methods( counts = function() {
|
|
|
319 |
usingMethods("counter")
|
|
|
320 |
sapply(seq_along(edits), "counter")
|
|
|
321 |
})
|
|
|
322 |
|
|
|
323 |
|
| 61035 |
jmc |
324 |
ff <- mv( data = xMat)
|
| 53068 |
jmc |
325 |
stopifnot(identical(markViewer, "ON")) # check initialize
|
|
|
326 |
ff$edit(2,2,0)
|
|
|
327 |
ff$data
|
| 69213 |
ripley |
328 |
if(methods:::.hasCodeTools()) # otherwise 'counter' is not visible
|
|
|
329 |
stopifnot(identical(ff$counts(), length(ff$edits[[1]][[3]])))
|
| 53068 |
jmc |
330 |
ff$undo()
|
|
|
331 |
stopifnot(all.equal(ff$data, xMat))
|
|
|
332 |
rm(ff)
|
|
|
333 |
gc()
|
|
|
334 |
stopifnot(identical(markViewer, "OFF")) #check finalize
|
| 53212 |
jmc |
335 |
|
| 53669 |
jmc |
336 |
## tests of copying
|
|
|
337 |
viewerPlus <- setRefClass("viewerPlus",
|
|
|
338 |
fields = list( text = "character",
|
|
|
339 |
viewer = "matrixViewer"))
|
| 61035 |
jmc |
340 |
ff <- mv( data = xMat)
|
|
|
341 |
v1 <- viewerPlus(text = letters, viewer = ff)
|
| 53669 |
jmc |
342 |
v2 <- v1$copy()
|
|
|
343 |
v3 <- v1$copy(TRUE)
|
|
|
344 |
v2$text <- "Hello, world"
|
|
|
345 |
v2$viewer$data <- t(xMat) # change a field in v2$viewer
|
|
|
346 |
v3$text <- LETTERS
|
| 61035 |
jmc |
347 |
v3$viewer <- mv( data = matrix(nrow=1,ncol=1))
|
| 53669 |
jmc |
348 |
## with a deep copy all is protected, with a shallow copy
|
|
|
349 |
## the environment of a copied field remains the same,
|
|
|
350 |
## but replacing the whole field should be local
|
|
|
351 |
stopifnot(identical(v1$text, letters),
|
|
|
352 |
identical(v1$viewer, ff),
|
|
|
353 |
identical(v2$text, "Hello, world"))
|
|
|
354 |
v3 <- v1$copy(TRUE)
|
|
|
355 |
v3$viewer$data <- t(xMat) # should modify v1$viewer as well
|
|
|
356 |
stopifnot(identical(v1$viewer$data, t(xMat)))
|
|
|
357 |
|
| 53693 |
jmc |
358 |
## the field() method
|
|
|
359 |
stopifnot(identical(v1$text, v1$field("text")))
|
|
|
360 |
v1$field("text", "Now is the time")
|
|
|
361 |
stopifnot(identical(v1$field("text"), "Now is the time"))
|
|
|
362 |
|
|
|
363 |
## setting a non-existent field, or a method, should throw an error
|
|
|
364 |
stopifnot(is(tryCatch(v1$field("foobar", 0), error = function(e)e), "error"),
|
|
|
365 |
is(tryCatch(v1$field("copy", 0), error = function(e)e), "error") )
|
|
|
366 |
|
| 53669 |
jmc |
367 |
## the methods to extract class definition and generator
|
| 53693 |
jmc |
368 |
stopifnot(identical(v3$getRefClass()$def, getRefClass("viewerPlus")$def),
|
|
|
369 |
identical(v3$getClass(), getClass("viewerPlus")))
|
| 53669 |
jmc |
370 |
|
| 53212 |
jmc |
371 |
## deal correctly with inherited methods and overriding existing
|
|
|
372 |
## methods from $methods(...)
|
|
|
373 |
refClassA <- setRefClass("refClassA", methods=list(foo=function() "A"))
|
|
|
374 |
refClassB <- setRefClass("refClassB", contains="refClassA")
|
|
|
375 |
mnames <- objects(getClass("refClassB")@refMethods)
|
|
|
376 |
refClassB$methods(foo=function() callSuper())
|
| 61035 |
jmc |
377 |
stopifnot(identical(refClassB()$foo(), "A"))
|
| 53212 |
jmc |
378 |
mnames2 <- objects(getClass("refClassB")@refMethods)
|
|
|
379 |
stopifnot(identical(mnames2[is.na(match(mnames2,mnames))], "foo#refClassA"))
|
|
|
380 |
refClassB$methods(foo=function() paste(callSuper(), "Version 2"))
|
| 61035 |
jmc |
381 |
stopifnot(identical(refClassB()$foo(), "A Version 2"))
|
| 53212 |
jmc |
382 |
stopifnot(identical(mnames2, objects(getClass("refClassB")@refMethods)))
|
| 53274 |
jmc |
383 |
|
|
|
384 |
if(methods:::.hasCodeTools()) {
|
| 54575 |
jmc |
385 |
## code warnings assigning locally to field names
|
| 56211 |
maechler |
386 |
stopifnot(is(tryCatch(mv$methods(test = function(x)
|
|
|
387 |
{ data <- x[!is.na(x)]; mean(data)}),
|
|
|
388 |
warning = function(e)e), "warning"))
|
| 53274 |
jmc |
389 |
|
| 54575 |
jmc |
390 |
## warnings for nonlocal assignment that is not a field
|
|
|
391 |
stopifnot(is(tryCatch(mv$methods(test2 = function(x) {something <<- data[!is.na(x)]}), warning = function(e)e), "warning"))
|
|
|
392 |
|
|
|
393 |
## error for trying to assign to a method name
|
|
|
394 |
stopifnot(is(tryCatch(mv$methods(test3 = function(x) {edit <<- data[!is.na(x)]}), error = function(e)e), "error"))
|
| 53274 |
jmc |
395 |
} else
|
|
|
396 |
warning("Can't run some tests: recommended package codetools is not available")
|
| 53330 |
jmc |
397 |
|
|
|
398 |
## tests (fragmentary by necessity) of promptClass for reference class
|
| 53470 |
jmc |
399 |
ccon <- textConnection("ctxt", "w")
|
|
|
400 |
suppressMessages(promptClass("refClassB", filename = ccon))
|
| 53330 |
jmc |
401 |
## look for a method, inheritance, inherited method
|
|
|
402 |
stopifnot(length(c(grep("foo.*refClassA", ctxt),
|
|
|
403 |
grep("code{foo()}", ctxt, fixed = TRUE),
|
|
|
404 |
grep("linkS4class{refClassA", ctxt, fixed = TRUE))) >= 3)
|
| 53470 |
jmc |
405 |
close(ccon)
|
| 53330 |
jmc |
406 |
rm(ctxt)
|
| 53382 |
jmc |
407 |
|
|
|
408 |
|
|
|
409 |
## tests related to subclassing environments. These really test code in the core, viz. builtin.c
|
| 61035 |
jmc |
410 |
a <- refClassA()
|
| 53382 |
jmc |
411 |
ev <- new.env(parent = a) # parent= arg
|
|
|
412 |
stopifnot(is.environment(ev))
|
|
|
413 |
foo <- function()"A"; environment(foo) <- a # environment of function
|
|
|
414 |
stopifnot(identical(as.environment(a), environment(foo)))
|
|
|
415 |
xx <- 1:10; environment(xx) <- a # environment attribute
|
|
|
416 |
stopifnot(identical(as.environment(a), environment(xx)))
|
|
|
417 |
|
|
|
418 |
|
| 56211 |
maechler |
419 |
## tests of [[<- and $<- for subclasses of environment. At one point
|
|
|
420 |
## methods for these assignments were defined and caused
|
|
|
421 |
## inf. recursion when the arguments to the [[<- case were changed in base.
|
| 53385 |
jmc |
422 |
setClass("myEnv", contains = "environment")
|
| 53641 |
jmc |
423 |
m <- new("myEnv", a="test")
|
|
|
424 |
m2 <- new("myEnv"); m3 <- new("myEnv")
|
|
|
425 |
## test that new.env() is called for each new object
|
|
|
426 |
stopifnot(!identical(as.environment(m), as.environment(m2)),
|
|
|
427 |
!identical(as.environment(m3), as.environment(m2)))
|
| 53385 |
jmc |
428 |
m[["x"]] <- 1; m$y <- 2
|
| 56211 |
maechler |
429 |
stopifnot(identical(c(m[["x"]], m$y), c(1,2)), is(m, "myEnv"))
|
| 53641 |
jmc |
430 |
rm(x, envir = m) # check rm() works, does not clobber class
|
|
|
431 |
stopifnot(identical(sort(objects(m)), sort(c("a", "y"))),
|
|
|
432 |
is(m, "myEnv"))
|
| 53465 |
jmc |
433 |
|
| 53564 |
jmc |
434 |
## tests of binding & environment tools with subclases of environment
|
|
|
435 |
lockBinding("y", m)
|
|
|
436 |
stopifnot(bindingIsLocked("y", m))
|
|
|
437 |
unlockBinding("y", m)
|
|
|
438 |
stopifnot(!bindingIsLocked("y", m))
|
|
|
439 |
|
|
|
440 |
makeActiveBinding("z", function(value) {
|
|
|
441 |
if(missing(value))
|
|
|
442 |
"dummy"
|
|
|
443 |
else
|
|
|
444 |
"dummy assignment"
|
|
|
445 |
}, m)
|
|
|
446 |
stopifnot(identical(get("z", m),"dummy"))
|
|
|
447 |
## assignment will return the value but do nothing
|
|
|
448 |
stopifnot(identical(assign("z","other", m), "other"),
|
|
|
449 |
identical(get("z", m),"dummy"))
|
|
|
450 |
|
|
|
451 |
|
|
|
452 |
## this has to be last--Seems no way to unlock an environment!
|
|
|
453 |
lockEnvironment(m)
|
|
|
454 |
stopifnot(environmentIsLocked(m))
|
|
|
455 |
|
| 53645 |
maechler |
456 |
rm(m)
|
|
|
457 |
m <- new("myEnv")
|
|
|
458 |
stopifnot(length(ls(m)) == 0)
|
|
|
459 |
## used to contain the previous content
|
| 53564 |
jmc |
460 |
|
| 53645 |
maechler |
461 |
|
| 53465 |
jmc |
462 |
## test of callSuper() to a hidden default method for initialize() (== initFields)
|
|
|
463 |
TestClass <- setRefClass ("TestClass",
|
| 53470 |
jmc |
464 |
fields = list (text = "character"),
|
|
|
465 |
methods = list(
|
|
|
466 |
print = function () {cat(text)},
|
|
|
467 |
initialize = function(text = "", ...) callSuper(text = paste(text, ":", sep=""),...)
|
|
|
468 |
))
|
| 61035 |
jmc |
469 |
tt <- TestClass("hello world")
|
| 53470 |
jmc |
470 |
stopifnot(identical(tt$text, "hello world:"))
|
|
|
471 |
## now a subclass with another field & another layer of callSuper()
|
|
|
472 |
TestClass2 <- setRefClass("TestClass2",
|
|
|
473 |
contains = "TestClass",
|
|
|
474 |
fields = list( version = "integer"),
|
|
|
475 |
methods = list(
|
| 56572 |
jmc |
476 |
initialize = function(..., version = 0L)
|
|
|
477 |
callSuper(..., version = version+1L))
|
| 53470 |
jmc |
478 |
)
|
| 61035 |
jmc |
479 |
tt <- TestClass2("test", version = 1L)
|
| 53470 |
jmc |
480 |
stopifnot(identical(tt$text, "test:"), identical(tt$version, as.integer(2)))
|
| 61035 |
jmc |
481 |
tt <- TestClass2(version=3L) # default text
|
| 53470 |
jmc |
482 |
stopifnot(identical(tt$text, ":"), identical(tt$version, as.integer(4)))
|
| 54575 |
jmc |
483 |
|
|
|
484 |
|
| 55779 |
jmc |
485 |
## test some capabilities but read-only for .self
|
|
|
486 |
.changeAllFields <- function(replacement) {
|
|
|
487 |
fields <- names(.refClassDef@fieldClasses)
|
|
|
488 |
for(field in fields)
|
|
|
489 |
eval(substitute(.self$FIELD <- replacement$FIELD,
|
|
|
490 |
list(FIELD = field)))
|
|
|
491 |
}
|
|
|
492 |
|
|
|
493 |
mEditor$methods(change = .changeAllFields)
|
| 61035 |
jmc |
494 |
xx <- mEditor(data = xMat)
|
| 55779 |
jmc |
495 |
xx$edit(2, 2, 0)
|
|
|
496 |
|
| 61035 |
jmc |
497 |
yy <- mEditor(data = xMat+1)
|
| 55779 |
jmc |
498 |
yy$change(xx)
|
|
|
499 |
stopifnot(identical(yy$data, xx$data), identical(yy$edits, xx$edits))
|
|
|
500 |
|
|
|
501 |
## but don't allow assigment
|
|
|
502 |
if(methods:::.hasCodeTools())
|
|
|
503 |
stopifnot(is(tryCatch(yy$.self$data <- xMat, error = function(e)e), "error"))
|
| 55988 |
jmc |
504 |
|
| 61058 |
jmc |
505 |
## the locked binding of refGeneratorSlot class should prevent modifying
|
| 55988 |
jmc |
506 |
## methods, locking fields or setting accessor methods
|
| 61058 |
jmc |
507 |
## Nothing special about refGeneratorSlot in this test -- the point is just
|
|
|
508 |
## to use a standard reference class known to be defined in a package
|
|
|
509 |
evr <- getRefClass("refGeneratorSlot") # in methods
|
| 55988 |
jmc |
510 |
stopifnot(is(tryCatch(evr$methods(foo = function()"..."), error = function(e)e), "error"),
|
|
|
511 |
is(tryCatch(evr$lock("def"), error = function(e)e), "error"),
|
|
|
512 |
is(tryCatch(evr$accessors("def"), error = function(e)e), "error"))
|
| 56119 |
jmc |
513 |
|
|
|
514 |
##getRefClass() method and function should work with either
|
|
|
515 |
## a class name or a class representation (bug report 14600)
|
|
|
516 |
tg <- setRefClass("tg", fields = "a")
|
| 61035 |
jmc |
517 |
t1 <- tg(a=1)
|
| 56119 |
jmc |
518 |
tgg <- t1$getRefClass()
|
|
|
519 |
tggg <- getRefClass("tg")
|
|
|
520 |
stopifnot(identical(tgg$def, tggg$def),
|
|
|
521 |
identical(tg$def, tgg$def))
|
|
|
522 |
|
| 57841 |
jmc |
523 |
## this used to fail in initFieldArgs() from partial matching "self"
|
|
|
524 |
selfClass <- setRefClass("selfClass",
|
|
|
525 |
fields=list(
|
|
|
526 |
self="character", super="character", sub="character"
|
|
|
527 |
)
|
|
|
528 |
)
|
|
|
529 |
|
| 61035 |
jmc |
530 |
stopifnot(identical(selfClass(self="B", super="A", sub="C")$self, "B"))
|