[Roxygen-devel] S4 implementation of @usage
Hadley Wickham
hadley at rice.edu
Thu Aug 30 22:07:37 CEST 2012
On Thu, Aug 30, 2012 at 2:12 PM, Vitalie Spinu <spinuvit at gmail.com> wrote:
> >> Hadley Wickham <hadley at rice.edu>
> >> on Thu, 30 Aug 2012 11:29:07 -0500 wrote:
>
>
> >> So roxygenize will iterate 3 times over all tags and call prepareTag on
> >> first iteration, then prepareDoc, and finally preparePackage.
>
> > That's better, but generally you only need to call preparePackage
> > once, not once for each instance of that tag.
>
> No, no ... that was precisely the main point! It should process each
> *tag* at "package level". Then process each *tag* at a "block level" and
> finally at "tag level". Here is the complete pseudo code for roxy
> package:
Hmmmm, that's an interesting approach.
I had another idea, and that was that what I was calling a GlobalTag
is originally what I was calling a Roccer - i.e. it's something that
takes a RoxyPackage as input and a RoxyPackage as output. Then it
would be a clean separation: RoxyTags act locally (at the RoxyBlock
level) and Roccers act globally (at the RoxyPackage level).
I think it makes sense to make this distinction because the process
you outline below doesn't quite fit the common Roccer (e.g. family,
inheritParams, include) scenario which typically involves two passes:
the first to built up a datastructure that stores information about
the global structure, and the second that goes through and modifies
individual RocBlocks.
I also think it seems wrong to have a generic called procPackage - why
do you have the name of the class it operates on in the generic name?
> roxygenise <- function(...., ## see below for explanation
> processors = c(procRd, procNamespace, procCollate, procMyCoolIndex)){
> roxypkg <- parse_all_files(...)
>
> roxypkg <- procPackage(roxypkg)
>
> for ( proc in processors )
> roxypkg <- proc(roxypkg)
>
> }
I was thinking of something like
roxygenise <- function(..., tags, roccers, outputs) {
pkg <- roxy_init(...) # not an S4 method because it starts the ball rolling
pkg <- roxyProcess(pkg, tags)
pkg <- roxyProcess(pkg, roccers)
roxyWrite(pkg, outputs)
}
where if not specified tags, roccers and outputs would default to
finding all classes that inherited from the appropriate base class.
> > I don't think that can work, because combining Rd commands can't work
> > at the string level, and it varies from command to command. i.e. if
> > you have multiple @keywords you do
>
> > \keyword{one}
> > \keyword{two}
> > \keyword{three}
>
> > but for multiple @params you do
>
> > \arguments{
> > \item{one}{desc one}
> > \item{two}{desc two}
> > }
>
> Good example. Let me fit it into the above paradigm.
>
> After the *block level* processing this RoxyBlock will have a tag of
> class "TagArguments" (and *no* tags of class TagParam). That is, it is a
> *standalone* entity which can be transformed by outRd into a string.
>
> In other words, TagParam's roxyProcess *block level* method creates a tag
> @arguments and removes the corresponding TagParam argument from the
> roxyBlock object.
Problems:
* calling it "block" level doesn't really make sense because it's now
(potentially) working on multiple blocks
* what happens to the objects? Does each RoxyBlock now have a list of
objects associated with it? If so, how do you associate the usage
statements with the objects. i.e. how would you resolve:
#' Topic a.
#'
#' @rdname shared
a <- function(x) {}
#' Topic b.
#'
#' @rdname shared
#' @usage b() # some comment here
b <- function(x) {}
> > If you did it with different methods (outRd, outNamespace,
> > outDescription), and the user created a new type of output (e.g.
> > outDemoIndex) how would they tell roxygen to all call the outDemoIndex
> > on every block/tag?
>
> Good point. I think your solution of passing processing functions to
> roxygenize should work best:
>
> roxygenize( ..., output = c(outRd, outCollate, outNamespace, outDemoIndex))
>
> where outRd, outCollate, outDemoIndex are function *or* generics which
> roxygenize will call on the RoxyPackage object. First procPackage
> should be called, and then all the "outputers" in turn. All of them
> should return back an object of class RoxyPackage which will be passed
> to the next processor in the chain.
>
> BTW, why "output"? I find this name confusing. This functions can have
> arbitrary side effects, or just change the content of the RoxyPackage
> object.
That's an interesting observation - the output objects have basically
the same semantics as the roccer objects. But I think there are some
important differences:
* Output objects are used solely for their side effects (writing to
disk). They return nothing.
* Roccer objects return a modified RoxyPackage and have no
side-effects. This is important for testing.
* All roccers need to be run before output can occur.
> > But output does differ between tags? Some need to output Rd, some
> > NAMESPACE, etc.
>
> BTW, is it a tag task to generate namespace? Isn't it that RoxyDoc's method
> should generate it.
It's the tags task to say where it's output should go - it shouldn't
modify the file on disk, but it should provide the output in suitable
format for writing.
> > Hmmm, but you list rd, html and text as potential output formats - I
> > definitely don't see html and text as output types. That's something
> > you might generate from the Rd files, but I don't think it's the job
> > of roxygen to generate anything that R doesn't use directly. Maybe
> > that's why we seem to be talking past each other.
>
> You are right. I am confused. And my confusion stems from the "output"
> terminology which I have hard time to get used to. Somehow it really
> doesn't sound right to call a namespace generator, an output. outCollate
> is even more weird.
I think of it as an output in the same sense that the RoxyBlocks (or
RoxyPackage) are inputs - everything else is just an intermediate
form. The user only sees what the Output objects do.
Hadley
--
Assistant Professor
Department of Statistics / Rice University
http://had.co.nz/
More information about the Roxygen-devel
mailing list