After writing the first version of the tutorial on wrapping and binding R functions on the JavaScript side of WebR, I had a few other WebR projects on my TODO list. However, I’ve been thinking about “wrapping and binding” for a long time and realized that there is a “very easy” way to make R functions available in JavaScript using javascript’s Function() constructor. I was. I’ll eventually put all of this into the GH webr-experiments repo, but see below and just view the source (as of this post, re: line #’s in the 130’s) please. before that.
Create dynamic JavaScript functions
of Function()
Constructors have many modes, one of which is to provide the entire function source and allow the function to be constructed. R folks likely know that you can do it in R (see: my {curlconverter} pkg), and it’s just as easy on the JavaScript side. Open the DevTools console and enter:
const sayHello = new Function('return function (name) { return `Hello, ${name}` }')();
Then call the function with the string value.
Only one input is required to create a dynamic R function wrapper (SUPER BASIC R functions only). Yes, I really mean you can do this:
let rbeta = await wrapRFunction("rbeta");
await rbeta(10, 1, 1, 0)
Returns results in WebR way toJs()
The function returns an R object.
{
"type": "double",
"names": null,
"values": [
0.9398577840605595,
0.42045006265859153,
0.26946718094298633,
0.3913958406551122,
0.8123499099597378,
0.49116132695862963,
0.754970193716774,
0.2952198011408607,
0.11734111483990002,
0.6263863870230043
]
}
full dress
Mr. R formals()
You can use function to get the argument list to a function, including default values. I don’t use them in this MVP version of the autowrapper, but I see no reason why they can’t be used in later iterations. Making JavaScript functions the “hard way” is “easy”.
async function formals(rFunctionName) {
let result = await globalThis.webR.evalR(`formals(${rFunctionName})`);
let output = await result.toJs();
return(Promise.resolve(output))
}
Now we need to build the function using these names. It’s an ugly little function, but it really does a few basic things:
async function wrapRFunction(rFunctionName) {
let f = await formals(rFunctionName)
let argNames = f.names.filter(argName => argName != '...');
let params = argNames.join(', ')
let env = argNames.map(name => `${name}: ${name}`).join(', ');
let fbody =
`return async function ${rFunctionName}(${params}) {
let result = await globalThis.webR.evalR(
'${rFunctionName}(${params})',
{ env: { ${env} }}
);
let output = await result.toJs();
globalThis.webR.destroy(result);
return Promise.resolve(output);
}`;
return new Function(fbody)()
}
- First, get the form of the provided function name
- Then remove the ones you can’t handle (yet!)
- Next, get the parameter names of the R function and create two objects.
- Something that creates a comma-separated list of parameter declarations (e.g.
param1, param2, param3
) - Another one that does the same thing, but
key: value
Pairs to pass as environments (see previous WebR blog post and experiments)
- Something that creates a comma-separated list of parameter declarations (e.g.
- The function body is another template string that creates standard WebR set operations for evaluating R objects and retrieving values.
the constructed function string to Function()
It’s a constructor and has an automatic JavaScript wrapper for it.
fin
this is very rustic rapper.it’s all up to the caller to specify all worth it. R has some fun features like the ability to check if a value is missing on the R side without specifying a value for a particular parameter. You can also mix named and positional parameters. ...
.
I’ll explain and/or go a little further on how best to implement it ^^, but as I continue to experiment I’ll end up using this idiom to wrap my R functions.
One more thing: I had to abandon the use of microlight
Syntax highlighter. It’s very small and fast, but I can’t handle the code I need, so I plan to update the initial webr-template to incorporate what I’m currently using: Shiki. It also contains wrapper functions.
*** This is a Security Bloggers Network syndicated blog on rud.is created by hrbrmstr. Read the original post: https://rud.is/b/2023/03/21/youre-one-javascript-function-call-away-from-using-most-webr-r-functions-in-your- webr-powered-apps-sites/