~ubuntu-branches/ubuntu/karmic/pypy/karmic

« back to all changes in this revision

Viewing changes to pypy/doc/js/using.txt

  • Committer: Bazaar Package Importer
  • Author(s): Alexandre Fayolle
  • Date: 2007-04-13 09:33:09 UTC
  • Revision ID: james.westby@ubuntu.com-20070413093309-yoojh4jcoocu2krz
Tags: upstream-1.0.0
ImportĀ upstreamĀ versionĀ 1.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
=====================================
 
2
How to use JavaScript backend of PyPy
 
3
=====================================
 
4
 
 
5
Author:
 
6
=======
 
7
 
 
8
Maciej Fijalkowski, fijal@genesilico.pl
 
9
 
 
10
Purpose:
 
11
========
 
12
 
 
13
This tutorial explains how to use `PyPy`_'s JavaScript backend. The
 
14
reader should have some previous knowledge of writing `RPython`_
 
15
programs.
 
16
 
 
17
The JavaScript backend lets you write `RPython`_ source code which gets
 
18
translated into JavaScript and executed in a browser. The resulting
 
19
JavaScript code should not depend on a browser (this is a backend
 
20
responsibility) and should integrate as much as possible with a web
 
21
server.
 
22
 
 
23
.. _`PyPy`: http://codespeak.net/pypy
 
24
.. _`RPython`: http://codespeak.net/pypy/dist/pypy/doc/coding-guide.html#restricted-python
 
25
 
 
26
Getting started:
 
27
----------------
 
28
 
 
29
You can use a JavaScript backend in many different ways. One of those is
 
30
to simply run `jscompile`_ from the 'bin' directory with a module name and a
 
31
list of functions, this makes that the listed functions get compiled. Another
 
32
way is to use the rpython2javascript function from `js.main`_ to generate
 
33
your javascript on-the-fly (e.g. when serving a web page).
 
34
 
 
35
.. _`jscompile`: http://codespeak.net/svn/pypy/dist/pypy/bin/jscompile.py
 
36
.. _`js.main`: http://codespeak.net/svn/pypy/dist/pypy/translator/js/main.py
 
37
 
 
38
Here is a simple example using `MochiKit`_'s logDebug call to show a
 
39
message::
 
40
 
 
41
  from pypy.translator.js.modules import mochikit
 
42
 
 
43
  def simple_example():
 
44
      mochikit.createLoggingPane(True)
 
45
      mochikit.logDebug("Hello")
 
46
 
 
47
Save this to a python file, e.g. simpledemo.py. Then use jscompile to
 
48
create a javascript version::
 
49
 
 
50
  $ python pypy/bin/jscompile.py simpledemo simple_example
 
51
 
 
52
Note that you specify the module as a python module which must be on the
 
53
python path.
 
54
 
 
55
When you run this you should see some information on the compilation
 
56
process scrolling past. The JavaScript is written to a file which looks
 
57
something like
 
58
`/tmp/usession-1/some_strange_function_which_will_never_be_called.js`.
 
59
 
 
60
You can call the compilation process programatically using
 
61
rpython2javascript::
 
62
 
 
63
  from pypy.translator.js.main import rpython2javascript
 
64
  
 
65
  import simpledemo
 
66
  
 
67
  js_src = rpython2javascript(simpledemo, ["simple_example"])
 
68
  print js_src
 
69
 
 
70
.. _`MochiKit`: http://www.mochikit.com/
 
71
.. _`rpython2javascript`: 
 
72
 
 
73
Easy AJAX:
 
74
----------
 
75
 
 
76
The idea is simple: Normal python method calls get rendered as
 
77
communication over `XMLHttpRequest`_ without too much user intervention.
 
78
To achieve this, you must tell PyPy that *these* particular method calls
 
79
need to be rendered in this way.
 
80
 
 
81
To achieve this, first you must subclass BasicExternal from `bltregistry`_ and
 
82
provide an instance of it to RPython code (for instance as global variable).
 
83
Then you need to set class instance's `_render_xmlhttp` to `True`, to tell the
 
84
JS backend to render it using xmlhttp communication. Because the web server
 
85
code does not need to be rpython, you have to supply some way of telling PyPy
 
86
what types can be returned out of it. This is done using the decorator
 
87
`@callback(retval = <used type>)` from `bltregistry`_. For example you may
 
88
provide::
 
89
 
 
90
  from pypy.translator.js.lib.support import callback
 
91
 
 
92
  @callback(retval = {str:str})
 
93
  def some_fun(self, some_arg = 3):
 
94
    ....
 
95
 
 
96
The decorator tells the compiler that this function will return mapping from
 
97
string to string and will take integer as an argument. You can simply specify
 
98
the arguments using keyword arguments with an example, or pass an args
 
99
dictionary to the described decorator.
 
100
 
 
101
Then you must supply a method which returns JSON data in the server
 
102
itself (for example, this is done automatically by `TurboGears`_ using
 
103
the `@expose(format='json')` decorator).
 
104
 
 
105
.. _`XMLHttpRequest`: http://en.wikipedia.org/wiki/XMLHttpRequest
 
106
.. _`TurboGears`: http://www.turbogears.org/
 
107
.. _`bltregistry`: http://codespeak.net/svn/pypy/dist/pypy/rpython/ootypesystem/bltregistry.py
 
108
 
 
109
Ajax Ping Example:
 
110
------------------
 
111
 
 
112
To create a simple javascript method which pings a server you need two parts, a server side python class which knows how to talk via XMLHttpRequest to a client side call.
 
113
 
 
114
On the server side::
 
115
 
 
116
  from pypy.rpython.ootypesystem.bltregistry import BasicExternal
 
117
  from pypy.translator.js.lib.support import callback
 
118
  
 
119
  class PingHandler(BasicExternal):
 
120
      _render_xmlhttp = True
 
121
 
 
122
      @callback(retval={str:str})
 
123
      def ping(self, ping_str="aa"):
 
124
          return dict(response="PONG: %s" % ping_str)
 
125
 
 
126
  ping_handler = PingHandler()    
 
127
 
 
128
This uses the BasicExternal class and the described decorator to let PyPy know
 
129
how to deal with the input and output of the methods. Now you can use an
 
130
instance of this class to pass to other parts of the RPython code.
 
131
 
 
132
On the client you call the ping_handler.ping method with a callback::
 
133
 
 
134
  from pypy.translator.js.modules import mochikit
 
135
  from somewhere import ping_handler
 
136
  
 
137
  def callback(response):
 
138
      mochikit.logDebug("Got response: " + response["response"])
 
139
  
 
140
  def ping():
 
141
      ping_handler.ping("PING", callback)
 
142
 
 
143
You compile this to JavaScript using jscompile or rpython2javascript and
 
144
the ping method. The resulting javascript is passed to a web browser,
 
145
while there needs to be a server which knows how to deal with a HTTP
 
146
request to `/ping` (the name is derived from the name of the method
 
147
decorated with described). The server then calls the `ping_handler.ping`
 
148
method with the data from the call and returns a JSON dictionary.
 
149
 
 
150
Integration with TurboGears or any other web framework:
 
151
-------------------------------------------------------
 
152
 
 
153
There is nothing special in this case. The JS backend can work with
 
154
virtually any web framework. In some of the examples TurboGears is used,
 
155
but just for simplifying generation of the JSON data. You can use
 
156
`simplejson`_ to generate a JSON response from any framework. The `django ping example`_ shows how to do this in `Django`_.
 
157
 
 
158
.. _`simplejson`: http://cheeseshop.python.org/pypi/simplejson
 
159
.. _`Django`: http://www.djangoproject.com/
 
160
 
 
161
Further examples:
 
162
-----------------
 
163
 
 
164
There is bub'n'bros client working in javascript available `here`_ (No
 
165
working copy on-line right now, sorry) and a simple example of JS a
 
166
`python console`_. There is also a simple `django ping example`_.
 
167
 
 
168
.. _`here`: http://codespeak.net/svn/pypy/dist/pypy/translator/js/examples/bnb/start_bnb.py
 
169
.. _`python console`: http://codespeak.net/svn/pypy/dist/pypy/translator/js/examples/pythonconsole.py
 
170
.. _`django ping example`: http://codespeak.net/svn/pypy/dist/pypy/translator/js/examples/djangoping