[Roxygen-devel] S4 implementation of @usage
Vitalie Spinu
spinuvit at gmail.com
Thu Aug 30 21:12:23 CEST 2012
>> 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:
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)
}
### --- package processors ---
setMethod("procPackage", c("RoxyPackage"),
function(package){
...
package <- lapply(package at blocks, processBlock)
## changes by blocks
for ( block in names(package at blocks) )
package <- procPackage(package, block )
})
setMethod("procPackage", c("RoxyPackage", "RoxyBloc"),
function(package, object){
...
## changes by tags
for ( tag in names(object at tags) )
package <- procPackage( package, tag )
})
setMethod("procPackage", c("RoxyPackage", "RoxyTag"),
function(package, object) ... )
### --- block processors ---
setMethod("prodBlock", c("RoxyBloc"),
function(block){
...
block <- lapply(block at tags, procTag)
## package changes by tags
for( tag in input at tags )
block <- procBlock(block, tag)
})
setMethod("prodBlock", c("RoxyBloc", "RoxyTag"),
function(block, object) ... )
### --- tag processors ---
setMethod("prodTag", c("RoxyTag"),
function(tag) ... )
I really looks to me that roxygen will not need more than this.
After the final processing stage (at package level) each element in
"roxypkg" is a self contained entity which can be directly
Rd-ed. Really, after all this stages you should hardly ever need any
further global processing, only local access. And if really needed, you
can proceed recursively as procPackage does above.
>> Hm, I was thinking that outRd should return a string containing an Rd
>> representation of the tag and should have nothing to with the file. It's
>> a task of a special function (write_rd_file) to aggregate all the tags
>> from an roxyDoc object and write them into a file.
> 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.
Does this make sense?
Can you give some other difficult examples?
>> Interesting, but it doesn't feel natural to me. It specifies a *type* of
>> an output by the type of an *input* object which you create specifically
>> for this purpose (to indicate the type of output). That's tough ;).
> 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.
May be processors? procRd, procCollate etc. as in my pseudo code above.
> 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.
>> A conceptual note. Roxygen is a documentation generator, so the output
>> is one to one correspondence to the file format (rd, text, html
>> etc). Making an namespace or description output is unnatural and seems
>> to be an unnecessary confusion.
> I don't think that's necessary true. e.g. a potential useful
> extension could be to modify @importFrom so that it also lists the
> external functions used in the documentation - then it would need to
> output to both namespace and Rd. I think there are lots of potential
> use cases for output to multiple locations.
Ok, I am convinced now. outNamespace (or procNamespace) could also be
a recursive generic.
> 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.
Vitalie.
More information about the Roxygen-devel
mailing list