User Questions
Mail::Sendmail
1 direct reply — Read more / Contribute
by Corion
on Mar 22, 2001 at 11:34

    Every program expands until it can send mail.

    Mail::Sendmail tries to make this task easier by providing an interface to any SMTP server you specify. In hindsight, the name should rather have been Mail::Simple, but it's too late for that. An alternative to Mail::Sendmail is Net::SMTP, which has about the same feature set except MIME, but I have not (yet) looked closely enough to make a qualified comparision.

    Why use Mail::Sendmail ?

    You need to send mail and you're not sure that there will be a local mailer installed. Mail::Sendmail works under Windows and Unix (most likely, Mac too) and it's a pure Perl solution. Installation is easy even if you don't have a make utility installed, as it consists of only one file to copy. If you install MIME::QuotedPrint, you'll also be able to easily send attachments and HTML encoded Email. It only makes one connection to the SMTP server for all recipients of the email.

    Why not use Mail::Sendmail ?

    Mail::Sendmail needs an existing network connection to the internet, or at least an existing network connection to the SMTP server you want it to use. It does not support local queuing or anything fancy. It modifies the headers of your email to have Content-Type and Content-transfer-encoding headers, and it will automagically try to do the right thing and quote high-ASCII characters. If you have warnings on, it will warn quite a bit about stuff. Mail::Sendmail only exports one function, &sendmail(). If you need finer grained feedback, like progress, etc. or if you don't have enough memory to keep your email twice! in it, Mail::Sendmail is not for you.

    Caveats

    Mail::Sendmail tries to do the right thing. This might bring surprising results if you use high-ASCII stuff. Mail::Sendmail tries to parse the email adresses given, but it isn't completely RFC compliant. This might bite if you have really fancy email addresses.

    Example

    The Mail::Sendmail documentation already has an exhaustive example, but I'm reposting my test script which I used to check whether Mail::Sendmail works under Win32 :

    #!/usr/bin/perl -w # Simple test script to test Mail::Sendmail under Win32 use strict; use Mail::Sendmail; # Set up some default configuration unshift @{$Mail::Sendmail::mailcfg{'smtp'}} , 'smtprelay.t-online.de'; $Mail::Sendmail::mailcfg{'from'} = "Corion (script) <corion\@sends.no. +spam>"; my %mail = ( Bcc => 'corion@wants.no.spam', Subject => "Test 1", 'X-Mailer' => "Mail::Sendmail test script v0.01/$Mail::Sendmail::VER +SION", Message => "Test number 1", ); sendmail( %mail ) or die "Error: $Mail::Sendmail::error\n";
Coordinate
1 direct reply — Read more / Contribute
by orbital
on Mar 19, 2001 at 23:14

    I just recently started using the GPS::Garmin module by Joao Pedro B Gonçalves , joaop@iscsp.utl.pt to dump my GPS data directly into my perl scripts. This module works great but unfortantly the Module gave me Lat. and Long. in degrees.minutes and I wanted it in UTM (Universal Transverse Mercator).

    • UTM is the standard used by multiple organizations around the world to locate a specific point on earth. UTM is calculated by one central orgin on earth, everything thing from that point is represent in meters. The first set of numbers is refered to as the Easting (East-West postion) and the second number is refered to as the Northing (North-South position).

      Advantages of having your data in UTM is that you are able to use USGS data in conjuction with your newly aquired data. You can obtain the data at EROS The DEM (Digital Elevation Models) data in my opinion the most useful, it allows you to grab a 3D snap shot of an area, in which you can then overlay your data on top of it.( here are the file specs for SDTS dem data Unfortantly there is no perl modules that will convert sdts information, but there are some great C libraries and programs already avaliable.

    Coordinate Module


    This little gem by Curtis Mills is not on CPAN, however you can download it from his site at: http://www.eskimo.com/~archer or ftp://ftp.eskimo.com/u/a/archer/aprs/xastir/
    Curtis has converted several C GNU libraries into pure perl code with this module. However be aware that this is still a work in progress and has some small errors:

    Please note that I didn't pay a lot of attention to keeping the "double" notation in the form of higher precision floating point routines. This means that the Perl5 code won't be as accurate as the original C-code. It doesn't matter for my purposes. If anyone converts to Math::BigFloat for higher precision, please send me the changes. As it is I did a quick check and found a difference of only 1.4 meters between my Perl results and the results from a web-based datum-shift calculator on the 'net. -- Curt.

    If you want to check the accuracy of the results generated by Coordinate I suggest submiting your data to this web form

    What does it exactly do?

    • Creating and manipulating Coordinate objects
    • Translating coordinates between UTM and Latitude/Longitude
    • Translating coordinates between ~231 different datums (Datums are used to "describe" the surface of Earth since its not a perfect Geometric shape, its Geodetic.
    • Formatting coordinates into decimal degrees, degrees/minutes, and degrees/minutes/seconds.

    Here is a chunk of sample code provided by Curtis:

    use Coordinate; my $position = Coordinate->new(); $position->latitude(48.125); $position->longitude(-122.500); $position->datum("NAD27 CONUS MEAN:W of Mississippi/Except Louisiana +/Minnesota/Missouri"); # Datum printf("Starting position(Lat, Long): %s %s\n", $position->latitude(), $position->longitude() ); $position->degrees_minutes_seconds(); # Convert to DD MM SS f +ormat printf("Starting position(Lat, Long): %s %s\n", $position->formatted_latitude(), $position->formatted_longitude() ); $position->lat_lon_to_utm(); printf("Calculated UTM position(Easting, Northing, Zone): %f %f + %s\n", $position->easting(), $position->northing(), $position->zone() ); $position->utm_to_lat_lon(); printf("Calculated Lat, Long position(Lat, Long): %f %f\n", $position->latitude(), $position->longitude() ); print "Changing from NAD27 to WGS84 datum...\n"; $position = $position->datum_shift_to_wgs84(); printf("Calculated Lat, Long position(Lat, Long): %f %f\n", $position->latitude(), $position->longitude() ); $position->degrees_minutes_seconds(); # Convert to DD MM SS printf("Calculated Lat, Long position(Lat, Long): %s %s\n", $position->formatted_latitude(), $position->formatted_longitude() ); print "Changing from WGS84 to NAD27 datum...\n"; $position = $position->datum_shift_from_wgs84_to( "NAD27 CONUS MEAN: +W of Mississippi/Except Louisiana/Minnesota/Missouri" ); printf("Calculated Lat, Long position(Lat, Long): %f %f\n", $position->latitude(), $position->longitude() ); print "\n0\n"; my $temp = CoordinateFormat->new( "0" ); printf(" decimal_degrees: %s\n", $temp->decimal_degrees( ) +); printf(" degrees_minutes: %s\n", $temp->degrees_minutes( ) +); printf("degrees_minutes_seconds: %s\n\n", $temp->degrees_minutes_sec +onds() ); print "180\n"; $temp->raw( "180" ); printf(" decimal_degrees: %s\n", $temp->decimal_degrees( "1 +80") ); printf(" degrees_minutes: %s\n", $temp->degrees_minutes( "1 +80") ); printf("degrees_minutes_seconds: %s\n\n", $temp->degrees_minutes_sec +onds("180") ); print "180 30\n"; $temp->raw( "180 30" ); printf(" decimal_degrees: %s\n", $temp->decimal_degrees( "1 +80 30") ); printf(" degrees_minutes: %s\n", $temp->degrees_minutes( "1 +80 30") ); printf("degrees_minutes_seconds: %s\n\n", $temp->degrees_minutes_sec +onds("180 30") ); print "180.50\n"; $temp->raw( "180.50" ); printf(" decimal_degrees: %s\n", $temp->decimal_degrees( "1 +80.50") ); printf(" degrees_minutes: %s\n", $temp->degrees_minutes( "1 +80.50") ); printf("degrees_minutes_seconds: %s\n\n", $temp->degrees_minutes_sec +onds("180.50") ); $temp->raw( "180 30.50" ); print "180 30.50\n"; printf(" decimal_degrees: %s\n", $temp->decimal_degrees( "1 +80 30.50") ); printf(" degrees_minutes: %s\n", $temp->degrees_minutes( "1 +80 30.50") ); printf("degrees_minutes_seconds: %s\n\n", $temp->degrees_minutes_sec +onds("180 30.50") ); $temp->raw( "180 30 30" ); print "180 30 30\n"; printf(" decimal_degrees: %s\n", $temp->decimal_degrees( "1 +80 30 30") ); printf(" degrees_minutes: %s\n", $temp->degrees_minutes( "1 +80 30 30") ); printf("degrees_minutes_seconds: %s\n\n", $temp->degrees_minutes_sec +onds("180 30 30") ); $temp->raw( "180 30 30.5" ); print "180 30 30.5\n"; printf(" decimal_degrees: %s\n", $temp->decimal_degrees("180 +30 30.5") ); printf(" degrees_minutes: %s\n", $temp->degrees_minutes("180 +30 30.5") ); printf("degrees_minutes_seconds: %s\n\n", $temp->degrees_minutes_sec +onds("180 30 30.5") ); $temp->raw( "-180 30 30.5" ); print "-180 30 30.5\n"; printf(" decimal_degrees: %s\n", $temp->decimal_degrees("-180 + 30 30.5") ); printf(" degrees_minutes: %s\n", $temp->degrees_minutes("-180 + 30 30.5") ); printf("degrees_minutes_seconds: %s\n\n", $temp->degrees_minutes_sec +onds("-180 30 30.5") );
    The output from this looks like following:

    Starting position(Lat, Long): 48.125 -122.5 Starting position(Lat, Long): 48 07 30.00000000 -122 30 0.00000000 Calculated UTM position(Easting, Northing, Zone): 537208.685551 533 +0095.589079 10U Calculated Lat, Long position(Lat, Long): 48.124997 -122.500000 Changing from NAD27 to WGS84 datum... Calculated Lat, Long position(Lat, Long): 48.124789 -122.501238 Calculated Lat, Long position(Lat, Long): 48 07 29.23995960 -122 30 + 4.45751911 Changing from WGS84 to NAD27 datum... Calculated Lat, Long position(Lat, Long): 48.124997 -122.500000 0 decimal_degrees: 0 degrees_minutes: 00 0.00000000 degrees_minutes_seconds: 00 00 0.00000000 180 decimal_degrees: 180 degrees_minutes: 180 0.00000000 degrees_minutes_seconds: 180 00 0.00000000 180 30 decimal_degrees: 180.50000000 degrees_minutes: 180 30 degrees_minutes_seconds: 180 30 0.00000000 180.50 decimal_degrees: 180.50 degrees_minutes: 180 30.00000000 degrees_minutes_seconds: 180 30 0.00000000 180 30.50 decimal_degrees: 180.50833333 degrees_minutes: 180 30.50 degrees_minutes_seconds: 180 30 30.00000000 180 30 30 decimal_degrees: 180.50833333 degrees_minutes: 180 30.50000000 degrees_minutes_seconds: 180 30 30 180 30 30.5 decimal_degrees: 180.50847222 degrees_minutes: 180 30.50833333 degrees_minutes_seconds: 180 30 30.5 -180 30 30.5 decimal_degrees: -180.50847222 degrees_minutes: -180 30.50833333 degrees_minutes_seconds: -180 30 30.5

    Curtis has also provide a few other methods that maybe useful,

    EllipsoidTable->enumerate(); DatumTable->enumerate();
    Both of these methods display the data tables that the program is basing its calculations on.
Storable
3 direct replies — Read more / Contribute
by TheoPetersen
on Feb 22, 2001 at 16:11
    Storable is one of those modules that I use so much, I forget it's there. My day job involves an overly ambitious application builder. The designer (one of my co-workers or a customer of ours) writes a text definition of an application and runs it through our compiler (using Parse::RecDescent, which I'd review also if it weren't being replaced), which builds the Perl object representation of the application and stores it in a repository via DB_File.

    When I first started working on the compiler, I wrote my own code to store and reconstitute objects in the repository. As it got more complex (and slow) I started to think this had to be a problem someone else had already solved. I went looking for help and discovered Storable (and CPAN along the way -- I was just a wee slip of a Perl coder then).

    Storable makes this kind of thing trivial. If you have coded your own solution as I was, don't be surprised if big stretches of perl vanish into a few imported function calls. Here's all the code you need to turn an object into a scalar:

    use Storable qw(freeze thaw); ... $buffer = freeze($obj);
    The $buffer scalar now contains a very compact representation of the object -- whether it was an array reference, a blessed hash or whatever. Drop that string into your favorite file, tied DBM database or SQL blob and you're done.

    Retrieve that same scalar in some other stretch of code (or another program, as long as it has loaded all the necessary modules) and you can have your object back just as easily: $newInstance = thaw($buffer); If the frozen buffer was a blessed reference, then so is the new instance, but not the same reference; Storable can be used to clone complex objects and structures this way, and even has convenience functions for that. (But you might want to look at Clone instead.

    Storable's pod suggests that objects can inherit from it and use freeze and thaw as methods. I don't do that; instead I store and retrieve objects from the aforementioned tied DB_File database like so:

    sub store { my $obj = shift; my $key = $obj->key; $db{$key} = freeze($obj->freeze); return $key; } sub fetchFromDb { my ($key, $noWake) = @_; if (my $buf = $db{$key}) { my $obj = thaw($buf); return $noWake || !$obj ? $obj : $obj->wake; } return undef; }
    (Code that checks if the database was opened for write and so on was omitted for cleaner lines and that sexy soft-spoken style.)

    The two functions are in a module that hides the details of the database from the rest of the program. The store function in effect becomes a filter that transforms an object into its retrieval key. If the object has attributes that shouldn't be stored (run-time only information, say) then it's special-built freeze method gets rid of it and returns $self. The fetch function can be used to retrieve the object in its frozen state, or (normally) will invoke a wake method to let the instance rebuild any run-time state it needs before it faces the world.

    Okay, this is rapidly turning into a review of how I use Storable instead of what the module does, so back to the feature list.

    Storable's documentation emphasizes the number of ways it will write and retrieve objects from files and other IO entities. If you use a file for each object (and remember that an "object" can be a simple hash or array too, no blessings required) then Storable will do all the work including opening and closing the files for you:

    store \%table, 'file'; $hashref = retrieve('file');
    To borrow more examples from the pod, you can use opened file handles too:
    store_fd \@array, \*STDOUT; nstore_fd \%table, \*STDOUT; $aryref = fd_retrieve(\*SOCKET); $hashref = fd_retrieve(\*SOCKET);
    The "n" versions of store and store_fd use network byte ordering for binary values, making it reasonably safe to store and retrieve objects across architectures. The retrieval examples show fetching objects from an open socket -- Perl-based object servers, anyone?

    While feature-rich, Storable remains fast, much faster than my original code. It is implemented in C with a close eye on Perl internals to work swiftly and efficiently.

    Storable has added quite a few features since I started using it; for example, you can now add your own hooks to the freeze and thaw code to implement what I did above at a lower level. In those hooks you can use special class methods to find out more about what Storable is doing and decide how your hook should act.

    Since CPAN now (optionally) uses Storable to store metadata, many Perl admins are aware of it, but might not be putting it to use in their own code. Consider this module any time you find yourself writing a loop to store a hash or array to a file. Storable "scales up" to more complex structures seamlessly, so you can use your favorite tricks without worrying about how you're going to write and retrieve it later.

HTML::TreeBuilder
No replies — Read more | Post response
by Nooks
on Feb 16, 2001 at 12:56
    I've been happily using this module for a few months. If you dislike code that (ab)uses regular expressions to parse HTML, this module could be what you're looking for!

    TreeBuilder uses HTML::Parser under the hood, and at the moment is fairly tightly coupled to HTML::Element, since it builds a tree of those objects if the parse is successful. (The author spoke recently on the libwww mailing list about making the module capable of building a tree of, say, subclassed HTML::Elements.)

    The killer feature of this module is that it tries to parse HTML as a browser would, rather than treating all input HTML as supposedly perfectly compliant documents---which the majority of them are not! This is extremely useful. I have not seen a HTML parser for any other language that does anything like this.

    Even though you'll use HTML::TreeBuilder, most of the functionality you'll want to use is in HTML::Element. The look_down() method is very useful---called on an Element, it searches down the tree looking for Elements that match a list of criteria. It's possible to specify a code reference as an argument (other forms of arguments are supported); Elements that pass the sub are returned (actually, in scalar context the first such Element is returned). Since look_down (and its sister, look_up, among many others) returns an Element, it's easy to search on successively more specific criteria for just what you want, and the code (written correctly) will keep working even if the HTML changes (I've used this pretty successfully to deduce the form contents required to fake a HTTPS login to HotMail---I'd post it here but there is too much LWP clutter in the way of what should be presented to show how this module shines).

    The module also provides Tree cloning, cutting, and splicing functionality, much like you'd expect from a Document Object Model in other languages (or even Perl!). TreeBuilder objects can be converted to and from HTML and XML Element trees using the HTML::DOMbo module, by the same author. (I haven't used this functionality myself...yet.)

    There are a few slight downsides to the module---at the moment it can't be usefully subclassed (a very minor problem); it's probably not as fast as searching your HTML with a regex; it may not even be as fast as `grepping' through parsed HTML via HTML::Parser directly. However I had to work with it quite extensively before I found any of these things even slightly problematic.

    The author, Sean M. Burke <sburke@spinn.net>, maintains the code well, and is ready to answer questions on the LWP mailing list.

    An excellent module that anyone dealing with HTML should become familiar with.

diagnostics.pm
1 direct reply — Read more / Contribute
by damian1301
on Feb 07, 2001 at 23:57

    Note: The only reason I put the title as 'use diagnostics' is because I didn't want it to be confused with the Perl documentation page diagnostics.

    As many of the monks out there already know, there is a module that catches errors and can potentially help you solve them by giving you examples and explanations of what, possibly, could go wrong.

    Just to explain this to you a little more clearly, here is an example that can commonly fail and cause a load of unneeded problems, which no one needs :). This is quite easy though.
    #!/usr/bin/perl use diagnostics; my ($q,$w) = 1,2;
    Obviously enough, this is a simple error to most Perl users. For those that don't know, the diagnostics module provides some quidelines for you.
    Useless use of a constant in void context at c:\windows\TEMP\DzTemp.pl + line 3 (#1) (W void) You did something without a side effect in a context that does nothing with the return value, such as a statement that doesn't return a value from a block, or the left side of a scalar comma operator. Very often this points not to stupidity on your part, but a failure of Perl to parse your program the way you thought it would. For example, you'd get this if you mixed up your C precedence with Python precedence and said $one, $two = 1, 2; when you meant to say ($one, $two) = (1, 2); Another common error is to use ordinary parentheses to construct a list reference when you should be using square or curly brackets, for example, if you say $array = (1,2); when you should have said $array = [1,2]; The square brackets explicitly turn a list value into a scalar value, while parentheses do not. So when a parenthesized list is evaluated in a scalar context, the comma is treated like C's comma operator, which throws away the left argument, which is not what you want. See perlref for more on this.
    As you can see this gives great help and most of the time will solve the problem. There are also alot of other good warning modules that you should use to solve an unknown error in your script or just help you maintain it. Some of these are.

    1. CGI::Carp
    2. warnings
    3. strict


    In conclusion, this is a great module that should be put at the top of your script next to
    use strict;
    . Great stuff. I recommend it.
Getopt::Declare
3 direct replies — Read more / Contribute
by danger
on Feb 02, 2001 at 17:25

    Getopt::Declare A quickie overview.

    Getopt::Declare is a module for parsing command line options -- and like many of Damian Conway's modules, this one has obviously been eating its wheaties with large doses of steroids (and it arrives with circa 1,500 lines of documentation to prove it). In short, this is not your mother's command line parser.

    Not satisfied with giving us yet another command line parser, Damian has given us a declarative language to specify not only command line options, but descriptions, parameter types, and actions as well. But don't let the size of the docs intimidate you, it is surprisingly simple to use.

    The basic mechanics of using the module are as follows:

    #!/usr/bin/perl -w use strict; use Getopt::Declare; my $spec = <<'SPEC'; # put your specification here SPEC my $ops = Getopt::Declare->new($spec); # rest of your program

    Obviously, it is the specification we are really interested in. So let's look a very trivial greplike script using the module:

    #!/usr/bin/perl -w use strict; use Getopt::Declare; use vars qw/$not $re/; $::VERSION = 0.01; my $spec = <<'EOS'; -p <pattern> pattern [required] { $re = $pattern } -f <INFILE>... input filename(s) [required] { defer{process(@INFILE)} } -not print out non-matches { $not = 1 } EOS my $opts = Getopt::Declare->new($spec); sub process { @ARGV = @_; while(<>){ if($::not){ print unless /$::re/; } else { print if /$::re/; } } } __END__

    An option declaration is comprised of a few components: the option specification itself (followed by one or more tabs); the option description (with optional directives); and an optional action block to be executed if the option is found. Let's break out the -f option above and look at each component:

    -f <INFILE>... # So we specify an option that looks like '-f' which takes one or # more arguments (that's the ... part) that will be stored in the # variable @INFILE for the action block input filename(s) [required] # This is the description of the option followed by the # [required] directive which means this option must be present on # the command line { defer{process(@INFILE)} } # This is the action block. The defer() function is from # Getopt::Declare and takes a code block which will not be # executed until all the command line options have been parsed. # Here we merely provide our own function and pass it the files # from the -f option as arguments.

    The option variable is available as a lexical variable within the action block, and you may set or access any globals that are available at the time of parsing. In our example above we set the global $re and $not variables in the action blocks so we can access those later rather than accessing those options via the $opts object. We deferred our file processing action because we want to ensure all options have been parsed (and all globals set) before we start grepping our files.

    You can also restrict parameter types when specifying parameter variables using a few predefined parameter types:

    -p <var:s> # accept strings -n <var:n> # accept any real number -i <var:i> # accept only integers

    And, because this is Perl, you can also specify your own regex to limit the types of things a parameter should accept or define new types:

    -hw <hw:/\d+x\d+$/> HeightxWidth coordinates #or [pvtype: coord /\d+x\d+$] -hw <hw:coord> HeightxWidth coordinates

    This module also gives us a -help option for free, and a -v option (if you've defined a $VERSION variable). Here's what we get with those:

    $ perl dopt.pl -v dopt.pl: version 0.01 (Fri Feb 2 09:30:34 2001) $ perl dopt.pl -help Usage: dopt.pl [options] -p <pattern> -f <INFILE>... dopt.pl -help dopt.pl -version Options: -p <pattern> pattern -f <INFILE>... input filename(s) -not print out non-matches

    And, with 1,500 lines of documentation I've clearly only scratched the surface in this little overview. Go ahead and grab it, read the docs, and play around (and, if you're feeling brave, read the code too).

HTML::Mason module review
1 direct reply — Read more / Contribute
by TheoPetersen
on Feb 01, 2001 at 17:24
    In honor of Mason's 1.0 release I thought I'd submit a quick review.

    This is one of my favorite Perl modules, and my tool of choice for creating Web pages. Mason is developed by Jonathan Swartz and a large number of other contributors. It was created originally for CMP Media, publishers of TechWeb.com and a wide variety of other sites; since then it has been put in use at a number of high-profile sites such as Salon.com and AvantGo.com, not to mention hordes of lower traffic places.

    Embedding Perl in HTML

    Anyone who's perused the HTML:: namespace on CPAN knows that there are a number of tools to choose from in putting Perl into Web pages. Among that list of choices, Mason is unique, just like all the rest :).

    Mason is first and foremost a Perl embedding tool; that is, it inserts Perl code directly into pages, to be interpretted on the fly as documents are served. This distinguishes it from the "template" camp of tools that separate documents and code; I won't get into the argument over which is better, but if you work on both document content and code together, you'll probably prefer an embedding tool. Other choices in this camp include HTML::EmbPerl and Apache::ASP.

    Mason adds a few new tags to tell its interpretter where to find Perl code. To evaluate a single line of Perl, preface it with a % at the beginning of the line:

    % my $date = localtime();
    To interpolate a Perl variable or expression into other text, surround it with the <% % > tag:
    Today's date is <% $date %>
    % lines can also be used to create conditional sections, or to build text using loops. To borrow two examples from the docs:
    % my $ua = $r->header_in('User-Agent'); % if ($ua =~ /msie/i) { Welcome, Internet Explorer users % } elsif ($ua =~ /mozilla/i) { Welcome, Netscape users % }

    % foreach $item (@list) { <li><% $item %> % }
    Longer pieces of code can be set off using <%perl> sections, where all statements up to the ending </%perl> are interpretted as code.

    Component architecture

    Mason's code embedding is nice, but the module really shines when used to build documents from pieces.

    In Mason, sections of pages are components. A top-level component corresponds to a document, and can contain all the content and Perl code directly. More likely though, the top-level refers to other components via the component call tag, <& &>. For example, suppose we have a page layout consisting of a header component, a navigation bar, a footer and what ever text the page contains. A top-level for that design would look like this:

    <& header &> <& nav-bar &> Here is the content of this page. <& footer &>

    Passing arguments to components

    But wait, there's more! The top-level component automatically receives any CGI parameters passed along with the request as arguments; it can also pass parameters along to any invoked component, which can in turn pass info along to any components they use.

    To invoke a component with arguments, pass them along inside the tags:

    <& header, date=>$date, section=>'News' &>
    To receive those values, the component needs an <%args> section:
    <%args> $date $section=>'Updates' </%args>
    In this example, the date argument is required to have a value when the component is invoked; the section argument has a default value, and can be omitted.

    Autohandlers and dhandlers

    Mason provides two mechanisms for additional standardization.

    Autohandlers are components that run before the top-level component; they can be used to provide a standard set of header/footer components or enforce other site rules. Mason checks the top-level component's directory (and all of its parents) for an autohandler and runs it before the code in the top-level itself.

    dhandlers take the place of a component that doesn't exist. This is most commonly used to replace top-level components requested by a generated URL; if Mason doesn't find the requested component, it checks the directory (and its parents) for a dhandler and runs that instead. The dhandler can look at the request URL and figure out what to do, such as retrieving the actual requested document from a database.

    Caching

    Behind the scenes, Mason translates a component into a Perl function and calls it; text in the component becomes literal values stored in the function, while the embedded code moves into the function more or less as-is. Mason caches the translated code in a separate directory for better run-time performance. As requests occur and components are called, Mason checks the modification times of its cache and the actual component file; if nothing has changed, it just uses the cache.

    Used in conjunction with mod_perl, this provides excellent performance, but those stat calls for checking times still add up. You can improve Mason's speed by telling it to check only a single file (the reload file) for updates, and then store the paths to changed components in that file as you modify them.

    And more...

    Mason has far too many features to do justice in a short review. A quick list of things to look for in the documentation:
    • Filters that allow you to work on the output of a component; these can be used to apply further rules or changes once a document has been generated.
    • Support for previewing, profiling and debugging components.
    • Component methods and attributes that make a rich object-oriented system.
    • Though it's a separate product, the Mason Content Manager provides graphical file management and a staging/production system that is aware of components and works with the reload file mechanism mentioned above.
    Take a look at the Mason Headquarters for more information.

    2001-03-04 Edit by Corion : Changed PRE tags to CODE tags.

Geo::Weather
No replies — Read more | Post response
by damian1301
on Jan 28, 2001 at 22:14
    I just got this module today with the advice of jcwren and it is the easiest way to get the weather from the web. All it takes is a simple snippet like this:
    #!/usr/bin/perl use Geo::Weather; my $weather = new Geo::Weather; $weather->get_weather('Philadelphia','PA'); print $weather->report();
    And that little bit will come with a weather report that will come out with this (Today, I mean):
    <font size=+4>Philadelphia, Pennsylvania</font><br> <img src="http://image.weather.com/weather/wx_icons/PFMScurrent/28.gif +" border=0> <font size=+3>Mostly Cloudy</font><br> <table border=0> <tr><td><b>Temp</b></td><td>37&deg F</td> <tr><td><b>Wind</b></td><td>From the West at 15 mph</td> <tr><td><b>Dew Point</b></td><td>18&deg F</td> <tr><td><b>Rel. Humidity</b></td><td>39%</td> <tr><td><b>Visibility</b></td><td>unlimited</td> <tr><td><b>Barometer</b></td><td>30.25 inches</td> <tr><td><b>Sunrise</b></td><td>7:14 am</td> <tr><td><b>Sunset</b></td><td>5:16 pm</td> </table>
    But if you don't want that big report you can even shorten it to make it more limited and more..fashionable:
    use Geo::Weather; my $weather = new Geo::Weather; my $current = $weather->get_weather('19067'); print "The current temperature is $current->{temp} degrees\n";
    And that would just print:
    The current temperature is 35 degrees
    Now, all this code presented is well documented in the module. All the keys are covered with a description next to it. So, in conclusion, this is MUCH easier than going out and writing a whole load of regular expressions to grab the weather where the results might not even be accurate! Trust me, I know. Get it here

    UPDATE: In the full report, you can use the zip code in there too for convenience. If your not connected to the internet when you run it, all that will happen is a little error.
AppConfig
3 direct replies — Read more / Contribute
by BoredByPolitics
on Jan 21, 2001 at 19:01

    ++

    Extremely flexible handling of both configuration files, and commandline parameters.

    Four parameter types - boolean, scalar, array and hash.

    As each parameter is defined it can have various properties set, including DEFAULT setting, ACTION to take on use, VALIDATE based on regex or sub result, various types of variable EXPANDing, variable name ALIASes.

    The properties DEFAULT, ACTION, VALIDATE, and EXPAND can be set globally as well as local to a parameter.

    Can handle multiple sources of configuration file, including filehandles.

    --

    VALIDATEs which use a sub don't appear to trigger the return of a false value from the arg() method, although a warning to the user is printed.

    ACTIONs cannot alter the value they're attached to, as this sets up a circular reference.

    Overall

    An extremely useful module which, although it takes a bit of time to get to know, is well worth the extra effort.

Text::CSV
5 direct replies — Read more / Contribute
by TStanley
on Jan 10, 2001 at 21:27
    Author: Alan Citterman

    I had a project where I needed to extract data from a file and send
    it to a customer. The file in question was from a database, and it
    had been exported to a CSV text file.

    I would have tried to write my own regular expression to handle this,
    but my overall knowledge of Perl isn't that good. However, after some
    research, I found a reference to this module.

    #!/usr/bin/perl use strict; use Text::CSV;
    I knew that the text file had lines of data that I didn't need, and
    that there was an easily recognizable pattern in those lines, so I could
    use a regular expression to put those lines into a trash file.

    my $input="input.csv"; my $output="output.txt"; my $trash="trashfile"; my $csv=Text::CSV->new(); #Creates a new Text::CSV object open(INFILE,$input) || die "Can't open file $input"; open(OUTFILE,">$output") || die "Can't open file $output"; open(TRASH,">$trash") || die "Can't open file $trash";

    Now to start reading the data from the file, store it in the $_ variable
    and print it to the trash file if its not good, or parse the variable, and
    print it to the output file if it is.

    while (<INFILE>) { if (/"X"/) { #The trash data has these 3 characters in it print TRASH "$_\n"; } else { #Now to deal with the data I want to keep if($csv->parse($_)) { #checks to see if data exists in $_ and +parses it if it does my @fields=$csv->fields; # puts the values from each field in an +array my $elements=@fields; #gets the number of elements in the arra +y for ($x=0;$x<$elements;$x++) { print OUTFILE "$fields[$x]\t"; } } } }
    Now that the files have been written to, I can close them up, and remove
    the trash file

    close INFILE; close OUTFILE; close TRASH; unlink $trash;
    All in all, a very useful module.
DBI vs. Oraperl
No replies — Read more | Post response
by wardk
on Dec 11, 2000 at 23:56

    Module(s):

    • Oraperl.pm
    • DBI.pm (DBD::Oracle)

    Author(s):

    • DBI and Oraperl emulation using DBD::Oracle by <cite><Tim.Bunce@ig.co.uk></cite>
    • Original Oraperl 2.4 code and documentation by <cite>Kevin Stock <kstock@auspex.fr></cite>.

    This is a short review of the two most used Perl toolkits for retrieving data from an Oracle database, DBI and Oraperl.

    In the beginning, there was Oraperl, and if you were using Perl 4, Oraperl was the only game in town. Then came Perl 5, then DBI. Now every RDBMS worth using has a uniform interface for Perl.

    But...what to do with all that old Oraperl code? Re-write?, /dev/null?, keep it?
    ......you *can* keep it!

    The Oraperl module (originally written by Kevin Stock) was re-written for Perl 5 by Tim Bunce to use the DBD::Oracle interface. So you get the best of both worlds...backward compatability for your existing scripts, and a new API to utilize in case you desire a generic interface that could perhaps work against another DBI supported RDBMS.

    On the job, I use both. I support a web-based HR system that was written originally in Perl 4 using Oraperl. This codebase now is on Perl 5, however the scripts still utilize Oraperl. So for new development I use DBD::Oracle via DBI, and when maintaining existing scripts I keep using Oraperl.

    When first taking over this position, I was convinced that I would need to eventually remove all that damn Oraperl....then I read the perldoc, and realized that this was not the same Oraperl I used about 4 years previous in another life, but one written and supported by the very man who wrote and supported DBI and DBD::Oracle...Tim Bunce.

    So instead of spending time re-writing boatloads of working code, I spent some time using Benchmark and attempted to see if there was any significant performance differences in using DBD:Oracle directly, or using the Oraperl interface to it. My benchmarks all proved out to me that Oraperl was in fact slower....just barely. In fact, they were so close in my tests that I just have no valid performance reasons to rework any Oraperl into native DBI.

    So which to use for accessing your Oracle database? Since Tim mentions in the docs that Oraperl is for backward compatibility, I suggest that you do not <cite>use Oraperl;</cite> if you are starting fresh. If you have existing code and are curious to the benefits of porting the code to native DBI...that's your call, I found no performance reasons for doing so, and since the same man that supports DBI wrote Oraperl, there shouldn't be any pressing issues over support.

    Bottom line is that both these modules are of high quality and production-ready, you can be safe utilizing either.

    For this review, I have decided to not supply any code samples as Tim Bunce has provided plenty of them in the perldocs. So if you are curious about syntactical and/or other differences....please refer to these links:

DBD::RAM
1 direct reply — Read more / Contribute
by mirod
on Nov 30, 2000 at 11:37

    Description

    DBD::RAM is Jeff Zucker's driver for the DBI that allows you to import files in memory and treat them as relational tables, with SQL queries.
    Several tables can be created this way and SQL joins can be simulated through loops.
    Changes to the data can be reflected to the original file (if the table is created using the catalog function) or the table can be export-ed to one of the formats supported by DBD::RAM.

    DBD::RAM can process the following formats:

    • CSV (Comma Separated Values),
    • Fixed-width records, using pack to define the format,
    • Perl structures (arrays of arrayrefs or hasrefs) so you can create the data in the Perl script and then use it as a relational table,
    • XML,
    • User-defined, which allows the user to define a subroutine that will parse the input and return an array with the various fields,
    • Other DBI data bases, so you can load a table in memory, close the connection and then process the data,
    • MP3 headers from a group of directories.

    The data in all formats can be input either locally, from strings, files or pipes, or remotely through LWP

    Why use DBD::RAM

    • you are dealing with existing data, which format you have no control over, but you still want to access it through the DBI interface, using SQL,
    • you want to use SQL without installing a relational DB,
    • you want to prototype an application without a DB but think that you might add one down the line,
    • you want to convert data from a DBD::RAM supported format to an other,
    • you want to use an XML file as a table (exporting it back might not work for you though)

    Why NOT use DBD::RAM

    You will not use DBD::RAM essentially if you need a real data base.

    • you process huge amounts of data,
    • the data is already in an existing DB.

    Example

    The obligatory XML example:

    # connect to the DB my $dbh= DBI->connect( "DBI:RAM:" , {RaiseError => 1} ); # create the table $dbh->func( { table_name => 'projects', data_type => 'XML', record_tag => 'projects project', col_names => 'pid,name,description', file_source => 'project.xml', }, 'import'); # prepare the SQL statement my $sth= $dbh->prepare( "SELECT * FROM projects"); # execute the statement $sth->execute(); # output the result of the query while( my $hashref= $sth->fetchrow_hashref()) { foreach my $field ( keys %$hashref) { print "$field: $hashref->{$field}\t"; } print "\n"; } # export the table back as XML $dbh->func( { data_type => 'XML', data_target => "new_projects.xml", data_source => "select * from projects", record_tag => 'projects project', col_names => 'pid,name,description', }, 'export' );

    Note on XML import: make sure you include the whole hierarchy of tags in the record_tag argument, from the document root to the record tag itself.

    Personal Notes

    I really like DBD::RAM. It allows treating lots of structured data as a relational table, including XML (mostly for extracting data from an XML file though). It also allows quick prototyping without having to go through the pain of yet-another-mysql install.

    The good
    DBD::RAM is really flexible. For example in the CSV format the field and record separators can actually be redefined so it's more like ASV (Anything Separated Values). For most formats field definitions can also be extracted from the first line of the file instead of being hard coded in the script.
    The XML import allows you a good deal of customizing the data you want to extract from the XML file, including having records inherit attributes from their parents. Encoding conversions, and especially latin-1 output are also handled.
    The documentation is pretty good: it is comprehensive and includes lots of examples that can be cut-n-paste'd.

    The not-so-good
    The initial debugging of an application can be quite a pain though, as error messages on import are no too helpful, they tell you that something is wrong but not quite where the exact error is.
    Some XML data is difficult to extract (for example if several parent tags have attributes with the same name you can't fold them properly) but this can be fixed by a simple pre-processing of the data.
    The syntax of the XML option is slightly confusing (space separated list of tags for the record_tag argument, but comma (no space) for the col_names argument.
    This should improve with future versions of the module.

    Related Modules

    For XML processing you might want to have a look at XML::RAX or at DBIx::XML_RDB (to export XML from a RDB).

    The future

    DBD::RAM should be replaced by AnyData and DBD::AnyData any time now, see this note for the planned architecture.

    Update: after the author reviewing the... review I have fixed a couple of (embarassing) mistakes: DBD::RAM does file locking (through flock), but it does not do join. I have fixed the review accordingly (plus a couple of other points Jeff mentioned.)

    Update (2): AnyData and DBD::AnyData are out and officially replace DBD::RAM.

Memoize
No replies — Read more | Post response
by ariels
on Nov 30, 2000 at 11:06

    Description

    Memoization speeds up calculation of a function by storing its previously-computed values. MJD's excellent Memoize module memoizes (almost) any function you ask it to. If you use Memoize;, applying this optimisation can be as simple as saying memoize 'slow_function';.

    Additional methods exist, allowing such things as persistant storage of memoized values.

    Why should I use it?

    Memoization is not a technique for everyday use. Only pure functions (functions which are executed only for their return values, not for any side effects) can be memoized. It's the sort of module you should download and learn how (and when) to use.

    Eventually you'll write a slow routine that gets called in a slow loop. If only a small number of different argument combinations get passed to the routine, it's an excellent candidate for memoization.

    The documentation contains several examples, some of which can serve as ideas for usage. The section on persistant storage of the cache is particularly noteworthy.

    Why should I read it?

    The documentation, code and a Perl Journal article make excellent associated reading, sure to improve your Perl. Both explain in detail what memoization is, and how (and when!) to use it. In particular, the article explains how the module performs its magic, by giving a very short (but complete!) implementation of the principle routine, memoize.

    Ways to use the module are mentioned, with examples:

    • Simple memoization
    • Using a batch process to "pre-memoize" some values persistantly
    • Memoizing list and scalar context together (normally the module keeps the contexts separate).
    • Support for Memoize::Expire.
    • Memoization as a lightweight substitute for dynamic programming.
    • Memoization as a clearer replacement for the Orcish maneuver.

    You should also read the documentation (or the article), paying attention to the routine's limitation regarding functions taking multiple arguments which may contain the contents of $; (see "Why shouldn't I use it", below).

    Finally, the author of this review is mentioned in the module's documentation. This gives at least one person an additional reason to read the documentation.

    Why shouldn't I use it?

    Most likely, because your problem doesn't need it.

    If your problem does need memoization, you might still need to help the module a bit.

    • If your routine takes multiple arguments, Memoize codes them using the single key join $; , @_; if your arguments may contain the contents of $; (in particular, if one of the arguments is binary data), you might need to do some extra work.
    • If your routine takes a complex data structure as argument, you'll probably also need to do some extra work to use the module.
    The documentation describes both problems and how to solve them. Neither is a showstopper, but it is probably worth your while to know about these problems before you run into them.

    Probably the single biggest drawback of memoization is that it doesn't work for functions with side effects. This is nothing to do with Memoize, and everything to do with the technique. Unfortunately, there is no way the module can check this for you. Blindly applying memoize to every slow function in your program will not work, and will cause your program to fail without warnings! Make sure to understand what you are doing, before you do it.

    2001-03-15 Edit by Corion : Removed spurious links

Spreadsheet::WriteExcel
1 direct reply — Read more / Contribute
by BigGuy
on Nov 03, 2000 at 20:03

    To use this module
    use Spreadsheet::WriteExcel;

    As stated above this module allows you to write excel files
    without that annoying popup asking you how your file is
    delimeted when you open the file. It works very well,
    the only problem i had was trying to convert one of our flat files
    that is over 70,000 records in length. But after
    i checked the problem is documented, it can only produce files
    <~ 7.0 MB. heres on little program I have created with it

    #!/usr/bin/perl use Spreadsheet::WriteExcel; print "Enter the path to the file(ie /home/): "; $path = <>; chomp($path); print "Enter the filename(ie data): "; $fname = <>; chomp($fname); $file = "$path$fname"; my $workbook = Spreadsheet::WriteExcel->new("/tmp/$fname.xls"); $worksheet1 = $workbook->addworksheet(sheet1); $worksheet2 = $workbook->addworksheet(sheet2); $worksheet3 = $workbook->addworksheet(sheet3); $format = $workbook->addformat(); $format->set_bold(); $format->set_color('black'); $format->set_align('center'); $format->set_size('10'); open input, "$file" || die "Can't open that file"; $k=0; for (<input>){ chomp($_); @data = split(/\t/,$_); for ($i=0; $i<=@data; $i++){ $worksheet1->write($k, $i, $data[$i], $format); } $k++; }
    Good Luck
    Rob
Image::Magick
5 direct replies — Read more / Contribute
by Corion
on Oct 25, 2000 at 08:20

    Update:The Image Magick URL was updated, thanks to the good folks notifying me.

    Image::Magick (also called PerlMagick) is the Perl wrapper for Image Magick, a feature rich command line image manipulation program.

    What's good ?

    If you have to manipulate images (crop, resize, convert, montage, grayscale, paint), Image::Magick is the thing for you. The ImageMagick suite of programs is seasoned and converts images between a set of claimed 68 different formats. If you're thinking about rolling your own image decoder, think if maybe ImageMagick already does the stuff for you.

    ImageMagick (and Image::Magick) is available for a lot of platforms, ranging from Win32 to VMS and OS/2.

    Image::Magick is used widely for creating images, for example the GeoCities banner generator uses Image::Magick.

    What's bad ?

    ImageMagick is written in C. While there is not that much bad about this immediately, this means, you have to find and install a version of ImageMagick written for your platform.

    The second thing is, that Image::Magick also needs some XS compiled, which means that you will need some way to compile the XS for your target machine. ActiveState has a Image::Magick for Perl 5.005_03 (build 522), but there is no Image::Magick package for Perl 5.6 (build 613+) - a nasty thing to find out after you upgrade.

    The third thing that might keep you from using Image::Magick is, that it is a bit overkill for some jobs. If you only need the dimensions of an image, think about using Image::Size, and if the image types you want to accept are limited (think PPM), a Perl decoder might be faster at load time/run time than Image::Magick. But Image::Magick saves you the trouble of finding a correct specification for your particular image format and you can add new file formats easily.

    Things of note

    The interface documentation for the Perl interface is installed with the main ImageMagick package, the Image::Magick package itself comes without documentation. The documentation itself leaves some bits wishing, it takes some experimentation until you get the parameter names right for every function call you can make. Other than that, the design is OK, you instantiate an Image::Magick object, into which you can load one or more images, you convert them and then you write them out to disk using the methods of the object. This is mainly efficient for converting large batches of images.

    If you can't get Image::Magick to work from within Perl, there is always the backup method of using shell commands to convert and mogrify, which are two command line programs that act as call-ins to the ImageMagick libraries as well.