write_sourceable_function: Sourceable text for functions, including character attributes

write_sourceable_functionR Documentation

Sourceable text for functions, including character attributes

Description

write_sourceable_function works like write, to produce a source()-friendly printout of a function. However, for the sake of clarity, any suitable character-vector attribute is printed as a multi-line raw string (see Quotes) wrapped in a call to docattr or to string2charvec, which will turn the string back into a character vector when the file is read back in by source. This hides a lot of ugliness, including escaped special characters and superfluous quotes. Character objects that you want attached to the function (but not inside its code) actually looks like the real thing! (They can be accessed by the function code since they live inside environment(sys.function()).) My own main use is a doc attribute for free-text documentation (which later gets turned into "Rd" format by doc2Rd when I produce my packages, but that's a detail). However, I quite often keep other text snippets too, eg "templates".

Raw strings didn't use to exist in R, so before version 2.10 of mvbutils, the alternative version write.sourceable.function (note the dots) instead relied the contortions of flatdoc and source.mvb and readLines.mvb to trick R into accepting unmodified text. None of that should be necessary now.

Obsolete: if write_sourceable_function is applied to a non-function with a "source" attribute, then just the source attribute is printed; the idea is that this could be read back by source, probably in the course of FF after fixr, to regenerate the non-function object. I don't think it's wise to rely on this....

Helpers

string2charvec, docattr, and simplest_name_generator are helper functions that you're unlikely to use yourself. For the record, though:

  • string2charvec turns a string (length-1 non-empty character vector with no attributes) into a character vector, with a new element for every newline. The first element is discarded, because it's usually just a linebreak (perhaps preceded by accidental spaces etc) inserted to let the "real" raw string start on a fresh line. string2charvec is called by docattr which facilitates keeping plain-text documentation directly with the function, as an attribute.

  • docattr is very similar, but adds an S3 class "docattr". It simplifies the code produced by write_sourceable_function for presenting the plain-text documentation. I don't recommend using docattr for anything except an attribute called "doc" that contains, yes, documenbloodytation.

  • simplest_name_generator prints an R symbol (a "name") in a way that could appear on the LHS of <symbol> <- 0. If the name is simple, with no funny characters in it, then it's not quoted and is left alone. If it contains mildly strange characters that would cause the unquoted version to not parse, then it's quoted. If it contains characters that would break simple quotes (for example, quotes or backticks!) then it's wrapped in a bullet-proof raw string. "Only the paranoid survive"...

  • cat_strings_rawly outputs (using cat) a character vector as a single raw string wrapped in a call to docattr (if its argument has class "docattr") or otherwise string2charvec. Thus, source will break up the raw string back into a separate element for each newline. (cat_strings_rawly is probably a bad name for this function, since it actually takes a character vector as input, not a string...). It calls cat directly, so you already need to have directed output to wherever you want, eg via sink.

Limitations

Some exotic language elements simply cannot be represented in sourceable text: for example, a "hard-coded" environment. A file will still be produced, but it won't work with source. There's no solution to such cases. For example:

  f <- function( e=.GlobalEnv) environmentName( e)
  formals( f)$e <- new.env()
  tf <- tempfile()
  write_sourceable_function( f, tf)
  source( tf)
  # ... complains about e = <environment>

Usage

write_sourceable_function( x, con, append=FALSE,
    print.name=FALSE, xn=NULL, prefix_package=TRUE, ...)
string2charvec( string)
simplest_name_generator( x)
cat_strings_rawly( x, prefix_package=TRUE)

Arguments

x

function or other object, or the name thereof, that is to be written by write_sourceable_function. If x is not a function, then it must have an attribute "source". For the helper functions, x is either a string itself (length-1 character vector), or for cat_strings_rawly a character vector.

con

a connection or filename

append

if "con" is not already open, should it be appended to rather than overwritten?

print.name

should output start with NAME <-, where NAME is deduced from x? Note that NAME will be processed by simplest_name_generator to make sure everything goes thru source nicely.

xn

(string) can set this to be the name of the function if print.name is TRUE

...

ignored, but allows calls that use old write.sourceable.function arguments

string

a string (length-1 character vector), presumably a "raw string" though R doesn't care.

prefix_package

Whether to prefix the call to docattr or string2charvec with mvbutils::. Should always be TRUE except when producing the R source code for mvbutils itself with KeepPlaintextDoco=YES in the "DESCRIPTION" file, since in that case those two functions won't be available as exports when the R source file is sourced.

Details

If x is unquoted and print.name=TRUE, the name is obtained from deparse( substitute( x)). If x is a character string, the name is x itself and the function printed is get(x).

The criteria for deciding whether to raw-string-ify an attribute are:

  • it must be mode character

  • it must have length>1 (otherwise there's little point)

  • it must not have any attributes, except perhaps an S3 class (e.g. no names, no dim)

  • it must not contain newline characters (since they would be confused with newlines inserted between elements).

Iff the attribute has S3 class "docattr", then cat_strings_rawly will wrap it in a call to mvbutils::docattr (which will mean it doesn't get full printed out at the console); otherwise, it will be wrapped in a call to mvbutils::string2charvec.

Examples

# This is from the examples for 'flatdoc'. It's there to illustrate plain-text documentation,
# but you can see the call to 'docattr' in the middle.
flubbo <- structure( function( x){
  ## A comment
  x+1
}
,doc=docattr( r"-{
flubbo       not-yet-in-a-package
'flubbo' is a function! And here is some informal doco for it. Whoop-de-doo!
Thanks to raw strings, which are wonderful (see 'Quotes' for extreeeeemly brief doco):
Look at 'flatdoc' examples for more on raw strings.
}-"))
## Don't run
# Infuriating CRAN check (ie that Don't run is ignored--- WTF?!) means I have to wrap this:
if( FALSE && is_very_annoying( "CRAN")){
  write_sourceable_function( write_sourceable_function, "wsf.r")
  # To dump all functions and their documentation in a workspace into a single sourceable file:
  cat( "", file="allfuns.r")
  sapply( find.funs(), write_sourceable_function,
      con="allfuns.r", append=TRUE, print.name=TRUE)
  # A non-function. Probably don't do this!
    scrunge <- c( 1:7, 11)
    attr( scrunge, "source") <- c( "# Another way:", "c( 1:4, c( 5:7, 11))")
    scrunge # [1] 1 2 3 4 5 6 7 11
    write_sourceable_function( scrunge, stdout()) # source
    fixr( scrunge) # source
} # if F
## End don't run

mvbutils documentation built on May 25, 2026, 5:09 p.m.