You are not logged in Log in Join
You are here: Home » Members » andym » wiki » SampleApp » wikipage_view

Log in
Name

Password

 
 
FrontPage »

SampleApp

Perl Scripts let you leverage the huge body of existing Perl modules from Zope.

By way of example, here's a small sample app which uses Perl Scripts.  I'll
assume you know at least a little Perl and a little DTML.

To use the sample app, you'll need to install Perl Script capability into your
Zope instance.  Information about doing this is available elsewhere in
this wiki, but it basically consists of installing Perl and Python, 
downloading "pyperl" and "zoperl", compiling them both, and following the
directions which come with them to get them up and going.

You'll also need to install the Finance::Quote module available via CPAN
(http://www.cpan.org) into your Perl installation.

If you're running Zope 2.3 beta 3 or less, to appease the Zope security gods, you may also need to
change the top of the file named lib/python/AccessControl/SimpleObjectPolicies.py
in your Zope installation to look like this:

import Record
try:
    import perl
    perlref = perl.get_ref("%")
except:
    perlref = {}
# Allow access to unprotected attributes
Record.Record.__allow_access_to_unprotected_subobjects__=1

ContainerAssertions={
    type(()): 1,
    type([]): 1,
    type({}): 1,
    type(perlref): 1,
    }

.. from what it is currently in your Zope install.

What we're going to do is to build an application which allows us to get
stock quotes using the Perl Finance::Quote module.

Once you've got Perl Scripts installed, create a dtml method named "stockinfo":
 
 <dtml-var standard_html_header>
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
 <html>
 <head>
 	<title>Untitled</title>
 </head>
 <body>
 <h1>Get Stock Information</h1>
 <table border cellpadding=5 cellspacing=1>
 <tr>
        <td valign=top align=center>
 	   <form action="&dtml-URL;">
 	   <select name="exchange">
              <dtml-let a="exchanges()">
              <dtml-in "a.keys()">
                  <option value="<dtml-var sequence-item>" <dtml-if "REQUEST.get('exchange') == _['sequence-item']">SELECTED</dtml-if>>
                  <dtml-var "a[_['sequence-item']]">
              </dtml-in>
              </dtml-let>
 	   </select>
 	</td>
        <td align=center>
            <dtml-let symbols="REQUEST.get('symbols', [])">
            <textarea name="symbols:lines" rows=4 cols=10><dtml-in symbols><dtml-var sequence-item>
</dtml-in></textarea>
	    </dtml-let>
        </td>
	<td valign=top align=center>
	   <input type="submit" value="Go">
	</td>
 </tr>
 <tr>
	<td>
	Select an exchange.
	</td>
	<td>
	Enter ticker symbols one per line
	</td>
	<td>
	Then click "Go".
	</td>
 </tr>
 </table>
 <hr>
 <dtml-if "REQUEST.has_key('symbols')">
 <dtml-let ref="finance(REQUEST['exchange'], REQUEST['symbols'])">
   <h2>For exchange <dtml-var "REQUEST['exchange']"></h2>
   <table border>
   <th>Symbol</th><th>Price</th>
   <dtml-in "ref.keys()">
   <tr>
   <td>
      <dtml-var sequence-item>
   </td>
   <td>
      <dtml-var "ref[_['sequence-item']]">
   </td>
   </tr>
   </dtml-in>
   </table>
 </dtml-let>
 <dtml-else>
 </dtml-if>
 </form>
 </body>
 </html>
 <dtml-var standard_html_footer>

Then create a file on your hard disk named "finance.pm" in your Zope's
Extensions/ZopeExt directory (if the "ZopeExt" directory doesn't exist, create
it).

The contents of the "finance.pm" file should be::

 package ZopeExt::finance;
 use Finance::Quote;

 sub finance {
     my ($exchange, $symbols) = @_;
     my @symbols = @$symbols;
     my $quoter = Finance::Quote->new;
     my %info = $quoter->fetch($exchange, @symbols);
     my %retn;
     foreach $symbol (@symbols) {
       if ($info{$symbol,"success"} and ($symbol)) {
         $retn{$symbol} = $info{$symbol, "price"};
         next;
       }
       $retn{$symbol} = "unknown";
       }
     \%retn;  
     }
 1;

Then create a regular Perl Script (not an *unrestricted* Perl Script)
by visiting the Zope management interface and choosing "Script (Perl)"
from the "Add" dropdown.  Give it the following body and arguments:

 id: exchanges
 title: < leave blank >
 arguments: <leave blank >
 code:

 my %exchanges = (
     "australia"      => "Australan Stock Exchange",
     "dwsfunds"       => "Deutsche Bank Gruppe funds",
     "fidelity"       => "Fidelity Investments",
     "tiaacref"       => "TIAA-CREF",
     "troweprice"     => "T. Rowe Price",
     "europe"         => "European Markets",
     "canada"         => "Canadian Markets",
     "usa"            => "USA Markets",
     "nyse"           => "New York Stock Exchange",
     "nasdaq"         => "NASDAQ",
     "uk_unit_trusts" => "UK Unit Trusts",
     "vanguard"       => "Vanguard Investments",
     "vwd"            => "Vereinigte Wirtschaftsdienste GmbH"
 );
 return \%exchanges;

Then create an *unrestricted* Perl Script which points to the "finance" subroutine
defined in the "finance.pm" module.  To do so, choose "Script (Perl,
unrestricted)" from the Zope add list.  Provide the following arguments to it:

id: finance
function name: finance
function arguments: exchange, symbols
perl module: ZopeExt::finance

Now view the "stockinfo" DTML Method.  You should be able to get stock
quotes for your favorite stocks from many different exchanges.  This
functionality is provided almost entirely by the Finance::Quote module.

What's happening is this:

Accessing Restricted Perl Script Data From DTML...

The stockinfo DTML method is calling the (restricted) Perl Script "exchanges"
in order to get a Perl hash (dictionary, associative array) of stock exchange
identifiers to human-readable names.  The stockinfo logic iterates over the
keys of this hash, populating a select list with stock exchange ids and
human-readable names.  Something to note here is that the "exchanges" script
returns a *reference* to a Perl hash, not the hash itself.  Non-scalar data
that is returned from a Perl Script is returned as a string representation,
which isn't so useful in this context, so we return a reference.  Returning
a reference to a nonscalar allows DTML to treat a Perl hash much like a
Python dictionary and a Perl array much like a Python list.
For more info see the pyperl documentation.

Accessing Unrestricted Perl Script Data From DTML...

The stockinfo DTML method also calls in to the "finances" Perl Script (which
is unrestricted) in order to get data returned from the Finance::Quote
module.  The snippet from "stockinfo" that makes this happen is:

 <dtml-if "REQUEST.has_key('symbols')">
 <dtml-let ref="finance(REQUEST['exchange'], REQUEST['symbols'])">
   <h2>For exchange <dtml-var "REQUEST['exchange']"></h2>
   <table border>
   <th>Symbol</th><th>Price</th>
   <dtml-in "ref.keys()">
   <tr>
   <td>
      <dtml-var sequence-item>
   </td>
   <td>
      <dtml-var "ref[_['sequence-item']]">
   </td>
   </tr>
   </dtml-in>
   </table>
 </dtml-let>
 <dtml-else>
 </dtml-if>

The "finances" subroutine is called with the arguments "exchange" and
"symbols".

The "finances" subroutine does a funny dance to get the
Python list which represents "symbols" into a native Perl type in the line:

     my @symbols = @$symbols;

Under the hood, this converts the Python list "symbols" into a Perl array.
The rest is straightforward Perl.  We also return a reference at the end
of "finances" for the reasons explained above.

Hope this helps,

- Chris McDonough