Skip to content

Lightweight 'package' idea.

2 messages · Keith Jewell

#
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:
6 days later
#
Following up on my own post of 13th,

Someone pointed out that I was MS Windows dependent. I've tried to correct 
that, but I'm in a Windows only environment so I can't check.

I've also tried to make a few other "improvements". The result is below.

No guarantees or warranties of any kind, but perhaps people will find it 
useful.

It now reasonably meets my needs so I'm not planning to do any more work  on 
it. I'm sure real R experts will be able to improve it..

Regards,

Keith J
============================
"Keith Jewell" <k.jewell at campden.co.uk> wrote in message 
news:hikudu$373$1 at ger.gmane.org...
<snip previous version>


## R code starts <<<<<<<<<<<<<<<<<<<<<<<
require(tools, quietly=TRUE) # for Rd2HTML
require(tcltk, quietly=TRUE) # for tk_choose.dir and tk_choose.files

# load an unbuilt package
loadDir <- function(Root = tk_choose.dir(getwd())){
   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.loadDir", Root, pos=Package) # insert Root into Package
   assign(".Package.loadDir", Package, pos=Package) # insert package name
# use the reloadDir function to populate the environment
   reloadDir(Package)
   invisible(Package)  # invisibly return .Package name
   }

# reload a previously loaded package (by default the most recently loaded)
reloadDir <- function(Package = .GlobalEnv) {
  Root <- get(".Root.loadDir", envir=as.environment(Package), 
mode="character") # retrieve Root
  Package <- get(".Package.loadDir", envir=as.environment(Package), 
mode="character") # and package name
  for (f in list.files(path=file.path(Root , "R"),  # path is 
.Root.loadDir/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

# display help from previously loaded package (by default most recently 
loaded)
help.loadDir <- function(subj="", Package=.GlobalEnv){    # default subject 
is blank, package is first found
   .Root <- get(".Root.loadDir", envir=as.environment(Package), 
mode="character") # get file path
   .Package <-  get(".Package.loadDir", envir=as.environment(Package), 
mode="character") # get package name
   if (substitute(subj)=="") subj = "*" else subj <- substitute(subj)  # 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 <- tk_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,
      outfile <- sub("Rd$", "html", hfile, ignore.case=TRUE)  # name of 
corresponding html
      out.mod <- file.info(outfile)[,"mtime"]  # if html absent or needs 
updating
      if (is.na(out.mod)||file.info(hfile)[,"mtime"] > out.mod) 
tools::Rd2HTML(hfile, outfile, .Package) # do it
      hfile <- outfile} # point to html
    hfile <- file.path(dirname(hfile), basename(hfile)) # needed to handle 
"//server" syntax on Windows
    shell.exec(shQuote(hfile))} # use operating system to open file of any 
type
   invisible(hfile)}    # invisibly return displayed file name
## R code ends >>>>>>>>>>>>>>>>>>>>>>>>>>

% File loadDir.Rd begins <<<<<<<<<<<<<<<<<<<<<
\name{loadDir}
\title{Load an unbuilt package}
\description{Loads code from a packages \file{\\R} subdirectory}
\usage{loadDir(Root = tk_choose.dir(getwd())}
\arguments{
 \item{Root}{character, scalar. The package directory (containing 
subdirectories \file{\\R} and \file{\\man}). The package name

(\code{.Package.loadDir}) is taken as \code{basename(Root)}.}
}
\details{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.

In that environment it also places \code{.Root.loadDir <- Root} and 
\code{.Package.loadDir <- basename(Root)} so that

\code{get(".Root.loadDir", pos=Package_name_as_character)} can be used to 
retrieve the original file path. }
\value{\code{invisible()}; scalar, character. Name of loaded package}
\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}}
% Add one or more standard keywords, see file 'KEYWORDS' in the
% R documentation directory.
\keyword{ ~kwd1 }
\keyword{ ~kwd2 }% __ONLY ONE__ keyword per line
% File loadDir.Rd ends >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

% File reloadDir.Rd begins <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
\name{reloadDir}
\title{Refresh an unbuilt package previously loaded by loadDir}
\description{Re-load code from a packages \file{\\R} subdirectory previously 
loaded by loadDir}
\usage{reloadDir(Package = .GlobalEnv)}
\arguments{\item{Package}{package name to be reloaded specified as either 
\itemize{
   \item{character, scalar. Name of entry on search list}
   \item{environment}}}}
\details{The environment specified by \code{Package} is searched for 
character variables \code{.Root.loadDir} and \code{.Package.loadDir}. Then 
all .R files in \file{.Root.loadDir\\R} (searching recursively) are sourced 
into \code{as.environment(.Package.loadDir)}

By default (\code{Package = .GlobalEnv}) the global environment is searched 
and then the search list. This means that if \code{Package} is not specified 
the package most recently loaded by loadDir is reloaded}
\value{\code{invisible()}; scalar, character. Name of reloaded package}
\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") or just reload() re-sources all '\\R\\*.R' files in 
package CBRIutils. }}
% Add one or more standard keywords, see file 'KEYWORDS' in the
% R documentation directory.
\keyword{ ~kwd1 }
\keyword{ ~kwd2 }% __ONLY ONE__ keyword per line

% File reloadDir.Rd ends >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

%File help.loadDir.Rd begins <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
\name{help.loadDir}
\title{Show help from an unbuilt package loaded by loadDir}
\description{ Gives access to help files in the packages \file{\\man} 
subdirectory, converting \file{.Rd} files to \file{.html} as appropriate.}
\usage{help.loadDir(subj="", Package=.GlobalEnv)}
\arguments{
  \item{subj}{character or name, scalar. File name to be searched for in 
\file{\\man} subdirectory}
  \item{.Package}{package name specified as either \itemize{
   \item{character, scalar. Name of entry on search list}
   \item{environment}}}}
\details{The environment specified by \code{Package} is searched for 
character variables \code{.Root.loadDir} and \code{.Package.loadDir}; these 
provide the context for the search for help files. By default (\code{Package 
= .GlobalEnv}) the global environment is searched and then the search list. 
This means that if \code{Package} is not specified the package most recently 
loaded by loadDir is searched.

The packages \file{\\man} subdirectory is recursively searched for files 
named \code{subj}, initially searching for files of type \file{.Rd}.

If there is not exactly one such file it opens a \code{tk_file.choose} 
dialog to choose a single file of any type.

If the single specified file is of type \file{.Rd} then the target file is a 
correspondingly named \file{.html} file with a later modification date. If 
this target file does not exist (no such \file{.html} file, or earlier 
modification) it is produced from the \file{.Rd} file using 
\code{tools::Rd2HTML}.

The target file is opened by the operating system's file associations.}
\value{ \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
 help.loadDir(item, "CBRIutils") or just help.loadDir(item)
    if required, converts '\\man\\item.Rd' to '\\man\\item.html'
    opens '\\man\\item.html' 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

%File help.loadDir.Rd ends 
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>