NAME
   Petal::CodePerl - Make Petal go faster by compiling the expressions

SYNOPSIS
     use Petal::CodePerl;

     # continue as you would normally using Petal

   or

     use Petal;
     $Petal::CodeGenerator = 'Petal::CodePerl::CodeGenerator';

 # continue as you would normally use Petal

DESCRIPTION
   This module provides a CodeGenerator for Petal that inherits almost
   everything from Petal::CodeGenerator but modifies how expressions are dealt
   with. Petal normally includes code like this

     $hash->get( "not:user" )

   in the compiled template. This means the path has to be parsed and
   interpreted at runtime. Using Petal::CodePerl, Petal will now produce this

     ! ($hash->{"user"})

   which will be much faster.

   It uses Parse::RecDescent to parse the PETALES expressions which makes it a
   bit slow to load the module but this won't matter much unless you have
   turned off caching. It won't matter at all for something like Apache's
   mod_perl.

USAGE
   You have two choices, you can replace "use Petal" with "use Petal::CodePerl"
   in all your scripts or you can do "$Petal::CodeGenerator =
   'Petal::CodePerl::CodeGenerator'". Either of these will cause Petal to use
   the expression compiling version of the CodeGenerator.

EXTRA BONUSES
   Using Parse::RecDescent makes it easier to expand the PETALES grammar. I
   have made the following enhancements.

   * alternators work as in TAL, so you can do

       petal:content="a/name|b/name|string:no name"

   * you can explicitly ask for hash, array or method in a path

     * user{name} is $hash->{"user"}->{"name"}

     * user[1] is $hash->{"user"}->[1]

     * user/method() is $hash->{"user"}->method()

       using these will make your template even faster although you need to be
       certain of your data types.

   * method arguments can be any expression for example

       user/purchase cookie{basket}

will give

       $hash->{"user"}->purchase($hash->{"cookie"}->{"basket"})

   * you can do more complex defines, like the following

       petal:define="a{b}[1] string:hello"

     which will give

       $hash->{"a"}->[1] = "hello"

   * some other stuff that I can't remember just now.

MODIFIERS
   Modifiers can now be compiled, partially compiled or work exactly as they
   did before. When compiling the expression, Petal::CodePerl will look at the
   modifier's package to figure what it supports. The order of preference is
   fully compiled, partially compiled, original style. So you can slowly
   migrate you modifiers to full compilation.

   Note that although original style still works, you cannot use any of the
   extra features of Petal::CodePerl in the path if you are using an original
   modifier. So you cannot do mymod:hash{key} until you convert your modifier
   into one of the newer styles. This is because your original style modifier
   uses Petal's parser and Petal's parser doesn't accept the {} syntax. It
   would probably be possible to fix this too but I don't think it's worth it.
   If you really need it, let me know.

 Partially Compiled
   Partially compiled modifiers are easiest, in fact they are even easier than
   Petal's original style. To partially compile a modifier, define a package
   with a "process_value()" method, and put that into %Petal::Hash::MODIFIERS
   just as you would with a normal modifier package.

   A simple example

     package Petal::Hash::Length;
     $Petal::Hash::MODIFIERS{"length:"} = "Petal::Hash::Length";

     sub process_value
     {
       my $class = shift;
       my $hash = shift;
       my $value = shift;

      return length($value);
     }

   This is a little different to the "process()" method originally used for
   modifiers. For a path like true:this/is/a/path, Petal would call "process()"
   with 2 arguments - the Petal hash and the string "this/is/a/path", it was
   then up to the method to parse that string and find the value that it
   pointed to. For "process_value()", this string has already been parsed and
   compiled, so the value defined by the path is passed in and can be used
   straight away.

 Fully Compiled
   The most efficient but a little more complicated is fully compiled. For a
   fully compiled modifier you need to have an "inline()" method which will
   return a Code::Perl object that will produce the compiled code. It's not a
   hard as it sounds. There is an easy to use Code::Perl object provided that
   makes this fairly straight-forward. Here's the example above rewritten as a
   fully compiled modifier.

     package Petal::Hash::Length;
     $Petal::Hash::MODIFIERS{"length:"} = "Petal::Hash::Length";

     use Petal::CodePerl::Expr qw( perlsprintf );

     sub inline
     {
       my $class = shift;
       my $hash_obj = shift;
       my $value_obj = shift;

       return perlsprintf("length(%s)", $value_obj);
     }

   The key points to note are that instead of getting the Petal hash and the
   value of the expression you are modifying, you get Code::Perl objects
   representing them, you then use these objects to construct another
   Code::Perl object which will eventually spit out the Perl code for your
   modifier. It's not in the example above but if your modifier wants to access
   the Petal hash please don't write '$hash->{blah}', instead write
   '%s->{blah}' and pass in the $hash_obj object. This allows for the
   possibility in the future that the hash is not called '$hash'.

   Why not just use simple strings? Because using Code::Perl objects instead of
   strings of Perl everywhere means you don't have to worry about escaping and
   wrapping things in ()s and it means that modifiers can be inside modifiers,
   deep inside complicated Petales expressions, which themselves are inside a
   modifier etc, etc.

 Tips for writing modifiers
   The easiest way to write a compiled modifier is to write a partially
   compiled one first and when you have that working perfectly, you can turn it
   into a fully compiled one. If at any stage you need to go back to using the
   partially compiled one, rather than commenting out the "inline()" method you
   can set "$Petal::CodePerl::InlineMod = 0" and no "inline()" methods routines
   will be used.

   If you are going to use the $value_obj more than once in a compiled modifier
   then you need to be a little bit careful as you only want to calculate the
   value once. Say you have a modifier that takes a string and doubles it, you
   could do this

     perlsprintf("%s.%s", $value_obj, $value_obj);

   but then double:thing/method() would be compiled to

     ($hash->{thing}->method()).($hash->{thing}->method())

   which is bad news because it's inefficient to call the method twice and
   there's no guarantee that the method will actually return the same value for
   each call. So what you should really do is

     perlsprintf("do{my $v = %s; $v.$v}", $value_obj);

   giving

     do{my $v = ($hash->{thing}->method()); $v.$v}

   which is efficient and safe.

 Original
   Any modifiers that are defined in the original Petal style, using a
   "process()" method will not be compiled and so will still work as before.

STATUS
   Petal::CodePerl is in development. There are no known bugs and Petal passes
   it's full test suite using this code generator. However there are probably
   some differences between it's grammar and Petal's current grammar. Please
   let me know if you find anything that works differently with
   Petal::CodePerl.

PROBLEMS
   Your templates may now generate "undefined value" warnings if you try to use
   an undefined value. Previously, Petal prevented many of these from
   occurring. As always, the best thing to do is not to avoid using undefined
   values in your templates. Hopefully this will be fixed shortly.

AUTHOR
   Written by Fergal Daly <[email protected]>.

COPYRIGHT
   Copyright 2003 by Fergal Daly <[email protected]>.

   This program is free software and comes with no warranty. It is distributed
   under the LGPL license

   See the file LGPL included in this distribution or
   http://www.fsf.org/licenses/licenses.html.