| Subcribe via RSS

Perl Module Monday: IMDB::Film

October 3rd, 2011 | 2 Comments | Posted in CPAN, Perl

For this week’s PMM, I’m going to go with something a little more fun: the IMDB::Film module. Though, to be fair, I’ll be offering it up with some caveats and reservations.

Still, I’m a huge fan of movies; I try to see a new film every week or two, and my DVD collection has out-grown two different shelves. I’ve even gone so far as to get an Android app on my phone (Packrat) for the sole purpose of keeping track of my collection so that I don’t impulse-buy something I already have (usually because I’ve found it on sale). And don’t get me started on slowly replacing my most-favorite films with Blu-Ray copies! Anyway, I’ve also been a huge fan of the IMDb web site since it first got its start. But they don’t offer an API to their data (which I find strange, given their huge reliance on open-source software and user-generated content). Until and unless they see the error of their ways, we’ll have to get by with modules like IMDB::Film, which does a lot of the heavy-lifting when it comes to screen-scraping IMDb.

The IMDB::Film class (and the companion IMDB::Persons class) handles all the page-fetching and parsing that you would otherwise have to do, and presents you with a reasonably-encapsulated object representing an IMDb film (or person). Based on the criteria you give it, it either goes directly to the necessary page, or it does a search and returns you the first matching record (along with enough additional information to get the remaining matched records). For example, the snippet here:

use IMDB::Film;

my $film = IMDB::Film->new(crit => 'Harry Potter');

This returns as the match in $film, “Harry Potter and the Sorcerer’s Stone”. And calling $film->matched(), you get an array-reference to the 43 (!) total matches for the string, “Harry Potter”. Part of each hash-reference in those 43 slots is the IMDb key for the given title, meaning you can fetch the subsequent titles without first going to the search form:

my $other_film = IMDB::Film->new(crit => $film->matched->[0]->{id});

This will go directly to that page and fill in $other_film with the info from it. Read the docs for the class to see the other accessors you can call, and see the docs for the IMDB::Persons class for what you can do with it. In particular, the cast() method on a film object will give you a list-reference of hash-references, one key of which is the IMDb ID for each cast member. You can use this to get their page info with IMDB::Persons.

Now, the dreaded caveats and reservations:

  • The current version (0.51 as of this writing) has left some debugging lines in the code, so calls to new() (in both the ::Film and ::Persons classes) send cruft to STDOUT.
  • And, by the way, why call one class “Film” (singular) and the other class “Persons” (plural)? I consider that bad design.
  • The cast() method only lists the cast that are listed on the main page of the film’s IMDb entry. In the Harry Potter example, this means only the first 15 people, most of whom are actually minor players.
  • In general, there seems to be no deeper-drilling for any information— you can get the short bio for an actor, but not the full bio for example.
  • You can get URLs for certain of the data elements (images, etc.), but not for the full page itself. If I wanted to extract data for Tom Cruise, for example, then render that data along with a link back to the IMDb page for him, I cannot get that URL from the IMDB::Persons record for Tom Cruise. This despite the fact that it had to have fetched that URL to get the data.

There are other minor nits, but those are the high points. I will be watching this module, to see if any of these get addressed (and I opened an RT ticket for the errant debugging messages, hopefully that will be addressed in the next release). But while I may seem to be harsh on it, I still think it’s a useful little module, and worth playing around with. Scraping IMDb is no small task, and I’m glad someone is doing the grunt-work of keeping up with their content-layout changes.

Tags: , ,

Perl Module Monday: Object::Tiny (and friends)

September 26th, 2011 | 3 Comments | Posted in CPAN, Perl

Seriously, I’m going to have to create a new tag with “module” in the plural form, at this rate. This week’s post started out just looking at one module, but as it happens there are three variant forms of it that are just as interesting and useful as the original. So it would be highly unfair to leave any of them out.

Let’s start with the module at the core of it all, Object::Tiny. Object::Tiny is exactly as the name implies: tiny. With the POD it’s just under 9000 bytes, and not counting the POD the current version (1.08) is 553 bytes. I like the *::Tiny modules, I like seeing people getting the most functionality in a truly modular way with a minimum of code and no dependencies. Object::Tiny gives you a truly minimal way to create objects with simple (read-only) accessors. It also gives you a dead-simple constructor if you don’t already have one (well, most of the time— I’ll come back to this in a bit). And it does it all with an extremely small footprint and a minimum of intrusiveness.

Some might be wondering why you would need this— after all, the object you create from Object::Tiny is little more than a hash-reference with delusions of grandeur: the storage is just a basic hash reference (no extra keys or meta-data), the accessors are read-only by design (but see the bit on related modules further down) no additional methods besides an inheritable new() are provided, etc. But it’s a hash-reference that can call methods, for one thing. And your users don’t need to know that it is just a lowly hash-ref under the hood. Plus, there are plenty of applications for read-only data structures. Indeed, at its core, functional programming calls for immutable data. Writing methods to effect changes by returning new objects with the updated member values would be pretty trivial. You could, for example, define a clone() operation that allows updated values to be passed in as:

sub clone {
    my $self = shift;

    return __PACKAGE__->new(%{$self}, @_);
}

(For the less-experienced Perl users, this calls the new() of the package that the code is in, with the contents of the existing object flattened from a hash to an array. In addition to that, it also passes any arguments to clone() itself. Because of the way array/hash flattening/conversion works, anything in the arguments will override similar-named keys in the original hash, effectively “updating” those keys.)

Of course, this being CPAN, you don’t need to do that. You just need to consider one of the alternatives:

  • Object::Tiny::RW – This variant creates accessors that are read/write, by slightly altering the code that is generated. Accessors will then be able to accept an argument that, if present, becomes the new value for the key: $obj->foo(2) sets the “foo” key to 2. Of course, no type-checking is done.
  • Object::Tiny::Lvalue – This variant also creates read/write accessors, but rather than using the “$obj->foo(2)” syntax it creates the accessors as lvalue methods, allowing you to do the same thing with “$obj->foo = 2“.
  • Object::Tiny::XS – This variant breaks the “tiny” rule slightly by depending on Class::XSAccessor. It generates read-only accessors and the inheritable new() method using Class::XSAccessor. Interestingly, it does not generate read/write accessors like the other two variants do, even though Class::XSAccessor provides a simple alternative that does this. That might be worthy of a feature-request, if someone feels strongly about it.

Since the usage syntax of these is all identical (well, except for the lvalue variant), one could even prototype with one module and switch to another later on if so needed. Particularly with Object::Tiny vs. Object::Tiny::XS, since both adhere to the read-only model of the generated accessors.

One thing I have noticed in the logic of Object::Tiny that seems to be reflected in all three of the variants, is: the class is only added to your (calling) class’ inheritance hierarchy if you do not already have something in your @ISA variable. If you do, it will not add itself to your inheritance path. This means that you won’t get an inherited constructor in cases where you might be expecting to. For example, your class might utilize some form of an exporter and have that in the @ISA array. But it doesn’t provide you a constructor. If you were expecting Object::Tiny to provide the constructor, you may be surprised when it doesn’t. Mind you, the constructor it provides is dead-simple, but just be sure to know this behavior before it catches you off-guard. This behavior isn’t a bug, either, because it makes sense that if your class inherits from another class, it is probably either inheriting a constructor or providing its own constructor as an override. So I don’t consider this a problem with Object::Tiny, it’s just something to be aware of when using it.

Object::Tiny (and friends): for your minimalist class-construction needs!

Tags: , ,

Perl Module Monday: Desktop::Notify

September 19th, 2011 | No Comments | Posted in CPAN, Perl

Boy am I slipping (again). Been a few weeks since I wrote at all, and on top of that I can’t seem to type AT ALL right now, so who knows how long it’ll take me to write this (and whether it actually gets posted while it is still Monday).

For this week, I’m going to continue on the theme of my previous feature, only this time for Linux systems: Desktop::Notify. If you use a GNOME desktop that is fairly recent in release, then you probably are already familiar with the DBus messages that various applications pop up from time to time; chat clients, web browsers, etc. Many of the current-generation graphical apps have some sort of notification needs, and if they are running on a desktop that has DBus notifications they are probably using this system. So in comes this module, to let you also take part.

It’s quite an easy module to use, and the manual page is pretty reasonable given the overall simplicity. It’s even simple-enough to use in a one-liner:

perl -MDesktop::Notify -e 'Desktop::Notify->new->create(
    summary => "Desktop::Notify", body => "A notification...",
    timeout => 3000)->show'

(Broken up for line-length and clarity, of course.) Something like that could be easily incorporated into a shell script (though the “notify-send” utility can do that just as easily).

But if you are looking for a simple way to send messages to the user in a fairly unobtrusive fashion, have a look at this!

Tags: , ,

Perl Module Monday: Growl::Tiny

August 29th, 2011 | 2 Comments | Posted in CPAN, Perl

I’m a fairly-new MacOS user. I’ve had this MacBook Pro since just a few days before this last OSCON, and I’m growing more and more fond of it by the day. So for this week’s PMM, I’m going to look at a Mac-centric module, apologies in advance to those who have no use for this— there’s something similar for Linux desktops that I might explore in the future.

Growl::Tiny is the latest (it seems) entry into the Growl-glue arena, and certainly the most-recently-updated. As the author states, he had run into problems with the prerequisites for modules such as Mac::Growl, so he wrote this as a solution. In following with the “tiny” convention, the module has no prerequisites. It only requires that you have /usr/local/bin/growlnotify installed (as well as Growl itself, of course). I found that it built and installed just fine on my system, with only one hitch that I’ll come back to later.

So what does it do? Well, it makes Growl notifications! If you are a MacOS user and you don’t know about Growl, you should probably get over to http://growl.info/ first and check it out. Seriously, it’s a terribly useful utility. Once you’ve done that, this module will let you, in a fairly lightweight fashion, use Growl to send desktop notifications to your users. It’s the “lightweight” part that appeals to me, as the older Growl libraries seemed to be dependent on some other modules that haven’t been kept up-to-date with the changes in MacOS. This one gets around this by opting to use a command-line utility (the aforementioned growlnotify) instead of native bindings. It’s not without limitations, as the author points out in his documentation. But then, if you’re sending several notifications per second, you might need something more substantial than this anyway, so the limitations might not be of concern.

The only issue I had with it was that two tests will fail if you don’t set up Growl to listen for localhost-directed network connections. The author recommends using the network feature in the docs, but it shouldn’t be a requirement for building and installation. A more graceful way of detecting that network connections are not enabled, and skipping the tests, would be preferable.

Tags: , ,

Perl Module Monday: Carp::Always

August 22nd, 2011 | 1 Comment | Posted in CPAN, Perl

(With special bonus-module this week!)

Ever run into an error or warning in someone else’s module, and wished you could get more information about it without having to wade through their code? It’s probably almost certain that you have, at least once. At least once, you’ve seen a warning or had a program die, and wished that you could see a stack trace without having to go in and edit the module. After all, the module is probably installed into a system location, and even if you don’t need root/sudo to edit it, you then have the hassle of going back and undoing the changes (or re-doing them, if/when you update the module in question) after your debugging has been done.

Enter Carp::Always. Carp::Always plays around with $SIG{__WARN__} and $SIG{__DIE__}, and gives you stack-traces on every die and warn that come from code. I was introduced to this module by a commenter on my “Chasing an Elusive Warning” post last week. Alas, it didn’t help in that case, as the warning was coming from within Perl itself. But I found the module to be a nice concept, and it’s easy to use on a only-when-you-need-it basis. Have a script that is generating warnings you want more information about?

perl -MCarp::Always script.pl

Carp::Always quietly slips in and make the necessary alteration to the die/warn handlers, and your script runs and does its thing. And when the warnings (or termination) come, you should have your stack trace.

The author does point out that this module may not play well with other modules that alter $SIG{__WARN__} and $SIG{__DIE__}, so there is that to be aware of. But that aside, hopefully this can be of great aid to your next debugging session!

(And as a bonus, here’s another module that does the essentially the same thing: Devel::SimpleTrace. I actually know much less about this one, except that it lists Data::Dumper as a dependency, which leads me to believe that it tries to do some pretty-printing with the data in stack-frames. But unlike Carp::Always, I haven’t used it. Still, if you like the concept, it’s worth checking out both modules and seeing which one you like more.)

Tags: , ,

Perl Module Release: RPC-XML 0.76

August 21st, 2011 | No Comments | Posted in CPAN, Perl, Software
Version: 0.76

Released: Saturday August 20, 2011, 06:30:00 PM -0700

Changes:

  • etc/make_method
  • lib/RPC/XML/Server.pm

RT #70258: Fixed typos in docs pointed out by Debian team.

  • lib/Apache/RPC/Server.pm

Better version of the fix for infinite loops. This is the patch originally suggested by Eric Cholet, who found the bug.

  • t/00_load.t

RT #70280: This test was still testing RPC/XML/Method.pm. Rewrote to remove that but include the (forgotten) XMLLibXML.pm module. That test has to be conditional on the presence of XML::LibXML.

  • Makefile.PL
  • t/51_client_with_host_header.t

Clean up test suite to work with older Test::More. Also specify a minimum Test::More that supports subtest(). This is also a part of RT #70280.

  • t/11_base64_fh.t
  • t/20_xml_parser.t
  • t/21_xml_libxml.t
  • t/40_server.t

These tests had failures when run as root. Permissions-based negative tests were incorrectly passing.

  • t/10_data.t

Moved the 64-bit “TODO” tests to a SKIP block. Non-64-bit systems will skip, rather than fail, these tests.

  • lib/RPC/XML/Server.pm

RT #65616: Fix for slow methods killing servers. Applied and modified patch from person who opened the ticket.

  • MANIFEST
  • lib/RPC/XML.pm
  • t/10_data.t
  • t/14_datetime_iso8601.t (added)

RT #55628: Improve flexibility of date parsing. This adds the ability to pass any ISO 8601 string to the RPC::XML::datetime_iso8601 constructor.

Tags: , , ,

How To Tell That CPAN Testers Is Doing Its Job

August 16th, 2011 | 1 Comment | Posted in CPAN, Perl

…or, “How To Generate Well Over 100 Failure Reports With Just One Release.”

Ever wonder whether CPAN Testers was really gathering data for you? Ever wonder whether you’re getting the daily summary emails you signed up for? Here’s how you can tell, in just a few (moderately) easy steps:

  1. Start with a fairly-robust CPAN distribution. Let’s call it “RPC-XML“, just for argument’s sake.
  2. Have it include a test suite like this one, that test-loads all the classes.
  3. Remove one of the classes, let’s say, “RPC/XML/Method.pm“.
  4. This is the important part, don’t change the test suite.
  5. Dutifully run your tests, note 100% pass rate due to the fact that you have a perfectly usable RPC/XML/Method.pm from an existing installation somewhere under /usr/lib/perl or /usr/share/perl.
  6. Release, and wait. The reports will come rolling in within just a few short days.
  7. Now you know that the emails really do get sent reliably!

So, technically this is an issue with the use_ok() predicate in Test::More. And I’ve opened an issue on this, in GitHub. But this may very well be a case of, “Doctor, it hurts when I do this.” And if Schwern decides that it isn’t a bug, I’ll have a hard time arguing with him. But hopefully he’ll agree with my suggestion, and maybe someone, someday, will be spared falling into the same hole I’ve very recently fallen into.

Tags: ,

Perl Module Release: RPC-XML 0.75

August 14th, 2011 | No Comments | Posted in CPAN, Perl, Software, XML

MetaCPAN.org: https://metacpan.org/release/RJRAY/RPC-XML-0.75

Version: 0.75

Released: Saturday August 13, 2011, 05:30:00 PM -0700

Changes:

  • MANIFEST

Somehow, t/13_no_deep_recursion.t never got added to MANIFEST.

  • lib/RPC/XML/Parser/XMLLibXML.pm

RT #65154: Fixed a cut/paste error in an error message.

  • lib/RPC/XML/Client.pm
  • t/51_client_with_host_header.t (added)

RT #68792: Merge pull request #2 from dragon3/master (https://github.com/dragon3). Allow setting of “Host” header, and test suite for it.

  • MANIFEST
  • t/51_client_with_host_header.t

Added new test suite to MANIFEST, fixed spelling. Also added “plan tests” line to the test suite.

  • lib/RPC/XML/Parser/XMLLibXML.pm
  • t/20_xml_parser.t
  • t/21_xml_libxml.t
  • t/41_server_hang.t

Merge pull request #3 from yannk/master (https://github.com/yannk). Expat parser subclass is protected against ext ent attack, libxml isn’t.

  • t/41_server_hang.t

Undo a change to this suite from yannk’s pull.

  • etc/make_method
  • lib/Apache/RPC/Server.pm
  • lib/Apache/RPC/Status.pm
  • lib/RPC/XML.pm
  • lib/RPC/XML/Client.pm
  • lib/RPC/XML/Function.pm
  • lib/RPC/XML/Method.pm
  • lib/RPC/XML/Parser.pm
  • lib/RPC/XML/Parser/XMLLibXML.pm
  • lib/RPC/XML/Parser/XMLParser.pm
  • lib/RPC/XML/ParserFactory.pm
  • lib/RPC/XML/Procedure.pm
  • lib/RPC/XML/Server.pm

More perlcritic-driven clean-up. This is mostly POD sections, but also includes heavy re-working of etc/make_method and parts of lib/RPC/XML.pm.

  • lib/RPC/XML/Parser/XMLLibXML.pm
  • t/21_xml_libxml.t

Fixed external entity handling on MacOS. Also made small change to the test suite to be cleaner.

  • lib/RPC/XML/Parser/XMLLibXML.pm
  • lib/RPC/XML/Parser/XMLParser.pm

Took out warnings on external entities blocking. Now it blocks silently. Also cleaned up some docs.

  • t/15_serialize.t

Additions to increase code coverage in XML.pm.

  • lib/RPC/XML.pm

Turns out this wasn’t exporting RPC_I8.

  • lib/Apache/RPC/Server.pm
  • lib/Apache/RPC/Status.pm
  • lib/RPC/XML.pm
  • lib/RPC/XML/Client.pm
  • lib/RPC/XML/Function.pm
  • lib/RPC/XML/Method.pm
  • lib/RPC/XML/Parser.pm
  • lib/RPC/XML/Parser/XMLLibXML.pm
  • lib/RPC/XML/Parser/XMLParser.pm
  • lib/RPC/XML/ParserFactory.pm
  • lib/RPC/XML/Procedure.pm
  • lib/RPC/XML/Server.pm
  • xt/02_pod_coverage.t

Made 5.8.8 the new minimum-required perl. Also dropped the utf8_downgrade hack, which affected an xt test.

  • lib/RPC/XML/Client.pm

Improved arguments-checking in send_request.

  • lib/RPC/XML/Client.pm
  • lib/RPC/XML/Parser/XMLLibXML.pm
  • lib/RPC/XML/Parser/XMLParser.pm
  • lib/RPC/XML/Server.pm

Fixed error-cases in usage of File::Temp->new(). File::Temp::new croaks on errors, doesn’t return undef like I thought.

  • MANIFEST
  • lib/RPC/XML/Function.pm (deleted)
  • lib/RPC/XML/Method.pm (deleted)
  • lib/RPC/XML/Procedure.pm

Roll Method.pm and Function.pm into Procedure.pm. Remove Method.pm and Function.pm from distro.

  • lib/RPC/XML/Parser/XMLLibXML.pm

Fixed regexp for methodName validation.

  • t/10_data.t
  • t/11_base64_fh.t
  • t/12_nil.t
  • t/15_serialize.t
  • t/20_xml_parser.t
  • t/21_xml_libxml.t
  • t/25_parser_negative.t (added)
  • t/29_parserfactory.t
  • t/30_method.t
  • t/40_server.t
  • t/40_server_xmllibxml.t
  • t/50_client.t
  • t/BadParserClass.pm (added)
  • t/meth_good_1.xpl
  • t/namespace3.xpl
  • t/svsm_text.b64 (added)
  • t/util.pl

First round of Devel::Cover-inspired improvements. These are the changes to the test suites to increase coverage of the code.

  • lib/RPC/XML.pm
  • lib/RPC/XML/Procedure.pm
  • lib/RPC/XML/Server.pm

Fixes and such from Devel::Cover analysis.

  • lib/RPC/XML/Procedure.pm
  • lib/RPC/XML/Server.pm
  • t/30_method.t
  • t/meth_good_1.xpl
  • t/meth_good_2.xpl (added)
  • t/meth_good_3.xpl (added)

Fixes for file-based method loading/reloading. New tests in the suite, and re-working of the ugliest hacky part of this package.

  • lib/RPC/XML/Procedure.pm
  • lib/RPC/XML/Server.pm
  • t/30_method.t
  • t/meth_good_3.xpl

RPC::XML::Procedure test-coverage improvement. Also removed some unneeded code.

  • lib/RPC/XML/Procedure.pm
  • lib/RPC/XML/Server.pm
  • t/30_method.t
  • t/40_server.t

Last round of RPC::XML::Procedure test coverage. This is mostly in t/40_server.t, though some bugs were found and addressed in the modules and in t/30_method.t.

  • lib/Apache/RPC/Server.pm
  • lib/Apache/RPC/Status.pm
  • lib/RPC/XML.pm
  • lib/RPC/XML/Client.pm
  • lib/RPC/XML/Parser.pm
  • lib/RPC/XML/Parser/XMLLibXML.pm
  • lib/RPC/XML/Parser/XMLParser.pm
  • lib/RPC/XML/ParserFactory.pm
  • lib/RPC/XML/Procedure.pm
  • lib/RPC/XML/Server.pm

Documentation clean-up and update.

  • lib/Apache/RPC/Server.pm
  • lib/Apache/RPC/Status.pm
  • lib/RPC/XML/Client.pm
  • lib/RPC/XML/Parser/XMLLibXML.pm
  • lib/RPC/XML/Parser/XMLParser.pm
  • lib/RPC/XML/Procedure.pm
  • lib/RPC/XML/Server.pm

Changes from new Perl::Critic::Bangs policies.

  • xt/01_pod.t
  • xt/02_pod_coverage.t
  • xt/03_meta.t
  • xt/04_minimumversion.t
  • xt/05_critic.t

Adjustments to reflect moving from t to xt. Also made changes to xt/02_pod_coverage.t to reflect changes to modules.

  • lib/RPC/XML/Client.pm

Removed some error checks that can never fail.

  • lib/RPC/XML/Server.pm
  • t/40_server.t

Code-coverage-driven changes and added tests.

  • etc/make_method

Fixes from new Perl::Critic::Bangs policies.

  • lib/RPC/XML/Server.pm

Removed usage of AutoLoader completely.

  • lib/RPC/XML/Server.pm
  • t/40_server.t
  • xt/02_pod_coverage.t

Removed some dead code and better did the aliases. This required a change in t/40_server.t for a private sub that no longer exists. Also updated xt/02_pod_coverage.t for private subs that have no pod.

  • lib/Apache/RPC/Server.pm

RT #67694: Fix a potential infinite-loop condition.

Tags: , , ,

Perl Module Monday: AutoRole

August 9th, 2011 | 4 Comments | Posted in CPAN, Perl

This week’s choice is a sort of follow-up to last week’s post. AutoRole is a module that lets you do run-time or compile-time loading of modules, along with potentially renaming what you import on the fly. It takes these two useful features and wraps them into one package.

I try not to do two such closely-related picks back-to-back, but I had actually noticed AutoRole about a year ago, and taken note of it. It was shortly after I had taken RJBS’s Moose tutorial at OSCON ’10, and I was looking for a way to do roles at my day-job without having the luxury of a full-on Moose install. Alas, as often happens with my ADD-addled brain, I promptly forgot about the module after a few days. Luckily, the module’s author mentioned it in a comment to last week’s post, and it reminded me to take another look at it.

And it looks quite flexible. You can specify one of three methods for loading the module (compile-time or two flavors of run-time loading), and you can both specify the methods/routines to load, and give them alternate names if necessary (or just desired). It’s also quite light-weight and has no dependencies. If I were to have any concerns about it, it would be that it seems to be fairly young code (the latest version at this writing being 0.03) and hasn’t been updated in just over a year. BUT, and this is important, these two facts don’t mean the code isn’t solid and usable. I, too, have had code that reached the point where I felt it was feature-complete and stable, while only having reached version 0.4 or so. So don’t let these two factors prevent you from at least looking over AutoRole and maybe giving it a try.

One thing I did notice that Exporter does, that neither Sub::Exporter or AutoRole seem to do, is export variables themselves. However, this may be considered a feature by some!

So here you go: Sub::Exporter for creating more flexibility in your exports as a module developer, and AutoRole for more flexibility on your imports (and to be fair, I’ll mention that RJBS also has a module called Sub::Import that provides a Sub::Exporter-sort-of-flexibility when importing from modules that don’t use Sub::Exporter). Different approaches to the same sort of problem, depending on the angle from which you are approaching it. Myself, I’ll be looking at both modules for my own use, at home and at work.

Tags: , ,

Perl Module Monday: Sub::Exporter

August 1st, 2011 | 5 Comments | Posted in CPAN, Perl

For this week’s entry, I’m taking a look at a module I first learned about in December  2009 while reading RJBS‘s Advent Calendar for that year: Sub::Exporter. I highly recommend his yearly calendar, as it is a great way to learn about new and interesting modules and features. Of course, it helps to actually use the things you find interesting: while I learned about this module over a year and a half ago, I’d completely forgotten about it until someone mentioned it during one of the talks as OSCON last week. Then I came across it in my notes on modules to consider for this series, and decided I’d best write about it soon, lest I forget it again!

Rather than going into an exhaustive explanation of what this module is, I invite you to take a quick look at the original advent calendar posting. Go ahead, I’ll wait. Done? Great!

Now, if you didn’t just check that out, or if you thought it was too long and just skimmed over it, here’s the short version: Sub::Exporter is a super-version of the core Exporter module. It allows other modules and scripts to import the routines you’ve chosen to export. But unlike Exporter, it gives both you and the user of your module a great range of flexibility in options and configuration of the routines that are exported/imported.

So, it can do everything that Exporter does, but it can also do a whole lot more. To me, the most useful feature of Sub::Exporter is the ability to rename an imported function when you import it. I have, in the past, had to opt to not import a given subroutine in order to avoid name-clashes between different modules. I would have to choose which one “wins”, and then use the full package name to call the other package’s routine. With Sub::Exporter, this is not only a fixable problem, it’s also the simplest of the examples of Sub::Exporter use.

The module is well-documented, coming not only with a basic manual page but also a tutorial page and a cookbook page. If only more modules did this! (I say that, but none of my modules do that, so I have no room to cast aspersions.) It is also fairly lightweight in both its own code and its dependencies (unlike last week’s PMM, which I later learned requires that you have Moose installed, even though it doesn’t use Moose directly).

I won’t necessarily replace all my usage of Exporter with Sub::Exporter— I think that some names are sufficiently unique as to avoid potential clashes— but I will certainly be using it in the future.

Tags: , ,