changeset 20:d382ca63d43f

Added docs with doctests.
author Atul Varma <varmaa@toolness.com>
date Thu, 10 Sep 2009 15:44:18 -0700
parents 2dc43c316df9
children cb73bb169b67
files pydertron.py test_docs.py
diffstat 2 files changed, 79 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/pydertron.py	Thu Sep 10 15:13:33 2009 -0700
+++ b/pydertron.py	Thu Sep 10 15:44:18 2009 -0700
@@ -37,6 +37,75 @@
 """
     Pydertron is a high-level wrapper for Pydermonkey that provides convenient,
     secure object wrapping between JS and Python space.
+
+    The JsSandbox class encapsulates a JavaScript runtime, context, global
+    object, and a simple SecurableModule implementation that complies
+    with the CommonJS standard. It also provides a high-level bridge between
+    Python and JavaScript so that you don't need to deal with any of the
+    low-level details of the Pydermonkey API.
+
+    For instance, here we'll create a JsSandbox whose module root
+    points to the 'monkeys' SecurableModule compliance test over HTTP:
+
+      >>> url = ("http://interoperablejs.googlecode.com/svn/trunk/"
+      ...        "compliance/monkeys/")
+      >>> sandbox = JsSandbox(HttpFileSystem(url))
+
+    This compliance test requires a global 'sys' object that contains one
+    method, print(), that takes two arguments. First, we'll create the
+    print() function and prepare it for exposure to JS code:
+
+      >>> @jsexposed
+      ... def jsprint(message, label):
+      ...   print message, label
+
+    Note the use of the @jsexposed decorator: all this does is set the
+    function's __jsexposed__ attribute to True. This is done for security
+    purposes: only Python callables satisfying this criteria will be
+    exposed to JavaScript code, to ensure that untrusted JS can't
+    accidentally gain access to privileged Python functionality.
+
+    Creating a JS object can be done like this:
+
+      >>> system = sandbox.new_object()
+
+    We can now access and set properties on this object via either
+    item or attribute lookup, just like in JavaScript. Because 'print'
+    is a reserved word in Python, though, we'll use item lookup to set
+    the property here:
+
+      >>> system['print'] = jsprint
+
+    Now we tell the sandbox that we want the 'sys' object to be a
+    global:
+
+      >>> sandbox.set_globals(sys = system)
+
+    And finally, we execute the compliance test by running a one-line
+    script that imports the 'program' module, like so:
+
+      >>> sandbox.run_script("require('program');")
+      PASS monkeys permitted pass
+      DONE info
+      0
+
+    Note the '0' in the last line: this is the return value of
+    sandbox.run_script(), which returns 0 on success, and -1 if an
+    exception was raised. For instance, the output of bad
+    code looks like this:
+
+      >>> sandbox.run_script("(function foo() { bar(); })();",
+      ...                    stderr=sys.stdout)
+      Traceback (most recent call last):
+        File "<string>", line 1, in <module>
+        File "<string>", line 1, in foo
+      ReferenceError: bar is not defined
+      -1
+
+    Note that the traceback displayed is actually referring to
+    JavaScript code: one of Pydertron's helpful conveniences is that
+    it makes debugging JS code as much like debugging Python code as
+    possible.
 """
 
 import sys
@@ -562,11 +631,14 @@
         return self.__modules[filename]
 
     def run_script(self, contents, filename='<string>', lineno=1,
-                   callback=None, stderr=sys.stderr):
+                   callback=None, stderr=None):
         """
         Runs the given JS script, returning 0 on success, -1 on failure.
         """
 
+        if stderr is None:
+            stderr = sys.stderr
+
         retval = -1
         cx = self.cx
         try:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test_docs.py	Thu Sep 10 15:44:18 2009 -0700
@@ -0,0 +1,6 @@
+import doctest
+
+import pydertron
+
+if __name__ == '__main__':
+    doctest.testmod(pydertron, verbose=True)