1

I am working on a function which is part of a package. This package contains a template for a new package, and a function which creates R data for the new package which has to have a dynamic name provided to this function.

At the moment I am doing the following:

makedata <- function(schemeName, data) {
  rdsFile <- paste0(schemeName, ".rds")
  varName <- paste0(schemeName)
  saveRDS(
    data,
    file = file.path( ".", "data", rdsFile )
  )
  cat(
    paste0(varName, " <- readRDS(\"./", rdsFile, "\")"),
    file = file.path( ".", "data", paste0(varName, ".R") )
  )
}

makedata(name = "test", data = letters)

which results in two files in the data directory:

  1. a file test.rds containing letters but which is not loaded by R when the package is loaded (rds is not supported)

  2. a file test.R which has the code test <- readRDS("./test.rds") and which causes, when the package is loaded, the data in test.rds to be loaded in the variable test which than contains letters.

Now CRAN does not like rds files in the data directory.

Is there another way that I can use the standard formats (preferably RData) to achieve this?

Rainer
  • 8,347
  • 1
  • 23
  • 28
  • I'm not sure I understood the question, but maybe something along the lines of ``eval(parse(text = sprintf("save(%s, file = %s)", varName, fileLocation)))`` would do the trick. This would however need that ``test`` would be exported as ``data``, which could also be done with ``eval parse``. Seems hacky, yes, so better solutions should exist. – runr May 24 '19 at 13:58
  • Brilliant. I definitely should look into these `eval()` and `parse()`. If you put this into an answer, I will accept it. Possibly with some info on what `parse()` and `eval()` are actually doing here? – Rainer May 24 '19 at 14:13
  • The file extension needs to be `.rda`, than it works without exporting. – Rainer May 24 '19 at 14:36
  • You may be right, I just recall having problems with ``.rda`` and actual variable names vs the filenames, but the issues might have been fixed. [Eval parse](https://stackoverflow.com/questions/1743698/evaluate-expression-given-as-a-string), though, is quite simple to use yet powerful if you're looking for dynamics in your code. The main problem, as you'd imagine, if you ever use it in an app, is that it allows for code injection if used carelessly. @alko989 solution seems cleaner – runr May 24 '19 at 15:03
  • Thanks for the explanations. I will look at @alko989 solution closer. – Rainer May 27 '19 at 06:43

2 Answers2

3

You can try something like this:

makedata <- function(schemeName, data) {
  rdataFile <- paste0(schemeName, ".rda")
  ## Assign data to the name saved in schemeName
  assign(x = schemeName, value = data)
  ## Save as RData file
  save(list = schemeName, file = file.path( ".", "data", rdataFile))
}
alko989
  • 7,688
  • 5
  • 39
  • 62
  • This edited version is not working (I tried this as well) as the save interprets the `schemeName` as the variable, and not as the name of the variable. Could you revert to the `do.call()` version, or is there a reason why you edited it? – Rainer May 27 '19 at 06:46
  • I changed it because it is simpler, it works for me as it is in a fresh session. You have to use the argument ´list = schemeName´ in save – alko989 May 27 '19 at 09:31
  • 1
    True - I overlooked the `list = `. Thanks. – Rainer May 27 '19 at 10:31
  • But as this is now an `.rda` file, the `.R` file with the `load...` is not needed anymore. – Rainer May 27 '19 at 10:32
-1

A possible alternative with eval parse, as discussed in the comments.

makedata <- function(schemeName, data) {
  rdaFile <- paste0(schemeName, ".rda")
  fileLocation <- file.path( ".", "data", rdaFile )
  varName <- paste0(schemeName)

  assign(varName, data)
  eval(parse(text = sprintf("save(%s, file = '%s')", varName, fileLocation)))

  cat(sprintf("%s <- load(%s, file = '%s')", 
              varName, varName,
              fileLocation
              ),
      file = file.path( ".", "data", paste0(varName, ".R") ))
}

Off topic: Also, since you're developing packages, one convenient option might be using system.file instead of file.path due to option system.file('data/test.R', package = 'yourPackage') which allows to look in your package directory, wherever it is installed. Haven't tested your previous solution, it might be working fine too.

runr
  • 1,142
  • 1
  • 9
  • 25
  • Thanks - the `eval(parse())` is very useful to know. But I will use the `save(file = ...)` approach by @alko989 as it easier to understand. – Rainer May 27 '19 at 10:34
  • Yes, I agree! Posted this because I've noticed you had problems with @alko989 solution. Glad you sorted it out – runr May 27 '19 at 10:35
  • Concerning the `system.file()`: I know (and use) it regularly, but here it is safer to use the `file.path` approach. The function is included in the package, but must only be used during development of packages using this one. So using `system.file()` would actually not work here and lead to wrong results. But thanks for pointing this out. – Rainer May 27 '19 at 10:36