UNPKG

r-integration-modified

Version:

Simple portable library used to interact with pre-installed R compiler by running commands or scripts(files)

294 lines (247 loc) 8.99 kB
const fs = require("fs"); var child_process = require('child_process'); /** * get the current Operating System name * * @returns {string} the operating system short name * - "win" -> for Windows based Systems * - "lin" -> for GNU/Linux based Systems * - "mac" -> for MacOS based Systems */ getCurrentOs = () => { var processPlatform = process.platform; var currentOs; // console.log("Get os - Plataforma: "+processPlatform) if (processPlatform === "win32"){ currentOs = "win"; }else if(processPlatform === "linux" || processPlatform === "openbsd" || processPlatform === "freebsd"){ currentOs = "lin"; }else { currentOs = "lin" } return currentOs; } /** * execute a command in the OS shell (used to execute R command) * * @param {string} command the command to execute * @param {string} sessionName the name of the session (just a parameter) * @returns {{string, string}} the command execution result */ executeShellCommand = (command) => { let stdout; let stderr; try { stdout = child_process.execSync(command, {stdio : 'pipe' }).toString() // console.log(stdout);s }catch(error){ stderr = error; } return {stdout, stderr}; } /** * execute a command in the OS shell (used to execute R command) * * @param {string} command the command to execute * @param {string} sessionName the name of the session (just a parameter) * @returns {{string, string}} the command execution result */ executeShellCommand = (command, sessionName) => { let stdout; let stderr; try { stdout = child_process.execSync(command+' '+sessionName, {stdio : 'pipe'}).toString() // console.log(stdout); }catch(error){ stderr = error; } return {stdout, stderr}; } /** * checks if Rscript(R) is installed od the system and returns * the path where the binary is installed * * @returns {string} the path where the Rscript binary is installed, null otherwise */ isRscriptInstallaed = () => { var installationDir = null; // console.log("os in isInstalled: "+getCurrentOs()) switch(getCurrentOs()){ case "win": if (fs.lstatSync("C:\\Program Files\\R").isDirectory()){ // Rscript is installed, let's find the path (verison problems) installationDir = "C:\\Program Files\\R"; fs.readdirSync(installationDir).forEach(obj => { installationDir += `\\${obj}\\bin\\Rscript.exe`; }); } break; case "mac": case "lin": // the command "which" is used to find the Rscript installation dir let result = executeShellCommand("which Rscript").stdout; // console.log("resultado shell command in is installed"+result) if (result){ // Rscript is installed installationDir = result.replace("\n", ""); } break; default: break; } return installationDir; } /** * Execute in R a specific one line command * * @param {string} command the single line R command * @returns {String[]} an array containing all the results from the command execution output, null if there was an error */ executeRCommand = (command) => { let RscriptBinaryPath = isRscriptInstallaed(); let output; if (RscriptBinaryPath){ var commandToExecute = `"${RscriptBinaryPath}" -e "${command}"`; var commandResult = executeShellCommand(commandToExecute); if (commandResult.stdout){ output = commandResult.stdout; output = filterMultiline(output); }else{ console.error(`[R: compile error] ${commandResult.stderr.stderr}`); } }else{ console.error("R not found, maybe not installed.\nSee www.r-project.org"); } return output; } /** * Execute in R a specific one line command - async * * @param {string} command the single line R command * @returns {String[]} an array containing all the results from the command execution output, null if there was an error */ executeRCommandAsync = (command) => { return new Promise(function(resolve, reject) { var result = executeRCommand(command); if (result){ resolve(result); }else{ reject("ERROR: there was an error"); } }); } /** * execute in R all the commands in the file specified by the parameter fileLocation * NOTE: the function reads only variables printed to stdout by the cat() or print() function. * It is recommended to use the print() function insted of the cat() to avoid line break problem. * If you use the cat() function remember to add the newline character "\n" at the end of each cat: * for example cat(" ... \n") * * @param {string} fileLocation where the file to execute is stored * @param {string} sessionName the name of the session * @returns {String[]} an array containing all the results from the command execution output, null if there was an error */ executeRScript = (sessionName, fileLocation) => { let RscriptBinaryPath = isRscriptInstallaed(); let output; if (! fs.existsSync(fileLocation)) { //file doesn't exist console.error(`ERROR: the file "${fileLocation} doesn't exist"`); return output; } // console.log("Rpath <"+RscriptBinaryPath+">"); if (RscriptBinaryPath){ var commandToExecute = `"${RscriptBinaryPath}" "${fileLocation}"`; // console.log("Comando ejecutado: <"+commandToExecute+"> - session: "+sessionName); var commandResult = executeShellCommand(commandToExecute, sessionName); if (commandResult.stdout){ // console.log(commandResult.stdout); output = commandResult.stdout; output = filterMultiline(output); }else{ console.error(`[R: compile error] ${commandResult.stderr.stderr}`); } }else{ console.error("R not found, maybe not installed.\nSee www.r-project.org"); } return output; } /** * calls a R function with parameters and returns the result * * @param {string} fileLocation where the file containing the function is stored * @param {string} methodName the name of the method to execute * @param {String []} params a list of parameters to pass to the function * @returns {string} the execution output of the function */ callMethod = (fileLocation, methodName, params) => { let output; if (!methodName || !fileLocation || !params){ console.error("ERROR: please provide valid parameters - methodName, fileLocation and params cannot be null"); return output; } var methodSyntax = `${methodName}(`; // check if params is an array of parameters or an object if (Array.isArray(params)){ params.forEach((element) => { methodSyntax += `${element},`; }); }else{ for (const [key, value] of Object.entries(params)) { methodSyntax += `${key}=${value},`; } } var methodSyntax = methodSyntax.slice(0,-1); methodSyntax += ")"; output = executeRCommand(`source('${fileLocation}') ; print(${methodSyntax})`); return output; } /** * calls a R function with parameters and returns the result - async * * @param {string} fileLocation where the file containing the function is stored * @param {string} methodName the name of the method to execute * @param {String []} params a list of parameters to pass to the function * @returns {string} the execution output of the function */ callMethodAsync = (fileLocation, methodName, params) => { return new Promise(function(resolve, reject) { var result = callMethod(fileLocation, methodName, params); if (result) { resolve(result); }else{ reject("ERROR: there was an error"); } }) } /** * filters the multiline output from the executeRcommand and executeRScript functions * using regular expressions * * @param {string} commandResult the multiline result of RScript execution * @returns {String[]} an array containing all the results */ filterMultiline = (commandResult) => { let data; // remove last newline to avoid empty results // NOTE: windows newline is composed by \r\n, GNU/Linux and Mac OS newline is \n var currentOS = getCurrentOs(); if (currentOS == "win"){ commandResult = commandResult.replace(/\r\n$/g, ""); data = commandResult.split("\r\n"); }else{ commandResult = commandResult.replace(/\n$/g, ""); data = commandResult.split("\n"); } data.forEach((element, index) => { data[index] = element.replace(/\[.\] /g, ""); }); return data; } module.exports = { executeRCommand, executeRCommandAsync, executeRScript, callMethod, callMethodAsync }