After writing the initial version of a tutorial on wrapping and binding R functions on the javascript side of WebR, I had a number of other WebR projects on the TODO list. But, I stuck around noodling on the whole “wrapping & binding” thing, and it dawned on me that there was a “pretty simple” way to make R functions available to javascript using javascript’s Function() constructor. I’ll eventually get this whole thing into the GH webr-experiments repo, but you can see below and just view-source (it’s as of the time of this post, in the 130’s re: line #’s) to check it out before that.
The Function()
constructor has many modes, one of which involves providing the whole function source and letting it build a function for you. R folks likely know you can do that in R (ref: my {curlconverter} pkg), and it’s as straightforward on the javascript side. Open up DevTools Console and enter this:
const sayHello = new Function('return function (name) { return `Hello, ${name}` }')();
then call the function with some string value.
We only need one input to create a dynamic R function wrapper (for SUPER BASIC R functions ONLY). Yes, I truly mean that you can just do this:
let rbeta = await wrapRFunction("rbeta");
await rbeta(10, 1, 1, 0)
and get back the result in the way WebR’s toJs()
function returns R objects:
{
"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
]
}
R’s formals()
function will let us get the argument list to a function, including any default values. We won’t be using them in this MVP version of the auto-wrapper, but I see no reason we couldn’t do that in a later iteration. It’s “easy” to make that a javascript function “the hard way”:
async function formals(rFunctionName) {
let result = await globalThis.webR.evalR(`formals(${rFunctionName})`);
let output = await result.toJs();
return(Promise.resolve(output))
}
Now, we just need to use those names to construct the function. This is an ugly little function, but it’s really just doing some 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)()
}
param1, param2, param3
)key: value
pairs to pass as the environment (see previous WebR blog posts and experiments)We pass the built function string to the Function()
constructor, and we have an automagic javascript wrapper for it.
This is a very naive wrapper. It’s all on the caller to specify all the values. R has some fun features, like the ability to not specify a value for a given parameter, and then check on the R side to see if it’s missing. It can also intermix named and positional parameters, and then there’s the dreaded ...
.
I’m going to noodle a bit more on how best to account and/or implement ^^, but I’ll 100% be using this idiom to wrap R functions as I keep experimenting.
One more thing: I had to abandon the use of the microlight
syntax highlighter. It’s super tiny and fast, but it doesn’t handle the code I need, so I’ll be updating my nascent webr-template to incorporate what I am using now: Shiki. The next release will also include these basic wrapper functions.
*** This is a Security Bloggers Network syndicated blog from rud.is authored by hrbrmstr. Read the original post at: 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/
As technology advances and attackers develop ever-more sophisticated tactics, CISOs and security teams face a constant battle of trying to…
You know YouTube, and you probably love YouTube. Beyond a place to share creative videos, it can be a great…
Understanding ITDR and ISPM In the cybersecurity world, two emerging identity-centric categories promise to provide... The post ITDR vs ISPM:…
Remember the old saying: “You can’t protect what you can’t see”? When I started preaching about it as part of…
Learn how to elevate your CX strategies with CIAM and data-driven insights. From seamless digital experiences to proactive customer engagement,…
Penetration testing, or pen testing for short, is a critical way to protect IT systems and sensitive data from malicious…