The R Project SVN R

Rev

Rev 53645 | Rev 53691 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
52846 jmc 1
options(error = recover)
52960 jmc 2
## simple call, only field names
3
fg <- setRefClass("foo", c("bar", "flag"))
4
f1<- new("foo")
5
f1$bar
6
f1 <- fg$new(flag = "testing")
7
f1$bar <- 1
8
stopifnot(identical(f1$bar, 1))
9
fg$methods(showAll = function() c(bar, flag))
10
stopifnot(all.equal(f1$showAll(), c(1, "testing")))
11
 
52903 jmc 12
fg <- setRefClass("foo", list(bar = "numeric", flag = "character"),
52960 jmc 13
            methods = list(
52816 jmc 14
            addToBar = function(incr) {
52960 jmc 15
                b = bar + incr
16
                bar <<- b
52816 jmc 17
                b
18
            }
19
            ))
20
ff = new("foo", bar = 1.5)
21
stopifnot(identical(ff$bar, 1.5))
22
ff$bar <- pi
23
stopifnot(identical(ff$bar, pi))
52903 jmc 24
## test against generator
52816 jmc 25
 
52903 jmc 26
f2 <- fg$new(bar = pi)
27
## identical does not return TRUE if *contents* of env are identical
28
stopifnot(identical(ff$bar, f2$bar), identical(ff$flag, f2$flag))
29
 
52960 jmc 30
f2$flag <- "standard flag"
31
stopifnot(identical(f2$flag, "standard flag"))
52903 jmc 32
 
52960 jmc 33
## fg$lock("flag")
34
## tryCatch(f2$flag <- "other", error = function(e)e)
52816 jmc 35
 
52960 jmc 36
 
37
## add some accessor methods
38
fg$accessors("bar")
39
 
52816 jmc 40
ff$setBar(1:3)
52960 jmc 41
stopifnot(identical(ff$getBar(), 1:3))
52816 jmc 42
 
43
ff$getBar()
44
stopifnot(all.equal(ff$addToBar(1), 2:4))
45
 
52960 jmc 46
 
52903 jmc 47
## Add a method
48
fg$methods(barTimes = function(x) {
49
    "This method multiples field bar by argument x
50
and this string is self-documentation"
51
    setBar(getBar() * x)})
52
 
53
ffbar <- ff$getBar()
54
ff$barTimes(10)
55
stopifnot(all.equal(ffbar * 10, ff$getBar()))
56
ff$barTimes(.1)
57
 
52846 jmc 58
## inheritance.  redefines flag so should fail:
52903 jmc 59
stopifnot(is(tryCatch(setRefClass("foo2", list(b2 = "numeric", flag = "complex"),
52816 jmc 60
            contains = "foo",
52903 jmc 61
            refMethods = list(addBoth = function(incr) {
52816 jmc 62
                addToBar(incr) #uses inherited class method
63
                setB2(getB2() + incr)
52903 jmc 64
                })),
65
          error = function(e)e), "error"))
52846 jmc 66
## but with flag as a subclass of "character", should work
52871 jmc 67
setClass("ratedChar", contains = "character", representation(score = "numeric"))
52903 jmc 68
foo2 <- setRefClass("foo2", list(b2 = "numeric", flag = "ratedChar"),
52846 jmc 69
            contains = "foo",
52960 jmc 70
            methods = list(addBoth = function(incr) {
52846 jmc 71
                addToBar(incr) #uses inherited class method
52960 jmc 72
                b2<<- b2 + incr
52816 jmc 73
                }))
52960 jmc 74
## now lock the flag field; should still allow one write
75
foo2$lock("flag")
52903 jmc 76
f2 <- foo2$new(bar = -3, flag = as("ANY", "ratedChar"), b2 = ff$bar)
52960 jmc 77
## but not a second one
78
stopifnot(is(tryCatch(f2$flag <- "Try again",
79
         error = function(e)e), "error"))
80
f22 <- foo2$new(bar = f2$bar)
81
## same story if assignment follows the initialization
82
f22$flag <- f2$flag
83
stopifnot(is(tryCatch(f22$flag <- "Try again",
84
         error = function(e)e), "error"))
85
## Exporting superclass object
52903 jmc 86
f22 <- fg$new(bar = f2$bar, flag = f2$flag)
87
f2e <- f2$export("foo")
88
stopifnot(identical(f2e$bar, f22$bar), identical(f2e$flag, f22$flag),
89
          identical(class(f2e), class(f22)))
52871 jmc 90
stopifnot(identical(f2$flag,  as("ANY", "ratedChar")), identical(f2$bar, -3),
52816 jmc 91
          all.equal(f2$b2, 2:4+0))
92
f2$addBoth(-1)
93
stopifnot(all.equal(f2$bar, -4), all.equal(f2$b2, 1:3+0))
94
 
52960 jmc 95
## test callSuper()
96
setRefClass("foo3", fields = list(flag2 = "ratedChar"),
97
            contains = "foo2",
98
            methods = list(addBoth = function(incr) {
52846 jmc 99
                callSuper(incr)
52960 jmc 100
                flag2 <<- as(paste(flag, paste(incr, collapse = ", "), sep = "; "), "ratedChar")
52816 jmc 101
                incr
102
            }))
103
 
52960 jmc 104
f2 <- foo2$new(bar = -3, flag = as("ANY", "ratedChar"), b2 =  1:3)
52846 jmc 105
f3 <- new("foo3")
106
f3$import(f2)
107
stopifnot(all.equal(f3$b2, f2$b2), all.equal(f3$bar, f2$bar), all.equal(f3$flag, f2$flag))
52871 jmc 108
f3$addBoth(1)
52960 jmc 109
stopifnot(all.equal(f3$bar, -2), all.equal(f3$b2, 2:4+0),
110
          all.equal(f3$flag2, as("ANY; 1", "ratedChar")))
52871 jmc 111
 
52960 jmc 112
## but the import should have used up the one write for $flag
113
stopifnot(is(tryCatch(f3$flag <- "Try again",
114
         error = function(e)e), "error"))
115
 
116
## a class with an initialize method, and an extra slot
117
setOldClass(c("simple.list", "list"))
118
fg4 <- setRefClass("foo4",
119
            contains = "foo2",
120
            methods = list(
121
              initialize = function(...) {
122
                  .self <- initFields(...)
123
                  .self@made = R.version
124
                  .self
125
              }),
126
            representation = list(made = "simple.list")
127
            )
128
 
129
f4 <- new("foo4", flag = "another test", bar = 1:3)
130
stopifnot(identical(f4@made, R.version))
52985 jmc 131
 
132
## simple active binding test
133
abGen <- setRefClass("ab",
134
                  fields = list(a = "ANY",
135
                  b = function(x) if(missing(x)) a else {a <<- x; x}))
136
 
137
ab1 <- abGen$new(a = 1)
138
 
139
stopifnot(identical(ab1$a, 1), identical(ab1$b, 1))
140
 
141
ab1$b <- 2
142
 
143
stopifnot(identical(ab1$a, 2), identical(ab1$b, 2))
53068 jmc 144
 
145
## a simple editor for matrix objects.  Method  $edit() changes some
146
## range of values; method $undo() undoes the last edit.
147
mEditor <- setRefClass("matrixEditor",
148
      fields = list( data = "matrix",
149
        edits = "list"),
150
      methods = list(
151
     edit = function(i, j, value) {
152
       ## the following string documents the edit method
153
       'Replaces the range [i, j] of the
154
        object by value.
155
        '
156
         backup <-
157
             list(i, j, data[i,j])
158
         data[i,j] <<- value
159
         edits <<- c(list(backup),
160
                     edits)
161
         invisible(value)
162
     },
163
     undo = function() {
164
       'Undoes the last edit() operation
165
        and update the edits field accordingly.
166
        '
167
         prev <- edits
168
         if(length(prev)) prev <- prev[[1]]
169
         else stop("No more edits to undo")
170
         edit(prev[[1]], prev[[2]], prev[[3]])
171
         ## trim the edits list
172
         length(edits) <<- length(edits) - 2
173
         invisible(prev)
174
     }
175
     ))
176
xMat <- matrix(1:12,4,3)
177
xx <- mEditor$new(data = xMat)
178
xx$edit(2, 2, 0)
179
xx$data
180
xx$undo()
181
mEditor$help("undo")
182
stopifnot(all.equal(xx$data, xMat))
183
 
184
## add a method to save the object
185
mEditor$methods(
186
     save = function(file) {
187
       'Save the current object on the file
188
        in R external object format.
189
       '
190
         base::save(.self, file = file)
191
     }
192
)
193
 
194
tf <- tempfile()
195
xx$save(tf) #$
196
load(tf)
197
unlink(tf)
198
stopifnot(identical(xx$data, .self$data))
199
 
200
markViewer <- ""
201
setMarkViewer <- function(what)
202
    markViewer <<- what
203
 
204
## Inheriting a reference class:  a matrix viewer
205
mv <- setRefClass("matrixViewer",
206
    fields = c("viewerDevice", "viewerFile"),
207
    contains = "matrixEditor",
208
    methods = list( view = function() {
209
        dd <- dev.cur(); dev.set(viewerDevice)
210
        devAskNewPage(FALSE)
211
        matplot(data, main = paste("After",length(edits),"edits"))
212
        dev.set(dd)},
213
        edit = # invoke previous method, then replot
214
          function(i, j, value) {
215
            callSuper(i, j, value)
216
            view()
217
          }))
218
 
219
## initialize and finalize methods
53470 jmc 220
mv$methods( initialize = function(file = "./matrixView.pdf", ...) {
221
    viewerFile <<- file
53068 jmc 222
    pdf(viewerFile)
223
    viewerDevice <<- dev.cur()
224
    message("Plotting to ", viewerFile)
225
    dev.set(dev.prev())
226
    setMarkViewer("ON")
227
    initFields(...)
228
  },
229
  finalize = function() {
230
    dev.off(viewerDevice)
231
    setMarkViewer("OFF")
232
  })
233
 
53669 jmc 234
ff = mv$new( data = xMat)
53068 jmc 235
stopifnot(identical(markViewer, "ON")) # check initialize
236
ff$edit(2,2,0)
237
ff$data
238
ff$undo()
239
stopifnot(all.equal(ff$data, xMat))
240
rm(ff)
241
gc()
242
stopifnot(identical(markViewer, "OFF")) #check finalize
53212 jmc 243
 
53669 jmc 244
## tests of copying
245
viewerPlus <- setRefClass("viewerPlus",
246
                   fields = list( text = "character",
247
                      viewer = "matrixViewer"))
248
ff <- mv$new( data = xMat)
249
v1 <- viewerPlus$new(text = letters, viewer = ff)
250
v2 <- v1$copy()
251
v3 <- v1$copy(TRUE)
252
v2$text <- "Hello, world"
253
v2$viewer$data <- t(xMat) # change a field in v2$viewer
254
v3$text <- LETTERS
255
v3$viewer <- mv$new( data = matrix(nrow=1,ncol=1))
256
## with a deep copy all is protected, with a shallow copy
257
## the environment of a copied field remains the same,
258
## but replacing the whole field should be local
259
stopifnot(identical(v1$text, letters),
260
          identical(v1$viewer, ff),
261
          identical(v2$text, "Hello, world"))
262
v3 <- v1$copy(TRUE)
263
v3$viewer$data <- t(xMat) # should modify v1$viewer as well
264
stopifnot(identical(v1$viewer$data, t(xMat)))
265
 
266
## the methods to extract class definition and generator
267
stopifnot(identical(v3$getRefClass(), mv),
268
          identical(v3$getClass(), getClass("viewerPlus")))
269
 
53212 jmc 270
## deal correctly with inherited methods and overriding existing
271
## methods from $methods(...)
272
refClassA <- setRefClass("refClassA", methods=list(foo=function() "A"))
273
refClassB <- setRefClass("refClassB", contains="refClassA")
274
mnames <- objects(getClass("refClassB")@refMethods)
275
refClassB$methods(foo=function() callSuper())
276
stopifnot(identical(refClassB$new()$foo(), "A"))
277
mnames2 <- objects(getClass("refClassB")@refMethods)
278
stopifnot(identical(mnames2[is.na(match(mnames2,mnames))], "foo#refClassA"))
279
refClassB$methods(foo=function() paste(callSuper(), "Version 2"))
280
stopifnot(identical(refClassB$new()$foo(), "A Version 2"))
281
stopifnot(identical(mnames2, objects(getClass("refClassB")@refMethods)))
53274 jmc 282
 
283
if(methods:::.hasCodeTools()) {
284
    ## code warnings assigning locally to, or hiding, field names
285
    stopifnot(is(tryCatch(mv$methods(test = function(x) {data <- x[!is.na(x)]; mean(data)}), warning = function(e)e), "warning"))
286
 
53335 jmc 287
### formal arg test suppressed--see comment in .checkFieldsInMethod
288
    ## stopifnot(is(tryCatch(mv$methods(test2 = function(data) {data[!is.na(x)]}), warning = function(e)e), "warning"))
53274 jmc 289
} else
290
    warning("Can't run some tests:  recommended package codetools is not available")
53330 jmc 291
 
292
## tests (fragmentary by necessity) of promptClass for reference class
53470 jmc 293
ccon <- textConnection("ctxt", "w")
294
suppressMessages(promptClass("refClassB", filename = ccon))
53330 jmc 295
## look for a method, inheritance, inherited method
296
stopifnot(length(c(grep("foo.*refClassA", ctxt),
297
                   grep("code{foo()}", ctxt, fixed = TRUE),
298
                   grep("linkS4class{refClassA", ctxt, fixed = TRUE))) >= 3)
53470 jmc 299
close(ccon)
53330 jmc 300
rm(ctxt)
53382 jmc 301
 
302
 
303
## tests related to subclassing environments.  These really test code in the core, viz. builtin.c
304
a <- refClassA$new()
305
ev <- new.env(parent = a) # parent= arg
306
stopifnot(is.environment(ev))
307
foo <- function()"A"; environment(foo) <- a # environment of function
308
stopifnot(identical(as.environment(a), environment(foo)))
309
xx <- 1:10; environment(xx) <- a # environment attribute
310
stopifnot(identical(as.environment(a), environment(xx)))
311
 
312
 
53385 jmc 313
## tests of [[<- and $<- for subclasses of environment.  At one point methods for these assignments were defined
314
## and caused inf. recursion when the arguments to the [[<- case were changed in base.
315
setClass("myEnv", contains = "environment")
53641 jmc 316
m <- new("myEnv", a="test")
317
m2 <- new("myEnv"); m3 <- new("myEnv")
318
## test that new.env() is called for each new object
319
stopifnot(!identical(as.environment(m), as.environment(m2)),
320
          !identical(as.environment(m3), as.environment(m2)))
53385 jmc 321
m[["x"]] <- 1; m$y <- 2
322
stopifnot(identical(c(m[["x"]], m$y), c(1,2)))
53641 jmc 323
rm(x, envir = m) # check rm() works, does not clobber class
324
stopifnot(identical(sort(objects(m)), sort(c("a", "y"))),
325
          is(m, "myEnv"))
53465 jmc 326
 
53564 jmc 327
## tests of binding & environment tools with subclases of environment
328
lockBinding("y", m)
329
stopifnot(bindingIsLocked("y", m))
330
unlockBinding("y", m)
331
stopifnot(!bindingIsLocked("y", m))
332
 
333
makeActiveBinding("z", function(value) {
334
    if(missing(value))
335
        "dummy"
336
    else
337
        "dummy assignment"
338
}, m)
339
stopifnot(identical(get("z", m),"dummy"))
340
## assignment will return the value but do nothing
341
stopifnot(identical(assign("z","other", m), "other"),
342
          identical(get("z", m),"dummy"))
343
 
344
 
345
## this has to be last--Seems no way to unlock an environment!
346
lockEnvironment(m)
347
stopifnot(environmentIsLocked(m))
348
 
53645 maechler 349
rm(m)
350
m <- new("myEnv")
351
stopifnot(length(ls(m)) == 0)
352
## used to contain the previous content
53564 jmc 353
 
53645 maechler 354
 
53465 jmc 355
## test of callSuper() to a hidden default method for initialize() (== initFields)
356
TestClass <- setRefClass ("TestClass",
53470 jmc 357
     fields = list (text = "character"),
358
     methods = list(
359
       print = function ()  {cat(text)},
360
       initialize = function(text = "", ...) callSuper(text = paste(text, ":", sep=""),...)
361
  ))
362
tt <- TestClass$new("hello world")
363
stopifnot(identical(tt$text, "hello world:"))
364
## now a subclass with another field & another layer of callSuper()
365
TestClass2 <- setRefClass("TestClass2",
366
        contains = "TestClass",
367
        fields = list( version = "integer"),
368
        methods = list(
369
          initialize = function(..., version = 1)
370
              callSuper(..., version = version+1))
371
  )
372
tt <- TestClass2$new("test", version = 1)
373
stopifnot(identical(tt$text, "test:"), identical(tt$version, as.integer(2)))
374
tt <- TestClass2$new(version=3) # default text
375
stopifnot(identical(tt$text, ":"), identical(tt$version, as.integer(4)))