Possible to create Rd help files for objects not in a package?

ぃ、小莉子 提交于 2019-11-27 01:42:34

问题


I am using Rstudio to streamline Sweave and R for data analyses that I will share with other analysts. In order to make the coding of variables crystal clear, it would be great to have something like a help file so they can call ?myData and get a helpful file, if they need. I like the Rd markdown and think it actually has great potential to document analytic datasets, including an overall summary, a variable by variable breakdown, and an example of how to run some exploratory analyses.

It's easy to do this if you're specifically creating a package, but I think that it's confusing since packages are ultimately a collection of functions and they don't integrate Rnw files.

Can I use Roxygen2 to create help files for datasets that aren't a part of any package?


回答1:


Before I take a crack at this, I would like to reiterate what others are saying. R's package system is literally exactly what you are looking for. It is used successfully by many to distribute just data and no code. Combined with R's lazyloading of data, you can distribute large datasets as packages and not burden users who don't wish to load it all.

In addition, you will not be able to take advantage of R's help system unless you use packages. The original question explicitly asks about using ?myData and your users will not be able to do that if you do not use a package. This is quite simply a limitation of R's base help function.


Now, to answer the question. You will need to use some non-exported roxygen functions to make this work, but it's not too onerous. In addition, you'll need to put your R file(s) documenting your data into a folder of their own somewhere, and within that folder you will want to create an empty folder called man.

Example directory structure:

# ./
# ./man/
# ./myData.R
# ./otherData.R

myData.R

#' My dataset
#' 
#' This is data I like.
#' 
#' @name myData
NULL

otherData.R:

#' My other dataset
#' 
#' This is another dataset I like
#' 
#' @name otherData
NULL

Now, the code that will bring it all together (and you can of course wrap this in a function):

library(roxygen2)
mydir <- "path/to/your/data/directory/"
myfiles <- c("myData.R","otherData.R")

# get parsed source into roxygen-friendly format
env <- new.env(parent = globalenv())
rfiles <- sapply(myfiles, function(f) file.path(mydir,f))
blocks <- unlist(lapply(rfiles, roxygen2:::parse_file, env=env), recursive=FALSE)
parsed <- list(env=env, blocks=blocks)

# parse roxygen comments into rd files and output then into the "./man" directory
roc <- roxygen2:::rd_roclet()
results <- roxygen2:::roc_process(roc, parsed, mydir)
roxygen2:::roc_output(roc, results, mydir, options=list(wrap=FALSE), check = FALSE)

You should now have properly formatted myData.Rd and otherData.Rd files in the once-empty man folder.




回答2:


roxygen2 now supports this natively but, because the relevant functions are marked “internal”, they are not exposed to the documentation index.

Still, the functions are exported and form part of the official API:

  • parse_file
  • roclet_process

And, to display the resulting help, you’ll need

  • tools::parse_Rd
  • tools::Rd2txt and tools::Rd2HTML

The workflow is as follows:

source_env = roxygen2::env_file(sourcefile)
rd_blocks = roxygen2::parse_file(sourcefile, source_env)
help_topics = roxygen2::roclet_process(roxygen2::rd_roclet(), rd_blocks, source_env, dirname(sourcefile))
rd_code = lapply(help_topics, format)

This gives you a list of help topics in a file. To display one of them you need the {tools} package, which is part of base R, but not attached by default.

The following shows how to display text help. Displaying HTML help is a bit more convoluted (I invite you to read and understand the source code of utils:::print.help_files_with_topic, which does the actual displaying of help topics, and which is completely undocumented.

# Display first help topic. In reality you’d want to select a specific one.
topic = names(rd_code)[1L]
help_text = rd_code[[topic]]

rd = tools::parse_Rd(textConnection(help_text))
packagename = tools::file_path_sans_ext(basename(sourcefile))
helpfile = tools::Rd2txt(rd, out = tempfile('Rtxt'), package = packagename)
helptitle = gettextf('R Help on %s', sQuote(sub('\\.Rd$', '', topic)))
file.show(helpfile, title = helptitle, delete.file = TRUE)



回答3:


Here's a hacky approach that works. Create a dummy package in a temp directory, use that to generate your Rd files, then extract the Rd files out, and clean up. See code below.

Hope this helps.

Note: Make sure you have the @export tag in the functions you want to generate Rd files for, in order for this to work.

makeRd <- function(rscript, dir.out){
  stopifnot(require(devtools))

  # Prepare paths
  pkg.path = tempdir()
  r.path = file.path(pkg.path, 'R')
  man.path = file.path(pkg.path, 'man')
  desc.path = file.path(pkg.path, 'DESCRIPTION')

  # Create directories
  dir.create(r.path, F)
  dir.create(man.path, F)

  # Write dummy description
  z = c('Package', 'Type', 'Title', 'Version', 'Date', 'Author', 'Maintainer', 'Description', 'Licence')
  writeLines(paste0(z, ': X'), desc.path)

  # Copy rscript file over to dummy package and generate rd files
  file.copy(rscript, r.path)
  suppressMessages( document(pkg.path) )

  # Copy generated Rd files to output directory
  f.in = list.files(man.path, full.names = T)
  f.out = file.path(dir.out, basename(f.in))
  for(i in 1:length(f.in)) file.copy(f.in[i], f.out[i], overwrite = T)

  # Unlink
  unlink(pkg.path, T, T)
  return(f.out)
}

# Example
rd = makeRd(rscript='foo.R', dir.out='~/Desktop')
print(rd)
# [1] "~/Desktop/myFunction.Rd"



回答4:


There is a function called parse_Rd in the tools package. You could generate the .Rd files, run parse_Rd on them, and save the output as objects in the module namespace. You would need a new search function (maybe modHelp) that finds the appropriate Rd object in the namespace and displays it using Rd2text or a different one, or a custom solution. Not sure if you can get anything other than the basic text help that Rd2text spits out, but you might.




回答5:


My answer is why don't you put the analysis in a package? This way you get all the bits and pieces of support that come with packages, including documentation (of data and any self-written functions), and having vignettes that automatically know where your data lives (and being able to list the vignettes from within R-help). You want the features of a package, without a package, that's just being needy. Instead, co-opt the package structure for an analysis, and use it to your advantage, like getting your datasets documented.

You comment that packages don't integrate Rnw files, but I rather think you are wrong. The default format for package vignettes is the Rnw or Sweave file. You can easily co-opt the vignette as a way to do the analysis report of the package.

I actually use this approach in my own analyses, and have documented it in a couple of blog posts: why, how, and comparison to project template. I've also used it in both academic analysis projects (doing it more and more, can't point to an example yet), and personal projects (e.g. https://github.com/rmflight/timmysDensity, http://rmflight.github.io/posts/2013/06/timmysDensity.html, note I was not yet using package mechanism to find data yet).

BTW, outside of putting the data in a package (which there are data only packages, Bioconductor has quite a number), I don't think there is a way to do what you are asking, outside of simply providing the raw roxygen2 tags in the .R file as was outlined above for a dataset.



来源:https://stackoverflow.com/questions/18923405/possible-to-create-rd-help-files-for-objects-not-in-a-package

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!