Dav Clark
Dav Clark

Reputation: 1470

Is there a sensible way to do something like docstrings in R?

This is not just a coding style question. If you know python (and I think also Ruby has something like this), you can have a docstring in a function, such that you can readily get that string by issuing a "help" command. e.g.:

def something(t=None):
    '''Do something, perhaps to t

    t : a thing
        You may not want to do this
    '''
    if t is not None:
        return t ** 2
    else:
        return 'Or maybe not'

Then help(something) returns the following:

Help on function something in module __main__:

something(t=None)
    Do something, perhaps to t

    t : a thing
        You may not want to do this

The way things work in R, you can get the full text of the defined code snippet, so you could see comments (including those at the beginning of the function), but that can be a lot of scrolling and visual filtering. Is there any better way?

Upvotes: 37

Views: 16790

Answers (6)

Dason
Dason

Reputation: 61983

I recently wrote a package to do just this task. The docstring package allows one to write their documentation as roxygen style comments within the function they are documenting. For example one could do

square <- function(x){
    #' Square a number

    return(x^2)
}

and then to view the documentation either call the docstring function

docstring(square)

or use the built in ? support and do

?square

The comments can either be a single chunk like shown above or fully roxygen style to take advantage of some of the keywords provided

square <- function(x){

    #' Square a number
    #'
    #' Calculates the square of the input
    #'
    #' @param x the input to be squared

    return(x^2)
}

This is on CRAN now: https://cran.r-project.org/package=docstring so you can just install using

install.packages("docstring")

or if you want the latest development version you can install from github:

library(devtools)
install_github("dasonk/docstring")

Upvotes: 26

Dirk is no longer here
Dirk is no longer here

Reputation: 368579

Sort-of -- look at the roxygen2 package on CRAN (vignette here). You write a declarative header, and among other things a help page is created for you when you 'roxygen-ize' your sources.

It may not be the easiest package to use, see here on SO for questions pertaining to it as well as its mailing list. But it probably is the closest match.

Upvotes: 11

user2443147
user2443147

Reputation:

RStudio helps you to create documentation quite easily. See their documentation for more information.

Upvotes: 9

Dav Clark
Dav Clark

Reputation: 1470

I had another idea as I'm finally wrapping my head around the fact that "R is a (very poor) LISP". Specifically, you can get access to the source code (usually) using the deparse command. So, this function would be a start towards defining your own custom source-code parsing help function:

docstr <- function(my.fun) {
    # Comments are not retained
    # So, we can put extra stuff here we don't want
    # our docstr users to see
    'This is a docstring that will be printed with extra whitespace and quotes'
    orig.code.ish <- deparse(my.fun)

    print(orig.code.ish[3])
}

docstr(docstr)

The above illustrates that deparse really does deparse, and is different from what you'd print at the REPL prompt if you typed docstr: quotes are changed to (default) double-quotes, opening curly brace gets moved to the second line, and blank lines (including comments) are removed. This actually helps a lot if you want to design a robust function. Would be trivial to look for e.g., opening and closing quotes down through the first line that doesn't start with a quote.

Another way to do it would be to get the list of call objects that make up the body list with body(docstr). The string would be in body(docstr)[[2]]. I have to admit that I'm a bit out of my depth here, as I don't fully understand the return value of body, and don't know where to find documentation! In particular, note that body(docstr)[2] returns an object of type and mode 'call'.

This latter approach seems much more LISPy. I'd love to hear other's thoughts on the general idea, or have pointers to actual language reference materials for this!

Upvotes: 4

chl
chl

Reputation: 29447

You can add any attributes you like to R objects, including function. So something like

describe <- function(obj) attr(obj, "help")
foo <- function(t=NULL) ifelse(!is.null(t), t^2, "Or maybe not")
attr(foo, "help") <- "Here is the help message"

produces more or less the desired output

> foo(2)
[1] 4
> foo()
[1] "Or maybe not"
> describe(foo)
[1] "Here is the help message"

Upvotes: 12

jverzani
jverzani

Reputation: 5700

The new reference class system has something very similar to docstrings for documenting methods of a class. Here is an example:

Something <- setRefClass("Something",
                         methods=list(
                           something=function(t=NULL) {
                             "Do something, perhaps to t
    t : a thing
        You may not want to do this
"
                             if(!is.null(t))
                               t^2
                             else
                               "Or maybe not"
                           }
                           ))


a <- Something$new()
a$something(2)
a$something()

Something$help("something") ## to see help page

Upvotes: 3

Related Questions