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], ())
 
--- 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; }});