Re: [Rd] Lightweight 'package' idea.

From: Keith Jewell <k.jewell_at_campden.co.uk>
Date: Wed, 13 Jan 2010 17:03:54 +0000

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" <ggrothendieck_at_gmail.com> wrote in message news:971536df0908210532k1152976al404b94a230f9858e_at_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.rowlingson_at_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_at_r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>

______________________________________________
R-devel_at_r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel Received on Wed 13 Jan 2010 - 18:18:56 GMT

Archive maintained by Robert King, hosted by the discipline of statistics at the University of Newcastle, Australia.
Archive generated by hypermail 2.2.0, at Wed 20 Jan 2010 - 19:30:47 GMT.

Mailing list information is available at https://stat.ethz.ch/mailman/listinfo/r-devel. Please read the posting guide before posting to the list.

list of date sections of archive