tvcutsem/harmony-reflect

confused about apply

Closed this issue · 3 comments

I'm trying to basically write a dsl, translating dot and bracket notation into operations on a remote database. With a bit of help i came up with;

function QueryBuilder() {
if (this instanceof QueryBuilder == false) return new QueryBuilder();
var self = this;
var fn = function () {
//ignored
};
fn.self = self;
this.proxy = new Proxy(fn, QueryBuilderProxyHandler);
this.parts = [];
return this;
}

var QueryBuilderProxyHandler = {
get: function(target, name){
target.self.parts.push(name);
return target.self.proxy;
},
apply: function(target, thisValue, args) {
target.self.parts.push({that:thisValue, args: args});
return target.self.proxy;
}
}

var thing = new QueryBuilder();

thing.proxy.test.this.out(1);

console.log(thing);

This logs the operations, but is shared and requires multiple calls.
Next I updated an old example from https://github.com/DavidBruant/HarmonyProxyLab to use the new api;
(function() {
var DeclarativeObject, declo;

DeclarativeObject = function() {
var constructorTrap, firstHandler, getTrap, middleHandler, propNames;
propNames = void 0;
getTrap = function(rec, name) {
propNames.push(name);
return Proxy(constructorTrap, middleHandler);
};
middleHandler = {
get: getTrap
};
constructorTrap = function() {
return propNames.slice();
};
firstHandler = {
get: function(rec, name) {
propNames = [];
return getTrap.apply(this, arguments);
}
};
return Proxy({}, firstHandler);
};

declo = new DeclarativeObject();

console.log(declo.a.b.c.ef(48));

console.log(declo.xo['cc'].xo.ke());

}).call(this);

This works, but as soon as i try adding the apply method all i get are TypeErrors. What is the proper way to do this?

What particular TypeError message do you get?

A Proxy only supports the apply trap if its target object is a function.

So, in your line return Proxy({},firstHandler), if you mean for this proxy to be callable, you should write return Proxy(function(){}, firstHandler).

TypeError assigned to proxy at line https://github.com/tvcutsem/harmony-reflect/blob/master/reflect.js#L2202

With either example that TypeError happens when i pass an empty function. If I do away with the middleHandler and just use firstHandler the arguments no longer come out with a TypeError in the results, but only because I'm not passing receiver (which is also a TypeError) into getTrap.

    var DeclarativeObject, declo;
    DeclarativeObject = function() {
      var constructorTrap, firstHandler, getTrap, propNames;
      propNames = void 0;
      getTrap = function() {
        propNames.push(arguments);
        return Proxy(constructorTrap, firstHandler);
      };
      constructorTrap = function() {
        return propNames.slice();
      };
      firstHandler = {
        get: function(target, name, reciever) {
          propNames = [];
          return getTrap(target, name);
        },
        apply: function(target, reciever, args) {
          propNames = [];
          return getTrap(target, args);
        }
      };
      return Proxy((function() {}), firstHandler);
    };

Is there an idiom i am missing? I've tried to look through all the examples i could find.

Rather than me trying to debug your code, I suggest you explain a bit about what you want to achieve with your DSL. Then, I could show you how I would implement it.

So far, I understand you want to be able to write:

declo = new DeclarativeObject();
console.log(declo.a.b.c.ef(48));
console.log(declo.xo['cc'].xo.ke());

What should this do?

My guess is that you want to accumulate all property names in an array until you actually try to call a property. Then, the call should do something with the accumulated property names + the arguments to the call.