Skip to content

Instantly share code, notes, and snippets.

@freakboy3742
Created March 7, 2018 01:20
Show Gist options
  • Select an option

  • Save freakboy3742/d98c513e92a8badcb632d38581ae54b1 to your computer and use it in GitHub Desktop.

Select an option

Save freakboy3742/d98c513e92a8badcb632d38581ae54b1 to your computer and use it in GitHub Desktop.
Desperately Seeking JSusan...
class PyType {
constructor(name, bases, dict) {
this.name = name
this.bases = bases
this.dict = dict
}
__str__() {
return this.name
}
__call__(...args) {
console.log(`Create new <${this.name}> with ${args.length} args...`)
return `New <${this.name}> object created with ${args.length} args`
}
__getattribute__(attr) {
return this[attr]
}
__setattr__(attr, value) {
this[attr] = value
}
}
let descriptor = {
get: function(obj, attr) {
if (attr === Symbol.toPrimitive) {
console.log('get as str', obj)
console.log('__str__', obj.__str__)
return obj.__str__.bind(obj)
} else {
console.log(`Getting ${attr}`)
return obj.__getattribute__(attr);
}
},
set: function(obj, attr, value) {
console.log(`Setting ${attr} to ${value}`)
obj.__setattr__(attr, value);
return true;
},
apply: function(obj, that, args) {
console.log(`Calling object with ${args.length} arguments`)
return obj.__call__.apply(that, args)
},
construct: function(obj, args) {
console.log(`Constructing object with ${args.length} arguments`)
throw "Python objects are constructed by invocation"
}
}
export function tester() {
let mt = new PyType('MyType', ['base1', 'base2'], {'attr1': 1, 'attr2': 2})
let MyType = new Proxy(mt, descriptor)
console.log('mt = ', MyType)
console.log('mt.name = ', MyType.name)
console.log('mt.bases = ', MyType.bases)
console.log('mt.dict = ', MyType.dict)
console.log('mt.__str__() = ', MyType.__str__())
console.log('mt.__call__() = ', MyType.__call__())
// This line fails:
// Uncaught TypeError: MyType is not a function
// at Object.tester (test.js:69)
let obj = MyType(1, 2, 3, 4)
}
@swenson

swenson commented Mar 7, 2018

Copy link
Copy Markdown

(I got some of this info from https://stackoverflow.com/a/40878674 )

@raphamorim

Copy link
Copy Markdown

This is the simplest solution with the least amount of functionality, but it's guaranteed to work almost anywhere. Create a new function and clone an object's properties onto it.

class PyType {
    constructor(name, bases, dict) {
        this.name = name
        this.bases = bases
        this.dict = dict
    }

    __str__() {
        return this.name
    }

    __call__(...args) {
        console.log(`Create new <${this.name}> with ${args.length} args...`)
        return `New <${this.name}> object created with ${args.length} args`
    }

    __getattribute__(attr) {
        return this[attr]
    }

    __setattr__(attr, value) {
        this[attr] = value
    }

}

let descriptor = {
    get: function(obj, attr) {
        if (attr === Symbol.toPrimitive) {
            console.log('get as str', obj)
            console.log('__str__', obj.__str__)
            return obj.__str__.bind(obj)
        } else {
            console.log(`Getting ${attr}`)
            return obj.__getattribute__(attr);
        }
    },
    set: function(obj, attr, value) {
        console.log(`Setting ${attr} to ${value}`)
        obj.__setattr__(attr, value);
        return true;
    },
    apply: function(obj, that, args) {
        console.log(`Calling object with ${args.length} arguments`)
        return obj.__call__.apply(that, args)
    },
    construct: function(obj, args) {
        console.log(`Constructing object with ${args.length} arguments`)
        throw "Python objects are constructed by invocation"
    }
}

const ObjectCallable_handler = {
    get: function get(self, key) {
        if (self.hasOwnProperty(key)) {
            return self[key];
        } else { return self.__inherit__[key]; }
    },
    apply: function apply(self, thisValue, args) {
        return (self.__call__ || self.__inherit__.__call__).apply(self, args);
    }
};

function ObjectCallable(cls) {
    var p = new Proxy(function() { }, ObjectCallable_handler);
    p.__inherit__ = cls;
    return p;
}

export function tester() {
    let mt = new PyType('MyType', ['base1', 'base2'], {'attr1': 1, 'attr2': 2})
    let MyType = new Proxy(ObjectCallable(mt), descriptor)

    console.log('mt = ', MyType)
    console.log('mt.name = ', MyType.name)
    console.log('mt.bases = ', MyType.bases)
    console.log('mt.dict = ', MyType.dict)
    console.log('mt.__str__() = ', MyType.__str__())
    console.log('mt.__call__() = ', MyType.__call__())

    // This line fails:
    // Uncaught TypeError: MyType is not a function
    //   at Object.tester (test.js:69)
    let obj = MyType(1, 2, 3, 4)
}

@raphamorim

raphamorim commented Mar 7, 2018 •

Copy link
Copy Markdown

However, this approach will only answer your first question about callable classes. Probably you will get another error, but now with name reference. So here's a example about valid approach for deal with it:

var proxyAccount = new Proxy (ObjectCallable(new PyType('MyType', ['base1', 'base2'], {'attr1': 1, 'attr2': 2})) , {
    get: function (target, name, receiver) {
        console.log('get called for field: ', name);
        if(!target.hasOwnProperty(name))
        {
           // do I have to store `name` into global variable, to reference it in `apply trap?
           // methodName = name
            return new Proxy(target[name],this);
        }
        return Reflect.get(target, name, receiver);
    },
    apply: (target,receiver,args) => {
        console.log('methodName: ',  'I need methodName here. how do I get  -withdraw- here?');
        return Reflect.apply(target, receiver, args);
    }
});

proxyAccount(); 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment