User Questions
CGI::Application
2 direct replies — Read more / Contribute
by rob_au
on Jul 27, 2001 at 14:37

     
    CGI::Application
     

     
    Item description : Framework for building reusable web-applications in an object-orientated and extensible fashion
    Review Synopsis : An excellent and well-thought out module implementing powerful and downright easy methods to write and build CGI-based applications.
     

     
    Why use CGI::Application?
     

     
    The CGI::Application module implements this object-orientated framework within which to build your application by creating a super-class within which specific 'run-modes' can be defined. Each run-mode can be correlated to a particular stage of the HTML/CGI user interface. Furthermore, the CGI::Application module implements methods to address the CGI.pm and HTML::Template modules, facilitating powerful methods by which to build extensible and portable web applications - It is obvious that the module author, Jesse Erlbaum (jesse at vm dot com), has put a lot of work into the development and writing of this module.
     
    This module allows you to do away with ugly code through the combination of CGI.pm, HTML::Template and methods provided by CGI::Application to implement persistent variables across execution states.
     
    (Part of the reason too as to my personal usage of this module is its integration with my preferred templating framework, HTML::Template - Different web application frameworks were reviewed by princepawn at Web Application Frameworks and their Templating Engines with a Comparative Study of Template and HTML::Template)
     

     
    Why avoid CGI::Application?
     

     
    There seems to be few reasons why to avoid using the CGI::Application module - Usage may not be necessary if persistence and state methods are implemented with other frameworks such as Apache::Session, HTML::Mason or HTML::Embperl.
     

     
    How to use CGI::Application?
     

     
    The documentation for the CGI::Application module is excellent and covers the building of a (theoretical) database search application. In short, this module promotes the building of applications as self-styled modules based on the CGI::Application framework - The end script (application) consists of an instance script and a module package.
     
    An example instance script may look like this:
     
    #!/usr/bin/perl # Use our self-styled application module built on the CGI::Applicati +on framework # use self; # Create constructor for our application module (self->new()) and ex +ecute this module in the desired run mode (self->run()) - The desired + run mode is set via the value of a CGI parameter specified by the mo +de_param() method of this module (see self-styled CGI::Application mo +dule package). # my ($application) = self->new(); $application->run(); exit 0;

     
    The corresponding module (self) based on the CGI::Application framework may look like this:
     
    package self; sub setup { my ($self) = shift; # Set the CGI parameter from which the run-mode of the applicati +on is derived to be 'stage' - This method allows you to set your own +run-mode specifier, passed to your CGI script via hidden HTML form in +put tags # $self->mode_param('stage'); # Set the matched run-mode / subroutine functions to determine w +hich function should be executed for a given run-mode - This method i +s that which allows reusable code to be easily implemented for separa +te run-mode. # # In this example, the subroutines 'display_form' and 'display_r +esults' have been specified to run for run-modes '1' and '2' respecti +vely. The subroutines can be defined as either a hard reference to t +he run-mode method or the name of the run-mode method to be called. # $self->run_modes({ '1' => \&display_form, '2' => 'display_results', }); # Set the mode which should be run in the first instance of the +script, where no run-mode may be specified by a passed CGI variable - + By default, this mode is called 'start', which too must be reference +d to a subroutine via the run_modes() method. # $self->start_mode('1'); }; 1;

     
    This is a very basic example of the totality of module framework required to implement the CGI::Application framework - The example above is lacking the referenced subroutines display_form and display_results but provides a clear example of HOW the module framework works.
     
    Additional methods within the CGI::Application framework include:
     
    param()
     
    This method allows to create parameter references which can be referenced across all module/application run modes - This method is most obviously used in the setup() method to implement such references such as DBI connections, HTML::FormValidator schema, etc. eg.
    sub setup { my ($self) = shift; $self->mode_param('stage'); $self->run_modes({ '1' => \&display_form, '2' => 'display_results', }); $self->start_mode('1'); # Create DBI connection handle and make accessible to all run-mo +des via CGI::Application param() method # $self->param('dbh' => DBI->connect()); };
    teardown()
     
    The paired partner of setup(), this method is implemented automatically after the application is run and can be used for clean up persistent variable and database connections. eg.
     
    sub teardown { my ($self) = shift; # Disconnect the (persistent, with Apache::DBI) DBI handle creat +ed in setup() and passed via the param() method # $self->param('dbh')->disconnect; };

     
    query()
     
    This method retrieves the CGI.pm object (CGI->new()) created with the instance of your self-styled CGI::Application module. All methods for CGI.pm can be applied to the blessed reference returned.

     
    load_tmpl()
     
    This method creates a HTML::Template object (HTML::Template->new()), allowing HTML templates to be employed, aiding in the pyrrhic (depending on your viewpoint) goal of separating code and design. All methods for HTML::Template can be applied to the blessed reference returned.

     
    Tips and Gotchas for CGI::Application
     

     
    The primary note made about run-mode methods in the CGI::Application documentation is to avoid printing directly to STDOUT, instead returning the HTML output ($html->output, if $html is a HTML::Template blessed reference created via load_tmpl()) at the end of the run-mode subroutine to the CGI::Application framework.
     
    For example:
     
    # An example run-mode method # sub display_page { my ($self) = shift; # Create a HTML::Template blessed reference with the template fi +le, page.html # my ($html) = $self->load_tmpl('page.html'); print STDOUT $html->output; # printing template output direc +tly to STDOUT (*BAD*) return $html->output; # return template output to CGI: +:Application framework for display (*GOOD*) };

     
    With the handling of HTML output to STDOUT by the CGI::Application framework rather than within the run-mode subroutine itself, header types and properties should also not be directly manipulated via CGI methods within run-mode methods. Instead, the CGI::Application framework provides two methods for handling header types and properties indirectly - These methods are described below:
     
    header_type(<'header' || 'redirect'>)
     
    This method specifies the type of HTTP headers which should be sent back to the client browser by the CGI::Application framework.

     
    header_props()
     
    This method specifies the HTTP header properties which should be sent back to the client browser by the CGI::Application framework - This method correlates to the header() (and redirect()) methods of the CGI.pm module.

     
    Another tip in the documentation of CGI::Application is the definition the run-mode 'AUTOLOAD' - This run-mode is evoked if the mode_param() CGI parameter calls a run-mode definition not matched to a package subroutine via run_modes() method. This allows the the implementation of 'user-friendly' error pages rather than the default CGI::Application behaviour to croak() on such errors. If evoked, the name of the intended run-mode passed via the mode_param() CGI parameter is passed to the AUTOLOAD run-mode as an argument.
Inline::Files
No replies — Read more | Post response
by ariels
on Jul 23, 2001 at 13:41
    Another of the (good) Dr. Damian Conway's modules, Inline::Files is another tour de force of Perl source code filtering, symbol table manipulation, overridden builtins and a wholly outlandish yet useful concept, wrapped in an entirely Perlish syntax.

    (In case you're wondering, yes, I like the module)

    A word of warning!

    If you're a "hands-on" person, you might want to install and use this module before finishing to read the documentation or this review. PLEASE be careful, and use the -backup flag to the module, at least until you understand what it does! Say "use Inline::Files -backup" instead of "use Inline::Files"!

    What does it do?

    Ever needed to package a few small files along with your program? Well, you can use DATA. But that just gives you one "file". And it's always on the DATA filehandle, which might not suit your programming style.

    Or you can use the "here-document" syntax to get at some strings in your program. That gives you as many strings as you like, but you can't use file operators to read them. And changing them can be tricky (see below for just how easy Inline::Files makes it to change your files...).

    Inline::Files lets you read "virtual files" which you enclose in your program's source. At BEGIN time it does its magic, and you have some new files available to you.

    Virtual files

    At the end of your program, you can put any number of what Inline::Files calls virtual files. These are just regions of you text beginning with special markers __YOUR_CHOICE_OF_ID__. You can then read the contents of this "virtual file" by reading the filehandle <YOUR_CHOICE_OF_ID>. Note that YOUR_CHOICE_OF_ID is the name of a filehandle, so it should be in UPPER CASE, or it won't be recognised.

    More than one virtual file can be associated with the same ID; reading from the filehandle will retrieve them in order.

    More information is available about these virtual files. In particular, you can get a list of the "virtual file names" associated with each ID; open is overloaded to know how to open these files by their names. You can also get the name of the current file being read by the ID, as well as some more esoteric information.

    An example

    #!/usr/local/bin/perl -w use Inline::Files; my ($a,$b,$a_end,$b_end); for($a=<A>, $b=<B>; ! $a_end || ! $b_end; ($a_end or $a=<A>), ($b_end or $b=<B>)) { $a_end=1, $a='' unless defined $a; $b_end=1, $b='' unless defined $b; chomp($a); chomp($b); printf "%35s | %35s\n", $a, $b; } __A__ This is a block of text. Note that this text had best have *SHORT* lines, or we could have some formatting trouble! __B__ The quick brown fox jumps over the lazy dog. The cow jumps over the moon.
    This code arranges 2 blocks of text in a nice manner; the text is read directly from a virtual file, which is nicer than having to split on all newlines of a string.

    It's also a nice way to test some code you want to write to run on real filehandles, while keeping everything in one file.

    Writing

    Not content with letting your programs read parts of themselves in weird and wonderful ways, Dr. Conway also lets your programs write those parts!

    If your program file is writable, all its virtual files are opened in read-write mode. To rewrite the file, just seek back to the beginning and rewrite it. (Or be more creative if you like.) You can even create new virtual files as your program is running.

    This is a cheap and useful way of keeping some "sticky" configuration data attached to your Perl scripts (note, however, that this is per-script or per-module configuration data, rather than per-user or per-instance data).

    See the fine manual and the examples provided with the module in the demo/ subdirectory for more examples.

    What -backup does

    If your program is writing virtual files, you should be very afraid: Your program is getting rewritten to disk continually. -backup makes a backup copy of your program when it loads, just in case. Use it if you're writing to virtual files!

    Prerequisites

    Inline::Files is a pure Perl extension, and doesn't require a C compiler to install. It does require that you have Filter::Util installed for your Perl, and that extension contains some C files.

Quantum::Superpositions
1 direct reply — Read more / Contribute
by larsen
on Jul 22, 2001 at 11:35
     
    <larsen> I think I'll add a disclaimer...
    <larsen> "No cat has been hurt to write this review"
    <neshura> lol
    <neshura> IMPOSSIBLE

    <larsen> hi neshura, I didn't noticed you
    <larsen> :)
    <neshura> now that you have noticed, bet you can't tell what my velocity is

    -- Two monks on IRC :)

    Quantum computing in a nutshell

    One of the possible formulations of Church-Turing's thesis (actually it's not equivalent: is a reinforcement also known as thesis of sequential computing) says that every computing model is simulable by a Turing Machine with at most a polynomial overhead.

    Quantum computing theory provides a model that seems to violate this assertion. Particularly, using a quantum computer (whatever it will be), it could be possible to efficiently solve classes of problems that are intractable nowadays using a classical computer, such as factorization.

    How is this possible? Quantum computing relies on some strange properties of quantum mechanics, called superpositions, entanglement, quantum parallelism.

    In order to take a brief look to these concepts, let's introduce quantum bits, a.k.a. qubits. They behave in part like classical bit, but they can also present "almost ghostly overlays of many different states", commonly known as superpositions of states. For example, it's possible for a qubit to be at the same time in its two states 1 and 2. Better, qubit is in a state where an observer has 1/2 probability to measure state 1 and 1/2 probability to measure state 0. With the notation commonly used in quantum theory:

    1/2(|0> + |1>)

    Unfortunately, measuring the state of a quantum bit alters its state. So if we measure the state of the qubit considered, we could measure state |1> or |0> with the same probability 1/2, but after the measurement the qubit will be in state |1> or |0>, depending on our measurement.

    You could say this is not so useful. Yes. And no. Juxtaposing many qubits we can obtain quantum registers. For example, using 8 qubits in the state 1/2(|0> + |1>) we obtain a register where every state (0..28-1) can be measured, with the same probability. Every integer that can be expressed with 8 bits is "contained" (in the sense explained above) in this quantum register.

    The interesting thing is that if we apply an operator to this register and we put the result in a second register, this register will contain every result that can be obtained applying the operator to the values that are contained in the first register.

    As I said for qubits, the act of measuring alters the state of the registers. But if we measure the value of the second register, even the state of the first register will collapse to the correspondig value. This is called entanglement. So if we measure f(x) from the second register, we will measure x from the firsti one.

    There's no quantum measurement possible to extract from the second register all the information about the function f. But note that the operator performed an exponential quantity of operations in an unitary time. This is called quantum parallelism. And, fortunately, there are other methods to obtain useful information about f. One of these methods (Discrete Fourier Transform, DFT) has been used by Shor to obtain a probabilistic quantum algorithm for factorization, that is known as an intractable problem in classical complexity theory. I think this is not the place to give other explanations: there's a lot of infos available on the net. I put some link at the end of this node.

    Quantum::Superpositions

    I've shown that Quantum Computing model permits to perform multiple operations in a single step by mean of superpositions. Quantum::Superpositions adds new linguistic tools to Perl (any and all) inspired to quantum mechanics.

    They both produce Superpositions, i.e. scalars that can partecipate to any arithmetic or logic operations due to their nature, but with "parallel semantic": when a Superposition partecipate to an arithmetic operation, this operation if perfomed in parallel on every element of the Superposition; when the Superposition partecipate in a logical operation, its truth value is true or false depending on the truth value of its elements, in a disjuntive or conjuntive way, depending on the operator used to build the Superposition (respectively: any or all). I've said "parallel semantic" but internals of this module actually cycle trough every value of the Superposition to perform the operation.

    So, one could write this program using Quantum::Superpositions:

    $product = any(1, 2, 3) * any( 2, 3, 4); print eigenvalues( $product );

    $product is a new Superposition that contain every possible result of the multiplication of the numbers (1, 2, 3) and the numbers (2, 3, 4) ($product is any(8,9,2,3,4,12,6)). eigenvalues is a useful function that returns all the states that our Superposition represent (In this context. See the documentation for details).

    Superpositions can also be passed to subroutines. The subroutine has not to know that what is going to be passed will be a superposition, but it will return a superposition of the results (as in the example of the operator applied to the quantum register).

    Quantum::Superpositions also allows to express succinctly complex logical conditions. From the examples found in the documentation:

    $ideal = any( all("tall", "rich", "handsome"), all("rich", "old"), all("smart","Australian","rich") ); while (@features = get_description) { if (any(@features) eq $ideal) { print "True love"; } }

    Here we build a disjunctive superposition of conjunctive superpositions (note the clarity with the concept of being the ideal is expressed). Then we cycle through a group of descriptions of (I guess :)) men, we build a superposition from the description (any(@features)) and we compare it disjunctively against our $ideal. In this case, is like cycling and comparing against our set of ideals: i.e. if (any(@features) eq all( "tall", "rich", "handsome")). We want that a subset of @features is equal to set ("tall", "rich", "handsome").

    Using Quantum::Superpositions

    First of all, a word about performance.
    Quantum::Superpositions has not to be intended as a practical way to do things in Perl. While it provides very succinct and smart idioms, their implementations are easily less efficient than a "hand-made" solution, because Quantum::Superpositions actually emulates a quantum computer. It isn't, of course, true quantum parallelism. So, this apparently very efficient factorization algorithm (from the examples of module documentation):

    sub factors { my ($n) = @_; my $q = $n / any(2..$n-1); return eigenstates(floor($q)==$q); }

    ...will be comparable to this one from the point of view of efficiency:

    sub factors { my ($n) = @_; my @q = map { $n / $_ } (2..$n-1); return grep { floor( $_ ) == $_ } @q; }
    Beware!, the output differ, because in floor($q)==$q we are asking for a numerical value of the superposition $q, that is generated by this code my @states = $_[0]->eigenstates; return $states[rand @states]. As I stated above, is in a state where we can measure with the same probability every value. Very funny, isn't it? :)

    Also, Quantum::Superpositions provides some, let's say, extra-physics functions that have no counterpart in nature, such as the function eigenstates (remember, "there's no quantum measurement possible to extract all the information..."). So this module should be carefully used if you want to study quantum computing (but there are better tools).

    Quantum::Superpositions is very useful to express, shortly, complex conditions that should be coded with grep/map combinations, as in the example of the ideal man. And it has great value, providing a good example of use of Class::Multimethods.

    References

    1. "Quantum Theory, the Church-Turing principle and the universal quantum computer". This classical paper could be find on David Deutsch's Home Page
    2. Adriano Barenco, Quantum physics and computers. Contemporary Physics, 1996, volume 37, number 5, pages 375-389. I don't know if this article is available on the net.
    3. Quantum Computing and Shor's Algorithm illustrates in detail Shor's factorization algorithm and contains a C++ implementation of the algorithm. Original paper is Shor, P.W., 1994, Proceedings of the 35th Annual Symposium on the Foundations of Computer Science, p.124.
    4. The Emperor's New Mind by Roger Penrose. This book does not directly concern quantum computing, but provides a good introduction to foundations of computer science like Turing machines and recursive functions. It contains also a large section about quantum theory.
    5. There's another module on CPAN inspired to Quantum theory: Quantum::Entanglement
Devel::Peek
No replies — Read more | Post response
by nakor
on Jul 11, 2001 at 14:10
    If you've ever wanted to know just how Perl is storing your data internally, this module is for you. Its most important function is Dump($sv), which prints a full description of the internal state of $sv: flags, contents, type, recerence count, etc. If $sv is a reverence, Dump() will also print the referred-to object. The output is much more technical that that of Data::Dumper, but if you suspect a bug in how Perl is handling your data, this is one of the best tools for checking. Simply Dump() your data structure and see if everything is there that should be. This module also provides a set of other, much more deeply embued-with-black-magic functions, such as ones which will retrieve memory usage statistics if your Perl was built using Perl's own malloc() and ones which let the programmer directuly manipulate a variable's reference count from withing Perl. This is not something that any normal Perl programmer should ever need (or want) to do, but if you're looking to learn more about the guts of the Perl 5 interpreter, this module is a great place to start.
SOAP::Lite
1 direct reply — Read more / Contribute
by $code or die
on Jun 26, 2001 at 19:54

    Update: Please let me know if the <pre> tags bother you. I wrote this in pod. I'll try and convert it to code tags if you think it's necessary.

    SOAP

    (Simple Object Access Protocol : http://www.w3.org/TR/SOAP/)

    SOAP is a lightweight protocol for exchanging data using XML. It allows you access methods and properties of remote objects. Each method call is typically a seperate SOAP envelope (xml document). The SOAP server opens the envelope, processes the data, and returns an envelope to the client with a response.

    SOAP::Lite does the hard work (creating the envelopes and decoding them), leaving the developer the easy task or writing client and server code which is almost no different to what she would have written before.

    Why use SOAP::Lite

    * It's much easier that using SOAP where you have to do a lot of the hard work as well

    * It supports SOAP 1.1

    * It supports lots of protocols other than HTTP. You can even create your own SOAP daemon

    * It supports WSDL (Web Service Description Language)

    * It supports tracing - so you can see what's going on behind the scenes

    * You can use the COM interface on Windows machines

    * It's very well documented

    Why NOT use SOAP::Lite

    * You want a more low-level API - and more work

    * SOAP can be slower that methods you may already be using

    * You prefer shower gel

    Simple Calculator SOAP Server

    The SOAP server is a regular Perl script, which instructs SOAP::Lite to dispatch methods to a named package. My example uses SOAP::Lite's CGI implimentation, but you can use SOAP::Lite over many other protocols such as POP3, SMTP and FTP.

      use strict;
      use SOAP::Transport::HTTP;
      SOAP::Transport::HTTP::CGI   
        -> dispatch_to('My::SoapServer')
        -> handle;
      package My::SoapServer;
      sub add      { $_[1] + $_[2]; }
      sub subtract { $_[1] - $_[2]; }
      sub multiply { $_[1] * $_[2]; }
      sub divide   { $_[1] / $_[2]; }

    Note that I am ignoring the first parameter for each of the method calls since it is simply the package name. I guess that SOAP::Lite interprets your requests as (in this case): My::SoapServer->methodname.

    Client Code to access this Web Service

    The client code is quite straightforward. You create a SOAP::lite object, passing it the details on the SOAP service. Then for each method call, it returns an object which has, amongst others, result and fault methods.

      use strict;
      use SOAP::Lite;
      my $soap = SOAP::Lite
        ->uri("http://myserver.org/My::SoapServer")
        ->proxy("http://www.mywebserver.com/soapserver.pl");
    
    
      print $soap->add(16,8)->result,       "\n";
      print $soap->subtract(10,2)->result,  "\n";
      print $soap->multiply(5,5)->result,   "\n";
      print $soap->divide(1024,2)->result,  "\n";

    Catching Errors

    Suppose I misspell the method call (ADD instead of add):

      print $soap->ADD(16,8)->result;

    ...prints nothing. Not very helpful. However, if you do the following, you can print the fault, (if there is one)...

      my $res = $soap->ADD(16,10);
      if ($res->fault) {
        print $res->faultstring;
      } else {
        print $res->result;
      }

    And this time, it will print ``Bad Method Call''

    There are many more error handling functions provided by SOAP::Lite. But you'll need to read the documentation!

    Autodispatching

    So far, the client code all looks a bit un-friendly. SOAP::Lite has a feature called autodispatch which allows you to write your client code just the same way you would write it if My::SoapServer were a locally installed module. e.g.

      print add(100,-99);

    See the SOAP::Lite docs for more information and unexpected side-effects.

    Things to note

    See the documentation on autodispatch before you use it - or it might have strange side-efects. (It overloads UNIVERSAL::AUTOLOAD)

    See the documentation on performance - you may be able to improve performance by base64 encoding the XML;

    Useful Links

    There is a two part article on perl.com by Paul Kulchenko (SOAP::Lite author):

    Part 1: http://www.perl.com/pub/2001/01/soap.html
    Part 2: http://www.perl.com/pub/2001/04/24/soap.html

    and you can visit Paul's site at the aptly named http://www.soaplite.com, which is an excellent SOAP resource in itself

    Update 2: http://www.salcentral.com and http://www.xmethods.net both provide listings of Web Services you can play around with.

String::Random
No replies — Read more | Post response
by ishmael
on Jun 13, 2001 at 08:08

    Motivation

    Until I saw this module, String::Random I have been using clunky ways to generate random text, always having to lookup ascii codes. This module is an excellent way to generate random strings from a template of possible characters.

    Instant Random Strings

    use String::Random; $foo = new String::Random; # e.g. AqF8, YcE2, BjW8 ... $string = $foo->randpattern("CcCn");

    yields a random four character string: uppercase letter, lowercase, uppercase and then a number. Need a license plate? randpattern("CnCnCn") works for where I live

    Smarter Random Strings

    Particularly useful is the ability to define sets of characters and assign them to a pattern

    # define vowels $foo->{'V'} = [ qw(a e i o u) ]; # define common consonants $foo->{'Q'} = [ qw(r s t n m) ]; # e.g. retom, satan, timis ... $string = $foo->randpattern("QVQVQ");

    particularly useful for generating names of MUD characters.

    Random Regex

    The module also accepts a regex as input.

    # e.g. 342, 289, 832 ... print $foo->randregex('\d\d\d');

    My Own Usage

    • generate short random sequences of DNA using $foo->{'V'} = [ qw(a t g c) ]; to define the four base pairs
    • generate passwords for users that are relatively easy to remember, like $foo->randpattern("!QVCVQn") which gives .saZem9 +nicot8 and so on
    • random file names without all the randomness of using Digest::MD5

    This is one of those small-tool modules that you may find yourself using over and over again.

    Edit: chipmunk 2001-06-18

Text::xSV
No replies — Read more | Post response
by TStanley
on May 14, 2001 at 14:33
    This module is used for reading character separated data. At the
    suggestion of it's creator, I used it in a project of mine,and I am
    quite glad that I did so.

    Here are the available methods within this module:

    new()
    This is the constructor. It will take a hash of three arguments, all of which are optional. The file name, file handle, and the single character separator are the three arguments. If a filename is passed, and a file handle isn't, it will open a filehandle on that file and set the filehandle accordingly. Also, the separator value is a comma by default.

    set_filename()
    set_fh()
    set_sep()
    These are the set methods for the optional arguments for the new() constructor.

    open_file()
    This method takes the name of a file and opens it. It will also set the filename
    and file handle.

    bind_fields()
    Takes an array of field names and memorizes the positions for later use.

    bind_headers() Reads a row from the file as a header line, and memorizes the field positions for
    later use. This method is preferred over the bind_fields method.

    get_row()
    Reads row from file and returns an array or a reference to an array, depending
    upon context. It also stores the row in the row property for later use.

    extract()
    Extracts a list of fields out of the last row read.

    The Good
    As tilly points out in the POD that accompanies the module, most people try to use
    split to separate value separated lines, or they read the line and try to parse it. This
    makes it impossible to handle returns that are embedded in a field.
    This problem is solved by the creation of the xSV object with access to the filehandle, and
    if in parsing, it notices that a new line is needed, it can read the file at will.

    The Bad (and Ugly)
    The module is very unforgiving concerning the character separator. It only works on a single
    character as a separator. The overall speed isn't to bad, but like in all things, there is always
    room for improvement.

    Example
    The below section of code is taken from my QuizTaker.pl program. This function
    is what reads all of the questions into a hash reference, where I later pull
    questions from it at random.
    sub Loader{ my $Data = shift; my $file = shift; ## I declare the Text::xSV object my $XSV = Text::xSV->new(); my $question_number; my $length; my $f; my @Sorter=(); ## I set my separator here, otherwise it ## defaults to a comma. $XSV->set_sep("|"); open(FH,"$file")||die "Can't open $file: $!\n"; while(<FH>){ ## Here I get use the get_row method to retrieve ## the row, which also parses it. @Sorter = $XSV->get_row(); $question_number = shift @Sorter; $length = @Sorter; for($f = 0;$f < $length;$f++){ $Data{$question_number}[$f] = $Sorter[$f]; }#End of for loop }#End of while loop close FH; return $Data; }#End of sub
    One thing I did notice is that if the lines were of different lengths (If one question was multiple choice, and the next was a true/false question), the module would spit out a warning to that effect, the information was also stored in the row property,and it noticed the difference. This, however, did not affect the overall performance of the program itself.
Data::FormValidator
2 direct replies — Read more / Contribute
by markjugg
on May 13, 2001 at 14:12
    I spend a lot of time writing perl to process HTML forms. I soon realized that I was writing very similar code in each case. Some common tasks of form validation include:
    • making sure required fields are populated
    • trimming leading and trailing whitespace off of input.
    • handling fields that become required when another field is filled in
    • validating common input types -- answering such questions as "is this a valid email?", "is this valid zipcode?", "is this valid telephone number?".
    Data::FormValidator helps with all these tasks and more. Outside of the functions it provides, I find declaring the the form validation profile through it's interface to be useful. Here's the example from the documentation:
        {
            customer_infos => {
                optional     =>
                    [ qw( company fax country ) ],
                required     =>
                    [ qw( fullname phone email address city state zipcode ) ],
                constraints  =>
                    {
                        email       => "email",
                        fax         => "american_phone",
                        phone       => "american_phone",
                        zipcode     => '/^\s*\d{5}(?:[-]\d{4})?\s*$/',
                        state       => "state",
                    },
                defaults => {
                    country => "USA",
                },
            },
            customer_billing_infos => {
                 optional       => [ "cc_no" ],
                 dependencies   => {
                    "cc_no" => [ qw( cc_type cc_exp ) ],
                 },
                 constraints => {
                    cc_no      => {  constraint  => "cc_number",
                                     params      => [ qw( cc_no cc_type ) ],
                                    },
                    cc_type => "cc_type",
                    cc_exp  => "cc_exp",
                  }
                filters       => [ "trim" ],
                field_filters => { cc_no => "digit" },
            },
        }
    
    Any validation that you want to yourself you can add in, so you aren't limited to just the options that this module provides. Additionally, HTML::FormValidator doesn't force you to handle the form validations errors in any particular way. Instead it returns the results like this:
        my( $valids, $missings, $invalids, $unknowns ) =
            $validator->validate( \%fdat, "customer_infos" );
    
    Here $valids will be a hash ref, and the other values will be array refs. A nice side effect of this arrangement is that if you've named your form fields with the same names as some database columns, you can now pass your $valids hash ref directly to a module like DBIx::Abstract to insert the results into a database, auto-quoting the values along the way.

    Room for improvement

    While I'm a fan of the module and find it very usable, it doesn't feel quite done yet. You can read and about my ideas to improve it.

    An example

    I've also put together an example of using Data::FormValidator for you to review. It demonstrates how you can use Data::FormValidator along with some other modules to easily display form validation results on the same page as the form, with the former values already filled in.
Devel::ptkdb
2 direct replies — Read more / Contribute
by busunsl
on May 07, 2001 at 08:13
    Review Synopsis: Good for viewing variables and data structures, and for remote debugging

    Devel::ptkdb is a graphical debugger using the Tk toolkit.

    What's good?

    The documentation is good.
    It's easy to use, much easier than the normal perl debugger.
    You can follow the flow of your program and choose if you want to step in or step over subroutine calls.
    You can set and maintain breakpoints easily.
    You can watch arbitrary expressions, variables and complex data structures during the run.
    You can debug remote running programs and cgi scripts.
    You can even debug Tk programs.

    What's bad?

    Though you can debug Tk programs, it is not always possible to do that.
    It is a bit slow.
    You need perlTk.
    It is so nice, you might end up using it for debugging simple problems, where it is just overkill.

    What's missing?

    A regex debugger would be nice, but i think this will come with perl 6.

    Bottomline

    Devel::ptkdb is a full featured graphical debugger for perl written in perl by Andrew Page.

    Though most of the time a simple print statement in the right place will tell you what's wrong, it's good to have a tool like this at hand.
    The 'step in', 'step over' and 'return' buttons make it easy to follow the flow of the running program as you like.
    You can see the values of needed expressions all the time, sometimes even inside of one statement, which is not possible for a print statement.
    With very few changes to your program you can debug cgi scripts and cron tasks, a feature that comes more with the XWindow infrastructure than with ptkdb, but is nevertheless very useful.

    Many thanks to Andrew Page for his work!

    There has been much controversy about debugging lately in the Monastery and I'd rather put dozens of print statements in a program than starting the debugger, but sometimes it can be VERY handy.

    For more thoughts on perl debugging have a look at the following nodes:

    Are debuggers good?
    Are debugging skills atrophying?
    Book Review: Debugging Perl
    Easy, elemental, but cool debug trick (read the comments)

MIME-tools
4 direct replies — Read more / Contribute
by mpolo
on May 06, 2001 at 16:04
    While Mail::Internet will permit you to manipulate ordinary emails, if you want to deal with attachments or foreign characters, you will eventually have to descend into the world of MIME.

    CPAN provides two basic suites for handling such messages: MIME::Lite, which permits generation, but not parsing, and the MIME-tools package, which both generates and parses MIME messages.

    Due to the complexity of MIME messages, the MIME-tools package can get confusing. You will likely find yourself bouncing between three or four different man pages/PODs to get where you want to go.

    Creating a MIME message is quite easy, and involves the MIME::Entity module (included). You simply call the build method to create the base message and then repeatedly call the attach method to add on parts.

    Decoding an incoming message is more complicated. In Mail::Internet, every message has a header and a body. This is no longer true in the world of MIME. If the message is single-part, MIME-tools will return a header and a body handle (the change allowing easier access to binary files). However, in a multi-part message (one that has attachments), the body does not exist as far as the package is concerned. Instead, you have to look at the ->parts of the message, each of which has a head and a body (unless the part itself is multipart, in which case you'll have to recurse...).

    There are a couple of convenience features that make life a bit easier. For instance, you can call the make_multipart method on all your incoming messages so that singlepart messages cease being a special case -- now you can use the parts method on it (iterating over the number of parts) to get the one or more parts that exist. If you have a multipart message that only has one part, there is a companion method to make_singlepart. Both of these methods behave gracefully when given inappropriate input.

    Good: The modules provided manage to handle just about everything you could want with MIME messages, and since HTMail and attachments are ubiquitous, few people can afford to assume that their mail can be handled by Mail::Internet.

    Bad: The moduleset is definitely "heavyweight". If you can get away with MIME::Lite (receiving only), you will save yourself some development time, and of course, your code will be "lighter", as should be obvious from the name. You will also need another way to send the mail you have produced (either pipe it to /usr/lib/sendmail -t -i on a *NIX or use Mail::Sendmail or Net::SMTP). As mentioned in a comment below, the encoding/decoding is done in memory, which can be a limitation. MIME-tools does, however, save parts out to disk if they are long, so you only have to have one part in memory at a time. A caveat is in order here: if you're creating a MIME message and use the purge method to get rid of disk files, the module will (try to) unlink the original attachment. If it fails due to file/directory permissions, it doesn't complain, though.

Parse::RecDescent
3 direct replies — Read more / Contribute
by Masem
on Apr 22, 2001 at 22:25
    Item Description: Provides a yacc/lex-like functionality for parsing input data into Perl.
    Review Synopsis: Replicates most of the features of yacc/lex minus a few shortcomings with addition benefits of using perl to make parsing complex input rather simple.
    Module Author: Damian Conway
    Module Homepage: http://www.cs.monash.edu.au/~damian

    Description

    Those that have dealt with free-form input files, which include nearly all programming languages in addition to other third party programs, probably have had to deal with parsing such input using tools called lex (LEXical Analyzer Generator) and yacc (Yet Another Compiler Compiler) or their GNU cousins, flex and bison. Using a combination of these tools, one could derive a grammar specification and use that to place data into data structures. These tools are common around C and C++ folk.

    However, with perl and it's strong regex engine, it's possible to replicate most input functions with advanced regexs, and thus, there usually isn't much need to worry about grammar specifications. However, there can be times where you just cannot do what you need to do with regexs without additional logic, but would be well-suited to using a grammar to interpret data. For example, given

    names = John Joe "Mary Sue" James
    you cannot simply get every name after the '=' by splitting on spaces using a regex. But with a grammar parser, this problem is simple.

    Introducing Parse::RecDescent, a grammar parser for Perl. It mainly works by calling two functions: a new routine with the desired grammar in order to prepare the parser, and a startrule which takes in the input to be processed and returns whatever results are needed. There are other functions available to swap rules in or out of the grammar set if needed, but most of the functionality is built into the initial description of the grammar rules set.

    For example, consider simple math problems. The grammar will look something like this:

    startrule: calculation statement: grouped_op | number grouped_op: '(' calculation ')' calculation: add_calculation | subtract_calculation add_calculation: statement '+' statement subtract_calculation: statement '-' statement number: /\d+/
    Basically, the text on the left are rules, and the statements on the right are what the parser expects to see when it is expecting those rules. Note that these can be recursive and the like; thus if I'm looking for a 'statement', and see a 'group_op', I could see yet another 'statement' inside that 'group_op'. Parse::RecDescent uses a special rule called "startrule" as the default starting point, though you can tell it to use a different rule if you desire. At the very basic level, Parse::RecDescent can determine if the input matches that grammar, and returns true or false:

    LISTING 1

    #!/usr/bin/perl -wT use strict; use Parse::RecDescent; my $parser = new Parse::RecDescent( q{ startrule: calculation eofile statement: grouped_op | number grouped_op: '(' calculation ')' calculation: add_calculation | subtract_calculation add_calculation: statement '+' statement subtract_calculation: statement '-' statement number: /\d+/ eofile: /^\Z/ } ); my @tests = ( "3", # BAD "4 + ", # BAD "4 + 8", # GOOD "4 + 8 +", # BAD "6 + (3 - 2)", # GOOD "6 + ()3 - 2", # BAD "(6 + (3 - 2)) + 1", # GOOD "(6 + (3 - 2) + 1)", # BAD "(6 + 3" # BAD ); foreach my $test ( @tests ) { print $test . ': ' . ( defined($parser->startrule( $test ) )?"good":"bad") . "\n"; }

    Obviously, my math here is not perfect, but for demonstration purposes, this is sufficient (One can play with grammar files indefinitely to continue to improve performances). One thing of note in the grammar specs is the use of 'eofile'; because of how Parse::RecDescent treats data (namely, trying to go left to right without any backtracking), it will make the most non-greedy match (think '.*?') it can, and once matched, it will be happy. So, as in case 4, "4 + 8 + ", without 'eofile' in the grammar rules, the parser will recognized "4 + 8" and be happy with that, the trailing plus sign ignored. The 'eofile' basically forces the match to work on the entire text string and not just the first parts it can match.

    Now, this might seem like overkill, as pattern matching is easily done by regexes. However, behind most of Parse::RecDescent is a powerful way to manipulate values that have been recognized, either for in-line processing or later evaluation. Without specifying any of these extra actions, the default behavior of Parse::RecDescent is to return the value of the last item matched in the rule. However, if you simply want a tree-like structure of how the input is defined, one can include a pragma "<autotree>" at the top of the grammar string that, when parsing, will return a hash with all the data in it. Alternatively, you could perform in-line calculations which is well suited to our sample program above...

    LISTING 2

    #!/usr/bin/perl -wT use strict; use Parse::RecDescent; my $parser = new Parse::RecDescent( q{ startrule: calculation eofile { $return = $item[1]; } statement: grouped_op | number grouped_op: '(' calculation ')' { $return = $item[2]; } calculation: add_calculation | subtract_calculation add_calculation: statement '+' statement { $return = $item[1]+$i +tem[3]; } subtract_calculation: statement '-' statement { $return = $item[1]-$i +tem[3]; } number: /\d+/ eofile: /^\Z/ } ); my @tests = ( "4 + 8", "6 + (3 - 2)", "(6 + (3 - 2)) + 1", ); foreach my $test ( @tests ) { print $test . ': ' . $parser->startrule( $test ) . "\n"; } # Output is: #4 + 8: 12 #6 + (3 - 2): 7 #(6 + (3 - 2)) + 1: 8

    Demonstrated here are two of the special variables that are used in defining these actions. @item is a list of the values of what actually matched the rule, starting with 1 and going up, and including each 'constant' as well (eg, in add_calculation, $item[2] would be '+' regardless of other arguments.) $return is the value that will be passed up to previous rules as the value for that rule. By default, as mentioned above, if there is no special action rule, the value of the last item matched will be passed along. As you can see here, I've created a very simple calculator without doing any of the logic within perl itself; you could easily extend this to do much more advanced calculations.

    There are many more features that will benefit those working with grammars. There are a number additional features of specifying the grammar itself, including matching on repeated items ala regex, look-aheads, passing matched values to further rules, as well as start-up and default actions. Within actions, there are a number of other special variables that are useful for parsing statements, including current line and column numbers for error reporting.

    An addition feature of Parse::RecDescent are directives that are included in the grammar portion of the system. One has already been mentioned, <autotree>, which automatically builds a hash tree of the parsed data, but there are a number of others. There are ones that can be used to parse strings or perl code, ones to provide scoring to determine which rules of multiple ones should be used, error reporting directives, conditional directives, and others to help improve the speed of parsing by bailing out of guaranteed failed matches.

    A final feature of Parse::RecDescent is the ability to set debugging flags. These are named as $::RD_<feature>, and can be used to influence the behavior of the engine or to output what rules and steps it is currently processing.

    Most of these features are layed out well in the included documentation, although it is expected that you have had previously knowledge of using grammars prior to using the module. As the module is written in pure Perl, it should be usable on all platforms that can run Perl.

    Benefits

    The grammar specification has tried to stick as close as possible to lex/yacc's grammar definitions as to make the use of existing grammars easy within Parse::RecDescent. In addition, several additional features have been added to make grammar work in a more perl-like way, making it very easy to add such features to an existing perl framework.

    Pitfalls/Caveats

    One thing that has been mentioned is that unlike perl's regex engine, which is 'greedy' and tries to consume as much as the string as possible when matching, Parse::RecDescent is the opposite and tends to be less greedy. This may cause problems such as letting trailing characters go through or missing parts of matches. Grammars that worker perfectly in lex/yacc may not work straight into Parse::RecDescent.

    Conclusions

    If you have any data input that is free form, then you should be using a grammar system to read that data into your program to avoid pitfalls with balancing quotes, whitespace, and other features. Parse::RecDescent provides an excellent equivalent for lex/yacc within perl, and assuming you have previous knowledge of using grammars, you'll be up and running this in no time.

Template Toolkit 2
1 direct reply — Read more / Contribute
by Masem
on Apr 14, 2001 at 12:57
    Item Description: Create text streams from Perl data and template files
    Review Synopsis: An extremely powerful and extendable module that can be used to separate data presentation concerns from Perl code
    Module Author: Andy Wardley
    Module Homepage: http://www.template-toolkit.org/index.html

    Description

    Template Toolkit 2 (hence referred to as TT2) is a distribution of Perl modules that can be used to place Perl data into templates, similar to modules like HTML::Template, HTML::Mason, or Text::Template. However, unlike these other template modules, TT2 is language-neutral and can be used to generate output for any text-based language, include HTML, XML, PS, plain text, or what have you.

    TT2 can be found on CPAN as a Distribution, and thus, can be easily installed on your system. It does take a while to compile support libraries, however. As there's no special system calls, TT2 should work on any platform that uses Perl. The documentation is well written and includes numerous examples of using TT2, and also has a mailing list for further support (available at the site above).

    The Perl interface to TT2 is rather simple:

    use Template; my $tt = Template-new(); $tt->process( $template_file , { scalar_param => $scalar, array_param => \@array, hash_param => \%hash } ) or die $tt->error();
    The first parameter to process() is the file which your template is in; various configuration flags can have this located relative to your script, or in an absolute file location. The second parameter is an anonymous hash which can contain anything (within reason); the keys are used for further reference in the template file. An optional third parameter can be used to point the output to a predefined string, file, or other text stream; without this, the output is sent directly to STDOUT (very handy for CGI scripting).

    The template itself may look something like this:

    Hello [% name %], how are you doing on this fine [%- IF hour < 11 -%] morning [%- ELSIF hour < 18 -%] afternoon [%- ELSE -%] evening [%- END -%] ?
    TT2 interprets everything between '[%' and '%]' itself, leaving other parts untouched. Because commands can sometimes extend onto multiple lines when the final output should not be, both the opening and closing delimiters can be marked to indicate if pre- or post-chomping should be done or not , as demonstrated in the IF block above. So if the above was processed, the final line would be contained on one single line.

    Unless recognized as a keyword or a statement, TT2 will substitute whatever is between the delimiters with the value associated with that key in the hash passed as the second parameter in the process function. Deeply nested data structures can be recalled using name-dot-name like notation:

    # # .. from perl .. # $tt()->process( 'text.tt', { data => ( name => 'John', age => '18', grades => ( 98, 57, 79 ) ) } ) or die $tt->error(); # # .. in template file .. # Hello, [% data.name %], your third test grade was [% data.grades.2 %] Your grades so far have been: [% FOREACH grade = data.grades %] [% grade %] [% END %]
    In addition, you can assign and adjust variables within the template language if needed. If you pass object variables, you can also call their methods directly from the template file. You can also create variables that exist only within the template, and furthermore, you can allow TT2 to specify a configuration template that will be precluded for any other template that you call, a useful tool when several data streams will be generated but with common elements.

    A large number of keywords (indicated as all-caps words) can be used for basic flow control, include IF-ELSIF-ELSE blocks, FOREACH blocks, and several others. You can also create template blocks, small bits of repeated code, and use INCLUDE statements to encourage code reuse. You can also define MARCOs to simplify parts of your input template file. Another powerful feature is the ability to use plug-ins for TT2, including one that gives you direct access to CGI.pm's functions, one to interface with DBI, and several XML ones. Since TT2 is language-neutral, there is no direct support for HTML or CGI forms, but the ability to access CGI.pm's features makes this a non-problem. There's also several other ways to extend the module beyond plug-ins to suit your needs.

    Besides being very useful from Perl, TT2 comes with two perl scripts, "tpage" and "ttree", that can allow you to create a single page or a whole directory tree of files from template files. This can be helpful to maintain, for example, static portions of a web site to keep a consistent theme across it. External configuration files can also help change certain features without doing massive editing of several files.

    One final key feature is the ability to include Perl code directly into the template file via the PERL directive. While this ability can be taken advantage of at any time, it easily allows one to create what are effectively embedded-perl pages, though some tweaking with the server will need to be done to make sure these are served efficently.

    Benefits

    The key benefit of TT2 over the other templating modules, as already mentioned, is it's language neutrality; other template modules tend to be tied to one language, but TT2 lacks that, though the current batch of plugins tend to favor HTML. TT2 has good caching support, which allows it to work quickly after initial processing in a persistent environment, such as in mod_perl.

    With proper use of TT2 it should be very easy to separate details of output from your Perl code, thus making it easier to either debug the logic in the Perl script, or redesign the output through the templates. Doing such can lead to a rapid development and design environment for any Perl application that has much moving targets.

    Numerous other benefits have been pointed out to by this node.

    Pitfalls/Caveats

    TT2 is not lightweight. When you initially load a template file, you'll get some delay as parsing and caching occur on the file. However, this can be easily avoided by taking proper steps to ensure that caching of the parsed files will be done (namely by keeping the instance variable around). While the caching may not be as fast as the other templating systems, it's understandable that a complex system such as this will take more time and resources to do it's job. In practical tests, once TT2 is caching the template files, it works at an outstanding pace.

    A minor nit that I've had is that the process function defaults to STDOUT, as opposed to going to some output string. Mind you, this is also easily dealt with using a third parameter, but when print $cgi->f() calls are mixed with $tt->process statements, both sending output to STDOUT, it can be a bit confusing.

    Conclusions

    TT2 is an excellent module for plugging data into a template file for preparation for any sort of text stream output, thanks to it's language neutrality. Numerous control functions allow for a powerful scripting language which can be interfaced back with Perl. While TT2 may be a bit power-hungry, it should work fine on high load servers once it gets going, making it excellent not only for HTML delivery, but XML or any other custom format. In addition, as I hope to get to in a later article, it helps to create the ability to do rapid development of applications by separating logic from presentation.

    Edited 2001-04-16 by Ovid

NET::LDAP
3 direct replies — Read more / Contribute
by bobtfish
on Apr 09, 2001 at 15:14
    Find it at: http://search.cpan.org/search?dist=perl-ldap

    Description
    Net::LDAP implements an OO interface to LDAP directories, allowing you to search, display and modify the information contained therein.

    Who should use it?
    Anyone who has to write perl that talks to an LDAP directory.

    Good features: Has good default behaviour so you do not have to pass lots of specifics if you don't need to.
    Will work asynchronously so that you can be doing work with the first results returned whilst the search is still being carried out

    What are the drawbacks or problems?
    There is no non-OO interface.
    Must install Convert::ASN1.

    Example code:
    Code to dump the entire database (from the perspective of an anonomous bind.)
    #!/usr/bin/perl -w use Net::LDAP; $ldap = Net::LDAP->new('127.0.0.1') or die "$@"; $ldap->bind ; # an anonymous bind $mesg = $ldap->search ( # perform a search base => "c=US", filter => "(objectclass=*)" ); $mesg->code && die $mesg->error; foreach $entry ($mesg->all_entries) { $entry->dump; } $ldap->unbind; # take down session

    20050126 Janitored by Corion: s!Covert!Convert!, closed code tag

CGI::Explorer
2 direct replies — Read more / Contribute
by stefp
on Mar 29, 2001 at 11:36
    Disclaimer: this review is preliminary.and will be extended once I will get the hang of that much needed module.

    I don't know other HList CGI support. so this module is most welcome.

    At first look the API is very clean. Keep It Simple.
    flame bait: KIS is too rare in the Perl world that delights too often on uneeded diversity and complexity, opening the road to languages that suffer the oposite shortcoming: lacking versatility.

    But I immediately ran into a major disappointment, the bundled demo was easily installed but failed to perform correctly on browsers other than Internet Explorer. CGI::explorer due to the use of proprietary tags. The module author is aware of it and will fix that.

    . -- stef

NetAddr::IP
1 direct reply — Read more / Contribute
by Clownburner
on Mar 27, 2001 at 15:39
    Description
    NetAddr::IP provides a simple interface to the tedious bit manipulation involved when handling IP address calculations. It also helps by performing range comparisons between subnets as well as other frequently used functions such as:

    • Checks to see if a host address or subnet is contained within another subnet
    • Count number of host addresses in a subnet
    • Enumeration of host addresses in a subnet
    • Calculate the Subnet or broadcast address of a given IP address and mask
    • Validation of host or subnet addresses
    • Compact subnets or addresses into the largest possible CIDR block
    It can also return results in either CIDR notation (10.1.1.1/24) or regular Mask notation (10.1.1.1 255.255.255.0). You can also return addresses without masks, or masks without addresses.

    Who should use it?

    Anyone who needs to perform complex operations on IP addresses, such as determining a subnet address for a given address, or a quick way to determine if address/subnet A is in subnet B. Saves a lot of time with binary conversions.

    Who should NOT use it?

    Anyone who is running on a system that may have endian problems -- the author clearly states in the documentation that it has not been extensively tested on a range of platforms. Be careful.

    Documentation

    Complete and very well presented, with plenty of examples.

    Personal Notes

    I've used this module extensively for subnet determination and address manipulation, and it worked extremely well (at least on Linux/Intel, there were no endian problems). The documentation is clear and simple. Recommended!