Mercurial > scratch
changeset 17:1d62177c5c27
Added a safe js object wrapper.
author | Atul Varma <varmaa@toolness.com> |
---|---|
date | Mon, 07 Sep 2009 04:23:09 -0700 |
parents | a78570a423ea |
children | 69e5523ebdc6 |
files | pydershell/pydershell.py pydershell/test.js |
diffstat | 2 files changed, 91 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- 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], ())