# HG changeset patch # User Atul Varma # Date 1252322589 25200 # Node ID 1d62177c5c2706296a4c2e46de5f36a727cac7c6 # Parent a78570a423ea5f6af554e256c69fb5c0130e12db Added a safe js object wrapper. diff -r a78570a423ea -r 1d62177c5c27 pydershell/pydershell.py --- a/pydershell/pydershell.py Mon Sep 07 00:33:56 2009 -0700 +++ b/pydershell/pydershell.py Mon Sep 07 04:23:09 2009 -0700 @@ -66,6 +66,89 @@ BaseException.__init__(self) self.exc_info = sys.exc_info() +class SafeJsObjectWrapper(object): + """ + Securely wraps a JS object to behave like any normal Python object. + """ + + __slots__ = ['_jsobject', '_cx', '_this'] + + def __init__(self, cx, jsobject, this): + if not isinstance(jsobject, pydermonkey.Object): + raise TypeError("Cannot wrap '%s' object" % + type(jsobject).__name__) + object.__setattr__(self, '_jsobject', jsobject) + object.__setattr__(self, '_cx', cx) + object.__setattr__(self, '_this', this) + + def __wrap_to_python(self, value): + if isinstance(value, pydermonkey.Object): + return SafeJsObjectWrapper(self._cx, value, self._jsobject) + else: + return value + + def __wrap_to_js(self, value): + # TODO: Add support for wrapping non-primitive python objects. + return value + + def __call__(self, *args): + cx = self._cx + jsobject = self._jsobject + this = self._this + + if isinstance(jsobject, pydermonkey.Function): + obj = cx.call_function(this, jsobject, + self.__wrap_to_js(args)) + return self.__wrap_to_python(obj) + else: + raise TypeError("'%s' object is not callable" % + type(jsobject).__name__) + + def __eq__(self, other): + if isinstance(other, SafeJsObjectWrapper): + return self._jsobject == other._jsobject + else: + return False + + def __str__(self): + return self.toString() + + def __unicode__(self): + return self.toString() + + def __setitem__(self, item, value): + self.__setattr__(item, value) + + def __setattr__(self, name, value): + cx = self._cx + jsobject = self._jsobject + + cx.define_property(jsobject, name, + self.__wrap_to_js(value)) + + def __getitem__(self, item): + return self.__getattr__(item) + + def __getattr__(self, name): + cx = self._cx + jsobject = self._jsobject + + return self.__wrap_to_python(cx.get_property(jsobject, name)) + + def __contains__(self, item): + cx = self._cx + jsobject = self._jsobject + + return cx.has_property(jsobject, item) + + def __iter__(self): + cx = self._cx + jsobject = self._jsobject + + properties = cx.enumerate(jsobject) + for property in properties: + yield property + def safejsfunc(cx, on_obj, name=None): """ Exposes the decorated Python function on the given JS object. @@ -140,6 +223,11 @@ cx.init_standard_classes(globalobj) @safejsfunc(cx, globalobj) + def bar(cx, this, args): + obj = SafeJsObjectWrapper(cx, args[0], this) + print obj.bar() + + @safejsfunc(cx, globalobj) def foo(cx, this, args): return cx.call_function(this, args[0], ()) diff -r a78570a423ea -r 1d62177c5c27 pydershell/test.js --- a/pydershell/test.js Mon Sep 07 00:33:56 2009 -0700 +++ b/pydershell/test.js Mon Sep 07 04:23:09 2009 -0700 @@ -10,4 +10,6 @@ } } -foo(blah); +//foo(blah); + +bar({blarg: "aweg", bar: function() { return this.blarg; }});