Monday, March 30, 2009

Smoke testing Perl with Test::TAP::HTMLMatrix



Testing is Great Fun, but what is the point if you can't impress your boss with a great-looking report?

I remember looking at the smoke-test-reports for Pugs several months ago, wondering "How did they make these great test reports?"

Well, it's pretty easy. Yuval Kogman, a prolific Perl module author, has created Test::TAP::HTMLMatrix.

This image is a screenshot of the kind of reports you can get from Test::TAP::HTMLMatrix. Each test name is hyperlinked to the test file itself. This example was created with the following script:

#!/usr/bin/perl

use strict;
use warnings;

use Test::TAP::HTMLMatrix;
use Test::TAP::Model::Visual;
use Test::TAP::Model::Consolidated;

# make a successful test run
my $model_ok = Test::TAP::Model::Visual->new_with_tests(
glob("t/*/*.t")
);
$model_ok->desc_string("real run");

my $v = Test::TAP::HTMLMatrix->new(
Test::TAP::Model::Consolidated->new( $model_ok )
);
$v->has_inline_css(1);

# this is the most popular view:
print $v->detail_html;

I run it like this:
perl smoke.pl > smoke.html


Friday, March 27, 2009

Perl UPS API Shootout




UPS, The United Parcel Service - AKA Big Brown - has been around since 1907.

Perl, the Practical Extraction and Reporting Language - AKA The Swiss Army Chainsaw - has been around since 1987.

I've been interacting with the UPS shipping tools since, well, since before they were converted to XML. About 3 weeks before, actually, and I had to rewrite that entire part of a client's website, for free, and the delay in getting paid nearly cost me my apartment.

Of course that would never have happened if I had instead used one of the available UPS modules on CPAN, because the modules' authors would have (probably) updated their code to work with the updated UPS interface for me.

So in an effort to save you some effort, I'll share my foray into the world of Perl/UPS integration options and let you know what I discover.

Business::UPS

The first thing I noticed about Business::UPS is that the API seems a little...1999-ish.

 use Business::UPS;

my ($shipping,$ups_zone,$error) = getUPS(qw/GNDCOM 23606 23607 50/);
$error and die "ERROR: $error\n";
print "Shipping is \$$shipping\n";
print "UPS Zone is $ups_zone\n";

%track = UPStrack("z10192ixj29j39");
$track{error} and die "ERROR: $track{error};

# 'Delivered' or 'In-transit'
print "This package is $track{Current Status}\n";
Also, when I installed Business::UPS via CPAN, I got version 1.13 instead of 2.0. After manually downloading version 2.0 and doing the standard incantation...
perl Makefile.PL
make
make test
sudo make install
...I discovered that the file test.pl does not actually test anything except to make sure that the module does in fact compile.

I attempted to email the author - cpan@datademons.com - and the email bounced.

CONCLUSION:
The module might be filed under the Business:: namespace, but until the author Justin Wheeler adds some real unit tests to this distribution, I wouldn't trust Business::UPS to my business, that's for sure. The apparently abandoned status does not bode well, either.

Webservice::UPS

This is a new distribution (as of March 26th, 2009) and offers a clean, object-oriented interface to some of the UPS API. Webservice::UPS is built on Mouse, a minimal implementation of Moose, the postmodern object system for Perl. This means that Webservice::UPS benefits from the features in Mouse, while remaining lightweight enough for web applications written in Apache2::ASP or Catalyst.

Unfortunately the module does not (yet) offer the ability to request shipping rates and methods for a package, but I've asked the author Kyle Brandt about adding that functionality.

CONCLUSION:

Webservice::UPS looks fairly nice and just might be the right tool for your UPS package-tracking needs. However, the lack of support for rate and shipping method requests makes me continue the search for a total solution.

Business::Shipping::UPS_XML

It appears to have been originally released in March of 2004, and the last release was in June of the same year. Sure, the UPS e-commerce tools don't appear to have changed that much since then, but when you download the documentation (dtk_RateXML_V1.zip) you see that the copyright is 2009. Something may have changed since 2004 - we don't know, because UPS doesn't give us a changelog with their UPS XML tools, but I have a hunch that we should have something a bit newer than 5 years old and apparently abandoned.

The module's author, Duane Hinkley of DownHomeWebDesign.com fame might make a fresh release soon, or transfer the module to someone else who will take care of it.

CONCLUSION:

Don't use this module. Write your own. In fact, write your own and release it on CPAN.

Business::Shipping

It was only after looking through the changelog of Business::UPS that I discovered a reference to Business::Shipping:
@@ -1,3 +1,13 @@
+Fri Jun 20 09:27:24 2003 jwheeler
+
+ * Changed namespace to the original Business::UPS to make room for
+ Dan Browning's Business::Shipping modules.
+
+Tue Jun 10 13:28:37 2003 jwheeler
+
+ * Came across this module, was horribly outdated, rewrote it to work again.
+ * Renamed to Business::Shipping::UPS so as not to interfere with solomon's namespace.
+

Mon Feb 22 16:03:01 1999 msolomon

* UPS.pm: Thanks to pudge@pobox.com, changed a {} to ()
I also discovered that because of the way old modules come under the care of new authors, sometimes the person currently assigned blame of a distribution does not deserve it. (Yes, English is my first language - go figure.)

Business::Shipping was written by Dan Browning. Although there is a Google Code project page, no code has been checked into it.

The synopsis from the Business::Shipping CPAN page looks fairly straightforward:
 use Business::Shipping;

my $rate_request = Business::Shipping->rate_request(
shipper => 'UPS_Offline',
service => 'Ground Residential',
from_zip => '98683',
to_zip => '98270',
weight => 5.00,
);

$rate_request->execute() or die $rate_request->user_error();

print $rate_request->rate();
Installing Business::Shipping version 2.03 fails.

cpan[3]> install Business::Shipping
Running install for module 'Business::Shipping'
Running make for D/DB/DBROWNING/Business-Shipping-2.03.tar.gz
Has already been unwrapped into directory /home/john/.cpan/build/Business-Shipping-2.03-l3GrDY
Has already been made
Running make test
PERL_DL_NONLAZY=1 /usr/bin/perl "-MExtUtils::Command::MM" "-e" "test_harness(0, 'blib/lib', 'blib/arch')" t/*.t
t/10_init....................ok
t/15_Pod.....................ok
t/16_Pod-Coverage............skipped: (no reason given)
t/20_business_shipping.......skipped: (no reason given)
t/21_preload.................skipped: (no reason given)
t/22_Version.................ok
t/30_USPS_Online.............skipped: (no reason given)
t/31_USPS_Online_Tracking....skipped: (no reason given)
t/40_UPS_Online..............skipped: (no reason given)
t/41_UPS_Online_Shop.........skipped: (no reason given)
t/42_UPS_Online_COD..........skipped: (no reason given)
t/45_UPS_Offline.............skipped: (no reason given)
t/61_Log4perl................1/? Global symbol "$INFO" requires explicit package name at t/61_Log4perl.t line 16.
Execution of t/61_Log4perl.t aborted due to compilation errors.
# Looks like your test exited with 255 just after 2.
t/61_Log4perl................ Dubious, test returned 255 (wstat 65280, 0xff00)
All 2 subtests passed
t/70_countries...............skipped: (no reason given)
t/80_usertag_sim.............skipped: (no reason given)

Test Summary Report
-------------------
t/61_Log4perl (Wstat: 65280 Tests: 2 Failed: 0)
Non-zero exit status: 255
Files=15, Tests=42, 3 wallclock secs ( 0.06 usr 0.01 sys + 2.16 cusr 0.19 csys = 2.42 CPU)
Result: FAIL
Failed 1/15 test programs. 0/42 subtests failed.
make: *** [test_dynamic] Error 255
DBROWNING/Business-Shipping-2.03.tar.gz
/usr/bin/make test -- NOT OK
//hint// to see the cpan-testers results for installing this module, try:
reports DBROWNING/Business-Shipping-2.03.tar.gz
Running make install
make test had returned bad status, won't install without force
Failed during this command:
DBROWNING/Business-Shipping-2.03.tar.gz : make_test NO
I did a "force install" since the error appeared to be a syntax error in a test (not a good sign).

I tried running the code from the synopsis and received the following error:
john@ubuntu-pc1:~/Desktop/ups$ perl bus-ship.pl
Use of uninitialized value $/ in join or string at /usr/local/share/perl/5.10.0/Config/IniFiles.pm line 2117.
Can't use string ("service=XDM to_country=Australia") as an ARRAY ref while "strict refs" in use at /usr/local/share/perl/5.10.0/Business/Shipping/Config.pm line 172.
That error does not make any sense, since my test script was trying to ship something from Denver to Los Angeles, not Australia.

CONCLUSION:

Do not use Business::Shipping, especially not for business. I tried to email Dan Browning at dan.browning@kavod.com but my email bounced.


THE BOTTOM LINE:

I started this post thinking "It's been a while since I did any UPS stuff with Perl - there's got to be some great tools out there now." Well maybe not so much, not today anyway.

We Perl hackers should have a nice interface to find out whether we can ship UPS Ground from Hawaii to Florida, or if Next Day Air is an option for shipping something 2 miles away. All it takes is 45 minutes of winding your way through the bizzare maze of broken links and password requests on the UPS website, plus the ability to make a few HTTP requests and send some HORRIBLY BROKEN XML to the UPS web services (more on that later).


Thursday, March 26, 2009

DBD::Google - Treat Google as a datasource for DBI



Somehow all of our information ends up on Google. Now we can treat Google like a database and query it with SQL just like a simple database:


#!/usr/bin/perl -w

use strict;
use warnings 'all';
use DBI;
use Data::Dumper;

my $key = 'ABQIAAA...-P_bCg';
my $dbh = DBI->connect("dbi:Google:", $key);
my $sth = $dbh->prepare('SELECT title, URL FROM google WHERE q = "perl"');
$sth->execute();
while( my $rec = $sth->fetchrow_hashref )
{
warn Dumper( $rec );
}# end while()
$sth->finish();
$dbh->disconnect();

Unfortunately, it requires you to get a Google SOAP API Key, which Google no longer supports.

Perhaps the author, Darren Chamberlain, will consider upgrading DBD::Google to use REST::Google or something similar instead.

Here's to hoping :-)


URI::GoogleChart - Generate Google Chart URIs




Google Charts. Everything goes just fine until you want to do something slightly complicated, like this (left) which involves a complex URL like this:
http://chart.apis.google.com/chart?cht=lxy&chs=200x125&chco=3072F3,FF0000&chd=t:5.3,16.0,37.2,79.8,90.4,95.7,100%7C16.0,26.6,37.2,47.9,58.5,69.1,79.8%7C-1%7C0,21.3,42.6,63.8,85.1

I don't know about you, but that looks like a real pain to remember and get correct all the time.

However, that chart was generated with the spectacular new URI::GoogleChart from the intrepid Norwegian Perl hacker Gisle Aas.

The only code necessary to generate that chart was this:

URI::GoogleChart->new("lxy", 200, 125,
data => [
[10,20,40,80,90,95,99],
[20,30,40,50,60,70,80],
[undef],
[5,25,45,65,85],
],
color => [qw(3072F3 red)],
);
Now that looks a bit more readable, doesn't it?

As you can see in the examples below, URI::GoogleChart makes it easy to generate many kinds of charts with the Google Charts API.


URI::GoogleChart Examples

URI::GoogleChart->new("pie-3d", 250, 100,
data => [60, 40],
chl => "Hello|World",
);


URI::GoogleChart->new("lines", 200, 125,
data => [40,60,60,45,47,75,70,72,],
min => 0,
max => 100,
);


URI::GoogleChart->new("sparklines", 200, 125,
data => [27,25,60,31,25,39,25,31,26,28,80,28,27,31,27,29,26,35,70,25],
min => 0,
max => 100,
);


URI::GoogleChart->new("lxy", 200, 125,
data => [
[10,20,40,80,90,95,99],
[20,30,40,50,60,70,80],
[undef],
[5,25,45,65,85],
],
color => [qw(3072F3 red)],
);


URI::GoogleChart->new("horizontal-stacked-bars", 200, 150,
data => [
[10,50,60,80,40],
[50,60,100,40,20],
],
min => 0,
max => 200,
color => [qw(3072F3 f00)],
);



URI::GoogleChart->new("vertical-grouped-bars", 300, 125,
data => [
[10,50,60,80,40],
[50,60,100,40,20],
],
min => 0,
max => 100,
chco => "3072F3,ff0000",
);

http://chart.apis.google.com/chart?cht=bvg&chs=300x125&chco=3072F3,ff0000&chd=t:10,50,60,80,40%7C50,60,100,40,20


URI::GoogleChart->new("gom", 125, 80, data => 80, chl => 80, title => "Awesomeness");


URI::GoogleChart->new("usa", 200, 100);


Wednesday, March 25, 2009

CPAN Release Reviews



This blog features (or will soon) reviews of recently-released Perl modules and when possible, an interview with the module's author(s).