Going back a few months.... I also thought "it would be nice if R had built into it some way of running code in source packages possibly with degraded functionality to ease development" so building on Barry Rowlingsons start I came up with this: --------------------------- loadDir <- function(.Root = choose.dir(getwd())){ require(tools, quietly=TRUE) # for Rd2HTML .Package = basename(.Root) # package name defined by directory name while(sum(search()==.Package)>0) detach(pos=which(search()==.Package)[1]) # if already attached, detach attach(NULL, name=.Package) # attach empty environment assign(".Root", .Root, pos=.Package) # insert .Root into .Package # create reloadDir function and add into .Package reloadDir <- function(.Package) { # .Package must be character for (f in list.files(path=file.path(get(".Root", pos=.Package) , "R"), # path is .Root/R/ pattern=".R$",full.names=TRUE,recursive=TRUE,ignore.case=TRUE)) # file type = .R sys.source(f, envir=as.environment(.Package)) # source all such files into .Package invisible(.Package)} # invisibly return package name assign(x = "reloadDir", value = reloadDir, pos=.Package) # create help.'.Package' function and add into package # (because function is created here, current value of .Root is in its environment) help.Package <- function(subj=""){ # default subject is blank if (substitute(subj)=="") subj = "*" else subj <- paste("*", substitute(subj), "*", sep="") # get *subj*' as character hfile <- list.files(path=file.path(.Root, "man"), # path is .Root/man/ pattern=paste(subj,"Rd$", sep="."), # file = subj.Rd full.names=TRUE,recursive=TRUE,ignore.case=TRUE) # list of matching files if (length(hfile) != 1) # if not exactly one file, choose one hfile <- choose.files(file.path(.Root, "man", paste(subj,"Rd", sep=".")), multi=FALSE) if(hfile != "") { # if exactly one file, open it if(length(grep(".Rd$", hfile, ignore.case=TRUE)) ==1) { # if it's an Rd file, create/update html outfile <- sub("Rd$", "html", hfile, ignore.case=TRUE) # name of corresponding html Rd2HTML(hfile, sub("Rd$", "html", hfile, ignore.case=TRUE), .Package) # convert Rd to html hfile <- sub("Rd$", "html", hfile, ignore.case=TRUE)} # point to html shell.exec(shQuote(hfile))} # use operating system to open file of any type invisible(hfile)} # invisibly return help file name assign(x = paste("help", .Package, sep="."), value=help.Package, pos=.Package) # use the reloadDir function to populate the environment reloadDir(.Package) invisible(.Package) # invisibly return .Package name } --------------------------- and a corresponding .Rd file ---------------------------- \name{loadDir} \alias{reloadDir} \alias{help.Package} \title{Load an unbuilt package} \description{ Loads code from a packages \file{\\R} subdirectory and gives access to help files in the packages \file{\\man} subdirectory (translating \file{.Rd} files to \file{.html}). } \usage{ loadDir(.Root = choose.dir(getwd())) reloadDir(.Package) help.'.Package'(subj="") } \arguments{ \item{.Root}{character, scalar. The package directory (containing subdirectories \file{\\R} and \file{\\man}). \cr \code{basename(.Root)} is taken as the package name (\code{.Package}).} \item{.Package}{character, scalar. Package name to be reloaded} \item{subj}{character, scalar. File name to be searched for in \file{\\man} subdirectory} } \details{ \describe{ \item{\code{loadDir}}{ attaches an environment at the second position on the search list with name \code{basename(.Root)} (after detaching any existing entries with that name). Into that environment it sources all \file{.R} files in the \file{\\R} subdirectory, searching recursively. \cr In that environment it also places \code{.Root} and \code{.Package <-basename(.Root)} so that \code{get(".Root", pos=.Package)} can be used to retrieve the original file path. \cr In that environment it also places function \code{reloadDir} (q.v.) \cr In that environment it also places a function named '\code{help.}' followed by the name of the package (see \code{help.'.Package'})} \item{\code{reloadDir}}{ re-sources all \file{.R} files in the packages \file{\\R} subdirectory, searching recursively.} \item{\code{help.'.Package'}}{ recursively searches the packages \file{\\man} subdirectory for files named \code{subj}, initially searching for files of type \file{.Rd}. \cr If there is not exactly one such file it opens a \code{file.choose} dialog to choose a single file of any type. \cr If the single file is of type \file{.Rd} it is translated to a correspondingly named \file{.html} file in the same folder, which is opened by the operating system's file associations. \cr If the file chosen is of any other type it is opened by the operating system's file associations.} }} \value{ \describe{ \item{\code{loadDir}}{ \code{invisible(.Package)}, scalar, character} \item{\code{reloadDir}}{ \code{invisible(.Package)}, scalar, character} \item{\code{help.'.Package'}}{\code{invisible}, scalar, character; file opened (the \file{.html} file if a \file{.Rd} file was chosen)}} } \references{ %% ~put references to the literature/web site here ~ } \author{ %% ~~who you are~~ } \note{ %% ~~further notes~~ }
%% ~Make other sections like Warning with \section{Warning }{....} ~ \seealso{ %% ~~objects to See Also as \code{\link{help}}, ~~~ } \examples{ \dontrun{ loadDir() navigating to '\\\\Server02\\stats\\R\\CBRIutils' adds the package CBRIutils then reload("CBRIutils") re-sources all '\\R\\*.R' files. and help.CBRIutils(item) converts '\\man\\item.Rd' to '\\man\\item.html' which it opens in the default web browser.}} % Add one or more standard keywords, see file 'KEYWORDS' in the % R documentation directory. \keyword{ ~kwd1 } \keyword{ ~kwd2 }% __ONLY ONE__ keyword per line ----------------------------------- No guarantees or warranties of any kind, but perhaps people will find it useful. I'm sure real R experts will be able to improve it.... Regards, Keith J ============================ "Gabor Grothendieck" <ggrothendi...@gmail.com> wrote in message news:971536df0908210532k1152976al404b94a230f98...@mail.gmail.com... That's nifty. Perhaps it could look into /foo/bar/baz/lib1/*/R in which case one could simply place source packages in /foo/bar/baz/lib1 In fact it would be nice if R had built into it some way of running code in source packages possibly with degraded functionality to ease development, i.e. if one added /foo/bar/baz/lib1 to .libPaths and if xx were a source package in /foo/bar/baz/lib1 then one could use library(xx) and use xx functions directly, possibly with degraded functionality, e.g. no help files. On Fri, Aug 21, 2009 at 8:03 AM, Barry Rowlingson<b.rowling...@lancaster.ac.uk> wrote: > I'm often wanting to develop functions whilst manipulating data. But I > don't want to end up with a .RData full of functions and data. It > might be that I have functions that are re-usable but not worth > sticking in a package. > > So I've tried to come up with a paradigm for function development > that more closely follows the way Matlab and Python do it (partly > inspired by a confused Matlab convert over on R-help). > > My requirements were thus: > > * .R files as the master source for R functions > * Don't see the functions in ls() > * After editing R, make it easy to update the definitions visible to > R (unlike rebuilding and reloading a package). > > So I wrote these two in a few mins: > > loadDir <- function(dir){ > e = attach(NULL,name=dir) > assign("__path__",dir,envir=e) > reloadDir(e) > e > } > > reloadDir <- function(e){ > path = get("__path__",e) > files = > list.files(path,".R$",full.names=TRUE,recursive=TRUE,ignore.case=TRUE) > for(f in files){ > sys.source(f,envir=e) > } > } > > Usage is something like: > > lib1 = loadDir("/foo/bar/baz/lib1/") > > - it creates a new environment on the search path and sources any .R > it finds in there into that environment. If you edit anything in that > directory, just do reloadDir(lib1) and the updated definitions are > loaded. It's like python's "import foo" and "reload(foo)". > > Sourcing everything on any change seems a bit wasteful, but until R > objects have timestamps I can't think of a better way. Hmm, maybe my > environment could keep a __timestamp__ object... Okay, this is getting > less simple now... > > So anyway, have I done anything wrong or stupid here, or is it a > useful paradigm that seems so obvious someone else has probably done > it (better)? > > Barry > > ______________________________________________ > R-devel@r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel > ______________________________________________ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel