Conventions, policies, and background

There are many ways to write R code for a certain task, and there are even more ways to generate this R code from JS. How exactly you do it, is left up to you. Still there are a number of considerations that you should follow, and background information you should understand.

Understanding the local() environment

More often than not you will have to create one or more temporary R objects in the code generated by your plugin. Normally, you do not want those to be placed in the user's workspace, potentially even overwriting user variables. Hence, all plugin generated code is run in a local() environment (see R help page on function local()). This means, all variables you create are temporary and will not be saved permanently.

If the user explicitly asks for a variable to be saved, you will need to assign to that object using .GlobalEnv$objectname <- value. In general, do not use the <<- operator. It will not necessarily assign in .GlobalEnv.

One important pitfall is using eval(). Here, you need to note that eval will by default use the current environment for evaluation, i.e. the local one. This will work well most of the times, but not always. Thus, if you need to use eval(), you will probably want to specify the envir parameter: eval(..., envir=globalenv()).

Code formatting

The most important thing is for your generated R code to work, but it should be also easy to read. Therefore, please also keep an eye on formatting. Some considerations:

Normal top-level R statements should be left aligned.

Statements in a lower block should be indented with one tab (see example below).

If you do very complex calculations, add a comment here and there, esp. to mark up logical sections. Note that there is a dedicated function comment() for inserting translatable comments in the generated code.

For example, generated code might look like this. The same code without indentation or comments would be pretty hard to read, despite its modest complexity:

# first determine the wobble and rotation
my.wobble <- wobble (x, y)
my.rotation <- wobble.rotation (my.wobble, z)

# boggling method needs to be chosen according to rotation
if (my.rotation > wobble.rotation.limit (x)) {
	method <- "foo"
	result <- boggle.foo (my.wobble, my.rotation)
} else {
	method <- "bar"
	result <- boggle.bar (my.wobble, my.rotation)
}
		

Dealing with complex options

Many plugins can do more than one thing. For instance, the Descriptive Statistics plugin can compute mean, range, sum, product, median, length, etc. However, typically the user will only choose to have some of those calculations performed. In this case, please try to keep the generated code as simple as possible. It should only contain portions relevant to the options that are actually selected. To achieve this, here is an example of a common design patterns as you would use it (in JS; here, "domean", "domedian", and "dosd" would be <checkbox> elements):

function calculate () {
	echo ('x <- <' + getString ("x") + ')\n');
	echo ('results <- list ()\n');

	if (getBoolean ("domean.state")) echo ("results$" + i18n ("Mean value") + " <- mean (x)\n");
	if (getBoolean ("domedian.state")) echo ("results$" + i18n ("Median") + " <- median (x)\n");
	if (getBoolean ("dosd.state")) echo ("results$" + i18n ("Standard deviation") + " <- sd (x)\n");
	//...
}