Search code examples
rassignr-package

Change variable in package namespace


I have a package that has a variable assigned to the package namespace on load, like so:

.onLoad <- function(libname, pkgname){
  assign(".myvar", 
         "foo", 
         envir = parent.env(environment()))
}

In my package, I use the variable like so:

myfn <- function(){
  print(.myvar)
}

Now, during testing I need to change the variable prior to running the test.

test_that("myfn works correctly", {
  myvar_tmp <- .myvar
  withr::defer(assign(".myvar", myvar_tmp , pos = "package:mypackage"))
  assign(".myvar", "bar", pos = "package:mypackage")
  
  expect_equal(myfn(), "bar")
})

When I run this test, however, I get:

── Failure (Line 6): myfn works correctly ──────────────────────────────────────
myfn() not equal to "bar".
1/1 mismatches
x[1]: "foo"
y[1]: "bar"

Clearly, I haven't updated .myvar correctly and myfn is still picking up the value set on load.

When I try to set the variable outside the test,

> assign(".myvar", "bar", pos = "package:mypackage")
> .myvar
# [1] "bar"

and this appears to be the package variable and not one in another namespace:

pryr::where(".myvar")
<environment: package:mypackage>
attr(,"name")
[1] "package:mypackage"
attr(,"path")
[1] "/home/user/Documents/mypackage"

But that said, when I call the function

> myfn()
#[1] "foo"

it doesn't use the new value, but rather the value specified on load.

Question: What is the correct way of updating a variable in the package namespace in this situation?


PS This is a toy example to demonstrate the principle, as the real use case is more complex. I realise that it's not clear why I'd want to change the variable in testing, but for the actual use case it's necessary.


Solution

  • The problem seems to have been with the format of the assign statements. Instead of

    assign(".myvar", "bar", pos = "package:mypackage")
    

    I used,

    assign(".myvar", "bar", pos = asNamespace("mypackage"))
    

    and this resolved the issue.