pixelpax
pixelpax

Reputation: 1517

Execute within an environment in javascript

I would like to allow my user to execute a series of functions while applying a certain object as the environment. For example, I have some object which contains data and operations.

environment = {

member1 = 0

operation1 = -> 
    member1 += 1
}

I want to allow the user to send commands into the environment as if it were the global object, without referencing it with this

i.e.

environment.evaluate("operation1()")

It would also be nice if I could create operations outside the environment, but allow them to be sent into this hypothetical 'evaluate' function.

Is it possible to build something like this? Does it have native javascript support?

Upvotes: 0

Views: 248

Answers (1)

synthet1c
synthet1c

Reputation: 6282

changing now. just realized what you needed

this calls a member of the private methods object.

// create a closure which is your environment using the module pattern
var environment = (function() {

  // local variables to the environment
  var member1 = 0;

  // public interface
  var methods = {
    operation: function(num) {
      return member1 += (num || 1);
    },
    evaluate: function evaluate(name) {
      var rest = Array.prototype.slice.call(arguments, 1);
      // call your function by name passing in the rest of the arguments
      return typeof methods[name] === 'function' && methods[name].apply(this, rest);
    }
  }

  return methods;
})();

console.assert(typeof member1 === 'undefined', 'member1 is out of scope');
console.assert((environment.evaluate("operation", 2) === 2), 'member1 === 2');
console.log(environment.evaluate("operation", 2));
<script src="http://codepen.io/synthet1c/pen/WrQapG.js"></script>

old answer

I just noticed you requested coffee script. This is javascript you could use. I have never used coffee script but it shouldn't be hard to change to coffee and coffee compiles to js anyway.

The key is having a closure around the entire environment and using eval to modify the internal state. You are really better off having specific getters and setters to limit the api to just the things you allow, otherwise the end user has access to modify anything in the scope, so nothing is private.

// create a closure which is your environment using the module pattern
var environment = (function() {

  // local variables to the environment
  var member1 = 0;
 
  // return the public interface
  return {
    // this function evals the code in the context of the environment 
    evaluate: function evaluate(operation) {
      // eval a closure so anything you put in there is run and returned to the outer environment
      return eval('(function(){ return ' + operation + '})()');
    }
  }
})();

console.assert( typeof member1 === 'undefined', 'is member1 out of scope' );
console.log( environment.evaluate("++member1") );

<!-- begin snippet: js hide: false -->
<script src="http://codepen.io/synthet1c/pen/WrQapG.js"></script>

var es6environment = (function() {

  let member1 = 0;

  const methods = {
    operation: (num = 1) => member += num,
    evaluate: (name, ...rest) => typeof methods[name] === 'function' && methods[name].apply(this, rest);
  }

  return methods;
})();
<script src="http://codepen.io/synthet1c/pen/WrQapG.js"></script>

Upvotes: 3

Related Questions