changeset 41:71ab5e977dd3

Added a context.call_function() method.
author Atul Varma <varmaa@toolness.com>
date Fri, 03 Jul 2009 20:57:58 -0700
parents 8a7abd0bb48d
children e62b1801f9af
files context.c test_pymonkey.py
diffstat 2 files changed, 86 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/context.c	Fri Jul 03 20:04:01 2009 -0700
+++ b/context.c	Fri Jul 03 20:57:58 2009 -0700
@@ -151,6 +151,46 @@
 }
 
 static PyObject *
+PYM_callFunction(PYM_JSContextObject *self, PyObject *args)
+{
+  PYM_JSObject *obj;
+  PYM_JSFunction *fun;
+  PyObject *funcArgs;
+
+  if (!PyArg_ParseTuple(args, "O!O!O!", &PYM_JSObjectType, &obj,
+                        &PYM_JSFunctionType, &fun,
+                        &PyTuple_Type, &funcArgs))
+    return NULL;
+
+  uintN argc = PyTuple_Size(funcArgs);
+  jsval argv[argc];
+  jsval *currArg = argv;
+
+  for (unsigned int i = 0; i < argc; i++) {
+    PyObject *item = PyTuple_GET_ITEM(funcArgs, i);
+    if (item == NULL ||
+        PYM_pyObjectToJsval(self->cx, item, currArg) == -1)
+      return NULL;
+    currArg++;
+  }
+
+  jsval rval;
+
+  // TODO: This assumes that a JSFunction * is actually a subclass of
+  // a JSObject *, which may or may not be regarded as an implementation
+  // detail.
+  if (!JS_CallFunction(self->cx, obj->obj, (JSFunction *) fun->base.obj,
+                       argc, argv, &rval)) {
+    // TODO: There's a pending exception on the JS context, should we
+    // do something about it?
+    PyErr_SetString(PYM_error, "Function failed");
+    return NULL;
+  }
+
+  return PYM_jsvalToPyObject(self, rval);
+}
+
+static PyObject *
 PYM_newFunction(PYM_JSContextObject *self, PyObject *args)
 {
   PyObject *callable;
@@ -175,6 +215,9 @@
    "Evaluate the given JavaScript code in the context of the given "
    "global object, using the given filename"
    "and line number information."},
+  {"call_function",
+   (PyCFunction) PYM_callFunction, METH_VARARGS,
+   "Calls a JS function."},
   {"new_function",
    (PyCFunction) PYM_newFunction, METH_VARARGS,
    "Creates a new function callable from JS."},
--- a/test_pymonkey.py	Fri Jul 03 20:04:01 2009 -0700
+++ b/test_pymonkey.py	Fri Jul 03 20:57:58 2009 -0700
@@ -153,8 +153,7 @@
         self.assertEqual(retval, u'o hai\u2026')
 
     def testEvaluateReturnsObject(self):
-        rt = pymonkey.Runtime()
-        cx = rt.new_context()
+        cx = pymonkey.Runtime().new_context()
         obj = cx.new_object()
         cx.init_standard_classes(obj)
         obj = cx.evaluate_script(obj, '({boop: 1})', '<string>', 1)
@@ -162,14 +161,54 @@
         self.assertEqual(cx.get_property(obj, u"boop"), 1)
 
     def testEvaluateReturnsFunction(self):
-        rt = pymonkey.Runtime()
-        cx = rt.new_context()
+        cx = pymonkey.Runtime().new_context()
         obj = cx.new_object()
         cx.init_standard_classes(obj)
         obj = cx.evaluate_script(obj, '(function boop() { return 1; })',
                                  '<string>', 1)
         self.assertTrue(isinstance(obj, pymonkey.Function))
 
+    def testCallFunctionRaisesErrorOnBadFuncArgs(self):
+        cx = pymonkey.Runtime().new_context()
+        obj = cx.new_object()
+        obj = cx.evaluate_script(
+            obj,
+            '(function boop(a, b) { return a+b+this.c; })',
+            '<string>', 1
+            )
+        self.assertRaises(
+            NotImplementedError,
+            cx.call_function,
+            obj, obj, (1, self)
+            )
+
+    def testCallFunctionRaisesErrorFromJS(self):
+        cx = pymonkey.Runtime().new_context()
+        obj = cx.new_object()
+        obj = cx.evaluate_script(
+            obj,
+            '(function boop(a, b) { blarg(); })',
+            '<string>', 1
+            )
+        self.assertRaises(
+            pymonkey.error,
+            cx.call_function,
+            obj, obj, (1,)
+            )
+
+    def testCallFunctionWorks(self):
+        cx = pymonkey.Runtime().new_context()
+        obj = cx.new_object()
+        thisArg = cx.new_object()
+        cx.define_property(thisArg, "c", 3)
+        cx.init_standard_classes(obj)
+        obj = cx.evaluate_script(
+            obj,
+            '(function boop(a, b) { return a+b+this.c; })',
+            '<string>', 1
+            )
+        self.assertEqual(cx.call_function(thisArg, obj, (1,2)), 6)
+
     def testEvaluateReturnsTrue(self):
         self.assertTrue(self._evaljs('true') is True)