Sophie

Sophie

distrib > Fedora > 14 > x86_64 > by-pkgid > 0c336499d2cce64b5aa2e42184f43f9e > files > 1209

cherokee-1.2.101-1.fc14.x86_64.rpm

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
                "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
    <meta http-equiv="Content-Language" content="en-us" />
    <meta name="ROBOTS" content="ALL" />
    <meta http-equiv="imagetoolbar" content="no" />
    <meta name="MSSmartTagsPreventParsing" content="true" />
    <meta name="Keywords" content="cherokee web server httpd http" />
    <meta name="Description" content="Cherokee is a flexible, very fast, lightweight Web server. It is implemented entirely in C, and has no dependencies beyond a standard C library. It is embeddable and extensible with plug-ins. It supports on-the-fly configuration by reading files or strings, TLS/SSL (via GNUTLS or OpenSSL), virtual hosts, authentication, cache friendly features, PHP, custom error management, and much more." />
    <link href="media/css/cherokee_doc.css" rel="stylesheet" type="text/css" media="all" />
  </head>
<body>
<h2 id="_a_href_index_html_index_a_8594_a_href_dev_html_development_info_a_8594_cherokee_tool_kit"><a href="index.html">Index</a> &#8594; <a href="dev.html">Development info</a> &#8594; Cherokee Tool Kit</h2>
<div class="sectionbody">
</div>
<h2 id="_introduction_to_ctk">Introduction to CTK</h2>
<div class="sectionbody">
<div class="paragraph"><p>CTK, the Cherokee ToolKit, is a toolkit originally implemented to
develop Cherokee-admin in Python. It aims to deliver all the fanciness
of modern web right to the hands of Python developers.</p></div>
<div class="paragraph"><p>CTK was developed to allow a fast development pace for Cherokee-Admin,
while providing a modern &amp; feature-rich web interface that fulfilled
two essential requirements:</p></div>
<div class="olist arabic"><ol class="arabic">
<li>
<p>
Having a maintainable code-base
</p>
</li>
<li>
<p>
Lowering the entry barrier to encourage participation in the development of Cherokee.
</p>
</li>
</ol></div>
<div class="paragraph"><p>CTK was developed with Cherokee-Admin in mind, but it is not confined
to Cherokee, and in fact some of its widgets aren&#8217;t even used in
Cherokee-Admin. It is currently used in every Cherokee release since
1.0, and is also used by some other third party applications.</p></div>
<h3 id="_rationale">Rationale</h3><div style="clear:left"></div>
<div class="paragraph"><p>The design of CTK makes developing rich web-applications easy and fun
once you&#8217;ve understood the rationale behind it. Of course, some
complex tasks might require a bit of extra effort, but overall you&#8217;ll
be gladly surprised by the ease of development.</p></div>
<div class="paragraph"><p>Everything is a widget in CTK. Everything, from the web page itself to
any web element you might want to use, is a widget. You just have to
instantiate a top-level widget (a container), add widgets to it, and
let CTK take care of the rest.  This includes asynchronous transfers,
submitting and validating forms in the background, event binding to
refresh the render of specific sections, and many other goodies you
would expect in a modern web application. Just pick a widget from the
extensive Widget Hierearchy provided by CTK, and append it to your
container.</p></div>
<div class="paragraph"><p>Some of the things provided by CTK:</p></div>
<div class="olist arabic"><ol class="arabic">
<li>
<p>
URL driven render
</p>
</li>
<li>
<p>
URLs mapped to functions or classes
</p>
</li>
<li>
<p>
Render as response (a page, or content)
</p>
</li>
<li>
<p>
Complete requests as results of a render, no partial results support
  (sent as render)
</p>
</li>
<li>
<p>
Widget Hierarchy inspired in desktop-app toolkits like GTK+ or QT.
</p>
</li>
</ol></div>
<div class="paragraph"><p>What make CTK particularly interesting is that everything can be
written and maintained in Python.</p></div>
<h3 id="_overview">Overview</h3><div style="clear:left"></div>
<div class="paragraph"><p>CTK will communicate your application with the web server through the
well known SCGI protocol, so you&#8217;ll just have to setup an information
source in Cherokee and access it through the SCGI handler to get
started.</p></div>
<h4 id="_ctk_run">CTK-run</h4>
<div class="paragraph"><p>You can quickly try out your CTK applications by using the provided
CTK-run command. It will launch an instance of Cherokee listening to
port 9091, and it will be set to communicate with any SCGI application
running on port 8000.</p></div>
<div class="paragraph"><p>The syntax of CTK-run is pretty straight forward:</p></div>
<div class="listingblock">
<div class="content">
<pre><tt> python CTK-run [-d /path/to/CTK] &lt;file.py&gt;</tt></pre>
</div></div>
<h4 id="_basic_ctk_app">Basic CTK app</h4>
<div class="paragraph"><p>The skeleton of a CTK application is also fairly simple:</p></div>
<div class="olist arabic"><ol class="arabic">
<li>
<p>
Import CTK into your app.
</p>
</li>
<li>
<p>
Publish some URLs and define what functions or classes should take
  care of rendering such URLs, handle submissions, etc.
</p>
</li>
<li>
<p>
Add widgets
</p>
</li>
<li>
<p>
Define a custom commit function if needed
</p>
</li>
<li>
<p>
Specify a port in which CTK must be launched and let it run.
</p>
</li>
</ol></div>
<h3 id="_simple_examples">Simple examples</h3><div style="clear:left"></div>
<div class="paragraph"><p>The examples listed here will set port 8000 for SCGI, so all of them
can be run quickly using CTK-run. Just copy and paste the scripts, and
launch them with CTK-run. You will be able to check the output by
accessing <a href="http://localhost:9091">http://localhost:9091</a> on your web-browser.</p></div>
<div class="paragraph"><p>Besides the basic examples listed here, you can take a look at
CTK/tests to see some very basic examples using CTK. Those have been
written as quick tests for some of the basic widgets. Any of them can
be run using the provided CTK-run command.</p></div>
<h4 id="_hello_world">Hello World</h4>
<div class="paragraph"><p>The one example that can never be missing: Hello World!</p></div>
<div class="listingblock">
<div class="content">
<pre><tt># hello_world.py
import CTK

class default:
    def __call__ (self):
        page = CTK.Page()
        page += CTK.RawHTML('Hello World!')
        return page.Render()

CTK.publish ('', default)
CTK.run (port=8000)</tt></pre>
</div></div>
<div class="paragraph"><p>As you can see, CTK is mapping the URL <tt>''</tt> to the default
class. Ordinarily you would map a specific URL, but since this
application is so simple we are using an empty URL. CTK processes
these mappings by matching the incoming requests against a list of
published paths. Those can be specified as regular expressions, so the
mechanism is very flexible. If a specific match is not found, every
request will fall through to the entry for <tt>''</tt>. In this case it means
that any request to <a href="http://localhost:9091">http://localhost:9091</a> will yield a “Hello World”
as response.</p></div>
<h4 id="_hello_button">Hello Button</h4>
<div class="paragraph"><p>This one goes a little further, and binds click events to actions.</p></div>
<div class="listingblock">
<div class="content">
<pre><tt># hello_button.py
import CTK

class default:
    def __call__ (self):
        text = CTK.RawHTML ('Hello World!')
        box  = CTK.Box (text)

        hide = CTK.Button ('Hide')
        hide.bind('click', box.JS_to_hide())

        show = CTK.Button ('Show')
        show.bind('click', box.JS_to_show())

        page = CTK.Page()
        page += box
        page += hide
        page += show

        return page.Render()

CTK.publish ('', default)
CTK.run (port=8000)</tt></pre>
</div></div>
<div class="paragraph"><p>It is embedding the HTML contents into a CTK.Box, which is in reality
nothing more than the container that we will be showing and hiding on
demand. All CTK Widgets provide some basic methods, such as:</p></div>
<div class="olist arabic"><ol class="arabic">
<li>
<p>
bind: used to bind events and actions
</p>
</li>
<li>
<p>
JS_to_hide: that renders Javascript code tohide the element
</p>
</li>
<li>
<p>
JS_to_show: that renders Javascript code to show the element
</p>
</li>
<li>
<p>
JS_to_trigger: that renders Javascript code to trigger a specific
  event (it accepts parameters and selectors other than the default
  one -the unique ID of the widget-).
</p>
</li>
</ol></div>
<h4 id="_form_submission">Form submission</h4>
<div class="paragraph"><p>With CTK, validating, submitting, and processing forms is very
simple. Take a look at the following script.</p></div>
<div class="listingblock">
<div class="content">
<pre><tt># form.py
import CTK
import time

def validate_number (value):
    try:
        if int(value) in range(10):
            return value
    except:
        raise ValueError('Not valid')
    raise ValueError('Not in range')

VALIDATIONS = [
    ('number', validate_number),
]

def apply():
    if CTK.post['show_delay']:
        time.sleep(2)
    return {'ret': 'ok'}

class default:
    def __call__ (self):
        submit = CTK.Submitter ('/apply')
        table  = CTK.PropsTable()
        table.Add ('Delay 2secs',
                   CTK.Checkbox ({'name': 'show_delay', 'checked': 0}),
                   'Delay response for 2 seconds to notice the submitting status')
        table.Add ('Number',
                   CTK.TextField({'name': 'number'}),
                   'Pick a number [0-9]')
        submit += table

        page  = CTK.Page ()
        page += submit

        return page.Render()

CTK.publish ('', default)
CTK.publish ('^/apply$', apply, method='POST', validation=VALIDATIONS)
CTK.run (port=8000)</tt></pre>
</div></div>
<div class="paragraph"><p>Notice the line where the <em>^/apply$</em> URL is published. As you can see,
there is a difference when comapared to the others shown until
now. Most remarkably, it specifies the method to be POST, since it
will be mapping a custom commit function to that URL, and it also
provides a list of validations to be applied when performing such
POST.</p></div>
<div class="paragraph"><p>If specified, the validations will be checked even before the data
flow reaches the specified function, <tt>apply</tt> in this case. The logic
behind this is to raise an exception if validation tests are not
passed, and CTK will display the error right beneath the field that
fails to pass the tests.</p></div>
<div class="paragraph"><p>Also notice how the form is built. A Submitter object is instanced,
that acts as a container for a variety of form elements (comboboxes,
input fields, textareas, radio buttons, checkboxes, etc). Each of
these is a widget itself. A submission button could have been added to
the form, but we&#8217;ve left it out to keep it as simple as possible.</p></div>
<div class="paragraph"><p>As soon as the form can be submitted, all the data is sent using
POST. Notice that this does not necessarily imply that every field in
the form has been given a value. In fact, in the previous example,
altering the value of any of the widgets will trigger the submission
of the whole form. Every widget can be instanced with a set of
specific parameters, so it is not complicated to specify which fields
require being filled, which ones are optional, etc. Among those
parameters, <em>class</em> is undoubtedly the most important one, since it
allows you to pass <em>class</em> attributes directly to the HTML
elements. Some of these actually influence how the submission is
performed.</p></div>
<div class="tableblock">
<table rules="all"
width="100%"
frame="border"
cellspacing="0" cellpadding="4">
<caption class="title">Important class attributes</caption>
<col width="25%" />
<col width="75%" />
<tbody>
<tr>
<td align="left" valign="top"><p class="table">required</p></td>
<td align="left" valign="top"><p class="table">Every widget marked as required needs to be filled up
            before the submission can be performed</p></td>
</tr>
<tr>
<td align="left" valign="top"><p class="table">noauto</p></td>
<td align="left" valign="top"><p class="table">Altering the value for the widget does not trigger the
            submission of the form, as it would do by default.</p></td>
</tr>
</tbody>
</table>
</div>
<div class="paragraph"><p>Even when a SubmitterButton widget is present, all required fields
must be present before any data is actually sent. Clicking on the
button will do nothing unless all these are filled up.</p></div>
<div class="paragraph"><p>Each widget has a specific syntax, so better the API in detail or dig
into the code.</p></div>
<h4 id="_dialogs">Dialogs</h4>
<div class="paragraph"><p>Using dialogs with CTK is also easy. In this example we will instance
two dialogs, one of which is opened on-load, and the other one bound
to the click event of a CTK.Button.</p></div>
<div class="listingblock">
<div class="content">
<pre><tt># dialog.py
import CTK


class content_box (CTK.Box):
    def __init__ (self):
        CTK.Box.__init__(self)
        self += CTK.RawHTML ('&lt;h1&gt;About&lt;/h1&gt;')

        note  = CTK.Notice()
        note += CTK.RawHTML ('&lt;p&gt;CTK dialogs are highly customizable.&lt;/p&gt;')

        self += CTK.RawHTML ('&lt;p&gt;By default, CTK dialogs are:&lt;/p&gt;')
        defaults = CTK.List()
        defaults.Add (CTK.RawHTML('Modal'))
        defaults.Add (CTK.RawHTML('Not resizable'))
        defaults.Add (CTK.RawHTML('Not opened automatically'))
        defaults.Add (CTK.RawHTML('Not draggabale'))
        defaults.Add (CTK.RawHTML('Rendered on the center of the screen'))
        self += CTK.Indenter (defaults)

class default:
    def __call__ (self):
        opened  = CTK.Dialog ({'title': _('Automatically opened dialog'), 'width': 450, 'autoOpen': True})
        opened += content_box()
        opened.AddButton (_('Close'), "close")

        closed  = CTK.Dialog ({'title': _('Manually opened dialog'), 'width': 450})
        closed += content_box()
        closed.AddButton (_('Close'), "close")
        button = CTK.Button('Open dialog')
        button.bind('click', closed.JS_to_show())

        page  = CTK.Page ()
        page += opened
        page += closed
        page += button

        return page.Render()

CTK.publish ('', default)
CTK.run (port=8000)</tt></pre>
</div></div>
<h4 id="_tabs">Tabs</h4>
<div class="paragraph"><p>As was mentioned before, you can add widgets to other widgets. Thanks
to this approach, using tabs is also intuitive. Just instantiate a
CTK.Tab object, and add as many tabs as you want. The contents of each
tab has to be a widget: an Image, a Box, etc.</p></div>
<div class="listingblock">
<div class="content">
<pre><tt># tabs.py
import CTK

IMAGES = ['on', 'off', 'loading', 'tick', 'del']

class default:
    def __call__ (self):
        page = CTK.Page()

        tabs = CTK.Tab()
        for img in IMAGES:
            tabs.Add (img.capitalize(), CTK.ImageStock(img))

        page += tabs
        return page.Render()

CTK.publish ('', default)
CTK.run (port=8000)</tt></pre>
</div></div>
<h4 id="_refreshable_elements">Refreshable elements</h4>
<div class="paragraph"><p>The CTK.Refreshable class allows the creation of objects that can be
rendered asynchronously in response to a given event. Normally every
CTK widget has a unique identifier that is generated automatically,
but since the contents of a Refreshable have to be written into a
specific container that you&#8217;ll need to know in advance, this class
demands an explicit <em>id</em> be given on instantiation.</p></div>
<div class="listingblock">
<div class="content">
<pre><tt># refresh.py
import CTK
import time

class Default:
    class Content (CTK.Box):
        def __init__ (self, refresh):
            CTK.Box.__init__ (self)
            button = CTK.Button ('Refresh')
            button.bind ('click', refresh.JS_to_refresh())

            self += CTK.RawHTML('&lt;p&gt;Rendered on %s.&lt;/p&gt;' %(time.ctime()))
            self += button

    def __call__ (self):
        r1 = CTK.Refreshable ({'id': 'r1'})
        r1.register (lambda: self.Content(r1).Render())

        r2 = CTK.Refreshable ({'id': 'r2'})
        r2.register (lambda: self.Content(r2).Render())

        page  = CTK.Page ()
        page += r1
        page += r2

        return page.Render()

CTK.publish ('', Default)
CTK.run (port=8000)</tt></pre>
</div></div>
<div class="paragraph"><p>So, what does it do? It instantiates two CTK.Refreshable elements,
each with its unique identifier, and each one is refreshed when the
button is clicked. Easy, right?</p></div>
<div class="paragraph"><p>Remember that identifiers must be unique for every DOM
element/node. Should you mistakenly provide the same identifier for
both Refreshable objects, clicking on anyone of the buttons would
probably update the same element (and only one of them).</p></div>
<h3 id="_advanced_examples">Advanced examples</h3><div style="clear:left"></div>
<div class="paragraph"><p>If the basic examples don&#8217;t seem enough for you, there are lots of
more complex examples at your disposal. The best way to dive into CTK
is reading the code of Cherokee-Admin, and checking the CTK code
itself from time to time. Most of CTK has been written to provide the
specific needs of Cherokee Admin, so most likely you&#8217;ll find examples
as complex as you want that will help you fully understand how things
are working.</p></div>
<h3 id="_some_considerations">Some considerations</h3><div style="clear:left"></div>
<div class="paragraph"><p>So far you&#8217;ve seen some very basic examples. Before you begin hacking
on Cherokee-Admin, you&#8217;ll probably need to know some more about other
CTK elements.</p></div>
<h4 id="_ctk_post">CTK.post</h4>
<div class="paragraph"><p>This is used to access every element submitted using the POST
method. You&#8217;ve seen how it works on some of the previous examples. The
most useful methods in this class involve accessing reading and
popping values and keys. Elements can also be accessed using
dictionary-like notation. In the examples above, both:</p></div>
<div class="listingblock">
<div class="content">
<pre><tt>CTK.post['show_delay']</tt></pre>
</div></div>
<div class="paragraph"><p>and</p></div>
<div class="listingblock">
<div class="content">
<pre><tt>CTK.get_val('show_delay')</tt></pre>
</div></div>
<div class="paragraph"><p>Would return the same value, although the second appearance lets you
specify a default value as optional argument.</p></div>
<h4 id="_ctk_cfg">CTK.cfg</h4>
<div class="paragraph"><p>The class CTK.Config seamlessly handles the Cherokee configuration
tree. With it you can read and write a configuration file, parse and
serialize the configuration tree, clone configuration elements, and
manipulate branches ands leaves at will.</p></div>
<div class="paragraph"><p>The class is instanced as soon as Cherokee-Admin loads, and it can be
accessed as CTK.cfg. Just like before, it can be accessed and
manipulated using its many methods, and dictionary-like syntax can
also be used. With little doubt, this is the most manipulated object
throughout the whole code-base. Study CTK.Config if you are interested
in the full details.</p></div>
<div class="paragraph"><p>The most used methods are the ones involving setting and gettings
entry values. This is done just like in a dictionary. Among the other
methods available, probably the most used are:</p></div>
<div class="olist arabic"><ol class="arabic">
<li>
<p>
pop: to pop elements from the configuration tree.
</p>
</li>
<li>
<p>
keys: access the list of subnodes of any given node
</p>
</li>
<li>
<p>
get_val: retrieve the value of a configuration
  key. CTK.cfg.get_val(<em>server!timeout</em>) would be equivalent to
  CTK.cfg[<em>server!timeout</em>]
</p>
</li>
<li>
<p>
apply_chunk: to apply a configuration chunk directly to the
  configuration tree. This is a lifesaver when dealing with wizards,
  for examples, where you have tamplates as large chunks that only
  require some customization.
</p>
</li>
<li>
<p>
normalize: also very useful when dealing with wizards, since it can
  be used to renumber configuration entries. It is recommended to
  always normalize the configuration after playing around with it.
</p>
</li>
<li>
<p>
get_next_entry_prefix: provided a path, it will yield the next entry
  in the sequence of currenlty existing elements.This is very used
  when having to add any new element to the configuration, such as a
  new rule, a new virtual server, a new information source, and so on.
</p>
</li>
</ol></div>
<h4 id="_the_tmp_configuration_node">The tmp configuration node</h4>
<div class="paragraph"><p>Whenever the configuration three is altered, a flag is set indicating
the configuration tree has been changed. In turn, the <em>Save</em> button on
the admin interface becomes clickable, and using it will dump the
configuration tree to the configuration file that is being used at the
moment. There is one exception to this rule: the <strong>tmp</strong> configuration
node. Everything hanging from that branch is ignored when loading and
saving the configuration tree. It is used extensively as a temporary
repository. For example, on multi-stage wizards, it is used to store
the intermediate values gathered along all the different stages.</p></div>
<div class="paragraph"><p>Every configuration entry hanging from this node can be set and
retrieved exactly like the rest, but nothing will be saved to disk.</p></div>
<h4 id="_config_related_widgets">Config related widgets</h4>
<div class="paragraph"><p>You have been some Widgets being used in the example about form
submission. What you haven&#8217;t yet seen are all the variants specially
conceived to interact with CTK.Config. Many widgets have a variant
with a name ending in <strong>Cfg</strong>.</p></div>
<div class="paragraph"><p>Normally, you would process form submissions in custom commit
functions that would extract the required data from CTK.post and
inject it into CTK.cfg. The <strong>Cfg</strong> widgets are bound to the
configuration tree itself, so the rest of the code can be simplified
by avoiding the need of duplicating logic for such repetitive tasks.</p></div>
<div class="paragraph"><p>These widgets are instantiated with a configuration entry, and their
values are retrieved from the configuration tree itself. Once
submitted, one call to the method CTK.cfg_apply_post will set the new
values in the configuration tree as well.</p></div>
<h4 id="_http_responses">HTTP responses</h4>
<div class="paragraph"><p>Complex things can be achieved through the use of custom HTTP
responses. Of course, CTK provides a convenient way to do this.</p></div>
<div class="paragraph"><p>For example, a custom commit function could decide that the user has
to be redirected to another location. Making it return a
CTK.HTTP_Redir response would redirect to whatever location was
specified.</p></div>
<div class="paragraph"><p>Any response can be issued, just dig into the class and try it out if
needed.</p></div>
<h4 id="_ctk_url_request">CTK.url_request</h4>
<div class="paragraph"><p>Sometimes passing parameters through the URL migh come in handy. Just
access the CTK.url_request property and you&#8217;ll be able to parse to
your heart&#8217;s contempt.</p></div>
<h4 id="_ctk_cookie">CTK.cookie</h4>
<div class="paragraph"><p>Basic cookie support is provided through this object.  Cookies can be
set an read using the well known bracket-syntax:</p></div>
<div class="listingblock">
<div class="content">
<pre><tt>CTK.cookie['user'] = 'my_user'</tt></pre>
</div></div>
<div class="paragraph"><p>and</p></div>
<div class="listingblock">
<div class="content">
<pre><tt>user = CTK.cookie['user']</tt></pre>
</div></div>
<h3 id="_final_notes">Final notes</h3><div style="clear:left"></div>
<div class="paragraph"><p>Although CTK was conceived as a tool to help in the development of
Cherokee-Admin, it has grown in complexity and flexibility to the
point that it is an Open Source project all by itself. Detailing every
last piece of it is far beyond the scope of this introductory
tutorial.</p></div>
<div class="paragraph"><p>You can easily achieve relatively complex tasks using CTK with very
little effort. Review the API, check the provided examples, and dig
into Cherokee-Admin. As you can see, once you get the hang of it it is
really not complicated, and you can always turn to our development
mailing list for help.</p></div>
</div>
<div id="footer">
<div id="footer-text">
</div>
</div>
</body>
</html>