Call function from string in nodejs
Write your functions in a separate file and export them and use with name reference of that to call them, Like
// functions.js
var funcOne = function(){
console.log('function ONE called')
}
module.exports={
// name_exported : internal_name
funcOne : funcOne
}
Use function defined in functions.js in index.js :
// index.js
var methods = require('./functions.js') // path to functions.js
methods['funcOne']()
OUTPUT :
> node index.js
> function ONE called
It works just fine
global.foo = function foo () {
console.log("foo was called");
}
process.stdin.on("data", function(input) {
// don't forget to call .trim() to remove the \n
var fn = input.toString().trim();
// function exists
if (fn in global && typeof global[fn] === "function") {
global[fn]();
}
// function does not exist
else {
console.log("could not find " + fn + " function");
}
});
process.stdin.resume();
Output
foo
foo was called
bar
could not find bar function
Whether or not this is a good idea... well, that's an entirely different discussion.
EDIT — ≈18 months later... Yeah, it's a horrible idea to call a global function like that.
In saying that, here's one way you could approach the problem in a much better way. Below we're going to build a little REPL (read-eval-print loop). In order to understand it better, I'll break it down into a couple parts.
First, we want to make sure our REPL waits for the user to press enter before we try running their command. To do that, we'll create a transform stream that waits for a "\n"
character before sending a line
down the pipe
The code below is written using ES6. If you're having trouble finding a compatible environment to run the code, I suggest you check out babel.
// line-unitizer.js
import {Transform} from 'stream';
class LineUnitizer extends Transform {
constructor(delimiter="\n") {
super();
this.buffer = "";
this.delimiter = delimiter;
}
_transform(chunk, enc, done) {
this.buffer += chunk.toString();
var lines = this.buffer.split(this.delimiter);
this.buffer = lines.pop();
lines.forEach(line => this.push(line));
done();
}
}
export default LineUnitizer;
Don't get too hung up on LineUnitizer
if you're new to stream processing and it doesn't quite make sense. This kind of stream transform is extremely common. The general idea is this: once we pipe process.stdin
into a receiving stream, process.stdin
will be emitting data every time the user presses a key. However, our Repl
(implemented below) can't act on a command until the user has finished typing the command. LineUnitizer
is the part that waits for the user to press enter (which inserts a "\n"
into the stream) and then signals to _transform
that the command is ready to be sent to repl
for processing!
Let's look at Repl
now
// repl.js
import {Writable} from 'stream';
class Repl extends Writable {
_parse(line) {
var [cmd, ...args] = line.split(/\s+/);
return {cmd, args};
}
_write(line, enc, done) {
var {cmd, args} = this._parse(line.toString());
this.emit(cmd, args);
done();
}
}
export default Repl;
Well hey, that was easy! What does it do tho? Each time repl
receives a line, it emits an event with some args. Here's a visual way to see how a command is parsed
The user enters emit event args
-------------------------------------------------------------
add 1 2 3 "add" ["1", "2", "3"]
hens chocobo cucco "hens" ["chocobo", "cucco"]
yay "yay" []
Ok, now let's wire everything together to see it work
// start.js
import LineUnitizer from './line-unitizer';
import Repl from './repl';
process.stdin
.pipe(new LineUnitizer())
.pipe(
(new Repl())
.on("add", function(args) {
var sum = args.map(Number).reduce((a,b) => a+b, 0);
console.log("add result: %d", sum);
})
.on("shout", function(args) {
var allcaps = args.map(s => s.toUpperCase()).join(" ");
console.log(allcaps);
})
.on("exit", function(args) {
console.log("kthxbai!");
process.exit();
}));
Run it
$ node start.js
Output
Lines prefixed with
>
are user input. The>
will not actually be visible in your terminal.
> add 1 2 3
add result: 6
> shout I can see it in your face!
I CAN SEE IT IN YOUR FACE!
> exit
kthxbai!
If you think that's awesome, we're not even done yet. The benefits of writing our program this way is that we can act on the commands regardless of how they arrive at our program.
Consider this commands.txt
file
add 100 200
shout streams are the bee's knees
exit
Now run it like this
$ cat commands.txt | node start.js
Output
300
STREAMS ARE THE BEE'S KNEES
kthxbai!
Ok, so that's pretty fricken great. Now consider that the commands could come from anywhere. Could be a database event, something across the network, a CRON job, etc. Because everything is nicely separated, we could easily adapt this program to accept a variety of inputs with ease.